From 67810b155268a6c55c37917f293d68547beb6ab7 Mon Sep 17 00:00:00 2001 From: pixar-oss Date: Mon, 17 Feb 2020 16:22:49 -0800 Subject: [PATCH] Remove deprecated Houdini plugin from the USD repository This plugin has been deprecated in favor of Houdini's native Solaris suite (also known as LOPs). (Internal change: 2042211) --- CMakeLists.txt | 4 - build_scripts/build_usd.py | 36 +- cmake/defaults/Options.cmake | 10 - cmake/defaults/Packages.cmake | 4 - cmake/modules/FindHoudini.cmake | 156 - third_party/houdini/CMakeLists.txt | 28 - third_party/houdini/README.md | 8 +- third_party/houdini/gusd/CMakeLists.txt | 143 - third_party/houdini/gusd/GEO_IOTranslator.cpp | 143 - third_party/houdini/gusd/GEO_IOTranslator.h | 61 - .../houdini/gusd/GT_OldPointInstancer.cpp | 48 - .../houdini/gusd/GT_OldPointInstancer.h | 55 - third_party/houdini/gusd/GT_PackedUSD.cpp | 833 -- third_party/houdini/gusd/GT_PackedUSD.h | 221 - .../houdini/gusd/GT_PointInstancer.cpp | 52 - third_party/houdini/gusd/GT_PointInstancer.h | 63 - third_party/houdini/gusd/GT_PrimCache.cpp | 489 - third_party/houdini/gusd/GT_PrimCache.h | 72 - third_party/houdini/gusd/GT_Utils.cpp | 1315 --- third_party/houdini/gusd/GT_Utils.h | 217 - third_party/houdini/gusd/GT_VtArray.h | 354 - third_party/houdini/gusd/GT_VtStringArray.h | 225 - third_party/houdini/gusd/GU_PackedUSD.cpp | 985 -- third_party/houdini/gusd/GU_PackedUSD.h | 325 - third_party/houdini/gusd/GU_USD.cpp | 1729 ---- third_party/houdini/gusd/GU_USD.h | 328 - .../houdini/gusd/NURBSCurvesWrapper.cpp | 752 -- third_party/houdini/gusd/NURBSCurvesWrapper.h | 101 - .../houdini/gusd/OP_ParmChangeMicroNode.cpp | 249 - .../houdini/gusd/OP_ParmChangeMicroNode.h | 87 - third_party/houdini/gusd/PRM_Shared.cpp | 347 - third_party/houdini/gusd/PRM_Shared.h | 117 - .../houdini/gusd/USD_CustomTraverse.cpp | 590 -- third_party/houdini/gusd/USD_CustomTraverse.h | 112 - third_party/houdini/gusd/USD_DataCache.cpp | 77 - third_party/houdini/gusd/USD_DataCache.h | 73 - third_party/houdini/gusd/USD_PropertyMap.h | 139 - third_party/houdini/gusd/USD_StdTraverse.cpp | 272 - third_party/houdini/gusd/USD_StdTraverse.h | 78 - .../houdini/gusd/USD_ThreadedTraverse.cpp | 115 - .../houdini/gusd/USD_ThreadedTraverse.h | 313 - third_party/houdini/gusd/USD_Traverse.cpp | 93 - third_party/houdini/gusd/USD_Traverse.h | 187 - third_party/houdini/gusd/USD_TraverseSimple.h | 97 - third_party/houdini/gusd/USD_Utils.cpp | 1011 -- third_party/houdini/gusd/USD_Utils.h | 322 - third_party/houdini/gusd/USD_VisCache.cpp | 269 - third_party/houdini/gusd/USD_VisCache.h | 98 - third_party/houdini/gusd/USD_XformCache.cpp | 485 - third_party/houdini/gusd/USD_XformCache.h | 147 - third_party/houdini/gusd/UT_Assert.h | 64 - third_party/houdini/gusd/UT_CappedCache.h | 190 - third_party/houdini/gusd/UT_Gf.h | 590 -- third_party/houdini/gusd/UT_StaticInit.h | 105 - third_party/houdini/gusd/UT_TypeTraits.cpp | 85 - third_party/houdini/gusd/UT_TypeTraits.h | 146 - third_party/houdini/gusd/UT_Version.h | 111 - third_party/houdini/gusd/UT_VtArray.h | 186 - third_party/houdini/gusd/__init__.py | 42 - third_party/houdini/gusd/agentUtils.cpp | 719 -- third_party/houdini/gusd/agentUtils.h | 145 - third_party/houdini/gusd/api.h | 41 - third_party/houdini/gusd/boundsCache.cpp | 151 - third_party/houdini/gusd/boundsCache.h | 137 - third_party/houdini/gusd/context.h | 129 - third_party/houdini/gusd/curvesWrapper.cpp | 893 -- third_party/houdini/gusd/curvesWrapper.h | 102 - third_party/houdini/gusd/debugCodes.cpp | 38 - third_party/houdini/gusd/debugCodes.h | 40 - third_party/houdini/gusd/defaultArray.h | 94 - third_party/houdini/gusd/error.cpp | 185 - third_party/houdini/gusd/error.h | 206 - third_party/houdini/gusd/groupBaseWrapper.cpp | 270 - third_party/houdini/gusd/groupBaseWrapper.h | 74 - third_party/houdini/gusd/gusd.h | 80 - third_party/houdini/gusd/instancerWrapper.cpp | 1666 ---- third_party/houdini/gusd/instancerWrapper.h | 235 - third_party/houdini/gusd/meshWrapper.cpp | 1263 --- third_party/houdini/gusd/meshWrapper.h | 145 - third_party/houdini/gusd/module.cpp | 37 - third_party/houdini/gusd/packedUsdWrapper.cpp | 388 - third_party/houdini/gusd/packedUsdWrapper.h | 96 - third_party/houdini/gusd/plugin.cpp | 194 - third_party/houdini/gusd/pointsWrapper.cpp | 384 - third_party/houdini/gusd/pointsWrapper.h | 107 - third_party/houdini/gusd/primWrapper.cpp | 1139 --- third_party/houdini/gusd/primWrapper.h | 392 - third_party/houdini/gusd/purpose.cpp | 110 - third_party/houdini/gusd/purpose.h | 115 - third_party/houdini/gusd/refiner.cpp | 891 -- third_party/houdini/gusd/refiner.h | 249 - third_party/houdini/gusd/scopeWrapper.cpp | 211 - third_party/houdini/gusd/scopeWrapper.h | 107 - third_party/houdini/gusd/shaderWrapper.cpp | 644 -- third_party/houdini/gusd/shaderWrapper.h | 65 - .../houdini/gusd/site/icons/pxh_gusdIcon.png | Bin 3477 -> 0 bytes third_party/houdini/gusd/stageCache.cpp | 1895 ---- third_party/houdini/gusd/stageCache.h | 360 - third_party/houdini/gusd/stageEdit.cpp | 93 - third_party/houdini/gusd/stageEdit.h | 102 - third_party/houdini/gusd/stageOpts.cpp | 38 - third_party/houdini/gusd/stageOpts.h | 79 - .../houdini/gusd/testenv/testGusdErrors.cpp | 175 - .../testGusdStageCache/defaultPrim.usda | 15 - .../gusd/testenv/testGusdStageCache/test.usda | 50 - .../testenv/testGusdStageCache/test2.usda | 23 - .../testenv/testGusdStageCache/test3.usda | 23 - .../testGusdStageCache/testGusdStageCache.py | 432 - third_party/houdini/gusd/tokens.cpp | 32 - third_party/houdini/gusd/tokens.h | 49 - third_party/houdini/gusd/treemodel.py | 751 -- third_party/houdini/gusd/treeview.py | 956 -- third_party/houdini/gusd/valueUtils.cpp | 1661 ---- third_party/houdini/gusd/valueUtils.h | 232 - third_party/houdini/gusd/wrapStageCache.cpp | 261 - third_party/houdini/gusd/wrapStageEdit.cpp | 155 - third_party/houdini/gusd/wrapStageOpts.cpp | 51 - third_party/houdini/gusd/writeCtrlFlags.cpp | 74 - third_party/houdini/gusd/writeCtrlFlags.h | 76 - third_party/houdini/gusd/xformWrapper.cpp | 217 - third_party/houdini/gusd/xformWrapper.h | 118 - third_party/houdini/plugin/CMakeLists.txt | 3 - .../houdini/plugin/OP_gusd/CMakeLists.txt | 77 - .../houdini/plugin/OP_gusd/OBJ_usdcamera.cpp | 734 -- .../houdini/plugin/OP_gusd/OBJ_usdcamera.h | 152 - .../houdini/plugin/OP_gusd/OP_Utils.cpp | 52 - third_party/houdini/plugin/OP_gusd/OP_Utils.h | 50 - .../houdini/plugin/OP_gusd/OPcustomize_gusd | 1 - .../plugin/OP_gusd/ROP_usdcoalesce.otl | Bin 40521 -> 0 bytes .../houdini/plugin/OP_gusd/ROP_usdcoalesce.py | 237 - .../houdini/plugin/OP_gusd/ROP_usdlayer.otl | Bin 41939 -> 0 bytes .../houdini/plugin/OP_gusd/ROP_usdlayer.py | 118 - .../houdini/plugin/OP_gusd/ROP_usdoutput.cpp | 2241 ----- .../houdini/plugin/OP_gusd/ROP_usdoutput.h | 109 - .../plugin/OP_gusd/ROP_usdreference.otl | Bin 41179 -> 0 bytes .../plugin/OP_gusd/ROP_usdreference.py | 212 - .../plugin/OP_gusd/SOP_camerafrustum.otl | Bin 696871 -> 0 bytes .../plugin/OP_gusd/SOP_usdbindproxy.otl | Bin 21154 -> 0 bytes .../OP_gusd/SOP_usdexportattributes.hda | Bin 15556 -> 0 bytes .../houdini/plugin/OP_gusd/SOP_usdimport.cpp | 697 -- .../houdini/plugin/OP_gusd/SOP_usdimport.h | 87 - .../OP_gusd/SOP_usdinstanceprototypes.hda | Bin 41749 -> 0 bytes .../houdini/plugin/OP_gusd/SOP_usdretime.hda | Bin 5117 -> 0 bytes .../houdini/plugin/OP_gusd/SOP_usdunpack.cpp | 565 -- .../houdini/plugin/OP_gusd/SOP_usdunpack.h | 88 - .../houdini/plugin/OP_gusd/UsdImport.pypanel | 31 - .../plugin/OP_gusd/help/USDPackedPrims.txt | 111 - .../plugin/OP_gusd/help/UsdOutputOverview.txt | 119 - .../help/nodes/out/pixar--usdlayer.txt | 71 - .../help/nodes/out/pixar--usdoutput.txt | 92 - .../help/nodes/out/pixar--usdreference.txt | 56 - .../help/nodes/sop/pixar--usdimport.txt | 129 - .../sop/pixar--usdinstanceprototypes.txt | 18 - .../help/nodes/sop/pixar--usdunpack.txt | 88 - .../plugin/OP_gusd/obj/pixar-usdcamera.py | 40 - .../plugin/OP_gusd/pixar-camerafrustum.png | Bin 6921 -> 0 bytes .../plugin/OP_gusd/pixar-camerafrustum.svg | 8515 ----------------- .../houdini/plugin/OP_gusd/pixar-usdrop.json | 11 - third_party/houdini/plugin/OP_gusd/plugin.cpp | 78 - 159 files changed, 4 insertions(+), 49992 deletions(-) delete mode 100644 cmake/modules/FindHoudini.cmake delete mode 100644 third_party/houdini/CMakeLists.txt delete mode 100644 third_party/houdini/gusd/CMakeLists.txt delete mode 100644 third_party/houdini/gusd/GEO_IOTranslator.cpp delete mode 100644 third_party/houdini/gusd/GEO_IOTranslator.h delete mode 100644 third_party/houdini/gusd/GT_OldPointInstancer.cpp delete mode 100644 third_party/houdini/gusd/GT_OldPointInstancer.h delete mode 100644 third_party/houdini/gusd/GT_PackedUSD.cpp delete mode 100644 third_party/houdini/gusd/GT_PackedUSD.h delete mode 100644 third_party/houdini/gusd/GT_PointInstancer.cpp delete mode 100644 third_party/houdini/gusd/GT_PointInstancer.h delete mode 100644 third_party/houdini/gusd/GT_PrimCache.cpp delete mode 100644 third_party/houdini/gusd/GT_PrimCache.h delete mode 100644 third_party/houdini/gusd/GT_Utils.cpp delete mode 100644 third_party/houdini/gusd/GT_Utils.h delete mode 100644 third_party/houdini/gusd/GT_VtArray.h delete mode 100644 third_party/houdini/gusd/GT_VtStringArray.h delete mode 100644 third_party/houdini/gusd/GU_PackedUSD.cpp delete mode 100644 third_party/houdini/gusd/GU_PackedUSD.h delete mode 100644 third_party/houdini/gusd/GU_USD.cpp delete mode 100644 third_party/houdini/gusd/GU_USD.h delete mode 100644 third_party/houdini/gusd/NURBSCurvesWrapper.cpp delete mode 100644 third_party/houdini/gusd/NURBSCurvesWrapper.h delete mode 100644 third_party/houdini/gusd/OP_ParmChangeMicroNode.cpp delete mode 100644 third_party/houdini/gusd/OP_ParmChangeMicroNode.h delete mode 100644 third_party/houdini/gusd/PRM_Shared.cpp delete mode 100644 third_party/houdini/gusd/PRM_Shared.h delete mode 100644 third_party/houdini/gusd/USD_CustomTraverse.cpp delete mode 100644 third_party/houdini/gusd/USD_CustomTraverse.h delete mode 100644 third_party/houdini/gusd/USD_DataCache.cpp delete mode 100644 third_party/houdini/gusd/USD_DataCache.h delete mode 100644 third_party/houdini/gusd/USD_PropertyMap.h delete mode 100644 third_party/houdini/gusd/USD_StdTraverse.cpp delete mode 100644 third_party/houdini/gusd/USD_StdTraverse.h delete mode 100644 third_party/houdini/gusd/USD_ThreadedTraverse.cpp delete mode 100644 third_party/houdini/gusd/USD_ThreadedTraverse.h delete mode 100644 third_party/houdini/gusd/USD_Traverse.cpp delete mode 100644 third_party/houdini/gusd/USD_Traverse.h delete mode 100644 third_party/houdini/gusd/USD_TraverseSimple.h delete mode 100644 third_party/houdini/gusd/USD_Utils.cpp delete mode 100644 third_party/houdini/gusd/USD_Utils.h delete mode 100644 third_party/houdini/gusd/USD_VisCache.cpp delete mode 100644 third_party/houdini/gusd/USD_VisCache.h delete mode 100644 third_party/houdini/gusd/USD_XformCache.cpp delete mode 100644 third_party/houdini/gusd/USD_XformCache.h delete mode 100644 third_party/houdini/gusd/UT_Assert.h delete mode 100644 third_party/houdini/gusd/UT_CappedCache.h delete mode 100644 third_party/houdini/gusd/UT_Gf.h delete mode 100644 third_party/houdini/gusd/UT_StaticInit.h delete mode 100644 third_party/houdini/gusd/UT_TypeTraits.cpp delete mode 100644 third_party/houdini/gusd/UT_TypeTraits.h delete mode 100644 third_party/houdini/gusd/UT_Version.h delete mode 100644 third_party/houdini/gusd/UT_VtArray.h delete mode 100644 third_party/houdini/gusd/__init__.py delete mode 100644 third_party/houdini/gusd/agentUtils.cpp delete mode 100644 third_party/houdini/gusd/agentUtils.h delete mode 100644 third_party/houdini/gusd/api.h delete mode 100644 third_party/houdini/gusd/boundsCache.cpp delete mode 100644 third_party/houdini/gusd/boundsCache.h delete mode 100644 third_party/houdini/gusd/context.h delete mode 100644 third_party/houdini/gusd/curvesWrapper.cpp delete mode 100644 third_party/houdini/gusd/curvesWrapper.h delete mode 100644 third_party/houdini/gusd/debugCodes.cpp delete mode 100644 third_party/houdini/gusd/debugCodes.h delete mode 100644 third_party/houdini/gusd/defaultArray.h delete mode 100644 third_party/houdini/gusd/error.cpp delete mode 100644 third_party/houdini/gusd/error.h delete mode 100644 third_party/houdini/gusd/groupBaseWrapper.cpp delete mode 100644 third_party/houdini/gusd/groupBaseWrapper.h delete mode 100644 third_party/houdini/gusd/gusd.h delete mode 100644 third_party/houdini/gusd/instancerWrapper.cpp delete mode 100644 third_party/houdini/gusd/instancerWrapper.h delete mode 100644 third_party/houdini/gusd/meshWrapper.cpp delete mode 100644 third_party/houdini/gusd/meshWrapper.h delete mode 100644 third_party/houdini/gusd/module.cpp delete mode 100644 third_party/houdini/gusd/packedUsdWrapper.cpp delete mode 100644 third_party/houdini/gusd/packedUsdWrapper.h delete mode 100644 third_party/houdini/gusd/plugin.cpp delete mode 100644 third_party/houdini/gusd/pointsWrapper.cpp delete mode 100644 third_party/houdini/gusd/pointsWrapper.h delete mode 100644 third_party/houdini/gusd/primWrapper.cpp delete mode 100644 third_party/houdini/gusd/primWrapper.h delete mode 100644 third_party/houdini/gusd/purpose.cpp delete mode 100644 third_party/houdini/gusd/purpose.h delete mode 100644 third_party/houdini/gusd/refiner.cpp delete mode 100644 third_party/houdini/gusd/refiner.h delete mode 100644 third_party/houdini/gusd/scopeWrapper.cpp delete mode 100644 third_party/houdini/gusd/scopeWrapper.h delete mode 100644 third_party/houdini/gusd/shaderWrapper.cpp delete mode 100644 third_party/houdini/gusd/shaderWrapper.h delete mode 100644 third_party/houdini/gusd/site/icons/pxh_gusdIcon.png delete mode 100644 third_party/houdini/gusd/stageCache.cpp delete mode 100644 third_party/houdini/gusd/stageCache.h delete mode 100644 third_party/houdini/gusd/stageEdit.cpp delete mode 100644 third_party/houdini/gusd/stageEdit.h delete mode 100644 third_party/houdini/gusd/stageOpts.cpp delete mode 100644 third_party/houdini/gusd/stageOpts.h delete mode 100644 third_party/houdini/gusd/testenv/testGusdErrors.cpp delete mode 100644 third_party/houdini/gusd/testenv/testGusdStageCache/defaultPrim.usda delete mode 100644 third_party/houdini/gusd/testenv/testGusdStageCache/test.usda delete mode 100644 third_party/houdini/gusd/testenv/testGusdStageCache/test2.usda delete mode 100644 third_party/houdini/gusd/testenv/testGusdStageCache/test3.usda delete mode 100644 third_party/houdini/gusd/testenv/testGusdStageCache/testGusdStageCache.py delete mode 100644 third_party/houdini/gusd/tokens.cpp delete mode 100644 third_party/houdini/gusd/tokens.h delete mode 100644 third_party/houdini/gusd/treemodel.py delete mode 100644 third_party/houdini/gusd/treeview.py delete mode 100644 third_party/houdini/gusd/valueUtils.cpp delete mode 100644 third_party/houdini/gusd/valueUtils.h delete mode 100644 third_party/houdini/gusd/wrapStageCache.cpp delete mode 100644 third_party/houdini/gusd/wrapStageEdit.cpp delete mode 100644 third_party/houdini/gusd/wrapStageOpts.cpp delete mode 100644 third_party/houdini/gusd/writeCtrlFlags.cpp delete mode 100644 third_party/houdini/gusd/writeCtrlFlags.h delete mode 100644 third_party/houdini/gusd/xformWrapper.cpp delete mode 100644 third_party/houdini/gusd/xformWrapper.h delete mode 100644 third_party/houdini/plugin/CMakeLists.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/CMakeLists.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.cpp delete mode 100644 third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.h delete mode 100644 third_party/houdini/plugin/OP_gusd/OP_Utils.cpp delete mode 100644 third_party/houdini/plugin/OP_gusd/OP_Utils.h delete mode 100644 third_party/houdini/plugin/OP_gusd/OPcustomize_gusd delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.otl delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.py delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdlayer.otl delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdlayer.py delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdoutput.cpp delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdoutput.h delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdreference.otl delete mode 100644 third_party/houdini/plugin/OP_gusd/ROP_usdreference.py delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_camerafrustum.otl delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdbindproxy.otl delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdexportattributes.hda delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdimport.cpp delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdimport.h delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdinstanceprototypes.hda delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdretime.hda delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdunpack.cpp delete mode 100644 third_party/houdini/plugin/OP_gusd/SOP_usdunpack.h delete mode 100644 third_party/houdini/plugin/OP_gusd/UsdImport.pypanel delete mode 100644 third_party/houdini/plugin/OP_gusd/help/USDPackedPrims.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/UsdOutputOverview.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdlayer.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdoutput.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdreference.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdimport.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdinstanceprototypes.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdunpack.txt delete mode 100644 third_party/houdini/plugin/OP_gusd/obj/pixar-usdcamera.py delete mode 100644 third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.png delete mode 100644 third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.svg delete mode 100644 third_party/houdini/plugin/OP_gusd/pixar-usdrop.json delete mode 100644 third_party/houdini/plugin/OP_gusd/plugin.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 39a3d84587..d0a20f429b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,10 +59,6 @@ if (${PXR_BUILD_KATANA_PLUGIN}) add_subdirectory(third_party/katana) endif() -if (${PXR_BUILD_HOUDINI_PLUGIN}) - add_subdirectory(third_party/houdini) -endif() - if (${PXR_BUILD_PRMAN_PLUGIN}) add_subdirectory(third_party/renderman-${RENDERMAN_VERSION_MAJOR}) endif() diff --git a/build_scripts/build_usd.py b/build_scripts/build_usd.py index 44d11366e7..d9abe91226 100644 --- a/build_scripts/build_usd.py +++ b/build_scripts/build_usd.py @@ -1334,14 +1334,6 @@ def InstallUSD(context, force, buildArgs): else: extraArgs.append('-DPXR_BUILD_KATANA_PLUGIN=OFF') - if context.buildHoudini: - if context.houdiniLocation: - extraArgs.append('-DHOUDINI_ROOT="{houdiniLocation}"' - .format(houdiniLocation=context.houdiniLocation)) - extraArgs.append('-DPXR_BUILD_HOUDINI_PLUGIN=ON') - else: - extraArgs.append('-DPXR_BUILD_HOUDINI_PLUGIN=OFF') - if Windows(): # Increase the precompiled header buffer limit. extraArgs.append('-DCMAKE_CXX_FLAGS="/Zm150"') @@ -1588,16 +1580,6 @@ def InstallUSD(context, force, buildArgs): group.add_argument("--katana-api-location", type=str, help="Directory where the Katana SDK is installed.") -group = parser.add_argument_group(title="Houdini Plugin Options") -subgroup = group.add_mutually_exclusive_group() -subgroup.add_argument("--houdini", dest="build_houdini", action="store_true", - default=False, - help="Build Houdini plugin for USD") -subgroup.add_argument("--no-houdini", dest="build_houdini", action="store_false", - help="Do not build Houdini plugin for USD (default)") -group.add_argument("--houdini-location", type=str, - help="Directory where Houdini is installed.") - args = parser.parse_args() class InstallContext: @@ -1710,11 +1692,6 @@ def __init__(self, args): self.buildKatana = args.build_katana self.katanaApiLocation = (os.path.abspath(args.katana_api_location) if args.katana_api_location else None) - - # - Houdini Plugin - self.buildHoudini = args.build_houdini - self.houdiniLocation = (os.path.abspath(args.houdini_location) - if args.houdini_location else None) def GetBuildArguments(self, dep): return self.buildArgs.get(dep.name.lower(), []) @@ -1813,9 +1790,6 @@ def ForceBuildDependency(self, dep): if not context.buildPython: pythonPluginErrorMsg = ( "%s plugin cannot be built when python support is disabled") - if context.buildHoudini: - PrintError(pythonPluginErrorMsg % "Houdini") - sys.exit(1) if context.buildKatana: PrintError(pythonPluginErrorMsg % "Katana") sys.exit(1) @@ -1844,7 +1818,7 @@ def ForceBuildDependency(self, dep): # We should not attempt to build the plugins for any other DCCs if we're # building against Maya's version of Python. - if any([context.buildHoudini, context.buildKatana]): + if any([context.buildKatana]): PrintError("Cannot build plugins for other DCCs when building against " "Maya's version of Python.") sys.exit(1) @@ -1955,7 +1929,6 @@ def ForceBuildDependency(self, dep): Draco Plugin {buildDraco} MaterialX Plugin {buildMaterialX} Katana Plugin {buildKatana} - Houdini Plugin {buildHoudini} Dependencies {dependencies}""" @@ -2004,8 +1977,7 @@ def FormatBuildArguments(buildArgs): buildDraco=("On" if context.buildDraco else "Off"), buildMaterialX=("On" if context.buildMaterialX else "Off"), enableHDF5=("On" if context.enableHDF5 else "Off"), - buildKatana=("On" if context.buildKatana else "Off"), - buildHoudini=("On" if context.buildHoudini else "Off")) + buildKatana=("On" if context.buildKatana else "Off")) Print(summaryMsg) @@ -2084,10 +2056,6 @@ def FormatBuildArguments(buildArgs): Print("See documentation at http://openusd.org/docs/Katana-USD-Plugins.html " "for setting up the Katana plugin.\n") -if context.buildHoudini: - Print("See documentation at http://openusd.org/docs/Houdini-USD-Plugins.html " - "for setting up the Houdini plugin.\n") - if context.buildPrman: Print("See documentation at http://openusd.org/docs/RenderMan-USD-Imaging-Plugin.html " "for setting up the RenderMan plugin.\n") diff --git a/cmake/defaults/Options.cmake b/cmake/defaults/Options.cmake index 037daafd79..14a0a0741a 100644 --- a/cmake/defaults/Options.cmake +++ b/cmake/defaults/Options.cmake @@ -35,7 +35,6 @@ option(PXR_BUILD_USDVIEW "Build usdview" ON) option(PXR_BUILD_KATANA_PLUGIN "Build usd katana plugin" OFF) option(PXR_BUILD_ALEMBIC_PLUGIN "Build the Alembic plugin for USD" OFF) option(PXR_BUILD_DRACO_PLUGIN "Build the Draco plugin for USD" OFF) -option(PXR_BUILD_HOUDINI_PLUGIN "Build the Houdini plugin for USD" OFF) option(PXR_BUILD_PRMAN_PLUGIN "Build the PRMan imaging plugin" OFF) option(PXR_BUILD_MATERIALX_PLUGIN "Build the MaterialX plugin for USD" OFF) option(PXR_BUILD_DOCUMENTATION "Generate doxygen documentation" OFF) @@ -171,15 +170,6 @@ if (${PXR_BUILD_KATANA_PLUGIN}) endif() endif() -if (${PXR_BUILD_HOUDINI_PLUGIN}) - if (NOT ${PXR_ENABLE_PYTHON_SUPPORT}) - message(STATUS - "Setting PXR_BUILD_HOUDINI_PLUGIN=OFF because " - "PXR_ENABLE_PYTHON_SUPPORT=OFF") - set(PXR_BUILD_HOUDINI_PLUGIN "OFF" CACHE BOOL "" FORCE) - endif() -endif() - if (${PXR_BUILD_PRMAN_PLUGIN}) if (NOT ${PXR_BUILD_IMAGING}) message(STATUS diff --git a/cmake/defaults/Packages.cmake b/cmake/defaults/Packages.cmake index b879e51e83..1c101f758f 100644 --- a/cmake/defaults/Packages.cmake +++ b/cmake/defaults/Packages.cmake @@ -154,10 +154,6 @@ if (PXR_BUILD_KATANA_PLUGIN) ) endif() -if (PXR_BUILD_HOUDINI_PLUGIN) - find_package(Houdini REQUIRED) -endif() - if (PXR_BUILD_PRMAN_PLUGIN) find_package(Renderman REQUIRED) endif() diff --git a/cmake/modules/FindHoudini.cmake b/cmake/modules/FindHoudini.cmake deleted file mode 100644 index cb19b8b94f..0000000000 --- a/cmake/modules/FindHoudini.cmake +++ /dev/null @@ -1,156 +0,0 @@ -# -# Copyright 2017 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# -# - Find Houdini Development Kit -# -# Finds an installed Houdini Development Kit -# -# Variables that will be defined: -# HOUDINI_FOUND Defined if HDK installation has been detected -# HOUDINI_BASE_DIR Path to the root of the Houdini installation -# HOUDINI_INCLUDE_DIRS Path to the HDK include directories -# HOUDINI_LIB_DIRS Path to the HDK libraray directories -# HOUDINI_VERSION Full Houdini version, 16.0.596 for example -# HOUDINI_MAJOR_VERSION -# HOUDINI_MINOR_VERSION -# HOUDINI_BUILD_VERSION - -# -# In: -# HOUDINI_ROOT -# -# Out: -# HOUDINI_FOUND -# HOUDINI_VERSION -# HOUDINI_BUILD_VERSION -# HOUDINI_INCLUDE_DIRS -# HOUDINI_LIBRARY_DIRS -# HOUDINI_LIBRARIES -# HOUDINI_APPS1_LIBRARY -# HOUDINI_APPS2_LIBRARY -# HOUDINI_APPS3_LIBRARY -# HOUDINI_DEVICE_LIBRARY -# HOUDINI_GEO_LIBRARY -# HOUDINI_OP1_LIBRARY -# HOUDINI_OP2_LIBRARY -# HOUDINI_OP3_LIBRARY -# HOUDINI_OPZ_LIBRARY -# HOUDINI_PRM_LIBRARY -# HOUDINI_RAY_LIBRARY -# HOUDINI_SIM_LIBRARY -# HOUDINI_UI_LIBRARY -# HOUDINI_UT_LIBRARY - -find_path(HOUDINI_BASE_DIR - NAMES - houdini - HINTS - "${HOUDINI_ROOT}" - "$ENV{HOUDINI_ROOT}" - ) - -find_path(HOUDINI_INCLUDE_DIRS - UT/UT_Version.h - HINTS - "${HOUDINI_ROOT}" - "$ENV{HOUDINI_ROOT}" - "${HOUDINI_BASE_DIR}" - PATH_SUFFIXES - toolkit/include/ - DOC - "Houdini Development Kit Header Path" -) - -if (UNIX) - set(HOUDINI_LIB_NAME "libHoudiniGEO.so") - set(HOUDINI_LIB_PATH_SUFFIX "dsolib/") -elseif(WIN32) - set(HOUDINI_LIB_NAME "libGEO.lib") - set(HOUDINI_LIB_PATH_SUFFIX "custom/houdini/dsolib/") -endif() - -find_path(HOUDINI_LIB_DIRS - ${HOUDINI_LIB_NAME} - HINTS - "${HOUDINI_ROOT}" - "$ENV{HOUDINI_ROOT}" - "${HOUDINI_BASE_DIR}" - PATH_SUFFIXES - ${HOUDINI_LIB_PATH_SUFFIX} - DOC - "Houdini Development Kit Library Path" -) - -foreach(HOUDINI_LIB - APPS1 - APPS2 - APPS3 - DEVICE - GEO - OP1 - OP2 - OP3 - OPZ - PRM - RAY - SIM - UI - UT) - find_library(HOUDINI_${HOUDINI_LIB}_LIBRARY - Houdini${HOUDINI_LIB} - HINTS - "${HOUDINI_LIB_DIRS}" - DOC - "Houdini's ${HOUDINI_LIB} library path" - NO_CMAKE_SYSTEM_PATH - ) - - if (HOUDINI_${HOUDINI_LIB}_LIBRARY) - list(APPEND HOUDINI_LIBRARIES ${HOUDINI_${HOUDINI_LIB}_LIBRARY}) - endif () -endforeach() - -if(HOUDINI_INCLUDE_DIRS AND EXISTS "${HOUDINI_INCLUDE_DIRS}/SYS/SYS_Version.h") - foreach(comp FULL MAJOR MINOR BUILD) - file(STRINGS - ${HOUDINI_INCLUDE_DIRS}/SYS/SYS_Version.h - TMP - REGEX "#define SYS_VERSION_${comp} .*$") - string(REGEX MATCHALL "[0-9.]+" HOUDINI_${comp}_VERSION ${TMP}) - endforeach() -endif() - -set(HOUDINI_VERSION ${HOUDINI_FULL_VERSION}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Houdini - REQUIRED_VARS - HOUDINI_BASE_DIR - HOUDINI_INCLUDE_DIRS - HOUDINI_LIB_DIRS - VERSION_VAR - HOUDINI_VERSION -) - - - diff --git a/third_party/houdini/CMakeLists.txt b/third_party/houdini/CMakeLists.txt deleted file mode 100644 index 0b01d7309a..0000000000 --- a/third_party/houdini/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -if (APPLE) - message(WARNING "Skipping third_party/houdini because the Houdini plugin is not supported on MacOS") - return() -elif (WIN32) - message(WARNING "The Houdini plugin is not supported on Windows") -endif() - -set(PXR_INSTALL_SUBDIR "third_party/houdini") - -add_definitions( - -DHOUDINI_API_VERSION=${HOUDINI_MAJOR_VERSION}${HOUDINI_MINOR_VERSION} - -DVERSION="${HOUDINI_VERSION}" - -DHOUDINI_DOT_VERSION=${HOUDINI_BUILD_VERSION} ) - -if (UNIX) - - add_definitions( -fpermissive -D_GNU_SOURCE -DLINUX -DAMD64 -DSIZEOF_VOID_P=8 -DFBX_ENABLED=1 -DOPENCL_ENABLED=1 -DOPENVDB_ENABLED=1 -DMAKING_DSO -DSESI_LITTLE_ENDIAN -DENABLE_THREADS -DUSE_PTHREADS -D_REENTRANT -D_FILE_OFFSET_BITS=64 -DGCC4 -DGCC3 -Wall -Wno-parentheses -Wno-sign-compare -Wno-reorder -Wno-uninitialized -Wunused -Wno-unused-parameter -Wno-unused-local-typedefs -Wno-empty-body -fno-strict-aliasing ) - -elseif(WIN32) - - # Note that most of these extra definitions come from running hcustom - add_definitions(-nologo -TP -Zc:forScope -Zc:rvalueCast -Zc:strictStrings -DAMD64 -DSIZEOF_VOID_P=8 -DI386 -DWIN32 -DSWAP_BITFIELDS -D_WIN32_WINNT=0x0502 -DNOMINMAX -DSTRICT -DWIN32_LEAN_AND_MEAN -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -DSESI_LITTLE_ENDIAN -DHBOOST_ALL_NO_LIB -DEIGEN_MALLOC_ALREADY_ALIGNED=0 -DFBX_ENABLED=1 -DOPENCL_ENABLED=1 -DOPENVDB_ENABLED=1 -DMAKING_DSO) - - set(CMAKE_SHARED_LINKER_FLAGS "\"${HOUDINI_LIB_DIRS}/*.a\" \"${HOUDINI_LIB_DIRS}/*.lib\"" ) -endif() - -add_subdirectory(gusd) -add_subdirectory(plugin) diff --git a/third_party/houdini/README.md b/third_party/houdini/README.md index bbb9ec6a66..0b080b8525 100644 --- a/third_party/houdini/README.md +++ b/third_party/houdini/README.md @@ -1,6 +1,2 @@ -Houdini Plugins -=============== - -This section contains libraries and plugins for Houdini. - -See the [online documentation](http://openusd.org/docs/Houdini-USD-Plugins.html) for more details. +The USD Houdini plugins have been deprecated in favor of Houdini's +native Solaris suite (also known as LOPs). diff --git a/third_party/houdini/gusd/CMakeLists.txt b/third_party/houdini/gusd/CMakeLists.txt deleted file mode 100644 index 61ada4ace1..0000000000 --- a/third_party/houdini/gusd/CMakeLists.txt +++ /dev/null @@ -1,143 +0,0 @@ - -set(PXR_PACKAGE gusd) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${HOUDINI_DEFINITIONS}") - -if (UNIX) - set(HOUDINI_LIB_NAMES - ${HOUDINI_UI_LIBRARY} - ${HOUDINI_OPZ_LIBRARY} - ${HOUDINI_OP3_LIBRARY} - ${HOUDINI_OP2_LIBRARY} - ${HOUDINI_OP1_LIBRARY} - ${HOUDINI_SIM_LIBRARY} - ${HOUDINI_GEO_LIBRARY} - ${HOUDINI_PRM_LIBRARY} - ${HOUDINI_UT_LIBRARY}) -elseif(WIN32) - # The library names on Windows don't match the linux ones, so we have a - # higher level CMakeLists.txt that links in all the Houdini libraries always - # on Windows. Future work on this would be to consolidate these two - # mechanisms. - set(HOUDINI_LIB_NAMES "") -endif() - - -pxr_shared_library(${PXR_PACKAGE} - LIBRARIES - ar - gf - sdf - tf - usd - usdGeom - usdRi - usdShade - usdSkel - usdUtils - ${HOUDINI_LIB_NAMES} - - INCLUDE_DIRS - ${HOUDINI_INCLUDE_DIRS} - - PUBLIC_CLASSES - agentUtils - boundsCache - curvesWrapper - debugCodes - error - groupBaseWrapper - instancerWrapper - meshWrapper - packedUsdWrapper - pointsWrapper - primWrapper - purpose - refiner - scopeWrapper - shaderWrapper - stageCache - stageEdit - tokens - valueUtils - writeCtrlFlags - xformWrapper - GEO_IOTranslator - GT_OldPointInstancer - GT_PackedUSD - GT_PointInstancer - GT_PrimCache - GT_Utils - GU_PackedUSD - GU_USD - NURBSCurvesWrapper - OP_ParmChangeMicroNode - PRM_Shared - USD_CustomTraverse - USD_DataCache - USD_StdTraverse - USD_ThreadedTraverse - USD_Traverse - USD_Utils - USD_VisCache - USD_XformCache - UT_TypeTraits - - PUBLIC_HEADERS - api.h - context.h - defaultArray.h - gusd.h - stageOpts.h - GT_VtArray.h - GU_USD.h - USD_PropertyMap.h - USD_TraverseSimple.h - UT_Assert.h - UT_CappedCache.h - UT_Gf.h - UT_StaticInit.h - UT_Version.h - - PRIVATE_HEADERS - GT_VtStringArray.h - UT_VtArray.h - - CPPFILES - plugin.cpp - - PYMODULE_FILES - __init__.py - treemodel.py - treeview.py - - PYMODULE_CPPFILES - module.cpp - wrapStageCache.cpp - wrapStageEdit.cpp - wrapStageOpts.cpp -) - -file(GLOB ICON_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "site/icons/*") - -install( - FILES - ${ICON_FILES} - DESTINATION - ${PXR_INSTALL_SUBDIR}/config/Icons -) - -# Disabling temporarily: need to resolve tbb link errors. -#pxr_build_test(testGusdErrors -# LIBRARIES -# gusd -# tf -# ${HOUDINI_UT_LIBRARY} -# CPPFILES -# testenv/testGusdErrors.cpp -#) - -#pxr_register_test(testGusdErrors -# COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testGusdErrors" -# EXPECTED_RETURN_CODE 0 -#) diff --git a/third_party/houdini/gusd/GEO_IOTranslator.cpp b/third_party/houdini/gusd/GEO_IOTranslator.cpp deleted file mode 100644 index b6b569d378..0000000000 --- a/third_party/houdini/gusd/GEO_IOTranslator.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GEO_IOTranslator.h" - -#include "GU_PackedUSD.h" - -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -// drand48 and srand48 defined in SYS_Math.h as of 13.5.153. and conflicts with imath. -#undef drand48 -#undef srand48 - -using std::cerr; -using std::endl; - -//############################################################################## -// class GusdGEO_IOTranslator implementation -//############################################################################## -GusdGEO_IOTranslator:: -GusdGEO_IOTranslator() -{} - - -GusdGEO_IOTranslator:: -~GusdGEO_IOTranslator() -{} - - -GEO_IOTranslator* GusdGEO_IOTranslator:: -duplicate() const -{ - return new GusdGEO_IOTranslator(*this); -} - - -const char* GusdGEO_IOTranslator:: -formatName() const -{ - return "Universal Scene Description"; -} - - -int GusdGEO_IOTranslator:: -checkExtension(const char* name) -{ - UT_String nameStr(name); - if(nameStr.fileExtension() - && (!strcmp(nameStr.fileExtension(), ".usd") - || !strcmp(nameStr.fileExtension(), ".usda") - || !strcmp(nameStr.fileExtension(), ".usdc"))) { - return true; - } - return false; -} - - -int GusdGEO_IOTranslator:: -checkMagicNumber(unsigned /*number*/) -{ - return 0; -} - - -GA_Detail::IOStatus GusdGEO_IOTranslator:: -fileLoad(GEO_Detail* gdp, UT_IStream& is, bool ate_magic) -{ - UT_WorkBuffer buffer; - if(!is.isRandomAccessFile(buffer)) { - return GA_Detail::IOStatus(false); - } - - const std::string fileName = buffer.toStdString(); - auto stage = UsdStage::Open( fileName, UsdStage::LoadNone); - if( !stage ) { - return GA_Detail::IOStatus( false ); - } - - float f = 1.0; - - if (CH_Manager::getContextExists()) - CHgetSampleFromTime( CHgetEvalTime() ); - - GU_Detail* detail = dynamic_cast(gdp); - if( !detail ) { - return GA_Detail::IOStatus( false ); - } - - // If the file contains a default prim, load that, otherwise load - // all the top level prims. - auto defPrim = stage->GetDefaultPrim(); - if( defPrim ) { - GusdGU_PackedUSD::Build(*detail, fileName, defPrim.GetPath(), f, NULL, - GusdPurposeSet(GUSD_PURPOSE_DEFAULT | - GUSD_PURPOSE_PROXY)); - } - else { - for( const auto &child : stage->GetPseudoRoot().GetChildren() ) { - GusdGU_PackedUSD::Build(*detail, fileName, child.GetPath(), f, NULL, - GusdPurposeSet(GUSD_PURPOSE_DEFAULT | - GUSD_PURPOSE_PROXY)); - } - } - - return GA_Detail::IOStatus(true); -} - - -GA_Detail::IOStatus GusdGEO_IOTranslator:: -fileSave(const GEO_Detail*, std::ostream&) -{ - return 0; -} - -PXR_NAMESPACE_CLOSE_SCOPE - -//############################################################################## - - diff --git a/third_party/houdini/gusd/GEO_IOTranslator.h b/third_party/houdini/gusd/GEO_IOTranslator.h deleted file mode 100644 index 140b84e360..0000000000 --- a/third_party/houdini/gusd/GEO_IOTranslator.h +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GEO_IOTRANSLATOR_H -#define GUSD_GEO_IOTRANSLATOR_H - -#include "pxr/pxr.h" - -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdGEO_IOTranslator : public GEO_IOTranslator -{ -public: - GusdGEO_IOTranslator(); - virtual ~GusdGEO_IOTranslator(); - - // GEO_IOTranslator interface ---------------------------------------------- - -public: - virtual GEO_IOTranslator* duplicate() const; - - virtual const char* formatName() const; - - virtual int checkExtension(const char* name); - - virtual int checkMagicNumber(unsigned magic); - - virtual GA_Detail::IOStatus fileLoad(GEO_Detail*, UT_IStream&, bool ate_magic); - - virtual GA_Detail::IOStatus fileSave(const GEO_Detail*, std::ostream&); - - // ------------------------------------------------------------------------- -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_GEO_IOTRANSLATOR_H diff --git a/third_party/houdini/gusd/GT_OldPointInstancer.cpp b/third_party/houdini/gusd/GT_OldPointInstancer.cpp deleted file mode 100644 index ffd238fb94..0000000000 --- a/third_party/houdini/gusd/GT_OldPointInstancer.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GT_OldPointInstancer.h" - -namespace { -int s_gtOldPointInstancerPrimId = GT_PRIM_UNDEFINED; -} - -GusdGT_OldPointInstancer::~GusdGT_OldPointInstancer() -{ -} - -/* static */ -int -GusdGT_OldPointInstancer::getStaticPrimitiveType() -{ - if( s_gtOldPointInstancerPrimId == GT_PRIM_UNDEFINED ) - s_gtOldPointInstancerPrimId = GT_Primitive::createPrimitiveTypeId(); - return s_gtOldPointInstancerPrimId; -} - - -int -GusdGT_OldPointInstancer::getPrimitiveType() const -{ - return getStaticPrimitiveType(); -} \ No newline at end of file diff --git a/third_party/houdini/gusd/GT_OldPointInstancer.h b/third_party/houdini/gusd/GT_OldPointInstancer.h deleted file mode 100644 index b9be4c7470..0000000000 --- a/third_party/houdini/gusd/GT_OldPointInstancer.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_OLD_POINT_INSTANCER_H -#define GUSD_GT_OLD_POINT_INSTANCER_H - -#include - -/// A GusdGT_PointInstancer is identical to a GT_PrimPointMesh except -/// that it is treated differently by the GusdRefiner and has -/// a different GusdPrimWrapper. - -class GusdGT_OldPointInstancer : public GT_PrimPointMesh -{ -public: - GusdGT_OldPointInstancer() {} - GusdGT_OldPointInstancer(const GT_AttributeListHandle &points, - const GT_AttributeListHandle &uniform) : - GT_PrimPointMesh( points, uniform ) - { - } - GusdGT_OldPointInstancer(const GusdGT_OldPointInstancer &src) : - GT_PrimPointMesh( src ) - { - } - virtual ~GusdGT_OldPointInstancer(); - - virtual const char *className() const override { return "GusdGT_OldPointInstancer"; } - - static int getStaticPrimitiveType(); - - virtual int getPrimitiveType() const override; -}; - -#endif // GUSD_GT_OLD_POINT_INSTANCER_H \ No newline at end of file diff --git a/third_party/houdini/gusd/GT_PackedUSD.cpp b/third_party/houdini/gusd/GT_PackedUSD.cpp deleted file mode 100644 index 5b4c10b189..0000000000 --- a/third_party/houdini/gusd/GT_PackedUSD.cpp +++ /dev/null @@ -1,833 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GT_PackedUSD.h" - -#include "GT_Utils.h" -#include "GU_PackedUSD.h" -#include "GU_USD.h" -#include "UT_Gf.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pxr/usd/usdGeom/xformCache.h" - -#include -#include - -using std::cout; -using std::cerr; -using std::endl; -using std::string; -using std::map; -using std::vector; - -//#define DEBUG - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -namespace std { - -template <> -struct hash -{ - size_t operator()(const UT_Options& options) const - { - return static_cast(options.hash()); - } -}; - -} - -PXR_NAMESPACE_OPEN_SCOPE - -namespace { - -int s_gtPackedUsdPrimId = GT_PRIM_UNDEFINED; -int s_gtPrimInstanceColorId = GT_PRIM_UNDEFINED; -int s_gtPackedUsdMeshId = GT_PRIM_UNDEFINED; - -struct _ViewportAttrFilter : public GT_GEOAttributeFilter -{ - virtual bool isValid(const GA_Attribute& attrib) const - { - // TODO Verify atts have correct type and dimension. - return attrib.getName() == "__primitive_id" - || attrib.getName() == GA_Names::Cd; - } -}; - -// GT_PrimInstanceWithColor is used to visualize PackedUSD prims which have a -// Cd attribute assigned. Unlike GT_PrimInstance, it will pass down Cd when it -// refines. This scheme breaks GL instancing and is potentially much slower to -// draw than GT_PrimInstance. We should have a first-class way to do this in -// the HDK. -class GT_PrimInstanceWithColor : public GT_PrimInstance -{ -public: - GT_PrimInstanceWithColor( - const GT_PrimitiveHandle &geometry, - const GT_TransformArrayHandle& transforms, - const GT_GEOOffsetList& packed_prim_offsets=GT_GEOOffsetList(), - const GT_AttributeListHandle& uniform=GT_AttributeListHandle(), - const GT_AttributeListHandle& detail=GT_AttributeListHandle(), - const GT_GEODetailListHandle& source=GT_GEODetailListHandle()) - : GT_PrimInstance( - geometry, - transforms, - packed_prim_offsets, - uniform, - detail, - source) - , m_uniformAttrs(uniform) - { - } - - GT_PrimInstanceWithColor(const GT_PrimInstanceWithColor& src) - : GT_PrimInstance(src) - , m_uniformAttrs( src.m_uniformAttrs ) - { - } - - virtual ~GT_PrimInstanceWithColor() - {} - - virtual int getPrimitiveType() const - { - if( s_gtPrimInstanceColorId == GT_PRIM_UNDEFINED ) - s_gtPrimInstanceColorId = GT_Primitive::createPrimitiveTypeId(); - return s_gtPrimInstanceColorId; - } - - virtual const char* className() const - { - return "GT_PrimInstanceWithColor"; - } - - - inline GT_AttributeListHandle - appendAttrs( GT_AttributeListHandle dest, int i ) const - { - if( dest && m_uniformAttrs ) { - if( auto colorArray = m_uniformAttrs->get( GA_Names::Cd, 0 )) { - dest = dest->addAttribute( - GA_Names::Cd, - new GT_DASubArray( colorArray, i, 1), true ); - } - auto idArray = m_uniformAttrs->get( "__primitive_id", 0 ); - if( idArray ) { - dest = dest->addAttribute( - "__primitive_id", - new GT_DASubArray( idArray, i, 1), true ); - } - } - return dest; - } - - virtual bool refine(GT_Refine& refiner, const GT_RefineParms* parms=NULL) const - { - GT_RefineCollect refineCollect; - GT_PrimInstance::refine(refineCollect, parms); - for(int i=0; igetPrimitiveType() == GT_PRIM_INSTANCE) { - auto instPrim = UTverify_cast(curPrim.get()); - curPrim.reset(new GT_PrimInstanceWithColor( - instPrim->geometry(), - instPrim->transforms(), - instPrim->packedPrimOffsets(), - m_uniformAttrs)); - } - else if(curPrim->getPrimitiveType() == GT_PRIM_SUBDIVISION_MESH) { - auto meshPrim = UTverify_cast(curPrim.get()); - curPrim.reset(new GT_PrimSubdivisionMesh( - *meshPrim, - meshPrim->getShared(), - meshPrim->getVertex(), - meshPrim->getUniform(), - appendAttrs( meshPrim->getDetail(), i ))); - } - else if(curPrim->getPrimitiveType() == GT_PRIM_POLYGON_MESH) { - auto meshPrim = UTverify_cast(curPrim.get()); - curPrim.reset(new GT_PrimPolygonMesh( - *meshPrim, - meshPrim->getShared(), - meshPrim->getVertex(), - meshPrim->getUniform(), - appendAttrs( meshPrim->getDetail(), i ))); - } - - refiner.addPrimitive(curPrim); - } - return true; - } - -private: - GT_AttributeListHandle m_uniformAttrs; -}; - -// ----------------------------------------------------------------------------- - -///////////////////////////////////////////////////////////////////////////////// - - -class CollectData : public GT_GEOPrimCollectData -{ -public: - CollectData( - const GT_GEODetailListHandle &geometry, - bool useViewportLOD, - bool refineToUSD) - : GT_GEOPrimCollectData(), - _geometry(geometry), - _useViewportLOD(useViewportLOD), - _refineToUSD(refineToUSD) - { - } - - virtual ~CollectData() - { - } - - bool append(const GU_PrimPacked &prim) - { - const GusdGU_PackedUSD *impl = - UTverify_cast(prim.implementation()); - - if (!impl->visibleGT()) - return true; - - if (!_refineToUSD) - { - if( _useViewportLOD ) - { - switch (prim.viewportLOD()) - { - case GEO_VIEWPORT_HIDDEN: - return true; // Handled - case GEO_VIEWPORT_CENTROID: - _centroidPrims.append(&prim); - return true; - case GEO_VIEWPORT_BOX: - _boxPrims.append(&prim); - return true; - case GEO_VIEWPORT_FULL: - _geoPrims.append(&prim); - return true; - default: - // Fall through to generic handling - break; - } - } - else - { - _geoPrims.append(&prim); - return true; - } - } - return false; - } - - class FillTask - { - public: - FillTask(UT_BoundingBox *boxes, - UT_Matrix4F *xforms, - const UT_Array&prims) - : myBoxes(boxes) - , myXforms(xforms) - , myPrims(prims) - { - } - void operator()(const UT_BlockedRange &range) const - { - UT_Matrix4D m4d; - for (exint i = range.begin(); i != range.end(); ++i) - { - const GU_PrimPacked &prim = *myPrims(i); - prim.getUntransformedBounds(myBoxes[i]); - prim.getFullTransform4(m4d); - myXforms[i] = m4d; - } - } - private: - UT_BoundingBox *myBoxes; - UT_Matrix4F *myXforms; - const UT_Array &myPrims; - }; - - void - addInstances( - GT_PrimCollect& collection, - GT_PrimitiveHandle geo, - const UT_Array& instances ) const - { - GT_GEOOffsetList primOffsetList; - GT_GEOOffsetList vtxOffsetList; - GT_TransformArrayHandle xformArray(new GT_TransformArray()); - - // Work around a SideFx Bug. If the geo has a non-identity transform, - // Houdini will draw the instance prim ok but does weird frustum culling. - UT_Matrix4D geoMat( 1 ); - auto geoTransform = geo->getPrimitiveTransform(); - geoTransform->getMatrix( geoMat ); - if( !geoMat.isIdentity() ) - { - geo = geo->clone(); - geo->setPrimitiveTransform( GT_Transform::identity() ); - } - - // get the offsets and transforms for each prim - for(auto const &packedPrim : instances ) { - - primOffsetList.append(packedPrim->getMapOffset()); - vtxOffsetList.append(packedPrim->getVertexOffset(0)); - - UT_Matrix4D instXform; - packedPrim->getFullTransform4(instXform); - UT_Matrix4D m = geoMat * instXform; - xformArray->append( new GT_Transform( &m, 1 )); - } - - // Copy __primitive_id attribute to support viewport picking - _ViewportAttrFilter filter; - GT_AttributeListHandle uniformAttrs - = _geometry->getPrimitiveVertexAttributes( - filter, primOffsetList, vtxOffsetList); - - GT_PrimInstance* gtInst; - if( uniformAttrs->hasName( GA_Names::Cd )) { - gtInst = new GT_PrimInstanceWithColor( - geo, - xformArray, - primOffsetList, - uniformAttrs ); - } - else { - gtInst = new GT_PrimInstance( - geo, - xformArray, - primOffsetList, - uniformAttrs ); - } - collection.appendPrimitive( gtInst ); - } - - GT_PrimitiveHandle finish() const - { - DBG( cerr << "CollectData::finish" << endl ); - - exint ngeo = _geoPrims.entries(); - exint nbox = _boxPrims.entries(); - exint ncentroid = _centroidPrims.entries(); - exint nproxies = SYSmax(nbox, ncentroid); - - if (!ngeo && !nproxies) - return GT_PrimitiveHandle(); - - GT_GEOPrimCollectBoxes boxdata(_geometry, true); - UT_StackBuffer boxes(nproxies); - UT_StackBuffer xforms(nproxies); - - GT_PrimCollect* rv = new GT_PrimCollect(); - - if (nbox) - { - //UTparallelFor(UT_BlockedRange(0, nbox), - UTserialFor(UT_BlockedRange(0, nbox), - FillTask(boxes, xforms, _boxPrims)); - for (exint i = 0; i < nbox; ++i) - { - boxdata.appendBox(boxes[i], xforms[i], - _boxPrims(i)->getMapOffset(), - _boxPrims(i)->getVertexOffset(0), - _boxPrims(i)->getPointOffset(0)); - } - rv->appendPrimitive(boxdata.getPrimitive()); - - } - if (ncentroid) - { - //UTparallelFor(UT_BlockedRange(0, ncentroid), - UTserialFor(UT_BlockedRange(0, ncentroid), - FillTask(boxes, xforms, _centroidPrims)); - for (exint i = 0; i < ncentroid; ++i) - { - boxdata.appendCentroid(boxes[i], xforms[i], - _centroidPrims(i)->getMapOffset(), - _centroidPrims(i)->getVertexOffset(0), - _centroidPrims(i)->getPointOffset(0)); - } - rv->appendPrimitive(boxdata.getPrimitive()); - } - - if( ngeo ) { - - // sort packed prims into collections of identical instances - std::unordered_map > - instanceMap; - - for( auto const & prim : _geoPrims ) { - - auto impl = - UTverify_cast(prim->implementation()); - - UT_Options instanceKey; - impl->getInstanceKey(instanceKey); - auto instanceMapIt = instanceMap.find(instanceKey); - if (instanceMapIt == instanceMap.end()) - { - UT_Array prims; - prims.append(prim); - instanceMap[instanceKey] = prims; - } - else - { - instanceMapIt->second.append(prim); - } - } - - // Iterate over groups of instances - for( auto const &kv : instanceMap ) { - - auto const & instancePrims = kv.second; - - auto impl = - UTverify_cast(instancePrims(0)->implementation()); - - // Use the first prim for geometry - GT_PrimitiveHandle geo = impl->fullGT(); - - if( !geo ) - continue; - - if( geo->getPrimitiveType() == GT_PRIM_COLLECT ) { - auto collect = UTverify_cast( geo.get() ); - - for( int i = 0; i < collect->entries(); ++i ) { - addInstances( *rv, collect->getPrim(i), kv.second ); - } - } - else { - addInstances( *rv, geo, kv.second ); - } - } - } - return rv; - } - - bool refineToUSD() { return _refineToUSD; } - -private: - const GT_GEODetailListHandle _geometry; - UT_Array _boxPrims; - UT_Array _centroidPrims; - UT_Array _geoPrims; - bool _useViewportLOD; - bool _refineToUSD; -}; - -} // close anonymous namespace - -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -// class GusdGT_PackedUSD implementation -//////////////////////////////////////////////////////////////////////////////// - -GusdGT_PackedUSD:: -GusdGT_PackedUSD( - const UT_StringHolder& fileName, - const UT_StringHolder& auxFileName, - const SdfPath& primPath, - const SdfPath& srcPrimPath, - exint instanceIndex, - UsdTimeCode frame, - GusdPurposeSet, - GT_AttributeListHandle pointAttributes, - GT_AttributeListHandle vertexAttributes, - GT_AttributeListHandle uniformAttributes, - GT_AttributeListHandle detailAttributes, - const GU_PrimPacked* prim) - : m_fileName(fileName) - , m_auxFileName(auxFileName) - , m_primPath(primPath) - , m_srcPrimPath(srcPrimPath) - , m_instanceIndex(instanceIndex) - , m_frame(frame) - , m_pointAttributes(pointAttributes) - , m_vertexAttributes(vertexAttributes) - , m_uniformAttributes(uniformAttributes) - , m_detailAttributes(detailAttributes) -{ - UTverify_cast(prim->implementation())->getBounds( m_box ); -} - -GusdGT_PackedUSD:: -GusdGT_PackedUSD(const GusdGT_PackedUSD& other) - : GT_Primitive( other ) - , m_fileName(other.m_fileName) - , m_auxFileName(other.m_auxFileName) - , m_primPath(other.m_primPath) - , m_srcPrimPath(other.m_srcPrimPath) - , m_instanceIndex(other.m_instanceIndex) - , m_frame(other.m_frame) - , m_pointAttributes(other.m_pointAttributes) - , m_vertexAttributes(other.m_vertexAttributes) - , m_uniformAttributes(other.m_uniformAttributes) - , m_detailAttributes(other.m_detailAttributes) - , m_box(other.m_box) -{ -} - - -GusdGT_PackedUSD:: -~GusdGT_PackedUSD() -{} - - -const char* GusdGT_PackedUSD:: -className() const -{ return "GusdGT_PackedUSD"; } - - -GT_PrimitiveHandle GusdGT_PackedUSD:: -doSoftCopy() const -{ return new GusdGT_PackedUSD(*this); } - - -/* static */ -int GusdGT_PackedUSD:: -getStaticPrimitiveType() -{ - if( s_gtPackedUsdPrimId == GT_PRIM_UNDEFINED ) - s_gtPackedUsdPrimId = GT_Primitive::createPrimitiveTypeId(); - return s_gtPackedUsdPrimId; -} - - -int GusdGT_PackedUSD:: -getPrimitiveType() const -{ - return getStaticPrimitiveType(); -} - -void GusdGT_PackedUSD:: -enlargeBounds(UT_BoundingBox boxes[], - int nsegments) const -{ - for( size_t i = 0; i < nsegments; ++i ) - boxes[i].enlargeBounds( m_box ); -} - -int GusdGT_PackedUSD:: -getMotionSegments() const -{ - return 1; -} - -int64 GusdGT_PackedUSD:: -getMemoryUsage() const -{ - return sizeof(*this); -} - -const GT_AttributeListHandle& GusdGT_PackedUSD:: -getPointAttributes() const -{ - return m_pointAttributes; -} - -const GT_AttributeListHandle& GusdGT_PackedUSD:: -getVertexAttributes() const -{ - return m_vertexAttributes; -} - -const GT_AttributeListHandle& GusdGT_PackedUSD:: -getUniformAttributes() const -{ - return m_uniformAttributes; -} - -const GT_AttributeListHandle& GusdGT_PackedUSD:: -getDetailAttributes() const -{ - return m_detailAttributes; -} -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -// class GusdGT_PackedUSDMesh implementation -//////////////////////////////////////////////////////////////////////////////// - -GusdGT_PackedUSDMesh:: -GusdGT_PackedUSDMesh( - const GT_PrimitiveHandle& mesh, - int64 id, - UT_Array& sourceMeshes) - : m_mesh(mesh) - , m_id(id) - , m_sourceMeshes(sourceMeshes) -{ -} - -GusdGT_PackedUSDMesh:: -~GusdGT_PackedUSDMesh() -{ -} - -const char* GusdGT_PackedUSDMesh:: -className() const -{ - return "GusdGT_PackedUSDMesh"; -} - -/* static */ -int GusdGT_PackedUSDMesh:: -getStaticPrimitiveType() -{ - if( s_gtPackedUsdMeshId == GT_PRIM_UNDEFINED ) { -#if SYS_VERSION_FULL_INT >= 0x10050000 - // XXX There appears to be a bug in 16.5 that prevents primitives - // with custom primitive ids to refine in the viewport. As a - // workaround we'll use GT_PRIM_ALEMBIC_SHAPE_MESH for now. - s_gtPackedUsdMeshId = GT_PRIM_ALEMBIC_SHAPE_MESH; -#else - s_gtPackedUsdMeshId = GT_Primitive::createPrimitiveTypeId(); -#endif - } - return s_gtPackedUsdMeshId; -} - -int GusdGT_PackedUSDMesh:: -getPrimitiveType() const -{ - //return GT_PRIM_UNDEFINED; - return getStaticPrimitiveType(); -} - -GT_PrimitiveHandle GusdGT_PackedUSDMesh:: -doSoftCopy() const -{ - return new GusdGT_PackedUSDMesh(*this); -} - -bool GusdGT_PackedUSDMesh:: -refine(GT_Refine& refiner, const GT_RefineParms* /*parms*/) const -{ - if(m_mesh) { - refiner.addPrimitive(m_mesh->copyTransformed( - this->getPrimitiveTransform())); - return true; - } - return false; -} - -void GusdGT_PackedUSDMesh:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - if(m_mesh) { - m_mesh->enlargeBounds(boxes, nsegments); - } -} - -int GusdGT_PackedUSDMesh:: -getMotionSegments() const -{ - if(m_mesh) { - return m_mesh->getMotionSegments(); - } - return 1; -} - -int64 GusdGT_PackedUSDMesh:: -getMemoryUsage() const -{ - int64 size = sizeof(*this); - - if(m_mesh) { - size += m_mesh->getMemoryUsage(); - } - for(const auto& p : m_sourceMeshes) { - size += p->getMemoryUsage(); - } - - return size; -} - -bool GusdGT_PackedUSDMesh:: -getUniqueID(int64& id) const -{ - id = m_id; - return true; -} -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -// class GusdGT_PrimCollect implementation -//////////////////////////////////////////////////////////////////////////////// - -GusdGT_PrimCollect::~GusdGT_PrimCollect() -{ -} - -GT_GEOPrimCollectData * -GusdGT_PrimCollect::beginCollecting( - const GT_GEODetailListHandle& geometry, - const GT_RefineParms* parms) const -{ - return new CollectData( - geometry, - GT_GEOPrimPacked::useViewportLOD(parms), - parms ? parms->get( "refineToUSD", false) : false ); -} - -class FilterUnderscore : public GT_GEOAttributeFilter { - - virtual bool isValid( const GA_Attribute &attrib ) const { - if( !GT_GEOAttributeFilter::isValid(attrib) ) - return false; - const char *n = attrib.getName().buffer(); - if( n == NULL || (strlen( n ) >= 1 && n[0] == '_' )) { - return false; - } - return true; - } -}; - -GT_PrimitiveHandle -GusdGT_PrimCollect::collect( - const GT_GEODetailListHandle &geo, - const GEO_Primitive *const* prim_list, - int nsegments, - GT_GEOPrimCollectData *data) const -{ - CollectData *collector = data->asPointer(); - const GU_PrimPacked *pack = - UTverify_cast(prim_list[0]); - - // If the prim is something simple that can be drawn in bulk (bbox or centroid), - // append to a list. - if (!collector->append(*pack)) - { - const GusdGU_PackedUSD *impl = - UTverify_cast(pack->implementation()); - - // if writing to a usd file we return a GusdGT_PackedUSD which can be interpreted - // as a usd reference - if(collector->refineToUSD()) - { - UT_Matrix4D m; - pack->getFullTransform4(m); - GT_TransformHandle xform(new GT_Transform(&m, 1)); - - FilterUnderscore filter; - GT_GEOOffsetList pointOffsets, vertexOffsets, primOffsets; - - pointOffsets.append( prim_list[0]->getPointOffset(0) ); - vertexOffsets.append( prim_list[0]->getVertexOffset(0) ); - primOffsets.append( prim_list[0]->getMapOffset() ); - GT_AttributeListHandle uniformAttrs - = geo->getPrimitiveAttributes(filter, &primOffsets); - - GusdGT_PackedUSD* gtPrim = - new GusdGT_PackedUSD( impl->fileName(), - impl->altFileName(), - impl->primPath(), - impl->srcPrimPath(), - impl->index(), - impl->frame(), - impl->getPurposes(), - geo->getPointAttributes( filter, &pointOffsets ), - geo->getVertexAttributes( filter, &vertexOffsets ), - geo->getPrimitiveAttributes( filter, &primOffsets ), - geo->getDetailAttributes( filter ), - pack ); - gtPrim->setPrimitiveTransform(xform); - - return gtPrim; - } - } - return GT_PrimitiveHandle(); -} - -GT_PrimitiveHandle -GusdGT_PrimCollect::endCollecting( - const GT_GEODetailListHandle &geometry, - GT_GEOPrimCollectData *data) const -{ - CollectData *collector = data->asPointer(); - GT_PrimitiveHandle rv = collector->finish(); -#ifdef DEBUG - cerr << "endCollecting, rv type = " << rv->className() << endl; - if( rv->getPrimitiveType() == GT_PRIM_COLLECT ) { - const GT_PrimCollect* collect = UTverify_cast(rv.get()); - cerr << "collection entries = " << collect->entries() << endl; - for( exint i = 0; i < collect->entries(); ++i ) { - GT_PrimitiveHandle p = collect->getPrim(i); - - cerr << "entry type = " << p->className() << endl; - if( p->getPrimitiveType() == GT_PRIM_INSTANCE ) { - const GT_PrimInstance* inst1 = UTverify_cast(p.get()); - - GT_PrimitiveHandle geo1 = inst1->geometry(); - cerr << "inst geo1 type = " << geo1->className() << endl; - - if( geo1->getPrimitiveType() == GT_PRIM_INSTANCE ) { - const GT_PrimInstance* inst2 = UTverify_cast(geo1.get()); - - GT_PrimitiveHandle geo2 = inst2->geometry(); - cerr << "inst geo2 type = " << geo2->className() << endl; - - } - } - } - } -#endif - return rv; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/GT_PackedUSD.h b/third_party/houdini/gusd/GT_PackedUSD.h deleted file mode 100644 index 7ea09cb0bb..0000000000 --- a/third_party/houdini/gusd/GT_PackedUSD.h +++ /dev/null @@ -1,221 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_PACKED_USD_H -#define GUSD_GT_PACKED_USD_H - -#include "api.h" -#include "purpose.h" - -#include "pxr/pxr.h" -#include "pxr/usd/sdf/path.h" -#include "pxr/usd/usd/timeCode.h" - -#include -#include - -class GU_PrimPacked; - -PXR_NAMESPACE_OPEN_SCOPE - -/// A GT implementation of a packed USD prim. -/// -/// This is a file backed prim that holds a reference to a prim in a usd file -/// at a particular frame. The prim can be a group of prims. -/// -/// When we write USD packed prim to a USD file, we write a reference to the -/// original file. USD has a limitation that it can only make references to root -/// nodes. -/// -/// When we write a reference into a USD file, we might want to use a different -/// file path than we use in the Houdini session. For example, we might want to -/// use a relative path vs. an absolute one. We might want to use a coalesced -/// file vs per frame files. We don't want to enshrine this logic in the core so -/// we provide a second "auxilary" file name that can be used for this. If -/// this fileName is left empty, we just us the primary file name. -/// - -class GusdGT_PackedUSD : public GT_Primitive -{ -public: - GusdGT_PackedUSD( - const UT_StringHolder& fileName, - const UT_StringHolder& auxFileName, - const SdfPath& primPath, - const SdfPath& srcPrimPath, - exint index, - UsdTimeCode frame, - GusdPurposeSet purpose, // Unused - GT_AttributeListHandle pointAttributes, - GT_AttributeListHandle vertexAttributes, - GT_AttributeListHandle uniformAttributes, - GT_AttributeListHandle detailAttributes, - const GU_PrimPacked* prim ); - - GusdGT_PackedUSD(const GusdGT_PackedUSD& other); - - virtual ~GusdGT_PackedUSD(); - - // GT_Primitive interface -------------------------------------------------- -public: - virtual const char* className() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - GUSD_API - static int getStaticPrimitiveType(); - - virtual int getPrimitiveType() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], - int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual const GT_AttributeListHandle& getPointAttributes() const override; - virtual const GT_AttributeListHandle& getVertexAttributes() const override; - virtual const GT_AttributeListHandle& getUniformAttributes() const override; - virtual const GT_AttributeListHandle& getDetailAttributes() const override; - - // ------------------------------------------------------------------------- - - // Get the name of the referenced USD file - const UT_StringHolder& getFileName() const { return m_fileName; } - - // Get the name of the referenced USD file - const UT_StringHolder& getAuxFileName() const { return m_auxFileName; } - - // Get the node path in the referenced USD file - const SdfPath& getPrimPath() const { return m_primPath; } - - const SdfPath& getSrcPrimPath() const { return m_srcPrimPath; } - - const exint& getInstanceIndex() const { return m_instanceIndex; } - -private: - UT_StringHolder m_fileName; - UT_StringHolder m_auxFileName; - SdfPath m_primPath; - SdfPath m_srcPrimPath; - exint m_instanceIndex; - UsdTimeCode m_frame; - UT_BoundingBox m_box; - - GT_AttributeListHandle m_pointAttributes; - GT_AttributeListHandle m_vertexAttributes; - GT_AttributeListHandle m_uniformAttributes; - GT_AttributeListHandle m_detailAttributes; -}; - - -//------------------------------------------------------------------------------ -// class GusdGT_PackedUSDMesh -//------------------------------------------------------------------------------ - -/* - * A utility class which supports meshes which have been coalesced together - * for viewport efficiency. Based on GT_PackedAlembicMesh in the HDK. - */ - -class GusdGT_PackedUSDMesh : public GT_Primitive -{ -public: - GusdGT_PackedUSDMesh( - const GT_PrimitiveHandle& mesh, - int64 id, - UT_Array& sourceMeshes); - - virtual ~GusdGT_PackedUSDMesh(); - - virtual const char* className() const override; - - static int getStaticPrimitiveType(); - - virtual int getPrimitiveType() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool refine( - GT_Refine& refiner, - const GT_RefineParms* parms=nullptr) const override; - - virtual void enlargeBounds( - UT_BoundingBox boxes[], - int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual bool getUniqueID(int64& id) const override; - -private: - GT_PrimitiveHandle m_mesh; - int64 m_id; - // Handles to uncoalesced meshes must be kept alive for viewport picking - // to work correctly. - UT_Array m_sourceMeshes; -}; - - -//------------------------------------------------------------------------------ -// class GusdGT_PrimCollect -//------------------------------------------------------------------------------ - -/* - * A collector for Packed USD primitives which creates corresponding - * GusdGT_PackedUSD prims - */ - -// XXX This could be named something more explicit like GusdGT_PackedUSDCollect - -class GusdGT_PrimCollect : public GT_GEOPrimCollect -{ -public: - GusdGT_PrimCollect() {} - virtual ~GusdGT_PrimCollect(); - - virtual GT_GEOPrimCollectData * - beginCollecting( - const GT_GEODetailListHandle &geometry, - const GT_RefineParms *parms) const; - - virtual GT_PrimitiveHandle - collect( - const GT_GEODetailListHandle &geo, - const GEO_Primitive *const* prim_list, - int nsegments, - GT_GEOPrimCollectData *data) const; - - virtual GT_PrimitiveHandle - endCollecting( - const GT_GEODetailListHandle &geometry, - GT_GEOPrimCollectData *data) const; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif // __GUSD_GU_PRIMCOLLECT_H__ diff --git a/third_party/houdini/gusd/GT_PointInstancer.cpp b/third_party/houdini/gusd/GT_PointInstancer.cpp deleted file mode 100644 index ed7135bc33..0000000000 --- a/third_party/houdini/gusd/GT_PointInstancer.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GT_PointInstancer.h" - -PXR_NAMESPACE_OPEN_SCOPE - -namespace { -int s_gtPointInstancerPrimId = GT_PRIM_UNDEFINED; -} - -GusdGT_PointInstancer::~GusdGT_PointInstancer() -{ -} - -/* static */ -int -GusdGT_PointInstancer::getStaticPrimitiveType() -{ - if( s_gtPointInstancerPrimId == GT_PRIM_UNDEFINED ) - s_gtPointInstancerPrimId = GT_Primitive::createPrimitiveTypeId(); - return s_gtPointInstancerPrimId; -} - - -int -GusdGT_PointInstancer::getPrimitiveType() const -{ - return getStaticPrimitiveType(); -} - -PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/third_party/houdini/gusd/GT_PointInstancer.h b/third_party/houdini/gusd/GT_PointInstancer.h deleted file mode 100644 index e59e0d63e8..0000000000 --- a/third_party/houdini/gusd/GT_PointInstancer.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_POINT_INSTANCER_H -#define GUSD_GT_POINT_INSTANCER_H - -#include "api.h" - -#include "pxr/pxr.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/// A GusdGT_PointInstancer is identical to a GT_PrimPointMesh except -/// that it is treated differently by the GusdRefiner and has -/// a different GusdPrimWrapper. - -class GUSD_API GusdGT_PointInstancer : public GT_PrimPointMesh -{ -public: - GusdGT_PointInstancer() {} - GusdGT_PointInstancer(const GT_AttributeListHandle &points, - const GT_AttributeListHandle &uniform) : - GT_PrimPointMesh( points, uniform ) - { - } - GusdGT_PointInstancer(const GusdGT_PointInstancer &src) : - GT_PrimPointMesh( src ) - { - } - virtual ~GusdGT_PointInstancer(); - - virtual const char *className() const override { return "GusdGT_PointInstancer"; } - - static int getStaticPrimitiveType(); - - virtual int getPrimitiveType() const override; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_GT_POINT_INSTANCER_H diff --git a/third_party/houdini/gusd/GT_PrimCache.cpp b/third_party/houdini/gusd/GT_PrimCache.cpp deleted file mode 100644 index 58de080fa8..0000000000 --- a/third_party/houdini/gusd/GT_PrimCache.cpp +++ /dev/null @@ -1,489 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// - -#include "GT_PrimCache.h" - -#include "GT_PackedUSD.h" -#include "primWrapper.h" -#include "USD_PropertyMap.h" -#include "USD_StdTraverse.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include "pxr/usd/usdGeom/boundable.h" -#include "pxr/usd/usdGeom/xformable.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// 0x100501BE corresponds to 16.5.446. -#if SYS_VERSION_FULL_INT >= 0x100501BE -#include -#endif - -PXR_NAMESPACE_OPEN_SCOPE - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -using std::vector; -using std::cerr; -using std::endl; - -typedef UT_IntrusivePtr GT_PrimPolygonMeshHandle; - - -//////////////////////////////////////////////////////////////////////////////////////////// - -namespace { - - struct CacheKeyValue - { - CacheKeyValue() : hash(0) {} - - CacheKeyValue(const UsdPrim& prim, UsdTimeCode time, - GusdPurposeSet purposes) - : prim(prim) - , time(time) - , purposes(purposes) - , hash(ComputeHash(prim,time,purposes)) {} - - static std::size_t ComputeHash(const UsdPrim& prim, UsdTimeCode time, - GusdPurposeSet purposes) - { - std::size_t h = hash_value(prim); - boost::hash_combine(h, time); - boost::hash_combine(h, purposes); - return h; - } - - bool operator==(const CacheKeyValue& o) const - { return prim == o.prim && - time == o.time && - purposes == o.purposes; } - - friend size_t hash_value(const CacheKeyValue& o) - { return o.hash; } - - struct HashCmp - { - static std::size_t hash(const CacheKeyValue& key) - { return key.hash; } - static bool equal(const CacheKeyValue& a, - const CacheKeyValue& b) - { return a == b; } - }; - - UsdPrim prim; - UsdTimeCode time; - GusdPurposeSet purposes; - std::size_t hash; - }; - - - - struct CacheEntry : public UT_CappedItem { - CacheEntry() : prim( NULL ) {} - CacheEntry( GT_PrimitiveHandle p ) : prim(p) {} - CacheEntry( const CacheEntry &rhs ) : prim( rhs.prim ) {} - - virtual int64 getMemoryUsage () const { - int64 rv = sizeof(*this); - if( prim ) - rv += prim->getMemoryUsage(); - return rv; - } - - GT_PrimitiveHandle prim; - }; - -#if SYS_VERSION_FULL_INT < 0x10050000 - static inline void intrusive_ptr_add_ref(const CacheEntry *o) { const_cast(o)->incref(); } - static inline void intrusive_ptr_release(const CacheEntry *o) { const_cast(o)->decref(); } -#endif - - struct CreateEntryFn { - - CreateEntryFn( GusdGT_PrimCache &cache ) : m_cache( cache ) {} - - UT_IntrusivePtr operator()( - const UsdPrim& prim, - UsdTimeCode time, - GusdPurposeSet purposes, - bool skipRoot ) const; - - GusdGT_PrimCache& m_cache; - }; - - // Override the refiner to recurse on subdivs and collections - struct Refiner : public GT_RefineCollect { - - UT_Array coalescedMeshes; - UT_Array coalescedIds; - UT_Array > sourceMeshes; - - virtual void addPrimitive( const GT_PrimitiveHandle &prim ) - { - const int primTypeId = prim->getPrimitiveType(); - - if( primTypeId == GT_PRIM_SUBDIVISION_MESH || - primTypeId == GT_PRIM_COLLECT || - primTypeId == GusdGT_PackedUSDMesh::getStaticPrimitiveType() ) { - - prim->refine( *this ); - } - - else if( primTypeId == GT_PRIM_POLYGON_MESH ) { - - - // There are significant performace advantages to combining as - // many meshes as possible. - - GT_PrimPolygonMeshHandle mesh = UTverify_cast(prim.get()); - int64 meshId = 0; - mesh->getUniqueID( meshId ); - - // Flatten transforms on the mesh - UT_Matrix4D m; - mesh->getPrimitiveTransform()->getMatrix( m ); - if( !m.isEqual( UT_Matrix4D::getIdentityMatrix() )) { - GT_AttributeListHandle newShared = mesh->getShared()->transform( mesh->getPrimitiveTransform() ); - mesh = new GT_PrimPolygonMesh( *mesh, newShared, mesh->getVertex(), mesh->getUniform(), mesh->getDetail() ); - } - - // Houdini is going to compute normals if we don't. Doing it here - // allows them to be cached. - auto normMesh = mesh->createPointNormalsIfMissing(); - if( normMesh ) { - mesh = normMesh; - } - - // If GT_CatPolygonMesh will combine meshes with the same - // attribute sets until it reaches some maximum size. - // If we fail to concate the new mesh with any of our existing - // concatenated meshs, just create a new one. - bool appended = false; - for( size_t i = 0; i < coalescedMeshes.size(); ++i ) { - if( coalescedMeshes(i).append( mesh )) { - SYShashCombine( coalescedIds(i), meshId ); - sourceMeshes(i).append( mesh ); - appended = true; - break; - } - } - if( !appended ) { - coalescedMeshes.append( GT_CatPolygonMesh() ); - coalescedMeshes.last().append( mesh ); - coalescedIds.append( meshId ); - sourceMeshes.append(); - sourceMeshes.last().append( mesh ); - } - } - else { - GT_RefineCollect::addPrimitive( prim ); - } - } - }; - - typedef GusdUT_CappedKey CacheKey; - -}; // end namespace - -//////////////////////////////////////////////////////////////////////////////// - -/* static */ -GusdGT_PrimCache & -GusdGT_PrimCache::GetInstance() -{ - static GusdGT_PrimCache cache; - return cache; -} - -//////////////////////////////////////////////////////////////////////////////// - -GusdGT_PrimCache::GusdGT_PrimCache() : - _prims( "GusdGT_PrimCache", 1024 ) -{ -} - -GusdGT_PrimCache::~GusdGT_PrimCache() -{ -} - -GT_PrimitiveHandle -GusdGT_PrimCache::GetPrim( const UsdPrim &usdPrim, - UsdTimeCode time, - GusdPurposeSet purposes, - bool skipRoot ) -{ - // We need to skip the root when walking into instance masters. - - if( !usdPrim.IsValid() ) { - return GT_PrimitiveHandle(); - } - - CacheKey key(CacheKeyValue(usdPrim, time, purposes)); - - CreateEntryFn createFunc(*this); - auto entry = _prims.FindOrCreate( key, createFunc, - usdPrim, time, - purposes, skipRoot ); - - return entry ? entry->prim : NULL; -} - -void -GusdGT_PrimCache::Clear() -{ - _prims.clear(); -} - -int64 -GusdGT_PrimCache::Clear(const UT_StringSet& paths) -{ - return _prims.ClearEntries( - [&](const UT_CappedKeyHandle& key, - const UT_CappedItemHandle& item) { - - return GusdUSD_DataCache::ShouldClearPrim( - (*UTverify_cast(key.get()))->prim, paths); - }); -} - -//////////////////////////////////////////////////////////////////////////////// - -UT_IntrusivePtr -CreateEntryFn::operator()( - const UsdPrim &prim, - UsdTimeCode time, - GusdPurposeSet purposes, - bool skipRoot ) const -{ - - // Build a cache entry for a USD Prim. A cache entry contains a GT_Primitive - // that can be used to draw the usd prim. - // - // Handle 3 different cases differently. - // - // USD gprims (leaves in the hierarchy) are just converted to GT_Primitives. - // - // For USD native instances, find the instance's master or the prim in - // master corresponding to an instance proxy, and recurse on that. This way - // each instance should share a cache with its master. - // - // Any other USD primitive represents a branch of the USD hierarchy. Find - // all the instances and leaves in this branch and build a GT_PrimCollect - // that represent the branch. - // - // The viewport doesn't seem to like nested collections very much. So we - // use a refiner to flatten the collections. - - Refiner refiner; - - // Tell the wrapper classes that we are refining for the viewport. In this case we just load the geometry and color. No - // other primvars. Also load curves as polylines. - GT_RefineParms refineParms; - refineParms.setPackedViewportLOD( true ); - - bool isInstance = prim.IsInstance(); - bool isInstanceProxy = prim.IsInstanceProxy(); - if( isInstance || isInstanceProxy) - { - DBG( cerr << "Create prim cache for instance " << prim.GetPath() << " at " << time << endl; ) - // Look for a cache entry from the instance master - UsdPrim masterPrim = isInstance ? prim.GetMaster() : prim.GetPrimInMaster(); - GT_PrimitiveHandle instancePrim = - m_cache.GetPrim( masterPrim, - time, - purposes, - true ); - - if( !instancePrim ) { - return NULL; - } - return new CacheEntry( instancePrim ); - } - else if( prim.IsA() ) - { - UsdGeomImageable imageable( prim ); - - DBG( cerr << "Create prim cache for gprim " << prim.GetPath() << " at " << time << endl; ) - - GT_PrimitiveHandle gp = - GusdPrimWrapper::defineForRead( - imageable, - time, - purposes ); - if( gp ) { - gp->refine( refiner, &refineParms ); - } - } - else { - - DBG( cerr << "Create prim cache for group " << prim.GetPath() << " at " << time << endl; ) - - // Find all the gprims in the group. - UT_Array gprims; - GusdUSD_StdTraverse::GetBoundableTraversal().FindPrims( - prim, - time, - purposes, - gprims, - skipRoot ); - - std::map> primSort; - - if( gprims.size() > 0 ) { - - // All the gprims and instances in this group need to be transformed - // into the groups space. - - UT_Matrix4D invGroupXform; - if (GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - prim, time, invGroupXform )) { - invGroupXform.invert(); - } else { - invGroupXform.identity(); - } - - // Iterate though all the prims and find matching instances. - for( auto it = gprims.begin(); it != gprims.end(); ++it ) - { - const UsdPrim& p = *it; - - GT_PrimitiveHandle gtPrim = - m_cache.GetPrim( p, - time, - purposes, - false ); - if( gtPrim ) { - - auto sortIt = primSort.find( gtPrim ); - if( sortIt == primSort.end() ) { - primSort[gtPrim] = std::vector( 1, p ); - } - else { - sortIt->second.push_back( p ); - } - } - } - - // Iterate through the results of the sort - for( auto const &kv : primSort ) { - - GT_PrimitiveHandle gtPrim = kv.first; - const std::vector &usdPrims = kv.second; - - if( usdPrims.size() == 1 ) { - - UsdPrim p = usdPrims[0]; - UT_Matrix4D gprimXform; - if (!GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - p, time, gprimXform )) { - gprimXform.identity(); - } - - UT_Matrix4D m = gprimXform * invGroupXform; - - refiner.addPrimitive( - gtPrim->copyTransformed( new GT_Transform( &m, 1 ))); - } - else { - - // Build GT_PrimInstances for prims that share the same geometry - auto transforms = new GT_TransformArray; - - for( auto const &p : usdPrims ) { - - UT_Matrix4D gprimXform; - if (!GusdUSD_XformCache::GetInstance() - .GetLocalToWorldTransform(p, time, gprimXform )) { - gprimXform.identity(); - } - - UT_Matrix4D m = gprimXform * invGroupXform; - - transforms->append( new GT_Transform( &m, 1 )); - } - refiner.addPrimitive( new GT_PrimInstance( gtPrim, transforms ) ); - } - } - } - } - exint numPrims = refiner.getPrimCollect()->entries() + - refiner.coalescedMeshes.size(); - if( numPrims == 0 ) { - return NULL; - } - // If we only created one mesh, return that one directly, otherwise - // create a collection. - if ( numPrims == 1 ) { - if( refiner.getPrimCollect()->entries() > 0 ) { - return new CacheEntry( refiner.getPrimCollect()->getPrim( 0 ) ); - } - else { -#if SYS_VERSION_FULL_INT >= 0x100501BE - return new CacheEntry( new GusdGT_PackedUSDMesh( - refiner.coalescedMeshes(0).result(), - refiner.coalescedIds(0), - refiner.sourceMeshes(0))); -#else - return new CacheEntry( refiner.coalescedMeshes(0).result() ); -#endif - } - } - GT_PrimCollect* collect = new GT_PrimCollect( *refiner.getPrimCollect() ); - for( size_t i = 0; i < refiner.coalescedMeshes.size(); ++i ) { - auto& catMesh = refiner.coalescedMeshes(i); - GT_PrimitiveHandle meshPrim = catMesh.result(); -#if SYS_VERSION_FULL_INT >= 0x100501BE - collect->appendPrimitive( - new GusdGT_PackedUSDMesh( - meshPrim, - refiner.coalescedIds(i), - refiner.sourceMeshes(i)) ); -#else - collect->appendPrimitive( meshPrim ); -#endif - } - return new CacheEntry( collect ); -} - -PXR_NAMESPACE_CLOSE_SCOPE - - - diff --git a/third_party/houdini/gusd/GT_PrimCache.h b/third_party/houdini/gusd/GT_PrimCache.h deleted file mode 100644 index 1af4c57d8b..0000000000 --- a/third_party/houdini/gusd/GT_PrimCache.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_PRIM_CACHE_H -#define GUSD_GT_PRIM_CACHE_H - -#include "api.h" - -#include "purpose.h" -#include "USD_DataCache.h" -#include "UT_CappedCache.h" - -#include - -#include "pxr/pxr.h" -#include "pxr/usd/usd/prim.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/// Cache of refined GT prims created draw USD in the viewport. -// -// We cache a GT prim for each imageable (leaf node) USD prim and each instance. -// The GT prims are refined to prims that can be directly imaged in the Houdini -// view port. -// The cache is build atop a UT_CappedCache (a LRU cache). - -class GusdGT_PrimCache : public GusdUSD_DataCache { - -public: - - GUSD_API - static GusdGT_PrimCache& GetInstance(); - - GusdGT_PrimCache(); - virtual ~GusdGT_PrimCache(); - - GT_PrimitiveHandle GetPrim( const UsdPrim &usdPrim, - UsdTimeCode time, - GusdPurposeSet purposes, - bool skipRoot = false ); - - virtual void Clear() override; - virtual int64 Clear(const UT_StringSet& paths) override; - -private: - - GusdUT_CappedCache _prims; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_GT_PRIM_CACHE_H diff --git a/third_party/houdini/gusd/GT_Utils.cpp b/third_party/houdini/gusd/GT_Utils.cpp deleted file mode 100644 index caaeda5398..0000000000 --- a/third_party/houdini/gusd/GT_Utils.cpp +++ /dev/null @@ -1,1315 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GT_Utils.h" -#include "UT_Gf.h" -#include "UT_Version.h" - -#include -#include -#include -#include -#include -#include - -#include "pxr/base/gf/vec3h.h" -#include "pxr/base/gf/vec4h.h" -#include "pxr/base/tf/span.h" -#include "pxr/base/tf/stringUtils.h" -#include "pxr/usd/usd/attribute.h" -#include "pxr/usd/usd/timeCode.h" -#include "pxr/usd/usdGeom/boundable.h" -#include "pxr/usd/usdGeom/xformable.h" - -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cout; -using std::cerr; -using std::endl; -using std::set; -using std::string; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -namespace { -//############################################################################# -// struct GtDataToUsdTypename -//############################################################################# -struct GtDataToUsdTypename -{ - typedef boost::tuple KeyType; - - struct equal_func : std::binary_function - { - bool operator()(const KeyType& lhs, const KeyType& rhs) const - { - return lhs.get<0>() == rhs.get<0>() - && lhs.get<1>() == rhs.get<1>() - && lhs.get<2>() == rhs.get<2>() - && lhs.get<3>() == rhs.get<3>(); - } - }; - - struct hash_func : std::unary_function - { - std::size_t operator()(const KeyType& k) const - { - std::size_t seed = 0; - boost::hash_combine(seed, k.get<0>()); - boost::hash_combine(seed, k.get<1>()); - boost::hash_combine(seed, k.get<2>()); - boost::hash_combine(seed, k.get<3>()); - return seed; - } - }; - - typedef UT_Map MapType; - MapType m_typeLookup; - - GtDataToUsdTypename() - { - // Integral types - - DefineTypeLookup(GT_STORE_INT32, GT_TYPE_NONE, -1, - SdfValueTypeNames->Int); - DefineTypeLookup(GT_STORE_INT64, GT_TYPE_NONE, -1, - SdfValueTypeNames->Int64); - DefineTypeLookup(GT_STORE_UINT8, GT_TYPE_NONE, -1, - SdfValueTypeNames->UChar); - -#if SYS_VERSION_FULL_INT >= 0x11000000 - // Up-cast int8/int16 to avoid precision loss. - DefineTypeLookup(GT_STORE_INT8, GT_TYPE_NONE, -1, - SdfValueTypeNames->Int); - DefineTypeLookup(GT_STORE_INT16, GT_TYPE_NONE, -1, - SdfValueTypeNames->Int); -#endif - - // Integral vectors. - // USD only supports a single precision for vectors of integers. -#if SYS_VERSION_FULL_INT >= 0x11000000 - for (auto storage : {GT_STORE_UINT8, GT_STORE_INT8, GT_STORE_INT16, - GT_STORE_INT32, GT_STORE_INT64}) -#else - for (auto storage : {GT_STORE_UINT8, GT_STORE_INT32, GT_STORE_INT64}) -#endif - { - DefineTypeLookup(storage, GT_TYPE_NONE, 2, - SdfValueTypeNames->Int2); - DefineTypeLookup(storage, GT_TYPE_NONE, 3, - SdfValueTypeNames->Int3); - DefineTypeLookup(storage, GT_TYPE_NONE, 4, - SdfValueTypeNames->Int4); - } - - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_NONE, -1, - SdfValueTypeNames->Half); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_NONE, -1, - SdfValueTypeNames->Float); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_NONE, -1, - SdfValueTypeNames->Double); - - // Vec2 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_NONE, 2, - SdfValueTypeNames->Half2); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_NONE, 2, - SdfValueTypeNames->Float2); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_NONE, 2, - SdfValueTypeNames->Double2); - - // GT_TYPE_TEXTURE -#if SYS_VERSION_FULL_INT >= 0x10050000 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_TEXTURE, 2, - SdfValueTypeNames->TexCoord2h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_TEXTURE, 2, - SdfValueTypeNames->TexCoord2f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_TEXTURE, 2, - SdfValueTypeNames->TexCoord2d); -#endif - - // GT_TYPE_ST - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_ST, 2, - SdfValueTypeNames->TexCoord2h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_ST, 2, - SdfValueTypeNames->TexCoord2f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_ST, 2, - SdfValueTypeNames->TexCoord2d); - - // Vec3 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_NONE, 3, - SdfValueTypeNames->Half3); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_NONE, 3, - SdfValueTypeNames->Float3); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_NONE, 3, - SdfValueTypeNames->Double3); - - // GT_TYPE_VECTOR 3 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_VECTOR, 3, - SdfValueTypeNames->Vector3h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_VECTOR, 3, - SdfValueTypeNames->Vector3f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_VECTOR, 3, - SdfValueTypeNames->Vector3d); - - // GT_TYPE_NORMAL 3 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_NORMAL, 3, - SdfValueTypeNames->Normal3h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_NORMAL, 3, - SdfValueTypeNames->Normal3f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_NORMAL, 3, - SdfValueTypeNames->Normal3d); - - // GT_TYPE_COLOR 3 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_COLOR, 3, - SdfValueTypeNames->Color3h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_COLOR, 3, - SdfValueTypeNames->Color3f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_COLOR, 3, - SdfValueTypeNames->Color3d); - - // GT_TYPE_POINT 3 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_POINT, 3, - SdfValueTypeNames->Point3h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_POINT, 3, - SdfValueTypeNames->Point3f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_POINT, 3, - SdfValueTypeNames->Point3d); - - // GT_TYPE_TEXTURE 3 -#if SYS_VERSION_FULL_INT >= 0x10050000 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_TEXTURE, 3, - SdfValueTypeNames->TexCoord3h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_TEXTURE, 3, - SdfValueTypeNames->TexCoord3f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_TEXTURE, 3, - SdfValueTypeNames->TexCoord3d); -#endif - - // Vec4 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_NONE, 4, - SdfValueTypeNames->Half4); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_NONE, 4, - SdfValueTypeNames->Float4); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_NONE, 4, - SdfValueTypeNames->Double4); - - // GT_TYPE_COLOR 4 - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_COLOR, 4, - SdfValueTypeNames->Color4h); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_COLOR, 4, - SdfValueTypeNames->Color4f); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_COLOR, 4, - SdfValueTypeNames->Color4d); - - // GT_TYPE_QUATERNION - DefineTypeLookup(GT_STORE_REAL16, GT_TYPE_QUATERNION, 4, - SdfValueTypeNames->Quath); - DefineTypeLookup(GT_STORE_REAL32, GT_TYPE_QUATERNION, 4, - SdfValueTypeNames->Quatf); - DefineTypeLookup(GT_STORE_REAL64, GT_TYPE_QUATERNION, 4, - SdfValueTypeNames->Quatd); - - // Matrices. - // USD only supports a single precision type for matrices. - for (auto storage : {GT_STORE_REAL16, - GT_STORE_REAL32, - GT_STORE_REAL64}) { - DefineTypeLookup(storage, GT_TYPE_MATRIX3, 9, - SdfValueTypeNames->Matrix3d); - DefineTypeLookup(storage, GT_TYPE_MATRIX, 16, - SdfValueTypeNames->Matrix4d); - } - - // String - DefineTypeLookup(GT_STORE_STRING, GT_TYPE_NONE, -1, - SdfValueTypeNames->String); - } - - SdfValueTypeName operator()(const GT_DataArrayHandle& gtData, bool isArray) const - { - GT_Size tupleSize = gtData->getTupleSize(); - // Types may be specialized for vectors of size 2,3,4 and matrices. - // -1 means "any size" - if(tupleSize != 2 && tupleSize != 3 && tupleSize != 4 - && tupleSize != 9 && tupleSize != 16) { - tupleSize = -1; - } - KeyType key(gtData->getStorage(), - gtData->getTypeInfo(), - tupleSize, - isArray); - MapType::const_iterator it = m_typeLookup.find(key); - if(it != m_typeLookup.end()) { - return it->second; - } - - return SdfValueTypeName(); - } - - void - DefineTypeLookup(GT_Storage storage, GT_Type type, int tupleSize, - const SdfValueTypeName& typeName) - { - // Scalar type - m_typeLookup[KeyType(storage, type, tupleSize, /*array*/ false)] = - typeName.GetScalarType(); - // Array type - m_typeLookup[KeyType(storage, type, tupleSize, /*array*/ true)] = - typeName.GetArrayType(); - } -}; -//############################################################################# - -//############################################################################# -// Converters -//############################################################################# - - -/// Copy \p count elements from \p src to \p dst. -template -void -_CopyArray(TO* dst, const FROM* src, GT_Size count) -{ - for (GT_Size i = 0; i < count; ++i) { - dst[i] = static_cast(src[i]); - } -} - - -bool _IsNumeric(GT_Storage storage) -{ - return GTisInteger(storage) || GTisFloat(storage); -} - - -/// Convert numeric GT types to USD. -/// This converter can only be used on types supported directly by the -/// GT_DataArray interface. -template -struct _ConvertNumericToUsd -{ - using ScalarType = typename GusdPodTupleTraits::ValueType; - static const int tupleSize = GusdGetTupleSize(); - - static bool fillValue(UsdType& usdValue, const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (_IsNumeric(gtData->getStorage()) && gtData->entries() > 0 && - gtData->getTupleSize() == tupleSize) { - - auto* dst = reinterpret_cast(&usdValue); - gtData->import(0, dst, tupleSize); - return true; - } - return false; - } - - static bool fillArray(VtArray& usdArray, - const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (_IsNumeric(gtData->getStorage()) && - gtData->getTupleSize() == tupleSize) { - - usdArray.resize(gtData->entries()); - auto* dst = reinterpret_cast(usdArray.data()); - gtData->fillArray(dst, 0, gtData->entries(), tupleSize); - return true; - } - return false; - } -}; - - -/// Convert numeric GT types to USD. -/// This can be used on types that are not directly supported by GT_DataArray, -/// and which require a static_cast to copy into the output. -template -struct _ConvertNumericWithCastToUsd -{ - using ScalarType = typename GusdPodTupleTraits::ValueType; - static const int tupleSize = GusdGetTupleSize(); - - static bool fillValue(UsdType& usdValue, const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (gtData->entries() > 0 && gtData->getTupleSize() == tupleSize) { - const GT_Storage storage = gtData->getStorage(); - if (storage == GT_STORE_UINT8) { - return _fillValue(usdValue, gtData); - } -#if SYS_VERSION_FULL_INT >= 0x11000000 - else if (storage == GT_STORE_INT8) { - return _fillValue(usdValue, gtData); - } else if (storage == GT_STORE_INT16) { - return _fillValue(usdValue, gtData); - } -#endif - else if (storage == GT_STORE_INT32) { - return _fillValue(usdValue, gtData); - } else if (storage == GT_STORE_INT64) { - return _fillValue(usdValue, gtData); - } else if (storage == GT_STORE_REAL16) { - return _fillValue(usdValue, gtData); - } else if (storage == GT_STORE_REAL32) { - return _fillValue(usdValue, gtData); - } else if (storage == GT_STORE_REAL64) { - return _fillValue(usdValue, gtData); - } - } - return false; - } - - static bool fillArray(VtArray& usdArray, - const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (gtData->getTupleSize() == tupleSize) { - const GT_Storage storage = gtData->getStorage(); - if (storage == GT_STORE_UINT8) { - return _fillArray(usdArray, gtData); - } -#if SYS_VERSION_FULL_INT >= 0x11000000 - else if (storage == GT_STORE_INT8) { - return _fillArray(usdArray, gtData); - } else if (storage == GT_STORE_INT16) { - return _fillArray(usdArray, gtData); - } -#endif - else if (storage == GT_STORE_INT32) { - return _fillArray(usdArray, gtData); - } else if (storage == GT_STORE_INT64) { - return _fillArray(usdArray, gtData); - } else if (storage == GT_STORE_REAL16) { - return _fillArray(usdArray, gtData); - } else if (storage == GT_STORE_REAL32) { - return _fillArray(usdArray, gtData); - } else if (storage == GT_STORE_REAL64) { - return _fillArray(usdArray, gtData); - } - } - return false; - } - -private: - template - static bool _fillValue(UsdType& usdValue, - const GT_DataArrayHandle& gtData, - GT_Offset offset=0) - { - GtType src[tupleSize]; - gtData->import(offset, src, tupleSize); - - _CopyArray(reinterpret_cast(&usdValue), src, tupleSize); - return true; - } - - template - static bool _fillArray(VtArray& usdArray, - const GT_DataArrayHandle& gtData) - { - const GT_Size numElems = gtData->entries(); - usdArray.resize(numElems); - auto dst = TfMakeSpan(usdArray); - for (GT_Offset i = 0; i < numElems; ++i) { - _fillValue(dst[i], gtData, i); - } - return true; - } -}; - - -/// Converter specialized for converting GT data to GfQuat types. -template -struct _ConvertQuatToUsd -{ - using GtScalarType = typename GusdPodTupleTraits::ValueType; - - static bool fillValue(UsdType& usdValue, const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (GTisFloat(gtData->getStorage()) && - gtData->entries() > 0 && - gtData->getTupleSize() == 4) { - - _fillValue(usdValue, gtData, 0); - return true; - } - return false; - } - - static bool fillArray(VtArray& usdArray, - const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (GTisFloat(gtData->getStorage()) && gtData->getTupleSize() == 4) { - - usdArray.resize(gtData->entries()); - auto dst = TfMakeSpan(usdArray); - for (GT_Offset i = 0; i < gtData->entries(); ++i) { - _fillValue(dst[i], gtData, i); - } - return true; - } - return false; - } - -private: - static void _fillValue(UsdType& usdValue, - const GT_DataArrayHandle& gtData, - GT_Offset offset=0) - { - GtScalarType src[4]; - gtData->import(offset, src, 4); - - // Houdini quaternions are stored as i,j,k,w - using UsdScalarType = typename UsdType::ScalarType; - - usdValue.SetReal(static_cast(src[3])); - usdValue.SetImaginary(static_cast(src[0]), - static_cast(src[1]), - static_cast(src[2])); - } -}; - - -void _ConvertString(const GT_String& src, std::string* dst) -{ - *dst = std::string(src ? src : ""); -} - - -void _ConvertString(const GT_String& src, TfToken* dst) -{ - *dst = TfToken(src ? src : ""); -} - - -void _ConvertString(const GT_String& src, SdfAssetPath* dst) -{ - *dst = SdfAssetPath(src ? src : ""); -} - - -/// Convert a GT type to a USD string value. -struct _ConvertStringToUsd -{ - static bool fillValue(std::string& usdValue, const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (GTisString(gtData->getStorage()) && - gtData->entries() > 0 && - gtData->getTupleSize() == 1) { - - _ConvertString(gtData->getS(0), &usdValue); - return true; - } - return false; - } - - static bool fillArray(VtStringArray& usdArray, - const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (GTisString(gtData->getStorage()) && - gtData->getTupleSize() == 1) { - // XXX tuples of strings not supported - usdArray.resize(gtData->entries()); - gtData->fillStrings(usdArray.data()); - return true; - } - return false; - } -}; - - -/// Convert a GT type to string-like types (eg., TfToken) -struct _ConvertStringLikeToUsd -{ - template - static bool fillValue(UsdType& usdValue, const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (GTisString(gtData->getStorage()) && - gtData->entries() > 0 && - gtData->getTupleSize() == 1) { - - _ConvertString(gtData->getS(0), &usdValue); - return true; - } - return false; - } - - template - static bool fillArray(VtArray& usdArray, - const GT_DataArrayHandle& gtData) - { - UT_ASSERT_P(gtData); - - if (GTisString(gtData->getStorage()) && - gtData->getTupleSize() == 1) { - - // XXX tuples of strings not supported - const GT_Size numElems = gtData->entries(); - usdArray.resize(numElems); - - auto dst = TfMakeSpan(usdArray); - for (GT_Size i = 0; i < numElems; ++i) { - _ConvertString(gtData->getS(i), &dst[i]); - } - return true; - } - return false; - } -}; - - -template struct _ConvertToUsd {}; - -#define _GUSD_DEFINE_CONVERTER(type, base) \ - template <> struct _ConvertToUsd : public base {}; - -// Scalars -_GUSD_DEFINE_CONVERTER(double, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(float, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfHalf, _ConvertNumericWithCastToUsd); -_GUSD_DEFINE_CONVERTER(bool, _ConvertNumericWithCastToUsd); -_GUSD_DEFINE_CONVERTER(int, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(uint8, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(int64, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(uint32, _ConvertNumericWithCastToUsd); -_GUSD_DEFINE_CONVERTER(uint64, _ConvertNumericWithCastToUsd); - -// Vectors -_GUSD_DEFINE_CONVERTER(GfVec2d, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec2f, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec2h, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec2i, _ConvertNumericToUsd); - -_GUSD_DEFINE_CONVERTER(GfVec3d, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec3f, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec3h, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec3i, _ConvertNumericToUsd); - -_GUSD_DEFINE_CONVERTER(GfVec4d, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec4f, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec4h, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfVec4i, _ConvertNumericToUsd); - -// Quat types -_GUSD_DEFINE_CONVERTER(GfQuatd, _ConvertQuatToUsd); -_GUSD_DEFINE_CONVERTER(GfQuatf, _ConvertQuatToUsd); -_GUSD_DEFINE_CONVERTER(GfQuath, _ConvertQuatToUsd); - -// Matrices -_GUSD_DEFINE_CONVERTER(GfMatrix2d, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfMatrix3d, _ConvertNumericToUsd); -_GUSD_DEFINE_CONVERTER(GfMatrix4d, _ConvertNumericToUsd); - -// Strings a string-like types. -_GUSD_DEFINE_CONVERTER(std::string, _ConvertStringToUsd); -_GUSD_DEFINE_CONVERTER(SdfAssetPath, _ConvertStringLikeToUsd); -_GUSD_DEFINE_CONVERTER(TfToken, _ConvertStringLikeToUsd); - - -template -bool _SetUsdAttributeT(const UsdAttribute& destAttr, - const GT_DataArrayHandle& sourceAttr, - const SdfValueTypeName& usdType, - UsdTimeCode time) -{ - UT_ASSERT(usdType); - - if (usdType.IsArray()) { - VtArray usdArray; - if (_ConvertToUsd::fillArray(usdArray, sourceAttr)) { - return destAttr.Set(usdArray, time); - } - } else { - UsdType usdValue; - if (_ConvertToUsd::fillValue(usdValue, sourceAttr)) { - return destAttr.Set(usdValue, time); - } - } - return false; -} - - -bool -_SetUsdAttribute(const UsdAttribute& destAttr, - const GT_DataArrayHandle& sourceAttr, - const SdfValueTypeName& usdType, - UsdTimeCode time) -{ - if (!sourceAttr || !destAttr) { - return false; - } - - const SdfValueTypeName scalarType = usdType.GetScalarType(); - - // GfVec3 - // GfVec3f is the most common type - // XXX: We compare using the TfType rather than the Sdf type name so that - // the same converters are employed regardless of the Sdf role. - - if (scalarType.GetType() == SdfValueTypeNames->Float3.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Double3.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Half3.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - - // GfVec2 - if (scalarType.GetType() == SdfValueTypeNames->Double2.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Float2.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Half2.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - - // GfVec4 - if (scalarType.GetType() == SdfValueTypeNames->Double4.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Float4.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Half4.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - - // Quaternions - if (scalarType == SdfValueTypeNames->Quatd) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->Quatf) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->Quath) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - - // Scalars. - if (scalarType == SdfValueTypeNames->Float) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->Double) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->Half) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->Int) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->Int64) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->UChar) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->UInt) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - if (scalarType == SdfValueTypeNames->UInt64) { - return _SetUsdAttributeT(destAttr, sourceAttr, usdType, time); - } - - // Matrices - if (scalarType.GetType() == SdfValueTypeNames->Matrix2d.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, - usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Matrix3d.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, - usdType, time); - } - if (scalarType.GetType() == SdfValueTypeNames->Matrix4d.GetType()) { - return _SetUsdAttributeT(destAttr, sourceAttr, - usdType, time); - } - - // Strings - if (scalarType == SdfValueTypeNames->String) { - return _SetUsdAttributeT(destAttr, sourceAttr, - usdType, time); - } - if (scalarType == SdfValueTypeNames->Token) { - return _SetUsdAttributeT(destAttr, sourceAttr, - usdType, time); - } - if (scalarType == SdfValueTypeNames->Asset) { - return _SetUsdAttributeT(destAttr, sourceAttr, - usdType, time); - } - - TF_WARN("setUsdAttribute: type not implemented: %s", - usdType.GetAsToken().GetText()); - return false; -} - - -//############################################################################# - -bool -setPvSample(const UsdGeomImageable& usdPrim, - const TfToken& name, - const GT_DataArrayHandle& gtData, - const TfToken& interpolationIn, - UsdTimeCode time) -{ - static const GtDataToUsdTypename usdTypename; - - TfToken interpolation = interpolationIn; - //bool isArrayType = (interpolation != UsdGeomTokens->constant); - SdfValueTypeName typeName = usdTypename( gtData, true ); - if( !typeName ) { - TF_WARN( "Unsupported primvar type %s, %s, tupleSize = %zd", - name.GetText(), GTstorage(gtData->getStorage()), - gtData->getTupleSize() ); - return false; - } - const UsdGeomPrimvar existingPrimvar = usdPrim.GetPrimvar( name ); - if( existingPrimvar && typeName != existingPrimvar.GetTypeName() ) { - - // If this primvar already exists, we can't change its type. Most notably, - // we change change a scalar to an array type. - typeName = existingPrimvar.GetTypeName(); - if( !typeName.IsArray() ) { - interpolation = UsdGeomTokens->constant; - } - } - - UsdGeomPrimvar primvar = usdPrim.CreatePrimvar( name, typeName, interpolation ); - - if(!primvar) - return false; - - return _SetUsdAttribute(primvar.GetAttr(), gtData, typeName, time); -} - -} // anon namespace - - -//############################################################################# -// class GusdGT_AttrFilter -//############################################################################# -GusdGT_AttrFilter:: -GusdGT_AttrFilter(const std::string& pattern) -{ - // always override these - m_overridePattern = - " ^__point_id" - " ^__vertex_id" - " ^__primitive_id" - " ^__topology" - " ^__primitivelist" - " ^usdMeta_*" - " ^usdvisible" - " ^usdactive"; - - setPattern(GT_OWNER_POINT, pattern); - setPattern(GT_OWNER_VERTEX, pattern); - setPattern(GT_OWNER_UNIFORM, pattern); - setPattern(GT_OWNER_CONSTANT, pattern); -} - -GusdGT_AttrFilter:: -GusdGT_AttrFilter(const GusdGT_AttrFilter &rhs) - : m_patterns( rhs.m_patterns ) - , m_activeOwners( rhs.m_activeOwners ) -{ - m_overridePattern = - " ^__point_id" - " ^__vertex_id" - " ^__primitive_id" - " ^__topology" - " ^usdMeta_*" - " ^usdvisible" - " ^usdactive"; -} - -void GusdGT_AttrFilter:: -setPattern(GT_Owner owner, const std::string& pattern) -{ - m_patterns[owner] = " " + pattern + m_overridePattern; -} - -void GusdGT_AttrFilter:: -appendPattern(GT_Owner owner, const std::string& pattern) -{ - m_patterns[owner] += " " + pattern; -} - -void GusdGT_AttrFilter:: -setActiveOwners(const OwnerArgs& owners) const -{ - m_activeOwners = owners; -} - -bool GusdGT_AttrFilter:: -matches(const std::string& attrName) const -{ - for(int i=0; i::const_iterator mapIt = - m_patterns.find(m_activeOwners.item(i)); - if(mapIt == m_patterns.end()) continue; - - UT_String str(attrName); - if(str.multiMatch(mapIt->second.c_str()) != 0) { - return true; - } - } - return false; -} - -//############################################################################# -// GusdGT_Utils implementation -//############################################################################# - - -GT_Type -GusdGT_Utils::getType(const SdfValueTypeName& typeName) -{ - const TfToken& role = typeName.GetRole(); - - if (role == SdfValueRoleNames->Point) { - return GT_TYPE_POINT; - } else if (role == SdfValueRoleNames->Normal) { - return GT_TYPE_NORMAL; - } else if (role == SdfValueRoleNames->Vector) { - return GT_TYPE_VECTOR; - } else if (role == SdfValueRoleNames->Color) { - return GT_TYPE_COLOR; - } else if (role == SdfValueRoleNames->TextureCoordinate) { -#if SYS_VERSION_FULL_INT >= 0x10050000 - return GT_TYPE_TEXTURE; -#endif - } else if (typeName == SdfValueTypeNames->Matrix4d) { - return GT_TYPE_MATRIX; - } else if (typeName == SdfValueTypeNames->Matrix3d) { - return GT_TYPE_MATRIX3; - } - return GT_TYPE_NONE; -} - - -TfToken -GusdGT_Utils::getRole(GT_Type type) -{ - switch (type) - { - case GT_TYPE_POINT: return SdfValueRoleNames->Point; - case GT_TYPE_VECTOR: return SdfValueRoleNames->Vector; - case GT_TYPE_NORMAL: return SdfValueRoleNames->Normal; - case GT_TYPE_COLOR: return SdfValueRoleNames->Color; - case GT_TYPE_ST: -#if SYS_VERSION_FULL_INT >= 0x10050000 - case GT_TYPE_TEXTURE: - return SdfValueRoleNames->TextureCoordinate; -#endif - default: - return TfToken(); - }; -} - - -bool GusdGT_Utils:: -setUsdAttribute(const UsdAttribute& destAttr, - const GT_DataArrayHandle& sourceAttr, - UsdTimeCode time) -{ - return _SetUsdAttribute(destAttr, sourceAttr, destAttr.GetTypeName(), time); -} - - -GT_DataArrayHandle GusdGT_Utils:: -getExtentsArray(const GT_PrimitiveHandle& gtPrim) -{ - GT_DataArrayHandle ret; - if(gtPrim) { - UT_BoundingBox houBoundsArray[] - = {UT_BoundingBox(SYS_FP32_MAX, SYS_FP32_MAX, SYS_FP32_MAX, - SYS_FP32_MIN, SYS_FP32_MIN, SYS_FP32_MIN)}; - houBoundsArray[0].initBounds(); - gtPrim->enlargeRenderBounds(houBoundsArray, 1); - GT_Real32Array* gtExtents = new GT_Real32Array(2, 3); - gtExtents->setTupleBlock(houBoundsArray[0].minvec().data(), 1, 0); - gtExtents->setTupleBlock(houBoundsArray[0].maxvec().data(), 1, 1); - ret = gtExtents; - } - return ret; -} - -#if (GUSD_VER_CMP_1(>=,15)) -typedef GT_AttributeMap::const_names_iterator AttrMapIterator; -#else -typedef UT_SymbolTable::traverser AttrMapIterator; -#endif - - -bool -GusdGT_Utils::setPrimvarSample( - const UsdGeomImageable& usdPrim, - const TfToken &name, - const GT_DataArrayHandle& data, - const TfToken& interpolation, - UsdTimeCode time ) -{ - DBG(cerr << "GusdGT_Utils::setPrimvarSample: " << name - << ", " << GTstorage( data->getStorage() ) << ", " - << data->getTupleSize() << ", " << interpolation << endl); - - return setPvSample(usdPrim, name, data, interpolation, time); -} - -template bool -isDataConst( const T* p, GT_Size entries, GT_Size tupleSize ) { - - if( tupleSize == 1 ) { - T first = *p++; - for( GT_Size i = 1; i < entries; ++i ) { - if( *p++ != first ) { - return false; - } - } - return true; - } - else if ( tupleSize == 3 ) { - T first_0 = *(p+0); - T first_1 = *(p+1); - T first_2 = *(p+2); - p += 3; - for( GT_Size i = 1; i < entries; ++i ) { - if( *(p+0) != first_0 || - *(p+1) != first_1 || - *(p+2) != first_2 ) { - return false; - } - p += 3; - } - return true; - } - else { - const T* firstP = p; - p += tupleSize; - for( GT_Size i = 1; i < entries; ++i ) { - for( GT_Size j = 0; j < tupleSize; ++ j ) { - if( *(p + j) != *(firstP + j) ) { - return false; - } - } - p += tupleSize; - } - return true; - } -} - -bool -GusdGT_Utils:: -isDataConstant( const GT_DataArrayHandle& data ) -{ - const GT_Storage storage = data->getStorage(); - const GT_Size tupleSize = data->getTupleSize(); - const GT_Size entries = data->entries(); - - if (entries == 0) { - return true; - } - - if (storage == GT_STORE_UINT8) { - GT_DataArrayHandle buffer; - return isDataConst(data->getU8Array(buffer), - entries, tupleSize); - - } -#if SYS_VERSION_FULL_INT >= 0x11000000 - else if (storage == GT_STORE_INT8) { - GT_DataArrayHandle buffer; - return isDataConst(data->getI8Array(buffer), - entries, tupleSize); - } else if (storage == GT_STORE_INT16) { - GT_DataArrayHandle buffer; - return isDataConst(data->getI16Array(buffer), - entries, tupleSize); - } -#endif - else if (storage == GT_STORE_INT32) { - GT_DataArrayHandle buffer; - return isDataConst(data->getI32Array(buffer), - entries, tupleSize); - - } else if (storage == GT_STORE_INT64) { - GT_DataArrayHandle buffer; - return isDataConst(data->getI64Array(buffer), - entries, tupleSize); - - } else if (storage == GT_STORE_REAL16) { - GT_DataArrayHandle buffer; - return isDataConst(data->getF16Array(buffer), - entries, tupleSize); - - } else if (storage == GT_STORE_REAL32) { - GT_DataArrayHandle buffer; - return isDataConst(data->getF32Array(buffer), - entries, tupleSize); - - } else if (storage == GT_STORE_REAL64) { - GT_DataArrayHandle buffer; - return isDataConst(data->getF64Array(buffer), - entries, tupleSize); - } else if (storage == GT_STORE_STRING) { - if (data->getStringIndexCount() >= 0) { - // If this is an indexed string array, we can just compare the indices. - // One would think that getIndexedStrings would return indices, - // but it doesn't. If we look at the header file for GT_DAIndexedString, - // we can deduce that getI32Array gets you the indices. - GT_DataArrayHandle buffer; - const int32* indices = data->getI32Array(buffer); - if (indices ) { - int32 first = indices[0]; - for (GT_Size i = 1; i < entries; ++i) { - if (indices[i] != first) { - return false; - } - } - return true; - } - } - - UT_StringArray strings; - data->getStrings(strings); - - // beware of arrays of strings, I don't how to compare these. - if (strings.entries() == 0) { - return false; - } - - const UT_StringHolder &first = strings(0); - for (GT_Size i = 1, end = std::min( entries, strings.entries() ); i < end; ++i) { - if (strings(i) != first) { - return false; - } - } - return true; - } - TF_WARN("Unsupported primvar type: %s, tupleSize = %zd", - GTstorage(storage), tupleSize); - return false; -} - -void GusdGT_Utils:: -setCustomAttributesFromGTPrim( - const UsdGeomImageable &usdGeomPrim, - const GT_AttributeListHandle& gtAttrs, - set& excludeSet, - UsdTimeCode time ) -{ - //TODO: The exclude set should be a GT_GEOAttributeFilter - - static const GtDataToUsdTypename usdTypename; - - UsdPrim prim = usdGeomPrim.GetPrim(); - if( !gtAttrs ) - return; - - const GT_AttributeMapHandle attrMapHandle = gtAttrs->getMap(); - for(AttrMapIterator mapIt=attrMapHandle->begin(); !mapIt.atEnd(); ++mapIt) { - -#if SYS_VERSION_FULL_INT < 0x11000000 - string name = mapIt.name(); -#else - string name = mapIt->first.toStdString(); -#endif - -#if (GUSD_VER_CMP_1(>=,15)) - const int attrIndex = attrMapHandle->get(name); -#else - const int attrIndex = attrMapHandle->getMapIndex(mapIt.thing()); -#endif - const GT_DataArrayHandle& gtData = gtAttrs->get(attrIndex); - - if( TfStringStartsWith( name, "__" ) || - excludeSet.find( name ) != excludeSet.end() ) { - continue; - } - - const SdfValueTypeName typeName = usdTypename( gtData, false ); - - UsdAttribute attr = - prim.CreateAttribute( TfToken( name ), typeName ); - - setUsdAttribute( attr, gtData, time ); - } -} - - - - -GT_DataArrayHandle GusdGT_Utils:: -getTransformArray(const GT_PrimitiveHandle& gtPrim) -{ - GT_DataArrayHandle ret; - if(gtPrim) { - UT_Matrix4D houXform; - gtPrim->getPrimitiveTransform()->getMatrix(houXform); - GT_Real64Array* gtData = new GT_Real64Array(houXform.data(), 1, 16); - ret = gtData; - } - return ret; -} - - -GT_DataArrayHandle GusdGT_Utils:: -getPackedTransformArray(const GT_PrimitiveHandle& gtPrim) -{ - GT_DataArrayHandle ret; - if(gtPrim) { - const GT_GEOPrimPacked* gtPacked - = dynamic_cast(gtPrim.get()); - if(gtPacked) { - UT_Matrix4D houXform; - gtPacked->getPrim()->getFullTransform4(houXform); - GT_Real64Array* gtData = new GT_Real64Array(houXform.data(), 1, 16); - ret = gtData; - } - } - return ret; -} - - -bool GusdGT_Utils:: -setTransformFromGTArray(const UsdGeomXformable& usdGeom, - const GT_DataArrayHandle& xform, - const TransformLevel transformLevel, - UsdTimeCode time) -{ - if(!usdGeom || !xform) return false; - - bool resetsXformStack=false; - std::vector xformOps = usdGeom.GetOrderedXformOps( - &resetsXformStack); - if(xformOps.size() <= transformLevel) return false; - - GfMatrix4d mat4; - if (_ConvertToUsd::fillValue(mat4, xform)) { - return xformOps[transformLevel].Set(mat4, time); - } - return false; -} - -GfMatrix4d GusdGT_Utils:: -getMatrixFromGTArray(const GT_DataArrayHandle& xform) -{ - GfMatrix4d mat4; - if (!_ConvertToUsd::fillValue(mat4, xform)) { - mat4.SetIdentity(); - } - return mat4; -} - -GT_DataArrayHandle GusdGT_Utils:: -transformPoints( - GT_DataArrayHandle pts, - const UT_Matrix4D& objXform ) -{ - GT_Real32Array *newPts = - new GT_Real32Array( pts->entries(), 3, pts->getTypeInfo() ); - UT_Vector3F* dstP = reinterpret_cast(newPts->data()); - - GT_DataArrayHandle buffer; - const UT_Vector3F* srcP = - reinterpret_cast(pts->getF32Array( buffer )); - for( GT_Size i = 0; i < pts->entries(); ++i ) { - *dstP++ = *srcP++ * objXform; - } - return newPts; -} - -GT_DataArrayHandle GusdGT_Utils:: -transformPoints( - GT_DataArrayHandle pts, - const GfMatrix4d& objXform ) -{ - return transformPoints( pts, GusdUT_Gf::Cast( objXform ) ); -} -//############################################################################# - -GT_AttributeListHandle GusdGT_Utils:: -getAttributesFromPrim( const GEO_Primitive *prim ) -{ - const GA_Detail& detail = prim->getDetail(); - GA_Offset offset = prim->getMapOffset(); - GA_Range range = GA_Range( detail.getPrimitiveMap(), offset, offset + 1 ); - const GA_AttributeDict& attrDict = detail.getAttributeDict(GA_ATTRIB_PRIMITIVE); - if( attrDict.entries() == 0 ) - return GT_AttributeListHandle(); - - GT_AttributeListHandle attrList = new GT_AttributeList(new GT_AttributeMap()); - for( GA_AttributeDict::iterator it=attrDict.begin(); !it.atEnd(); ++it) - { - GA_Attribute *attr = it.attrib(); - // Ignore any attributes which define groups. - if( attr && !GA_ATIGroupBool::isType( attr )) - { - GT_DataArrayHandle array = GT_Util::extractAttribute( *attr, range ); - attrList = attrList->addAttribute( attr->getName(), array, true ); - } - } - return attrList; -} - -std::string GusdGT_Utils:: -makeValidIdentifier(const TfToken& usdFilePath, const SdfPath& nodePath) -{ - return TfMakeValidIdentifier(usdFilePath) - + "__" + TfMakeValidIdentifier(nodePath.GetString()); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/GT_Utils.h b/third_party/houdini/gusd/GT_Utils.h deleted file mode 100644 index 0e78e53e90..0000000000 --- a/third_party/houdini/gusd/GT_Utils.h +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_UTILS_H -#define GUSD_GT_UTILS_H - -#include "api.h" - -#include -#include -#include -#include -#include -#include - -#include "pxr/pxr.h" -#include "pxr/base/gf/half.h" -#include "pxr/usd/usd/common.h" -#include "pxr/usd/usd/timeCode.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -class GfMatrix4d; -class GusdContext; -class SdfPath; -class SdfValueTypeName; -class TfToken; -class UsdAttribute; -class UsdGeomBoundable; -class UsdGeomImageable; -class UsdGeomXformable; - -//------------------------------------------------------------------------------ -// class GusdGT_AttrFilter -//------------------------------------------------------------------------------ -class GusdGT_AttrFilter -{ -public: - typedef UT_VariadicT OwnerArgs; - -public: - - GUSD_API - explicit GusdGT_AttrFilter(const std::string& pattern="*"); - - GUSD_API - GusdGT_AttrFilter( const GusdGT_AttrFilter& rhs ); - - GUSD_API - void setPattern(GT_Owner owner, const std::string& pattern); - - GUSD_API - void appendPattern(GT_Owner owner, const std::string& pattern); - - GUSD_API - bool matches(const std::string& str) const; - - GUSD_API - void setActiveOwners(const OwnerArgs& owners) const; - -private: - UT_Map m_patterns; - - std::string m_overridePattern; - - mutable OwnerArgs m_activeOwners; -}; - -//------------------------------------------------------------------------------ -// class GusdGT_Utils -//------------------------------------------------------------------------------ -class GusdGT_Utils -{ -public: - enum TransformLevel { - TransformLevelObject, - TransformLevelIntrinsic, - - TransformLevelCount - }; - -public: - - /// Returns the GT_Type corresponding to a USD type. - static GT_Type getType(const SdfValueTypeName& typeName); - - /// Returns the USD role name corresponding to the given GT type. - static TfToken getRole(GT_Type type); - - static bool setUsdAttribute(const UsdAttribute& destAttr, - const GT_DataArrayHandle& sourceAttr, - UsdTimeCode time=UsdTimeCode::Default()); - - static GT_DataArrayHandle getExtentsArray(const GT_PrimitiveHandle& gtPrim); - - static bool setPrimvarSample( const UsdGeomImageable& usdPrim, - const TfToken &name, - const GT_DataArrayHandle& data, - const TfToken& interpolation, - UsdTimeCode time ); - - static bool isDataConstant( const GT_DataArrayHandle& data ); - - static void setCustomAttributesFromGTPrim( - const UsdGeomImageable &usdGeomPrim, - const GT_AttributeListHandle& gtAttrs, - std::set& excludeSet, - UsdTimeCode time=UsdTimeCode::Default()); - - - // TODO remove - static bool setTransformFromGTArray(const UsdGeomXformable& usdGeom, - const GT_DataArrayHandle& xform, - const TransformLevel transformLevel, - UsdTimeCode time=UsdTimeCode::Default()); - - static GT_DataArrayHandle - getTransformArray(const GT_PrimitiveHandle& gtPrim); - - static GT_DataArrayHandle - getPackedTransformArray(const GT_PrimitiveHandle& gtPrim); - - static GfMatrix4d getMatrixFromGTArray(const GT_DataArrayHandle& xform); - - static GT_DataArrayHandle - transformPoints( - GT_DataArrayHandle pts, - const GfMatrix4d& objXform ); - - static GT_DataArrayHandle - transformPoints( - GT_DataArrayHandle pts, - const UT_Matrix4D& objXform ); - - static GT_AttributeListHandle - getAttributesFromPrim( const GEO_Primitive *prim ); - - static std::string - makeValidIdentifier(const TfToken& usdFilePath, const SdfPath& nodePath); - - - /// Struct for querying storage by POD type. - /// XXX: replace this with a constexpr in C++11. - template - struct StorageByType; -}; -//------------------------------------------------------------------------------ - - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_UINT8; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_UINT8; }; - -#if SYS_VERSION_FULL_INT >= 0x11000000 -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_INT8; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_INT16; }; -#endif - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_INT32; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_INT64; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_REAL16; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_REAL16; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_REAL32; }; - -template <> -struct GusdGT_Utils::StorageByType -{ static const GT_Storage value = GT_STORE_REAL64; }; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_GT_UTILS_H - diff --git a/third_party/houdini/gusd/GT_VtArray.h b/third_party/houdini/gusd/GT_VtArray.h deleted file mode 100644 index 94be465741..0000000000 --- a/third_party/houdini/gusd/GT_VtArray.h +++ /dev/null @@ -1,354 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_VT_ARRAY_H -#define GUSD_GT_VT_ARRAY_H - -#include -#include -#include -#include -#include - -#include "pxr/pxr.h" -#include "pxr/base/vt/array.h" - -#include "UT_TypeTraits.h" -#include "GT_Utils.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/// GT_DataArray implementation that wraps a VtArray. -/// -/// This allows, in some cases, for arrays read in from USD to be -/// pushed into GT prims without having to incur copying. -/// Example: -/// \code -/// VtArray valsFromUSD; -/// GT_DataArrayHandle hnd(new GusdGT_VtArray(valsFromUSD)); -/// \endcode -/// -/// These arrays are designed to be read-only. -/// If you need to make edits, use the following pattern: -/// -/// \code -/// GusdGT_VtArray srcData; -/// // swap data into tmp array, modify. -/// VtArray tmp; -/// srcData.swap(tmp); -/// tmp[10] = 37; -/// // swap data back into place. -/// srcData.swap(tmp); -/// \endcode -/// -/// Note that this kind of swapping trick does *not* require the -/// full array to be copied; only the internal references are swapped. -template -class GusdGT_VtArray : public GT_DataArray -{ -public: - SYS_STATIC_ASSERT(GusdIsPodTuple()); - - using This = GusdGT_VtArray; - using ValueType = T; - using ArrayType = VtArray; - using PODType = typename GusdPodTupleTraits::ValueType; - - static const int tupleSize = GusdGetTupleSize(); - static const GT_Storage storage = - GusdGT_Utils::StorageByType::value; - - GusdGT_VtArray(const ArrayType& array, GT_Type type=GT_TYPE_NONE); - GusdGT_VtArray(GT_Type type=GT_TYPE_NONE); - - ~GusdGT_VtArray() override = default; - - virtual const char* className() const { return "GusdGT_VtArray"; } - - const T& operator()(GT_Offset o) const - { - UT_ASSERT_P(o >= 0 && o <= _size); - return reinterpret_cast(_data)[o]; - } - - PODType operator()(GT_Offset o, int idx) const - { return getT(o, idx); } - - const ArrayType& operator*() const { return _array; } - - const PODType* data() const { return _data; } - - /// Swap our array contents with another array. - void swap(ArrayType& o); - - virtual GT_DataArrayHandle harden() const; - - const PODType* getData(GT_Offset o) const - { - UT_ASSERT_P(o >= 0 && o <= _size); - return _data + o*tupleSize; - } - - /// Access to individual elements as given POD type. - /// For performance, this is preferred to the virtual getXX() methods. - template - PODT getT(GT_Offset o, int idx=0) const; - - /// Get access to a raw array of data. - /// If @a OTHERPODT is not the same as the array's underlying type, - /// the raw array will be stored in the given @a buf. - template - const PODT* getArrayT(GT_DataArrayHandle& buf) const; - - /// Extract a tuple into @a dst - template - void importT(GT_Offset o, PODT* dst, int tsize=-1) const; - - /// Extract data for entire array into @a dst. - template - void fillArrayT(PODT* dst, GT_Offset start, GT_Size length, - int tsize=-1, int stride=-1) const; - - /// Extended form of array extraction that supports repeated elems. - template - void extendedFillT(PODT* dst, GT_Offset start, - GT_Size length, int tsize=-1, - int nrepeats=1, int stride=-1) const; - - virtual GT_Storage getStorage() const { return storage; } - virtual GT_Size getTupleSize() const { return tupleSize; } - virtual GT_Size entries() const { return _size; } - virtual GT_Type getTypeInfo() const { return _type; } - virtual int64 getMemoryUsage() const - { return sizeof(*this) + sizeof(T)*_size; } - - // Type-specific virtual getters. - -#define _DECL_GETTERS(suffix,podt) \ -public: \ - virtual podt SYS_CONCAT(get,suffix)(GT_Offset o, int idx=0) const\ - { return getT(o, idx); } \ - \ - virtual const podt* SYS_CONCAT(get,SYS_CONCAT(suffix,Array)) \ - (GT_DataArrayHandle& buf) const \ - { return getArrayT(buf); } \ - \ -protected: \ - virtual void doImport(GT_Offset o, podt* dst, GT_Size tsize) const\ - { importT(o, dst, tsize); } \ - \ - virtual void doFillArray(podt* dst, GT_Offset start, GT_Size length,\ - int tsize, int stride) const \ - { fillArrayT(dst, start, length, tsize, stride); }\ - \ - virtual void extendedFill(podt* dst, GT_Offset start, \ - GT_Size length, int tsize, \ - int nrepeats, int stride=-1) const \ - { extendedFillT(dst, start, length, \ - tsize, nrepeats, stride); } - -#if SYS_VERSION_FULL_INT >= 0x10050000 - _DECL_GETTERS(I8, int8); - _DECL_GETTERS(I16, int16); -#endif - _DECL_GETTERS(U8, uint8); - _DECL_GETTERS(I32, int32); - _DECL_GETTERS(I64, int64); - _DECL_GETTERS(F16, fpreal16); - _DECL_GETTERS(F32, fpreal32); - _DECL_GETTERS(F64, fpreal64); - -#undef _DECL_GETTER - -protected: - /// Update our @a _data member to point at the array data. - /// This must be called after any operation that changes - /// the contents of @a _array. - void _UpdateDataPointer(bool makeUnique); - -private: - // No string support. For strings, use GusdGT_VtStringArray. - virtual GT_String getS(GT_Offset, int) const { return nullptr; } - virtual GT_Size getStringIndexCount() const { return -1; } - virtual GT_Offset getStringIndex(GT_Offset,int) const { return -1; } - virtual void getIndexedStrings(UT_StringArray&, - UT_IntArray&) const {} - -protected: - ArrayType _array; - const GT_Type _type; - GT_Size _size; - const PODType* _data; /// Raw pointer to the underlying data. - /// Held separately as an optimization. -}; - - -template -GusdGT_VtArray::GusdGT_VtArray(const ArrayType& array, GT_Type type) - : _array(array), _type(type), _size(array.size()) -{ - _UpdateDataPointer(false); -} - - -template -GusdGT_VtArray::GusdGT_VtArray(GT_Type type) - : _type(type), _size(0), _data(nullptr) -{} - - -template -void -GusdGT_VtArray::_UpdateDataPointer(bool makeUnique) -{ - // Access a non-const pointer to make the array unique. - _data = reinterpret_cast( - makeUnique ? _array.data() : _array.cdata()); - UT_ASSERT(_size == 0 || _data != nullptr); -} - - -template -void -GusdGT_VtArray::swap(ArrayType& o) -{ - _array.swap(o); - _size = _array.GetSize(); - _UpdateDataPointer(false); -} - - -template -GT_DataArrayHandle -GusdGT_VtArray::harden() const -{ - This* copy = new This(_array, _type); - copy->_UpdateDataPointer(true); - return GT_DataArrayHandle(copy); -} - - -template -template -PODT -GusdGT_VtArray::getT(GT_Offset o, int idx) const -{ - UT_ASSERT_P(o >= 0 && o < _size); - UT_ASSERT_P(idx >= 0 && idx < tupleSize); - return static_cast(_data[tupleSize*o + idx]); -} - - -template -template -const PODT* -GusdGT_VtArray::getArrayT(GT_DataArrayHandle& buf) const -{ - if(SYS_IsSame::value) - return reinterpret_cast(_data); - -#if SYS_VERSION_FULL_INT < 0x10050000 - using _GTArrayType = - GT_DANumeric::value>; -#else - using _GTArrayType = GT_DANumeric; -#endif - - _GTArrayType* tmpArray = new _GTArrayType(_size, tupleSize, _type); - fillArrayT(tmpArray->data(), 0, _size, tupleSize); - buf = tmpArray; - return tmpArray->data(); -} - - -template -template -void -GusdGT_VtArray::importT(GT_Offset o, PODT* dst, int tsize) const -{ - tsize = tsize < 1 ? tupleSize : SYSmin(tsize, tupleSize); - const PODType* src = getData(o); - if( src ) - { - for(int i = 0; i < tsize; ++i) - dst[i] = static_cast(src[i]); - } -} - - -template -template -void -GusdGT_VtArray::fillArrayT(PODT* dst, GT_Offset start, GT_Size length, - int tsize, int stride) const -{ - if(_size == 0) - return; - if(tsize < 1) - tsize = tupleSize; - // Stride is >= the unclamped tuple size. - // This seems wrong, but is consistent with GT_DANumeric. - stride = SYSmax(stride, tsize); - tsize = SYSmin(tsize, tupleSize); - if(SYS_IsSame::value && - tsize == tupleSize && stride == tupleSize) { - // direct copy is safe - memcpy(dst, getData(start), length*tsize*sizeof(PODT)); - } else { - const PODType* src = getData(start*tupleSize); - for(GT_Offset i = 0; i < length; ++i, src += tupleSize, dst += stride) { - for(int j = 0; j < tsize; ++j) - dst[j] = static_cast(src[j]); - } - } -} - - -template -template -void -GusdGT_VtArray::extendedFillT(PODT* dst, GT_Offset start, - GT_Size length, int tsize, - int nrepeats, int stride) const -{ - if(nrepeats == 1) - return fillArrayT(dst, start, length, tsize, stride); - if(_size == 0) - return; - if(tsize < 1) - tsize = tupleSize; - stride = SYSmax(stride, tsize); - tsize = SYSmin(tsize, tupleSize); - - const PODType* src = getData(start*tupleSize); - for(GT_Offset i = 0; i < length; ++i, src += tupleSize) { - for(int r = 0; r < nrepeats; ++r, dst += stride) { - for(int j = 0; j < tsize; ++j) - dst[j] = static_cast(src[j]); - } - } -} - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_GT_VT_ARRAY_H*/ diff --git a/third_party/houdini/gusd/GT_VtStringArray.h b/third_party/houdini/gusd/GT_VtStringArray.h deleted file mode 100644 index bfc12c3386..0000000000 --- a/third_party/houdini/gusd/GT_VtStringArray.h +++ /dev/null @@ -1,225 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GT_VT_STRING_ARRAY_H -#define GUSD_GT_VT_STRING_ARRAY_H - - -#include - -#include "pxr/pxr.h" -#include "pxr/usd/sdf/assetPath.h" -#include "pxr/usd/sdf/path.h" -#include "pxr/base/vt/array.h" -#include "pxr/base/tf/token.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** GT_DataArray implementation wrapping VtArray for - string-like types. I.e., std::string, TfToken, et. al. - - @warning: The GT_String (const char*) pointer returned for all empty - strings is always the NULL pointer. This includes std::string, which - can't be constructed from a NULL string. Be careful when reconstring - source objects! */ -template -class GusdGT_VtStringArray : public GT_DataArray -{ -public: - typedef GusdGT_VtStringArray This; - typedef T ValueType; - typedef VtArray ArrayType; - - - GusdGT_VtStringArray(); - GusdGT_VtStringArray(const ArrayType& array); - - virtual ~GusdGT_VtStringArray() {} - - virtual const char* className() const { return "GusdGT_VtStringArray"; } - - const T& operator()(GT_Offset o) const - { - UT_ASSERT_P(o >= 0 && o <= _size); - return _data[o]; - } - - const ArrayType& operator*() const { return _array; } - - /* Non-virtual string accessor.*/ - GT_String getString(GT_Offset o) const - { return _GetString((*this)(o)); } - - /** Swap our array contents with another array.*/ - void swap(ArrayType& o); - - virtual GT_DataArrayHandle harden() const; - - virtual GT_String getS(GT_Offset o, int idx=0) const - { return getString(o); } - - /** Indexed strings are not currently supported in Vt.*/ - virtual GT_Size getStringIndexCount() const { return -1; } - virtual GT_Offset getStringIndex(GT_Offset, int) const { return -1; } - virtual void getIndexedStrings(UT_StringArray&, - UT_IntArray&) const {} - - virtual GT_Storage getStorage() const { return GT_STORE_STRING; } - virtual GT_Size getTupleSize() const { return 1; } - virtual GT_Size entries() const { return _size; } - virtual GT_Type getTypeInfo() const { return GT_TYPE_NONE; } - virtual int64 getMemoryUsage() const - { return sizeof(*this) + sizeof(T)*_size; } - -protected: - /** Update our @a _data member to point at the array data. - This must be called after any operation that changes - the contents of @a _array.*/ - void _UpdateDataPointer(bool makeUnique); - - /** Return a GT_String from one of our elems. - This must be specialized per element type.*/ - GT_String _GetString(const T& o) const; - - GT_String _GetStringFromStdString(const std::string& o) const - { return o.empty() ? NULL : o.c_str(); } - -private: - /** No numeric accessors supported.*/ - virtual uint8 getU8(GT_Offset, int idx) const { return 0; } - virtual int32 getI32(GT_Offset, int idx) const { return 0; } - virtual fpreal32 getF32(GT_Offset, int idx) const { return 0; } - -private: - ArrayType _array; - GT_Size _size; - const T* _data; /*! Raw pointer to the underlying data. - This is held in order to avoid referencing - checks on every array lookup.*/ -}; - - -template -GusdGT_VtStringArray::GusdGT_VtStringArray(const ArrayType& array) - : _array(array), _size(array.size()) -{ - _UpdateDataPointer(false); -} - - -template -GusdGT_VtStringArray::GusdGT_VtStringArray() - : _size(0), _data(NULL) -{} - - -template -void -GusdGT_VtStringArray::_UpdateDataPointer(bool makeUnique) -{ - /* Access a non-const pointer to make the array unique.*/ - _data = makeUnique ? _array.data() : _array.cdata(); - UT_ASSERT(_size == 0 || _data != NULL); -} - - -template -void -GusdGT_VtStringArray::swap(ArrayType& o) -{ - _array.swap(o); - _size = _array.size(); - _UpdateDataPointer(false); -} - - -template -GT_DataArrayHandle -GusdGT_VtStringArray::harden() const -{ - This* copy = new This(_array); - copy->_UpdateDataPointer(true); - return GT_DataArrayHandle(copy); -} - - -template <> -GT_String -GusdGT_VtStringArray::_GetString(const std::string& o) const -{ return _GetStringFromStdString(o); } - - -template <> -GT_String -GusdGT_VtStringArray::_GetString(const TfToken& o) const -{ return _GetStringFromStdString(o.GetString()); } - - -template <> -GT_String -GusdGT_VtStringArray::_GetString(const SdfPath& o) const -{ return _GetStringFromStdString(o.GetString()); } - - -template <> -GT_String -GusdGT_VtStringArray::_GetString(const SdfAssetPath& o) const -{ return _GetStringFromStdString(o.GetAssetPath()); } - - - -template <> -int64 -GusdGT_VtStringArray::getMemoryUsage() const -{ - int64 sz = sizeof(*this) + sizeof(ValueType)*_size; - for(GT_Size i = 0; i < _size; ++i) - sz += _data[i].size()*sizeof(char); - return sz; -} - - -template <> -int64 -GusdGT_VtStringArray::getMemoryUsage() const -{ - int64 sz = sizeof(*this) + sizeof(ValueType)*_size; - for(GT_Size i = 0; i < _size; ++i) { - const SdfAssetPath& p = _data[i]; - sz += (p.GetAssetPath().size() + - p.GetResolvedPath().size())*sizeof(char); - } - return sz; -} - -/** TODO: Specialization of getMemoryUsage for SdPath? */ - - -typedef GusdGT_VtStringArray GusdGT_VtStdStringArray; -typedef GusdGT_VtStringArray GusdGT_VtTokenArray; -typedef GusdGT_VtStringArray GusdGT_VtPathArray; -typedef GusdGT_VtStringArray GusdGT_VtAssetPathArray; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_GT_VT_STRING_ARRAY_H*/ diff --git a/third_party/houdini/gusd/GU_PackedUSD.cpp b/third_party/houdini/gusd/GU_PackedUSD.cpp deleted file mode 100644 index 74a7e4c103..0000000000 --- a/third_party/houdini/gusd/GU_PackedUSD.cpp +++ /dev/null @@ -1,985 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GU_PackedUSD.h" - -#include "boundsCache.h" -#include "GT_PackedUSD.h" -#include "GT_PrimCache.h" -#include "GT_Utils.h" -#include "GU_USD.h" -#include "meshWrapper.h" -#include "pointsWrapper.h" -#include "primWrapper.h" -#include "stageEdit.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" -#include "xformWrapper.h" - -#include "pxr/base/tf/fileUtils.h" -#include "pxr/base/tf/stringUtils.h" - -#include "pxr/usd/usd/primRange.h" - -#include "pxr/usd/usdGeom/mesh.h" -#include "pxr/usd/usdGeom/pointBased.h" -#include "pxr/usd/usdGeom/points.h" -#include "pxr/usd/usdGeom/scope.h" -#include "pxr/usd/usdGeom/xform.h" -#include "pxr/usd/usdGeom/xformable.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cout; -using std::cerr; -using std::endl; -using std::string; -using std::vector; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -namespace { - -class UsdPackedFactory : public GU_PackedFactory -{ -public: - UsdPackedFactory() - : GU_PackedFactory("PackedUSD", "Packed USD") - { - registerIntrinsic("usdFileName", - StringHolderGetterCast(&GusdGU_PackedUSD::intrinsicFileName), - StringHolderSetterCast(&GusdGU_PackedUSD::setFileName)); - registerIntrinsic("usdAltFileName", - StringHolderGetterCast(&GusdGU_PackedUSD::intrinsicAltFileName), - StringHolderSetterCast(&GusdGU_PackedUSD::setAltFileName)); - registerIntrinsic("usdPrimPath", - StringHolderGetterCast(&GusdGU_PackedUSD::intrinsicPrimPath), - StringHolderSetterCast(&GusdGU_PackedUSD::setPrimPath)); - // The USD prim's localToWorldTransform is stored in this intrinsic. - // This may differ from the packed prim's actual transform. - registerTupleIntrinsic("usdLocalToWorldTransform", - IntGetterCast(&GusdGU_PackedUSD::usdLocalToWorldTransformSize), - F64VectorGetterCast(&GusdGU_PackedUSD::usdLocalToWorldTransform), - NULL); - registerIntrinsic("usdFrame", - FloatGetterCast(&GusdGU_PackedUSD::intrinsicFrame), - FloatSetterCast(&GusdGU_PackedUSD::setFrame)); - registerIntrinsic("usdSrcPrimPath", - StringHolderGetterCast(&GusdGU_PackedUSD::intrinsicSrcPrimPath), - StringHolderSetterCast(&GusdGU_PackedUSD::setSrcPrimPath)); - registerIntrinsic("usdIndex", - IntGetterCast(&GusdGU_PackedUSD::index), - IntSetterCast(&GusdGU_PackedUSD::setIndex)); - registerIntrinsic("usdType", - StringHolderGetterCast(&GusdGU_PackedUSD::intrinsicType)); - registerTupleIntrinsic("usdViewportPurpose", - IntGetterCast(&GusdGU_PackedUSD::getNumPurposes), - StringArrayGetterCast(&GusdGU_PackedUSD::getIntrinsicPurposes), - StringArraySetterCast(&GusdGU_PackedUSD::setIntrinsicPurposes)); - } - virtual ~UsdPackedFactory() {} - - virtual GU_PackedImpl *create() const - { - return new GusdGU_PackedUSD(); - } -}; - -static UsdPackedFactory *theFactory = NULL; -const char* k_typeName = "PackedUSD"; - -} // close namespace - -/* static */ -GU_PrimPacked* -GusdGU_PackedUSD::Build( - GU_Detail& detail, - const UT_StringHolder& fileName, - const SdfPath& primPath, - UsdTimeCode frame, - const char* lod, - GusdPurposeSet purposes, - const UsdPrim& prim, - const UT_Matrix4D* xform ) -{ - auto packedPrim = GU_PrimPacked::build( detail, k_typeName ); - auto impl = UTverify_cast(packedPrim->implementation()); - impl->m_fileName = fileName; - impl->m_primPath = primPath; - impl->m_frame = frame; - - if( prim && !prim.IsA() ) - { - UsdGeomImageable geom = UsdGeomImageable(prim); - std::vector authoredPrimvars = geom.GetAuthoredPrimvars(); - GT_DataArrayHandle buffer; - - for( const UsdGeomPrimvar &primvar : authoredPrimvars ) { - // XXX This is temporary code, we need to factor the usd read code into GT_Utils.cpp - // to avoid duplicates and read for types GfHalf,double,int,string ... - GT_DataArrayHandle gtData = GusdPrimWrapper::convertPrimvarData( primvar, frame ); - if (!gtData) - continue; - - const UT_String name(primvar.GetPrimvarName()); - const GT_Storage gtStorage = gtData->getStorage(); - const GT_Size gtTupleSize = gtData->getTupleSize(); - - GA_Attribute *anAttr = detail.addTuple(GT_Util::getGAStorage(gtStorage), GA_ATTRIB_PRIMITIVE, name, - gtTupleSize); - - if( !anAttr ) { - // addTuple could fail for various reasons, like if there's a - // non-alphanumeric character in the primvar name. - continue; - } - - if( const GA_AIFTuple *aIFTuple = anAttr->getAIFTuple()) { - - const float* flatArray = gtData->getF32Array( buffer ); - aIFTuple->set( anAttr, packedPrim->getMapOffset(), flatArray, gtTupleSize ); - - } else { - - //TF_WARN( "Unsupported primvar type: %s, %s, tupleSize = %zd", - // GT_String( name ), GTstorage( gtStorage ), gtTupleSize ); - } - } - } - - if( lod ) - { -#if SYS_VERSION_FULL_INT < 0x10050000 - impl->intrinsicSetViewportLOD( lod ); -#else - impl->intrinsicSetViewportLOD( packedPrim, lod ); -#endif - } - impl->setPurposes( purposes ); - - // It seems that Houdini may reuse memory for packed implementations with - // out calling the constructor to initialize data. - impl->resetCaches(); - - // If a UsdPrim was passed in, make sure it is used. - impl->m_usdPrim = prim; - - if (xform) { - impl->setTransform(*xform); - } else { - impl->updateTransform(); - } - return packedPrim; -} - -/* static */ -GU_PrimPacked* -GusdGU_PackedUSD::Build( - GU_Detail& detail, - const UT_StringHolder& fileName, - const SdfPath& primPath, - const SdfPath& srcPrimPath, - int index, - UsdTimeCode frame, - const char* lod, - GusdPurposeSet purposes, - const UsdPrim& prim, - const UT_Matrix4D* xform ) -{ - auto packedPrim = GU_PrimPacked::build( detail, k_typeName ); - auto impl = UTverify_cast(packedPrim->implementation()); - impl->m_fileName = fileName; - impl->m_primPath = primPath; - impl->m_srcPrimPath = srcPrimPath; - impl->m_index = index; - impl->m_frame = frame; - if( lod ) - { -#if SYS_VERSION_FULL_INT < 0x10050000 - impl->intrinsicSetViewportLOD( lod ); -#else - impl->intrinsicSetViewportLOD( packedPrim, lod ); -#endif - } - impl->setPurposes( purposes ); - - // It seems that Houdini may reuse memory for packed implementations with - // out calling the constructor to initialize data. - impl->resetCaches(); - - // If a UsdPrim was passed in, make sure it is used. - impl->m_usdPrim = prim; - - if (xform) { - impl->setTransform(*xform); - } else { - impl->updateTransform(); - } - return packedPrim; -} - - -/* static */ -GU_PrimPacked* -GusdGU_PackedUSD::Build( - GU_Detail& detail, - const UsdPrim& prim, - UsdTimeCode frame, - const char* lod, - GusdPurposeSet purposes, - const UT_Matrix4D* xform ) -{ - // TODO: Should we pull the identifier from the root layer as the file name? - return GusdGU_PackedUSD::Build(detail, /*fileName*/ UT_StringHolder(), - prim.GetPath(), frame, lod, - purposes, prim, xform); -} - - -GusdGU_PackedUSD::GusdGU_PackedUSD() - : GU_PackedImpl() - , m_transformCacheValid(false) - , m_masterPathCacheValid(false) - , m_index(-1) - , m_frame(std::numeric_limits::min()) - , m_purposes( GusdPurposeSet( GUSD_PURPOSE_DEFAULT | GUSD_PURPOSE_PROXY )) -{ -} - -GusdGU_PackedUSD::GusdGU_PackedUSD( const GusdGU_PackedUSD &src ) - : GU_PackedImpl( src ) - , m_fileName( src.m_fileName ) - , m_altFileName( src.m_altFileName ) - , m_primPath( src.m_primPath ) - , m_srcPrimPath( src.m_srcPrimPath ) - , m_index( src.m_index ) - , m_frame( src.m_frame ) - , m_purposes( src.m_purposes ) - , m_usdPrim( src.m_usdPrim ) -#if SYS_VERSION_FULL_INT < 0x12000000 - , m_boundsCache( src.m_boundsCache ) -#endif - , m_transformCacheValid( src.m_transformCacheValid ) - , m_transformCache( src.m_transformCache ) - , m_masterPathCacheValid( src.m_masterPathCacheValid ) - , m_masterPathCache( src.m_masterPathCache ) - , m_gtPrimCache( NULL ) -{ - topologyDirty(); -} - -GusdGU_PackedUSD::~GusdGU_PackedUSD() -{ -} - -void -GusdGU_PackedUSD::install( GA_PrimitiveFactory &gafactory ) -{ - if (theFactory) - return; - - theFactory = new UsdPackedFactory(); - GU_PrimPacked::registerPacked( &gafactory, theFactory ); - - const GA_PrimitiveDefinition* def = - GU_PrimPacked::lookupTypeDef( k_typeName ); - - // Bind GEOPrimCollect for collecting GT prims for display in the viewport - static GusdGT_PrimCollect *collector = new GusdGT_PrimCollect(); - collector->bind(def->getId()); -} - -GA_PrimitiveTypeId -GusdGU_PackedUSD::typeId() -{ - return GU_PrimPacked::lookupTypeId( k_typeName ); -} - -void -GusdGU_PackedUSD::resetCaches() -{ -#if SYS_VERSION_FULL_INT < 0x12000000 - m_boundsCache.makeInvalid(); -#endif - m_usdPrim = UsdPrim(); - m_transformCacheValid = false; - m_gtPrimCache = GT_PrimitiveHandle(); -} - -void -GusdGU_PackedUSD::updateTransform() -{ - setTransform(getUsdTransform()); -} - -void -GusdGU_PackedUSD::setTransform( const UT_Matrix4D& mx ) -{ - UT_Vector3D p; - mx.getTranslates(p); - - GEO_PrimPacked *prim = getPrim(); - prim->setLocalTransform(UT_Matrix3D(mx)); - prim->setPos3(0, p ); -} - -void -GusdGU_PackedUSD::setFileName( const UT_StringHolder& fileName ) -{ - if( fileName != m_fileName ) - { - m_fileName = fileName; - topologyDirty(); // Notify base primitive that topology has changed - resetCaches(); - updateTransform(); - } -} - -void -GusdGU_PackedUSD::setAltFileName( const UT_StringHolder& fileName ) -{ - if( fileName != m_altFileName ) - { - m_altFileName = fileName; - } -} - -void -GusdGU_PackedUSD::setPrimPath( const UT_StringHolder& p ) -{ - SdfPath path; - GusdUSD_Utils::CreateSdfPath(p, path); - setPrimPath(path); -} - - -void -GusdGU_PackedUSD::setPrimPath( const SdfPath &path ) -{ - if( path != m_primPath ) - { - m_primPath = path; - topologyDirty(); // Notify base primitive that topology has changed - resetCaches(); - updateTransform(); - } -} - -void -GusdGU_PackedUSD::setSrcPrimPath( const UT_StringHolder& p ) -{ - SdfPath path; - GusdUSD_Utils::CreateSdfPath(p, path); - setSrcPrimPath(path); -} - -void -GusdGU_PackedUSD::setSrcPrimPath( const SdfPath &path ) -{ - if( path != m_srcPrimPath ) { - m_srcPrimPath = path; - } -} - -void -GusdGU_PackedUSD::setIndex( exint index ) -{ - if( index != m_index ) { - m_index = index; - } -} - -void -GusdGU_PackedUSD::setFrame( UsdTimeCode frame ) -{ - if( frame != m_frame ) - { - m_frame = frame; - topologyDirty(); // Notify base primitive that topology has changed - resetCaches(); - updateTransform(); - } -} - -void -GusdGU_PackedUSD::setFrame( fpreal frame ) -{ - setFrame(UsdTimeCode(frame)); -} - -exint -GusdGU_PackedUSD::getNumPurposes() const -{ - exint rv = 0; - if( m_purposes & GUSD_PURPOSE_PROXY ) - ++rv; - if( m_purposes & GUSD_PURPOSE_RENDER ) - ++rv; - if( m_purposes & GUSD_PURPOSE_GUIDE ) - ++rv; - return rv; -} - -void -GusdGU_PackedUSD::setPurposes( GusdPurposeSet purposes ) -{ - m_purposes = purposes; - topologyDirty(); - resetCaches(); -} - -void -GusdGU_PackedUSD::getIntrinsicPurposes( UT_StringArray& purposes ) const -{ - purposes.clear(); - if( m_purposes & GUSD_PURPOSE_PROXY ) - purposes.append( UT_StringHolder( UT_StringHolder::REFERENCE, "proxy" )); - if( m_purposes & GUSD_PURPOSE_RENDER ) - purposes.append( UT_StringHolder( UT_StringHolder::REFERENCE, "render" )); - if( m_purposes & GUSD_PURPOSE_GUIDE ) - purposes.append( UT_StringHolder( UT_StringHolder::REFERENCE, "guide" )); -} - -void -GusdGU_PackedUSD::setIntrinsicPurposes( const UT_StringArray& purposes ) -{ - // always include default purpose - setPurposes(GusdPurposeSet(GusdPurposeSetFromArray(purposes)| - GUSD_PURPOSE_DEFAULT)); -} - -UT_StringHolder -GusdGU_PackedUSD::intrinsicType() const -{ - // Return the USD prim type so it can be displayed in the spreadsheet. - UsdPrim prim = getUsdPrim(); - return GusdUSD_Utils::TokenToStringHolder( prim.GetTypeName() ); -} - -const UT_Matrix4D & -GusdGU_PackedUSD::getUsdTransform() const -{ - if( m_transformCacheValid ) - return m_transformCache; - - UsdPrim prim = getUsdPrim(); - - if( !prim ) { - TF_WARN( "Invalid prim! %s", m_primPath.GetText() ); - m_transformCache.identity(); - return m_transformCache; - } - - if (GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - prim, m_frame, m_transformCache)) { - m_transformCacheValid = true; - } else { - m_transformCache.identity(); - } - - return m_transformCache; -} - -void -GusdGU_PackedUSD::usdLocalToWorldTransform(fpreal64* val, exint size) const -{ - UT_ASSERT(size == 16); - - if( isPointInstance() ) - { - UT_Matrix4D ident(1); - std::copy( ident.data(), ident.data()+16, val ); - } - else - { - const UT_Matrix4D &m = getUsdTransform(); - std::copy( m.data(), m.data()+16, val ); - } -} - -GU_PackedFactory* -GusdGU_PackedUSD::getFactory() const -{ - return theFactory; -} - -GU_PackedImpl* -GusdGU_PackedUSD::copy() const -{ - return new GusdGU_PackedUSD(*this); -} - -void -GusdGU_PackedUSD::clearData() -{ -} - -bool -GusdGU_PackedUSD::isValid() const -{ - return bool(m_usdPrim); -} - -bool -GusdGU_PackedUSD::load(const UT_Options &options, const GA_LoadMap &map) -{ - update( options ); - return true; -} - -void -GusdGU_PackedUSD::update(const UT_Options &options) -{ - UT_StringHolder fileName, altFileName, primPath; - if( options.importOption( "usdFileName", fileName ) || - options.importOption( "fileName", fileName )) - { - m_fileName = fileName; - } - - if( options.importOption( "usdAltFileName", altFileName ) || - options.importOption( "altFileName", altFileName )) - { - setAltFileName( altFileName ); - } - - if( options.importOption( "usdPrimPath", primPath ) || - options.importOption( "nodePath", primPath )) - { - GusdUSD_Utils::CreateSdfPath(primPath, m_primPath); - } - - if( options.importOption( "usdSrcPrimPath", primPath )) - { - GusdUSD_Utils::CreateSdfPath(primPath, m_srcPrimPath); - } - - exint index; - if( options.importOption( "usdIndex", index )) - { - m_index = index; - } - - fpreal frame; - if( options.importOption( "usdFrame", frame ) || - options.importOption( "frame", frame )) - { - m_frame = frame; - } - - UT_StringArray purposes; - if( options.importOption( "usdViewportPurpose", purposes )) - { - setIntrinsicPurposes( purposes ); - } - resetCaches(); -} - -bool -GusdGU_PackedUSD::save(UT_Options &options, const GA_SaveMap &map) const -{ - options.setOptionS( "usdFileName", m_fileName ); - options.setOptionS( "usdAltFileName", m_altFileName ); - options.setOptionS( "usdPrimPath", m_primPath.GetText() ); - options.setOptionS( "usdSrcPrimPath", m_srcPrimPath.GetText() ); - options.setOptionI( "usdIndex", m_index ); - options.setOptionF( "usdFrame", GusdUSD_Utils::GetNumericTime(m_frame) ); - - UT_StringArray purposes; - getIntrinsicPurposes( purposes ); - options.setOptionSArray( "usdViewportPurpose", purposes ); - return true; -} - -bool -GusdGU_PackedUSD::getBounds(UT_BoundingBox &box) const -{ - // Box caching is handled in getBoundsCached() -#if SYS_VERSION_FULL_INT < 0x12000000 - if( m_boundsCache.isValid() ) - { - box = m_boundsCache; - return true; - } -#endif - - UsdPrim prim = getUsdPrim(); - - if( !prim ) { - UT_ASSERT_MSG(0, "Invalid USD prim"); - } - - if(UsdGeomImageable visPrim = UsdGeomImageable(prim)) - { - TfTokenVector purposes = GusdPurposeSetToTokens(m_purposes); - - if ( GusdBoundsCache::GetInstance().ComputeUntransformedBound( - prim, - UsdTimeCode( m_frame ), - purposes, - box )) { -#if SYS_VERSION_FULL_INT < 0x12000000 - m_boundsCache = box; -#endif - return true; - } - } - box.makeInvalid(); - return false; -} - -bool -GusdGU_PackedUSD::getRenderingBounds(UT_BoundingBox &box) const -{ -#if SYS_VERSION_FULL_INT >= 0x12000000 - return getBoundsCached(box); -#else - return getBounds(box); -#endif -} - -void -GusdGU_PackedUSD::getVelocityRange(UT_Vector3 &min, UT_Vector3 &max) const -{ - -} - -void -GusdGU_PackedUSD::getWidthRange(fpreal &min, fpreal &max) const -{ - -} - -bool -GusdGU_PackedUSD::getLocalTransform(UT_Matrix4D &m) const -{ - return false; -} - -bool -GusdGU_PackedUSD::unpackPrim( - GU_Detail& destgdp, - UsdGeomImageable prim, - const SdfPath& primPath, - const UT_Matrix4D& xform, - const GT_RefineParms& rparms ) const -{ - GT_PrimitiveHandle gtPrim = - GusdPrimWrapper::defineForRead( - prim, - m_frame, - m_purposes ); - - if( !gtPrim ) { - const TfToken &type = prim.GetPrim().GetTypeName(); - static const TfToken PxHairman("PxHairman"); - static const TfToken PxProcArgs("PxProcArgs"); - if( type != PxHairman && type != PxProcArgs ) { - TF_WARN( "Can't convert prim for unpack. %s. Type = %s.", - prim.GetPrim().GetPath().GetText(), - type.GetText() ); - } - return false; - } - GusdPrimWrapper* wrapper = UTverify_cast(gtPrim.get()); - - if( !wrapper->unpack( - destgdp, - fileName(), - primPath, - xform, - intrinsicFrame(), -#if SYS_VERSION_FULL_INT < 0x10050000 - intrinsicViewportLOD(), -#else - intrinsicViewportLOD( getPrim() ), -#endif - m_purposes )) { - - // If the wrapper prim does not do the unpack, do it here. - UT_Array details; - - if( prim.GetPrim().IsInMaster() ) { - - gtPrim->setPrimitiveTransform( new GT_Transform( &xform, 1 ) ); - } - - - GA_Size startIndex = destgdp.getNumPrimitives(); - - GT_Util::makeGEO(details, gtPrim, &rparms); - - for (exint i = 0; i < details.entries(); ++i) - { - copyPrimitiveGroups(*details(i), false); -#if SYS_VERSION_FULL_INT < 0x11000000 - unpackToDetail(destgdp, details(i), true); -#else - unpackToDetail(destgdp, details(i), &xform); -#endif - delete details(i); - } - - if (GT_RefineParms::getBool(&rparms, "usd:addPathAttributes", true)) { - // Add usdpath and usdprimpath attributes to unpacked geometry. - const GA_Size endIndex = destgdp.getNumPrimitives(); - - if( endIndex > startIndex ) - { - GA_RWHandleS primPathAttr( - destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PRIMPATH_ATTR, 1 )); - GA_RWHandleS pathAttr( - destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PATH_ATTR, 1 )); - - const GA_Range range(destgdp.getPrimitiveMap(), - startIndex, endIndex, GA_Range::ordered()); - - if (const GA_AIFSharedStringTuple* tuple = - primPathAttr.getAttribute()->getAIFSharedStringTuple()) { - tuple->setString(primPathAttr.getAttribute(), range, - prim.GetPath().GetText(), 0); - } - if (const GA_AIFSharedStringTuple* tuple = - pathAttr.getAttribute()->getAIFSharedStringTuple()) { - tuple->setString(pathAttr.getAttribute(), range, - fileName().c_str(), 0); - } - } - } - } - return true; -} - -bool -GusdGU_PackedUSD::unpackGeometry( - GU_Detail &destgdp, - const char* primvarPattern, -#if SYS_VERSION_FULL_INT >= 0x11000000 - const UT_Matrix4D *transform, -#endif - const GT_RefineParms* refineParms) const -{ - UsdPrim usdPrim = getUsdPrim(); - - if( !usdPrim ) - { - TF_WARN( "Invalid prim found" ); - return false; - } - -#if SYS_VERSION_FULL_INT < 0x11000000 - UT_Matrix4D xform(1); - const GU_PrimPacked *prim = getPrim(); - if( prim ) { - prim->getFullTransform4(xform); - } -#endif - - GT_RefineParms rparms; - if (refineParms) { - rparms = *refineParms; - } - - // Need to manually force polysoup to be turned off. - rparms.setAllowPolySoup( false ); - - if (primvarPattern) { - rparms.set("usd:primvarPattern", primvarPattern); - } - - DBG( cerr << "GusdGU_PackedUSD::unpackGeometry: " << usdPrim.GetTypeName() << ", " << usdPrim.GetPath() << endl; ) - -#if SYS_VERSION_FULL_INT >= 0x11000000 - return unpackPrim( destgdp, UsdGeomImageable( usdPrim ), - m_primPath, *transform, rparms ); -#else - return unpackPrim( destgdp, UsdGeomImageable( usdPrim ), - m_primPath, xform, rparms ); -#endif -} - -#if SYS_VERSION_FULL_INT >= 0x11000000 -bool -GusdGU_PackedUSD::unpack(GU_Detail &destgdp, const UT_Matrix4D *transform) const -{ - // FIXME: The downstream code should support accepting a null transform. - // We shouldn't have to make a redundant identity matrix here. - UT_Matrix4D temp; - if( !transform ) { - temp.identity(); - } - // Unpack with "*" as the primvar pattern, meaning unpack all primvars. - return unpackGeometry( destgdp, "*", transform ? transform : &temp ); -} - -bool -GusdGU_PackedUSD::unpackUsingPolygons(GU_Detail &destgdp, const GU_PrimPacked *prim) const -{ - UT_Matrix4D xform; - if( prim ) { - prim->getFullTransform4(xform); - } - else { - // FIXME: The downstream code should support accepting a null transform. - // We shouldn't have to make a redundant identity matrix here. - xform.identity(); - } - // Unpack with "*" as the primvar pattern, meaning unpack all primvars. - return unpackGeometry( destgdp, "*", &xform ); -} -#else -bool -GusdGU_PackedUSD::unpack(GU_Detail &destgdp) const -{ - // Unpack with "*" as the primvar pattern, meaning unpack all primvars. - return unpackGeometry( destgdp, "*" ); -} - -bool -GusdGU_PackedUSD::unpackUsingPolygons(GU_Detail &destgdp) const -{ - // Unpack with "*" as the primvar pattern, meaning unpack all primvars. - return unpackGeometry( destgdp, "*" ); -} -#endif - -bool -GusdGU_PackedUSD::getInstanceKey(UT_Options& key) const -{ - key.setOptionS("f", m_fileName); - key.setOptionS("n", m_primPath.GetString()); - key.setOptionF("t", GusdUSD_Utils::GetNumericTime(m_frame)); - key.setOptionI("p", m_purposes ); - - if( !m_masterPathCacheValid ) { - UsdPrim usdPrim = getUsdPrim(); - - if( !usdPrim ) { - return true; - } - - // Disambiguate masters of instances by including the stage pointer. - // Sometimes instances are opened on different stages, so their - // path will both be "/__Master_1" even if they are different prims. - // TODO: hash by the Usd instancing key if it becomes exposed. - std::ostringstream ost; - ost << (void const *)get_pointer(usdPrim.GetStage()); - std::string stagePtr = ost.str(); - if( usdPrim.IsValid() && usdPrim.IsInstance() ) { - m_masterPathCache = stagePtr + - usdPrim.GetMaster().GetPrimPath().GetString(); - } - else if( usdPrim.IsValid() && usdPrim.IsInstanceProxy() ) { - m_masterPathCache = stagePtr + - usdPrim.GetPrimInMaster().GetPrimPath().GetString(); - } - else{ - m_masterPathCache = ""; - } - m_masterPathCacheValid = true; - } - - if( !m_masterPathCache.empty() ) { - // If this prim is an instance, replace the prim path with the - // master's path so that instances can share GT prims. - key.setOptionS("n", m_masterPathCache ); - } - - return true; -} - -int64 -GusdGU_PackedUSD::getMemoryUsage(bool inclusive) const -{ - int64 mem = inclusive ? sizeof(*this) : 0; - - // Don't count the (shared) GU_Detail, since that will greatly - // over-estimate the overall memory usage. - // mem += _detail.getMemoryUsage(false); - - return mem; -} - -void -GusdGU_PackedUSD::countMemory(UT_MemoryCounter &counter, bool inclusive) const -{ - // TODO -} - -bool -GusdGU_PackedUSD::visibleGT() const -{ - return true; -} - -UsdPrim -GusdGU_PackedUSD::getUsdPrim(UT_ErrorSeverity sev) const -{ - if(m_usdPrim) - return m_usdPrim; - - m_masterPathCacheValid = false; - - SdfPath primPathWithoutVariants; - GusdStageEditPtr edit; - GusdStageEdit::GetPrimPathAndEditFromVariantsPath( - m_primPath, primPathWithoutVariants, edit); - - GusdStageCacheReader cache; - m_usdPrim = cache.GetPrim(m_fileName, primPathWithoutVariants, edit, - GusdStageOpts::LoadAll(), sev).first; - return m_usdPrim; -} - - -GT_PrimitiveHandle -GusdGU_PackedUSD::fullGT() const -{ - if( m_gtPrimCache ) - return m_gtPrimCache; - - if(UsdPrim usdPrim = getUsdPrim()) { - m_gtPrimCache = GusdGT_PrimCache::GetInstance().GetPrim( - m_usdPrim, - m_frame, - m_purposes ); - } - return m_gtPrimCache; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/GU_PackedUSD.h b/third_party/houdini/gusd/GU_PackedUSD.h deleted file mode 100644 index c53f5f2786..0000000000 --- a/third_party/houdini/gusd/GU_PackedUSD.h +++ /dev/null @@ -1,325 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// - -#ifndef GUSD_GU_PACKED_USD_H -#define GUSD_GU_PACKED_USD_H - - -#include -#include -#include -#include - -#include "pxr/pxr.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usdGeom/imageable.h" -#include "purpose.h" -#include "stageEdit.h" -#include "USD_Utils.h" - -class GusdPrimDef; -class GU_PrimPacked; -class GT_RefineParms; - -PXR_NAMESPACE_OPEN_SCOPE - -/// A GU implementation of a packed USD prim. -/// -/// This is a file backed prim that holds a reference to a prim in a usd file -/// at a particular frame. The prim can be a group of prims. -/// -/// When a packed prim that references a USD group is unpacked, the result is -/// packed prims that represent the contents of that group. Those packed prims -/// may also be groups. To unpack down to the leafs, you may have to unpack may -/// times. -/// -/// When we write USD packed prim to a USD file, we write a reference to the -/// original file. USD has a limitation that it can only make references to root -/// nodes. -/// -/// When we write a reference into a USD file, we might want to use a different -/// file path than we use in the Houdini session. For example, we might want to -/// use a relative path vs. an absolute one. We might want to use a coalesced -/// file vs per frame files. We don't want to enshrine this logic in the core so -/// we provide a second alternative file name that can be used for this. If -/// this fileName is left empty, we just us the primary file name. -/// - -class GusdGU_PackedUSD : public GU_PackedImpl -{ -public: - - static GU_PrimPacked* Build( - GU_Detail& detail, - const UT_StringHolder& fileName, - const SdfPath& primPath, - UsdTimeCode frame, - const char* lod = nullptr, - GusdPurposeSet purposes = GUSD_PURPOSE_PROXY, - const UsdPrim& prim = UsdPrim(), - const UT_Matrix4D* xform = nullptr ); - - static GU_PrimPacked* Build( - GU_Detail& detail, - const UT_StringHolder& fileName, - const SdfPath& primPath, - const SdfPath& srcPrimPath, - int index, - UsdTimeCode frame, - const char* lod = nullptr, - GusdPurposeSet purposes = GUSD_PURPOSE_PROXY, - const UsdPrim& prim = UsdPrim(), - const UT_Matrix4D* xform = nullptr ); - - /// Convenience method for building a packed USD prim for \p prim. - static GU_PrimPacked* Build( - GU_Detail& detail, - const UsdPrim& prim, - UsdTimeCode frame, - const char* lod = nullptr, - GusdPurposeSet purpose = GUSD_PURPOSE_PROXY, - const UT_Matrix4D* xform = nullptr ); - - GusdGU_PackedUSD(); - GusdGU_PackedUSD(const GusdGU_PackedUSD &src ); - virtual ~GusdGU_PackedUSD(); - - static void install(GA_PrimitiveFactory &factory); - GUSD_API - static GA_PrimitiveTypeId typeId(); - - const UT_StringHolder& fileName() const { return m_fileName; } - UT_StringHolder intrinsicFileName() const { return m_fileName; } - void setFileName( const UT_StringHolder& fileName ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - UT_StringHolder intrinsicFileName(const GU_PrimPacked *prim) const - { return intrinsicFileName(); } - void setFileName(GU_PrimPacked *prim, const UT_StringHolder& fileName) - { setFileName(fileName); } -#endif - - const UT_StringHolder& altFileName() const { return m_altFileName; } - UT_StringHolder intrinsicAltFileName() const { return m_altFileName; } - void setAltFileName( const UT_StringHolder& fileName ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - UT_StringHolder intrinsicAltFileName(const GU_PrimPacked *prim) const - { return intrinsicAltFileName(); } - void setAltFileName(GU_PrimPacked *prim, const UT_StringHolder& fileName) - { setAltFileName(fileName); } -#endif - - const SdfPath& primPath() const { return m_primPath; } - UT_StringHolder intrinsicPrimPath() const { return m_primPath.GetText(); } - void setPrimPath( const UT_StringHolder& p ); - void setPrimPath( const SdfPath& primPath ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - UT_StringHolder intrinsicPrimPath(const GU_PrimPacked *prim) const - { return intrinsicPrimPath(); } - void setPrimPath(GU_PrimPacked *prim, const UT_StringHolder& p) - { setPrimPath(p); } -#endif - - // If this prim was unpacked from a point instancer, srcPrimPath is the path - // to the instancer. - const SdfPath& srcPrimPath() const { return m_srcPrimPath; } - UT_StringHolder intrinsicSrcPrimPath() const { return m_srcPrimPath.GetText(); } - void setSrcPrimPath( const UT_StringHolder& p ); - void setSrcPrimPath( const SdfPath& primPath ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - UT_StringHolder intrinsicSrcPrimPath(const GU_PrimPacked *prim) const - { return intrinsicSrcPrimPath(); } - void setSrcPrimPath(GU_PrimPacked *prim, const UT_StringHolder& p) - { setSrcPrimPath(p); } -#endif - - // If this prim was unpacked from a point instancer, index is the array - // index in the source point instancer. - exint index() const { return m_index; } - void setIndex( exint i ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - exint index(const GU_PrimPacked *prim) const - { return index(); } - void setIndex(GU_PrimPacked *prim, exint i) - { setIndex(i); } -#endif - - // Return true if this is a prim that has been unpacked from a point instancer. - bool isPointInstance() const { return m_index >= 0; } - - // return the USD prim type - UT_StringHolder intrinsicType() const; -#if SYS_VERSION_FULL_INT >= 0x10050000 - UT_StringHolder intrinsicType(const GU_PrimPacked *prim) const - { return intrinsicType(); } -#endif - - GA_Size usdLocalToWorldTransformSize() const { return 16; } - void usdLocalToWorldTransform(fpreal64* val, exint size) const; -#if SYS_VERSION_FULL_INT >= 0x10050000 - GA_Size usdLocalToWorldTransformSize(const GU_PrimPacked *prim) const - { return 16; } - void usdLocalToWorldTransform(const GU_PrimPacked *prim, - fpreal64* val, exint size) const - { usdLocalToWorldTransform(val, size); } -#endif - - UsdTimeCode frame() const { return m_frame; } - fpreal intrinsicFrame() const { return GusdUSD_Utils::GetNumericTime(m_frame); } - void setFrame( UsdTimeCode frame ); - void setFrame( fpreal frame ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - fpreal intrinsicFrame(const GU_PrimPacked *prim) const - { return intrinsicFrame(); } - void setFrame(GU_PrimPacked *prim, fpreal frame) - { setFrame(frame); } -#endif - - GusdPurposeSet getPurposes() const { return m_purposes; } - void setPurposes( GusdPurposeSet purposes ); - - exint getNumPurposes() const; - void getIntrinsicPurposes( UT_StringArray& purposes ) const; - void setIntrinsicPurposes( const UT_StringArray& purposes ); -#if SYS_VERSION_FULL_INT >= 0x10050000 - exint getNumPurposes(const GU_PrimPacked *prim) const - { return getNumPurposes(); } - void getIntrinsicPurposes(const GU_PrimPacked *prim, - UT_StringArray& purposes ) const - { getIntrinsicPurposes(purposes); } - void setIntrinsicPurposes(GU_PrimPacked *prim, - const UT_StringArray& purposes ) - { setIntrinsicPurposes(purposes); } -#endif - - virtual GU_PackedFactory *getFactory() const override; - virtual GU_PackedImpl *copy() const override; - virtual void clearData() override; - - virtual bool isValid() const override; - virtual bool save(UT_Options &options, const GA_SaveMap &map) const override; -#if SYS_VERSION_FULL_INT < 0x10050000 - virtual bool load(const UT_Options &options, const GA_LoadMap &map) override; - virtual void update(const UT_Options &options) override; -#else - bool load(const UT_Options &options, const GA_LoadMap &map); - void update(const UT_Options &options); - virtual bool load(GU_PrimPacked *prim, - const UT_Options &options, - const GA_LoadMap &map) override - { return load(options, map); } - virtual void update(GU_PrimPacked *prim, - const UT_Options &options) override - { update(options); } -#endif - - virtual bool getBounds(UT_BoundingBox &box) const override; - virtual bool getRenderingBounds(UT_BoundingBox &box) const override; - virtual void getVelocityRange(UT_Vector3 &min, UT_Vector3 &max) const override; - virtual void getWidthRange(fpreal &min, fpreal &max) const override; - - virtual bool getLocalTransform(UT_Matrix4D &m) const override; - -#if SYS_VERSION_FULL_INT < 0x11000000 - virtual bool unpack(GU_Detail &destgdp) const override; - virtual bool unpackUsingPolygons(GU_Detail &destgdp) const override; -#else - virtual bool unpack(GU_Detail &destgdp, - const UT_Matrix4D *transform) const override; - virtual bool unpackUsingPolygons(GU_Detail &destgdp, - const GU_PrimPacked *prim) const override; -#endif - - bool visibleGT() const; - GT_PrimitiveHandle fullGT() const; - - // Return a structure that can be hashed to sort instances by prototype. - bool getInstanceKey(UT_Options& key) const; - - /// Report memory usage (includes all shared memory) - virtual int64 getMemoryUsage(bool inclusive) const override; - - /// Count memory usage using a UT_MemoryCounter in order to count - /// shared memory correctly. - virtual void countMemory(UT_MemoryCounter &counter, bool inclusive) const override; - - /// Get the underlying UsdPrim for this packed prim. - /// This may involve on-demand loading of a UsdStage to access the prim. - /// Any errors that occur while loading the stage and accessing the prim - /// will be reported on the currently scoped error manager with a severity - /// of \p sev. - UsdPrim getUsdPrim(UT_ErrorSeverity sev=UT_ERROR_ABORT) const; - -#if SYS_VERSION_FULL_INT >= 0x11000000 - bool unpackGeometry( - GU_Detail &destgdp, - const char* primvarPattern, - const UT_Matrix4D *transform, - const GT_RefineParms* parms=nullptr) const; -#else - bool unpackGeometry( - GU_Detail &destgdp, - const char* primvarPattern, - const GT_RefineParms* parms=nullptr) const; -#endif - - const UT_Matrix4D& getUsdTransform() const; - -private: - - bool unpackPrim( - GU_Detail& destgdp, - UsdGeomImageable prim, - const SdfPath& primPath, - const UT_Matrix4D& xform, - const GT_RefineParms& rparms ) const; - - void resetCaches(); - void updateTransform(); - void setTransform( const UT_Matrix4D& mx ); - - // intrinsics - UT_StringHolder m_fileName; - UT_StringHolder m_altFileName; - SdfPath m_srcPrimPath; - int m_index; - SdfPath m_primPath; - UsdTimeCode m_frame; - GusdPurposeSet m_purposes; - - - // caches - mutable UsdPrim m_usdPrim; -#if SYS_VERSION_FULL_INT < 0x12000000 - mutable UT_BoundingBox m_boundsCache; -#endif - mutable bool m_transformCacheValid; - mutable UT_Matrix4D m_transformCache; - mutable GT_PrimitiveHandle m_gtPrimCache; - mutable bool m_masterPathCacheValid; - mutable std::string m_masterPathCache; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_GU_PACKED_USD_H diff --git a/third_party/houdini/gusd/GU_USD.cpp b/third_party/houdini/gusd/GU_USD.cpp deleted file mode 100644 index 497892108a..0000000000 --- a/third_party/houdini/gusd/GU_USD.cpp +++ /dev/null @@ -1,1729 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "GU_USD.h" - -#include "error.h" -#include "GU_PackedUSD.h" -#include "USD_Utils.h" -#include "UT_Assert.h" - -#include "pxr/base/arch/hints.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -namespace { - - -void _LogAttrCreateError(const char* name) -{ - GUSD_ERR().Msg("Failed creating attribute '%s'."); -} - - -template -bool _AttrBindSuccess(Handle& handle, const char* name) -{ - if(handle.isValid()) - return true; - GUSD_ERR().Msg("Attribute '%s' is missing or the wrong type", name); - return false; -} - - -template -bool _AttrCreateSuccess(Handle& handle, const char* name) -{ - if(handle.isValid()) - return true; - _LogAttrCreateError(name); - return false; -} - - -} /*namespace*/ - - -bool -GusdGU_USD::OffsetArrayFromRange(const GA_Range& r, - GA_OffsetArray& offsets) -{ - offsets.setSize(r.getEntries()); - exint i = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it, ++i) - offsets(i) = *it; - return true; -} - - -bool -GusdGU_USD::ComputeRangeIndexMap(const GA_Range& r, - GA_OffsetArray& indexMap) -{ - if(!r.getRTI()) - return false; - - const GA_IndexMap& attrIndexMap = r.getRTI()->getIndexMap(); - indexMap.setSize(attrIndexMap.offsetSize()); - - exint i = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it, ++i) - indexMap(*it) = GA_Offset(i); - return true; -} - - -namespace { - - -template -struct _ObjectsFromSharedStringTupleT -{ - _ObjectsFromSharedStringTupleT(const GA_Attribute& attr, - const GA_AIFSharedStringTuple& tuple, - const StringToObjFn& stringToObjFn, - UT_Array& vals, - UT_ErrorSeverity sev, - GusdErrorTransport& errTransport, - std::atomic_bool& workerInterrupt) - : _attr(attr), _tuple(tuple), _stringToObjFn(stringToObjFn), - _vals(vals), _sev(sev), _errTransport(errTransport), - _workerInterrupt(workerInterrupt) {} - - void operator()(const UT_BlockedRange& r) const - { - GusdAutoErrorTransport autoErrTransport(_errTransport); - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - for(size_t i = r.begin(); i < r.end(); ++i) { - // Exit early either via user interrupt or - // by another worker thread. - if(ARCH_UNLIKELY(!++bcnt && (boss->opInterrupt() || - _workerInterrupt))) - return; - - UT_StringRef str(_tuple.getTableString(&_attr, i)); - if(str.isstring()) { - T val; - if(_stringToObjFn(str, val, _sev)) { - _vals(i) = val; - } else if(_sev >= UT_ERROR_ABORT) { - // Interrupt the other worker threads. - _workerInterrupt = true; - return; - } - } - } - } -private: - const GA_Attribute& _attr; - const GA_AIFSharedStringTuple& _tuple; - const StringToObjFn& _stringToObjFn; - UT_Array& _vals; - UT_ErrorSeverity _sev; - GusdErrorTransport& _errTransport; - std::atomic_bool& _workerInterrupt; -}; - - - -template -bool -_GetObjsFromStringAttrT(const GA_Attribute& attr, - const StringToObjFn& stringToObjFn, - UT_Array& vals, - UT_ErrorSeverity sev=UT_ERROR_NONE) -{ - const GA_AIFSharedStringTuple* tuple = attr.getAIFSharedStringTuple(); - if(!tuple) - return false; - - GA_Size count = tuple->getTableEntries(&attr); - vals.setSize(count); - - GusdErrorTransport errTransport; - std::atomic_bool workerInterrupt(false); - - if(stringToObjFn.lightItems) { - UTparallelForLightItems( - UT_BlockedRange(0, count), - _ObjectsFromSharedStringTupleT( - attr, *tuple, stringToObjFn, - vals, sev, errTransport, workerInterrupt)); - } else { - UTparallelFor( - UT_BlockedRange(0, count), - _ObjectsFromSharedStringTupleT( - attr, *tuple, stringToObjFn, - vals, sev, errTransport, workerInterrupt)); - } - return (!UTgetInterrupt()->opInterrupt() && !workerInterrupt); -} - - - -template -bool -_GetObjsFromStringAttrT(const GA_Attribute& attr, - const GA_Range& rng, - const StringToObjFn& stringToObjFn, - UT_Array& vals, - UT_ErrorSeverity sev=UT_ERROR_NONE) -{ - GA_ROHandleS hnd(&attr); - if(hnd.isInvalid()) - return false; - - UT_Array tableVals; - if(!_GetObjsFromStringAttrT(attr, stringToObjFn, - tableVals, sev)) - return false; - - vals.clear(); - vals.setSize(rng.getEntries()); - - auto* boss = UTgetInterrupt(); - - exint i = 0; - char bcnt = 0; - for(GA_Iterator it(rng); !it.atEnd(); ++it, ++i) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - GA_StringIndexType idx = hnd.getIndex(*it); - if(idx != GA_INVALID_STRING_INDEX) - vals(i) = tableVals(idx); - } - return true; -} - - -struct _StringToPrimPathFn -{ - static const bool lightItems = true; - - bool operator()(const UT_StringRef& str, SdfPath& path, - UT_ErrorSeverity sev) const - { - return GusdUSD_Utils::CreateSdfPath(str, path, sev); - } -}; - - -struct _StringToTokenFn -{ - static const bool lightItems = true; - - _StringToTokenFn(const char* nameSpace) - { - if(UTisstring(nameSpace)) { - _ns = nameSpace; - _ns += ':'; - } - } - - bool operator()(const UT_StringRef& str, TfToken& token, - UT_ErrorSeverity sev) const - { - if(_ns.empty()) - token = TfToken(str.toStdString()); - else - token = TfToken(_ns + str.toStdString()); - return true; - } -private: - std::string _ns; -}; - - - -} /*namespace */ - - -bool -GusdGU_USD::GetPrimPathsFromStringAttr(const GA_Attribute& attr, - UT_Array& paths, - UT_ErrorSeverity sev) -{ - return _GetObjsFromStringAttrT( - attr, _StringToPrimPathFn(), paths, sev); -} - - -bool -GusdGU_USD::GetPrimPathsFromStringAttr(const GA_Attribute& attr, - const GA_Range& rng, - UT_Array& paths, - UT_ErrorSeverity sev) -{ - return _GetObjsFromStringAttrT( - attr, rng, _StringToPrimPathFn(), paths, sev); -} - - -bool -GusdGU_USD::GetTokensFromStringAttr(const GA_Attribute& attr, - UT_Array& tokens, - const char* nameSpace) -{ - return _GetObjsFromStringAttrT( - attr, _StringToTokenFn(nameSpace), tokens); -} - - -bool -GusdGU_USD::GetTokensFromStringAttr(const GA_Attribute& attr, - const GA_Range& rng, - UT_Array& tokens, - const char* nameSpace) -{ - return _GetObjsFromStringAttrT( - attr, rng, _StringToTokenFn(nameSpace), tokens); -} - - -bool -GusdGU_USD::BindPrims(GusdStageCacheReader& cache, - UT_Array& prims, - const GA_Detail& gd, - const GA_Range& rng, - UT_Array* variants, - GusdDefaultArray* purposes, - GusdDefaultArray* times, - UT_ErrorSeverity sev) -{ - // Bind prims. - if(rng.getOwner() == GA_ATTRIB_PRIMITIVE) { - if(!BindPrimsFromPackedPrims(prims, rng, variants, - purposes ? &purposes->GetArray() : nullptr, - sev)) - return false; - - if(times && !GetTimeCodesFromPackedPrims(rng, times->GetArray())) - return false; - } else { - auto owner = rng.getOwner(); - // Path and prim path are required. - GA_ROHandleS path(&gd, owner, GUSD_PATH_ATTR); - if(!_AttrBindSuccess(path, GUSD_PATH_ATTR)) - return false; - GA_ROHandleS primPath(&gd, owner, GUSD_PRIMPATH_ATTR); - if(!_AttrBindSuccess(primPath, GUSD_PRIMPATH_ATTR)) - return false; - - if(!BindPrimsFromAttrs(cache, prims, rng, *path.getAttribute(), - primPath.getAttribute(), - gd.findAttribute(owner, GUSD_VARIANTS_ATTR), - variants, sev)) - return false; - - if(purposes) { - // TODO: add proper attr support. - purposes->SetConstant(GUSD_PURPOSE_DEFAULT); - } - - if(times) { - GA_ROHandleF timesHnd(&gd, owner, GUSD_FRAME_ATTR); - if(timesHnd.isValid()) { - if(!GetTimeCodesFromAttr(rng, *timesHnd.getAttribute(), - times->GetArray())) - return false; - } - } - } - return true; -} - - -namespace { - - -bool -_GetStringsFromAttr(const GA_Attribute& attr, - const GA_Range& rng, - GusdDefaultArray& strings) -{ - const GA_AIFSharedStringTuple* tuple = attr.getAIFSharedStringTuple(); - if(!tuple) - return false; - - exint tableEntries = tuple->getTableEntries(&attr); - if(tableEntries == 0) { - strings.SetConstant(UT_StringHolder()); - return true; - } - - // Get the unique strings from the table, so we can share holder refs. - UT_StringArray uniqueStrings; - uniqueStrings.setSize(tableEntries); - - for(exint i = 0; i < tableEntries; ++i) - uniqueStrings(i) = tuple->getTableString(&attr, i); - - strings.GetArray().setSize(rng.getEntries()); - exint idx = 0; - for(GA_Offset o : rng) { - auto handle = tuple->getHandle(&attr, o); - if(handle != GA_INVALID_STRING_INDEX) - strings(idx) = uniqueStrings(handle); - ++idx; - } - return true; -} - - -} /*namespace*/ - - -bool -GusdGU_USD::BindPrimsFromAttrs( - GusdStageCacheReader& cache, - UT_Array& prims, - const GA_Range& rng, - const GA_Attribute& pathAttr, - const GA_Attribute* primPathAttr, - const GA_Attribute* variantsAttr, - UT_Array* variants, - UT_ErrorSeverity sev) -{ - // Handle paths first. This might allow us to skip loading stages. - - UT_Array primPaths; - if(primPathAttr) { - if(!GetPrimPathsFromStringAttr(*primPathAttr, rng, primPaths, sev)) - return false; - } else { - const exint size = rng.getEntries(); - primPaths.setSize(size); - primPaths.constant(GusdUSD_Utils::GetDefaultPrimIdentifier()); - } - - UT_ASSERT(primPaths.size() == rng.getEntries()); - - GusdDefaultArray filePaths; - if(!_GetStringsFromAttr(pathAttr, rng, filePaths)) - return false; - - GusdDefaultArray edits; - if(variantsAttr) { - // Get the unique set of variants on the table. - UT_Array uniqueVariants; - if(!GetPrimPathsFromStringAttr(*variantsAttr, uniqueVariants, sev)) - return false; - - // Create edits for the variants. - UT_Array uniqueEdits; - uniqueEdits.setSize(uniqueVariants.size()); - for(exint i = 0; i < uniqueVariants.size(); ++i) { - GusdStageEdit* edit = new GusdStageEdit; - edit->GetVariants().append(uniqueVariants(i)); - uniqueEdits(i).reset(edit); - } - - // Expand out the edit array. - GA_ROHandleS hnd(variantsAttr); - UT_ASSERT(hnd.isValid()); - - auto& editArray = edits.GetArray(); - editArray.setSize(rng.getEntries()); - - if(variants) - variants->setSize(rng.getEntries()); - - exint idx = 0; - for(GA_Offset o : rng) { - auto handle = hnd.getIndex(o); - if(handle != GA_INVALID_STRING_INDEX) { - editArray(idx) = uniqueEdits(handle); - if(variants) - (*variants)(idx) = uniqueVariants(handle); - } - ++idx; - } - } - - prims.setSize(rng.getEntries()); - return cache.GetPrims(filePaths, primPaths, edits, - prims.data(), GusdStageOpts::LoadAll(), sev); -} - - -bool -GusdGU_USD::BindPrimsFromPackedPrims( - UT_Array& prims, - const GA_Range& rng, - UT_Array* variants, - UT_Array* purposes, - UT_ErrorSeverity sev) -{ - const exint size = rng.getEntries(); - prims.setSize(size); - - // If variants array was provided, - // match array size to other arrays. - if (variants) { - variants->setSize(size); - } - if( purposes ) { - purposes->setSize(size); - } - - // Acquire GEO_Detail from rng. - const GEO_Detail* gdp = - UTverify_cast(&rng.getRTI()->getIndexMap().getDetail()); - UT_ASSERT_P(gdp); - - // TODO: Would be better to thread this. - exint i = 0; - for (GA_Iterator it(rng); !it.atEnd(); ++it, ++i) { - - const GEO_Primitive* p = gdp->getGEOPrimitive(*it); - const GU_PrimPacked* pp = dynamic_cast(p); - if (!pp) { - continue; - } - - const GusdGU_PackedUSD* prim = - dynamic_cast(pp->implementation()); - - if (!prim) { - continue; - } - - prims(i) = prim->getUsdPrim(sev); - - SdfPath primPath, variantPath; - GusdUSD_Utils::ExtractPrimPathAndVariants(prim->primPath(), - primPath, variantPath); - if (variants) { - (*variants)(i) = variantPath; - } - - if( purposes ) { - (*purposes)(i) = prim->getPurposes(); - } - } - return true; -} - - -bool -GusdGU_USD::GetTimeCodesFromAttr(const GA_Range& rng, - const GA_Attribute& attr, - UT_Array& times) -{ - GA_ROHandleF hnd(&attr); - if(hnd.isInvalid()) - return false; - - times.setSize(rng.getEntries()); - - auto* boss = UTgetInterrupt(); - char bcnt = 0; - exint idx = 0; - for(GA_Iterator it(rng); !it.atEnd(); ++it, ++idx) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - times(idx) = hnd.get(*it); - } - return true; -} - - -bool -GusdGU_USD::GetTimeCodesFromPackedPrims(const GA_Range& rng, - UT_Array& times) -{ - times.setSize(rng.getEntries()); - - // Acquire GEO_Detail from rng. - const GEO_Detail* gdp = - UTverify_cast(&rng.getRTI()->getIndexMap().getDetail()); - UT_ASSERT_P(gdp); - - exint i = 0; - for (GA_Iterator it(rng); !it.atEnd(); ++it, ++i) { - - const GEO_Primitive* p = gdp->getGEOPrimitive(*it); - const GU_PrimPacked* pp = dynamic_cast(p); - if (!pp) { - continue; - } - - const GusdGU_PackedUSD* prim = - dynamic_cast(pp->implementation()); - - if (!prim) { - continue; - } - - times(i) = prim->frame(); - } - return true; -} - - - -GA_Offset -GusdGU_USD::AppendRefPoints(GU_Detail& gd, - const UT_Array& prims, - const char* pathAttrName, - const char* primPathAttrName) -{ - auto owner = GA_ATTRIB_POINT; - GA_RWHandleS path(gd.addStringTuple(owner, pathAttrName, 1)); - GA_RWHandleS primPath(gd.addStringTuple(owner, primPathAttrName, 1)); - if(!_AttrCreateSuccess(path, pathAttrName) || - !_AttrCreateSuccess(primPath, primPathAttrName)) - return GA_INVALID_OFFSET; - - GA_Offset start = gd.appendPointBlock(prims.size()); - GA_Offset end = start + prims.size(); - - // Write in serial for now. - auto* boss = UTgetInterrupt(); - char bcnt = 0; - exint i = 0; - - /* Prim paths vary, but stages are often the same. - Makes sense to try and cache lookups.*/ - auto* pathAttr = path.getAttribute(); - auto* pathTuple = GusdUTverify_ptr(pathAttr->getAIFSharedStringTuple()); - GA_AIFSharedStringTuple::StringBuffer buf(pathAttr, pathTuple); - - UsdStageWeakPtr lastStage; - GA_StringIndexType lastStageIdx = GA_INVALID_STRING_INDEX; - - for(GA_Offset o = start; o < end; ++o, ++i) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return GA_INVALID_OFFSET; - - if(const UsdPrim& prim = prims(i)) { - UsdStageWeakPtr stage = prim.GetStage(); - if(stage != lastStage) { - lastStage = stage; - lastStageIdx = buf.append( - stage->GetRootLayer()->GetIdentifier().c_str()); - } - path.set(o, lastStageIdx); - primPath.set(o, prim.GetPath().GetString().c_str()); - } - } - return start; -} - -static std::map packedPrimBuildFuncRegistry; - -void -GusdGU_USD::RegisterPackedPrimBuildFunc( - const TfToken &typeName, - GusdGU_USD::PackedPrimBuildFunc func ) { - - packedPrimBuildFuncRegistry[typeName] = func; -} - -bool -GusdGU_USD::AppendPackedPrims( - GU_Detail& gd, - const UT_Array& prims, - const UT_Array& variants, - const GusdDefaultArray& times, - const GusdDefaultArray& lods, - const GusdDefaultArray& purposes) -{ - UT_ASSERT(variants.size() == prims.size()); - UT_ASSERT(times.IsConstant() || times.size() == prims.size()); - UT_ASSERT(lods.IsConstant() || lods.size() == prims.size()); - UT_ASSERT(purposes.IsConstant() || purposes.size() == prims.size()); - - for (exint i = 0; i < prims.size(); ++i) { - if (const UsdPrim& prim = prims(i)) { - - const std::string& usdFileName = - prim.GetStage()->GetRootLayer()->GetIdentifier(); - - SdfPath usdPrimPath = prim.GetPath(); - - // If variants(i) is a valid variant path, then update usdPrimPath - // to include the variant selections from variants(i). - if (variants(i).ContainsPrimVariantSelection()) { - SdfPath strippedPath = variants(i).StripAllVariantSelections(); - usdPrimPath = usdPrimPath.ReplacePrefix(strippedPath, variants(i)); - } - - auto it = packedPrimBuildFuncRegistry.find( prim.GetTypeName() ); - if( it != packedPrimBuildFuncRegistry.end() ) { - - (*it->second)( gd, usdFileName, usdPrimPath, - times(i), lods(i), purposes(i) ); - } - else { - GusdGU_PackedUSD::Build( gd, usdFileName, usdPrimPath, - times(i), lods(i), purposes(i), prim ); - } - } - } - - return true; -} - - -GA_Offset -GusdGU_USD::AppendExpandedRefPoints( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& prims, - const GA_AttributeFilter& filter, - const char* pathAttrName, - const char* primPathAttrName) -{ - // Need an array of just the prims. - UT_Array primArray(prims.size(), prims.size()); - for(exint i = 0; i < prims.size(); ++i) - primArray(i) = prims(i).first; - - // Add the new ref points. - GA_Offset start = AppendRefPoints(gd, primArray, pathAttrName, - primPathAttrName); - if(!GAisValid(start)) - return GA_INVALID_OFFSET; - - // Find attributes to copy. - GA_AttributeFilter filterNoRefAttrs( - GA_AttributeFilter::selectAnd( - GA_AttributeFilter::selectNot( - GA_AttributeFilter::selectOr( - GA_AttributeFilter::selectByName(pathAttrName), - GA_AttributeFilter::selectByName(primPathAttrName))), - filter)); - - UT_Array attrs; - srcGd.getAttributes().matchAttributes( - filterNoRefAttrs, srcRng.getOwner(), attrs); - - if(attrs.isEmpty()) - return start; - - /* Need to build out a source range including repeats for all - of our expanded indices.*/ - GA_OffsetList srcOffsets; - const GA_IndexMap& srcMap = srcGd.getIndexMap(srcRng.getOwner()); - { - srcOffsets.setEntries(prims.size()); - GA_OffsetArray offsets; - if(!OffsetArrayFromRange(srcRng, offsets)) - return GA_INVALID_OFFSET; - for(exint i = 0; i < prims.size(); ++i) - srcOffsets.set(i, offsets(prims(i).second)); - } - - GA_Range dstRng(gd.getPointMap(), start, start+prims.size()); - - if(CopyAttributes(GA_Range(srcMap, srcOffsets), - dstRng, gd.getPointMap(), attrs)) - return start; - return GA_INVALID_OFFSET; -} - - -namespace { - - -bool -_BuildTypedRangesFromPrimRanges( - const GA_AttributeOwner& type, - const GA_Detail& srcGd, - const GA_Detail& dstGd, - const GA_Range& primSrcRng, - const GA_Range& primDstRng, - GA_Range& typedSrcRng, - GA_Range& typedDstRng) -{ - GA_Offset (GA_Primitive::*offsetFunc)(GA_Size) const; - - // type must be either GA_ATTRIB_POINT or GA_ATTRIB_VERTEX - if (type == GA_ATTRIB_POINT) { - offsetFunc = &GA_Primitive::getPointOffset; - - } else if (type == GA_ATTRIB_VERTEX) { - offsetFunc = &GA_Primitive::getVertexOffset; - - } else { - return false; - } - - // Gather a list of src and dst offsets from each prim. - GA_OffsetList srcOffsets, dstOffsets; - - for (GA_Iterator srcIt(primSrcRng), dstIt(primDstRng); - !srcIt.atEnd(); srcIt.advance(), dstIt.advance()) { - - auto* primSrc = srcGd.getPrimitive(srcIt.getOffset()); - GA_Offset srcOffset0 = (primSrc->*offsetFunc)(0); - - auto* primDst = dstGd.getPrimitive(dstIt.getOffset()); - for (exint i = 0; i < primDst->getVertexCount(); ++i) { - srcOffsets.append(srcOffset0); - dstOffsets.append((primDst->*offsetFunc)(i)); - } - } - - typedSrcRng = GA_Range(srcGd.getIndexMap(type), srcOffsets); - typedDstRng = GA_Range(dstGd.getIndexMap(type), dstOffsets); - - return true; -} - - -} /*namespace*/ - - -bool -GusdGU_USD::AppendExpandedPackedPrims( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& primIndexPairs, - const UT_Array& variants, - const GusdDefaultArray& times, - const GA_AttributeFilter& filter, - bool unpackToPolygons, - const UT_String& primvarPattern) -{ - UT_AutoInterrupt task("Unpacking packed USD prims"); - - const exint srcSize = srcRng.getEntries(); - const exint dstSize = primIndexPairs.size(); - - // Need an array of just the prims. - UT_Array prims(dstSize, dstSize); - for (exint i = 0; i < dstSize; ++i) { - prims(i) = primIndexPairs(i).first; - } - - // Create an index-to-offset map from srcRng. - GA_OffsetArray indexToOffset; - if (!OffsetArrayFromRange(srcRng, indexToOffset)) { - return false; - } - - // Collect the transform and viewportLOD from each source packed prim. - UT_Array srcXforms(srcSize, srcSize); - ComputeTransformsFromPackedPrims(srcGd, indexToOffset, - srcXforms.array()); - UT_StringArray srcVpLOD; - srcVpLOD.setSize(srcSize); - UT_Array srcPurposes; - srcPurposes.setSize(srcSize); - GetPackedPrimViewportLODAndPurposes(srcGd, indexToOffset, - srcVpLOD, srcPurposes); - - // Now remap these arrays to align with the destination packed prims. - UT_Array dstXforms(dstSize, dstSize); - GusdDefaultArray dstVpLOD; - dstVpLOD.GetArray().setSize(dstSize); - - GusdDefaultArray dstPurposes; - dstPurposes.GetArray().setSize(dstSize); - - for (exint i = 0; i < dstSize; ++i) { - dstXforms(i) = srcXforms(primIndexPairs(i).second); - dstVpLOD.GetArray()(i) = srcVpLOD(primIndexPairs(i).second); - dstPurposes.GetArray()(i) = srcPurposes(primIndexPairs(i).second); - } - - // Make a GU_Detail pointer to help handle 2 cases: - // 1. If unpacking to polygons, point to a new temporary detail so - // that intermediate prims don't get appended to gd. - // 2. If NOT unpacking to polygons, point to gd so result prims do - // get appended to it. - GU_Detail* gdPtr = unpackToPolygons ? new GU_Detail : &gd; - - GA_Size start = gdPtr->getNumPrimitives(); - AppendPackedPrims(*gdPtr, prims, variants, times, dstVpLOD, dstPurposes); - - // Now set transforms on those appended packed prims. - GA_Range primDstRng(gdPtr->getPrimitiveRangeSlice(start)); - SetPackedPrimTransforms(*gdPtr, primDstRng, dstXforms.array()); - - // Need to build a list of source offsets, - // including repeats for expanded prims. - GA_OffsetList srcOffsets; - - if (unpackToPolygons) { - GA_Size gdStart = gd.getNumPrimitives(); - - // If unpacking down to polygons, iterate through the intermediate - // packed prims in gdPtr and unpack them into gd. - exint i = 0; - for (GA_Iterator it(primDstRng); !it.atEnd(); ++it, ++i) { - if(task.wasInterrupted()) { - return false; - } - - const GEO_Primitive* p = gdPtr->getGEOPrimitive(*it); - const GU_PrimPacked* pp = dynamic_cast(p); - if (!pp) { - continue; - } - - if (const GusdGU_PackedUSD* prim = - dynamic_cast(pp->implementation())) { - - GA_Size gdCurrent = gd.getNumPrimitives(); - -#if SYS_VERSION_FULL_INT >= 0x11000000 - UT_Matrix4D transform; - pp->getFullTransform4(transform); - - // Unpack this prim. - if (!prim->unpackGeometry(gd, primvarPattern.c_str(), &transform)) { - return false; - } -#else - // Unpack this prim. - if (!prim->unpackGeometry(gd, primvarPattern.c_str())) { - return false; - } -#endif - - const GA_Offset offset = - indexToOffset(primIndexPairs(i).second); - const exint count = gd.getNumPrimitives() - gdCurrent; - for (exint j = 0; j < count; ++j) { - srcOffsets.append(offset); - } - } - } - - // primDstRng needs to be reset to be the range of unpacked prims in - // gd (instead of the range of intermediate packed prims in gdPtr). - primDstRng = GA_Range(gd.getPrimitiveRangeSlice(gdStart)); - - // All done with gdPtr. - delete gdPtr; - - } else { - // Compute list of source offsets. - srcOffsets.setEntries(dstSize); - for (exint i = 0; i < dstSize; ++i) { - srcOffsets.set(i, indexToOffset(primIndexPairs(i).second)); - } - } - - // Get the filtered lists of attributes to copy. - UT_Array primAttrs, vertexAttrs, pointAttrs; - auto& attrs = srcGd.getAttributes(); - attrs.matchAttributes(filter, GA_ATTRIB_PRIMITIVE, primAttrs); - attrs.matchAttributes(filter, GA_ATTRIB_VERTEX, vertexAttrs); - attrs.matchAttributes(filter, GA_ATTRIB_POINT, pointAttrs); - - // If no attrs to copy, exit early. - if (primAttrs.isEmpty() && vertexAttrs.isEmpty() && pointAttrs.isEmpty()) { - return true; - } - - // Create a range for source prims using srcOffsets. - GA_Range primSrcRng(srcGd.getIndexMap(srcRng.getOwner()), srcOffsets); - - // primDstRng and primSrcRng should be the same size. - UT_ASSERT(primDstRng.getEntries() == primSrcRng.getEntries()); - - if (!CopyAttributes(primSrcRng, primDstRng, - gd.getPrimitiveMap(), primAttrs)) { - return false; - } - - if (!vertexAttrs.isEmpty()) { - GA_Range vtxSrcRng, vtxDstRng; - _BuildTypedRangesFromPrimRanges(GA_ATTRIB_VERTEX, - srcGd, gd, primSrcRng, primDstRng, vtxSrcRng, vtxDstRng); - if (!CopyAttributes(vtxSrcRng, vtxDstRng, - gd.getVertexMap(), vertexAttrs)) { - return false; - } - } - if (!pointAttrs.isEmpty()) { - GA_Range pntSrcRng, pntDstRng; - _BuildTypedRangesFromPrimRanges(GA_ATTRIB_POINT, - srcGd, gd, primSrcRng, primDstRng, pntSrcRng, pntDstRng); - if (!CopyAttributes(pntSrcRng, pntDstRng, - gd.getPointMap(), pointAttrs)) { - return false; - } - } - - return true; -} - - -namespace { - - -bool -_WriteVariantStrings(GU_Detail& gd, - const GA_Range& rng, - const UT_Array& orderedVariants, - const UT_Array& variantIndices, - const char* variantsAttr) -{ - auto* boss = UTgetInterrupt(); - - UT_AutoInterrupt task("Write variant strings", boss); - - auto* attr = gd.addStringTuple(rng.getOwner(), variantsAttr, 1); - if(!attr) { - _LogAttrCreateError(variantsAttr); - return false; - } - - auto* tuple = attr->getAIFSharedStringTuple(); - GA_AIFSharedStringTuple::StringBuffer buf(attr, tuple); - - // Add strings, creating a map of variantIndex -> string table index. - UT_Array variantIndexToStrMap; - variantIndexToStrMap.setSize(orderedVariants.size()); - - for(exint i = 0; i < orderedVariants.size(); ++i) { - const UT_StringHolder& path = orderedVariants(i); - variantIndexToStrMap(i) = path.isstring() ? - buf.append(path) : GA_INVALID_STRING_INDEX; - } - - // Apply the string indices to all of the source offsets. - // XXX: could be done in parallel... - GA_RWHandleS hnd(attr); - - char bcnt = 0; - exint idx = 0; - for(GA_Iterator it(rng); !it.atEnd(); ++it, ++idx) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - exint variantIndex = variantIndices(idx); - if(variantIndex >= 0) - hnd.set(*it, variantIndexToStrMap(variantIndex)); - } - return true; -} - - -} /*namespace*/ - - -bool -GusdGU_USD::WriteVariantSelectionsToAttr( - GU_Detail& gd, - const GA_Range& rng, - const UT_Array& prims, - const GusdUSD_Utils::VariantSelArray& selections, - const char* variantsAttr, - const UT_Array* prevVariants) -{ - UT_ASSERT(prims.size() == rng.getEntries()); - UT_ASSERT(!prevVariants || prevVariants->size() == prims.size()); - - UT_Array orderedVariants; - UT_Array indices; - - if(!GusdUSD_Utils::AppendVariantSelections( - prims, selections, orderedVariants, indices, prevVariants)) - return false; - return _WriteVariantStrings(gd, rng, orderedVariants, - indices, variantsAttr); -} - - -bool -GusdGU_USD::WriteVariantSelectionsToPackedPrims( - GU_Detail& gd, - const GA_Range& rng, - const UT_Array& prims, - const GusdUSD_Utils::VariantSelArray& selections, - const UT_Array* prevVariants) -{ - GUSD_ERR().Msg("GusdGU_USD::WriteVariantSelectionsToPackedPrims() " - "is not yet implemented"); - return false; -} - - -GA_Offset -GusdGU_USD::AppendRefPointsForExpandedVariants( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& orderedVariants, - const GusdUSD_Utils::IndexPairArray& variantIndices, - const GA_AttributeFilter& filter, - const char* variantsAttr) -{ - // Need an array of just the variant indices. - UT_Array indices(variantIndices.size(), variantIndices.size()); - for(exint i = 0; i < indices.size(); ++i) - indices(i) = variantIndices(i).second; - - // Add the new ref points. - GA_Offset start = gd.appendPointBlock(indices.size()); - if(!GAisValid(start)) - return GA_INVALID_OFFSET; - - // Write the variants attribute. - GA_Range dstRng(gd.getPointMap(), start, start+indices.size()); - if(!_WriteVariantStrings(gd, dstRng, orderedVariants, - indices, variantsAttr)) - return GA_INVALID_OFFSET; - - // Find attributes to copy. - GA_AttributeFilter filterNoRefAttrs( - GA_AttributeFilter::selectAnd( - GA_AttributeFilter::selectNot( - GA_AttributeFilter::selectByName(variantsAttr)), - filter)); - - UT_Array attrs; - srcGd.getAttributes().matchAttributes( - filterNoRefAttrs, srcRng.getOwner(), attrs); - - if(attrs.isEmpty()) - return start; - - /* Need to build out a source range including repeats for all - of our expanded indices.*/ - GA_OffsetList srcOffsets; - const GA_IndexMap& srcMap = srcGd.getIndexMap(srcRng.getOwner()); - { - srcOffsets.setEntries(variantIndices.size()); - GA_OffsetArray offsets; - if(!OffsetArrayFromRange(srcRng, offsets)) - return GA_INVALID_OFFSET; - for(exint i = 0; i < variantIndices.size(); ++i) - srcOffsets.set(i, offsets(variantIndices(i).first)); - } - if(CopyAttributes(GA_Range(srcMap, srcOffsets), - dstRng, gd.getPointMap(), attrs)) - return start; - return GA_INVALID_OFFSET; -} - - -GA_Offset -GusdGU_USD::AppendPackedPrimsForExpandedVariants( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& orderedVariants, - const GusdUSD_Utils::IndexPairArray& variantIndices, - const GA_AttributeFilter& filter) -{ - GUSD_ERR().Msg("GusdGU_USD::AppendPackedPrimsForExpandedVariants() " - "is not yet implemented"); - return GA_INVALID_OFFSET; -} - - -bool -GusdGU_USD::CopyAttributes(const GA_Range& srcRng, - const GA_Range& dstRng, - const GA_IndexMap& dstMap, - const UT_Array& attrs) -{ - UT_AutoInterrupt task("Copying attributes"); - - /* Process each attribute individually (best for performance). - Note that we want to keep going and at least copy attrs even - if the offset list is emtpy.*/ - for(exint i = 0; i < attrs.size(); ++i) - { - if(task.wasInterrupted()) - return false; - const GA_Attribute* srcAttr = attrs(i); - - GA_Attribute* dstAttr = NULL; - - if(const auto* grpAttr = GA_ATIGroupBool::cast(srcAttr)) - { - /* cloneAttribute() does not clone groups, because they - define additional structure on a detail. Must go through - the group creation interface.*/ - - /* createElementGroup() will cause an existing group - to be destroyed, so must first try to finding compatible - groups.*/ - - auto* grp = dstMap.getDetail().findElementGroup( - dstMap.getOwner(), grpAttr->getName()); - if(!grp || grp->getOrdered() != grpAttr->getOrdered()) - { - /** XXX: if we had an existing group of an umatched order, - we lose its membership at this point. - This is expected, because if we are turning an unordered - group into an ordered group, it's not clear what the - order should be. However, it may be desirable to preserve - existing membership when converting in the other - direction.*/ - grp = dstMap.getDetail().createElementGroup( - dstMap.getOwner(), grpAttr->getName(), - grpAttr->getOrdered()); - } - if(grp) - dstAttr = grp->getAttribute(); - } - else - { - dstAttr = dstMap.getDetail().getAttributes().cloneAttribute( - dstMap.getOwner(), srcAttr->getName(), - *srcAttr, /*clone opts*/ true); - } - - if(dstAttr) - { - if(const GA_AIFCopyData* copy = srcAttr->getAIFCopyData()) - { - /* Copy the attribute values. - This runs in parallel internally. - - TODO: Verify that this is doing something smart - for blob data. - Also, we ignore copying errors, assuming that - a failure to copy means copying is incompatible - for the type. Is this correct? */ - copy->copy(*dstAttr, dstRng, *srcAttr, srcRng); - } - } - } - return true; -} - - -namespace { - - -template -struct _ModifyXformsT -{ - _ModifyXformsT(const ModifyFn& modifyFn, const GA_OffsetArray& offsets, - UT_Matrix4D* xforms) - : _modifyFn(modifyFn), _offsets(offsets), _xforms(xforms) {} - - void operator()(const UT_BlockedRange& r) const - { - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - for(size_t i = r.begin(); i < r.end(); ++i) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return; - _modifyFn(_xforms[i], _offsets(i)); - } - } -private: - const ModifyFn& _modifyFn; - const GA_OffsetArray& _offsets; - UT_Matrix4D* const _xforms; -}; - - -struct _XformRowFromAttrFn -{ - _XformRowFromAttrFn(const GA_ROHandleV3& attr, int comp) - : _attr(attr), _comp(comp) {} - - void operator()(UT_Matrix4D& xform, GA_Offset o) const - { - UT_Vector3F vec = _attr.get(o); - /* Scale should come from scale attrs; - only want orientation here.*/ - vec.normalize(); - xform[_comp] = UT_Vector4F(vec); - } - -private: - const GA_ROHandleV3& _attr; - const int _comp; -}; - - -struct _XformApplyScaleFn -{ - _XformApplyScaleFn(const GA_ROHandleV3& attr) : _attr(attr) {} - - void operator()(UT_Matrix4D& xform, GA_Offset o) const - { - UT_Vector3F scale = _attr.get(o); - for(int i = 0; i < 3; ++i) - xform[i] *= scale[i]; - } -private: - const GA_ROHandleV3& _attr; -}; - - -struct _XformApplyPScaleFn -{ - _XformApplyPScaleFn(const GA_ROHandleF& attr) : _attr(attr) {} - - void operator()(UT_Matrix4D& xform, GA_Offset o) const - { - float scale = _attr.get(o); - for(int i = 0; i < 3; ++i) - xform[i] *= scale; - } -private: - const GA_ROHandleF& _attr; -}; - - -struct _XformsFromInstMatrixFn -{ - _XformsFromInstMatrixFn(const GA_AttributeInstanceMatrix& instMx, - const GA_ROHandleV3& p, - const GA_OffsetArray& offsets, - UT_Matrix4D* xforms) - : _instMx(instMx), _p(p), _offsets(offsets), _xforms(xforms) {} - - void operator()(const UT_BlockedRange& r) const - { - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - for(size_t i = r.begin(); i < r.end(); ++i) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return; - GA_Offset o = _offsets(i); - _instMx.getMatrix(_xforms[i], _p.get(o), o); - } - } -private: - const GA_AttributeInstanceMatrix& _instMx; - const GA_ROHandleV3& _p; - const GA_OffsetArray& _offsets; - UT_Matrix4D* const _xforms; -}; - - -} /*namespace*/ - -bool -GusdGU_USD::GetPackedPrimViewportLODAndPurposes( - const GA_Detail& gd, - const GA_OffsetArray& offsets, - UT_StringArray& viewportLOD, - UT_Array& purposes) -{ - for (exint i = 0; i < offsets.size(); ++i) { - - const GA_Primitive* p = gd.getPrimitive(offsets(i)); - const GU_PrimPacked* pp = dynamic_cast(p); - if (!pp) { - continue; - } - - if (const GusdGU_PackedUSD* prim = - dynamic_cast(pp->implementation())) { - -#if SYS_VERSION_FULL_INT < 0x10050000 - viewportLOD(i) = prim->intrinsicViewportLOD(); -#else - viewportLOD(i) = prim->intrinsicViewportLOD(pp); -#endif - purposes(i) = prim->getPurposes(); - } - } - return true; -} - -bool -GusdGU_USD::ComputeTransformsFromAttrs(const GA_Detail& gd, - GA_AttributeOwner owner, - const GA_OffsetArray& offsets, - UT_Matrix4D* xforms) -{ - UT_AutoInterrupt task("Computing tranforms from attributes"); - - GA_ROHandleV3 p(&gd, owner, GEO_STD_ATTRIB_POSITION); - if(p.isInvalid()) - return false; - - GA_ROHandleV3 i(&gd, owner, "i"), j(&gd, owner, "j"), k(&gd, owner, "k"); - - UT_BlockedRange rng(0, offsets.size()); - - if(i.isValid() && j.isValid() && k.isValid()) { - - GA_ROHandleV3 handles[] = {i, j, k, p}; - - for(int comp = 0; comp < 4; ++comp) { - UTparallelForLightItems( - rng, _ModifyXformsT<_XformRowFromAttrFn>( - _XformRowFromAttrFn(handles[comp], comp), offsets, xforms)); - if(task.wasInterrupted()) - return false; - } - GA_ROHandleF pscale(&gd, owner, GEO_STD_ATTRIB_PSCALE); - if(pscale.isValid()) { - UTparallelForLightItems( - rng, _ModifyXformsT<_XformApplyPScaleFn>( - _XformApplyPScaleFn(pscale), offsets, xforms)); - if(task.wasInterrupted()) - return false; - } - GA_ROHandleV3 scale(&gd, owner, "scale"); - if(scale.isValid()) { - UTparallelForLightItems( - rng, _ModifyXformsT<_XformApplyScaleFn>( - _XformApplyScaleFn(scale), offsets, xforms)); - if(task.wasInterrupted()) - return false; - } - - return true; - } - GA_AttributeInstanceMatrix instMx(gd.getAttributeDict(owner)); - UTparallelFor(rng, _XformsFromInstMatrixFn(instMx, p, offsets, xforms)); - return !task.wasInterrupted(); -} - - -bool -GusdGU_USD::ComputeTransformsFromPackedPrims(const GA_Detail& gd, - const GA_OffsetArray& offsets, - UT_Matrix4D* xforms) -{ - for (exint i = 0; i < offsets.size(); ++i) { - const GA_Primitive* p = gd.getPrimitive(offsets(i)); - - if ( p->getTypeId() == GusdGU_PackedUSD::typeId() ) { - auto prim = UTverify_cast(p); - auto packedUSD = UTverify_cast(prim->implementation()); - - // The transforms on a USD packed prim contains the combination - // of the transform in the USD file and any transform the user - // has applied in Houdini. Compute just the transform that the - // user has applied in Houdini. - - UT_Matrix4D primXform; - prim->getFullTransform4(primXform); - UT_Matrix4D invUsdXform = packedUSD->getUsdTransform(); - - invUsdXform.invert(); - xforms[i] = invUsdXform * primXform; - - } else { - xforms[i].identity(); - } - } - return true; -} - - -bool -GusdGU_USD::SetTransformAttrs(GU_Detail& gd, - const GA_Range& r, - const GA_OffsetArray& indexMap, - OrientAttrRepresentation orientRep, - ScaleAttrRepresentation scaleRep, - const UT_Matrix4D* xforms) -{ - /* TODO: This currently makes up a large chunk of exec time - for the USD Transform SOP. Consider threading this.*/ - - auto* boss = UTgetInterrupt(); - UT_AutoInterrupt task("Set transform attributes", boss); - - auto owner = r.getOwner(); - - // Position. - GA_RWHandleV3 p(&gd, owner, GEO_STD_ATTRIB_POSITION); - if(!_AttrBindSuccess(p, GA_Names::P)) - return false; - - char bcnt = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - const UT_Matrix4D& xf = xforms[indexMap(*it)]; - p.set(*it, UT_Vector3D(xf[3])); - } - - // Scale. - if(scaleRep != SCALEATTR_IGNORE) { - if(scaleRep == SCALEATTR_SCALE) { - GA_RWHandleV3 scale(gd.addFloatTuple(owner, GA_Names::scale, 3)); - if(!_AttrCreateSuccess(scale, GA_Names::scale)) - return false; - - char bcnt = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - - const UT_Matrix4D& xf = xforms[indexMap(*it)]; - scale.set(*it, UT_Vector3F(xf[0].length(), - xf[1].length(), - xf[2].length())); - } - - GA_RWHandleF pscale(&gd, owner, GA_Names::pscale); - if(pscale.isValid()) { - // Make sure pscale is set to 1 over the range. - GA_Attribute* pscaleAttr = pscale.getAttribute(); - if(const GA_AIFTuple* tuple = pscaleAttr->getAIFTuple()) - tuple->set(pscaleAttr, r, 1.0f); - } - } else { // SCALEATTR_PSCALE - GA_RWHandleF pscale( - gd.addFloatTuple(owner, GA_Names::pscale, 1)); - if(!_AttrCreateSuccess(pscale, GA_Names::pscale)) - return false; - - char bcnt = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - - const UT_Matrix4D& xf = xforms[indexMap(*it)]; - float s = xf[0].length() + xf[1].length() + xf[2].length(); - s /= 3; - pscale.set(*it, s); - } - - GA_RWHandleV3 scale(&gd, owner, GA_Names::scale); - if(scale.isValid()) { - // Make sure sclae is set to 1 over the range. - GA_Attribute* scaleAttr = scale.getAttribute(); - - float scaleOne[] = {1,1,1}; - if(const GA_AIFTuple* tuple = scaleAttr->getAIFTuple()) - tuple->set(scaleAttr, r, scaleOne, 3); - } - } - } - - // Orientation - if(orientRep != ORIENTATTR_IGNORE) { - if(orientRep == ORIENTATTR_ORIENT) { - GA_RWHandleQ orient( - gd.addFloatTuple(owner, GA_Names::orient, 4)); - if(!_AttrCreateSuccess(orient, GA_Names::orient)) - return false; - orient.getAttribute()->setTypeInfo(GA_TYPE_QUATERNION); - - char bcnt = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - - const UT_Matrix4D& xf = xforms[indexMap(*it)]; - UT_Matrix3 rot; - xf.extractRotate(rot); - rot.makeRotationMatrix(); - UT_QuaternionF q; - q.updateFromRotationMatrix(rot); - orient.set(*it, q); - } - } else { - const char* names[] = {"i","j","k"}; - GA_RWHandleV3 handles[3]; - for(int i = 0; i < 3; ++i) { - handles[i].bind(gd.addFloatTuple(owner, names[i], 3)); - if(!_AttrCreateSuccess(handles[i], names[i])) - return false; - handles[i].getAttribute()->setTypeInfo(GA_TYPE_NORMAL); - } - - // iterate by attr to improve cache locality. - for(int i = 0; i < 3; ++i) { - char bcnt = 0; - for(GA_Iterator it(r); !it.atEnd(); ++it) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return false; - const UT_Matrix4D& xf = xforms[indexMap(*it)]; - UT_Vector3D vec(xf[i]); - /* Scale should come from scale attrs; - only want orientation here.*/ - vec.normalize(); - handles[i].set(*it, vec); - } - } - } - } - return true; -} - - -bool -GusdGU_USD::SetPackedPrimTransforms(GU_Detail& gd, - const GA_Range& r, - const UT_Matrix4D* xforms) -{ - exint i = 0; - for (GA_Iterator it(r); !it.atEnd(); ++it, ++i) { - GEO_Primitive* p = gd.getGEOPrimitive(*it); - - if ( p->getTypeId() == GusdGU_PackedUSD::typeId() ) { - auto prim = UTverify_cast(p); - auto packedUSD = UTverify_cast(prim->implementation()); - - // The transforms on a USD packed prim contains the combination - // of the transform in the USD file and any transform the user - // has applied in Houdini. - - UT_Matrix4D m = packedUSD->getUsdTransform() * xforms[i]; - - UT_Matrix3D xform(m); - UT_Vector3 pos; - m.getTranslates(pos); - - prim->setLocalTransform(xform); - prim->setPos3(0, pos); - } - } - return true; -} - - - -namespace { - - -struct _XformAttrsFn -{ - _XformAttrsFn(const GA_AttributeTransformer& xformer, - const GA_OffsetArray& indexMap, - const UT_Matrix4D* xforms) - : _xformer(xformer), _indexMap(indexMap), _xforms(xforms) {} - - void operator()(const GA_SplittableRange& r) const - { - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - GA_Offset o, end; - for(GA_Iterator it(r); it.blockAdvance(o,end); ) { - if(ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) - return; - - for( ; o < end; ++o) { - GA_AttributeTransformer::Transform xf( - _xforms[_indexMap(o)]); - _xformer.transform(o, xf); - } - } - } - - -private: - GA_AttributeTransformer _xformer; - const GA_OffsetArray& _indexMap; - const UT_Matrix4D* _xforms; -}; - - -} /*namespace*/ - - -bool -GusdGU_USD::MultTransformableAttrs(GU_Detail& gd, - const GA_Range& r, - const GA_OffsetArray& indexMap, - const UT_Matrix4D* xforms, - bool keepLengths, - const GA_AttributeFilter* filter) -{ - UT_ASSERT(xforms); - - UT_AutoInterrupt task("Transform attributes"); - - GA_AttributeTransformer xformer(gd, r.getOwner()); - - if(filter) { - xformer.addAttributes(*filter, keepLengths); - } else { - GA_AttributeFilter xformables( - GA_AttributeFilter::selectTransforming(/*includeP*/ true)); - xformer.addAttributes(xformables, keepLengths); - } - UTparallelFor(GA_SplittableRange(r), - _XformAttrsFn(xformer, indexMap, xforms)); - return !task.wasInterrupted(); -} - - -bool -GusdGU_USD::ImportPrimUnpacked(GU_Detail& gd, - const UsdPrim& prim, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - const char* primvarPattern, - const UT_Matrix4D* xform, - const GT_RefineParms* refineParms) -{ - if (prim) { - - // Create a packed prim on a temporary detail. - - GU_Detail tmpGd; - - if (auto* packedPrim = - GusdGU_PackedUSD::Build(tmpGd, prim, time, lod, purpose, xform)) { - - const GusdGU_PackedUSD* impl = - dynamic_cast( - packedPrim->implementation()); - UT_ASSERT_P(impl); - - // Unpack the prims. - -#if SYS_VERSION_FULL_INT >= 0x11000000 - UT_Matrix4D xform; - packedPrim->getFullTransform4(xform); - - return impl->unpackGeometry(gd, primvarPattern, &xform, refineParms); -#else - return impl->unpackGeometry(gd, primvarPattern, refineParms); -#endif - } - } - return false; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/GU_USD.h b/third_party/houdini/gusd/GU_USD.h deleted file mode 100644 index a358007249..0000000000 --- a/third_party/houdini/gusd/GU_USD.h +++ /dev/null @@ -1,328 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GU_USD_H -#define GUSD_GU_USD_H - -#include -#include -#include -#include - -#include "pxr/pxr.h" - -#include "api.h" -#include "defaultArray.h" -#include "stageCache.h" -#include "USD_Traverse.h" -#include "USD_Utils.h" - -class GA_AttributeFilter; -class GT_RefineParms; -class GU_Detail; -class GU_PrimPacked; - -PXR_NAMESPACE_OPEN_SCOPE - -/** The default names of the USD ref attributes. - @{ */ -#define GUSD_PATH_ATTR "usdpath" -#define GUSD_PRIMPATH_ATTR "usdprimpath" -#define GUSD_FRAME_ATTR "frame" -#define GUSD_VARIANTS_ATTR "usdvariants" -#define GUSD_CONSTRAINT_ATTR "usdconstraint" -#define GUSD_PURPOSE_ATTR "usdpurpose" -#define GUSD_ACTIVE_ATTR "usdactive" -#define GUSD_VISIBLE_ATTR "usdvisible" - -#define GUSD_OVERTRANSFORMS_ATTR "usdovertransforms" -#define GUSD_OVERPOINTS_ATTR "usdoverpoints" -#define GUSD_OVERPRIMVARS_ATTR "usdoverprimvars" -#define GUSD_OVERALL_ATTR "usdoverall" - -#define GUSD_WRITESTATICTOPOLOGY_ATTR "usdwritestatictopology" -#define GUSD_WRITESTATICPRIMVARS_ATTR "usdwritestaticprimvars" -#define GUSD_WRITESTATICGEO_ATTR "usdwritestaticgeo" -/** @} */ - - -/** Set of helpers for working with ranges of prims/points, etc.*/ -class GUSD_API GusdGU_USD -{ -public: - /** Compute an array of offsets from a range.*/ - static bool OffsetArrayFromRange(const GA_Range& r, - GA_OffsetArray& offsets); - - /** Compute an array mapping offset->range_index for the given range.*/ - static bool ComputeRangeIndexMap(const GA_Range& r, - GA_OffsetArray& indexMap); - - static bool - BindPrims(GusdStageCacheReader& cache, - UT_Array& prims, - const GA_Detail& gd, - const GA_Range& rng, - UT_Array* variants=nullptr, - GusdDefaultArray* purposes=nullptr, - GusdDefaultArray* times=nullptr, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /** Bind prims from references defined in the given attributes. - This creates an entry in @a prims for each entry in the given range, - mapped to the corresponding prim. - If @a variants is non-null, resolved variant paths are stored - in the given array.*/ - static bool - BindPrimsFromAttrs(GusdStageCacheReader& cache, - UT_Array& prims, - const GA_Range& rng, - const GA_Attribute& pathAttr, - const GA_Attribute* primPathAttr=nullptr, - const GA_Attribute* variantsAttr=nullptr, - UT_Array* variants=nullptr, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - static bool - BindPrimsFromPackedPrims(UT_Array& prims, - const GA_Range& rng, - UT_Array* variants=nullptr, - UT_Array* purposes=nullptr, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - static bool GetTimeCodesFromAttr(const GA_Range& rng, - const GA_Attribute& attr, - UT_Array& times); - - static bool GetTimeCodesFromPackedPrims(const GA_Range& rng, - UT_Array& times); - - /** Given a string attribute that represents prim paths, - return an array of actual prim paths. - @{ */ - static bool GetPrimPathsFromStringAttr(const GA_Attribute& attr, - UT_Array& paths, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - static bool GetPrimPathsFromStringAttr(const GA_Attribute& attr, - const GA_Range& rng, - UT_Array& paths, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - /** @} */ - - - /** Givena string attribute, return an array of tokens. - @{ */ - static bool GetTokensFromStringAttr(const GA_Attribute& attr, - UT_Array& tokens, - const char* nameSpace=nullptr); - - static bool GetTokensFromStringAttr(const GA_Attribute& attr, - const GA_Range& rng, - UT_Array& tokens, - const char* nameSpace=nullptr); - /** @} */ - - - /** Append points to a detail that represent references to prims. - The point offsets are contiguous, and the offset of the first - point is returned. If any failures occur, and invalid - offset is returned.*/ - static GA_Offset AppendRefPoints( - GU_Detail& gd, - const UT_Array& prims, - const char* pathAttrName=GUSD_PATH_ATTR, - const char* primPathAttrName=GUSD_PRIMPATH_ATTR); - - typedef GU_PrimPacked* (*PackedPrimBuildFunc)( - GU_Detail& detail, - const UT_StringHolder& fileName, - const SdfPath& primPath, - const UsdTimeCode& frame, - const char* lod, - const GusdPurposeSet purposes ); - - /** Register a function to be used by AppendPackedPrims to build - a packed prim of the given type. */ - static void RegisterPackedPrimBuildFunc( const TfToken& typeName, - PackedPrimBuildFunc func ); - - /** Append packed prims to the given detail that reference the - given prims with the given variants. */ - static bool AppendPackedPrims( - GU_Detail& gd, - const UT_Array& prims, - const UT_Array& variants, - const GusdDefaultArray& times, - const GusdDefaultArray& lods, - const GusdDefaultArray& purposes); - - typedef GusdUSD_Traverse::PrimIndexPair PrimIndexPair; - - /** Append prims @a prims, as an expansion of prims defined on - @a srcRange. The prim index pairs provide the prim found in - the expansion, and the index of the prim in the source range - whose expansion produced that prim. - Attributes matching @a filter are copied from the source - to the newly created ref points.*/ - static GA_Offset AppendExpandedRefPoints( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& prims, - const GA_AttributeFilter& filter, - const char* pathAttrName=GUSD_PATH_ATTR, - const char* primPathAttrName=GUSD_PRIMPATH_ATTR); - - static bool AppendExpandedPackedPrims( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& primIndexPairs, - const UT_Array& variants, - const GusdDefaultArray& times, - const GA_AttributeFilter& filter, - bool unpackToPolygons, - const UT_String& primvarPattern); - - /** Apply all variant selections in @a selections to each prim - in the range, storing the resulting variant path in @a variantsAttr. - For each source prim, this will first validate that the - variant selection is valid on the target prims. - If @a prevVariants is supplied, the variant selections are added - on top of any variant selections in the given paths.*/ - static bool WriteVariantSelectionsToAttr( - GU_Detail& gd, - const GA_Range& rng, - const UT_Array& prims, - const GusdUSD_Utils::VariantSelArray& selections, - const char* variantsAttr=GUSD_VARIANTS_ATTR, - const UT_Array* prevVariants=nullptr); - - static bool WriteVariantSelectionsToPackedPrims( - GU_Detail& gd, - const GA_Range& rng, - const UT_Array& prims, - const GusdUSD_Utils::VariantSelArray& selections, - const UT_Array* prevVariants=nullptr); - - /** Append variant selections defined by @a orderedVariants and - @a variantIndices as an expansion of prims from @a srcRng. - Attributes matching @a attrs filterare copied from the source - to the newly created ref points.*/ - static GA_Offset AppendRefPointsForExpandedVariants( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& orderedVariants, - const GusdUSD_Utils::IndexPairArray& variantIndices, - const GA_AttributeFilter& filter, - const char* variantsAttr=GUSD_VARIANTS_ATTR); - - static GA_Offset AppendPackedPrimsForExpandedVariants( - GU_Detail& gd, - const GA_Detail& srcGd, - const GA_Range& srcRng, - const UT_Array& orderedVariants, - const GusdUSD_Utils::IndexPairArray& variantIndices, - const GA_AttributeFilter& filter); - - /** Copy attributes from a source to dest range.*/ - static bool CopyAttributes( - const GA_Range& srcRng, - const GA_Range& dstRng, - const GA_IndexMap& dstMap, - const UT_Array& attrs); - - static bool GetPackedPrimViewportLODAndPurposes( - const GA_Detail& gd, - const GA_OffsetArray& offsets, - UT_StringArray& viewportLOD, - UT_Array& purposes); - - /** Compute world transforms from attributes over an array of offsets. - - In addition to using the standard instancing attributes, - this supports an additional schema for non-orthonormal transforms, - where the basis vectors (rows) of a rotation matrix are stored - as normal attributes 'i', 'j', 'k'.*/ - static bool ComputeTransformsFromAttrs(const GA_Detail& gd, - GA_AttributeOwner owner, - const GA_OffsetArray& offsets, - UT_Matrix4D* xforms); - - static bool ComputeTransformsFromPackedPrims(const GA_Detail& gd, - const GA_OffsetArray& offsets, - UT_Matrix4D* xforms); - - /** Support representations of attributes when authoring new transforms.*/ - enum OrientAttrRepresentation - { - ORIENTATTR_ORIENT, //! quaternion orient. - ORIENTATTR_IJK, //! vec3 i,j,k (can be non-orthogonal). - ORIENTATTR_IGNORE - }; - - enum ScaleAttrRepresentation - { - SCALEATTR_SCALE, //! scale (vec3). - SCALEATTR_PSCALE, //! single pscale. - SCALEATTR_IGNORE - }; - - /** Create and set transform attributes over the given range. - The @a indexMap maps offset->range_index, as computed by - ComputeRangeIndexMap().*/ - static bool SetTransformAttrs(GU_Detail& gd, - const GA_Range& r, - const GA_OffsetArray& indexMap, - OrientAttrRepresentation orientRep, - ScaleAttrRepresentation scaleRep, - const UT_Matrix4D* xforms); - - static bool SetPackedPrimTransforms(GU_Detail& gd, - const GA_Range& r, - const UT_Matrix4D* xforms); - - static bool MultTransformableAttrs(GU_Detail& gd, - const GA_Range& r, - const GA_OffsetArray& indexMap, - const UT_Matrix4D* xforms, - bool keepLengths=false, - const GA_AttributeFilter* filter=nullptr); - - /// Imports \p prim as unpacked geometry in \p gd. - static bool ImportPrimUnpacked(GU_Detail& gd, - const UsdPrim& prim, - UsdTimeCode time, - const char* lod = nullptr, - GusdPurposeSet purpose = GusdPurposeSet( - GUSD_PURPOSE_DEFAULT|GUSD_PURPOSE_PROXY), - const char* primvarPattern = "*", - const UT_Matrix4D* xform = nullptr, - const GT_RefineParms* refineParms = nullptr); -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_GU_USD_H*/ diff --git a/third_party/houdini/gusd/NURBSCurvesWrapper.cpp b/third_party/houdini/gusd/NURBSCurvesWrapper.cpp deleted file mode 100644 index 4ea5add9f5..0000000000 --- a/third_party/houdini/gusd/NURBSCurvesWrapper.cpp +++ /dev/null @@ -1,752 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "NURBSCurvesWrapper.h" - -#include "context.h" -#include "GT_VtArray.h" -#include "tokens.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include -#include -#include -#include -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::map; - -namespace { - -map gtToUsdBasisTranslation = { - { GT_BASIS_BEZIER, UsdGeomTokens->bezier }, - { GT_BASIS_BSPLINE, UsdGeomTokens->bspline }, - { GT_BASIS_CATMULLROM, UsdGeomTokens->catmullRom }, - { GT_BASIS_CATMULL_ROM, UsdGeomTokens->catmullRom }, - { GT_BASIS_HERMITE, UsdGeomTokens->hermite }}; - -map usdToGtBasisTranslation = { - { UsdGeomTokens->bezier, GT_BASIS_BEZIER }, - { UsdGeomTokens->bspline, GT_BASIS_BSPLINE }, - { UsdGeomTokens->catmullRom, GT_BASIS_CATMULLROM }, - { UsdGeomTokens->hermite, GT_BASIS_HERMITE }}; - -} // end of namespace - -GusdNURBSCurvesWrapper:: -GusdNURBSCurvesWrapper( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride ) -{ - initUsdPrim( stage, path, isOverride ); -} - -GusdNURBSCurvesWrapper:: -GusdNURBSCurvesWrapper( - const UsdGeomNurbsCurves& usdCurves, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdPrimWrapper( time, purposes ) - , m_usdCurves( usdCurves ) -{ -} - -GusdNURBSCurvesWrapper:: -~GusdNURBSCurvesWrapper() -{} - -bool GusdNURBSCurvesWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - bool newPrim = true; - if( asOverride ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing ) { - newPrim = false; - m_usdCurves = UsdGeomNurbsCurves(stage->OverridePrim( path )); - } - else { - // When fracturing, we want to override the outside surfaces and create - // new inside surfaces in one export. So if we don't find an existing prim - // with the given path, create a new one. - m_usdCurves = UsdGeomNurbsCurves::Define( stage, path ); - } - } - else { - m_usdCurves = UsdGeomNurbsCurves::Define( stage, path ); - } - if( !m_usdCurves || !m_usdCurves.GetPrim().IsValid() ) { - TF_WARN( "Unable to create %s NURBS curves '%s'.", newPrim ? "new" : "override", path.GetText() ); - } - return bool( m_usdCurves ); -} - -GT_PrimitiveHandle GusdNURBSCurvesWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - return new GusdNURBSCurvesWrapper( - sourcePrim, - stage, - path, - ctxt.writeOverlay); -} - -GT_PrimitiveHandle GusdNURBSCurvesWrapper:: -defineForRead( - const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdNURBSCurvesWrapper( - UsdGeomNurbsCurves( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdNURBSCurvesWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay); - clearCaches(); - return true; -} - -bool -GusdNURBSCurvesWrapper::refine( - GT_Refine& refiner, - const GT_RefineParms* parms) const -{ - if(!isValid()) - return false; - - bool refineForViewport = GT_GEOPrimPacked::useViewportLOD(parms); - - const UsdGeomNurbsCurves& usdCurves = m_usdCurves; - - GT_AttributeListHandle gtVertexAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtUniformAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtDetailAttrs = new GT_AttributeList( new GT_AttributeMap() ); - - // vertex counts - UsdAttribute countsAttr = usdCurves.GetCurveVertexCountsAttr(); - if(!countsAttr) { - TF_WARN( "Invalid USD vertext count attribute for NURB Curve. %s", - usdCurves.GetPrim().GetPath().GetText() ); - return false; - } - - VtIntArray usdCounts; - countsAttr.Get(&usdCounts, m_time); - auto gtVertexCounts = new GusdGT_VtArray( usdCounts ); - - UsdAttribute orderAttr = usdCurves.GetOrderAttr(); - if( !orderAttr ) { - TF_WARN( "Invalid USD order attribute for NURB Curve. %s", - usdCurves.GetPrim().GetPath().GetText() ); - return false; - } - - VtIntArray usdOrder; - orderAttr.Get( &usdOrder, m_time ); - - if( usdOrder.size() < usdCounts.size() ) { - TF_WARN( "Not enough values given for USD order attribute for NURB Curve. %s", - usdCurves.GetPrim().GetPath().GetText() ); - return false; - } - GT_DataArrayHandle gtOrder = new GusdGT_VtArray( usdOrder ); - - int numPoints = std::accumulate( usdCounts.begin(), usdCounts.end(), 0 ); - int numSegs = numPoints - 3 * usdCounts.size(); - int numSegEndPoints = numSegs + usdCounts.size(); - int numKnots = numPoints + std::accumulate( usdOrder.begin(), usdOrder.end(), 0 ); - - // point positions - UsdAttribute pointsAttr = usdCurves.GetPointsAttr(); - if(!pointsAttr) { - TF_WARN( "Invalid USD points attribute for NURB Curve. %s", - usdCurves.GetPrim().GetPath().GetText() ); - return false; - } - - VtVec3fArray usdPoints; - pointsAttr.Get(&usdPoints, m_time); - - if( usdPoints.size() < numPoints ) { - TF_WARN( "Not enough points specified for NURBS Curve. %s. Expected %d, got %zd", - usdCurves.GetPrim().GetPath().GetText(), - numPoints, usdPoints.size() ); - return false; - } - - GT_DataArrayHandle gtPoints = new GusdGT_VtArray(usdPoints,GT_TYPE_POINT); - gtVertexAttrs = gtVertexAttrs->addAttribute( "P", gtPoints, true ); - - GT_Basis basis = GT_BASIS_LINEAR; - GT_DataArrayHandle gtKnots; - - if( !refineForViewport ) { - - basis = GT_BASIS_BSPLINE; - - UsdAttribute knotsAttr = usdCurves.GetKnotsAttr(); - if( !knotsAttr ) { - TF_WARN( "Invalid USD order attribute for NURB Curve. %s", - usdCurves.GetPrim().GetPath().GetText() ); - } - else { - VtDoubleArray usdKnots; - knotsAttr.Get( &usdKnots, m_time ); - - if( usdKnots.size() >= numKnots ) { - gtKnots = new GusdGT_VtArray( usdKnots ); - } - else if ( usdKnots.size() == numKnots - 2 ) { - - // There was a time when the maya exported did not duplicate - // the end points when it should. - auto knotArray = new GT_Real64Array( numKnots, 1 ); - knotArray->set( usdKnots[0], 0 ); - for( size_t i = 0; i < usdKnots.size(); ++i ) { - knotArray->set( usdKnots[i], i+1 ); - } - knotArray->set( usdKnots[usdKnots.size()-1], numKnots-1 ); - gtKnots = knotArray; - } - else { - TF_WARN( "Not enough NURBS curve knot values specified. %s. Expected %d, got %zd", - usdCurves.GetPrim().GetPath().GetText(), - numKnots, usdKnots.size() ); - } - } - - // Build a array that maps values defined on segment end points to - // verticies. The number of segment end points is 2 less than the - // number of control point so just duplicate the first and last values. - // - 3. - auto segEndPointIndicies = new GT_Int32Array( usdPoints.size(), 1 ); - - GT_Offset srcIdx = 0; - GT_Offset dstIdx = 0; - for( const auto& c : usdCounts ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - for( int i = 0; i < c - 2; ++i ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - segEndPointIndicies->set( srcIdx, dstIdx++ ); - } - - UsdAttribute widthsAttr = usdCurves.GetWidthsAttr(); - VtFloatArray usdWidths; - if( widthsAttr.Get(&usdWidths, m_time) ) { - - GT_DataArrayHandle gtWidths = new GusdGT_VtArray(usdWidths); - - TfToken widthsInterpolation = usdCurves.GetWidthsInterpolation(); - if( widthsInterpolation == UsdGeomTokens->varying ) { - - if( usdWidths.size() < numSegEndPoints ) { - TF_WARN( "Not enough values provided for NURB curve varying widths for %s. Expected %d got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - numSegEndPoints, usdWidths.size() ); - } - else { - - gtWidths = new GT_DAIndirect( segEndPointIndicies, gtWidths ); - gtVertexAttrs = gtVertexAttrs->addAttribute( "pscale", gtWidths, true ); - } - } - if( widthsInterpolation == UsdGeomTokens->vertex ) { - - if( usdWidths.size() < numPoints ) { - TF_WARN( "Not enough values provided for NURB curve vertex widths for %s. Expected %d got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - numPoints, usdWidths.size() ); - } - else { - gtVertexAttrs = gtVertexAttrs->addAttribute( "pscale", gtWidths, true ); - } - } - else if( widthsInterpolation == UsdGeomTokens->uniform ) { - if( usdWidths.size() < usdCounts.size() ) { - TF_WARN( "Not enough values provided for NURB curve uniform widths for %s. Expected %zd got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - usdCounts.size(), usdWidths.size() ); - } - else { - gtUniformAttrs = gtUniformAttrs->addAttribute( "pscale", gtWidths, true ); - } - } - else if( widthsInterpolation == UsdGeomTokens->constant ) { - if( usdWidths.size() < 1 ) { - TF_WARN( "Not enough values provided for NURB curve constant widths for %s. Expected 1 got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - usdWidths.size() ); - } - else { - GT_DataArrayHandle gtWidths = new GusdGT_VtArray(usdWidths); - gtDetailAttrs = gtDetailAttrs->addAttribute( "pscale", gtWidths, true ); - } - } - } - // velocities - UsdAttribute velAttr = usdCurves.GetVelocitiesAttr(); - VtVec3fArray usdVelocities; - if( velAttr.Get(&usdVelocities, m_time) ) { - - GT_DataArrayHandle gtVelocities = - new GusdGT_VtArray(usdVelocities,GT_TYPE_VECTOR); - - // velocities are always vertex attributes - gtVertexAttrs = gtVertexAttrs->addAttribute( "v", gtVelocities, true ); - } - // normals - UsdAttribute normAttr = usdCurves.GetNormalsAttr(); - VtVec3fArray usdNormals; - if(normAttr.Get(&usdNormals, m_time) ) { - - GT_DataArrayHandle gtNormals = - new GusdGT_VtArray(usdNormals,GT_TYPE_NORMAL); - - TfToken normalsInterpolation = usdCurves.GetNormalsInterpolation(); - if( normalsInterpolation == UsdGeomTokens->varying ) { - - if( usdNormals.size() < numSegEndPoints ) { - TF_WARN( "Not enough values provided for NURB curve varying normals for %s. Expected %d got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - numSegEndPoints, usdNormals.size() ); - } - else { - - gtNormals = new GT_DAIndirect( segEndPointIndicies, gtNormals ); - gtVertexAttrs = gtVertexAttrs->addAttribute( "N", gtNormals, true ); - } - } - if( normalsInterpolation == UsdGeomTokens->vertex ) { - - if( usdNormals.size() < numPoints ) { - TF_WARN( "Not enough values provided for NURB curve vertex normals for %s. Expected %d got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - numPoints, usdNormals.size() ); - } - else { - gtVertexAttrs = gtVertexAttrs->addAttribute( "N", gtNormals, true ); - } - } - else if( normalsInterpolation == UsdGeomTokens->uniform ) { - if( usdNormals.size() < usdCounts.size() ) { - TF_WARN( "Not enough values provided for NURB curve uniform normals for %s. Expected %zd got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - usdCounts.size(), usdNormals.size() ); - } - else { - gtUniformAttrs = gtUniformAttrs->addAttribute( "N", gtNormals, true ); - } - } - else if( normalsInterpolation == UsdGeomTokens->constant ) { - if( usdNormals.size() < 1 ) { - TF_WARN( "Not enough values provided for NURB curve constant widths for %s. Expected 1 got %zd.", - usdCurves.GetPrim().GetPath().GetText(), - usdNormals.size() ); - } - else { - gtDetailAttrs = gtDetailAttrs->addAttribute( "N", gtNormals, true ); - } - } - } - // Load primvars. segEndPointIndicies are used if we need to expand primvar arrays - // from a value at segment end points to values in point attributes. - loadPrimvars( m_time, parms, - usdCounts.size(), - usdPoints.size(), - numSegEndPoints, - usdCurves.GetPath().GetString(), - NULL, - >VertexAttrs, - >UniformAttrs, - >DetailAttrs, - segEndPointIndicies ); - - } else { - - UsdGeomPrimvar colorPrimvar = usdCurves.GetPrimvar(GusdTokens->Cd); - if( !colorPrimvar || !colorPrimvar.GetAttr().HasAuthoredValue() ) { - colorPrimvar = usdCurves.GetPrimvar(GusdTokens->displayColor); - } - - if( colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValue()) { - - GT_DataArrayHandle gtData = convertPrimvarData( colorPrimvar, m_time ); - if( gtData ) { - if( colorPrimvar.GetInterpolation() == UsdGeomTokens->constant ) { - - gtDetailAttrs = gtDetailAttrs->addAttribute( "Cd", gtData, true ); - } - else if( colorPrimvar.GetInterpolation() == UsdGeomTokens->uniform ) { - - gtUniformAttrs = gtUniformAttrs->addAttribute( "Cd", gtData, true ); - } - else if( colorPrimvar.GetInterpolation() == UsdGeomTokens->vertex ) { - - gtVertexAttrs = gtVertexAttrs->addAttribute( "Cd", gtData, true ); - } - else { - - auto segEndPointIndicies = new GT_Int32Array( usdPoints.size(), 1 ); - - GT_Offset srcIdx = 0; - GT_Offset dstIdx = 0; - for( const auto& c : usdCounts ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - for( int i = 0; i < c; ++i ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - segEndPointIndicies->set( srcIdx, dstIdx++ ); - } - gtData = new GT_DAIndirect( segEndPointIndicies, gtData ); - gtVertexAttrs = gtVertexAttrs->addAttribute( "Cd", gtData, true ); - } - } - } - } - - auto prim = new GT_PrimCurveMesh( - basis, - gtVertexCounts, - gtVertexAttrs, - gtUniformAttrs, - gtDetailAttrs, - false ); - - if( !refineForViewport ) { - if( gtOrder ) { - prim->setOrder( gtOrder ); - } - if( gtKnots ) { - prim->setKnots( gtKnots ); - } - } - - // set local transform - UT_Matrix4D mat; - - if( !GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - usdCurves.GetPrim(), - m_time, - mat ) ) { - TF_WARN( "Failed to compute transform" ); - return false; - } - - prim->setPrimitiveTransform( getPrimitiveTransform() ); - refiner.addPrimitive( prim ); - return true; -} - - -const char* GusdNURBSCurvesWrapper:: -className() const -{ - return "GusdNURBSCurvesWrapper"; -} - - -void GusdNURBSCurvesWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdNURBSCurvesWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdNURBSCurvesWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdNURBSCurvesWrapper:: -doSoftCopy() const -{ - // TODO - return GT_PrimitiveHandle(new GusdNURBSCurvesWrapper(*this)); -} - - -bool -GusdNURBSCurvesWrapper::isValid() const -{ - return bool( m_usdCurves ); -} - -bool -GusdNURBSCurvesWrapper::updateFromGTPrim( - const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache - ) -{ - if( !m_usdCurves ) { - TF_WARN( "Attempting to update invalid curve prim" ); - return false; - } - - const GT_PrimCurveMesh* gtCurves - = dynamic_cast(sourcePrim.get()); - if(!gtCurves) { - TF_WARN( "Attempting to update curve of wrong type %s", sourcePrim->className() ); - return false; - } - - bool overlayTransforms = ctxt.overlayTransforms; - - // While I suppose we could write both points and transforms, it gets confusing, - // and I don't this its necessary so lets not. - if( ctxt.overlayPoints || ctxt.overlayAll ) { - overlayTransforms = false; - } - - UsdTimeCode geoTime = ctxt.time; - if( ctxt.writeStaticGeo ) { - geoTime = UsdTimeCode::Default(); - } - - GfMatrix4d xform = computeTransform( - m_usdCurves.GetPrim().GetParent(), - geoTime, - houXform, - xformCache ); - - GfMatrix4d loc_xform = computeTransform( - m_usdCurves.GetPrim(), - geoTime, - houXform, - xformCache ); - - // If we are writing points for an overlay but not writing transforms, - // then we have to transform the points into the proper space. - bool transformPoints = - (ctxt.overlayPoints || ctxt.overlayAll) && - !GusdUT_Gf::Cast(loc_xform).isIdentity(); - - GT_Owner attrOwner = GT_OWNER_INVALID; - GT_DataArrayHandle houAttr; - UsdAttribute usdAttr; - - if( !ctxt.writeOverlay && ctxt.purpose != UsdGeomTokens->default_ ) { - m_usdCurves.GetPurposeAttr().Set( ctxt.purpose ); - } - - // intrinsic attributes ---------------------------------------------------- - - if( !ctxt.writeOverlay || ctxt.overlayAll || overlayTransforms || ctxt.overlayPoints ) { - - // extent ------------------------------------------------------------------ - houAttr = GusdGT_Utils::getExtentsArray(sourcePrim); - usdAttr = m_usdCurves.GetExtentAttr(); - if(houAttr && usdAttr && transformPoints ) { - houAttr = GusdGT_Utils::transformPoints( houAttr, loc_xform ); - } - updateAttributeFromGTPrim( GT_OWNER_INVALID, "extents", houAttr, usdAttr, geoTime ); - } - - // transform --------------------------------------------------------------- - if( !ctxt.writeOverlay || ctxt.overlayAll || overlayTransforms) { - updateTransformFromGTPrim( xform, geoTime, - ctxt.granularity == GusdContext::PER_FRAME ); - } - - // visibility --------------------------------------------------------------- - - updateVisibilityFromGTPrim(sourcePrim, geoTime, - (!ctxt.writeOverlay || ctxt.overlayAll) && - ctxt.granularity == GusdContext::PER_FRAME ); - - if( !ctxt.writeOverlay || ctxt.overlayAll || ctxt.overlayPoints ) { - - // P - houAttr = sourcePrim->findAttribute("P", attrOwner, 0); - usdAttr = m_usdCurves.GetPointsAttr(); - if(houAttr && usdAttr && transformPoints ) { - houAttr = GusdGT_Utils::transformPoints( houAttr, loc_xform ); - } - updateAttributeFromGTPrim( attrOwner, "P", houAttr, usdAttr, geoTime ); - } - - if( !ctxt.writeOverlay || ctxt.overlayAll ) { - - UsdTimeCode topologyTime = ctxt.time; - if( ctxt.writeStaticTopology ) { - topologyTime = UsdTimeCode::Default(); - } - - // Vertex counts - usdAttr = m_usdCurves.GetCurveVertexCountsAttr(); - auto gtCurveCounts = gtCurves->getCurveCounts(); - - updateAttributeFromGTPrim( GT_OWNER_INVALID, "vertexcounts", - gtCurveCounts, usdAttr, topologyTime ); - - // Order - usdAttr = m_usdCurves.GetOrderAttr(); - if( gtCurves->isUniformOrder() ) { - VtIntArray val( gtCurveCounts->entries() ); - for( size_t i = 0; i < val.size(); ++i ) { - val[i] = gtCurves->uniformOrder(); - } - usdAttr.Set( val ); - } - else { - GT_DataArrayHandle buffer; - const int64* gtOrders = gtCurves->varyingOrders()->getI64Array( buffer ); - VtIntArray val( gtCurves->varyingOrders()->entries() ); - for( size_t i = 0; i < val.size(); ++i ) { - val[i] = gtOrders[i]; - } - usdAttr.Set( val ); - } - - // Knots - GT_DataArrayHandle knotTmpBuffer; - usdAttr = m_usdCurves.GetKnotsAttr(); - GT_DataArrayHandle gtKnots = gtCurves->knots(); - if( gtKnots->getStorage() != GT_STORE_REAL64 ) { - gtKnots = new GT_Real64Array( gtKnots->getF64Array( knotTmpBuffer ), - gtKnots->entries(), 1 ); - } - - updateAttributeFromGTPrim( GT_OWNER_INVALID, "knots", - gtKnots, usdAttr, geoTime ); - } - - - if( !ctxt.writeOverlay || ctxt.overlayAll || ctxt.overlayPoints ) { - // N - houAttr = sourcePrim->findAttribute("N", attrOwner, 0); - usdAttr = m_usdCurves.GetNormalsAttr(); - updateAttributeFromGTPrim( attrOwner, "N", houAttr, usdAttr, geoTime ); - - // v - houAttr = sourcePrim->findAttribute("v", attrOwner, 0); - usdAttr = m_usdCurves.GetVelocitiesAttr(); - updateAttributeFromGTPrim( attrOwner, "v", houAttr, usdAttr, geoTime ); - - // pscale & width - houAttr = sourcePrim->findAttribute("width", attrOwner, 0); - if(!houAttr) { - houAttr = sourcePrim->findAttribute("pscale", attrOwner, 0); - } - - usdAttr = m_usdCurves.GetWidthsAttr(); - - updateAttributeFromGTPrim( attrOwner, "width", houAttr, usdAttr, geoTime ); - m_usdCurves.SetWidthsInterpolation( UsdGeomTokens->vertex ); - } - - // ------------------------------------------------------------------------- - - // primvars ---------------------------------------------------------------- - - if( !ctxt.writeOverlay || ctxt.overlayAll || ctxt.overlayPrimvars ) { - - UsdTimeCode primvarTime = ctxt.time; - if( ctxt.writeStaticPrimvars ) { - primvarTime = UsdTimeCode::Default(); - } - - GusdGT_AttrFilter filter = ctxt.attributeFilter; - - filter.appendPattern(GT_OWNER_VERTEX, "^P ^N ^v ^width ^pscale ^visible"); - if(const GT_AttributeListHandle vtxAttrs = sourcePrim->getVertexAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_VERTEX; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( - vtxAttrs, filter, UsdGeomTokens->vertex, primvarTime ); - } - filter.appendPattern(GT_OWNER_CONSTANT, "^visible"); - if(const GT_AttributeListHandle constAttrs = sourcePrim->getDetailAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_CONSTANT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( constAttrs, filter, UsdGeomTokens->constant, primvarTime ); - } - filter.appendPattern(GT_OWNER_UNIFORM, "^visible"); - if(const GT_AttributeListHandle uniformAttrs = sourcePrim->getUniformAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_UNIFORM; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( uniformAttrs, filter, UsdGeomTokens->uniform, primvarTime ); - } - - // If we have a "Cd" attribute, write it as both "Cd" and "displayColor". - // The USD guys promise me that this data will get "deduplicated" so there - // is not cost for doing this. - GT_Owner own; - if(GT_DataArrayHandle Cd = sourcePrim->findAttribute( "Cd", own, 0 )) { - - GT_AttributeMapHandle attrMap = new GT_AttributeMap(); - GT_AttributeListHandle attrList = new GT_AttributeList( attrMap ); - attrList = attrList->addAttribute( "displayColor", Cd, true ); - GusdGT_AttrFilter filter( "*" ); - GusdGT_AttrFilter::OwnerArgs owners; - owners << own; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( attrList, filter, s_ownerToUsdInterpCurve[own], primvarTime ); - } - } - - // ------------------------------------------------------------------------- - return GusdPrimWrapper::updateFromGTPrim(sourcePrim, houXform, ctxt, xformCache); -} - -PXR_NAMESPACE_CLOSE_SCOPE - - diff --git a/third_party/houdini/gusd/NURBSCurvesWrapper.h b/third_party/houdini/gusd/NURBSCurvesWrapper.h deleted file mode 100644 index 95c0863026..0000000000 --- a/third_party/houdini/gusd/NURBSCurvesWrapper.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_NURBSCURVES_WRAPPER_H -#define GUSD_NURBSCURVES_WRAPPER_H - -#include "primWrapper.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/nurbsCurves.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -class GusdNURBSCurvesWrapper : public GusdPrimWrapper -{ -public: - GusdNURBSCurvesWrapper( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride = false ); - GusdNURBSCurvesWrapper( - const UsdGeomNurbsCurves& usdCurves, - UsdTimeCode time, - GusdPurposeSet purposes ); - - virtual ~GusdNURBSCurvesWrapper(); - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdCurves; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) override; - - virtual bool isValid() const override; - - virtual bool refine(GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const override; -public: - - static GT_PrimitiveHandle - defineForWrite( const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - bool initUsdPrim( const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - UsdGeomNurbsCurves m_usdCurves; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_NURBSCURVES_WRAPPER_H diff --git a/third_party/houdini/gusd/OP_ParmChangeMicroNode.cpp b/third_party/houdini/gusd/OP_ParmChangeMicroNode.cpp deleted file mode 100644 index 2fda9ae627..0000000000 --- a/third_party/houdini/gusd/OP_ParmChangeMicroNode.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "OP_ParmChangeMicroNode.h" - -#include "UT_Assert.h" - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -struct GusdOP_ParmChangeMicroNode::_ParmCache -{ - _ParmCache(const PRM_Parm& parm, int pi, int vi) - : _pi(pi), _vi(vi) - { - UT_ASSERT(vi < parm.getVectorSize()); - } - - virtual ~_ParmCache() {} - - virtual bool Update(OP_Parameters& node, fpreal t, int thread) = 0; - -protected: - const int _pi, _vi; -}; - - -namespace { - - -struct _FloatEval -{ - void operator()(fpreal& val, OP_Parameters& node, - int pi, int vi, fpreal t, int thread) const - { val = node.evalFloatT(pi, vi, t, thread); } - - void operator()(fpreal64* vals, OP_Parameters& node, - int pi, fpreal t, int thread) const - { - UT_ASSERT_P(vals); - node.evalFloatsT(pi, vals, t, thread); - } -}; - - -struct _IntEval -{ - void operator()(int& val, OP_Parameters& node, - int pi, int vi, fpreal t, int thread) const - { val = node.evalIntT(pi, vi, t, thread); } - void operator()(int* vals, OP_Parameters& node, - int pi, fpreal t, int thread) const - { - UT_ASSERT_P(vals); - const int vecSize = node.getParm(pi).getVectorSize(); - for(int i = 0; i < vecSize; ++i) - vals[i] = node.evalIntT(pi, i, t, thread); - } -}; - - -struct _StrEval -{ - void operator()(UT_String& val, OP_Parameters& node, - int pi, int vi, fpreal t, int thread) const - { node.evalStringT(val, pi, vi, t, thread); } - - void operator()(UT_String* vals, OP_Parameters& node, - int pi, fpreal t, int thread) const - { - UT_ASSERT_P(vals); - const int vecSize = node.getParm(pi).getVectorSize(); - for(int i = 0; i < vecSize; ++i) - node.evalStringT(vals[i], pi, i, t, thread); - } -}; - - -template -struct _ParmCacheSingleT : public GusdOP_ParmChangeMicroNode::_ParmCache -{ - _ParmCacheSingleT(const PRM_Parm& parm, int pi, int vi) - : _ParmCache(parm, pi, vi) {} - - virtual bool Update(OP_Parameters& node, fpreal t, int thread) - { - T tmp; - EVALFN()(tmp, node, _pi, _vi, t, thread); - if(tmp != _val) { - SetVal(tmp); - return true; - } - return false; - } - - void SetVal(const T& val) { _val = val; } -private: - T _val; -}; - - -/* Specialize setter for strings.*/ -template <> -void -_ParmCacheSingleT::SetVal(const UT_String& src) -{ - _val.harden(src); -} - - -template -struct _ParmCacheMultiT : public GusdOP_ParmChangeMicroNode::_ParmCache -{ - _ParmCacheMultiT(const PRM_Parm& parm, int pi, int vi) - : _ParmCache(parm, pi, vi) - { - const int vecSize = parm.getVectorSize(); - _vals.setSize(vecSize); - _tmpVals.setSize(vecSize); - } - - virtual bool Update(OP_Parameters& node, fpreal t, int thread) - { - EVALFN()(_tmpVals.array(), node, _pi, t, thread); - if(_tmpVals != _vals) { - SetVals(_tmpVals); - return true; - } - return false; - } - void SetVals(const UT_Array& vals) { _vals = vals; } -private: - UT_Array _vals; - UT_Array _tmpVals; /*! Temp value buffer. - Used to avoid allocation when updating.*/ -}; - - -/* Specialize setter for strings.*/ -template <> -void -_ParmCacheMultiT::SetVals(const UT_Array& vals) -{ - _vals = vals; - for(exint i = 0; i < _vals.size(); ++i) - _vals(i).harden(); -} - - -} /*namespace*/ - - -GusdOP_ParmChangeMicroNode::~GusdOP_ParmChangeMicroNode() -{ - for(exint i = 0; i < _cachedVals.size(); ++i) - delete GusdUTverify_ptr(_cachedVals(i)); -} - - -void -GusdOP_ParmChangeMicroNode::addParm(int parmIdx, int vecIdx) -{ - UT_ASSERT(parmIdx >= 0 && parmIdx <= _node.getNumParms()); - - const PRM_Parm& parm = _node.getParm(parmIdx); - const int vecSize = parm.getVectorSize(); - - UT_ASSERT(vecSize > 0); - - if(vecSize == 1) - vecIdx = 0; - - if(parm.getType().isFloatType()) - { - if(vecIdx >= 0) - _cachedVals.append(new _ParmCacheSingleT( - parm, parmIdx, vecIdx)); - else - _cachedVals.append(new _ParmCacheMultiT( - parm, parmIdx, vecIdx)); - } - else if(parm.getType().isOrdinalType()) - { - if(vecIdx >= 0) - _cachedVals.append(new _ParmCacheSingleT( - parm, parmIdx, vecIdx)); - else - _cachedVals.append(new _ParmCacheMultiT( - parm, parmIdx, vecIdx)); - } - else if(parm.getType().isStringType()) - { - if(vecIdx >= 0) - _cachedVals.append(new _ParmCacheSingleT( - parm, parmIdx, vecIdx)); - else - _cachedVals.append(new _ParmCacheMultiT( - parm, parmIdx, vecIdx)); - } else { - /* nothing to track.*/ - return; - } - PRM_ParmList* parms = GusdUTverify_ptr(_node.getParmList()); - if(vecIdx < 0) { - for(int i = 0; i < vecSize; ++i) - addExplicitInput(parms->parmMicroNode(parmIdx, i)); - } else { - addExplicitInput(parms->parmMicroNode(parmIdx, vecIdx)); - } - _parmsAdded = true; -} - - -bool -GusdOP_ParmChangeMicroNode::updateVals(fpreal t, int thread) -{ - int changed = _parmsAdded; - _parmsAdded = false; - - for(exint i = 0; i < _cachedVals.size(); ++i) - changed += GusdUTverify_ptr(_cachedVals(i))->Update(_node, t, thread); - - DEP_TimedMicroNode::update(t); - return changed; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/OP_ParmChangeMicroNode.h b/third_party/houdini/gusd/OP_ParmChangeMicroNode.h deleted file mode 100644 index bd819cd9dc..0000000000 --- a/third_party/houdini/gusd/OP_ParmChangeMicroNode.h +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief -*/ -#ifndef GUSD_OP_PARM_CHANGE_MICRO_NODE_H -#define GUSD_OP_PARM_CHANGE_MICRO_NODE_H - -#include "pxr/pxr.h" - -#include "api.h" - -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/** Micro node for tracking changes to a set of parameters. - This is similar to OP_ParmCache, except that this tracks changes to the - *resolved* values of parameters, rather than their dirty states. - - Only persistent parameters can be tracked. Spare and dynamic parameters - (I.e., instances of multi parms) cannot be tracked through this class. - - This class is not thread safe!*/ -class GUSD_API GusdOP_ParmChangeMicroNode : public DEP_TimedMicroNode -{ -public: - explicit GusdOP_ParmChangeMicroNode(OP_Parameters& node) - : DEP_TimedMicroNode(), _node(node), _parmsAdded(false) {} - - virtual ~GusdOP_ParmChangeMicroNode(); - - /** Begin tracking the given parm. - If @a vectorIdx is less than zero, all elements of the parm - tuple are tracked.*/ - void addParm(int parmIdx, int vecIdx=-1); - - /** Update the resolved parm values. - @return true if any resolved values changed.*/ - bool updateVals(fpreal t, int thread=SYSgetSTID()); - - bool updateIfNeeded(fpreal t, int thread=SYSgetSTID()) - { return requiresUpdate(t) && updateVals(t, thread); } - - virtual void update(fpreal t) { updateVals(t); } - - /** Clear our inputs. - This is overridden to disallow clearing of explicit inputs, - which are meant to persist on this micro node.*/ - virtual void clearInputs() { setTimeDependent(false); } - - struct _ParmCache; - -private: - OP_Parameters& _node; - - UT_Array<_ParmCache*> _cachedVals; - bool _parmsAdded; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_OP_PARM_CHANGE_MICRO_NODE_H*/ diff --git a/third_party/houdini/gusd/PRM_Shared.cpp b/third_party/houdini/gusd/PRM_Shared.cpp deleted file mode 100644 index fc932f72a3..0000000000 --- a/third_party/houdini/gusd/PRM_Shared.cpp +++ /dev/null @@ -1,347 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "PRM_Shared.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stageCache.h" -#include "GU_USD.h" -#include "USD_StdTraverse.h" -#include "USD_Traverse.h" -#include "USD_Utils.h" - -#include "pxr/usd/sdf/fileFormat.h" -#include "pxr/usd/sdf/layer.h" -#include "pxr/usd/usd/attribute.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usd/stage.h" -#include "pxr/usd/usd/primRange.h" -#include "pxr/usd/usdGeom/imageable.h" - -#if !(SYS_VERSION_FULL_INT >= 0x10050000 && SYS_VERSION_FULL_INT < 0x11000000) -#include -#endif - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -namespace { - - -UT_SingletonWithLock _componentsSingleton; - - -void _GenUsdPrimMenu(void* data, PRM_Name* names, int size, - const PRM_SpareData* spare, const PRM_Parm* parm) -{ - /** BUG: Having a large number of items in the menu causes items - to overlap each other in the menu, making the menu unusable. - Clamp the range as a temporary fix. When real hierarchic menus come - in, this limit should go away. */ - size = std::min(size, 500); - - names[0] = PRM_Name(); - if(!spare) - return; - if(const char* fileParm = spare->getValue("fileprm")) - { - OP_Node* node = static_cast(data); - UT_String file; - node->evalString(file, fileParm, 0, 0); - - GusdStageCacheReader cache; - if(auto stage = cache.FindOrOpen(UT_StringHolder(file), - GusdStageOpts::LoadNone())) - { - GusdPurposeSet purposes = GUSD_PURPOSE_NONE; - UT_Array prims; - // Only list components (keep the list size small) - GusdUSD_StdTraverse::GetRecursiveModelTraversal().FindPrims( - stage->GetPseudoRoot(), UsdTimeCode::Default(), purposes, prims); - - names[0] = PRM_Name("/", ""); - exint primEnd = size - 1; // leave room for end marker. - int i = 0; - for(const auto& prim : prims) { - if(++i > primEnd) - break; - const char* path = prim.GetPath().GetText(); - names[i] = PRM_Name(path,path); - names[i].harden(); - } - names[i] = PRM_Name(); - } - } -} - - -void _GenUsdPrimAttrMenu(void* data, PRM_Name* names, int size, - const PRM_SpareData* spare, const PRM_Parm* parm) -{ - /** BUG: Same as in _GenUsdPrimMenu() */ - size = std::min(size, 500); - - UT_IntArray idxs; - parm->getMultiInstanceIndex(idxs); - - names[0] = PRM_Name(); - if(!spare) - return; - UT_String fileParm(spare->getValue("fileprm")); - parm->instanceMultiString(fileParm, idxs, false); - UT_String primPathParm(spare->getValue("primpathprm")); - parm->instanceMultiString(primPathParm, idxs, false); - - if(!fileParm.isstring() || !primPathParm.isstring()) - return; - - OP_Node* node = static_cast(data); - UT_String file, primPath; - node->evalString(file, fileParm, 0, 0); - node->evalString(primPath, primPathParm, 0, 0); - - GusdStageCacheReader cache; - UsdPrim usdPrim = cache.GetPrimWithVariants(fileParm, primPath).first; - if(!usdPrim) - return; - - std::vector keyNames; - - bool wantAttrs=false; - UT_String primAttrCondition(spare->getValue("primattrcondition")); - if(primAttrCondition.isstring()) - { - parm->instanceMultiString(primAttrCondition, idxs, false); - PRM_Conditional cond(primAttrCondition); -#if UT_MAJOR_VERSION_INT >= 16 - wantAttrs = cond.eval(*parm, *node->getParmList(), NULL); -#else - wantAttrs = cond.eval(*node->getParmList(), NULL); -#endif - } - if(!primAttrCondition) - wantAttrs = true; - if(wantAttrs) - { - // XXX: This may wish to examine all attributes (via GetAttributes()) - // rather than just the authored attributes. - for(const auto& attr : usdPrim.GetAuthoredAttributes()) - keyNames.push_back(attr.GetName()); - } - std::sort(keyNames.begin(), keyNames.end()); - int maxKeys = std::min((int)keyNames.size(), size-1); - for(int i = 0; i < maxKeys; ++i) - { - names[i] = PRM_Name(keyNames[i].c_str(), keyNames[i].c_str()); - names[i].harden(); - } - names[maxKeys] = PRM_Name(); -} - - -void _MakePrefixedName(UT_String& str, const char* name, - int prefixCount, const char* prefix) -{ - const int len = strlen(prefix); - - UT_WorkBuffer buf; - for(int i = 0; i < prefixCount; ++i) - buf.append(prefix, len); - buf.append(name); - buf.stealIntoString(str); -} - - -void _AppendTypes(const TfType& type, UT_Array& names, - PRM_AutoDeleter& deleter, int depth=0) -{ - const auto& typeName = type.GetTypeName(); - // Add spacing at front, by depth, to indicate hierarchy. - UT_String label; - _MakePrefixedName(label, typeName.c_str(), depth, "| "); - - // Only 16.5 (not 16.0 and not 17.0) needs to use hboost::function here. - // In 16.0 hboost doesn't exist yet. In 17.0 the argument is templated. - names.append(PRM_Name(typeName.c_str(), deleter.appendCallback( -#if SYS_VERSION_FULL_INT >= 0x10050000 && SYS_VERSION_FULL_INT < 0x11000000 - hboost::function(free), label.steal()))); -#else - boost::function(free), label.steal()))); -#endif - - for(const auto& derived : type.GetDirectlyDerivedTypes()) - _AppendTypes(derived, names, deleter, depth+1); -} - - -PRM_Name* _GetTypeNames() -{ - static UT_Array names; - static PRM_AutoDeleter deleter; - - TfType type = TfType::Find(); - _AppendTypes(type, names, deleter); - - names.append(PRM_Name()); - - return &names(0); -} - - -void _AppendKinds(const GusdUSD_Utils::KindNode* kind, - UT_Array& names, - PRM_AutoDeleter& deleter, int depth=0) -{ - const auto& name = kind->kind.GetString(); - // Add spacing at front, by depth, to indicate hierarchy. - UT_String label; - _MakePrefixedName(label, name.c_str(), depth, "| "); - - // Only 16.5 (not 16.0 and not 17.0) needs to use hboost::function here. - // In 16.0 hboost doesn't exist yet. In 17.0 the argument is templated. - names.append(PRM_Name(name.c_str(), deleter.appendCallback( -#if SYS_VERSION_FULL_INT >= 0x10050000 && SYS_VERSION_FULL_INT < 0x11000000 - hboost::function(free), label.steal()))); -#else - boost::function(free), label.steal()))); -#endif - - for(const auto& derived : kind->children) - _AppendKinds(derived.get(), names, deleter, depth+1); -} - - -PRM_Name* _GetModelKindNames() -{ - static UT_Array names; - static PRM_AutoDeleter deleter; - - for(const auto& kind : GusdUSD_Utils::GetModelKindHierarchy().children) - _AppendKinds(kind.get(), names, deleter); - - names.append(PRM_Name()); - - return &names(0); -} - - -PRM_Name* _GetPurposeNames() -{ - static UT_Array names; - for(const auto& p : UsdGeomImageable::GetOrderedPurposeTokens()) - names.append(PRM_Name(p.GetText(), p.GetText())); - names.append(PRM_Name()); - return &names(0); -} - - -UT_String -_ComputeFileFormatExtensionsPattern() -{ - UT_WorkBuffer buf; - - const auto extensions = SdfFileFormat::FindAllFileFormatExtensions(); - - if (!extensions.empty()) { - - auto it = extensions.begin(); - - buf.append("*."_UTsh); - buf.append(*it); - - for (++it; it != extensions.end(); ++it) { - buf.append(",*."_UTsh); - buf.append(*it); - } - } - - UT_String str; - buf.stealIntoString(str); - return str; -} - - -} /*namespace*/ - - - -GusdPRM_Shared::GusdPRM_Shared() - : _components(_componentsSingleton.get()) -{} - - -GusdPRM_Shared::Components::Components() : - filePattern(_ComputeFileFormatExtensionsPattern()), - usdFileROData( - PRM_SpareArgs() - << PRM_SpareToken(PRM_SpareData::getFileChooserPatternToken(), - filePattern) - << PRM_SpareToken(PRM_SpareData::getFileChooserModeToken(), - PRM_SpareData::getFileChooserModeValRead())), - - usdFileRWData( - PRM_SpareArgs() - << PRM_SpareToken(PRM_SpareData::getFileChooserPatternToken(), - filePattern) - << PRM_SpareToken(PRM_SpareData::getFileChooserModeToken(), - PRM_SpareData::getFileChooserModeValReadAndWrite())), - - usdFileWOData( - PRM_SpareArgs() - << PRM_SpareToken(PRM_SpareData::getFileChooserPatternToken(), - filePattern) - << PRM_SpareToken(PRM_SpareData::getFileChooserModeToken(), - PRM_SpareData::getFileChooserModeValWrite())), - - filePathName("file", "USD File"), - - primPathName("primpath", "Prim Path"), - primMenu(PRM_CHOICELIST_REPLACE, _GenUsdPrimMenu), - multiPrimMenu(PRM_CHOICELIST_TOGGLE, _GenUsdPrimMenu), - primAttrMenu(PRM_CHOICELIST_REPLACE, _GenUsdPrimAttrMenu), - - fileParm(PRM_SpareArgs() - << PRM_SpareToken( "fileprm", filePathName.getToken() )), - primAttrData(PRM_SpareArgs() - << PRM_SpareToken( "fileprm", filePathName.getToken()) - << PRM_SpareToken( "primpathprm", primPathName.getToken() )), - - typesMenu(PRM_CHOICELIST_TOGGLE, _GetTypeNames()), - modelKindsMenu(PRM_CHOICELIST_TOGGLE, _GetModelKindNames()), - purposesMenu(PRM_CHOICELIST_TOGGLE, _GetPurposeNames()), - pathAttrDefault(0, GUSD_PATH_ATTR), - primPathAttrDefault(0, GUSD_PRIMPATH_ATTR), - variantsAttrDefault(0, GUSD_VARIANTS_ATTR) -{} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/PRM_Shared.h b/third_party/houdini/gusd/PRM_Shared.h deleted file mode 100644 index f63a51b14f..0000000000 --- a/third_party/houdini/gusd/PRM_Shared.h +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief Shared PRM objects. -*/ -#ifndef GUSD_PRM_SHARED_H -#define GUSD_PRM_SHARED_H - -#include "pxr/pxr.h" - -#include "api.h" - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/** Common PRM data for USD.*/ -class GusdPRM_Shared -{ -public: - GUSD_API - GusdPRM_Shared(); - - struct Components - { - Components(); - - /** Pattern of all USD-backed extensions.*/ - UT_String filePattern; - - /** Spare data with extension pattern for usd files. - The different variations are for the read/write mode of the - file chooser dialog. - @{ */ - PRM_SpareData usdFileROData; - PRM_SpareData usdFileRWData; - PRM_SpareData usdFileWOData; - /** @} */ - - PRM_Name filePathName; /*! file */ - - PRM_Name primPathName; /*! primpath */ - - /** Dynamic menu for selecting prim paths. - Must be paired with a PRM_SpareData giving 'fileprm', whose value - is the name of a string parm on the same prim, which gives the path - to the usd file. - @todo This currently uses a simple drop-down menu. When the new UI - API access rolls out in the HDK, this should be updated to use a proper - hierarchy UI, like the regular operator picker menus in Houdini.*/ - PRM_ChoiceList primMenu; - - /** Variant of the above @em primMenu that can be used to - pick multiple prims.*/ - PRM_ChoiceList multiPrimMenu; - - /** Dynamic menu for selecting prim attributes. - Like @a primMenu, must be paired with spair data giveing 'fileprm' - as well as 'primpathprm'. Additional spare data 'primattrcondtiion' - optionally provide conditional parm expressions for determining whether - or not the attribute keys are included.*/ - PRM_ChoiceList primAttrMenu; - - /** Has fileprm=>'fileprm', the common mapping for @a primMenu. */ - PRM_SpareData fileParm; - - /** Has primpathprm=>'primpath', and fileprm=>'fileprm', the mapping - commonly used for @a primAttrMenu. */ - PRM_SpareData primAttrData; - - /** Multi-select menu for all UsdSchema-inherited types.*/ - PRM_ChoiceList typesMenu; - - /** Multi-select menu for all model kinds.*/ - PRM_ChoiceList modelKindsMenu; - - /** Multi-select menu for all imageable purposes.*/ - PRM_ChoiceList purposesMenu; - - PRM_Default pathAttrDefault; //! usdpath - PRM_Default primPathAttrDefault; //! usdprimpath - PRM_Default variantsAttrDefault; //! usdvariants - }; - - Components* operator->() const { return &_components; } - Components& operator*() const { return _components; } - -private: - Components& _components; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /* __GUSD_PRM_PRMSHARED_H__ */ diff --git a/third_party/houdini/gusd/USD_CustomTraverse.cpp b/third_party/houdini/gusd/USD_CustomTraverse.cpp deleted file mode 100644 index 611de195f2..0000000000 --- a/third_party/houdini/gusd/USD_CustomTraverse.cpp +++ /dev/null @@ -1,590 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_CustomTraverse.h" - -#include -#include - -#include "PRM_Shared.h" -#include "USD_ThreadedTraverse.h" -#include "USD_Utils.h" - -#include "pxr/base/arch/hints.h" -#include "pxr/base/plug/registry.h" -#include "pxr/usd/kind/registry.h" -#include "pxr/usd/usd/modelAPI.h" -#include "pxr/usd/usdGeom/imageable.h" - -PXR_NAMESPACE_OPEN_SCOPE - -void -GusdUSD_CustomTraverse::Opts::Reset() -{ - defined = TRUE_STATE; - abstract = FALSE_STATE; - active = TRUE_STATE; - visible = TRUE_STATE; - imageable = TRUE_STATE; - model = group = instance = master = clips = ANY_STATE; - - traverseMatched = false; - kinds.clear(); - purposes.clear(); - types.clear(); -} - - -namespace { - -void _PredicateSwitch(Usd_PrimFlagsConjunction& p, - GusdUSD_CustomTraverse::TriState state, - Usd_PrimFlags flag) -{ - switch(state) { - case GusdUSD_CustomTraverse::TRUE_STATE: p &= flag; break; - case GusdUSD_CustomTraverse::FALSE_STATE: p &= !flag; break; - default: break; - } -} - -} /*namespace*/ - - -Usd_PrimFlagsPredicate -GusdUSD_CustomTraverse::Opts::MakePredicate() const -{ - // Build a predicate from the user-configured options. - - /* Note that we *intentionally* exclude load state from being - user-configurable, since traversers are primarily intended to - be used on pure, read-only caches, in which case users aren't meant - to know about prim load states. - - We also don't default add UsdPrimIsLoaded at all to the predicate, - as that prevents users from traversing to inactive prims, since - if a prim carrying payloads has been deactivated, the prim will - be considered both inactive and unloaded.*/ - - Usd_PrimFlagsConjunction p; - - _PredicateSwitch(p, active, UsdPrimIsActive); - _PredicateSwitch(p, model, UsdPrimIsModel); - _PredicateSwitch(p, group, UsdPrimIsGroup); - _PredicateSwitch(p, defined, UsdPrimIsDefined); - _PredicateSwitch(p, abstract, UsdPrimIsAbstract); - _PredicateSwitch(p, instance, UsdPrimIsInstance); - _PredicateSwitch(p, master, Usd_PrimMasterFlag); - _PredicateSwitch(p, clips, Usd_PrimClipsFlag); - return p; -} - - -bool -GusdUSD_CustomTraverse::Opts::Configure(OP_Parameters& parms, fpreal t) -{ -#define _EVALTRI(NAME) \ - NAME = static_cast(parms.evalInt(#NAME, 0, t)); - - _EVALTRI(active); - _EVALTRI(visible); - _EVALTRI(imageable); - _EVALTRI(defined); - _EVALTRI(abstract); - _EVALTRI(model); - _EVALTRI(group); - _EVALTRI(instance); - _EVALTRI(master); - _EVALTRI(clips); - - - traverseMatched = parms.evalInt("traversematched", 0, t); - -#define _EVALSTR(NAME,VAR) parms.evalString(VAR, #NAME, 0, t); - - UT_String kindsStr, purposesStr, typesStr; - _EVALSTR(kinds, kindsStr); - _EVALSTR(purposes, purposesStr); - _EVALSTR(types, typesStr); - - std::string err; - if(!SetKindsByPattern(kindsStr, true, &err) || - !SetPurposesByPattern(purposesStr, true, &err) || - !SetTypesByPattern(typesStr, true, &err)) { - - parms.opLocalError(OP_ERR_ANYTHING, err.c_str()); - return false; - } - - UT_String namePatternStr, pathPatternStr; - _EVALSTR(namemask, namePatternStr); - _EVALSTR(pathmask, pathPatternStr); - - SetNamePattern(namePatternStr); - SetPathPattern(pathPatternStr); - - if(kinds.size() > 0 && model == FALSE_STATE) { - parms.opLocalError(OP_ERR_ANYTHING, - "Model kinds specified, but models " - "are being excluded. Matches are impossible."); - return false; - } - return true; -} - - -namespace { - -void -_BadPatternError(const char* type, - const char* pattern, - std::string* err=NULL) -{ - if(err) { - UT_WorkBuffer buf; - buf.sprintf("No %s matched pattern '%s'", type, pattern); - *err = buf.toStdString(); - } -} - - -void -_SetPattern(UT_StringMMPattern& patternObj, - const char* pattern, - bool caseSensitive) -{ - if(!UTisstring(pattern) || UT_String(pattern) == "*") { - patternObj.clear(); - } else { - patternObj.compile(pattern, caseSensitive); - } -} - - - -} /*namespace*/ - - -bool -GusdUSD_CustomTraverse::Opts::SetKindsByPattern( - const char* pattern, bool caseSensitive, std::string* err) -{ - if(!UTisstring(pattern) || UT_String(pattern) == "*") { - kinds.clear(); - return true; - } - GusdUSD_Utils::GetBaseModelKindsMatchingPattern( - pattern, kinds, caseSensitive); - if(kinds.size() == 0) { - _BadPatternError("model kinds", pattern, err); - return false; - } - return true; -} - - -bool -GusdUSD_CustomTraverse::Opts::SetPurposesByPattern( - const char* pattern, bool caseSensitive, std::string* err) -{ - if(!UTisstring(pattern) || UT_String(pattern) == "*") { - // Empty pattern means 'match everything' - purposes.clear(); - return true; - } - GusdUSD_Utils::GetPurposesMatchingPattern(pattern, purposes, caseSensitive); - if(purposes.size() == 0) { - _BadPatternError("purposes", pattern, err); - return false; - } - return true; -} - - -bool -GusdUSD_CustomTraverse::Opts::SetTypesByPattern( - const char* pattern, bool caseSensitive, std::string* err) -{ - if(!UTisstring(pattern) || UT_String(pattern) == "*") { - // Empty pattern means 'match everything' - types.clear(); - return true; - } - GusdUSD_Utils::GetBaseSchemaTypesMatchingPattern(pattern, types, - caseSensitive); - if(types.size() == 0) { - _BadPatternError("prim schema types", pattern, err); - return false; - } - return true; -} - - -void -GusdUSD_CustomTraverse::Opts::SetNamePattern( - const char* pattern, bool caseSensitive) -{ - _SetPattern(namePattern, pattern, caseSensitive); -} - - -void -GusdUSD_CustomTraverse::Opts::SetPathPattern( - const char* pattern, bool caseSensitive) -{ - _SetPattern(pathPattern, pattern, caseSensitive); -} - - -namespace { - - -struct _Visitor -{ - _Visitor(const GusdUSD_CustomTraverse::Opts& opts) - : _opts(opts), - _predicate(opts.MakePredicate()) {} - - Usd_PrimFlagsPredicate TraversalPredicate() const - { - // Need a predicate matching all prims. - return Usd_PrimFlagsPredicate::Tautology(); - } - - bool AcceptPrim(const UsdPrim& prim, - UsdTimeCode time, - GusdPurposeSet purposes, - GusdUSD_TraverseControl& ctl); - - bool AcceptType(const UsdPrim& prim) const; - - bool AcceptPurpose(const UsdGeomImageable& prim, - GusdUSD_TraverseControl& ctl); - - bool AcceptKind(const UsdPrim& prim) const; - - bool AcceptVis(const UsdGeomImageable& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl); - - bool AcceptNamePattern(const UsdPrim& prim) const; - - bool AcceptPathPattern(const UsdPrim& prim) const; - -private: - const GusdUSD_CustomTraverse::Opts& _opts; - const Usd_PrimFlagsPredicate _predicate; - TfToken _vis, _purpose; -}; - - -bool -_Visitor::AcceptPrim(const UsdPrim& prim, - UsdTimeCode time, - GusdPurposeSet purposes, - GusdUSD_TraverseControl& ctl) -{ - UsdGeomImageable ip(prim); - - bool visit = true; - - if(ARCH_UNLIKELY(!(bool)ip)) { - // Prim is not imageable - if(_opts.imageable == GusdUSD_CustomTraverse::TRUE_STATE) { - visit = false; - // will be inherited. - ctl.PruneChildren(); - } else if(_opts.purposes.size() > 0 || - _opts.visible == GusdUSD_CustomTraverse::TRUE_STATE) { - // Can only match prims that depend on imageable attributes - // Since this prim is not imageable, it can't possibly - // match our desired visibility or purpose. - visit = false; - } - } - // Always test purpose and visibility; that may allow us to prune traversal - // early, and is also necessary for propagation of inherited state. - visit = AcceptPurpose(ip, ctl) && visit; - visit = AcceptVis(ip, time, ctl) && visit; - - /* These tests are based on cached data; - check them before anything that requires attribute reads.*/ - visit = visit && _predicate(prim) && AcceptType(prim); - - visit = visit && AcceptKind(prim) - && AcceptNamePattern(prim) - && AcceptPathPattern(prim); - - if(visit && !_opts.traverseMatched) - ctl.PruneChildren(); - - return visit; -} - - -bool -_Visitor::AcceptType(const UsdPrim& prim) const -{ - if(_opts.types.size() == 0) - return true; - - const std::string& typeName = prim.GetTypeName().GetString(); - if(!typeName.empty()) { - /* TODO: profile this search. - It may be faster to fill an unordered set of type - names to do this test instead.*/ - TfType type = - PlugRegistry::FindDerivedTypeByName(typeName); - for(auto& t : _opts.types) { - if(type.IsA(t)) { - return true; - } - } - } - return false; -} - - -bool -_Visitor::AcceptPurpose(const UsdGeomImageable& prim, - GusdUSD_TraverseControl& ctl) -{ - if(_opts.purposes.size() == 0) - return true; - - if (!_purpose.IsEmpty()) { - // The root-most non-default purpose wins, so only query a new purpose - // if we haven't already found a non-default purpose during traversal. - if (_purpose == UsdGeomTokens->default_) { - TfToken purpose; - prim.GetPurposeAttr().Get(&purpose); - if (!purpose.IsEmpty()) { - _purpose = purpose; - } - } - } else { - _purpose = prim.ComputePurpose(); - } - for(auto& p : _opts.purposes) { - if(p == _purpose) { - return true; - } - } - if (_purpose != UsdGeomTokens->default_) { - // Purpose is a pruning operation; if a non-default purpose - // is found that doesn't match, we should not traverse further. - ctl.PruneChildren(); - } - return false; -} - - -bool -_Visitor::AcceptKind(const UsdPrim& prim) const -{ - if(_opts.kinds.size() == 0) - return true; - - UsdModelAPI model(prim); - TfToken kind; - model.GetKind(&kind); - for(auto& k : _opts.kinds) { - if(KindRegistry::IsA(kind, k)) - return true; - } - return false; -} - - -bool -_Visitor::AcceptVis(const UsdGeomImageable& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) -{ - if(_opts.visible == GusdUSD_CustomTraverse::ANY_STATE) - return true; - - if (!_vis.IsEmpty()) { - TfToken vis; - prim.GetVisibilityAttr().Get(&vis, time); - if (vis == UsdGeomTokens->invisible) { - _vis = vis; - } - } else { - _vis = prim.ComputeVisibility(time); - } - - if(_opts.visible == GusdUSD_CustomTraverse::TRUE_STATE) { - if (_vis == UsdGeomTokens->inherited) { - return true; - } - // Not visible. None of the children will be either, - // so no need to traverse any further. - ctl.PruneChildren(); - return false; - } else { // FALSE_STATE - return _vis == UsdGeomTokens->invisible; - } -} - - -bool -_Visitor::AcceptNamePattern(const UsdPrim& prim) const -{ - if(_opts.namePattern.isEmpty()) - return true; - return UT_String(prim.GetName().GetText()).multiMatch(_opts.namePattern); -} - - -bool -_Visitor::AcceptPathPattern(const UsdPrim& prim) const -{ - if(_opts.pathPattern.isEmpty()) - return true; - return UT_String(prim.GetPath().GetText()).multiMatch(_opts.pathPattern); -} - - -static GusdUSD_CustomTraverse::Opts _defaultOpts; - - -} /*namespaces*/ - - -bool -GusdUSD_CustomTraverse::FindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - bool skipRoot, - const GusdUSD_Traverse::Opts* opts) const -{ - const auto* customOpts = UTverify_cast(opts); - _Visitor visitor(customOpts ? *customOpts : _defaultOpts); - - return GusdUSD_ThreadedTraverse::ParallelFindPrims( - root, time, purposes, prims, visitor, skipRoot); -} - - -bool -GusdUSD_CustomTraverse::FindPrims( - const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot, - const GusdUSD_Traverse::Opts* opts) const -{ - const auto* customOpts = UTverify_cast(opts); - _Visitor visitor(customOpts ? *customOpts : _defaultOpts); - - return GusdUSD_ThreadedTraverse::ParallelFindPrims( - roots, times, purposes, prims, visitor, skipRoot); -} - - -namespace { - - -const PRM_Template* _CreateTemplates() -{ - static PRM_Default trueDef(GusdUSD_CustomTraverse::TRUE_STATE, ""); - static PRM_Default falseDef(GusdUSD_CustomTraverse::FALSE_STATE, ""); - static PRM_Default anyDef(GusdUSD_CustomTraverse::ANY_STATE, ""); - - static PRM_Name activeName("active", "Is Active"); - static PRM_Name visibleName("visible", "Is Visible"); - static PRM_Name imageableName("imageable", "Is Imageable"); - static PRM_Name definedName("defined", "Is Defined"); - static PRM_Name abstractName("abstract", "Is Abstract"); - static PRM_Name groupName("group", "Is Group"); - static PRM_Name modelName("model", "Is Model"); - static PRM_Name instanceName("instance", "Is Instance"); - static PRM_Name masterName("master", "Is Instance Master"); - static PRM_Name clipsName("clips", "Has Clips"); - - static PRM_Name stateNames[] = { - PRM_Name("true", "True"), - PRM_Name("false", "False"), - PRM_Name("any", "Ignore"), - PRM_Name() - }; - static PRM_ChoiceList stateMenu(PRM_CHOICELIST_SINGLE, stateNames); - - static PRM_Name nameMaskName("namemask", "Name Mask"); - static PRM_Name pathMaskName("pathmask", "Path Mask"); - - static PRM_Name traverseMatchedName("traversematched", "Traverse Matched"); - - static PRM_Name typesName("types", "Prim Types"); - static PRM_Name purposesName("purposes", "Purposes"); - static PRM_Name kindsName("kinds", "Kinds"); - -#define _STATETEMPLATE(name,def) \ - PRM_Template(PRM_ORD, 1, &name, &def, &stateMenu) - - GusdPRM_Shared shared; - - static PRM_Template templates[] = { - PRM_Template(PRM_STRING, 1, &typesName, - PRMzeroDefaults, &shared->typesMenu), - PRM_Template(PRM_STRING, 1, &purposesName, - PRMzeroDefaults, &shared->purposesMenu), - PRM_Template(PRM_STRING, 1, &kindsName, - PRMzeroDefaults, &shared->modelKindsMenu), - PRM_Template(PRM_STRING, 1, &nameMaskName, PRMzeroDefaults), - PRM_Template(PRM_STRING, 1, &pathMaskName, PRMzeroDefaults), - PRM_Template(PRM_TOGGLE, 1, &traverseMatchedName, PRMzeroDefaults), - - _STATETEMPLATE(activeName, trueDef), - _STATETEMPLATE(visibleName, trueDef), - _STATETEMPLATE(imageableName, trueDef), - _STATETEMPLATE(definedName, trueDef), - _STATETEMPLATE(abstractName, falseDef), - _STATETEMPLATE(groupName, anyDef), - _STATETEMPLATE(modelName, anyDef), - _STATETEMPLATE(instanceName, anyDef), - _STATETEMPLATE(masterName, anyDef), - _STATETEMPLATE(clipsName, anyDef), - PRM_Template() - }; - return templates; -} - -} /* namespace */ - -void -GusdUSD_CustomTraverse::Initialize() -{ - // Simply creating this object will register it with our traversal - // table. - static GusdUSD_TraverseType _type(new GusdUSD_CustomTraverse, - "std:custom", "Custom Traversal", _CreateTemplates(), - "Configurable traversal, allowing complex " - "discovery patterns."); -} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/USD_CustomTraverse.h b/third_party/houdini/gusd/USD_CustomTraverse.h deleted file mode 100644 index feba05bdf0..0000000000 --- a/third_party/houdini/gusd/USD_CustomTraverse.h +++ /dev/null @@ -1,112 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_CUSTOM_TRAVERSE_H -#define GUSD_USD_CUSTOM_TRAVERSE_H - -#include "pxr/pxr.h" - -#include "USD_Traverse.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/** A traversal implementation offering users full configuration - over many aspects of traversal.*/ -class GusdUSD_CustomTraverse : public GusdUSD_Traverse -{ -public: - enum TriState - { - TRUE_STATE, - FALSE_STATE, - ANY_STATE - }; - - struct Opts : public GusdUSD_Traverse::Opts - { - Opts() : GusdUSD_Traverse::Opts() {} - virtual ~Opts() {} - - virtual void Reset(); - virtual bool Configure(OP_Parameters& parms, fpreal t); - - /** Methods for matching components by wildcard pattern. - Note that for all methods, an empty pattern is treated - as equivalent to '*'. I.e., an empty pattern matches everything. - @{ */ - bool SetKindsByPattern(const char* pattern, - bool caseSensitive=true, - std::string* err=nullptr); - - bool SetPurposesByPattern(const char* pattern, - bool caseSensitive=true, - std::string* err=nullptr); - - bool SetTypesByPattern(const char* pattern, - bool caseSensitive=true, - std::string* err=nullptr); - - void SetNamePattern(const char* pattern, - bool caseSensitive=true); - - void SetPathPattern(const char* pattern, - bool caseSensitive=true); - /** @} */ - - /** Create a predicate matching all of the configurable - options that refer to prim flags.*/ - Usd_PrimFlagsPredicate MakePredicate() const; - - - TriState active, visible, imageable, defined, abstract, - model, group, instance, master, clips; - bool traverseMatched; - UT_Array purposes, kinds; - UT_Array types; - UT_StringMMPattern namePattern, pathPattern; - }; - - virtual Opts* CreateOpts() const { return new Opts; } - - virtual bool FindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - bool skipRoot=true, - const GusdUSD_Traverse::Opts* opts=nullptr) const; - - virtual bool FindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot=true, - const GusdUSD_Traverse::Opts* opts=nullptr) const; - - static void Initialize(); -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_CUSTOM_TRAVERSE_H*/ diff --git a/third_party/houdini/gusd/USD_DataCache.cpp b/third_party/houdini/gusd/USD_DataCache.cpp deleted file mode 100644 index 94e5e8e0ec..0000000000 --- a/third_party/houdini/gusd/USD_DataCache.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_DataCache.h" -#include "USD_PropertyMap.h" -#include "UT_Gf.h" - -#include "pxr/usd/usdGeom/xformable.h" - -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -GusdUSD_DataCache::GusdUSD_DataCache(GusdStageCache& cache) - : _stageCache(cache) -{ - cache.AddDataCache(*this); -} - - -GusdUSD_DataCache::GusdUSD_DataCache() - : GusdUSD_DataCache(GusdStageCache::GetInstance()) -{} - - -GusdUSD_DataCache::~GusdUSD_DataCache() -{ - _stageCache.RemoveDataCache(*this); -} - -bool -GusdUSD_DataCache::ShouldClearPrim( - const UsdPrim& prim, - const UT_StringSet& stagesToClear) -{ - if(!prim) { - // Always clear expired prims. - return true; - } - if (prim.GetStage()->GetRootLayer()->IsAnonymous()) - { - const std::string& path = - prim.GetStage()->GetRootLayer()->GetIdentifier(); - return stagesToClear.contains(path); - } - else - { - const std::string& path = - prim.GetStage()->GetRootLayer()->GetRealPath(); - return stagesToClear.contains(path); - } -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/USD_DataCache.h b/third_party/houdini/gusd/USD_DataCache.h deleted file mode 100644 index 2fb47779c1..0000000000 --- a/third_party/houdini/gusd/USD_DataCache.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_DATA_CACHE_H -#define GUSD_USD_DATA_CACHE_H - -#include "api.h" -#include "stageCache.h" - -#include "pxr/pxr.h" -#include "pxr/base/tf/token.h" - -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -#define GUSDUT_USDCACHE_NAME "USD Cache" - -class GusdStageCache; - - -class GUSD_API GusdUSD_DataCache -{ -public: - GusdUSD_DataCache(GusdStageCache& cache); - GusdUSD_DataCache(); - - virtual ~GusdUSD_DataCache(); - - /// Clear all caches. - virtual void Clear() {} - - /// Clear caches for a set of stages by path - virtual int64 Clear(const UT_StringSet& stagePaths) { return 0; } - - - /// Helper for implementations to decide if a cache entry - /// corresponding to @a prim should be discarded. - static bool ShouldClearPrim( - const UsdPrim& prim, - const UT_StringSet& stagesToClear); - -protected: - GusdStageCache& _stageCache; -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /*GUSD_USD_DATA_CACHE_H*/ diff --git a/third_party/houdini/gusd/USD_PropertyMap.h b/third_party/houdini/gusd/USD_PropertyMap.h deleted file mode 100644 index b62d2e92ea..0000000000 --- a/third_party/houdini/gusd/USD_PropertyMap.h +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_PROPERTY_MAP_H -#define GUSD_USD_PROPERTY_MAP_H - -#include -#include - -#include "pxr/pxr.h" -#include "pxr/usd/usd/object.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usd/stage.h" -#include "pxr/usd/usd/timeCode.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** TBB-style hash key for time-varying prim properties.*/ -struct GusdUSD_VaryingPropertyKey -{ - GusdUSD_VaryingPropertyKey() : hash(0) {} - - GusdUSD_VaryingPropertyKey(const UsdPrim& prim, UsdTimeCode time) - : prim(prim) - , time(time) - , hash(ComputeHash(prim, time)) {} - - static std::size_t ComputeHash(const UsdPrim& prim, UsdTimeCode time) - { - std::size_t h = SYShash(prim); - SYShashCombine(h, time); - return h; - } - - bool operator==(const GusdUSD_VaryingPropertyKey& o) const - { return prim == o.prim && time == o.time; } - - friend size_t hash_value(const GusdUSD_VaryingPropertyKey& o) - { return o.hash; } - - struct HashCmp - { - static std::size_t hash(const GusdUSD_VaryingPropertyKey& key) - { return key.hash; } - static bool equal(const GusdUSD_VaryingPropertyKey& a, - const GusdUSD_VaryingPropertyKey& b) - { return a == b; } - }; - - UsdPrim prim; - UsdTimeCode time; - std::size_t hash; -}; - - -/** Concurrent hash map for holding a time-varying property on a prim.*/ -template -class GusdUSD_VaryingPropertyMap - : public UT_ConcurrentHashMap -{ -public: - typedef GusdUSD_VaryingPropertyKey Key; - typedef GusdUSD_VaryingPropertyKey::HashCmp HashCmp; - typedef T value_type; - - GusdUSD_VaryingPropertyMap() : - UT_ConcurrentHashMap() {} -}; - - -/** TBB-style hash key for unvarying prim properties.*/ -struct GusdUSD_UnvaryingPropertyKey -{ - GusdUSD_UnvaryingPropertyKey() {} - - GusdUSD_UnvaryingPropertyKey(const UsdPrim& prim) - : prim(prim) {} - - static std::size_t ComputeHash(const UsdPrim& prim) - { return hash_value(prim); } - - bool operator==(const GusdUSD_UnvaryingPropertyKey& o) const - { return prim == o.prim; } - - friend size_t hash_value(const GusdUSD_UnvaryingPropertyKey& o) - { return SYShash(o.prim); } - - struct HashCmp - { - static std::size_t hash(const GusdUSD_UnvaryingPropertyKey& key) - { return SYShash(key.prim); } - static bool equal(const GusdUSD_UnvaryingPropertyKey& a, - const GusdUSD_UnvaryingPropertyKey& b) - { return a == b; } - }; - - UsdPrim prim; -}; - - -/** Concurrent hash map for holding an unvarying property of a prim.*/ -template -class GusdUSD_UnvaryingPropertyMap - : public UT_ConcurrentHashMap -{ -public: - typedef GusdUSD_UnvaryingPropertyKey Key; - typedef GusdUSD_UnvaryingPropertyKey::HashCmp HashCmp; - typedef T value_type; - - GusdUSD_UnvaryingPropertyMap() : - UT_ConcurrentHashMap() {} -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_PROPERTY_MAP_H*/ diff --git a/third_party/houdini/gusd/USD_StdTraverse.cpp b/third_party/houdini/gusd/USD_StdTraverse.cpp deleted file mode 100644 index 057bca3b07..0000000000 --- a/third_party/houdini/gusd/USD_StdTraverse.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_StdTraverse.h" - -#include "USD_Traverse.h" -#include "USD_TraverseSimple.h" - -#include "pxr/base/arch/hints.h" - -#include "pxr/usd/kind/registry.h" -#include "pxr/usd/usd/modelAPI.h" - -#include "pxr/usd/usdGeom/boundable.h" -#include "pxr/usd/usdGeom/gprim.h" -#include "pxr/usd/usdGeom/mesh.h" - -PXR_NAMESPACE_OPEN_SCOPE - -using GusdUSD_ThreadedTraverse::DefaultImageablePrimVisitorT; - -namespace GusdUSD_StdTraverse { - -namespace { - - -template -struct _VisitByTypeT -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) const - { - if(ARCH_UNLIKELY((bool)Type(prim))) { - ctl.PruneChildren(); - return true; - } - return false; - } -}; - - -typedef DefaultImageablePrimVisitorT< - _VisitByTypeT > _VisitImageableMeshes; -typedef DefaultImageablePrimVisitorT< - _VisitByTypeT > _VisitImageableGprims; -typedef DefaultImageablePrimVisitorT< - _VisitByTypeT > _VisitImageableBoundables; - - -struct _VisitBoundablesAndInstances -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) const - { - if(ARCH_UNLIKELY((bool)UsdGeomBoundable(prim) || - prim.IsInstance())) { - ctl.PruneChildren(); - return true; - } - return false; - } -}; - -typedef DefaultImageablePrimVisitorT< - _VisitBoundablesAndInstances,true> _VisitImageableBoundablesAndInstances; - -struct _VisitModels -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) - { - if(ARCH_UNLIKELY(prim.IsModel())) { - UsdModelAPI model(prim); - if(model) { - TfToken kind; - model.GetKind(&kind); - if(KindRegistry::IsA(kind, KindTokens->component)) { - // No models can appear beneath components. - ctl.PruneChildren(); - } - } - return true; - } - return false; - } -}; - - -typedef DefaultImageablePrimVisitorT< - _VisitModels,true> _RecursiveVisitImageableModels; - - -struct _VisitNonGroupModels -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) - { - if(ARCH_UNLIKELY(prim.IsModel() && !prim.IsGroup())) { - ctl.PruneChildren(); - return true; - } - return false; - } -}; - -typedef DefaultImageablePrimVisitorT<_VisitNonGroupModels> _VisitImageableModels; - - -struct _VisitGroups -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) - { - if(ARCH_UNLIKELY(prim.IsGroup())) { - ctl.PruneChildren(); - return true; - } - return false; - } -}; - -typedef DefaultImageablePrimVisitorT<_VisitGroups> _VisitImageableGroups; - - -struct _VisitComponentsAndBoundables -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) - { - - if(ARCH_UNLIKELY(prim.IsA())) { - ctl.PruneChildren(); - return true; - } - UsdModelAPI model(prim); - if(ARCH_UNLIKELY((bool)model)) { - TfToken kind; - model.GetKind(&kind); - if( ARCH_UNLIKELY( - KindRegistry::IsA(kind, KindTokens->component) || - KindRegistry::IsA(kind, KindTokens->subcomponent))) { - ctl.PruneChildren(); - return true; - } - } - return false; - } -}; - - -typedef DefaultImageablePrimVisitorT< - _VisitComponentsAndBoundables > _VisitImageableComponentsAndBoundables; - - -template -struct _VisitByKindT -{ - bool operator()(const UsdPrim& prim, - UsdTimeCode time, - GusdUSD_TraverseControl& ctl) - { - UsdModelAPI model(prim); - if(ARCH_UNLIKELY((bool)model)) { - TfToken kind; - model.GetKind(&kind); - if(ARCH_UNLIKELY(MatchKind()(kind))) { - ctl.PruneChildren(); - return true; - } - } - return false; - } -}; - -struct _MatchComponents -{ - bool operator()(const TfToken& kind) const - { - return KindRegistry::IsA(kind, KindTokens->component) || - KindRegistry::IsA(kind, KindTokens->subcomponent); - } -}; - -struct _MatchAssemblies -{ - bool operator()(const TfToken& kind) const - { - return KindRegistry::IsA(kind, KindTokens->assembly); - } -}; - - - - -typedef DefaultImageablePrimVisitorT< - _VisitByKindT<_MatchComponents> > _VisitImageableComponents; - -typedef DefaultImageablePrimVisitorT< - _VisitByKindT<_MatchAssemblies> > _VisitImageableAssemblies; - - -} /*namespace*/ - - -#define _DECLARE_STATIC_TRAVERSAL(name,visitor) \ - const GusdUSD_Traverse& name() \ - { \ - static visitor v; \ - static GusdUSD_TraverseSimpleT t(v); \ - return t; \ - } - - -_DECLARE_STATIC_TRAVERSAL(GetComponentTraversal, _VisitImageableComponents); -_DECLARE_STATIC_TRAVERSAL(GetComponentAndBoundableTraversal,_VisitImageableComponentsAndBoundables); -_DECLARE_STATIC_TRAVERSAL(GetAssemblyTraversal, _VisitImageableAssemblies); -_DECLARE_STATIC_TRAVERSAL(GetModelTraversal, _VisitImageableModels); -_DECLARE_STATIC_TRAVERSAL(GetGroupTraversal, _VisitImageableGroups); -_DECLARE_STATIC_TRAVERSAL(GetBoundableTraversal, _VisitImageableBoundables); -_DECLARE_STATIC_TRAVERSAL(GetGprimTraversal, _VisitImageableGprims); -_DECLARE_STATIC_TRAVERSAL(GetMeshTraversal, _VisitImageableMeshes); - -_DECLARE_STATIC_TRAVERSAL(GetRecursiveModelTraversal, _RecursiveVisitImageableModels); - -namespace { - -GusdUSD_TraverseType stdTypes[] = { - GusdUSD_TraverseType(&GetComponentAndBoundableTraversal(), "std:components", - "Components", NULL, - "Returns default-imageable models with a " - "component-derived kind."), - GusdUSD_TraverseType(&GetGroupTraversal(), "std:groups", - "Groups", NULL, - "Returns default-imageable groups (of any kind)."), - GusdUSD_TraverseType(&GetBoundableTraversal(), "std:boundables", - "Gprims", NULL, - "Return leaf geometry primitives, instances, and procedurals."), -}; - - -} /*namespace*/ - -} /*namespace GusdUSD_StdTraverse */ - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/USD_StdTraverse.h b/third_party/houdini/gusd/USD_StdTraverse.h deleted file mode 100644 index aa55b0cc5c..0000000000 --- a/third_party/houdini/gusd/USD_StdTraverse.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief Standard traversal algos. -*/ -#ifndef GUSD_USD_STD_TRAVERSE_H -#define GUSD_USD_STD_TRAVERSE_H - -#include "pxr/pxr.h" - -#include "USD_Traverse.h" - -PXR_NAMESPACE_OPEN_SCOPE - -namespace GusdUSD_StdTraverse -{ - - -/** Core prim traversal. - These traverse only default-imageable prims. This does not account for - visibility which, for performance reasons, is expected to occur as - a post-traversal operation. - - None of the traversals return nested matches. - @{ */ -const GusdUSD_Traverse& GetComponentTraversal(); - -const GusdUSD_Traverse& GetComponentAndBoundableTraversal(); - -const GusdUSD_Traverse& GetAssemblyTraversal(); - -const GusdUSD_Traverse& GetModelTraversal(); - -const GusdUSD_Traverse& GetGroupTraversal(); - -const GusdUSD_Traverse& GetBoundableTraversal(); - -const GusdUSD_Traverse& GetGprimTraversal(); - -const GusdUSD_Traverse& GetMeshTraversal(); -/** @} */ - -/** Recursive model traversal, returning all nested models. - This is primarily provided for UI menus.*/ -const GusdUSD_Traverse& GetRecursiveModelTraversal(); - - -/** Register core traversals.*/ -void Register(); - - -} /*namespace GusdUSD_StdTraverse*/ - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_STD_TRAVERSE_H*/ diff --git a/third_party/houdini/gusd/USD_ThreadedTraverse.cpp b/third_party/houdini/gusd/USD_ThreadedTraverse.cpp deleted file mode 100644 index 01bc7a1280..0000000000 --- a/third_party/houdini/gusd/USD_ThreadedTraverse.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_ThreadedTraverse.h" - - -PXR_NAMESPACE_OPEN_SCOPE - - -namespace GusdUSD_ThreadedTraverse { - - -TaskData::~TaskData() -{ - for(auto it = threadData.begin(); it != threadData.end(); ++it) { - if(auto* tdata = it.get()) - delete tdata; - } -} - - -bool -TaskData::GatherPrimsFromThreads( - UT_Array& prims) -{ - prims.clear(); - - /* Compute the full prim count & pre-allocate space.*/ - exint nPrims = 0; - for(auto it = threadData.begin(); it != threadData.end(); ++it) { - if(const auto* tdata = it.get()) - nPrims += tdata->prims.size(); - } - prims.setCapacity(nPrims); - - /* Concat the per-thread arrays.*/ - for(auto it = threadData.begin(); it != threadData.end(); ++it) { - if(const auto* tdata = it.get()) - prims.concat(tdata->prims); - } - - /* The ordering of prims coming directly from different threads - will be non-deterministic. Sort them to make our results deterministic.*/ - UTparallelStableSort< - UT_Array::iterator>( - prims.begin(), prims.end(), - [](const GusdUSD_Traverse::PrimIndexPair& lhs, - const GusdUSD_Traverse::PrimIndexPair& rhs) - { - return lhs.second < rhs.second || - (lhs.second == rhs.second && - lhs.first.GetPath() < rhs.first.GetPath()); - }); - return !UTgetInterrupt()->opInterrupt(); -} - - -bool -TaskData::GatherPrimsFromThreads(UT_Array& prims) -{ - prims.clear(); - - /* Compute the full prim count */ - exint nPrims = 0; - for(auto it = threadData.begin(); it != threadData.end(); ++it) { - if(const auto* tdata = it.get()) - nPrims += tdata->prims.size(); - } - - /* Pre-allocate all the space we need */ - prims.setCapacity(nPrims); - - /* Concat the per-thread arrays.*/ - for(auto it = threadData.begin(); it != threadData.end(); ++it) { - if(const auto* tdata = it.get()) { - /* Entries are stored in threads as (prim,index) pairs, - so need to pull the prims separately.*/ - exint start = prims.size(); - exint count = tdata->prims.size(); - prims.setSize(start + count); - for(exint i = 0; i < count; ++i) - prims(start + i) = tdata->prims(i).first; - } - } - - /* The ordering of prims coming directly from different threads - will be non-deterministic. Sort them to make our results deterministic.*/ - return GusdUSD_Utils::SortPrims(prims); -} - - -} /*namespace GusdUSD_ThreadedTraverse*/ - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/USD_ThreadedTraverse.h b/third_party/houdini/gusd/USD_ThreadedTraverse.h deleted file mode 100644 index ffaa420ad4..0000000000 --- a/third_party/houdini/gusd/USD_ThreadedTraverse.h +++ /dev/null @@ -1,313 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_THREADED_TRAVERSE_H -#define GUSD_USD_THREADED_TRAVERSE_H - - -#include -#include -#include -#include -#include - -#include "UT_Assert.h" -#include "USD_Traverse.h" -#include "USD_Utils.h" - -#include "pxr/pxr.h" -#include "pxr/base/arch/hints.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usdGeom/imageable.h" - -PXR_NAMESPACE_OPEN_SCOPE - -namespace GusdUSD_ThreadedTraverse { - - -template -bool ParallelFindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - const Visitor& visitor, - bool skipRoot=true); - -template -bool ParallelFindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - const Visitor& visitor, - bool skipRoot=true); - - -/** Visitor for default-imageable prims. - This takes @a Visitor as a child visitor to exec on each - default-imageable prim.*/ -template -struct DefaultImageablePrimVisitorT -{ - bool AcceptPrim(const UsdPrim& prim, - UsdTimeCode time, - GusdPurposeSet purposes, - GusdUSD_TraverseControl& ctl) const; - - Usd_PrimFlagsPredicate TraversalPredicate() const - { return UsdTraverseInstanceProxies(UsdPrimIsActive && UsdPrimIsDefined && - UsdPrimIsLoaded && !UsdPrimIsAbstract); } -}; - - -template -bool -DefaultImageablePrimVisitorT::AcceptPrim( - const UsdPrim& prim, - UsdTimeCode time, - GusdPurposeSet purposes, - GusdUSD_TraverseControl& ctl) const -{ - UsdGeomImageable ip(prim); - if(ip) { - TfToken purpose; - ip.GetPurposeAttr().Get(&purpose); - if( GusdPurposeInSet( purpose, purposes )) { - if(ARCH_UNLIKELY(Visitor()(prim, time, ctl))) { - if(!Recursive) - ctl.PruneChildren(); - return true; - } - } else { - ctl.PruneChildren(); - } - } else { - ctl.PruneChildren(); - } - return false; -} - - -struct TaskThreadData -{ - UT_Array prims; -}; - -typedef UT_ThreadSpecificValue TaskThreadDataTLS; - - -struct TaskData -{ - ~TaskData(); - - TaskThreadDataTLS threadData; - - /** Collect all of the prims from the numerous threads. - The resulting prims are sorted (for determinism) */ - bool GatherPrimsFromThreads(UT_Array& prims); - - bool GatherPrimsFromThreads( - UT_Array& prims); -}; - - -/** Task for traversing a prim tree in parallel. - - See DefaultImageablePrimVisitorT<> for an example of the structure - expected for visitors. */ -template -struct TraverseTaskT : public UT_Task -{ - TraverseTaskT(const UsdPrim& prim, exint idx, UsdTimeCode time, - GusdPurposeSet purposes, - TaskData& data, const Visitor& visitor, bool skipPrim) - : UT_Task(), _prim(prim), _idx(idx), _time(time), - _purposes(purposes), _data(data), - _visited(false), _visitor(visitor), _skipPrim(skipPrim) {} - - virtual UT_Task* run(); - -private: - UsdPrim _prim; - exint _idx; - UsdTimeCode _time; - GusdPurposeSet _purposes; - TaskData& _data; - bool _visited; - Visitor _visitor; - bool _skipPrim; -}; - - -/** XXX: This parallel recursion pattern follows the - 'Recycling Parent as Continuation' pattern from - TBB's 'Catalog of Recommend task Patterns' */ -template -UT_Task* -TraverseTaskT::run() -{ - /* XXX: Ended up needing this check at some point. - Find out if it's still necessary.*/ - if(ARCH_UNLIKELY(_visited)) return NULL; - _visited = true; - - UT_ASSERT_P(_prim); - - if(!_skipPrim) { - - GusdUSD_TraverseControl ctl; - if(ARCH_UNLIKELY(_visitor.AcceptPrim(_prim, _time, _purposes, ctl))) { - /* Matched. Add it to the thread-specific list.*/ - auto*& threadData = _data.threadData.get(); - if(!threadData) - threadData = new TaskThreadData; - threadData->prims.append( - GusdUSD_Traverse::PrimIndexPair(_prim, _idx)); - } - if(ARCH_UNLIKELY(!ctl.GetVisitChildren())) { - return NULL; - } - } - - /* Count the children so we can increment the ref count accordingly.*/ - int count = 0; - auto children = _prim.GetFilteredChildren(_visitor.TraversalPredicate()); - for (auto i = children.begin(); i != children.end(); ++i, ++count) {} - - if(count == 0) - return NULL; - - setRefCount(count); - recycleAsContinuation(); - - const int last = count - 1; - int idx = 0; - for (const auto& child : - _prim.GetFilteredChildren(_visitor.TraversalPredicate())) { - auto& task = - *new(allocate_child()) TraverseTaskT(child, _idx, _time, - _purposes, _data, - _visitor, /*skip prim*/ false); - if(idx == last) - return &task; - else - spawnChild(task); - ++idx; - } - return NULL; -} - - -template -bool -ParallelFindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - const Visitor& visitor, - bool skipRoot) -{ - TaskData data; - bool skipPrim = skipRoot || root.GetPath() == SdfPath::AbsoluteRootPath(); - auto& task = - *new(UT_Task::allocate_root()) - TraverseTaskT(root, -1, time, purposes, - data, visitor, skipPrim); - UT_Task::spawnRootAndWait(task); - - if(UTgetInterrupt()->opInterrupt()) - return false; - - return data.GatherPrimsFromThreads(prims); -} - - -template -struct RunTasksT -{ - RunTasksT(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - const Visitor& visitor, TaskData& data, bool skipRoot) - : _roots(roots), _times(times), _purposes(purposes), - _visitor(visitor), _data(data), _skipRoot(skipRoot) {} - - void operator()(const UT_BlockedRange& r) const - { - auto* boss = GusdUTverify_ptr(UTgetInterrupt()); - - for(std::size_t i = r.begin(); i < r.end(); ++i) - { - if(boss->opInterrupt()) - return; - - if(const UsdPrim& prim = _roots(i)) { - bool skipPrim = _skipRoot || - prim.GetPath() == SdfPath::AbsoluteRootPath(); - - auto& task = - *new(UT_Task::allocate_root()) - TraverseTaskT(prim, i, _times(i), - _purposes(i), _data, - _visitor, skipPrim); - UT_Task::spawnRootAndWait(task); - } - } - } - -private: - const UT_Array& _roots; - const GusdDefaultArray& _times; - const GusdDefaultArray& _purposes; - const Visitor& _visitor; - TaskData& _data; - const bool _skipRoot; -}; - - - - -template -bool -ParallelFindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - const Visitor& visitor, - bool skipRoot) -{ - TaskData data; - UTparallelFor(UT_BlockedRange(0, roots.size()), - RunTasksT(roots, times, purposes, - visitor, data, skipRoot)); - if(UTgetInterrupt()->opInterrupt()) - return false; - - return data.GatherPrimsFromThreads(prims); -} - - -} /*namespace GusdUSD_ThreadedTraverse*/ - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_THREADED_TRAVERSE_H*/ diff --git a/third_party/houdini/gusd/USD_Traverse.cpp b/third_party/houdini/gusd/USD_Traverse.cpp deleted file mode 100644 index 4bd9e6ab26..0000000000 --- a/third_party/houdini/gusd/USD_Traverse.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_Traverse.h" -#include "UT_Assert.h" - -PXR_NAMESPACE_OPEN_SCOPE - -bool -GusdUSD_Traverse::FindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot, - const Opts* opts) const -{ - UT_Array primIndexPairs; - if(!FindPrims(roots, times, purposes, primIndexPairs, skipRoot, opts)) - return false; - prims.setSize(primIndexPairs.size()); - for(exint i = 0; i < prims.size(); ++i) - prims(i) = primIndexPairs(i).first; - return true; -} - - -GusdUSD_TraverseType::GusdUSD_TraverseType(const GusdUSD_Traverse* traversal, - const char* name, - const char* label, - const PRM_Template* templates, - const char* help) - : _traversal(traversal), _name(name, label), - _templates(templates), _help(help, 1) -{ - UT_ASSERT(traversal); - GusdUSD_TraverseTable::GetInstance().Register(this); -} - - -GusdUSD_TraverseTable& -GusdUSD_TraverseTable::GetInstance() -{ - static GusdUSD_TraverseTable table; - return table; -} - - -void -GusdUSD_TraverseTable::Register(const GusdUSD_TraverseType* type) -{ - UT_ASSERT(type); - const char* name = GusdUTverify_ptr(type->GetName().getToken()); - _map[UT_StringHolder(UT_StringHolder::REFERENCE,name)] = type; -} - - -const GusdUSD_TraverseType* -GusdUSD_TraverseTable::Find(const char* name) const -{ - auto it = _map.find(UT_StringHolder(UT_StringHolder::REFERENCE,name)); - return it == _map.end() ? NULL : it->second; -} - - -const GusdUSD_Traverse* -GusdUSD_TraverseTable::FindTraversal(const char* name) const -{ - if(const auto* type = Find(name)) - return &(**type); - return NULL; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/USD_Traverse.h b/third_party/houdini/gusd/USD_Traverse.h deleted file mode 100644 index bc1100f47a..0000000000 --- a/third_party/houdini/gusd/USD_Traverse.h +++ /dev/null @@ -1,187 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief Methods for USD scene traversal. -*/ -#ifndef GUSD_USD_TRAVERSE_H -#define GUSD_USD_TRAVERSE_H - - -#include -#include -#include -#include -#include -#include - -#include "api.h" -#include "defaultArray.h" -#include "purpose.h" -#include "USD_Utils.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usd/prim.h" - - -class OP_Parameters; -class PRM_Template; - -PXR_NAMESPACE_OPEN_SCOPE - -/** Base class for custom stage traversal. - - To register traversals, define a static GusdUSD_TraverseType singleton - that takes an instance of the traverse object. */ -class GusdUSD_Traverse -{ -public: - struct Opts; - typedef std::pair PrimIndexPair; - - virtual ~GusdUSD_Traverse() {} - - virtual Opts* CreateOpts() const { return nullptr; } - - /** Find prims beneath the given root.*/ - virtual bool FindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - bool skipRoot=true, - const Opts* opts=nullptr) const = 0; - - /** Find prims beneath the given root prims. - Note that the input array of prims may contain invalid prims. - The returned @a prims array holds the new prims, and the index - of their root prim from the @a roots array. The array is sorted - by the index and the prim path.*/ - virtual bool FindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot=true, - const Opts* opts=nullptr) const = 0; - - bool FindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot=true, - const Opts* opts=nullptr) const; - - /** Base class that can be derived to provide - configuration options to the traversal.*/ - struct Opts - { - Opts() { Reset(); } - virtual ~Opts() {} - - /** Reset options back to defaults.*/ - virtual void Reset() {} - - virtual bool Configure(OP_Parameters& parms, fpreal t) = 0; - }; - -}; - - -class GusdUSD_TraverseType -{ -public: - GusdUSD_TraverseType(const GusdUSD_Traverse* traversal, - const char* name, - const char* label, - const PRM_Template* templates=nullptr, - const char* help=nullptr); - - const PRM_Name& GetName() const { return _name; } - const PRM_Template* GetTemplates() const { return _templates; } - const char* GetHelp() const { return _help; } - - const GusdUSD_Traverse& operator*() const { return *_traversal; } - const GusdUSD_Traverse* operator->() const { return _traversal; } - -private: - const GusdUSD_Traverse* const _traversal; - const PRM_Name _name; - const PRM_Template* const _templates; - const UT_String _help; -}; - - -/** Helper to provide control over traversal through children.*/ -struct GusdUSD_TraverseControl -{ - GusdUSD_TraverseControl() : _visitChildren(true) {} - - bool GetVisitChildren() const { return _visitChildren; } - void SetVisitChildren(bool tf) { _visitChildren = tf; } - void PruneChildren() { SetVisitChildren(false); } - -private: - bool _visitChildren; -}; - - -/** Table for registering custom stage traversals. */ -class GusdUSD_TraverseTable : UT_NonCopyable -{ -public: - typedef UT_StringMap Map; - typedef Map::const_iterator const_iterator; - typedef Map::iterator iterator; - - GUSD_API - static GusdUSD_TraverseTable& GetInstance(); - - GUSD_API - void Register(const GusdUSD_TraverseType* type); - - GUSD_API - const GusdUSD_TraverseType* Find(const char* name) const; - - GUSD_API - const GusdUSD_Traverse* FindTraversal(const char* name) const; - - const char* GetDefault() const - { return _default; } - - void SetDefault(const char* name) - { _default.harden(name); } - - iterator begin() { return _map.begin(); } - const_iterator begin() const { return _map.begin(); } - - iterator end() { return _map.end(); } - const_iterator end() const { return _map.end(); } - -private: - Map _map; - UT_String _default; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_TRAVERSE_H*/ diff --git a/third_party/houdini/gusd/USD_TraverseSimple.h b/third_party/houdini/gusd/USD_TraverseSimple.h deleted file mode 100644 index 92f9b4b0ea..0000000000 --- a/third_party/houdini/gusd/USD_TraverseSimple.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_TRAVERSE_SIMPLE_H -#define GUSD_USD_TRAVERSE_SIMPLE_H - -#include "pxr/pxr.h" - -#include "defaultArray.h" -#include "USD_Traverse.h" -#include "USD_ThreadedTraverse.h" - - -PXR_NAMESPACE_OPEN_SCOPE - -/** Templated class for declaring simple, threaded traversals. - See GusdUSD_ThreadedTraverse::VisiblePrimVisitorT for an - example of the structure expected for visitors.*/ -template -class GusdUSD_TraverseSimpleT : public GusdUSD_Traverse -{ -public: - GusdUSD_TraverseSimpleT(const Visitor& visitor) - : GusdUSD_Traverse(), _visitor(visitor) {} - - virtual ~GusdUSD_TraverseSimpleT() {} - - virtual bool FindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - bool skipRoot=true, - const Opts* opts=NULL) const; - - virtual bool FindPrims(const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot=true, - const Opts* opts=NULL) const; - -private: - const Visitor& _visitor; -}; - - -template -bool -GusdUSD_TraverseSimpleT::FindPrims(const UsdPrim& root, - UsdTimeCode time, - GusdPurposeSet purposes, - UT_Array& prims, - bool skipRoot, - const Opts* opts) const -{ - return GusdUSD_ThreadedTraverse::ParallelFindPrims( - root, time, purposes, prims, _visitor, skipRoot); -} - - -template -bool -GusdUSD_TraverseSimpleT::FindPrims( - const UT_Array& roots, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - UT_Array& prims, - bool skipRoot, - const Opts* opts) const -{ - return GusdUSD_ThreadedTraverse::ParallelFindPrims( - roots, times, purposes, prims, _visitor, skipRoot); -} - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_TRAVERSE_SIMPLE_H*/ diff --git a/third_party/houdini/gusd/USD_Utils.cpp b/third_party/houdini/gusd/USD_Utils.cpp deleted file mode 100644 index 6a87934024..0000000000 --- a/third_party/houdini/gusd/USD_Utils.cpp +++ /dev/null @@ -1,1011 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_Utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pxr/base/tf/type.h" -#include "pxr/usd/kind/registry.h" -#include "pxr/usd/sdf/path.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usd/variantSets.h" -#include "pxr/usd/usdGeom/imageable.h" -#include "pxr/usd/usdGeom/tokens.h" - -PXR_NAMESPACE_OPEN_SCOPE - -namespace GusdUSD_Utils { - - -UT_StringHolder -TokenToStringHolder(const TfToken& token) -{ - if (token.IsImmortal()) { - return !token.IsEmpty() ? - UT_StringHolder(UT_StringHolder::REFERENCE, token.GetString()) - : UT_StringHolder(); - } else { - return UT_StringHolder(token.GetString()); - } -} - - -bool -CreateSdfPath(const UT_StringRef& pathStr, - SdfPath& path, UT_ErrorSeverity sev) -{ - if(!pathStr) - return true; - - /* XXX: Paths require parsing which, when dealing with many - thousands of prims, can be expensive to continually - recompute. To speed things up, cache the conversions. - We only cache valid conversions so that we don't have to - worry about also caching error messages.*/ - - typedef UT_ConcurrentHashMap PathMap; - static PathMap map; - - { - PathMap::const_accessor a; - if(map.find(a, UTmakeUnsafeRef(pathStr))) { - path = a->second; - return true; - } - } - - std::string str(pathStr.toStdString()); - - /* TODO: using 'IsValidPathString()' requires us to parse the - path a second time. It would be better to parse a single - time, and capture any warnings produced while parsing. - This is not currently possible because Tf warnings can't - be captured with TfMark. See BUG: 127366 */ - if(sev > UT_ERROR_NONE) { - std::string errStr; - if(!SdfPath::IsValidPathString(str, &errStr)) { - GUSD_GENERIC_ERR(sev).Msg("Failed parsing path '%s': %s", - pathStr.c_str(), errStr.c_str()); - } - } else { - if(!SdfPath::IsValidPathString(str)) - return false; - } - - PathMap::accessor a; - if(map.insert(a, pathStr)) - a->second = SdfPath(str); - path = a->second; - return true; -} - - -const SdfPath& -GetDefaultPrimIdentifier() -{ - static const SdfPath path("defaultPrim"); - return path; -} - - -UsdPrim -GetPrimFromStage(const UsdStagePtr& stage, - const SdfPath& path, - UT_ErrorSeverity sev) -{ - UT_ASSERT_P(stage); - - if (!path.IsEmpty()) { - UsdPrim prim = stage->GetPrimAtPath(path); - if (!prim) { - // Check if we wanted the default prim. - if (path == GetDefaultPrimIdentifier()) { - prim = stage->GetDefaultPrim(); - if (!prim) { - GUSD_GENERIC_ERR(sev).Msg( - "Could not retrieve a valid defaultPrim from " - "stage @%s@.", - stage->GetRootLayer()->GetIdentifier().c_str()); - } - } else { - GUSD_GENERIC_ERR(sev).Msg( - "Prim '%s' not found in stage @%s@.", - path.GetText(), - stage->GetRootLayer()->GetIdentifier().c_str()); - } - } - return prim; - } - // Get an empty prim for an empty path (not an error!) - return UsdPrim(); -} - - -bool -GetPrimAndVariantPathsFromPathList( - const char* str, - UT_Array& primPaths, - UT_Array& variants, - UT_ErrorSeverity sev) -{ - UT_WorkArgs args; - UT_String tokenStr(str); - tokenStr.tokenize(args); - - primPaths.setCapacity(args.entries()); - variants.setCapacity(args.entries()); - for(exint i = 0; i < args.entries(); ++i) { - UT_String arg(args(i)); - if(arg.isstring()) { - SdfPath path; - if(CreateSdfPath(arg, path, sev)) { - SdfPath primPath, variantsPath; - ExtractPrimPathAndVariants(path, primPath, variantsPath); - primPaths.append(primPath); - variants.append(variantsPath); - } else { - return false; - } - } - } - return true; -} - - -void -ExtractPrimPathAndVariants(const SdfPath& path, - SdfPath& primPath, SdfPath& variants) -{ - if(path.IsAbsolutePath()) { - primPath = path.StripAllVariantSelections(); - if(primPath != path) { - // Path differs, so the input had variants. - // The variants path might be pointing at a sub-path - // like /some{a=b}path. Strip off the trailing elements - // so that the variants path doesn't include any unnecessary - // trailing elements. This is done in part because, in some - /// contexts, the path will become a cache key. - for(variants = path; (!variants.IsPrimVariantSelectionPath() && - !variants.IsEmpty()); - variants = variants.GetParentPath()) { - - UT_ASSERT_P(!variants.IsEmpty()); - } - } else { - variants = SdfPath(); - } - } else { - if (path == GetDefaultPrimIdentifier()) { - primPath = path; - } else { - primPath = SdfPath(); - } - variants = SdfPath(); - } -} - -void -SetModelingVariant( - const UsdStageRefPtr& stage, - const UsdPrim& prim, - const TfToken& variant) -{ - if (prim) { - UsdVariantSets variantSets = prim.GetVariantSets(); - if (variantSets.HasVariantSet(kModelingVariantToken)) { - UsdVariantSet modelingVariantSet = - prim.GetVariantSet(kModelingVariantToken); - if (modelingVariantSet.HasAuthoredVariant(variant)) { - modelingVariantSet.SetVariantSelection(variant); - } - } - } -} - -void -ClearModelingVariant(const UsdStageRefPtr& stage, const UsdPrim& prim) -{ - if (prim) { - UsdVariantSets variantSets = prim.GetVariantSets(); - if (variantSets.HasVariantSet(kModelingVariantToken)) { - UsdVariantSet modelingVariantSet = - prim.GetVariantSet(kModelingVariantToken); - if (modelingVariantSet.HasAuthoredVariantSelection()) { - modelingVariantSet.ClearVariantSelection(); - } - } - } -} - -bool -SortPrims(UT_Array& prims) -{ - UTparallelStableSort::iterator>( - prims.begin(), prims.end(), - [](const UsdPrim& a, const UsdPrim& b) - { return a.GetPath() < b.GetPath(); }); - return !UTgetInterrupt()->opInterrupt(); -} - - -namespace { - - -struct _Pattern -{ - _Pattern(const char* pattern, bool caseSensitive) - { _pattern.compile(pattern, caseSensitive); } - - bool Match(const std::string& str) const - { return UT_String(str.c_str()).multiMatch(_pattern); } - bool Match(const TfToken& str) const - { return Match(str.GetString()); } -private: - UT_StringMMPattern _pattern; -}; - - -void _GetSchemaTypesMatchingPattern(TfType type, - const _Pattern& pattern, - UT_Array& types) -{ - if(pattern.Match(type.GetTypeName())) { - types.append(type); - } else { - for(auto& derived : type.GetDirectlyDerivedTypes()) { - _GetSchemaTypesMatchingPattern(derived, pattern, types); - } - } -} - - -void _GetModelKindsMatchingPattern(const KindNode* kind, - const _Pattern& pattern, - UT_Array& kinds) -{ - if(pattern.Match(kind->kind)) { - kinds.append(kind->kind); - } else { - for(auto& derived : kind->children) { - _GetModelKindsMatchingPattern(derived.get(), pattern, kinds); - } - } -} - - -} /*namespace*/ - - -void -GetBaseSchemaTypesMatchingPattern(const char* pattern, - UT_Array& types, - bool caseSensitive) -{ - types.clear(); - if(!UTisstring(pattern)) - return; - - TfType base = TfType::Find(); - UT_ASSERT(!base.IsUnknown()); - _GetSchemaTypesMatchingPattern( - base, _Pattern(pattern, caseSensitive), types); -} - - -void -GetBaseModelKindsMatchingPattern(const char* pattern, - UT_Array& kinds, - bool caseSensitive) -{ - kinds.clear(); - if(!UTisstring(pattern)) - return; - - _GetModelKindsMatchingPattern(&GetModelKindHierarchy(), - _Pattern(pattern, caseSensitive), kinds); -} - - -void -GetPurposesMatchingPattern(const char* pattern, - UT_Array& purposes, - bool caseSensitive) -{ - purposes.clear(); - if(!UTisstring(pattern)) - return; - - _Pattern pat(pattern, caseSensitive); - for(const auto& purpose : UsdGeomImageable::GetOrderedPurposeTokens()) { - if(pat.Match(purpose)) - purposes.append(purpose); - } -} - - -namespace { - -KindNode _BuildModelKindHierarchy() -{ - static KindNode root; - - UT_Map kindMap; - - // Create nodes for all kinds. - for(const auto& kind : KindRegistry::GetAllKinds()) { - KindNode::RefPtr node(new KindNode); - node->kind = kind; - kindMap[kind] = node; - } - - // Map nodes onto the child map of their parent (base kind) - for(auto& pair : kindMap) { - auto baseKind = KindRegistry::GetBaseKind(pair.first); - KindNode* parent = baseKind.IsEmpty() ? &root : kindMap[baseKind].get(); - parent->children.append(pair.second); - } - - // Sort all of the children. - for(auto& pair : kindMap) { - pair.second->children.stdsort( - [](const KindNode::RefPtr& a, const KindNode::RefPtr& b) - { return a->kind < b->kind; }); - } - root.kind = TfToken(); - - return root; -} - -} /*namespace*/ - - -const KindNode& -GetModelKindHierarchy() -{ - static const KindNode root = _BuildModelKindHierarchy(); - return root; -} - - -void -AppendVariantSelectionString(UT_WorkBuffer& buf, - const SdfPath& prim, - const SdfPath& variants, - const std::string& vset, - const std::string& sel) -{ - if(buf.isEmpty()) { - const auto& primStr = prim.GetString(); - if(variants.IsEmpty()) { - buf.append(primStr.c_str(), primStr.size()); - } else { - /* Buffer needs to hold the variant selection, as well as any part - of the path to the prim past that variant. - I.e., if the variant path is /a{var=sel}, and the prim is /a/b/c, - we need to fill the buffer with '/a{var=sel}b/c */ - const auto& variantsPrimPath = variants.GetPrimPath(); - - size_t variantLength = variantsPrimPath.GetString().size(); - - if(prim.HasPrefix(variantsPrimPath)) { - buf.append(variantsPrimPath.GetString().c_str(), variantLength); - - buf.append(primStr.c_str() + variantLength, - primStr.size() - variantLength); - } else { - /* The variant doesn't apply to this prim, - so ignore the variant and init the buffer to the prim path.*/ - buf.append(primStr.c_str(), primStr.size()); - } - } - } - buf.append('{'); - buf.append(vset.c_str(), vset.size()); - buf.append('='); - buf.append(sel.c_str(), sel.size()); - buf.append('}'); -} - - -namespace { - - -/** Concurrent map to aid in construction of variant paths when - appending variant selections. - For a constant set of variant selections, this computes mappings - of (prim+old variant path) -> (new variant path with selections).*/ -struct _VariantPathMap -{ - typedef std::pair StringIndexPair; - - struct _Key - { - _Key(const UsdPrim& prim, const SdfPath& variant, exint idx=-1) - : prim(prim), variant(variant), idx(idx) {} - - bool operator==(const _Key& o) const - { return prim == o.prim && - idx == o.idx && variant == o.variant; } - - UsdPrim prim; - SdfPath variant; - exint idx; - }; - - struct _HashKey - { - static size_t hash(const _Key& o) - { - std::size_t hash = hash_value(o.prim); - boost::hash_combine(hash, o.variant); - boost::hash_combine(hash, o.idx); - return hash; - } - - static bool equal(const _Key& a, const _Key& b) - { return a == b; } - }; - - - exint Append(const VariantSelArray& sels, - const UsdPrim& prim, - const SdfPath& prevVariant, - UT_WorkBuffer& buf) - { - _Key key(prim, prevVariant); - - { - _Map::const_accessor a; - if(_map.find(a, key)) - return a->second.second; - } - - _Map::accessor a; - if(_map.insert(a, key)) { - buf.clear(); - auto vsets = prim.GetVariantSets(); - - bool haveSel = false; - for(const auto& sel : sels) { - auto vset = vsets.GetVariantSet(sel.variantSet); - if(vset.HasAuthoredVariant(sel.variant)) { - AppendVariantSelectionString( - buf, prim.GetPath(), prevVariant, - sel.variantSet, sel.variant); - haveSel = true; - } - } - if(haveSel) { - a->second.first = buf.buffer(); - a->second.second = _counter.exchangeAdd(1); - } else { - a->second.second = -1; - } - } - return a->second.second; - } - - exint Append(const UsdPrim& prim, - const SdfPath& prevVariant, - const std::string& variantSet, - const std::string& variant, - exint idx, - UT_WorkBuffer& buf) - { - _Key key(prim, prevVariant, idx); - - { - _Map::const_accessor a; - if(_map.find(a, key)) - return a->second.second; - } - - _Map::accessor a; - if(_map.insert(a, key)) { - buf.clear(); - AppendVariantSelectionString( - buf, prim.GetPath(), prevVariant, variantSet, variant); - a->second.first = buf.buffer(); - a->second.second = _counter.exchangeAdd(1); - } - return a->second.second; - } - - - void GetOrderedPaths(UT_Array& paths) const - { - paths.setSize(_counter.relaxedLoad()); - for(const auto& pair : _map) { - if(pair.second.second >= paths.size()) - paths.bumpSize(pair.second.second + 1); - if(pair.second.second >= 0) - paths(pair.second.second) = pair.second.first; - } - } -private: - typedef UT_ConcurrentHashMap<_Key, StringIndexPair,_HashKey> _Map; - - _Map _map; - SYS_AtomicInt32 _counter; -}; - - -/** Functor for computing new variant paths on prims. - This populates the @a variantOverrides map, together with the - @a variantIndices. The latter maps elements of the range into - the @a variantOverrides map.*/ -struct _AppendVariantSelectionsFn -{ - _AppendVariantSelectionsFn(const VariantSelArray& selections, - const UT_Array& prims, - const UT_Array* prevVariants, - UT_Array& variantIndices, - _VariantPathMap& pathMap) - : _selections(selections), _prims(prims), - _prevVariants(prevVariants), _variantIndices(variantIndices), - _pathMap(pathMap) {} - - void operator()(const UT_BlockedRange& r) const - { - // Scratch buffer reused when constructing paths. - UT_WorkBuffer buf; - - auto* boss = UTgetInterrupt(); - char bcnt = 0; - for(size_t i = r.begin(); i < r.end(); ++i) { - if(!++bcnt && boss->opInterrupt()) - return; - - if(UsdPrim prim = _prims(i)) { - SdfPath variants = _prevVariants ? - (*_prevVariants)(i) : SdfPath(); - - _variantIndices(i) = - _pathMap.Append(_selections, prim, variants, buf); - } - } - } -private: - const VariantSelArray& _selections; - const UT_Array& _prims; - const UT_Array* const _prevVariants; - UT_Array& _variantIndices; - _VariantPathMap& _pathMap; -}; - - -} /*namespace*/ - - -bool -AppendVariantSelections(const UT_Array& prims, - const VariantSelArray& selections, - UT_Array& orderedVariants, - UT_Array& indices, - const UT_Array* prevVariants) -{ - UT_ASSERT(!prevVariants || prevVariants->size() == prims.size()); - - UT_AutoInterrupt task("Append variant selections"); - - indices.setSize(prims.size()); - - _VariantPathMap pathMap; - - UTparallelFor(UT_BlockedRange(0, prims.size()), - _AppendVariantSelectionsFn(selections, prims, - prevVariants, - indices, pathMap)); - if(task.wasInterrupted()) - return false; - - pathMap.GetOrderedPaths(orderedVariants); - return true; -} - - -namespace { - - -typedef UT_ThreadSpecificValue _IndexPairArrayTLS; - - -struct _IndexPairArrayData -{ - ~_IndexPairArrayData() - { - for(auto it = indicesTLS.begin(); it != indicesTLS.end(); ++it) { - if(auto* tdata = it.get()) - delete tdata; - } - } - - _IndexPairArrayTLS indicesTLS; -}; - - -/** Functor for computing expanded variant paths on prims.*/ -struct _ExpandVariantSelectionsFn -{ - _ExpandVariantSelectionsFn(const std::string& variantSet, - const NameMatcher& matcher, - const UT_Array& prims, - const UT_Array* prevVariants, - _IndexPairArrayTLS& indicesTLS, - _VariantPathMap& pathMap) - : _variantSet(variantSet), _matcher(matcher), _prims(prims), - _prevVariants(prevVariants), _indicesTLS(indicesTLS), - _pathMap(pathMap) {} - - void operator()(const UT_BlockedRange& r) const - { - IndexPairArray*& indices = _indicesTLS.get(); - if(!indices) - indices = new IndexPairArray; - - // Scratch buffer reused when constructing paths. - UT_WorkBuffer buf; - - auto* boss = UTgetInterrupt(); - char bcnt = 0; - for(size_t i = r.begin(); i < r.end(); ++i) { - if(!++bcnt && boss->opInterrupt()) - return; - - if(UsdPrim prim = _prims(i)) { - SdfPath prevVariant = _prevVariants ? - (*_prevVariants)(i) : SdfPath(); - - auto vsets = prim.GetVariantSets(); - auto vset = vsets.GetVariantSet(_variantSet); - exint idx = 0; - for(const auto& name : vset.GetVariantNames()) { - if(_matcher(name)) { - exint variantIdx = - _pathMap.Append(prim, prevVariant, - _variantSet, name, - idx, buf); - indices->append(IndexPair(i,variantIdx)); - ++idx; - } - } - } - } - } -private: - const std::string& _variantSet; - const NameMatcher& _matcher; - const UT_Array& _prims; - const UT_Array* const _prevVariants; - _IndexPairArrayTLS& _indicesTLS; - _VariantPathMap& _pathMap; -}; - - -bool -_GatherIndexPairsFromThreads(IndexPairArray& indices, - _IndexPairArrayTLS& indicesTLS) -{ - indices.clear(); - - // Compute the full count and pre-allocate space. - exint nPairs = 0; - for(auto it = indicesTLS.begin(); it != indicesTLS.end(); ++it) { - if(const auto* tdata = it.get()) - nPairs += tdata->size(); - } - indices.setCapacity(nPairs); - - // Concat the per-thread arrays. - for(auto it = indicesTLS.begin(); it != indicesTLS.end(); ++it) { - if(const auto* tdata = it.get()) - indices.concat(*tdata); - } - - /* Everything is currently ordered by threads, so will be non-deterministic. - Sort to make the results deterministic.*/ - UTparallelStableSort( - indices.begin(), indices.end()); - return !UTgetInterrupt()->opInterrupt(); -} - - - -} /*namespace*/ - - -bool -ExpandVariantSetPaths(const UT_Array& prims, - const std::string& variantSet, - const NameMatcher& matcher, - UT_Array& orderedVariants, - IndexPairArray& indices, - const UT_Array* prevVariants) -{ - UT_ASSERT(!prevVariants || prevVariants->size() == prims.size()); - - UT_AutoInterrupt task("Append variant selections"); - - _VariantPathMap pathMap; - - _IndexPairArrayData data; - - UTparallelFor(UT_BlockedRange(0, prims.size()), - _ExpandVariantSelectionsFn(variantSet, matcher, prims, - prevVariants, data.indicesTLS, - pathMap)); - if(task.wasInterrupted()) - return false; - - pathMap.GetOrderedPaths(orderedVariants); - - return _GatherIndexPairsFromThreads(indices, data.indicesTLS); -} - - -void -SetVariantsFromPath(const SdfPath& path, const SdfLayerHandle& layer) -{ - if(path.IsPrimPath() || path.IsPrimVariantSelectionPath()) { - for(SdfPath p = path; p != SdfPath::AbsoluteRootPath(); - p = p.GetParentPath()) { - - if(p.IsPrimVariantSelectionPath()) { - auto sel = p.GetVariantSelection(); - SdfPrimSpecHandle spec = - SdfCreatePrimInLayer(layer, p.GetPrimPath()); - spec->SetVariantSelection(sel.first, sel.second); - } - } - } -} - - -namespace { - - -struct _TokenIndexMap -{ - exint Append(const TfToken& key) - { - { - _Map::const_accessor a; - if(_map.find(a, key)) - return a->second; - } - _Map::accessor a; - if(_map.insert(a, key)) - a->second = _counter.exchangeAdd(1); - return a->second; - } - - void GetOrderedTokens(UT_Array& tokens) { - tokens.setSize(_counter.relaxedLoad()); - for(const auto& pair : _map) { - if(pair.second >= tokens.size()) - tokens.bumpSize(pair.second + 1); - if(pair.second >= 0) - tokens(pair.second) = \ - UT_StringHolder(pair.first.GetString().c_str(), - UT_StringHolder::REFERENCE); - } - } - -private: - struct _HashCmp - { - static size_t hash(const TfToken& t) - { return hash_value(t); } - static bool equal(const TfToken&a, const TfToken& b) - { return a == b; } - }; - - typedef UT_ConcurrentHashMap _Map; - _Map _map; - SYS_AtomicInt32 _counter; -}; - - -struct _GetPropertyNamesFn -{ - _GetPropertyNamesFn(const NameMatcher& matcher, - const UT_Array& prims, - _IndexPairArrayTLS& indicesTLS, - _TokenIndexMap& map, - const std::string& nameSpace) - : _matcher(matcher), _prims(prims), - _indicesTLS(indicesTLS), _map(map), _nameSpace(nameSpace) {} - - void operator()(const UT_BlockedRange& r) const - { - IndexPairArray*& indices = _indicesTLS.get(); - if(!indices) - indices = new IndexPairArray; - - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - for(size_t i = r.begin(); i < r.end(); ++i) { - if(!++bcnt && boss->opInterrupt()) - return; - - if(UsdPrim prim = _prims(i)) { - const auto props = - prim.GetPropertiesInNamespace(_nameSpace); - for(const auto& prop : props) { - const auto& name = prop.GetName(); - if(_matcher(name.GetString())) { - indices->append( - IndexPair(i,_map.Append(name))); - } - } - } - } - } -private: - const NameMatcher& _matcher; - const UT_Array& _prims; - _IndexPairArrayTLS& _indicesTLS; - _TokenIndexMap& _map; - const std::string& _nameSpace; -}; - - -} /*namespace*/ - - -bool -GetPropertyNames(const UT_Array& prims, - const NameMatcher& matcher, - UT_Array& orderedNames, - IndexPairArray& indices, - const std::string& nameSpace) -{ - UT_AutoInterrupt task("Compute matching property names"); - - _TokenIndexMap tokenMap; - _IndexPairArrayData data; - - UTparallelFor(UT_BlockedRange(0, prims.size()), - _GetPropertyNamesFn(matcher, prims, data.indicesTLS, - tokenMap, nameSpace)); - if(task.wasInterrupted()) - return false; - - tokenMap.GetOrderedTokens(orderedNames); - - return _GatherIndexPairsFromThreads(indices, data.indicesTLS); -} - - -namespace { - - -void -_SortedStringArrayFromSet(const UT_Set& set, - UT_Array& array) -{ - array.setSize(set.size()); - exint idx = 0; - for(const auto& str : set) { - array(idx) = str; - ++idx; - } - array.stdsort(std::less()); -} - - -} /*namespace*/ - - -bool -GetUniqueVariantSetNames(const UT_Array& prims, - UT_Array& names) -{ - /* This isn't used in performance sensitive contexts, - so just loop in serial for now.*/ - UT_Set visited; - UT_Set nameSet; - for(const auto& prim : prims) { - if(visited.find(prim) != visited.end()) - continue; - - auto vsets = prim.GetVariantSets(); - for(const auto& name : vsets.GetNames()) { - if(nameSet.find(UT_StringRef(name.c_str())) == nameSet.end()) - nameSet.insert(UT_StringHolder(name.c_str())); - } - visited.insert(prim); - } - _SortedStringArrayFromSet(nameSet, names); - return true; -} - - -bool -GetUniqueVariantNames(const UT_Array& prims, - const std::string& variantSet, - UT_Array& names) -{ - /* This isn't used in performance sensitive contexts, - so just loop in serial for now.*/ - UT_Set visited; - UT_Set nameSet; - for(const auto& prim : prims) { - if(visited.find(prim) != visited.end()) - continue; - - auto vsets = prim.GetVariantSets(); - auto vset = vsets.GetVariantSet(variantSet); - for(const auto& name : vset.GetVariantNames()) { - if(nameSet.find(UT_StringRef(name.c_str())) == nameSet.end()) - nameSet.insert(UT_StringHolder(name.c_str())); - } - visited.insert(prim); - } - _SortedStringArrayFromSet(nameSet, names); - return true; -} - - -bool -GetUniquePropertyNames(const UT_Array& prims, - UT_Array& names, - const std::string& nameSpace) -{ - /* This isn't used in performance sensitive contexts, - so just loop in serial for now.*/ - UT_Set visited; - std::set nameSet; // use std::set for sorting. - for(const auto& prim : prims) { - if(visited.find(prim) != visited.end()) - continue; - for(auto p : prim.GetPropertiesInNamespace(nameSpace)) { - const auto& name = p.GetName(); - if(nameSet.find(name) == nameSet.end()) - nameSet.insert(name); - } - visited.insert(prim); - } - names.setSize(nameSet.size()); - exint idx = 0; - for(const auto& name : nameSet) { - names(idx) = UT_StringHolder(name.GetString().c_str()); - ++idx; - } - return true; -} - - -} /*namespace GusdUSD_Utils */ - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/USD_Utils.h b/third_party/houdini/gusd/USD_Utils.h deleted file mode 100644 index ea55741587..0000000000 --- a/third_party/houdini/gusd/USD_Utils.h +++ /dev/null @@ -1,322 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_UTILS_H -#define GUSD_USD_UTILS_H - -#include "api.h" - -#include "error.h" - -#include "pxr/pxr.h" -#include "pxr/base/arch/hints.h" -#include "pxr/base/tf/token.h" -#include "pxr/usd/usdGeom/imageable.h" -#include "pxr/usd/usdGeom/tokens.h" - -#include -#include -#include -#include -#include -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -namespace GusdUSD_Utils -{ - -/// TODO: Would be nice to loft these TfTokens into a a shared place. -const TfToken kModelingVariantToken("modelingVariant"); -const TfToken kAllVariantsToken("ALL_VARIANTS"); - - -/// Convert a TfToken to a UT_StringHolder. -GUSD_API -UT_StringHolder TokenToStringHolder(const TfToken& token); - -/// Extract the numeric time from a time code. -/// If @a time is not numeric, returns the numeric value -/// from UsdTimeCode::EarliestTime(). -GUSD_API -double GetNumericTime(UsdTimeCode time); - - -/// Parse and construct and SdfPath from a string. -/// Returns true if there were no parse errors. -/// Any errors that occur while attempting to construct the path are reported -/// on the currently scoped error manager at a severity of \p sev. -GUSD_API -bool CreateSdfPath(const UT_StringRef& pathStr, - SdfPath& path, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - -/// Returns an SdfPath that can be used for identify the stage's defaultPrim. -GUSD_API -const SdfPath& GetDefaultPrimIdentifier(); - - -/// Get a prim from a stage. -/// If no prim can be found at \p path, an error is reported on the currently -/// scoped error manager at a severity of \p sev. -GUSD_API -UsdPrim GetPrimFromStage(const UsdStagePtr& stage, - const SdfPath& path, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - -/// Helper for creating and validating schema objects. -/// If the prim doesn't match the expected schema type, an error is reported -/// on the currently scoped error manager at a severity of \p sev. -template -SchemaT MakeSchemaObj(const UsdPrim& prim, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - -/// Given a string representing a list of whitespace-delimited paths, -/// which may or may not include variant specifications, -/// return an array of prim and variant paths. -/// -/// The resulting @a primPaths and @a variantPaths arrays -/// will be the same size. If no variants are associated with a path, -/// then the corresponding entry in @a variants will be an empty path. -/// If any errors occur while parsing the path, errors are reporeted on the -/// currently scoped error manager at a severity of \p sev. -GUSD_API -bool GetPrimAndVariantPathsFromPathList( - const char* str, - UT_Array& primPaths, - UT_Array& variants, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - -/** Extract a prim path and variant selection from a path.*/ -GUSD_API -void ExtractPrimPathAndVariants(const SdfPath& path, - SdfPath& primPath, - SdfPath& variants); - -/** Set a modeling variant on a stage given the prim and variant to set.*/ -GUSD_API -void SetModelingVariant(const UsdStageRefPtr& stage, - const UsdPrim& prim, - const TfToken& variant); - -/** Clear any variant selection on a prim.*/ -GUSD_API -void ClearModelingVariant(const UsdStageRefPtr& stage, - const UsdPrim& prim); - -/** Sort an array of prims (by path) */ -GUSD_API -bool SortPrims(UT_Array& prims); - - -/** Traverse the tree of schema types to compute a list - of types matching a pattern. - Derived types of types that match the pattern are not added - to the list; the minimal set of matching types is returned - to simplify later type comparisons.*/ -GUSD_API -void GetBaseSchemaTypesMatchingPattern(const char* pattern, - UT_Array& types, - bool caseSensitive=true); - - -/** Get the list of all model kinds matching the given pattern. - Derived types of types that match the pattern are not added - to the list; the minimal set of matching types is returned - to simplify later type comparisons.*/ -GUSD_API -void GetBaseModelKindsMatchingPattern(const char* pattern, - UT_Array& kinds, - bool caseSensitive=true); - - -GUSD_API -void GetPurposesMatchingPattern(const char* pattern, - UT_Array& purposes, - bool caseSensitive=true); - - -struct KindNode -{ - typedef UT_SharedPtr RefPtr; - TfToken kind; - UT_Array children; -}; - - -/** Get a walkable hierarchy of the registered model kinds. - The root of the hierarchy is always a root node with an empty kind.*/ -const KindNode& GetModelKindHierarchy(); - - -struct VariantSel -{ - std::string variantSet, variant; -}; - -typedef UT_Array VariantSelArray; - - -/** Helper for building up a variant-encoded prim path. - Appends string {vset=sel} to @a buf. If the buffer is empty, - the buffer is initialized to the path up to @a prim, including - any of the variant selections specified in @a variants.*/ -GUSD_API -void AppendVariantSelectionString(UT_WorkBuffer& buf, - const SdfPath& prim, - const SdfPath& variants, - const std::string& vset, - const std::string& sel); - - -/** Given an array of prims, compute new variant path strings - that apply a set of variant selections. - Only the variants that exist on each prim are applied. - The @a variants array may optionally be specified to provide - the previous variant path of each prim. - - The resulting @a indices array provides an index per-prim into - the @a orderedVariants array. The indices may be -1 to indicate - that the entry has no variant selections.*/ -GUSD_API -bool AppendVariantSelections(const UT_Array& prims, - const VariantSelArray& selections, - UT_Array& orderedVariants, - UT_Array& indices, - const UT_Array* prevVariants=NULL); - - -struct NameMatcher -{ - virtual ~NameMatcher() {} - virtual bool operator()(const std::string& name) const = 0; -}; - -typedef std::pair IndexPair; -typedef UT_Array IndexPairArray; - - -/** Expand selections of variants that match a given match function. - For every prim in @a prims that has variant set @a variantSet, - this appends an entry in @a indices for each matching variant. - The first component of the pair in @a indices is the index of the - original prim from @a prims from which the entry was expanded. - The second component is an index into the @a orderedVariants array. */ -GUSD_API -bool ExpandVariantSetPaths(const UT_Array& prims, - const std::string& variantSet, - const NameMatcher& matcher, - UT_Array& orderedVariants, - IndexPairArray& indices, - const UT_Array* prevVariants=NULL); - - -/// Author variant selections on a layer using -/// variants stored in a path. -GUSD_API -void SetVariantsFromPath(const SdfPath& path, - const SdfLayerHandle& layer); - - -/** Compute a set of properties matching the namespace of a range of prims. - For every prim in @a prims, this appends an entry in @a indices for - each matching attribute. The first component of the pairt in @a indices - is the index of the original prim from @a prims that the attribute - was matched from. The second component is an index into the - @a orderedNames array.*/ -GUSD_API -bool GetPropertyNames(const UT_Array& prims, - const NameMatcher& matcher, - UT_Array& orderedNames, - IndexPairArray& indices, - const std::string& nameSpace=std::string()); - - -/** Query all unique variant set names for a range of prims.*/ -GUSD_API -bool GetUniqueVariantSetNames(const UT_Array& prims, - UT_Array& names); - - -/** Query all unique variant names for a specific variant - set on all of the given prims.*/ -GUSD_API -bool GetUniqueVariantNames(const UT_Array& prims, - const std::string& variantSet, - UT_Array& names); - - -/** Query all unique property names for a range of prims.*/ -GUSD_API -bool GetUniquePropertyNames(const UT_Array& prims, - UT_Array& names, - const std::string& nameSpace=std::string()); - - -inline double -GetNumericTime(UsdTimeCode time) -{ - return time.IsNumeric() ? - time.GetValue() : UsdTimeCode::EarliestTime().GetValue(); -} - - -inline UsdTimeCode -ClampTimeCode(UsdTimeCode t, double start, double end, int digits) -{ - if(ARCH_UNLIKELY(t.IsDefault())) - return t; - return UsdTimeCode( - SYSniceNumber(SYSclamp(t.GetValue(), start, end), digits)); -} - - -template -SchemaT -MakeSchemaObj(const UsdPrim& prim, UT_ErrorSeverity sev) -{ - SchemaT obj(prim); - if(!obj) { - static const std::string typeName = - TfType::Find().GetTypeName(); - - GUSD_GENERIC_ERR(sev).Msg( - "Prim '%s' is not a %s.", - prim.GetPath().GetText(), typeName.c_str()); - } - return obj; -} - - -} /*namespace GusdUSD_Utils*/ - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_UTILS_H*/ diff --git a/third_party/houdini/gusd/USD_VisCache.cpp b/third_party/houdini/gusd/USD_VisCache.cpp deleted file mode 100644 index 3838fd08de..0000000000 --- a/third_party/houdini/gusd/USD_VisCache.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_VisCache.h" - -#include "USD_PropertyMap.h" -#include "USD_Utils.h" - -#include "pxr/base/arch/hints.h" - -PXR_NAMESPACE_OPEN_SCOPE - -GusdUSD_VisCache::GusdUSD_VisCache(GusdStageCache& cache) - : GusdUSD_DataCache(cache), - _visInfos(GUSDUT_USDCACHE_NAME, 256) -{} - - -GusdUSD_VisCache::GusdUSD_VisCache() - : GusdUSD_VisCache(GusdStageCache::GetInstance()) -{} - - -GusdUSD_VisCache& -GusdUSD_VisCache::GetInstance() -{ - static GusdUSD_VisCache cache; - return cache; -} - - -namespace { - - -enum VisFlags -{ - FLAGS_ISMAYBETIMEVARYING = 1 << 0, - FLAGS_RESOLVED_ISMAYBETIMEVARYING = 1 << 1 -}; - - -enum VisType -{ - VIS_UNVARYING, - VIS_VARYING, - VIS_UNVARYING_RESOLVED, - VIS_VARYING_RESOLVED -}; - - -enum VisState -{ - STATE_VISIBLE = 1 << 0, - STATE_COMPUTED = 1 << 1 -}; - - -int _GetStateFlags(int flags, VisType type) - { return flags>>(2*type + 2); } - -int _SetStateFlags(int flags, int stateFlags, VisType type) - { return flags|(stateFlags<<(2*type + 2)); } - - -using _UnvaryingKey = GusdUT_CappedKey; - - -bool _QueryVisibility(const UsdAttributeQuery& query, UsdTimeCode time) -{ - TfToken vis; - query.Get(&vis, time); - return vis != UsdGeomTokens->invisible; -} - - -bool -_ShouldCacheVisibility(int flags, UsdTimeCode time) -{ - // Only time-invariant visibility is cached. - return !(flags&FLAGS_ISMAYBETIMEVARYING) || time.IsDefault(); -} - - -} /*namespace*/ - - -GusdUSD_VisCache::VisInfoHandle -GusdUSD_VisCache::_GetVisInfo(const UsdPrim& prim) -{ - _UnvaryingKey key((GusdUSD_UnvaryingPropertyKey(prim))); - - if (UT_CappedItemHandle info = _visInfos.findItem(key)) { - return VisInfoHandle(UTverify_cast(info.get())); - } - // XXX: Potential race in construction, but in the worst case that will - // just mean a few extra computes. - - UsdGeomImageable ip(prim); - if (ARCH_UNLIKELY(!ip)) { - return VisInfoHandle(); - } - - UsdAttribute visAttr(ip.GetVisibilityAttr()); - - int flags = 0; - if (visAttr.ValueMightBeTimeVarying()) { - flags |= FLAGS_ISMAYBETIMEVARYING|FLAGS_RESOLVED_ISMAYBETIMEVARYING; - } else if (UsdPrim parent = prim.GetParent()) { - if (auto parentInfo = _GetVisInfo(parent)) { - if (parentInfo->flags.relaxedLoad()& - FLAGS_RESOLVED_ISMAYBETIMEVARYING) { - flags |= FLAGS_RESOLVED_ISMAYBETIMEVARYING; - } - } - } - return VisInfoHandle( - UTverify_cast( - _visInfos.addItem( - key, UT_CappedItemHandle( - new VisInfo(flags, visAttr))).get())); -} - - -bool -GusdUSD_VisCache::GetVisibility(const UsdPrim& prim, - UsdTimeCode time) -{ - if (auto info = _GetVisInfo(prim)) { - int flags = info->flags.relaxedLoad(); - bool vis = true; - if (_GetVisibility(flags, info->query, time, vis)) { - info->flags.store(flags); - } - return vis; - } - return false; -} - - -bool -GusdUSD_VisCache::_GetVisibility(int& flags, - const UsdAttributeQuery& query, - UsdTimeCode time, - bool& vis) -{ - if (_ShouldCacheVisibility(flags, time)) { - VisType visType = time.IsDefault() ? VIS_UNVARYING : VIS_VARYING; - int stateFlags = _GetStateFlags(flags, visType); - if (stateFlags&STATE_COMPUTED) { - vis = stateFlags&STATE_VISIBLE; - return false; - } else { - if (vis = _QueryVisibility(query, time)) { - stateFlags |= STATE_VISIBLE; - } - flags = _SetStateFlags(flags, stateFlags|STATE_COMPUTED, visType); - } - } else { - // Visibility is not cached when time-varying. - vis = _QueryVisibility(query, time); - return false; - } - return true; -} - - -bool -GusdUSD_VisCache::GetResolvedVisibility(const UsdPrim& prim, UsdTimeCode time) -{ - auto info = _GetVisInfo(prim); - if (ARCH_UNLIKELY(!info)) { - return false; - } - - int flags = info->flags.relaxedLoad(); - if (_ShouldCacheVisibility(flags, time)) { - VisType visType = time.IsDefault() ? - VIS_UNVARYING_RESOLVED : VIS_VARYING_RESOLVED; - int stateFlags = _GetStateFlags(flags, visType); - if (stateFlags&STATE_COMPUTED) { - return stateFlags&STATE_VISIBLE; - } else { - bool vis = true; - _GetVisibility(flags, info->query, time, vis); - if (vis) { - if (UsdPrim parent = prim.GetParent()) { - if (!parent.IsPseudoRoot()) { - vis = GetResolvedVisibility(parent, time); - } - } - } - if (vis) { - stateFlags |= STATE_VISIBLE; - } - flags = _SetStateFlags(flags, stateFlags|STATE_COMPUTED, visType); - info->flags.store(flags); - return vis; - } - } else { - // Visibility is not cached when time-varying. - if (_QueryVisibility(info->query, time)) { - if (UsdPrim parent = prim.GetParent()) { - if (!parent.IsPseudoRoot()) { - return GetResolvedVisibility(parent, time); - } - } - return true; - } - return false; - } -} - - -void -GusdUSD_VisCache::Clear() -{ - _visInfos.clear(); -} - - -namespace { - - -template -int64 -_RemoveKeysT(const UT_StringSet& paths, GusdUT_CappedCache& cache) -{ - return cache.ClearEntries( - [&](const UT_CappedKeyHandle& key, - const UT_CappedItemHandle& item) { - - return GusdUSD_DataCache::ShouldClearPrim( - (*UTverify_cast(key.get()))->prim, - paths); - }); -} - - -} /*namespace*/ - - -int64 -GusdUSD_VisCache::Clear(const UT_StringSet& paths) -{ - return _RemoveKeysT<_UnvaryingKey>(paths, _visInfos); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/USD_VisCache.h b/third_party/houdini/gusd/USD_VisCache.h deleted file mode 100644 index 7c8df944f7..0000000000 --- a/third_party/houdini/gusd/USD_VisCache.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_VIS_CACHE_H -#define GUSD_USD_VIS_CACHE_H - -#include "api.h" - -#include "USD_DataCache.h" -#include "UT_CappedCache.h" - -#include - -#include "pxr/pxr.h" -#include "pxr/usd/usd/attributeQuery.h" -#include "pxr/usd/usdGeom/imageable.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** Thread-safe, memory-capped visibility cache. - This does not cache varying visibility state; only unvarying visibility - values and information about whether or not visibility might vary - with time is cached.*/ -class GusdUSD_VisCache final : public GusdUSD_DataCache -{ -public: - - GUSD_API - static GusdUSD_VisCache& GetInstance(); - - GusdUSD_VisCache(GusdStageCache& cache); - GusdUSD_VisCache(); - - virtual ~GusdUSD_VisCache() {} - - // Not cached. - GUSD_API - bool GetVisibility(const UsdPrim& prim, UsdTimeCode time); - - // Cached. - GUSD_API - bool GetResolvedVisibility(const UsdPrim& prim, UsdTimeCode time); - - GUSD_API - virtual void Clear() override; - - GUSD_API - virtual int64 Clear(const UT_StringSet& paths) override; - -private: - struct VisInfo : public UT_CappedItem - { - VisInfo(int flags, const UsdAttribute& attr) - : UT_CappedItem(), flags(flags), query(attr) {} - - virtual ~VisInfo() {} - - virtual int64 getMemoryUsage() const { return sizeof(*this); } - - SYS_AtomicInt32 flags; - UsdAttributeQuery query; - }; - typedef UT_IntrusivePtr VisInfoHandle; - - VisInfoHandle _GetVisInfo(const UsdPrim& prim); - - /** Query visibility. Returns true if @a flags were modified.*/ - bool _GetVisibility(int& flags, - const UsdAttributeQuery& query, - UsdTimeCode time, - bool& vis); - - GusdUT_CappedCache _visInfos; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_VIS_CACHE_H*/ diff --git a/third_party/houdini/gusd/USD_XformCache.cpp b/third_party/houdini/gusd/USD_XformCache.cpp deleted file mode 100644 index 7a360e36c8..0000000000 --- a/third_party/houdini/gusd/USD_XformCache.cpp +++ /dev/null @@ -1,485 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "USD_XformCache.h" - -#include "USD_PropertyMap.h" -#include "UT_Gf.h" -#include "UT_CappedCache.h" - -#include "pxr/base/arch/hints.h" - -#include -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -namespace { - - -typedef GusdUT_CappedKey _UnvaryingKey; - -typedef GusdUT_CappedKey _VaryingKey; - - -struct _CappedXformItem : public UT_CappedItem -{ - _CappedXformItem(const UT_Matrix4D& xform) - : UT_CappedItem(), xform(xform) {} - - virtual ~_CappedXformItem() {} - - virtual int64 getMemoryUsage() const { return sizeof(*this); } - - const UT_Matrix4D xform; -}; - -typedef UT_IntrusivePtr _CappedXformItemHandle; - -#if SYS_VERSION_FULL_INT < 0x10050000 -static inline void intrusive_ptr_add_ref(const _CappedXformItem *o) { const_cast<_CappedXformItem *>(o)->incref(); } -static inline void intrusive_ptr_release(const _CappedXformItem *o) { const_cast<_CappedXformItem *>(o)->decref(); } -#endif - -} /*namespace*/ - -#if SYS_VERSION_FULL_INT < 0x10050000 -static inline void intrusive_ptr_add_ref(const GusdUSD_XformCache::XformInfo *o) { const_cast(o)->incref(); } -static inline void intrusive_ptr_release(const GusdUSD_XformCache::XformInfo *o) { const_cast(o)->decref(); } -#endif - -void -GusdUSD_XformCache::XformInfo::ComputeFlags(const UsdPrim& prim, - GusdUSD_XformCache& cache) -{ - if(query.TransformMightBeTimeVarying()) { - _flags = FLAGS_LOCAL_MAYBE_TIMEVARYING| - FLAGS_WORLD_MAYBE_TIMEVARYING; - } else { - /* Local transform isn't time-varying, but maybe the parent is.*/ - if(!query.GetResetXformStack()) { - const UsdPrim parent = prim.GetParent(); - if(parent && !parent.IsPseudoRoot()) { - auto info = cache.GetXformInfo(parent); - if(info && info->WorldXformIsMaybeTimeVarying()) { - _flags = FLAGS_WORLD_MAYBE_TIMEVARYING; - } - } - } - } - - if(!query.GetResetXformStack()) { - const UsdPrim parent = prim.GetParent(); - if(parent && !parent.IsPseudoRoot()) { - _flags |= FLAGS_HAS_PARENT_XFORM; - } - } -} - - -GusdUSD_XformCache& -GusdUSD_XformCache::GetInstance() -{ - static GusdUSD_XformCache cache; - return cache; -} - - -GusdUSD_XformCache::XformInfoHandle -GusdUSD_XformCache::GetXformInfo(const UsdPrim& prim) -{ - if (ARCH_UNLIKELY(prim.IsPseudoRoot())) { - return nullptr; - } - - _UnvaryingKey key((GusdUSD_UnvaryingPropertyKey(prim))); - - if(auto item = _xformInfos.findItem(key)) - return XformInfoHandle(UTverify_cast(item.get())); - - auto* info = new XformInfo(UsdGeomXformable(prim)); - info->ComputeFlags(prim, *this); - auto item = UT_CappedItemHandle(info); - return XformInfoHandle(UTverify_cast( - _xformInfos.addItem(key,item).get())); -} - - -bool -GusdUSD_XformCache::GetLocalTransformation(const UsdPrim& prim, - UsdTimeCode time, - UT_Matrix4D& xform) -{ - if (const auto info = GetXformInfo(prim)) { - return _GetLocalTransformation(prim, time, xform, info); - } - return false; -} - - -bool -GusdUSD_XformCache::_GetLocalTransformation(const UsdPrim& prim, - UsdTimeCode time, - UT_Matrix4D& xform, - const XformInfoHandle& info) -{ - // See if we can remap the time to for unvarying xforms. - if(!time.IsDefault() && !info->LocalXformIsMaybeTimeVarying()) { - /* XXX: we know we're not time varying, but that doesn't - mean that we can key default, since there might still - be a single varying value that we'd miss. - Key off of time=0 instead.*/ - time = UsdTimeCode(0.0); - } - _VaryingKey key(GusdUSD_VaryingPropertyKey(prim, time)); - - if(auto item = _xforms.findItem(key)) { - xform = UTverify_cast(item.get())->xform; - return true; - } - /* XXX: Race is possible when setting computed value, - but it's preferable to have multiple threads compute the - same thing than to cause lock contention.*/ - if(info->query.GetLocalTransformation(GusdUT_Gf::Cast(&xform), time)) { - _xforms.addItem(key, UT_CappedItemHandle(new _CappedXformItem(xform))); - return true; - } - return false; -} - - -bool -GusdUSD_XformCache::GetLocalToWorldTransform(const UsdPrim& prim, - UsdTimeCode time, - UT_Matrix4D& xform) -{ - const auto info = GetXformInfo(prim); - if(ARCH_UNLIKELY(!info)) { - return false; - } - - // See if we can remap the time to for unvarying xforms. - if(!time.IsDefault() && !info->WorldXformIsMaybeTimeVarying()) { - /* XXX: we know we're not time varying, but that doesn't - mean that we can key default, since there might still - be a single varying value that we'd miss. - Key off of time=0 instead.*/ - time = UsdTimeCode(0.0); - } - _VaryingKey key(GusdUSD_VaryingPropertyKey(prim, time)); - - if(auto item = _worldXforms.findItem(key)) { - xform = UTverify_cast(item.get())->xform; - return true; - } - /* XXX: Race is possible when setting computed value, - but it's preferable to have multiple threads compute the - same thing than to cause lock contention.*/ - if(_GetLocalTransformation(prim, time, xform, info)) { - if(ARCH_UNLIKELY(!info->HasParentXform())) { - _worldXforms.addItem(key, UT_CappedItemHandle( - new _CappedXformItem(xform))); - return true; - } - const UsdPrim parent = prim.GetParent(); - UT_ASSERT_P(parent); - - UT_Matrix4D parentXf; - if(GetLocalToWorldTransform(parent, time, parentXf)) { - xform *= parentXf; - _worldXforms.addItem( - key, UT_CappedItemHandle(new _CappedXformItem(xform))); - return true; - } - } - return false; -} - - - -GusdUSD_XformCache::GusdUSD_XformCache(GusdStageCache& cache) - : GusdUSD_DataCache(cache), - _xforms(GUSDUT_USDCACHE_NAME, 512), - _worldXforms(GUSDUT_USDCACHE_NAME, 512), - _xformInfos(GUSDUT_USDCACHE_NAME, 256) {} - - -GusdUSD_XformCache::GusdUSD_XformCache() - : GusdUSD_XformCache(GusdStageCache::GetInstance()) -{} - - -namespace { - - -/** Functor for computing transforms from USD prims.*/ -template -struct _ComputeXformsT -{ - _ComputeXformsT(const XformFn& xformFn, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) - : _xformFn(xformFn), _prims(prims), - _times(times), _xforms(xforms) {} - - void operator()(const UT_BlockedRange& r) const - { - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - for(size_t i = r.begin(); i < r.end(); ++i) { - if(!++bcnt && boss->opInterrupt()) - return; - if(UsdPrim prim = _prims(i)) { - _xformFn(_xforms[i], prim, _times(i), i); - continue; - } - _xforms[i].identity(); - } - } - -private: - const XformFn& _xformFn; - const UT_Array& _prims; - const GusdDefaultArray& _times; - UT_Matrix4D* const _xforms; -}; - - -struct _WorldXformFn -{ - _WorldXformFn(GusdUSD_XformCache& cache) - : _cache(cache) {} - - void operator()(UT_Matrix4D& xf, - const UsdPrim& prim, UsdTimeCode time, size_t i) const - { - if(!_cache.GetLocalToWorldTransform(prim, time, xf)) - xf.identity(); - } - -private: - GusdUSD_XformCache& _cache; -}; - - -struct _LocalXformFn -{ - _LocalXformFn(GusdUSD_XformCache& cache) - : _cache(cache) {} - - void operator()(UT_Matrix4D& xf, - const UsdPrim& prim, UsdTimeCode time, size_t i) const - { - if(!_cache.GetLocalTransformation(prim, time, xf)) - xf.identity(); - } - -private: - GusdUSD_XformCache& _cache; -}; - - -template -bool -_ComputeXforms(const XformFn& xformFn, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) -{ - UTparallelFor(UT_BlockedRange(0, prims.size()), - _ComputeXformsT(xformFn, prims, times, xforms)); - return !UTgetInterrupt()->opInterrupt(); -} - - -} /*namespace*/ - - -bool -GusdUSD_XformCache::GetLocalTransformations( - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) -{ - return _ComputeXforms<_LocalXformFn>(_LocalXformFn(*this), - prims, times, xforms); -} - - -bool -GusdUSD_XformCache::GetLocalToWorldTransforms( - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) -{ - return _ComputeXforms<_WorldXformFn>(_WorldXformFn(*this), - prims, times, xforms); -} - - -namespace { - - -template -struct _QueryConstraintsT -{ - _QueryConstraintsT(const NameFn& nameFn, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) - : _nameFn(nameFn), _prims(prims), _times(times), _xforms(xforms) {} - - void operator()(const UT_BlockedRange& r) const - { - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - for(size_t i = r.begin(); i < r.end(); ++i) { - if(!++bcnt && boss->opInterrupt()) - return; - if(UsdPrim prim = _prims(i)) { - const TfToken& name = _nameFn(i); - if(!name.IsEmpty()) { - if(prim.GetAttribute(name).Get( - GusdUT_Gf::Cast(_xforms + i), _times(i))) - continue; - } - } - _xforms[i].identity(); - } - } - - -private: - const NameFn& _nameFn; - const UT_Array& _prims; - const GusdDefaultArray& _times; - UT_Matrix4D* const _xforms; -}; - - -struct _SingleNameFn -{ - _SingleNameFn(const TfToken& name) : _name(name) {} - - const TfToken& operator()(exint i) const { return _name; } -private: - const TfToken& _name; -}; - - -struct _ArrayOfNamesFn -{ - _ArrayOfNamesFn(const UT_Array& names) : _names(names) {} - - const TfToken& operator()(exint i) const { return _names(i); } -private: - const UT_Array& _names; -}; - - -template -bool -_QueryConstraints(const NameFn& nameFn, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) -{ - UTparallelFor(UT_BlockedRange(0, prims.size()), - _QueryConstraintsT(nameFn, prims, times, xforms)); - return !UTgetInterrupt()->opInterrupt(); -} - - -} /*namespace*/ - - -bool -GusdUSD_XformCache::GetConstraintTransforms( - const TfToken& constraint, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) -{ - return _QueryConstraints<_SingleNameFn>(_SingleNameFn(constraint), - prims, times, xforms); -} - - -bool -GusdUSD_XformCache::GetConstraintTransforms( - const UT_Array& constraints, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms) -{ - return _QueryConstraints<_ArrayOfNamesFn>(_ArrayOfNamesFn(constraints), - prims, times, xforms); -} - - -void -GusdUSD_XformCache::Clear() -{ - _xforms.clear(); - _worldXforms.clear(); - _xformInfos.clear(); -} - - -namespace { - - -template -int64 -_RemoveKeysT(const UT_StringSet& paths, GusdUT_CappedCache& cache) -{ - return cache.ClearEntries( - [&](const UT_CappedKeyHandle& key, - const UT_CappedItemHandle& item) { - - return GusdUSD_DataCache::ShouldClearPrim( - (*UTverify_cast(key.get()))->prim, - paths); - }); -} - - -} /*namespace*/ - - -int64 -GusdUSD_XformCache::Clear(const UT_StringSet& paths) -{ - return _RemoveKeysT<_VaryingKey>(paths, _xforms) + - _RemoveKeysT<_VaryingKey>(paths, _worldXforms ) + - _RemoveKeysT<_UnvaryingKey>(paths, _xformInfos); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/USD_XformCache.h b/third_party/houdini/gusd/USD_XformCache.h deleted file mode 100644 index c59aa01b04..0000000000 --- a/third_party/houdini/gusd/USD_XformCache.h +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_USD_XFORM_CACHE_H -#define GUSD_USD_XFORM_CACHE_H - -#include "api.h" - -#include "defaultArray.h" -#include "UT_CappedCache.h" -#include "USD_DataCache.h" -#include "USD_Utils.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/xformable.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** Concurrent memory-capped cache for primitive transforms.*/ -class GusdUSD_XformCache final : public GusdUSD_DataCache -{ -public: - - GUSD_API - static GusdUSD_XformCache& GetInstance(); - - GusdUSD_XformCache(GusdStageCache& cache); - GusdUSD_XformCache(); - - virtual ~GusdUSD_XformCache() {} - - bool GetLocalTransformation(const UsdPrim& prim, - UsdTimeCode time, - UT_Matrix4D& xform); - - bool GetLocalToWorldTransform(const UsdPrim& prim, - UsdTimeCode time, - UT_Matrix4D& xform); - - /** Compute multiple local transforms in parallel. */ - bool GetLocalTransformations( - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xfroms); - - /** Compute multiple world transforms in parallel.*/ - bool GetLocalToWorldTransforms( - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms); - - /* Compute constraint transforms given a common constraint name - for all prims. Constraint transforms not cached.*/ - bool GetConstraintTransforms( - const TfToken& constraint, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms); - - /* Given tokens representing *full* names of attributes - (I.e., including the namespace), compute constraint transforms. - Constraint transforms not cached.*/ - bool GetConstraintTransforms( - const UT_Array& constraints, - const UT_Array& prims, - const GusdDefaultArray& times, - UT_Matrix4D* xforms); - - struct XformInfo : public UT_CappedItem - { - enum Flags - { - FLAGS_LOCAL_MAYBE_TIMEVARYING=0x1, - FLAGS_WORLD_MAYBE_TIMEVARYING=0x2, - FLAGS_HAS_PARENT_XFORM=0x4 - }; - - XformInfo(const UsdGeomXformable& xf) - : UT_CappedItem(), query(xf), _flags(0) {} - - virtual ~XformInfo() {} - - virtual int64 getMemoryUsage() const { return sizeof(*this); } - - void ComputeFlags(const UsdPrim& prim, - GusdUSD_XformCache& cache); - - SYS_FORCE_INLINE bool LocalXformIsMaybeTimeVarying() const - { return _flags&FLAGS_LOCAL_MAYBE_TIMEVARYING; } - - SYS_FORCE_INLINE bool WorldXformIsMaybeTimeVarying() const - { return _flags&FLAGS_WORLD_MAYBE_TIMEVARYING; } - - SYS_FORCE_INLINE bool HasParentXform() const - { return _flags&FLAGS_HAS_PARENT_XFORM; } - - const UsdGeomXformable::XformQuery query; - private: - int _flags; - }; - typedef UT_IntrusivePtr XformInfoHandle; - - - GUSD_API - XformInfoHandle GetXformInfo(const UsdPrim& prim); - - GUSD_API - virtual void Clear() override; - - GUSD_API - virtual int64 Clear(const UT_StringSet& paths) override; - -private: - bool _GetLocalTransformation(const UsdPrim& prim, - UsdTimeCode time, - UT_Matrix4D& xform, - const XformInfoHandle& info); - - - -private: - GusdUT_CappedCache _xforms, _worldXforms, _xformInfos; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_USD_XFORM_CACHE_H*/ diff --git a/third_party/houdini/gusd/UT_Assert.h b/third_party/houdini/gusd/UT_Assert.h deleted file mode 100644 index fda6bf8a7e..0000000000 --- a/third_party/houdini/gusd/UT_Assert.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_UT_ASSERT_H -#define GUSD_UT_ASSERT_H - -#include - -#include "pxr/pxr.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** Helper for adding inline assertions to validate that a pointer is non-null. - - Example: - - @code - OP_Node* cwd = GusdUTverify_ptr(OPgetDirector())->getCwd(); - @endcode */ -template -T* GusdUTverify_ptr(T* ptr) -{ - UT_ASSERT_P(ptr != NULL); - return ptr; -} - - -/** Helper for inline assertions of the validity of some non-pointer type. - - Example: - @code - UsdStage stage = GusdUTverify_val(GetStage(...)); - @endcode */ -template -T& GusdUTverify_val(T&& val) -{ - UT_ASSERT_P((bool)val); - return val; -} - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /*GUSD_UT_ASSERT_H*/ diff --git a/third_party/houdini/gusd/UT_CappedCache.h b/third_party/houdini/gusd/UT_CappedCache.h deleted file mode 100644 index 881ff9d3c4..0000000000 --- a/third_party/houdini/gusd/UT_CappedCache.h +++ /dev/null @@ -1,190 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief -*/ -#ifndef GUSD_UT_CAPPED_CACHE_H -#define GUSD_UT_CAPPED_CACHE_H - -#include "pxr/pxr.h" - -#include -#include -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/** Convenience wrapper around UT_CappedKey. - This allows keys to be constructed in TBB's style. - These can only be used in a UT_CappedCache if all keys - in the cache have the same type.*/ -template > -class GusdUT_CappedKey : public UT_CappedKey -{ -public: - GusdUT_CappedKey() : UT_CappedKey() {} - GusdUT_CappedKey(const KeyT& key) : UT_CappedKey(), _key(key) {} - - virtual ~GusdUT_CappedKey() {} - - virtual UT_CappedKey* duplicate() const - { return new GusdUT_CappedKey(_key); } - - virtual unsigned getHash() const - { return HashCompare().hash(_key); } - - virtual bool isEqual(const UT_CappedKey& key) const - { - return HashCompare().equal(_key, - UTverify_cast( - &key)->_key); - } - - KeyT* operator->() { return &_key; } - const KeyT* operator->() const { return &_key; } - KeyT& operator*() { return _key; } - const KeyT& operator*() const { return _key; } - -private: - KeyT _key; -}; - - -/** Variant of UT_CappedCache that improves on item construction. - This adds in a mechanism for locking items during construction, - to prevent multiple threads from performing the same work to - initialize cache items.*/ -class GusdUT_CappedCache : public UT_CappedCache -{ -public: - GusdUT_CappedCache(const char* name, int64 size_in_mb=32) - : UT_CappedCache(name, size_in_mb) {} - ~GusdUT_CappedCache() {} - - template - UT_IntrusivePtr Find(const UT_CappedKey& key); - - template - UT_IntrusivePtr FindOrCreate(const UT_CappedKey& key, - const Creator& creator, - Args&... args); - - template - bool FindVal(const UT_CappedKey& key); - - template - bool FindOrCreateVal(const UT_CappedKey& key, - const Creator& creator, - Args&... args); - - template - int64 ClearEntries(const MatchFn& matchFn); - -private: - - struct _HashCompare - { - static size_t hash(const UT_CappedKeyHandle& k) - { return (size_t)k->getHash(); } - static bool equal(const UT_CappedKeyHandle& a, - const UT_CappedKeyHandle& b) - { return a->isEqual(*b); } - }; - - - typedef UT_ConcurrentHashMap _ConstructMap; - _ConstructMap _constructMap; -}; - - -template -UT_IntrusivePtr -GusdUT_CappedCache::Find(const UT_CappedKey& key) -{ - if(UT_CappedItemHandle hnd = findItem(key)) - return UT_IntrusivePtr( - UTverify_cast(hnd.get())); - return UT_IntrusivePtr(); -} - - -template -UT_IntrusivePtr -GusdUT_CappedCache::FindOrCreate(const UT_CappedKey& key, - const Creator& creator, - Args&... args) -{ - if(auto item = Find(key)) - return item; - - UT_CappedKeyHandle keyHnd(key.duplicate()); - - _ConstructMap::accessor a; - if(_constructMap.insert(a, keyHnd)) { - // Make sure another thread didn't beat us to it. - a->second = findItem(key); - if(!a->second) { - if((a->second = creator(args...))) { - addItem(key, a->second); - } else { - _constructMap.erase(a); - return UT_IntrusivePtr(); - } - } - } - UT_IntrusivePtr item( - UTverify_cast(a->second.get())); - _constructMap.erase(a); - return item; -} - -template -int64 -GusdUT_CappedCache::ClearEntries(const MatchFn& matchFn) -{ - int64 freed = 0; - - auto traverseFn([&](const UT_CappedKeyHandle& key, - const UT_CappedItemHandle& item) - { - if(matchFn(key, item)) { - freed += item->getMemoryUsage(); - // XXX: deleteItem() is safe in threadSafeTraversal! - this->deleteItem(*key); - } - return true; - }); - threadSafeTraversal(traverseFn); - return freed; -} - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_UT_CAPPED_CACHE_H*/ diff --git a/third_party/houdini/gusd/UT_Gf.h b/third_party/houdini/gusd/UT_Gf.h deleted file mode 100644 index 6c2e825615..0000000000 --- a/third_party/houdini/gusd/UT_Gf.h +++ /dev/null @@ -1,590 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_UT_GF_H -#define GUSD_UT_GF_H - -#include "pxr/pxr.h" - -#include "UT_TypeTraits.h" - -// Conversion specializations require full defs for some types. -#include "pxr/base/gf/quaternion.h" -#include "pxr/base/gf/quatd.h" -#include "pxr/base/gf/quatf.h" -#include "pxr/base/gf/quath.h" -#include "pxr/base/gf/vec4d.h" -#include "pxr/base/gf/vec4f.h" - -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/// Helpers for working with Gf types (vectors, matrices, etc.) within the HDK. -struct GusdUT_Gf -{ - /// Struct providing info about type equivalence between - /// UT and Gf types. Each struct defines: - /// - /// \code - /// static const bool isSpecialized = true; - /// typedef ... GfType; - /// typedef ... UtType; - /// typedef ... AltType; // Type from the alternate API. - /// // Eg., if this is a UT type, it will be the Gf - /// // type, and vice versa. - /// \endcode - template - struct TypeEquivalence - { - static const bool isSpecialized = false; - }; - - /// Struct defining whether or not a type is valid for direct casting to - /// other types. We explicitly disable casting for types that require some - /// kind of data manipulation when going in-between UT and Gf. - template - struct Castable - { - static const bool value = true; - }; - - /// Helpers for casting between UT and Gf types. The cast can go either way. - /// This can be done with a reinterpret cast, but this cast adds a bit of - /// extra compile-time checks to make sure that this really is safe. - /// - /// These cast methods only take a single template argument. The output - /// is cast to the equivalent type from the alternate API. For example, - /// if given a UT_Matrix4D, the cast is to a GfMatrix4d, and vice versa. - /// - /// \note Any type used here must be declared with a specialization of - /// GusdUT_TypeTraits::PODTuple (see GUSD_DECLARE_POD_TUPLE). - /// - /// Examples: - /// - /// \code - /// // implicit cast of Gf->UT - /// UT_Matrix4D& mx = GusdUT_Gf::Cast(gfMatrix4dInstance); - /// UT_Matrix4D* mx = GusdUT_Gf::Cast(gfMatrix4dInstancePtr); - /// const UT_Matrix4D& mx = GusdUT_Gf::Cast(gfMatrix4dInstanceConst); - /// const UT_Matrix4D* mx = GusdUT_Gf::Cast(gfMatrix4dInstancePtrConst); - /// - /// // implicit cast of UT->Gf - /// GfMatrix4d& mx = GusdUT_Gf::Cast(utMatrix4dInstance); - /// GfMatrix4d* mx = GusdUT_Gf::Cast(utMatrix4dInstancePtr); - /// const GfMatrix4d& mx = GusdUT_Gf::Cast(utMatrix4dInstanceConst); - /// const GfMatrix4d* mx = GusdUT_Gf::Cast(utMatrix4dInstancePtrConst); - /// - /// // compile error! types are not bitwise compatible - /// UT_Matrix4D src; - /// GfMatrix4f& mx = GusdUT_Gf::Cast(src); - /// - /// // compile error! discards cv-qualifier. - /// const UT_Matrix4F& src = ...; - /// GfMatrix4f& mx = GusdUT_Gf::Cast(src); - /// \endcode - /// @{ - template - static inline const typename - TypeEquivalence::AltType* Cast(const T* val); - - template - static inline typename - TypeEquivalence::AltType* Cast(T* val); - - template - static inline const typename - TypeEquivalence::AltType& Cast(const T& val); - - template - static inline typename - TypeEquivalence::AltType& Cast(T& val); - /// @} - - /// Explicit casts between UT and Gf types. - /// This is just like the implicit cast methods, except that the source and - /// target types are explicitly specified via template arguments. - /// This can be used for casting between types when the types aren't exact - /// counterparts. For instance, we can safely cast a GfMatrix2d to a - /// UT_Vector4D, even though UT_Vector4D is not UT's equivalence type for - /// GfMatrix2d. - /// - /// @{ - template - static inline const TO* Cast(const FROM* val); - - template - static inline TO* Cast(FROM* val); - - template - static inline const TO& Cast(const FROM& val); - - template - static inline TO& Cast(FROM& val); - /// @} - - - /// Convert between UT and Gf types. This works for any pod tuples that have - /// equivalent tuple sizes, even if their underlying precision differs. - /// - /// \note Any type used here must be declared with a specialization of - /// GusdUT_TypeTraits::PODTuple (see GUSD_DECLARE_POD_TUPLE). - template - static inline void Convert(const FROM& from, TO& to); - - - /// Conversions between GF and UT quaternions. - /// Gf and UT have a different ordering of the real component, - /// hence the need for speciailized converters. - /// - /// XXX: 4d vector types are sometimes used in place of GfQuaternion, - /// hence their inclusion here. That is primarily the fault of USD: - /// if USD gets a real quaternion type, we can clean these up. - /// @{ - template - static inline void Convert(const GfQuaternion& from, UT_QuaternionT& to); - - template - static inline void Convert(const GfQuatd& from, UT_QuaternionT& to); - - template - static inline void Convert(const GfQuatf& from, UT_QuaternionT& to); - - template - static inline void Convert(const GfQuath& from, UT_QuaternionT& to); - - template - static inline void Convert(const GfVec4d& from, UT_QuaternionT& to); - - template - static inline void Convert(const GfVec4f& from, UT_QuaternionT& to); - - template - static inline void Convert(const UT_QuaternionT& from, GfQuaternion& to); - - template - static inline void Convert(const UT_QuaternionT& from, GfQuatd& to); - - template - static inline void Convert(const UT_QuaternionT& from, GfQuatf& to); - - template - static inline void Convert(const UT_QuaternionT& from, GfQuath& to); - - template - static inline void Convert(const UT_QuaternionT& from, GfVec4d& to); - - template - static inline void Convert(const UT_QuaternionT& from, GfVec4f& to); - /// @} - -private: - template - static inline void _ConvertQuat(const GFQUAT& from, UT_QuaternionT& to); - - template - static inline void _AssertIsPodTuple(); - - template - static inline void _AssertCanCast(); - - // Our casting tricks assume that the typedefs set in SYS_Types are - // referencing the types we think they are. Verify our assumptions. - static_assert(std::is_same::value, - "std::is_same::value"); - static_assert(std::is_same::value, - "std::is_same::value"); -}; - - -/// Declare a type as being uncastable. -#define _GUSDUT_DECLARE_UNCASTABLE(TYPE) \ - template <> \ - struct GusdUT_Gf::Castable \ - { \ - static const bool value = false; \ - }; - - -/// Declare a partial type equivalence. This specifies a one-way -/// type equivalence. -#define _GUSDUT_DECLARE_PARTIAL_EQUIVALENCE(TYPE,GFTYPE,UTTYPE,ALTTYPE) \ - template <> \ - struct GusdUT_Gf::TypeEquivalence { \ - static const bool isSpecialized = true; \ - using GfType = GFTYPE; \ - using UtType = UTTYPE; \ - using AltType = ALTTYPE; \ - }; - -/// Declare type equivalent between UT and Gf types. -/// Only a single equivalence relationship may be defined per type. -/// -/// The type info for both types must be declared first! -#define _GUSDUT_DECLARE_EQUIVALENCE(GFTYPE,UTTYPE) \ - _GUSDUT_DECLARE_PARTIAL_EQUIVALENCE(GFTYPE,GFTYPE,UTTYPE,UTTYPE); \ - _GUSDUT_DECLARE_PARTIAL_EQUIVALENCE(UTTYPE,GFTYPE,UTTYPE,GFTYPE); - -/// Declare POD tuples for Gf types. -GUSDUT_DECLARE_POD_TUPLE(class GfVec2h, fpreal16, 2); -GUSDUT_DECLARE_POD_TUPLE(class GfVec3h, fpreal16, 3); -GUSDUT_DECLARE_POD_TUPLE(class GfVec4h, fpreal16, 4); - -GUSDUT_DECLARE_POD_TUPLE(class GfVec2f, fpreal32, 2); -GUSDUT_DECLARE_POD_TUPLE(class GfVec3f, fpreal32, 3); -GUSDUT_DECLARE_POD_TUPLE(class GfVec4f, fpreal32, 4); - -GUSDUT_DECLARE_POD_TUPLE(class GfVec2d, fpreal64, 2); -GUSDUT_DECLARE_POD_TUPLE(class GfVec3d, fpreal64, 3); -GUSDUT_DECLARE_POD_TUPLE(class GfVec4d, fpreal64, 4); - -GUSDUT_DECLARE_POD_TUPLE(class GfVec2i, int32, 2); -GUSDUT_DECLARE_POD_TUPLE(class GfVec3i, int32, 3); -GUSDUT_DECLARE_POD_TUPLE(class GfVec4i, int32, 4); - -GUSDUT_DECLARE_POD_TUPLE(class GfQuath, fpreal16, 4); -GUSDUT_DECLARE_POD_TUPLE(class GfQuatf, fpreal32, 4); -GUSDUT_DECLARE_POD_TUPLE(class GfQuatd, fpreal64, 4); - -GUSDUT_DECLARE_POD_TUPLE(class GfMatrix2f, fpreal32, 4); -GUSDUT_DECLARE_POD_TUPLE(class GfMatrix3f, fpreal32, 9); -GUSDUT_DECLARE_POD_TUPLE(class GfMatrix4f, fpreal32, 16); - -GUSDUT_DECLARE_POD_TUPLE(class GfMatrix2d, fpreal64, 4); -GUSDUT_DECLARE_POD_TUPLE(class GfMatrix3d, fpreal64, 9); -GUSDUT_DECLARE_POD_TUPLE(class GfMatrix4d, fpreal64, 16); - -PXR_NAMESPACE_CLOSE_SCOPE - -/// Declare types as PODs, so that UT_Arrays of the types can be optimized. -/// This is done to ensure that Gf types are handled in the same manner as -/// UT types: the same is done for UT types as well (see UT/UT_VectorTypes.h). - -SYS_DECLARE_IS_POD(PXR_NS::GfHalf); - -SYS_DECLARE_IS_POD(PXR_NS::GfVec2h); -SYS_DECLARE_IS_POD(PXR_NS::GfVec3h); -SYS_DECLARE_IS_POD(PXR_NS::GfVec4h); - -SYS_DECLARE_IS_POD(PXR_NS::GfVec2f); -SYS_DECLARE_IS_POD(PXR_NS::GfVec3f); -SYS_DECLARE_IS_POD(PXR_NS::GfVec4f); - -SYS_DECLARE_IS_POD(PXR_NS::GfVec2d); -SYS_DECLARE_IS_POD(PXR_NS::GfVec3d); -SYS_DECLARE_IS_POD(PXR_NS::GfVec4d); - -SYS_DECLARE_IS_POD(PXR_NS::GfVec2i); -SYS_DECLARE_IS_POD(PXR_NS::GfVec3i); -SYS_DECLARE_IS_POD(PXR_NS::GfVec4i); - -SYS_DECLARE_IS_POD(PXR_NS::GfQuath); -SYS_DECLARE_IS_POD(PXR_NS::GfQuatf); -SYS_DECLARE_IS_POD(PXR_NS::GfQuatd); - -SYS_DECLARE_IS_POD(PXR_NS::GfMatrix2f); -SYS_DECLARE_IS_POD(PXR_NS::GfMatrix3f); -SYS_DECLARE_IS_POD(PXR_NS::GfMatrix4f); - -SYS_DECLARE_IS_POD(PXR_NS::GfMatrix2d); -SYS_DECLARE_IS_POD(PXR_NS::GfMatrix3d); -SYS_DECLARE_IS_POD(PXR_NS::GfMatrix4d); - -PXR_NAMESPACE_OPEN_SCOPE - -// No casting on quaternions; real component is ordered -// in a different way between UT and Gf. -_GUSDUT_DECLARE_UNCASTABLE(class GfQuaternion); -_GUSDUT_DECLARE_UNCASTABLE(class GfQuatf); -_GUSDUT_DECLARE_UNCASTABLE(class GfQuatd); -_GUSDUT_DECLARE_UNCASTABLE(UT_QuaternionF); -_GUSDUT_DECLARE_UNCASTABLE(UT_QuaternionD); -#if SYS_VERSION_FULL_INT >= 0x11000000 -_GUSDUT_DECLARE_UNCASTABLE(UT_QuaternionH); -#endif - -// Declare type correspondances between Gf and UT. -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec2h, UT_Vector2H); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec3h, UT_Vector3H); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec4h, UT_Vector4H); - -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec2d, UT_Vector2D); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec3d, UT_Vector3D); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec4d, UT_Vector4D); - -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec2f, UT_Vector2F); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec3f, UT_Vector3F); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec4f, UT_Vector4F); - -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec2i, UT_Vector2i); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec3i, UT_Vector3i); -_GUSDUT_DECLARE_EQUIVALENCE(class GfVec4i, UT_Vector4i); - -_GUSDUT_DECLARE_EQUIVALENCE(class GfQuatd, UT_QuaternionD); -_GUSDUT_DECLARE_EQUIVALENCE(class GfQuatf, UT_QuaternionF); -#if SYS_VERSION_FULL_INT >= 0x11000000 -_GUSDUT_DECLARE_EQUIVALENCE(class GfQuath, UT_QuaternionH); -#endif - -_GUSDUT_DECLARE_EQUIVALENCE(class GfMatrix2d, UT_Matrix2D); -_GUSDUT_DECLARE_EQUIVALENCE(class GfMatrix3d, UT_Matrix3D); -_GUSDUT_DECLARE_EQUIVALENCE(class GfMatrix4d, UT_Matrix4D); - -_GUSDUT_DECLARE_EQUIVALENCE(class GfMatrix2f, UT_Matrix2F); -_GUSDUT_DECLARE_EQUIVALENCE(class GfMatrix3f, UT_Matrix3F); -_GUSDUT_DECLARE_EQUIVALENCE(class GfMatrix4f, UT_Matrix4F); - - -template -void -GusdUT_Gf::_AssertIsPodTuple() -{ - static_assert(GusdIsPodTuple(), "Type is not declared as a POD-tuple"); -} - - -template -void -GusdUT_Gf::_AssertCanCast() -{ - _AssertIsPodTuple(); - _AssertIsPodTuple(); - static_assert(Castable::value, "Source is not castable"); - static_assert(Castable::value, "Output is not castable"); - static_assert(GusdPodTuplesAreBitwiseCompatible(), - "Types in cast are not bitwise compatible"); -} - - -template -const TO* -GusdUT_Gf::Cast(const FROM* val) -{ - _AssertCanCast(); - return reinterpret_cast(val); -} - - -template -TO* -GusdUT_Gf::Cast(FROM* val) -{ - _AssertCanCast(); - return reinterpret_cast(val); -} - - -template -const TO& -GusdUT_Gf::Cast(const FROM& val) -{ - _AssertCanCast(); - return reinterpret_cast(val); -} - - -template -TO& -GusdUT_Gf::Cast(FROM& val) -{ - _AssertCanCast(); - return reinterpret_cast(val); -} - - -template -typename GusdUT_Gf::TypeEquivalence::AltType& -GusdUT_Gf::Cast(T& val) -{ - _AssertIsPodTuple(); - return Cast::AltType>(val); -} - - -template -const typename GusdUT_Gf::TypeEquivalence::AltType& -GusdUT_Gf::Cast(const T& val) -{ - _AssertIsPodTuple(); - return Cast::AltType>(val); -} - - -template -typename GusdUT_Gf::TypeEquivalence::AltType* -GusdUT_Gf::Cast(T* val) -{ - _AssertIsPodTuple(); - return Cast::AltType>(val); -} - - -template -const typename GusdUT_Gf::TypeEquivalence::AltType* -GusdUT_Gf::Cast(const T* val) -{ - _AssertIsPodTuple(); - return Cast::AltType>(val); -} - - -template -void -GusdUT_Gf::Convert(const FROM& from, TO& to) -{ - using FromPodType = typename GusdPodTupleTraits::ValueType; - using ToPodType = typename GusdPodTupleTraits::ValueType; - - _AssertIsPodTuple(); - _AssertIsPodTuple(); - static_assert(GusdPodTuplesAreCompatible(), - "Types are not compatible (mismatched tuple sizes)"); - - const auto* src = reinterpret_cast(&from); - ToPodType* dst = reinterpret_cast(&to); - - for (int i = 0; i < GusdGetTupleSize(); ++i) { - dst[i] = static_cast(src[i]); - } -} - - -template -void -GusdUT_Gf::_ConvertQuat(const GFQUAT& from, UT_QuaternionT& to) -{ - reinterpret_cast&>(to) = Cast(from.GetImaginary()); - to(3) = from.GetReal(); -} - - -template -void -GusdUT_Gf::Convert(const GfQuaternion& from, UT_QuaternionT& to) -{ - return _ConvertQuat(from, to); -} - - -template -void -GusdUT_Gf::Convert(const GfQuatd& from, UT_QuaternionT& to) -{ - return _ConvertQuat(from, to); -} - - -template -void -GusdUT_Gf::Convert(const GfQuatf& from, UT_QuaternionT& to) -{ - return _ConvertQuat(from, to); -} - - -template -void -GusdUT_Gf::Convert(const GfQuath& from, UT_QuaternionT& to) -{ - return _ConvertQuat(from, to); -} - - -template -void -GusdUT_Gf::Convert(const GfVec4d& from, UT_QuaternionT& to) -{ - to = UT_QuaternionT(from[1],from[2],from[3],from[0]); -} - - -template -void -GusdUT_Gf::Convert(const GfVec4f& from, UT_QuaternionT& to) -{ - to = UT_QuaternionT(from[1],from[2],from[3],from[0]); -} - - -template -void -GusdUT_Gf::Convert(const UT_QuaternionT& from, GfQuaternion& to) -{ - to.SetReal(from.w()); - to.SetImaginary(GfVec3d(from.x(), from.y(), from.z())); -} - - -template -void -GusdUT_Gf::Convert(const UT_QuaternionT& from, GfQuatd& to) -{ - to.SetReal(from.w()); - to.SetImaginary(GfVec3d(from.x(), from.y(), from.z())); -} - - -template -void -GusdUT_Gf::Convert(const UT_QuaternionT& from, GfQuatf& to) -{ - to.SetReal(from.w()); - to.SetImaginary(GfVec3f(from.x(), from.y(), from.z())); -} - - -template -void -GusdUT_Gf::Convert(const UT_QuaternionT& from, GfQuath& to) -{ - to.SetReal(GfHalf(from.w())); - to.SetImaginary( - GfVec3h(GfHalf(from.x()), GfHalf(from.y()), GfHalf(from.z()))); -} - - -template -void -GusdUT_Gf::Convert(const UT_QuaternionT& from, GfVec4d& to) -{ - to = GfVec4d(from.w(), from.x(), from.y(), from.z()); -} - - -template -void -GusdUT_Gf::Convert(const UT_QuaternionT& from, GfVec4f& to) -{ - to = GfVec4f(from.w(), from.x(), from.y(), from.z()); -} - - -#undef _GUSDUT_DECLARE_UNCASTABLE -#undef _GUSDUT_DECLARE_PARTIAL_EQUIVALENCE -#undef _GUSDUT_DECLARE_EQUIVALENCE - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_UT_GF_H*/ diff --git a/third_party/houdini/gusd/UT_StaticInit.h b/third_party/houdini/gusd/UT_StaticInit.h deleted file mode 100644 index 841ee2198c..0000000000 --- a/third_party/houdini/gusd/UT_StaticInit.h +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_UT_STATIC_INIT_H -#define GUSD_UT_STATIC_INIT_H - -#include "pxr/pxr.h" - -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/** Helper for creating a static value, whose construction - is deferred and backed by a lock. - This is similar to UT_SingletonWithLock, except that the value held - is the result of calling method, rather than constructing an object. - - Example usage: - - @code - T* someFn(); - static auto staticVal(GusdUT_StaticVal(someFn)); - - // Function is not exec'd until accessed. - // To access: - T* val = *staticVal; - // Or: - staticVal->method(); - @endcode */ -template -struct GusdUT_StaticValHolder -{ -public: - typedef GusdUT_StaticValHolder This; - using T = typename std::result_of::type; - - GusdUT_StaticValHolder(Fn& fn) - : _val(NULL), _fn(fn), _lock() {} - - GusdUT_StaticValHolder(This&& o) noexcept - : _fn(o._fn) - { - if(_val) delete _val; - _val = o._val; - } - - ~GusdUT_StaticValHolder() - { if(_val) delete _val; } - - T& operator*() { return *get(); } - T* operator->() { return get(); } - - T* get() - { - if(!_val) { - UT_AutoLock lock(_lock); - if(!_val) { - _val = new T(); - *_val = _fn(); - } - } - return _val; - } - -private: - Fn& _fn; - UT_Lock _lock; - T* _val; -}; - -/** Helper for constructing static values. - This allows automatic template deduction of the function.*/ -template -GusdUT_StaticValHolder -GusdUT_StaticVal(const Fn& fn) -{ - return GusdUT_StaticValHolder(fn); -} - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /*GUSD_UT_STATIC_INIT_H*/ diff --git a/third_party/houdini/gusd/UT_TypeTraits.cpp b/third_party/houdini/gusd/UT_TypeTraits.cpp deleted file mode 100644 index 40df8ffe08..0000000000 --- a/third_party/houdini/gusd/UT_TypeTraits.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "UT_TypeTraits.h" - -#include -#include -#include -#include -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -// Make sure that the HDK doesn't change out the UT types on us, -// since we have hard-coded expectations of theses types. -// -// We don't do this in UT_TypeTraits.h because this level of validation -// requires the full type definitions, whereas we only want forward -// declarations in the header. -#define _VERIFY_TYPE(TYPE) \ - static_assert(SYSisSame::ValueType, \ - TYPE::value_type>(), \ - "Type declared for POD tuple does not match HDK type"); \ - static_assert(TYPE::tuple_size == GusdGetTupleSize(), \ - "Tuple size declared for POD tuple does not match " \ - "tuple size declared in HDK."); - -_VERIFY_TYPE(UT_Matrix2F); -_VERIFY_TYPE(UT_Matrix3F); -_VERIFY_TYPE(UT_Matrix4F); - -_VERIFY_TYPE(UT_Matrix2D); -_VERIFY_TYPE(UT_Matrix3D); -_VERIFY_TYPE(UT_Matrix4D); - -_VERIFY_TYPE(UT_QuaternionF); -_VERIFY_TYPE(UT_QuaternionD); -#if SYS_VERSION_FULL_INT >= 0x11000000 -_VERIFY_TYPE(UT_QuaternionH); -#endif - -_VERIFY_TYPE(UT_Vector2H); -_VERIFY_TYPE(UT_Vector3H); -_VERIFY_TYPE(UT_Vector4H); - -_VERIFY_TYPE(UT_Vector2F); -_VERIFY_TYPE(UT_Vector3F); -_VERIFY_TYPE(UT_Vector4F); - -_VERIFY_TYPE(UT_Vector2D); -_VERIFY_TYPE(UT_Vector3D); -_VERIFY_TYPE(UT_Vector4D); - -_VERIFY_TYPE(UT_Vector2i); -_VERIFY_TYPE(UT_Vector3i); -_VERIFY_TYPE(UT_Vector4i); - -_VERIFY_TYPE(UT_Vector2I); -_VERIFY_TYPE(UT_Vector3I); -_VERIFY_TYPE(UT_Vector4I); - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/UT_TypeTraits.h b/third_party/houdini/gusd/UT_TypeTraits.h deleted file mode 100644 index 45c524aa27..0000000000 --- a/third_party/houdini/gusd/UT_TypeTraits.h +++ /dev/null @@ -1,146 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_UT_TYPE_TRAITS_H -#define GUSD_UT_TYPE_TRAITS_H - -#include "pxr/pxr.h" - -#include -#include -#include -#include - -#include "pxr/base/gf/half.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/// Traits for a POD tuple; fixed-size tuples of a single POD type. -/// These are defined in order to have an API for type traits shared between -/// both the Houdini's UT types and Gf types. -/// Use GUSDUT_DECLARE_POD_TUPLE() to declare the type info for a new type. -template -struct GusdPodTupleTraits -{ - using ValueType = void; - static const int tupleSize = 1; -}; - - -/// Helper for declaring a POD tuple. -#define GUSDUT_DECLARE_POD_TUPLE(TYPE, VALUETYPE, TUPLESIZE) \ - template <> \ - struct GusdPodTupleTraits { \ - static const int tupleSize = TUPLESIZE; \ - using ValueType = VALUETYPE; \ - }; - - -/// Returns true if a type is a POD tuple. -template -constexpr bool GusdIsPodTuple() -{ - return !SYSisSame::ValueType, void>(); -} - - -/// Returns the tuples ize of a POD tuple. -template -constexpr int GusdGetTupleSize() -{ - return GusdPodTupleTraits::tupleSize; -} - - -/// Returns true if two POD tuples are compatible -/// (I.e., same tuple size, not necessarily same types). -template -constexpr bool GusdPodTuplesAreCompatible() -{ - return GusdGetTupleSize() == GusdGetTupleSize(); -} - - -/// Returns true if two POD tuples have identical memory layouts. -template -constexpr bool GusdPodTuplesAreBitwiseCompatible() -{ - return GusdPodTuplesAreCompatible() && - SYSisSame::ValueType, - typename GusdPodTupleTraits::ValueType>(); -} - - -/// Declare traits on core types. -GUSDUT_DECLARE_POD_TUPLE(UT_Vector2H, fpreal16, 2); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector3H, fpreal16, 3); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector4H, fpreal16, 4); - -GUSDUT_DECLARE_POD_TUPLE(UT_Vector2F, fpreal32, 2); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector3F, fpreal32, 3); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector4F, fpreal32, 4); - -GUSDUT_DECLARE_POD_TUPLE(UT_Vector2D, fpreal64, 2); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector3D, fpreal64, 3); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector4D, fpreal64, 4); - -GUSDUT_DECLARE_POD_TUPLE(UT_Vector2I, int64, 2); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector3I, int64, 3); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector4I, int64, 4); - -GUSDUT_DECLARE_POD_TUPLE(UT_Vector2i, int32, 2); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector3i, int32, 3); -GUSDUT_DECLARE_POD_TUPLE(UT_Vector4i, int32, 4); - -#if SYS_VERSION_FULL_INT >= 0x11000000 -GUSDUT_DECLARE_POD_TUPLE(UT_QuaternionH, fpreal16, 4); -#endif -GUSDUT_DECLARE_POD_TUPLE(UT_QuaternionF, fpreal32, 4); -GUSDUT_DECLARE_POD_TUPLE(UT_QuaternionD, fpreal64, 4); - -GUSDUT_DECLARE_POD_TUPLE(UT_Matrix2F, fpreal32, 4); -GUSDUT_DECLARE_POD_TUPLE(UT_Matrix3F, fpreal32, 9); -GUSDUT_DECLARE_POD_TUPLE(UT_Matrix4F, fpreal32, 16); - -GUSDUT_DECLARE_POD_TUPLE(UT_Matrix2D, fpreal64, 4); -GUSDUT_DECLARE_POD_TUPLE(UT_Matrix3D, fpreal64, 9); -GUSDUT_DECLARE_POD_TUPLE(UT_Matrix4D, fpreal64, 16); - -/// Declare PODs as POD tuples of tupleSize=1. -GUSDUT_DECLARE_POD_TUPLE(bool, bool, 1); -GUSDUT_DECLARE_POD_TUPLE(uint8, uint8, 1); -GUSDUT_DECLARE_POD_TUPLE(uint16, uint16, 1); -GUSDUT_DECLARE_POD_TUPLE(uint32, uint32, 1); -GUSDUT_DECLARE_POD_TUPLE(uint64, uint64, 1); -GUSDUT_DECLARE_POD_TUPLE(int8, int8, 1); -GUSDUT_DECLARE_POD_TUPLE(int16, int16, 1); -GUSDUT_DECLARE_POD_TUPLE(int32, int32, 1); -GUSDUT_DECLARE_POD_TUPLE(int64, int64, 1); -GUSDUT_DECLARE_POD_TUPLE(fpreal16, fpreal16, 1); -GUSDUT_DECLARE_POD_TUPLE(fpreal32, fpreal32, 1); -GUSDUT_DECLARE_POD_TUPLE(fpreal64, fpreal64, 1); -GUSDUT_DECLARE_POD_TUPLE(GfHalf, GfHalf, 1); - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_UT_TYPE_TRAITS_H diff --git a/third_party/houdini/gusd/UT_Version.h b/third_party/houdini/gusd/UT_Version.h deleted file mode 100644 index 73e742395f..0000000000 --- a/third_party/houdini/gusd/UT_Version.h +++ /dev/null @@ -1,111 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief Helpers for dealing with versioning in the HDK. -*/ -#ifndef GUSD_UT_VERSION_H -#define GUSD_UT_VERSION_H - -#include "pxr/pxr.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/** Max number of versions for any component (major,minor,etc.) of the - current build. Should be at least 1K under current conventions.*/ -#define _GUSD_MAX_VERS 10000 - -/** Construct a single, consolidated integer value that allows legal - comparison between the combination of major+minor+build+patch components.*/ -#define _GUSD_VER_INT(major,minor,build,patch) \ - (major*_GUSD_MAX_VERS*_GUSD_MAX_VERS*_GUSD_MAX_VERS + \ - minor*_GUSD_MAX_VERS*_GUSD_MAX_VERS + \ - build*_GUSD_MAX_VERS + patch) - -/** Construct a consolidated version integer for the current Houdini version. - Each macro specifies a different level of granularity. - @{ */ -#define _GUSD_CURR_VER_INT_1 _GUSD_VER_INT(UT_MAJOR_VERSION_INT,0,0,0) - -#define _GUSD_CURR_VER_INT_2 _GUSD_VER_INT(UT_MAJOR_VERSION_INT, \ - UT_MINOR_VERSION_INT,0,0) - -#define _GUSD_CURR_VER_INT_3 _GUSD_VER_INT(UT_MAJOR_VERSION_INT, \ - UT_MINOR_VERSION_INT, \ - UT_BUILD_VERSION_INT,0) - -#define _GUSD_CURR_VER_INT_4 _GUSD_VER_INT(UT_MAJOR_VERSION_INT, \ - UT_MINOR_VERSION_INT, \ - UT_BUILD_VERSION_INT, \ - UT_PATCH_VERSION_INT) -/* @} */ - -/** Compare the current Houdini version against some other version. - - @a op should be a comparison operator (<,>,...). The @a major, @a minor,... - args form the right-hand side of the comparison. - - These are typically used to simplify expressions that are used to control - compilation that must change from version to version. The different macros - each compare the version at a different level of granularity, from the major - version all the way down to the patch. - - Example usage: - @code - #if (GUSD_VER_CMP_2(>=, 13, 256)) - // special code path - ... - @endcode - - This is equivalent to the comparison, "major.minor >= 13.256" - - @note: Only the components of the version int specified in the comparison - operator are compared. For example, take the following expression: - - @code - GUSD_VER_CMP_2(>, 13, 1) - @endcode - - The expression above will evaluate to _false_ when the internal Houdini - version is 13.1.211, because only the major and minor components are - being compared; any build difference is ignored. - @{ */ -#define GUSD_VER_CMP_1(op, major) \ - _GUSD_CURR_VER_INT_1 op _GUSD_VER_INT(major,0,0,0) - -#define GUSD_VER_CMP_2(op, major, minor) \ - _GUSD_CURR_VER_INT_2 op _GUSD_VER_INT(major,minor,0,0) - -#define GUSD_VER_CMP_3(op, major, minor, build) \ - _GUSD_CURR_VER_INT_3 op _GUSD_VER_INT(major,minor,build,0) - -#define GUSD_VER_CMP_4(op, major, minor, build, patch) \ - _GUSD_CURR_VER_INT_4 op _GUSD_VER_INT(major,minor,build,patch) -/** @} */ - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /* GUSD_UT_VERSION_H */ diff --git a/third_party/houdini/gusd/UT_VtArray.h b/third_party/houdini/gusd/UT_VtArray.h deleted file mode 100644 index 9a4203190d..0000000000 --- a/third_party/houdini/gusd/UT_VtArray.h +++ /dev/null @@ -1,186 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_UT_VT_ARRAY_H -#define GUSD_UT_VT_ARRAY_H - -#include -#include - -#include "pxr/pxr.h" -#include "pxr/base/vt/array.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** Read-only wrapper to assist in read operations on a VtArray. - - This container is not meant to be an owner of the VtArray -- - only a temporary structure used when iterating over the array. - Hence, it retains a reference to the array, rather than holding - a shared pointer. The array must remain in memory while the - container is in use. - - Since this container is read-only on the referenced array, - it is guaranteed that none of its method will trigger copying - of that data.*/ -template -class GusdUT_VtArrayRO -{ -public: - typedef T ValueType; - typedef VtArray ArrayType; - - typedef typename ArrayType::const_iterator const_iterator; - typedef typename ArrayType::const_reverse_iterator const_reverse_iterator; - - GusdUT_VtArrayRO(const ArrayType& array) - : _array(array), _size(array.GetSize()), _data(array.cdata()) - { UT_ASSERT(_size == 0 || _data != NULL); } - - const T& operator()(exint i) const - { - UT_ASSERT_P(i >= 0 && i < _size); - return _data[i]; - } - - const ArrayType& operator*() const { return _array; } - - const ArrayType& array() const { return _array; } - - const T* data() const { return _data; } - - exint size() const { return _size; } - - const_iterator begin() const { return _array.begin(); } - const_iterator end() const { return _array.end(); } - const_reverse_iterator rbegin() const { return _array.rbegin(); } - const_reverse_iterator rend() const { return _array.rend(); } - -private: - const ArrayType& _array; - const T* _data; /*! Cached as an optimization.*/ - exint _size; -}; - - -/** Read-write wrapper on a VtArray. - - As with GusdUT_VtArrayRW, this does not own the VtArray, but rather - is a general tool for editing one, and so retains a reference to - the underyling array. The array must remain in memory while the - container is in use. */ -template -class GusdUT_VtArrayRW -{ -public: - typedef T ValueType; - typedef VtArray ArrayType; - - typedef typename ArrayType::iterator iterator; - typedef typename ArrayType::reverse_iterator reverse_iterator; - typedef typename ArrayType::const_iterator const_iterator; - typedef typename ArrayType::const_reverse_iterator const_reverse_iterator; - - GusdUT_VtArrayRW(const ArrayType& array) : _array(array) - { update(); } - - const T& operator()(exint i) const - { - UT_ASSERT_P(i >= 0 && i < _size); - UT_ASSERT_P(_size == _array.GetSize()); - return _data[i]; - } - - T& operator()(exint i) - { - UT_ASSERT_P(i >= 0 && i < _size); - UT_ASSERT_P(_size == _array.GetSize()); - return _data[i]; - } - - /** Access to the underlying array. - @warning If you modify the arrays externally, you should - call update() before attempting to access the array again - through this container. - @{ */ - const ArrayType& operator*() const { return _array; } - ArrayType& operator*() { return _array; } - - const ArrayType& array() const { return _array; } - ArrayType& array() { return _array; } - /** @} */ - - const T* data() const { return _data; } - T* data() { return _data; } - - exint size() const { return _size; } - - void resize(exint size) - { - UT_ASSERT(size >= 0); - _array.resize(size); - update(); - } - - void reserve(exint size) - { - UT_ASSERT(size >= 0); - _array.reserve(size); - update(); - } - - void swap(ArrayType& array) - { - _array.swap(array); - update(); - } - - /** Update the state of the array to reflect changes - in the underlying array (eg., change in size).*/ - void update() - { - _data = _array.data(); - _size = _array.GetSize(); - UT_ASSSERT(_size == 0 || _data != NULL); - } - - const_iterator begin() const { return _array.begin(); } - const_iterator end() const { return _array.end(); } - iterator begin() { return _array.begin(); } - iterator end() { return _array.end(); } - - const_reverse_iterator rbegin() const { return _array.rbegin(); } - const_reverse_iterator rend() const { return _array.rend(); } - reverse_iterator rbegin() { return _array.rbegin(); } - reverse_iterator rend() { return _array.rend(); } - -private: - ArrayType& _array; - T* _data; /*! Cache as an optimization - (avoid referencing checks on every value lookup)*/ - exint _size; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_UT_VT_ARRAY_H*/ diff --git a/third_party/houdini/gusd/__init__.py b/third_party/houdini/gusd/__init__.py deleted file mode 100644 index 592ba01dac..0000000000 --- a/third_party/houdini/gusd/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright 2017 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# - -# We need to import Usd here to ensure certain Python wrappings that the -# Gusd module depends on are present. In particular, the c'tor for -# GusdStageOpts uses UsdStage::LoadAll as a default value, so we need to -# ensure this is present before import. -from pxr import Usd -import _gusd -del Usd - -from pxr import Tf -Tf.PrepareModule(_gusd, locals()) -del Tf - -try: - from . import __DOC - __DOC.Execute(locals()) - del __DOC -except Exception: - pass diff --git a/third_party/houdini/gusd/agentUtils.cpp b/third_party/houdini/gusd/agentUtils.cpp deleted file mode 100644 index 8ae36a5f63..0000000000 --- a/third_party/houdini/gusd/agentUtils.cpp +++ /dev/null @@ -1,719 +0,0 @@ -// -// Copyright 2019 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "agentUtils.h" - -#include "error.h" -#include "GU_PackedUSD.h" -#include "GU_USD.h" -#include "stageCache.h" -#include "UT_Gf.h" - -#include "pxr/base/gf/matrix4d.h" -#include "pxr/base/gf/matrix4f.h" -#include "pxr/base/tf/span.h" - -#include "pxr/usd/usdGeom/imageable.h" -#include "pxr/usd/usdSkel/binding.h" -#include "pxr/usd/usdSkel/skeleton.h" -#include "pxr/usd/usdSkel/skeletonQuery.h" -#include "pxr/usd/usdSkel/topology.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -// TODO: Encoding of namespaced properties is subject to change in -// future releases. -#define GUSD_SKEL_JOINTINDICES_ATTR "skel_jointIndices"_UTsh -#define GUSD_SKEL_JOINTWEIGHTS_ATTR "skel_jointWeights"_UTsh - - -namespace { - - -void -Gusd_ConvertTokensToStrings(const VtTokenArray& tokens, - UT_StringArray& strings) -{ - strings.setSize(tokens.size()); - for (size_t i = 0; i < tokens.size(); ++i) { - strings[i] = GusdUSD_Utils::TokenToStringHolder(tokens[i]); - } -} - - -/// Get names for each joint in \p skel, for use in a GU_AgentRig. -bool -Gusd_GetJointNames(const UsdSkelSkeleton& skel, - const VtTokenArray& joints, - VtTokenArray& jointNames) -{ - // Skeleton may optionally specify explicit joint names. - // If so, use those instead of paths. - if (skel.GetJointNamesAttr().Get(&jointNames)) { - if (jointNames.size() != joints.size()) { - GUSD_WARN().Msg("%s -- size of jointNames [%zu] " - "!= size of joints [%zu]", - skel.GetPrim().GetPath().GetText(), - jointNames.size(), joints.size()); - return false; - } - } else { - // No explicit joint names authored. - // Use the joint paths instead. - // Although the path tokens could be converted to SdfPath objects, - // and the tail of those paths could be extracted, they may not - // be unique: uniqueness is only required for full joint paths. - jointNames = joints; - } - return true; -} - - -/// Compute an ordered array giving the number of children for each -/// joint in \p topology. -bool -Gusd_GetChildCounts(const UsdSkelTopology& topology, - UT_IntArray& childCounts) -{ - childCounts.setSize(topology.GetNumJoints()); - childCounts.constant(0); - for (size_t i = 0; i < topology.GetNumJoints(); ++i) { - const int parent = topology.GetParent(i); - if (parent >= 0) { - UT_ASSERT_P(static_cast(parent) < topology.GetNumJoints()); - ++childCounts[parent]; - } - } - return true; -} - - -/// Compute an ordered array of the children of all joints in \p topology. -bool -Gusd_GetChildren(const UsdSkelTopology& topology, - const UT_IntArray& childCounts, - UT_IntArray& children) -{ - UT_ASSERT_P(childCounts.size() == topology.GetNumJoints()); - - const size_t numJoints = topology.GetNumJoints(); - - // Create an array of (nextChild,numAdded) per joint. - // This will be filled with (startIndex,0) for every joint, - // then used to to populate the 'children' array. - UT_Array > childIters(numJoints, numJoints); - exint startIndex = 0; - exint numChildren = 0; - for (exint i = 0; i < childCounts.size(); ++i) { - childIters[i].first = startIndex; - childIters[i].second = 0; - startIndex += childCounts[i]; - numChildren += childCounts[i]; - } - - // Now use the iterators above to insert all children, in order. - children.setSize(numChildren); - for (size_t i = 0; i < numJoints; ++i) { - int parent = topology.GetParent(i); - if (parent >= 0) { - exint childIndex = childIters[parent].first; - children[childIndex] = static_cast(i); - ++childIters[parent].first; - ++childIters[parent].second; - - if (!TF_VERIFY(childIters[parent].second <= childCounts[parent])) { - return false; - } - } - } - return true; -} - - -} // namespace - - -GU_AgentRigPtr -GusdCreateAgentRig(const char* name, const UsdSkelSkeletonQuery& skelQuery) -{ - TRACE_FUNCTION(); - - if (!skelQuery.IsValid()) { - GUSD_WARN().Msg("%s -- invalid skelDefinition.", - skelQuery.GetSkeleton().GetPrim().GetPath().GetText()); - return nullptr; - } - - if(!skelQuery.HasBindPose()) { - GUSD_WARN().Msg("%s -- `bindTransformsAttrs` is invalid.", - skelQuery.GetSkeleton().GetPrim().GetPath().GetText()); - return nullptr; - } - - const UsdSkelSkeleton& skel = skelQuery.GetSkeleton(); - - if (!skel) { - TF_CODING_ERROR("'skel' is invalid"); - return nullptr; - } - - VtTokenArray joints; - if (!skel.GetJointsAttr().Get(&joints)) { - GUSD_WARN().Msg("%s -- 'joints' attr is invalid", - skel.GetPrim().GetPath().GetText()); - return nullptr; - } - - VtTokenArray jointNames; - if (!Gusd_GetJointNames(skel, joints, jointNames)) { - return nullptr; - } - - const UsdSkelTopology topology(joints); - std::string reason; - if (!topology.Validate(&reason)) { - GUSD_WARN().Msg("%s -- invalid topology: %s", - skel.GetPrim().GetPath().GetText(), - reason.c_str()); - return nullptr; - } - - return GusdCreateAgentRig(name, topology, jointNames); -} - - -GU_AgentRigPtr -GusdCreateAgentRig(const char* name, - const UsdSkelTopology& topology, - const VtTokenArray& jointNames) -{ - TRACE_FUNCTION(); - - if (jointNames.size() != topology.GetNumJoints()) { - TF_CODING_ERROR("jointNames size [%zu] != num joints [%zu]", - jointNames.size(), topology.GetNumJoints()); - return nullptr; - } - - UT_IntArray childCounts; - if (!Gusd_GetChildCounts(topology, childCounts)) { - return nullptr; - } - UT_IntArray children; - if (!Gusd_GetChildren(topology, childCounts, children)) { - return nullptr; - } - - UT_ASSERT(children.size() == jointNames.size()); - UT_ASSERT(std::accumulate(childCounts.begin(), - childCounts.end(), 0) == children.size()); - - UT_StringArray names; - Gusd_ConvertTokensToStrings(jointNames, names); - - // Add a __locomotion__ transform for root motion. - names.append("__locomotion__"); - childCounts.append(0); - - const auto rig = GU_AgentRig::addRig(name); - UT_ASSERT_P(rig); - - if (rig->construct(names, childCounts, children)) { - return rig; - } else { - // XXX: Would be nice if we got a reasonable warning/error... - GUSD_WARN().Msg("internal error constructing agent rig '%s'", name); - } - return nullptr; -} - - -namespace { - - -/// Create capture attrs on \p gd, in the form expected for LBS skinning. -/// This expects \p gd to have already imported 'primvars:skel:jointIndices' -/// and 'primvars:skel:jointWeights' -- as defined by the UsdSkelBindingAPI. -/// If \p deleteInfluencePrimvars=true, the original primvars imported for -/// UsdSkel are deleted after conversion. -bool -Gusd_CreateCaptureAttributes( - GEO_Detail& gd, - const VtMatrix4dArray& inverseBindTransforms, - const VtTokenArray& jointNames, - bool deleteInluencePrimvars=true, - UT_ErrorSeverity sev=UT_ERROR_ABORT) -{ - TRACE_FUNCTION(); - - // Expect to find the jointIndices/jointWeights properties already - // imported onto the detail. We could query them from USD ourselves, - // but then we would need to worry about things like winding order, etc. - - GA_ROHandleI jointIndicesHnd(&gd, GA_ATTRIB_POINT, - GUSD_SKEL_JOINTINDICES_ATTR); - - bool perPointJointIndices = true; - - if (jointIndicesHnd.isInvalid()) { - - // If the influences were stored with 'constant' interpolation, - // they may be defined as a detail attrib instead. - jointIndicesHnd.bind(&gd, GA_ATTRIB_DETAIL, - GUSD_SKEL_JOINTINDICES_ATTR); - if (jointIndicesHnd.isValid()) { - perPointJointIndices = false; - } else { - GUSD_WARN().Msg("Could not find int skel_jointIndices attribute."); - return false; - } - } - GA_ROHandleF jointWeightsHnd(&gd, GA_ATTRIB_POINT, - GUSD_SKEL_JOINTWEIGHTS_ATTR); - bool perPointJointWeights = true; - - if (jointWeightsHnd.isInvalid()) { - - // If the influences were stored with 'constant' interpolation, - // they may be defined as a detail attrib instead. - jointWeightsHnd.bind(&gd, GA_ATTRIB_DETAIL, - GUSD_SKEL_JOINTWEIGHTS_ATTR); - if (jointWeightsHnd.isValid()) { - perPointJointWeights = false; - } else { - GUSD_WARN().Msg("Could not find float skel_jointWeights " - "attribute."); - return false; - } - } - if (jointIndicesHnd.getTupleSize() != jointWeightsHnd.getTupleSize()) { - GUSD_WARN().Msg("Tuple size of skel_jointIndices [%d] != " - "tuple size of skel_JointWeights [%d]", - jointIndicesHnd.getTupleSize(), - jointWeightsHnd.getTupleSize()); - return false; - } - - const int tupleSize = jointIndicesHnd.getTupleSize(); - const int numJoints = static_cast(jointNames.size()); - - int regionsPropId = -1; - - GA_RWAttributeRef captureAttr = - gd.addPointCaptureAttribute(GEO_Detail::geo_NPairs(tupleSize)); - GA_AIFIndexPairObjects* joints = - GEO_AttributeCaptureRegion::getBoneCaptureRegionObjects( - captureAttr, regionsPropId); - joints->setObjectCount(numJoints); - - - // Set the names of each joint. - { - GEO_RWAttributeCapturePath jointPaths(&gd); - for (int i = 0; i < numJoints; ++i) { - // TODO: Elide the string copy. - jointPaths.setPath(i, jointNames[i].GetText()); - } - } - - // Store the inverse bind transforms of each joint. - { - const GfMatrix4d* xforms = inverseBindTransforms.cdata(); - for (int i = 0; i < numJoints; ++i) { - - GEO_CaptureBoneStorage r; - r.myXform = GusdUT_Gf::Cast(xforms[i]); - - joints->setObjectValues(i, regionsPropId, r.floatPtr(), - GEO_CaptureBoneStorage::tuple_size); - } - } - - // Copy weights and indices. - const GA_AIFTuple* jointIndicesTuple = jointIndicesHnd->getAIFTuple(); - const GA_AIFTuple* jointWeightsTuple = jointWeightsHnd->getAIFTuple(); - - const GA_AIFIndexPair* indexPair = captureAttr->getAIFIndexPair(); - indexPair->setEntries(captureAttr, tupleSize); - - UTparallelFor( - GA_SplittableRange(gd.getPointRange()), - [&](const GA_SplittableRange& r) - { - UT_FloatArray weights(tupleSize, tupleSize); - UT_IntArray indices(tupleSize, tupleSize); - - auto* boss = UTgetInterrupt(); - char bcnt = 0; - - GA_Offset o,end; - for (GA_Iterator it(r); it.blockAdvance(o,end); ) { - if (ARCH_UNLIKELY(!++bcnt && boss->opInterrupt())) { - return; - } - - for ( ; o < end; ++o) { - if (jointIndicesTuple->get(jointIndicesHnd.getAttribute(), - perPointJointIndices ? o : 0, - indices.data(), tupleSize) && - jointWeightsTuple->get(jointWeightsHnd.getAttribute(), - perPointJointWeights ? o : 0, - weights.data(), tupleSize)) { - - // Joint influences are required to be stored - // pre-normalized in USD, but subsequent import - // processing may have altered that. - // Normalize in-place to be safe. - // - // TODO: If the shape was rigid, then we are needlessly - // re-normalizing over each run. It would be more - // efficient to pre-normalize instead. - float sum = 0; - for (int c = 0; c < tupleSize; ++c) - sum += weights[c]; - if (sum > 1e-6) { - for (int c = 0; c < tupleSize; ++c) { - weights[c] /= sum; - } - } - - for (int c = 0; c < tupleSize; ++c) { - indexPair->setIndex(captureAttr, o, c, indices[c]); - indexPair->setData(captureAttr, o, c, weights[c]); - } - } - } - } - }); - - if (deleteInluencePrimvars) { - gd.destroyAttribute(jointIndicesHnd->getOwner(), - jointIndicesHnd->getName()); - gd.destroyAttribute(jointWeightsHnd->getOwner(), - jointWeightsHnd->getName()); - } - return true; -} - - -bool -Gusd_ReadSkinnablePrims(const UsdSkelBinding& binding, - const VtTokenArray& jointNames, - const VtMatrix4dArray& invBindTransforms, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - UT_ErrorSeverity sev, - const GT_RefineParms* refineParms, - UT_Array& details) -{ - TRACE_FUNCTION(); - - UT_AutoInterrupt task("Read USD shapes for shapelib"); - - const size_t numTargets = binding.GetSkinningTargets().size(); - - details.clear(); - details.setSize(numTargets); - - GusdErrorTransport errTransport; - - // Read in details for all skinning targets in parallel. - UTparallelForHeavyItems( - UT_BlockedRange(0, numTargets), - [&](const UT_BlockedRange& r) - { - const GusdAutoErrorTransport autoErrTransport(errTransport); - - for (size_t i = r.begin(); i < r.end(); ++i) { - - if (task.wasInterrupted()) - return; - - const UsdGeomImageable ip( - binding.GetSkinningTargets()[i].GetPrim()); - if (!ip) { - continue; - } - if (ip.ComputeVisibility(time) == UsdGeomTokens->invisible) { - continue; - } - if (!GusdPurposeInSet(ip.ComputePurpose(), purpose)) { - continue; - } - - GU_DetailHandle gdh; - gdh.allocateAndSet(new GU_Detail); - - const GU_DetailHandleAutoWriteLock gdl(gdh); - - if (GusdReadSkinnablePrim( - *gdl.getGdp(), binding.GetSkinningTargets()[i], - jointNames, invBindTransforms, - time, lod, purpose, sev, refineParms)) { - details[i] = gdh; - } else if (sev >= UT_ERROR_ABORT) { - return; - } - } - }); - - return !task.wasInterrupted(); -} - - -void -Gusd_InvertTransforms(TfSpan xforms) -{ - UTparallelForLightItems( - UT_BlockedRange(0, xforms.size()), - [&](const UT_BlockedRange& r) - { - for (size_t i = r.begin(); i < r.end(); ++i) { - xforms[i] = xforms[i].GetInverse(); - } - }); -} - - -bool -Gusd_ReadSkinnablePrims(const UsdSkelBinding& binding, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - UT_ErrorSeverity sev, - const GT_RefineParms* refineParms, - UT_Array& details) -{ - const UsdSkelSkeleton& skel = binding.GetSkeleton(); - - VtTokenArray joints; - if (!skel.GetJointsAttr().Get(&joints)) { - GUSD_WARN().Msg("%s -- 'joints' attr is invalid", - skel.GetPrim().GetPath().GetText()); - return false; - } - VtTokenArray jointNames; - if (!Gusd_GetJointNames(skel, joints, jointNames)) { - return false; - } - - VtMatrix4dArray invBindTransforms; - if (!skel.GetBindTransformsAttr().Get(&invBindTransforms)) { - GUSD_WARN().Msg("%s -- no authored bindTransforms", - skel.GetPrim().GetPath().GetText()); - return false; - } - if (invBindTransforms.size() != joints.size()) { - GUSD_WARN().Msg("%s -- size of 'bindTransforms' [%zu] != " - "size of 'joints' [%zu].", - skel.GetPrim().GetPath().GetText(), - invBindTransforms.size(), joints.size()); - return false; - } - // XXX: Want *inverse* bind transforms when writing out capture data. - Gusd_InvertTransforms(invBindTransforms); - - return Gusd_ReadSkinnablePrims(binding, jointNames, invBindTransforms, time, - lod, purpose, sev, refineParms, details); -} - - -} // namespace - - -bool -GusdReadSkinnablePrims(const UsdSkelBinding& binding, - UT_Array& details, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - UT_ErrorSeverity sev, - const GT_RefineParms* refineParms) -{ - const UsdSkelSkeleton& skel = binding.GetSkeleton(); - - VtTokenArray joints; - if (!skel.GetJointsAttr().Get(&joints)) { - GUSD_WARN().Msg("%s -- 'joints' attr is invalid", - skel.GetPrim().GetPath().GetText()); - return false; - } - VtTokenArray jointNames; - if (!Gusd_GetJointNames(skel, joints, jointNames)) { - return false; - } - - VtMatrix4dArray invBindTransforms; - if (!skel.GetBindTransformsAttr().Get(&invBindTransforms)) { - GUSD_WARN().Msg("%s -- no authored bindTransforms", - skel.GetPrim().GetPath().GetText()); - return false; - } - if (invBindTransforms.size() != joints.size()) { - GUSD_WARN().Msg("%s -- size of 'bindTransforms' [%zu] != " - "size of 'joints' [%zu].", - skel.GetPrim().GetPath().GetText(), - invBindTransforms.size(), joints.size()); - return false; - } - // XXX: Want *inverse* bind transforms when writing out capture data. - Gusd_InvertTransforms(invBindTransforms); - - return Gusd_ReadSkinnablePrims(binding, jointNames, invBindTransforms, time, - lod, purpose, sev, refineParms, details); -} - - -bool -GusdReadSkinnablePrim(GU_Detail& gd, - const UsdSkelSkinningQuery& skinningQuery, - const VtTokenArray& jointNames, - const VtMatrix4dArray& invBindTransforms, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - UT_ErrorSeverity sev, - const GT_RefineParms* refineParms) -{ - TRACE_FUNCTION(); - - // Convert joint names in Skeleton order to the order specified - // on this skinnable prim (if any). - VtTokenArray localJointNames = jointNames; - if (skinningQuery.GetMapper()) { - if (!skinningQuery.GetMapper()->Remap( - jointNames, &localJointNames)) { - return false; - } - } - - const GfMatrix4d geomBindTransform = skinningQuery.GetGeomBindTransform(); - const UsdPrim& skinnedPrim = skinningQuery.GetPrim(); - const char* primvarPattern = "Cd skel:jointIndices skel:jointWeights"; - - return (GusdGU_USD::ImportPrimUnpacked( - gd, skinnedPrim, time, lod, purpose, primvarPattern, - &GusdUT_Gf::Cast(geomBindTransform), refineParms) && - Gusd_CreateCaptureAttributes( - gd, invBindTransforms, localJointNames, sev)); -} - - -GU_AgentShapeLibPtr -GusdCreateAgentShapeLib(const UsdSkelBinding& binding, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - UT_ErrorSeverity sev, - const GT_RefineParms* refineParms) -{ - const UsdSkelSkeleton& skel = binding.GetSkeleton(); - - // Read geom for each skinning target into its own detail. - - UT_Array details; - if (!Gusd_ReadSkinnablePrims(binding, time, lod, purpose, - sev, refineParms, details)) { - return nullptr; - } - - const size_t numTargets = binding.GetSkinningTargets().size(); - UT_ASSERT_P(details.size() == numTargets); - - auto shapeLib = - GU_AgentShapeLib::addLibrary(skel.GetPrim().GetPath().GetText()); - - // Add the resulting details to the shape lib. - for (size_t i = 0; i < numTargets; ++i) { - if (const auto& gdh = details[i]) { - const UsdPrim& prim = binding.GetSkinningTargets()[i].GetPrim(); - - const UT_StringHolder name(prim.GetPath().GetString()); - shapeLib->addShape(name, gdh); - } - } - return shapeLib; -} - - -namespace { - -// TODO: This is the bottle neck in import. -bool -_CoalesceShapes(GEO_Detail& coalescedGd, - const UT_Array& details) -{ - UT_AutoInterrupt task("Coalesce shapes"); - - for (const auto& gdh : details) { - if (task.wasInterrupted()) - return false; - - const GU_DetailHandleAutoReadLock gdl(gdh); - if (const GU_Detail* gdp = gdl.getGdp()) { - coalescedGd.merge(*gdp); - } - } - return !task.wasInterrupted(); -} - -} // namespace - - -bool -GusdCoalesceAgentShapes(GEO_Detail& gd, - const UsdSkelBinding& binding, - UsdTimeCode time, - const char* lod, - GusdPurposeSet purpose, - UT_ErrorSeverity sev, - const GT_RefineParms* refineParms) -{ - UT_Array details; - if (GusdReadSkinnablePrims(binding, details, time, lod, - purpose, sev, refineParms)) { - return _CoalesceShapes(gd, details); - } - return false; -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/agentUtils.h b/third_party/houdini/gusd/agentUtils.h deleted file mode 100644 index 043a285540..0000000000 --- a/third_party/houdini/gusd/agentUtils.h +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright 2019 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_AGENT_UTILS_H -#define GUSD_AGENT_UTILS_H - -/// \file agentUtils.h -/// \ingroup group_gusd_Agents -/// Utilities for translating agents to/from USD. -/// -/// These do not provide complete, automatic conversion to/from USD at this -/// stage. Rather, these utilities may be used to build out a conversion -/// pipeline, such as generating all of the various JSON files needed to -/// build out the components of GU_Agent primitives. -/// - -#include "api.h" -#include "purpose.h" - -#include "pxr/base/vt/array.h" -#include "pxr/usd/usd/timeCode.h" - -#include -#include -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -class GT_RefineParms; -class UsdSkelBinding; -class UsdSkelSkeleton; -class UsdSkelSkeletonQuery; -class UsdSkelSkinningQuery; -class UsdSkelTopology; - - -/// Create an agent rig from a \p skelQuery. -GUSD_API GU_AgentRigPtr -GusdCreateAgentRig(const char* name, const UsdSkelSkeletonQuery& skelQuery); - - -/// Create an agent rig from \p topology and \p jointNames. -/// Each joint name must be unique. -GUSD_API GU_AgentRigPtr -GusdCreateAgentRig(const char* name, - const UsdSkelTopology& topology, - const VtTokenArray& jointNames); - - -/// Create a shape library where every skinning target of \p binding is -/// a separate shape. -/// The \p sev defines the error severity when reading in each shape. -/// If the severity is less than UT_ERROR_ABORT, the invalid shape is -/// skipped. Otherwise, creation of the shape lib fails if errors are -/// produced processing any shapes. -GUSD_API GU_AgentShapeLibPtr -GusdCreateAgentShapeLib(const UsdSkelBinding& binding, - UsdTimeCode time=UsdTimeCode::EarliestTime(), - const char* lod=nullptr, - GusdPurposeSet purpose=GusdPurposeSet( - GUSD_PURPOSE_DEFAULT|GUSD_PURPOSE_PROXY), - UT_ErrorSeverity sev=UT_ERROR_WARNING, - const GT_RefineParms* refineParms=nullptr); - - -/// Read in all skinnable shapes for \p binding, coalescing them into \p gd. -/// The \p sev defines the error severity when reading in each shape. -/// If the severity is less than UT_ERROR_ABORT, the invalid shape is -/// skipped. Otherwise, creation of the coalesced detail fails if errors are -/// produced processing any shapes. -GUSD_API bool -GusdCoalesceAgentShapes(GEO_Detail& gd, - const UsdSkelBinding& binding, - UsdTimeCode time=UsdTimeCode::EarliestTime(), - const char* lod=nullptr, - GusdPurposeSet purpose=GusdPurposeSet( - GUSD_PURPOSE_DEFAULT|GUSD_PURPOSE_PROXY), - UT_ErrorSeverity sev=UT_ERROR_WARNING, - const GT_RefineParms* refineParms=nullptr); - - -/// Read in a skinnable prim given by \p skinningQuery into \p gd. -/// The \p jointNames array provides the names of the joints of the bound -/// Skeleton, using the ordering specified on the Skeleton. -/// The \p invBindTransforms array holds the inverse of the Skeleton's -/// bind transforms. -/// Errors encountered while reading the skinnable primitive are reported -/// with a severity of \p sev. -GUSD_API bool -GusdReadSkinnablePrim(GU_Detail& gd, - const UsdSkelSkinningQuery& skinningQuery, - const VtTokenArray& jointNames, - const VtMatrix4dArray& invBindTransforms, - UsdTimeCode time=UsdTimeCode::EarliestTime(), - const char* lod=nullptr, - GusdPurposeSet purpose=GusdPurposeSet( - GUSD_PURPOSE_DEFAULT|GUSD_PURPOSE_PROXY), - UT_ErrorSeverity sev=UT_ERROR_ABORT, - const GT_RefineParms* refineParms=nullptr); - - -/// Read shapes for each shape in \p binding. -/// The \p sev defines the error severity when reading in each shape. -/// If the severity is less than UT_ERROR_ABORT, invalid shapes are -/// skipped, and an empty detail handle is stored in \p details for -/// the corresponding shape. Otherwise, the process returns false if -/// errors are encountered processing any shapes. -bool -GusdReadSkinnablePrims(const UsdSkelBinding& binding, - UT_Array& details, - UsdTimeCode time=UsdTimeCode::EarliestTime(), - const char* lod=nullptr, - GusdPurposeSet purpose=GusdPurposeSet( - GUSD_PURPOSE_DEFAULT|GUSD_PURPOSE_PROXY), - UT_ErrorSeverity sev=UT_ERROR_WARNING, - const GT_RefineParms* refineParms=nullptr); - - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_AGENT_UTILS_H diff --git a/third_party/houdini/gusd/api.h b/third_party/houdini/gusd/api.h deleted file mode 100644 index 7ed3d75e1e..0000000000 --- a/third_party/houdini/gusd/api.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_API_H -#define GUSD_API_H - -#include "pxr/base/arch/export.h" -#include - -#if defined(GUSD_EXPORTS) -# define GUSD_API ARCH_EXPORT -# define GUSD_API_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) -# define GUSD_API_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) -#else -# define GUSD_API ARCH_IMPORT -# define GUSD_API_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) -# define GUSD_API_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) -#endif -#define GUSD_LOCAL ARCH_HIDDEN - -#endif diff --git a/third_party/houdini/gusd/boundsCache.cpp b/third_party/houdini/gusd/boundsCache.cpp deleted file mode 100644 index ca932036e7..0000000000 --- a/third_party/houdini/gusd/boundsCache.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "boundsCache.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; - -//////////////////////////////////////////////////////////////////////////////// - -/* static */ -GusdBoundsCache & -GusdBoundsCache::GetInstance() -{ - static GusdBoundsCache cache; - return cache; -} - -GusdBoundsCache::GusdBoundsCache() -{ -} - -GusdBoundsCache::~GusdBoundsCache() -{ -} - -bool -GusdBoundsCache::ComputeWorldBound( - const UsdPrim &prim, - UsdTimeCode time, - const TfTokenVector &includedPurposes, - UT_BoundingBox &bounds ) -{ - return _ComputeBound( - prim, - time, - includedPurposes, - &UsdGeomBBoxCache::ComputeWorldBound, - bounds ); -} - -bool -GusdBoundsCache::ComputeUntransformedBound( - const UsdPrim &prim, - UsdTimeCode time, - const TfTokenVector &includedPurposes, - UT_BoundingBox &bounds ) -{ - return _ComputeBound( - prim, - time, - includedPurposes, - &UsdGeomBBoxCache::ComputeUntransformedBound, - bounds ); -} - -bool -GusdBoundsCache::_ComputeBound( - const UsdPrim &prim, - UsdTimeCode time, - const TfTokenVector &includedPurposes, - ComputeFunc boundFunc, - UT_BoundingBox &bounds ) -{ - if( !prim.IsValid() ) - return false; - - TfToken stageId( prim.GetStage()->GetRootLayer()->IsAnonymous() - ? prim.GetStage()->GetRootLayer()->GetIdentifier() - : prim.GetStage()->GetRootLayer()->GetRealPath() ); - - MapType::accessor accessor; - if( !m_map.find( accessor, Key( stageId, includedPurposes ))) { - m_map.insert( accessor, Key( stageId, includedPurposes ) ); - accessor->second = new Item( time, includedPurposes ); - } - std::lock_guard lock(accessor->second->lock); - UsdGeomBBoxCache& cache = accessor->second->bboxCache; - - cache.SetTime( time ); - - // boundFunc is either ComputeWorldBound or ComputeLocalBound - GfBBox3d primBBox = (cache.*boundFunc)(prim); - - if( !primBBox.GetRange().IsEmpty() ) - { - const GfRange3d rng = primBBox.ComputeAlignedRange(); - - bounds = - UT_BoundingBox( - rng.GetMin()[0], - rng.GetMin()[1], - rng.GetMin()[2], - rng.GetMax()[0], - rng.GetMax()[1], - rng.GetMax()[2]); - return true; - } - - return false; -} - -void -GusdBoundsCache::Clear() -{ - m_map.clear(); -} - -int64 -GusdBoundsCache::Clear(const UT_StringSet& paths) -{ - int64 freed = 0; - - UT_Array keys; - for( auto const& entry : m_map ) { - if( paths.contains( entry.first.path.GetString() ) ) { - keys.append( entry.first ); - } - } - - for( auto const& k : keys ) { - m_map.erase( k ); - } - return freed; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/boundsCache.h b/third_party/houdini/gusd/boundsCache.h deleted file mode 100644 index 2ca3598542..0000000000 --- a/third_party/houdini/gusd/boundsCache.h +++ /dev/null @@ -1,137 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_BOUNDS_CACHE_H -#define GUSD_BOUNDS_CACHE_H - -#include "pxr/pxr.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usdGeom/bboxCache.h" -#include "pxr/base/tf/token.h" - -#include "USD_DataCache.h" - -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -/// A wrapper arround UsdGeomBBoxCache. -/// -/// This singleton class keeps a cache per stage and per purpose. -/// It will be flushed when the stage cache is flushed. -/// -/// Unfortunaly UsdGeomBBoxCaches only store a single frame at -/// a time. I considered creating a cache per frame but I thought -/// that would defeat optimizations for non animated geometry. - -class GusdBoundsCache : public GusdUSD_DataCache { -public: - static GusdBoundsCache& GetInstance(); - - GusdBoundsCache(); - virtual ~GusdBoundsCache(); - - bool ComputeWorldBound( - const UsdPrim &prim, - UsdTimeCode time, - const TfTokenVector &includedPurposes, - UT_BoundingBox &bounds ); - - bool ComputeUntransformedBound( - const UsdPrim &prim, - UsdTimeCode time, - const TfTokenVector &includedPurposes, - UT_BoundingBox &bounds ); - - virtual void Clear() override; - virtual int64 Clear(const UT_StringSet& stageNames) override; - -private: - - // Key that hashes the stage file name and a set of purposes. - struct Key - { - Key() : hash(0) {} - - Key(const TfToken &path, TfTokenVector purposes) - : path(path), purposes( purposes ), hash(ComputeHash(path,purposes)) {} - - static std::size_t ComputeHash(const TfToken &path, TfTokenVector purposes) - { - std::size_t h = hash_value(path); - boost::hash_combine(h, purposes); - return h; - } - - bool operator==(const Key& o) const - { return path == o.path && - purposes == o.purposes ; } - - friend size_t hash_value(const Key& o) - { return o.hash; } - - struct HashCmp - { - static std::size_t hash(const Key& key) - { return key.hash; } - static bool equal(const Key& a, - const Key& b) - { return a == b; } - }; - - TfToken path; - TfTokenVector purposes; - std::size_t hash; - }; - - struct Item : public UT_IntrusiveRefCounter - { - Item( UsdTimeCode time, const TfTokenVector& includedPurposes ) - : bboxCache( time, includedPurposes ) - { - } - - UsdGeomBBoxCache bboxCache; - std::mutex lock; - }; - - typedef GfBBox3d (UsdGeomBBoxCache::*ComputeFunc)(const UsdPrim& prim); - - bool _ComputeBound( - const UsdPrim &prim, - UsdTimeCode time, - const TfTokenVector &includedPurposes, - ComputeFunc boundFunc, - UT_BoundingBox &bounds ); - - typedef UT_IntrusivePtr ItemHandle; - - typedef UT_ConcurrentHashMap MapType; - MapType m_map; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_BOUNDS_CACHE_H diff --git a/third_party/houdini/gusd/context.h b/third_party/houdini/gusd/context.h deleted file mode 100644 index cff72694b4..0000000000 --- a/third_party/houdini/gusd/context.h +++ /dev/null @@ -1,129 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// - -#ifndef GUSD_CONTEXT_H -#define GUSD_CONTEXT_H - -#include "pxr/pxr.h" -#include "pxr/usd/usd/timeCode.h" -#include "pxr/usd/usd/stage.h" -#include "pxr/usd/usdGeom/tokens.h" - -#include - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdGT_AttrFilter; -class UsdGeomXformCache; - -/// A GusdContext structure is created by the ROPs that write USD files and -/// passed to the GusdPrimWrappers to control how they are written to the USD file. - -class GusdContext { -public: - typedef std::function GetStageFunc; - enum Granularity { ONE_FILE, PER_FRAME }; - - GusdContext( UsdTimeCode t, - Granularity g, - const GusdGT_AttrFilter& af ) - : time( t ) - , granularity( g ) - , writeOverlay( false ) - , overlayPoints( false ) - , overlayTransforms( false ) - , overlayPrimvars( false ) - , overlayAll( false ) - , writeStaticGeo( false ) - , writeStaticTopology( false ) - , writeStaticPrimvars( false ) - , attributeFilter( af ) - , purpose( UsdGeomTokens->default_ ) - , makeRefsInstanceable( true ) - {} - - // Time of the current frame we are writing - UsdTimeCode time; - - // Are we writing on frame per file or all the frames into a single file? - Granularity granularity; - - bool writeOverlay; // Overlay existing geometry rather than creating new geometry? - - // Flags indicating what should be overlayed - bool overlayPoints; // For point instancers, overlayPoints and overlayTransforms are synonymous.Ï€ - bool overlayTransforms; - bool overlayPrimvars; - bool overlayAll; // Completely replace prims, including topology. - // For point instancers, if overlayAll is set and - // prototypes are specified, replace the prototypes. - - bool writeStaticGeo; - bool writeStaticTopology; - bool writeStaticPrimvars; - - // Filter specifying what primvars to write for each prim. - const GusdGT_AttrFilter& attributeFilter; - - // Name of attribute that specifies usd prim path to write prims to. - // a prim. - std::string primPathAttribute; - - // Path to a sop or obj node that contains all the prototypes so we can - // write a complete and static relationship array. Will be overridden by - // attributes if they exist. - std::string usdPrototypesPath; - - // Identifier (and possibly path to a primitive) to both create an entry - // in a point instancer's relationship array and mark which prototype to use - // for a point. Will be overridden by attributes if they exist. - std::string usdInstancePath; - - // Offset value to set in a Layer Offset of a USD reference. For retiming - // references. - double usdTimeOffset; - - // Scale value to set in a Layer Offset of a USD reference. For retiming - // references. - double usdTimeScale; - - // When we write a USD packed prim to a USD file, we write a USD reference. - // If the prim path attribute in the USD packed prim contains a variant - // selection, write that with the reference. - bool authorVariantSelections; - - // Purpose (render, proxy or guide) to tag prims with. - TfToken purpose; - - // Whether to make references to a USD prims instanceable. - bool makeRefsInstanceable; - -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_CONTEXT_H diff --git a/third_party/houdini/gusd/curvesWrapper.cpp b/third_party/houdini/gusd/curvesWrapper.cpp deleted file mode 100644 index b795aa0617..0000000000 --- a/third_party/houdini/gusd/curvesWrapper.cpp +++ /dev/null @@ -1,893 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "curvesWrapper.h" -#include "NURBSCurvesWrapper.h" - -#include "context.h" -#include "GT_VtArray.h" -#include "tokens.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include -#include -#include -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::cout; -using std::endl; -using std::map; - -namespace { - -map gtToUsdBasisTranslation = { - { GT_BASIS_BEZIER, UsdGeomTokens->bezier }, - { GT_BASIS_BSPLINE, UsdGeomTokens->bspline }, - { GT_BASIS_CATMULLROM, UsdGeomTokens->catmullRom }, - { GT_BASIS_CATMULL_ROM, UsdGeomTokens->catmullRom }, - { GT_BASIS_HERMITE, UsdGeomTokens->hermite }}; - -map usdToGtBasisTranslation = { - { UsdGeomTokens->bezier, GT_BASIS_BEZIER }, - { UsdGeomTokens->bspline, GT_BASIS_BSPLINE }, - { UsdGeomTokens->catmullRom, GT_BASIS_CATMULLROM }, - { UsdGeomTokens->hermite, GT_BASIS_HERMITE }}; - -void _validateData( - const char* destName, - const char* srcName, - const char* primName, - GT_DataArrayHandle data, - const TfToken& interpolation, - GT_DataArrayHandle segEndPointIndicies, - int numCurves, - int numPoints, - int numSegmentEndPoints, - GT_AttributeListHandle* vertexAttrs, - GT_AttributeListHandle* uniformAttrs, - GT_AttributeListHandle* detailAttrs ); - -} // end of namespace - -GusdCurvesWrapper:: -GusdCurvesWrapper( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride ) - : m_forceCreateNewGeo( false ) -{ - initUsdPrim( stage, path, isOverride ); -} - -GusdCurvesWrapper:: -GusdCurvesWrapper( - const UsdGeomBasisCurves& usdCurves, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdPrimWrapper( time, purposes ) - , m_usdCurves( usdCurves ) - , m_forceCreateNewGeo( false ) -{ -} - -GusdCurvesWrapper:: -~GusdCurvesWrapper() -{} - -bool GusdCurvesWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - bool newPrim = true; - m_forceCreateNewGeo = false; - if( asOverride ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing ) { - newPrim = false; - m_usdCurves = UsdGeomBasisCurves(stage->OverridePrim( path )); - } - else { - // When fracturing, we want to override the outside surfaces and create - // new inside surfaces in one export. So if we don't find an existing prim - // with the given path, create a new one. - m_usdCurves = UsdGeomBasisCurves::Define( stage, path ); - m_forceCreateNewGeo = true; - } - } - else { - m_usdCurves = UsdGeomBasisCurves::Define( stage, path ); - } - if( !m_usdCurves || !m_usdCurves.GetPrim().IsValid() ) { - TF_WARN( "Unable to create %s curves '%s'.", newPrim ? "new" : "override", path.GetText() ); - } - return bool( m_usdCurves ); -} - -GT_PrimitiveHandle GusdCurvesWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - if( sourcePrim->getPrimitiveType() != GT_PRIM_CURVE_MESH ) { - TF_WARN( "Invalid prim" ); - return GT_PrimitiveHandle(); - } - - auto sourceCurves = UTverify_cast(sourcePrim.get()); - - // For most types, the prim wrapper base classes decides what type USD prim to - // create based on the type of the GT prim. However, Basis curves and NURBs share - // the same GT type. - // We have some legacy code that turns all curves into NURBs. This causes a problem - // with overlays, so we add a check to make sure we are overlaying the proper type. - - if( sourceCurves->getBasis() == GT_BASIS_BSPLINE && sourceCurves->knots() ) { - - bool validNURB = true; - if( ctxt.writeOverlay ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing && existing.IsA() ) { - validNURB = false; - } - } - - if( validNURB ) { - return new GusdNURBSCurvesWrapper( - sourcePrim, - stage, - path, - ctxt.writeOverlay ); - } - } - return new GusdCurvesWrapper( - sourcePrim, - stage, - path, - ctxt.writeOverlay ); -} - -GT_PrimitiveHandle GusdCurvesWrapper:: -defineForRead( - const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdCurvesWrapper( - UsdGeomBasisCurves( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdCurvesWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay ); - clearCaches(); - return true; -} - -bool -GusdCurvesWrapper::refine( - GT_Refine& refiner, - const GT_RefineParms* parms) const -{ - if(!isValid()) - return false; - - bool refineForViewport = GT_GEOPrimPacked::useViewportLOD(parms); - - const UsdGeomBasisCurves& usdCurves = m_usdCurves; - - GT_AttributeListHandle gtVertexAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtUniformAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtDetailAttrs = new GT_AttributeList( new GT_AttributeMap() ); - - GT_Basis basis = GT_BASIS_INVALID; - if( refineForViewport ) { - basis = GT_BASIS_LINEAR; - } - else { - - TfToken type; - usdCurves.GetTypeAttr().Get( &type, m_time ); - if( type == UsdGeomTokens->linear ) { - basis = GT_BASIS_LINEAR; - } - else { - - TfToken usdBasis; - usdCurves.GetBasisAttr().Get( &usdBasis, m_time ); - auto const& it = usdToGtBasisTranslation.find( usdBasis ); - if( it != usdToGtBasisTranslation.end() ) { - basis = it->second; - } - } - if( basis == GT_BASIS_INVALID ) { - TF_WARN( "Usupported curve basis" ); - return false; - } - } - - bool wrap = false; - - TfToken usdWrap; - usdCurves.GetWrapAttr().Get( &usdWrap, m_time ); - if( usdWrap == UsdGeomTokens->periodic ) { - wrap = true; - } - - // vertex counts - UsdAttribute countsAttr = usdCurves.GetCurveVertexCountsAttr(); - if(!countsAttr) - return false; - - VtIntArray usdCounts; - countsAttr.Get(&usdCounts, m_time); - auto gtVertexCounts = new GusdGT_VtArray( usdCounts ); - - // point positions - UsdAttribute pointsAttr = usdCurves.GetPointsAttr(); - if(!pointsAttr) - return false; - VtVec3fArray usdPoints; - pointsAttr.Get(&usdPoints, m_time); - - UT_IntrusivePtr segEndPointIndicies; - int numSegmentEndPoints = usdPoints.size(); - if( !refineForViewport ) { - - // In USD, primvars for bezier curves are stored on the endpoints of - // each segment. In Houdini these need to be point attributes. Create a - // LUT to map these indexes. - - if( basis == GT_BASIS_BEZIER ) { - - segEndPointIndicies = new GT_Int32Array( usdPoints.size(), 1 ); - - GT_Offset srcIdx = 0; - GT_Offset dstIdx = 0; - for( const auto& c : usdCounts ) { - for( int i = 0, segs = c / 3; i < segs; ++i ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - segEndPointIndicies->set( srcIdx, dstIdx++ ); - segEndPointIndicies->set( srcIdx, dstIdx++ ); - ++srcIdx; - } - if( !wrap ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - } - numSegmentEndPoints = srcIdx; - } - else if ( basis == GT_BASIS_BSPLINE || - basis == GT_BASIS_CATMULLROM ) { - - // For non-periodic bsplines and catroms there are 2 less segment end points - // then there are vertices. Just dupe the first and last values. - - if( !wrap ) { - segEndPointIndicies = new GT_Int32Array( usdPoints.size(), 1 ); - - GT_Offset srcIdx = 0; - GT_Offset dstIdx = 0; - for( const auto& c : usdCounts ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - for( int i = 0; i < c - 2 ; ++i ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - segEndPointIndicies->set( srcIdx, dstIdx++ ); - } - numSegmentEndPoints = srcIdx; - } - } - else if( basis != GT_BASIS_LINEAR ) { - TF_WARN( "Can't map curve primvar. Unsupported curve type" ); - } - } - - auto gtPoints = new GusdGT_VtArray(usdPoints,GT_TYPE_POINT); - gtVertexAttrs = gtVertexAttrs->addAttribute( "P", gtPoints, true ); - - if( !refineForViewport ) { - - UsdAttribute widthsAttr = usdCurves.GetWidthsAttr(); - VtFloatArray usdWidths; - if(widthsAttr.Get(&usdWidths, m_time) ) { - _validateData( "pscale", "widths", - usdCurves.GetPrim().GetPath().GetText(), - new GusdGT_VtArray(usdWidths), - usdCurves.GetWidthsInterpolation(), - segEndPointIndicies, - gtVertexCounts->entries(), - gtPoints->entries(), - numSegmentEndPoints, - >VertexAttrs, - >UniformAttrs, - >DetailAttrs ); - } - - // velocities - UsdAttribute velAttr = usdCurves.GetVelocitiesAttr(); - VtVec3fArray usdVelocities; - if( velAttr.Get(&usdVelocities, m_time) ) { - - GT_DataArrayHandle gtVelocities = - new GusdGT_VtArray(usdVelocities,GT_TYPE_VECTOR); - - gtVertexAttrs = gtVertexAttrs->addAttribute( "v", gtVelocities, true ); - } - - // normals - UsdAttribute normAttr = usdCurves.GetNormalsAttr(); - VtVec3fArray usdNormals; - if(normAttr.Get(&usdNormals, m_time) ) { - - _validateData( "N", "normals", - usdCurves.GetPrim().GetPath().GetText(), - new GusdGT_VtArray(usdNormals,GT_TYPE_NORMAL), - usdCurves.GetNormalsInterpolation(), - segEndPointIndicies, - gtVertexCounts->entries(), - gtPoints->entries(), - numSegmentEndPoints, - >VertexAttrs, - >UniformAttrs, - >DetailAttrs ); - } - - // Load primvars. segEndPointIndicies are used if we need to expand primvar arrays - // from a value at segment end points to values in point attributes. - loadPrimvars( m_time, parms, - usdCounts.size(), - usdPoints.size(), - numSegmentEndPoints, - usdCurves.GetPath().GetString(), - NULL, - >VertexAttrs, - >UniformAttrs, - >DetailAttrs, - segEndPointIndicies ); - } - else { - - UsdGeomPrimvar colorPrimvar = usdCurves.GetPrimvar(GusdTokens->Cd); - if( !colorPrimvar || !colorPrimvar.GetAttr().HasAuthoredValue() ) { - colorPrimvar = usdCurves.GetPrimvar(GusdTokens->displayColor); - } - - if( colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValue()) { - - // cerr << "curve color primvar " << colorPrimvar.GetBaseName() << "\t" << colorPrimvar.GetTypeName() << "\t" << colorPrimvar.GetInterpolation() << endl; - - GT_DataArrayHandle gtData = convertPrimvarData( colorPrimvar, m_time ); - if( gtData ) { - if( colorPrimvar.GetInterpolation() == UsdGeomTokens->constant ) { - - gtDetailAttrs = gtDetailAttrs->addAttribute( "Cd", gtData, true ); - } - else if( colorPrimvar.GetInterpolation() == UsdGeomTokens->uniform ) { - - gtUniformAttrs = gtUniformAttrs->addAttribute( "Cd", gtData, true ); - } - else if( colorPrimvar.GetInterpolation() == UsdGeomTokens->vertex || - ( colorPrimvar.GetInterpolation() == UsdGeomTokens->varying && - basis == GT_BASIS_LINEAR )) { - - gtVertexAttrs = gtVertexAttrs->addAttribute( "Cd", gtData, true ); - } - else { - - // In this case there is one value per segment end point - - auto segEndPointIndicies = new GT_Int32Array( usdPoints.size(), 1 ); - - GT_Offset srcIdx = 0; - GT_Offset dstIdx = 0; - if( basis == GT_BASIS_BEZIER ) { - for( const auto& c : usdCounts ) { - for( int i = 0, segs = c / 3; i < segs; ++i ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - segEndPointIndicies->set( srcIdx, dstIdx++ ); - segEndPointIndicies->set( srcIdx, dstIdx++ ); - ++srcIdx; - } - if( !wrap ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - } - } - else if ( basis == GT_BASIS_BSPLINE || basis == GT_BASIS_CATMULLROM ) { - for( const auto& c : usdCounts ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - for( int i = 0; i < c; ++i ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - if( !wrap ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - } - } - } - gtData = new GT_DAIndirect( segEndPointIndicies, gtData ); - gtVertexAttrs = gtVertexAttrs->addAttribute( "Cd", gtData, true ); - } - } - } - - UsdGeomPrimvar alphaPrimvar = usdCurves.GetPrimvar(GusdTokens->Alpha); - if( !alphaPrimvar || !alphaPrimvar.GetAttr().HasAuthoredValue() ) { - alphaPrimvar = usdCurves.GetPrimvar(GusdTokens->displayOpacity); - } - - if( alphaPrimvar && alphaPrimvar.GetAttr().HasAuthoredValue()) { - - // cerr << "curve color primvar " << alphaPrimvar.GetBaseName() << "\t" << alphaPrimvar.GetTypeName() << "\t" << alphaPrimvar.GetInterpolation() << endl; - - GT_DataArrayHandle gtData = convertPrimvarData( alphaPrimvar, m_time ); - if( gtData ) { - if( alphaPrimvar.GetInterpolation() == UsdGeomTokens->constant ) { - - gtDetailAttrs = gtDetailAttrs->addAttribute( "Alpha", gtData, true ); - } - else if( alphaPrimvar.GetInterpolation() == UsdGeomTokens->uniform ) { - - gtUniformAttrs = gtUniformAttrs->addAttribute( "Alpha", gtData, true ); - } - else if( alphaPrimvar.GetInterpolation() == UsdGeomTokens->vertex || - ( alphaPrimvar.GetInterpolation() == UsdGeomTokens->varying && - basis == GT_BASIS_LINEAR )) { - - gtVertexAttrs = gtVertexAttrs->addAttribute( "Alpha", gtData, true ); - } - else { - - // In this case there is one value per segment end point - - auto segEndPointIndicies = new GT_Int32Array( usdPoints.size(), 1 ); - - GT_Offset srcIdx = 0; - GT_Offset dstIdx = 0; - if( basis == GT_BASIS_BEZIER ) { - for( const auto& c : usdCounts ) { - for( int i = 0, segs = c / 3; i < segs; ++i ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - segEndPointIndicies->set( srcIdx, dstIdx++ ); - segEndPointIndicies->set( srcIdx, dstIdx++ ); - ++srcIdx; - } - if( !wrap ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - } - } - else if ( basis == GT_BASIS_BSPLINE || basis == GT_BASIS_CATMULLROM ) { - for( const auto& c : usdCounts ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - for( int i = 0; i < c; ++i ) { - segEndPointIndicies->set( srcIdx++, dstIdx++ ); - } - if( !wrap ) { - segEndPointIndicies->set( srcIdx, dstIdx++ ); - } - } - } - gtData = new GT_DAIndirect( segEndPointIndicies, gtData ); - gtVertexAttrs = gtVertexAttrs->addAttribute( "Alpha", gtData, true ); - } - } - } - } - - auto prim = new GT_PrimCurveMesh( - basis, - gtVertexCounts, - gtVertexAttrs, - gtUniformAttrs, - gtDetailAttrs, - wrap ); - - // set local transform - UT_Matrix4D mat; - - if( !GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - usdCurves.GetPrim(), - m_time, - mat ) ) { - TF_WARN( "Failed to compute transform" ); - return false; - } - - prim->setPrimitiveTransform( getPrimitiveTransform() ); - refiner.addPrimitive( prim ); - return true; -} - -namespace { - -void -_validateData( - const char* destName, - const char* srcName, - const char* primName, - GT_DataArrayHandle data, - const TfToken& interpolation, - GT_DataArrayHandle segEndPointIndicies, - int numCurves, - int numPoints, - int numSegmentEndPoints, - GT_AttributeListHandle* vertexAttrs, - GT_AttributeListHandle* uniformAttrs, - GT_AttributeListHandle* detailAttrs ) -{ - if( interpolation == UsdGeomTokens->varying && segEndPointIndicies ) { - - if( data->entries() < numSegmentEndPoints ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - else { - // if necessary, expand primvar values from samples at segment - // ends to point attributes. - - data = new GT_DAIndirect( segEndPointIndicies, data ); - *vertexAttrs = (*vertexAttrs)->addAttribute( destName, data, true ); - } - } - else if( interpolation == UsdGeomTokens->vertex || - interpolation == UsdGeomTokens->varying ) { - - if( data->entries() < numPoints ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - else { - *vertexAttrs = (*vertexAttrs)->addAttribute( destName, data, true ); - } - } - else if( interpolation == UsdGeomTokens->uniform ) { - if( data->entries() < numCurves ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - *uniformAttrs = (*uniformAttrs)->addAttribute( destName, data, true ); - } - else if( interpolation == UsdGeomTokens->constant ) { - if( data->entries() < 1 ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - *detailAttrs = (*detailAttrs)->addAttribute( destName, data, true ); - } -} -} - - -const char* GusdCurvesWrapper:: -className() const -{ - return "GusdCurvesWrapper"; -} - - -void GusdCurvesWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdCurvesWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdCurvesWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdCurvesWrapper:: -doSoftCopy() const -{ - // TODO - return GT_PrimitiveHandle(new GusdCurvesWrapper(*this)); -} - - -bool GusdCurvesWrapper::isValid() const -{ - return bool( m_usdCurves ); -} - - - - -bool GusdCurvesWrapper:: -updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache - ) -{ - if( !m_usdCurves ) { - TF_WARN( "Attempting to update invalid curve prim" ); - return false; - } - - const GT_PrimCurveMesh* gtCurves - = dynamic_cast(sourcePrim.get()); - if(!gtCurves) { - TF_WARN( "Attempting to update invalid curve prim" ); - return false; - } - - bool writeOverlay = ctxt.writeOverlay && !m_forceCreateNewGeo; - - // While I suppose we could write both points and transforms, it gets confusing, - // and I don't thik its necessary so lets not. - bool overlayTransforms = ctxt.overlayTransforms && !ctxt.overlayPoints; - - // USD only supports linear and cubic curves. Houdini supports higher order - // curves but we just issue a warning when we see them. - - // The Houdini APIs, support closed curves, but in practice we don't see - // the wrap attribute ever being non-zero. Instead was see an extra segment - // that overlaps the first segment. - - // USD expects primvars (and widths) specified for the end points of segments - // while Houdini uses point attributes. - - if( !gtCurves->isUniformOrder() ) { - TF_WARN("Non-uniform curve order not supported" ); - return false; - } - - int order = gtCurves->uniformOrder(); - if( order != 2 && order != 4 ) { - TF_WARN("USD only supports linear and cubic curves." ); - return false; - } - GT_Basis basis = gtCurves->getBasis(); - - bool closed = gtCurves->getWrap(); - - if( !writeOverlay || ctxt.overlayAll ) { - - m_usdCurves.CreateTypeAttr().Set( - order == 2 ? UsdGeomTokens->linear : UsdGeomTokens->cubic ); - - if( order == 4 ) { - - auto it = gtToUsdBasisTranslation.find( basis ); - if( it == gtToUsdBasisTranslation.end() ) { - TF_WARN( "Unsupported curve basis '%s'.", GTbasis( basis )); - return false; - } - m_usdCurves.CreateBasisAttr().Set( it->second ); - } - - m_usdCurves.CreateWrapAttr().Set( - closed ? UsdGeomTokens->periodic : UsdGeomTokens->nonperiodic ); - } - - UsdTimeCode geoTime = ctxt.time; - if( ctxt.writeStaticGeo ) { - geoTime = UsdTimeCode::Default(); - } - - GfMatrix4d xform = computeTransform( - m_usdCurves.GetPrim().GetParent(), - geoTime, - houXform, - xformCache ); - - GfMatrix4d loc_xform = computeTransform( - m_usdCurves.GetPrim(), - geoTime, - houXform, - xformCache ); - - // If we are writing points for an overlay but not writing transforms, - // then we have to transform the points into the proper space. - bool transformPoints = - writeOverlay && ctxt.overlayPoints && - !GusdUT_Gf::Cast(loc_xform).isIdentity(); - - GT_Owner attrOwner = GT_OWNER_INVALID; - GT_DataArrayHandle houAttr; - UsdAttribute usdAttr; - - if( !writeOverlay && ctxt.purpose != UsdGeomTokens->default_ ) { - m_usdCurves.GetPurposeAttr().Set( ctxt.purpose ); - } - - // intrinsic attributes ---------------------------------------------------- - - if( !writeOverlay || ctxt.overlayAll || overlayTransforms || ctxt.overlayPoints) { - - // extent ------------------------------------------------------------------ - houAttr = GusdGT_Utils::getExtentsArray(sourcePrim); - usdAttr = m_usdCurves.GetExtentAttr(); - if(houAttr && usdAttr && transformPoints ) { - houAttr = GusdGT_Utils::transformPoints( houAttr, loc_xform ); - } - updateAttributeFromGTPrim( GT_OWNER_INVALID, "extents", houAttr, usdAttr, geoTime ); - } - - // transform --------------------------------------------------------------- - if( !writeOverlay || ctxt.overlayAll || overlayTransforms) { - updateTransformFromGTPrim( xform, geoTime, - ctxt.granularity == GusdContext::PER_FRAME ); - } - - // visibility --------------------------------------------------------------- - updateVisibilityFromGTPrim(sourcePrim, geoTime, - (!ctxt.writeOverlay || ctxt.overlayAll) && - ctxt.granularity == GusdContext::PER_FRAME ); - - if( !writeOverlay || ctxt.overlayAll || ctxt.overlayPoints ) { - - // P - houAttr = sourcePrim->findAttribute("P", attrOwner, 0); - usdAttr = m_usdCurves.GetPointsAttr(); - if(houAttr && usdAttr && transformPoints ) { - houAttr = GusdGT_Utils::transformPoints( houAttr, loc_xform ); - } - updateAttributeFromGTPrim( attrOwner, "P", houAttr, usdAttr, geoTime ); - } - - if( !writeOverlay || ctxt.overlayAll ) { - - UsdTimeCode topologyTime = ctxt.time; - if( ctxt.writeStaticTopology ) { - topologyTime = UsdTimeCode::Default(); - } - - // Vertex counts - houAttr = gtCurves->getCurveCounts(); - usdAttr = m_usdCurves.GetCurveVertexCountsAttr(); - - // Houdini repeats point for closed beziers so we need to - if( order == 4 && closed ) { - auto modCounts = new GT_Real32Array( houAttr->entries(), 1 ); - for( GT_Size i = 0; i < houAttr->entries(); ++i ) { - modCounts->set( houAttr->getValue( i ) - 4, i ); - } - houAttr = modCounts; - } - updateAttributeFromGTPrim( GT_OWNER_INVALID, "vertexcounts", - houAttr, usdAttr, topologyTime ); - } - - if( !writeOverlay || ctxt.overlayAll || ctxt.overlayPoints ) { - // N - houAttr = sourcePrim->findAttribute("N", attrOwner, 0); - usdAttr = m_usdCurves.GetNormalsAttr(); - updateAttributeFromGTPrim( attrOwner, "N", houAttr, usdAttr, geoTime ); - - // v - houAttr = sourcePrim->findAttribute("v", attrOwner, 0); - usdAttr = m_usdCurves.GetVelocitiesAttr(); - updateAttributeFromGTPrim( attrOwner, "v", houAttr, usdAttr, geoTime ); - - // pscale & width - houAttr = sourcePrim->findAttribute("width", attrOwner, 0); - if(!houAttr) { - houAttr = sourcePrim->findAttribute("pscale", attrOwner, 0); - } - - usdAttr = m_usdCurves.GetWidthsAttr(); - updateAttributeFromGTPrim( attrOwner, "width", houAttr, usdAttr, geoTime ); - m_usdCurves.SetWidthsInterpolation( UsdGeomTokens->vertex ); - } - - // ------------------------------------------------------------------------- - - // primvars ---------------------------------------------------------------- - - if( !writeOverlay || ctxt.overlayAll || ctxt.overlayPrimvars ) { - - UsdTimeCode primvarTime = ctxt.time; - if( ctxt.writeStaticPrimvars ) { - primvarTime = UsdTimeCode::Default(); - } - - // TODO check that varying & facevarying working -- houdini might not support - // facevarying through GT - GusdGT_AttrFilter filter = ctxt.attributeFilter; - - filter.appendPattern(GT_OWNER_VERTEX, "^P ^N ^v ^width ^pscale"); - if(const GT_AttributeListHandle vtxAttrs = sourcePrim->getVertexAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_VERTEX; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( vtxAttrs, filter, UsdGeomTokens->vertex, primvarTime ); - } - if(const GT_AttributeListHandle constAttrs = sourcePrim->getDetailAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_CONSTANT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( constAttrs, filter, UsdGeomTokens->constant, primvarTime ); - } - if(const GT_AttributeListHandle uniformAttrs = sourcePrim->getUniformAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_UNIFORM; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( uniformAttrs, filter, UsdGeomTokens->uniform, primvarTime ); - } - - // If we have a "Cd" attribute, write it as both "Cd" and "displayColor". - // The USD guys promise me that this data will get "deduplicated" so there - // is not cost for doing this. - GT_Owner own; - if(GT_DataArrayHandle Cd = sourcePrim->findAttribute( "Cd", own, 0 )) { - - GT_AttributeMapHandle attrMap = new GT_AttributeMap(); - GT_AttributeListHandle attrList = new GT_AttributeList( attrMap ); - attrList = attrList->addAttribute( "displayColor", Cd, true ); - GusdGT_AttrFilter filter( "*" ); - GusdGT_AttrFilter::OwnerArgs owners; - owners << own; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( attrList, filter, s_ownerToUsdInterpCurve[own], primvarTime ); - } - // If we have a "Alpha" attribute, write it as both "Alpha" and "displayAlpha". - if(GT_DataArrayHandle Alpha = sourcePrim->findAttribute( "Alpha", own, 0 )) { - - GT_AttributeMapHandle attrMap = new GT_AttributeMap(); - GT_AttributeListHandle attrList = new GT_AttributeList( attrMap ); - attrList = attrList->addAttribute( "displayOpacity", Alpha, true ); - GusdGT_AttrFilter filter( "*" ); - GusdGT_AttrFilter::OwnerArgs owners; - owners << own; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( attrList, filter, s_ownerToUsdInterpCurve[own], primvarTime ); - } - } - - // ------------------------------------------------------------------------- - return GusdPrimWrapper::updateFromGTPrim(sourcePrim, houXform, ctxt, xformCache); -} - -PXR_NAMESPACE_CLOSE_SCOPE - - diff --git a/third_party/houdini/gusd/curvesWrapper.h b/third_party/houdini/gusd/curvesWrapper.h deleted file mode 100644 index 60891ea392..0000000000 --- a/third_party/houdini/gusd/curvesWrapper.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_CURVES_WRAPPER_H -#define GUSD_CURVES_WRAPPER_H - -#include "primWrapper.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/basisCurves.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -class GusdCurvesWrapper : public GusdPrimWrapper -{ -public: - GusdCurvesWrapper( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride = false ); - GusdCurvesWrapper( - const UsdGeomBasisCurves& usdCurves, - UsdTimeCode time, - GusdPurposeSet purposes ); - - virtual ~GusdCurvesWrapper(); - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdCurves; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) override; - - virtual bool isValid() const override; - - virtual bool refine(GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const override; -public: - - static GT_PrimitiveHandle - defineForWrite( const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - bool initUsdPrim( const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - UsdGeomBasisCurves m_usdCurves; - bool m_forceCreateNewGeo; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_CURVES_WRAPPER_H diff --git a/third_party/houdini/gusd/debugCodes.cpp b/third_party/houdini/gusd/debugCodes.cpp deleted file mode 100644 index e8f44f91e6..0000000000 --- a/third_party/houdini/gusd/debugCodes.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "debugCodes.h" - -#include "pxr/base/tf/registryManager.h" - - -PXR_NAMESPACE_OPEN_SCOPE - - -TF_REGISTRY_FUNCTION(TfDebug) -{ - TF_DEBUG_ENVIRONMENT_SYMBOL(GUSD_STAGECACHE, "GusdStageCache details."); -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/debugCodes.h b/third_party/houdini/gusd/debugCodes.h deleted file mode 100644 index 9498864ce1..0000000000 --- a/third_party/houdini/gusd/debugCodes.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_DEBUG_CODES_H -#define GUSD_DEBUG_CODES_H - -#include "pxr/pxr.h" -#include "pxr/base/tf/debug.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -TF_DEBUG_CODES( - GUSD_STAGECACHE -); - - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_DEBUG_CODES_H diff --git a/third_party/houdini/gusd/defaultArray.h b/third_party/houdini/gusd/defaultArray.h deleted file mode 100644 index f787a755e7..0000000000 --- a/third_party/houdini/gusd/defaultArray.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_DEFAULT_ARRAY_H -#define GUSD_DEFAULT_ARRAY_H - -#include "pxr/pxr.h" - -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -/// Simple array wrapper, providing an array that may either hold a -/// single constant value, or an array of values. -template -class GusdDefaultArray -{ -public: - using value_type = T; - using array_type = UT_Array; - - GusdDefaultArray() - { - if(SYSisPOD()) - memset((void*)&_default, 0, sizeof(T)); - } - - GusdDefaultArray(const T& defaultVal) - : _default(defaultVal) {} - - exint size() const - { return _array.size(); } - - void Clear() - { return _array.clear(); } - - bool IsConstant() const { return size() == 0; } - - bool IsVarying() const { return size() > 0; } - - T& GetDefault() { return _default; } - const T& GetDefault() const { return _default; } - - void SetDefault(const T& val) {_default = val; } - - /// Turn this into a constant array, with value @a val. - void SetConstant(const T& val) - { - Clear(); - SetDefault(val); - } - - T& operator()(exint i) - { return IsVarying() ? _array(i) : GetDefault(); } - - const T& operator()(exint i) const - { return IsVarying() ? _array(i) : GetDefault(); } - - array_type& GetArray() { return _array; } - - const array_type& GetArray() const { return _array; } - -private: - array_type _array; - T _default; -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /*GUSD_DEFAULT_ARRAY_H*/ diff --git a/third_party/houdini/gusd/error.cpp b/third_party/houdini/gusd/error.cpp deleted file mode 100644 index 7b69ae86f5..0000000000 --- a/third_party/houdini/gusd/error.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "error.h" - -#include -#include - -#include "pxr/base/arch/stackTrace.h" - - -PXR_NAMESPACE_OPEN_SCOPE - - -void -GusdPostErrorHelper::Msg(const char* msg) const -{ - UTaddGeneric(_sev, "Common", UT_ERROR_JUST_STRING, msg); -} - - -void -GusdErrorTransport::StealErrors(UT_ErrorManager& victim, - UT_ErrorSeverity sev, - bool borrowOnly) -{ - if(_mgr) { - auto victimSev = victim.getSeverity(); - if(victimSev > SYSmax(sev, UT_ERROR_NONE)) { - UT_Lock::Scope lock(_lock); - _mgr->stealErrors(victim, /*range start*/ 0, /*range end*/ -1, - sev, borrowOnly); - } - } -} - - -std::string -GusdGetErrors(UT_ErrorManager* mgr, UT_ErrorSeverity sev) -{ - std::string err; - if(mgr && mgr->getSeverity() >= SYSmin(sev, UT_ERROR_MESSAGE)) { - UT_String msg; - mgr->getErrorMessages(msg, sev, /*headerflag*/ 0); - err = msg.toStdString(); - } - return err; -} - - -namespace { - - -void -_SanitizeErrorString(UT_WorkBuffer& buf) -{ - // When errors are displayed in the MMB node menu, they are displayed with - // basic HTML formatting. - // An artifact of this is that any text within '<>' brackets is not - // displayed, since it is interpreted as markup. But <> brackets are common - // in Tf errors. For instance, errors referring to UsdPrim instances usually - // come wrapped in <> brackets. - // As a temporary workaround, to ensure that errors remain visible on nodes, - // swap any occurrences of <> with []. - // Long term, it would be better to have some way of telling the MMB display - // to not apply any special formatting. - - UT_WorkBuffer::AutoLock lock(buf); - char* str = lock.string(); - for(exint i = 0; i < buf.length(); ++i) { - - switch(str[i]) { - case '<': str[i] = '['; break; - case '>': str[i] = ']'; break; - default: break; - } - } -} - - -void -_FormatErrorSimple(const TfEnum& code, - const TfCallContext& ctx, - const std::string& msg, - UT_WorkBuffer& buf) -{ - buf.append(TfDiagnosticMgr::GetCodeName(code).c_str()); - buf.append(": ", 2); - UT_String fn(ctx.GetFunction()); - if(!ctx.IsHidden() && fn.isstring()) { - buf.append(fn); - buf.append(" -- ", 4); - } - buf.append(msg.c_str()); - _SanitizeErrorString(buf); -} - - -void -_FormatErrorVerbose(const TfEnum& code, - const TfCallContext& ctx, - const std::string& msg, - UT_WorkBuffer& buf) -{ - buf.append(TfDiagnosticMgr::GetCodeName(code).c_str()); - int thread = SYSgetSTID(); - if(thread != 1) - buf.appendSprintf(" (thread %d)", thread); - buf.append(": ", 2); - - UT_String fn(ctx.GetFunction()); - UT_String file(ctx.GetFile()); - - if(ctx.IsHidden() || !fn.isstring() || !file.isstring()) { - buf.append(msg.c_str()); - buf.append('['); - buf.append(ArchGetProgramNameForErrors()); - buf.append(']'); - } else { - buf.appendSprintf(" in %s at line %zu of %s -- %s", - fn.c_str(), ctx.GetLine(), - file.c_str(), msg.c_str()); - } - _SanitizeErrorString(buf); -} - - -} // namespace - - -UT_ErrorSeverity -GusdTfErrorScope::_Update() -{ - int sev = UT_ERROR_NONE; - - if(_mgr && _sev > UT_ERROR_NONE) { - auto end = _mark.GetEnd(); - - UT_WorkBuffer buf; - - for(auto it = _mark.GetBegin(); it != end; ++it) { - - UT_SourceLocation loc(it->GetSourceFileName().c_str(), - it->GetSourceLineNumber()); - buf.clear(); - // XXX: Not sure what verbosity level we want for errors. - // Maybe make it configurable from the environment? - if(1) { - _FormatErrorVerbose(it->GetDiagnosticCode(), - it->GetContext(), it->GetCommentary(), buf); - } else { - _FormatErrorSimple(it->GetDiagnosticCode(), - it->GetContext(), it->GetCommentary(), buf); - } - - sev = _mgr->addGeneric("Common", UT_ERROR_JUST_STRING, - buf.buffer(), _sev, &loc); - } - } - _mark.Clear(); - return UT_ErrorSeverity(sev); -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/error.h b/third_party/houdini/gusd/error.h deleted file mode 100644 index f26c48defa..0000000000 --- a/third_party/houdini/gusd/error.h +++ /dev/null @@ -1,206 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_ERROR_H -#define GUSD_ERROR_H - -#include "api.h" - -#include "pxr/pxr.h" - -#include "pxr/base/arch/hints.h" -#include "pxr/base/tf/errorMark.h" - -#include -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -/// Evaluate and post an error message, based on a configurable -/// reporting severity. -/// -/// This macros is used as follows: -/// \code -/// GUSD_GENERIC_ERR(sev).Msg("Failed because of: %s", reason); -/// \endcode -/// -/// The result of the macro itself is a GusdPostErrorHelper object, -/// through which errors may be posted. If the severity is UT_ERROR_NONE, -/// none of the error-posting code will be invoked. -#define GUSD_GENERIC_ERR(sev) \ - if(sev == UT_ERROR_NONE) /*empty*/ ; else GusdPostErrorHelper(sev) - -#define GUSD_ERR() GusdPostErrorHelper(UT_ERROR_ABORT) - -#define GUSD_WARN() GusdPostErrorHelper(UT_ERROR_WARNING) - -#define GUSD_MSG() GusdPostErrorHelper(UT_ERROR_MESSAGE) - - -class GUSD_API GusdPostErrorHelper -{ -public: - GusdPostErrorHelper(UT_ErrorSeverity sev) : _sev(sev) {} - - void Msg(const char* msg) const; - - template - void Msg(const char* format, T&& arg1, Args&&... args) const; - -private: - UT_ErrorSeverity _sev; -}; - - -template -void -GusdPostErrorHelper::Msg(const char* format, T&& arg1, Args&&... args) const -{ - UT_WorkBuffer buf; - buf.sprintf(format, std::forward(arg1), std::forward(args)...); - UTaddGeneric(_sev, "Common", UT_ERROR_JUST_STRING, buf.buffer()); -} - - -/// Helper class used to propagate errors from different threads. -/// There is a thread-local UT_ErrorManager for each thread in Houdini. -/// Error reporting methods should generally just call UTaddError(), -/// UTaddWarning(), etc. to report errors, -- or GUSD_ERR, and similar -/// helpers above -- which will put errors on currently scoped UT_ErrorManager -/// of the active thread. -/// When splitting into threads, though, an additional step is required -/// to pull any error messages from each thread that is spawned, to copy them -/// back into the originating thread. -/// -/// Example: -/// \code -/// GusdErrorTransport errTransport; -/// UTparallelFor( -/// UT_BlockedRange(0,n), -/// [&](const UT_BlockedRange& r) -/// { -/// GusdAutoErrorTransport autoErrTransport(errTransport): -/// UTaddError(...); -/// ... -/// }); -/// \endcode -class GUSD_API GusdErrorTransport : UT_NonCopyable -{ -public: - GusdErrorTransport(UT_ErrorManager* mgr=UTgetErrorManager()) : _mgr(mgr) {} - - GusdErrorTransport(int thread) : _mgr(UTgetErrorManager(thread)) {} - - void operator()() - { StealGlobalErrors(); } - - void StealErrors(UT_ErrorManager& victim, - UT_ErrorSeverity sev=UT_ERROR_NONE, - bool borrowOnly=false); - - void StealGlobalErrors(UT_ErrorSeverity sev=UT_ERROR_NONE, - bool borrowOnly=false) - { StealErrors(*UTgetErrorManager(), sev, borrowOnly); } - -private: - UT_Lock _lock; - UT_ErrorManager* const _mgr; -}; - - -/// Helper for ensuring consistent, automatic transport of errors from -/// within threaded loops. This avoids the need for HextUT_ErrorTransport -/// users to manually trigger error transport when returning from a -/// threaded call. -class GusdAutoErrorTransport : UT_NonCopyable -{ -public: - GusdAutoErrorTransport(GusdErrorTransport& transport) - : _transport(transport) {} - - ~GusdAutoErrorTransport() { _transport(); } - -private: - GusdErrorTransport& _transport; -}; - - -/// Helper for extracting error messages from \p mgr. -/// Any errors with a severity greater or equal to \p sev are included. -GUSD_API std::string -GusdGetErrors(UT_ErrorManager* mgr=UTgetErrorManager(), - UT_ErrorSeverity sev=UT_ERROR_NONE); - - -/// Helper for catching Tf errors and forwarding them to a UT_ErrorManager. -/// Note that it's currently only possible to forward a subset of Tf errors. -/// Warnings and status messages cannot be forwarded. -class GUSD_API GusdTfErrorScope : UT_NonCopyable -{ -public: - /// Construct a scope for capturing Tf errors and forwarding them to \p mgr. - /// Captured Tf errors are forwarding to \p mgr with a severity of \p sev. - /// If \p sev is UT_ERROR_NONE, the Tf errors will be silently ignored. - GusdTfErrorScope(UT_ErrorSeverity sev=UT_ERROR_ABORT, - UT_ErrorManager* mgr=UTgetErrorManager()) - : _mgr(mgr), _sev(sev) - { _mark.SetMark(); } - - ~GusdTfErrorScope() - { - if(ARCH_UNLIKELY(!_mark.IsClean())) - _Update(); - } - - explicit operator bool() const { return _mgr; } - - /// Clean any errors on the current scope. - /// Returns the resulting error level. - UT_ErrorSeverity Update() - { - if(_mark.IsClean()) - return UT_ERROR_NONE; - return _Update(); - } - - bool IsClean() const { return _mark.IsClean(); } - - UT_ErrorSeverity GetLogSeverity() const { return _sev; } - -protected: - UT_ErrorSeverity _Update(); - -private: - TfErrorMark _mark; - UT_ErrorManager* const _mgr; - const UT_ErrorSeverity _sev; -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_ERROR_H diff --git a/third_party/houdini/gusd/groupBaseWrapper.cpp b/third_party/houdini/gusd/groupBaseWrapper.cpp deleted file mode 100644 index 0ebb55b851..0000000000 --- a/third_party/houdini/gusd/groupBaseWrapper.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "groupBaseWrapper.h" - -#include "context.h" -#include "GU_PackedUSD.h" -#include "GU_USD.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include "pxr/usd/usdGeom/boundable.h" - -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - -// drand48 and srand48 defined in SYS_Math.h as of 13.5.153. and conflicts with imath. -#undef drand48 -#undef srand48 - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -GusdGroupBaseWrapper::GusdGroupBaseWrapper() - : GusdPrimWrapper() -{ -} - -GusdGroupBaseWrapper::GusdGroupBaseWrapper( - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdPrimWrapper( time, purposes ) -{ -} - -GusdGroupBaseWrapper::GusdGroupBaseWrapper( const GusdGroupBaseWrapper &in ) - : GusdPrimWrapper( in ) -{ -} - -GusdGroupBaseWrapper::~GusdGroupBaseWrapper() -{} - -namespace { -bool -containsBoundable( const UsdPrim& p, GusdPurposeSet purposes ) -{ - // Return true if this prim has a boundable geom descendant. - // Boundables are gprims and the point instancers. - // Used when unpacking so we don't create empty GU prims. - - UsdGeomImageable ip( p ); - if(!ip) - return false; - - TfToken purpose; - ip.GetPurposeAttr().Get(&purpose); - if( !GusdPurposeInSet( purpose, purposes ) && !p.IsMaster() ) - return false; - - if( p.IsA() ) - return true; - - for( const auto& child : p.GetFilteredChildren( - UsdTraverseInstanceProxies(UsdPrimDefaultPredicate)) ) - { - if( containsBoundable( child, purposes )) - return true; - } - return false; -} -} - -bool -GusdGroupBaseWrapper::unpack( - GU_Detail& gdr, - const UT_StringRef& fileName, - const SdfPath& primPath, - const UT_Matrix4D& xform, - fpreal frame, - const char* viewportLod, - GusdPurposeSet purposes ) -{ - UsdPrim usdPrim = getUsdPrim().GetPrim(); - - // To unpack a xform or a group, create a packed prim for - // each child - UT_Array usefulChildren; - for( const auto& child : usdPrim.GetFilteredChildren( - UsdTraverseInstanceProxies(UsdPrimDefaultPredicate)) ) - { - if( containsBoundable( child, purposes )) - usefulChildren.append( child ); - } - - // Sort the children to maintain consistency in unpacking. - GusdUSD_Utils::SortPrims(usefulChildren); - - SdfPath strippedPathHead(primPath.StripAllVariantSelections()); - for( const auto &child : usefulChildren ) - { - // Replace the head of the path to perserve variant specs. - SdfPath path = child.GetPath().ReplacePrefix(strippedPathHead, - primPath ); - - GU_PrimPacked *guPrim = - GusdGU_PackedUSD::Build( gdr, fileName, path, - frame, viewportLod, purposes ); - - UT_Matrix4D m; - GusdUSD_XformCache::GetInstance().GetLocalTransformation( - child, frame, m ); - - UT_Matrix4D m1 = m * xform; - UT_Vector3 p; - m1.getTranslates( p ); - - guPrim->setLocalTransform(UT_Matrix3( m1 )); - guPrim->setPos3(0, p); - } - return true; -} - -bool -GusdGroupBaseWrapper::refineGroup( - const UsdPrim& prim, - GT_Refine& refiner, - const GT_RefineParms* parms ) const -{ - UsdPrimSiblingRange children = prim.GetFilteredChildren( - UsdTraverseInstanceProxies(UsdPrimDefaultPredicate)); - - GT_PrimCollect* collection = NULL; - for( const UsdPrim& child : children ) - { - GT_PrimitiveHandle gtPrim = - GusdPrimWrapper::defineForRead( - UsdGeomImageable(child), - m_time, - m_purposes ); - - if( gtPrim ) - { - UT_Matrix4D m; - GusdUSD_XformCache::GetInstance().GetLocalTransformation( - child, m_time, m ); - gtPrim->setPrimitiveTransform( new GT_Transform( &m, 1 ) ); - - if( !collection ) { - collection = new GT_PrimCollect(); - } - collection->appendPrimitive( gtPrim ); - } - } - if( collection ) { - refiner.addPrimitive( collection ); - return true; - } - return false; -} - -bool -GusdGroupBaseWrapper::updateGroupFromGTPrim( - const UsdGeomImageable& destPrim, - const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) -{ - if( !destPrim ) - return false; - - if( !ctxt.writeOverlay && ctxt.purpose != UsdGeomTokens->default_ ) { - destPrim.GetPurposeAttr().Set( ctxt.purpose ); - } - - if( !ctxt.writeOverlay || ctxt.overlayTransforms || ctxt.overlayAll ) - { - GfMatrix4d xform = computeTransform( - destPrim.GetPrim().GetParent(), - ctxt.time, - houXform, - xformCache ); - - - updateTransformFromGTPrim( xform, ctxt.time, - ctxt.granularity == GusdContext::PER_FRAME ); - - // cache this transform so that if we write a child, we can compute its - // relative transform. - xformCache[destPrim.GetPrim().GetPath()] = houXform; - } - - // sourcePrim can be NULL if the ROP wants to write a transform without having - // a corresponding GT_Primitive - if( !sourcePrim ) { - return true; - } - - if( !ctxt.writeOverlay || ctxt.overlayPrimvars || ctxt.overlayAll ) - { - GusdGT_AttrFilter filter = ctxt.attributeFilter; - filter.appendPattern(GT_OWNER_UNIFORM, "^P"); - if( const GT_AttributeListHandle uniformAttrs = sourcePrim->getUniformAttributes()) - { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_UNIFORM; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( uniformAttrs, filter, UsdGeomTokens->uniform, ctxt.time ); - } - } - - // Set active state - updateGroupActiveFromGTPrim(destPrim, sourcePrim, ctxt.time); - - return true; -} - -void -GusdGroupBaseWrapper::updateGroupActiveFromGTPrim( - const UsdGeomImageable& destPrim, - const GT_PrimitiveHandle& sourcePrim, - UsdTimeCode time) -{ - UsdPrim prim = destPrim.GetPrim(); - - GT_Owner attrOwner; - GT_DataArrayHandle houAttr - = sourcePrim->findAttribute(GUSD_ACTIVE_ATTR, attrOwner, 0); - if (houAttr) { - GT_String state = houAttr->getS(0); - if (state) { - if (strcmp(state, "active") == 0) { - prim.SetActive(true); - } else if (strcmp(state, "inactive") == 0) { - prim.SetActive(false); - } - } - } -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/groupBaseWrapper.h b/third_party/houdini/gusd/groupBaseWrapper.h deleted file mode 100644 index 33fe9a99f3..0000000000 --- a/third_party/houdini/gusd/groupBaseWrapper.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GROUP_BASE_WRAPPER_H -#define GUSD_GROUP_BASE_WRAPPER_H - -#include "primWrapper.h" - -#include "pxr/pxr.h" - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdGroupBaseWrapper : public GusdPrimWrapper -{ -public: - GusdGroupBaseWrapper(); - GusdGroupBaseWrapper( - UsdTimeCode time, - GusdPurposeSet purposes ); - GusdGroupBaseWrapper( const GusdGroupBaseWrapper& in ); - virtual ~GusdGroupBaseWrapper(); - - virtual bool unpack( - GU_Detail& gdr, - const UT_StringRef& fileName, - const SdfPath& primPath, - const UT_Matrix4D& xform, - fpreal frame, - const char * viewportLod, - GusdPurposeSet purposes ) override; - -protected: - bool refineGroup( - const UsdPrim& prim, - GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const; - - bool updateGroupFromGTPrim( - const UsdGeomImageable& destPrim, - const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ); - - void updateGroupActiveFromGTPrim( - const UsdGeomImageable& destPrim, - const GT_PrimitiveHandle& sourcePrim, - UsdTimeCode time ); - -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif diff --git a/third_party/houdini/gusd/gusd.h b/third_party/houdini/gusd/gusd.h deleted file mode 100644 index 6369b4dcb5..0000000000 --- a/third_party/houdini/gusd/gusd.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_GUSD_H -#define GUSD_GUSD_H - -#include "pxr/usd/usd/prim.h" -#include "api.h" - -#include "pxr/pxr.h" -#include -#include - -class GA_PrimitiveFactory; - -PXR_NAMESPACE_OPEN_SCOPE - -class TfToken; - -GUSD_API -void GusdInit(); - -GUSD_API -void GusdNewGeometryPrim( GA_PrimitiveFactory* f ); - -GUSD_API -void GusdNewGeometryIO(); - -// We sometimes need to be able to convert an absolute path to an asset to a -// path that can be resolved to an asset using lib Ar. How this is done depends -// on the site specific system used to resolve assets, so we provide a callback. -typedef std::function GusdPathComputeFunc; - -GUSD_API -void GusdRegisterComputeRelativeSearchPathFunc( const GusdPathComputeFunc &func ); - -GUSD_API -std::string GusdComputeRelativeSearchPath( const std::string &path ); - -// When we write a new asset to a USD file, we want to assign a "kind". By -// default we mark it a "component". -GUSD_API -void GusdSetAssetKind( const TfToken &kind ); - -GUSD_API -TfToken GusdGetAssetKind(); - -// We often need to call some function, which may be system -// specific, on a USD prim so we provide a callback. -typedef std::function GusdUsdPrimFunc; - -GUSD_API -void GusdRegisterOperateOnUsdPrimFunc( const GusdUsdPrimFunc &func ); - -GUSD_API -bool GusdOperateOnUsdPrim( const UsdPrim &prim ); - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif diff --git a/third_party/houdini/gusd/instancerWrapper.cpp b/third_party/houdini/gusd/instancerWrapper.cpp deleted file mode 100644 index 14f565f04d..0000000000 --- a/third_party/houdini/gusd/instancerWrapper.cpp +++ /dev/null @@ -1,1666 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "instancerWrapper.h" - -#include "context.h" -#include "GT_PrimCache.h" -#include "GU_PackedUSD.h" -#include "refiner.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pxr/base/gf/quatf.h" -#include "pxr/base/tf/pathUtils.h" - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; -using std::string; -using std::vector; -using std::map; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -TF_DEFINE_PRIVATE_TOKENS( - _tokens, - ((prunable, "pruning:prunable")) - (Xform) -); - -namespace { - -const SdfPath kReferenceProtoPath("Prototypes"); - -// TODO This is duped from OP_gusd/ROP_UsdInstPrototypes.cpp. -// Move to a common location. -SdfPath _rootPrimPath(const SdfPath path) -{ - if( path.IsRootPrimPath() - || path.IsEmpty()) { - return path; - } - - return _rootPrimPath(path.GetParentPath()); -} - -void setAngularVelocity(GT_DataArrayHandle houWAttr, std::vector& houWArray) { - // Houdini stores angular velocity in radians per second. - // USD is degrees per second - const GT_Size numVals = houWAttr->entries() * houWAttr->getTupleSize(); - houWArray = std::vector(numVals); - houWAttr->fillArray(houWArray.data(), 0, houWAttr->entries(), houWAttr->getTupleSize()); - std::transform( - houWArray.begin(), - houWArray.end(), - houWArray.begin(), - std::bind1st(std::multiplies(), 180.0 / M_PI)); -} - -void setTransformAttrsFromComponents(UsdAttribute& usdPositionAttr, - UsdAttribute& usdRotationAttr, - UsdAttribute& usdScaleAttr, - const GT_AttributeListHandle& gtAttrs, - UsdTimeCode time) -{ - // Build instance transform using houdini attribute conventions. - // It's assumed that the GT_AttributeListHandle contains point attributes. - if (!usdRotationAttr.IsValid() - || !usdScaleAttr.IsValid() - || !gtAttrs) - return; - - GT_DataArrayHandle houPosAttr = gtAttrs->get("P", 0); - GT_DataArrayHandle houNormalAttr = gtAttrs->get("N", 0); - GT_DataArrayHandle houVelAttr = gtAttrs->get("v", 0); - GT_DataArrayHandle houUpAttr = gtAttrs->get("up", 0); - GT_DataArrayHandle houTransAttr = gtAttrs->get("trans", 0); - GT_DataArrayHandle houScaleAttr = gtAttrs->get("scale", 0); - GT_DataArrayHandle houUniformScaleAttr = gtAttrs->get("pscale", 0); - GT_DataArrayHandle houRotAttr = gtAttrs->get("rot", 0); - GT_DataArrayHandle houOrientAttr = gtAttrs->get("orient", 0); - GT_DataArrayHandle houPivotAttr = gtAttrs->get("pivot", 0); - - bool needsScale = ( houScaleAttr || houUniformScaleAttr ); - bool needsFullScale = bool(houScaleAttr); - bool needsRotation = ( houNormalAttr || houVelAttr || houUpAttr - || houRotAttr || houOrientAttr ); - - const float *houPosArray=NULL, *houNormalArray=NULL, *houVelArray=NULL, - *houUpArray=NULL, *houTransArray=NULL, *houScaleArray=NULL, - *houUniformScaleArray=NULL, *houRotArray=NULL, - *houOrientArray=NULL, *houPivotArray=NULL; - - GT_DataArrayHandle houPosBuffer, houNormalBuffer, houVelBuffer, houUpBuffer, - houTransBuffer, houScaleBuffer, houUniformScaleBuffer, - houRotBuffer, houOrientBuffer, houPivotBuffer; - - if(houPosAttr && houPosAttr->getTupleSize() == 3) - houPosArray = houPosAttr->getF32Array(houPosBuffer); - - // Instance prim isn't valid if we don't have position data - if(!houPosAttr || !houPosArray) - return; - - if(needsScale) { - if(houScaleAttr && houScaleAttr->getTupleSize() == 3) - houScaleArray = houScaleAttr->getF32Array(houUniformScaleBuffer); - - if(houUniformScaleAttr && houUniformScaleAttr->getTupleSize() == 1) - houUniformScaleArray = houUniformScaleAttr - ->getF32Array(houUniformScaleBuffer); - } - - if(needsRotation) { - if(houNormalAttr && houNormalAttr->getTupleSize() == 3) - houNormalArray = houNormalAttr->getF32Array(houNormalBuffer); - - if(houVelAttr && houVelAttr->getTupleSize() == 3) - houVelArray = houVelAttr->getF32Array(houVelBuffer); - - if(houUpAttr && houUpAttr->getTupleSize() == 3) - houUpArray = houUpAttr->getF32Array(houUpBuffer); - - if(houTransAttr && houTransAttr->getTupleSize() == 3) - houTransArray = houTransAttr->getF32Array(houTransBuffer); - - if(houRotAttr && houRotAttr->getTupleSize() == 4) - houRotArray = houRotAttr->getF32Array(houRotBuffer); - - if(houOrientAttr && houOrientAttr->getTupleSize() == 4) - houOrientArray = houOrientAttr->getF32Array(houOrientBuffer); - - if(houPivotAttr && houPivotAttr->getTupleSize() == 3) - houPivotArray = houPivotAttr->getF32Array(houPivotBuffer); - - // Houdini convention is to substitute v for N if N is missing - if(!houNormalArray) - houNormalArray = houVelArray; - } - - if(needsScale || needsRotation) { - - UT_Vector3 defaultN(0,0,0); - UT_Vector3 scale, up, trans, pivot; - UT_Quaternion rot, orient; - float defaultScale = 1.0; - UT_Matrix4F instanceM; - - const int numPoints = houPosAttr->entries(); - - GT_DataArrayHandle houRotationsHandle; - GT_Real32Array* houRotations = NULL; - if(needsRotation) { - houRotations = new GT_Real32Array(numPoints, 4); - houRotationsHandle = houRotations; - } - - GT_DataArrayHandle houScalesHandle; - GT_DataArrayHandle houUniformScalesHandle; - GT_Real32Array* houScales = NULL; - GT_Real32Array* houUniformScales = NULL; - if(needsFullScale) { - houScales = new GT_Real32Array(numPoints, 3); - houScalesHandle = houScales; - } - else if(needsScale) { - houUniformScales = new GT_Real32Array(numPoints, 3); - houUniformScalesHandle = houUniformScales; - } - - - for(std::size_t i=0; isetTuple(scale.data(), i); - } - else if(houUniformScales != NULL) { - houUniformScales->set(scale.x(), i, 0); - houUniformScales->set(scale.x(), i, 1); - houUniformScales->set(scale.x(), i, 2); - } - if(houRotations != NULL) { - // TODO clean this up - rot.updateFromRotationMatrix(xform); - GfQuatf gfRot(rot.w(), GfVec3f(rot.x(), rot.y(), rot.z())); - gfRot.Normalize(); - // Houdini quaternions are i,j,k,w - rot.assign(gfRot.GetImaginary()[0], - gfRot.GetImaginary()[1], - gfRot.GetImaginary()[2], - gfRot.GetReal()); - houRotations->setTuple(rot.data(), i); - } - } - - GusdGT_Utils::setUsdAttribute(usdPositionAttr, houPosBuffer, time); - - if(needsRotation && houRotationsHandle) { - GusdGT_Utils::setUsdAttribute(usdRotationAttr, houRotationsHandle, time); - } - - if(needsFullScale && houScalesHandle) { - GusdGT_Utils::setUsdAttribute(usdScaleAttr, houScalesHandle, time); - } - else if(needsScale && houUniformScalesHandle) { - GusdGT_Utils::setUsdAttribute(usdScaleAttr, - houUniformScalesHandle, time); - } - } -} - -} // anon namespace - -///////////////////////////////////////////////////////////////////////////// - -GusdInstancerWrapper:: -GusdInstancerWrapper( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - bool isOverride ) -{ - initUsdPrim( stage, path, isOverride ); -} - -GusdInstancerWrapper:: -GusdInstancerWrapper( - const UsdGeomPointInstancer& usdInstancer, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdPrimWrapper( time, purposes ) - , m_usdPointInstancer( usdInstancer ) -{ -} - -GusdInstancerWrapper:: -~GusdInstancerWrapper() -{} - -bool GusdInstancerWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - bool newPrim = true; - if( asOverride ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing ) { - newPrim = false; - m_usdPointInstancer = UsdGeomPointInstancer(stage->OverridePrim( path )); - } - else { - // When fracturing, we want to override the outside surfaces and create - // new inside surfaces in one export. So if we don't find an existing prim - // with the given path, create a new one. - m_usdPointInstancer = UsdGeomPointInstancer::Define( stage, path ); - } - } - else { - m_usdPointInstancer = UsdGeomPointInstancer::Define( stage, path ); - } - if( !m_usdPointInstancer || !m_usdPointInstancer.GetPrim().IsValid() ) { - TF_WARN( "Unable to create %s instancer '%s'.", newPrim ? "new" : "override", path.GetText() ); - } - return bool( m_usdPointInstancer ); -} - -void GusdInstancerWrapper::storePreOverlayData(bool justProtoIndices, - const UsdTimeCode* time=nullptr) { - // Store point instancer attribute data so that we can write "partial" - // overlays during overlay transform. Once a new attribute list is overlaid - // we lose the original data, so we have to store it somewhere if we want to - // access it for points where we just want the original data. - - UsdGeomPointInstancer& pI = m_usdPointInstancer; - UsdAttribute usdProtoIndicesAttr = pI.GetProtoIndicesAttr(); - m_preOverlayDataMap[UsdGeomTokens->protoIndices] = - PreOverlayDataEntry(usdProtoIndicesAttr); - if (!justProtoIndices) { - m_preOverlayDataMap[UsdGeomTokens->positions] = - PreOverlayDataEntry(pI.GetPositionsAttr()); - m_preOverlayDataMap[UsdGeomTokens->orientations] = - PreOverlayDataEntry(pI.GetOrientationsAttr()); - m_preOverlayDataMap[UsdGeomTokens->scales] = - PreOverlayDataEntry(pI.GetScalesAttr()); - m_preOverlayDataMap[UsdGeomTokens->velocities] = - PreOverlayDataEntry(pI.GetVelocitiesAttr()); - m_preOverlayDataMap[UsdGeomTokens->angularVelocities] = - PreOverlayDataEntry(pI.GetAngularVelocitiesAttr()); - } - - // Get all the time samples we have for prototype indices, or use the - // the provided timecode. - std::vector times; - if (time == nullptr){ - usdProtoIndicesAttr.GetTimeSamples(×); - } else { - times.push_back(time->GetValue()); - } - - // For time samples where we have prototype indices, store data. - for (int i = 0; i < times.size(); i++) { - for (const TfToken& token : m_usdGeomTokens) { - if (!m_preOverlayDataMap.count(token)) - continue; - boost::apply_visitor(StoreAtTime(UsdTimeCode(times[i])), m_preOverlayDataMap[token]); - } - } - -} -void GusdInstancerWrapper::clearPreOverlayData() { - // Clears original data so we don't have to store unnecessary information. - for (const TfToken& token : m_usdGeomTokens){ - if (!m_preOverlayDataMap.count(token)) - continue; - boost::apply_visitor(ClearData{}, m_preOverlayDataMap[token]); - } - -} - -GT_PrimitiveHandle GusdInstancerWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - GusdInstancerWrapper* instancePrim = - new GusdInstancerWrapper( stage, path, ctxt, ctxt.writeOverlay ); - - if( ctxt.writeOverlay ) { - // For overlays, store original point instancer data in case of partial - // overlay. - bool justProtoIndices = (ctxt.overlayPoints || ctxt.overlayAll); - if (ctxt.granularity != GusdContext::PER_FRAME){ - instancePrim->storePreOverlayData(justProtoIndices); - } else { - instancePrim->storePreOverlayData(justProtoIndices, &ctxt.time); - } - } - - if(!ctxt.writeOverlay || ctxt.overlayAll) { - - // Set empty defaults for positions, scale, and indices. - // This prevents katana errors when expanding per-frame exports - // with animated visibility. - if(instancePrim) { - VtIntArray intArray; - VtVec3fArray vec3fArray; - VtQuathArray quathArray; - instancePrim->m_usdPointInstancer.GetProtoIndicesAttr().Set(intArray, UsdTimeCode::Default()); - instancePrim->m_usdPointInstancer.GetPositionsAttr().Set(vec3fArray, UsdTimeCode::Default()); - instancePrim->m_usdPointInstancer.GetScalesAttr().Set(vec3fArray, UsdTimeCode::Default()); - instancePrim->m_usdPointInstancer.GetOrientationsAttr().Set(quathArray, UsdTimeCode::Default()); - } - - } - - // Write out prototypes in usd and build an index map for prototype - // relationships. - instancePrim->writePrototypes( ctxt, stage, sourcePrim ); - - if( ctxt.writeOverlay ) { - // If we are writing an overlay, turn off pruning for this point instancer. - // We may have shuffled the instance index order. - if( UsdAttribute attr = - instancePrim->m_usdPointInstancer.GetPrim().CreateAttribute( - _tokens->prunable, SdfValueTypeNames->Bool, - false, SdfVariabilityUniform )) { - attr.Set( false ); - } - } - - - return GT_PrimitiveHandle( instancePrim ); -} - -GT_PrimitiveHandle GusdInstancerWrapper:: -defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdInstancerWrapper( - UsdGeomPointInstancer( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdInstancerWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay ); - - if( ctxt.writeOverlay ) { - // If per frame and redefining, we don't need to store all data, so - // clear previous frames and store this frame's. - bool justProtoIndices = (ctxt.overlayPoints || ctxt.overlayAll); - if (ctxt.granularity == GusdContext::PER_FRAME){ - clearPreOverlayData(); - storePreOverlayData(justProtoIndices); - } else { - storePreOverlayData(justProtoIndices, &ctxt.time); - } - } - - if(!ctxt.writeOverlay || ctxt.overlayAll) { - - // Set empty defaults for positions, scale, and indices. - // This prevents katana errors when expanding per-frame exports - // with animated visibility. - if( m_usdPointInstancer ) { - VtIntArray intArray; - VtVec3fArray vec3fArray; - VtQuathArray quathArray; - m_usdPointInstancer.GetProtoIndicesAttr().Set( - intArray, UsdTimeCode::Default()); - m_usdPointInstancer.GetPositionsAttr().Set( - vec3fArray, UsdTimeCode::Default()); - m_usdPointInstancer.GetScalesAttr().Set( - vec3fArray, UsdTimeCode::Default()); - m_usdPointInstancer.GetOrientationsAttr().Set( - quathArray, UsdTimeCode::Default()); - - } - } - - stage->OverridePrim( path.AppendPath( - !m_prototypesScope.IsEmpty() ? m_prototypesScope : kReferenceProtoPath)); - - m_relationshipIndexMap.clear(); - clearCaches(); - - // Write out prototypes in usd and build an index map for prototype - // relationships. - writePrototypes( ctxt, stage, sourcePrim ); - - return true; -} - - -const char* GusdInstancerWrapper:: -className() const -{ - return "GusdInstancerWrapper"; -} - - -void GusdInstancerWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdInstancerWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdInstancerWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdInstancerWrapper:: -doSoftCopy() const -{ - // TODO - return GT_PrimitiveHandle(new GusdInstancerWrapper( *this )); -} - - -bool GusdInstancerWrapper::isValid() const -{ - return static_cast(m_usdPointInstancer); -} - -void GusdInstancerWrapper:: -writePrototypes(const GusdContext& ctxt, const UsdStagePtr& stage, - const GT_PrimitiveHandle& sourcePrim) -{ - // Write out all the prototypes in usd, populate the prototype relationship - // array and build a map from prototype name to an index into the prototype - // array. - // - // When we write the point instancer, we will write all our prototypes - // into a group called "Prototypes" that is a child of the point instancer. - // Each prototype will be given the name "prototype_*" numbered for each - // primitive at the marked "usdprototypespath" node. - // - // This map is used to compute the index that is stored in each enty of the - // point array that is used to pick which prototype to use for that entry. - - if( !m_usdPointInstancer) { - TF_WARN( "No usd point instancer found to write prototypes to." ); - return; - } - - // Check to make sure we have a valid source prim (NULL when 0 points) - if (sourcePrim == NULL) { - return; - } - - // Get prorotypes path from context in case it was set as a parameter. - string usdPrototypesPath = ctxt.usdPrototypesPath; - GT_Owner owner; - GT_DataArrayHandle prototypesPathAttr; - // If an attribute exists for usdprototypespath, set that as our path. - prototypesPathAttr = sourcePrim->findAttribute("usdprototypespath", owner, 0); - if(prototypesPathAttr != NULL && prototypesPathAttr->entries() > 0) { - usdPrototypesPath = prototypesPathAttr->getS(0); - } - - if (usdPrototypesPath.empty() && !ctxt.writeOverlay) { - TF_WARN("No usdprototypespath attribute found. Specify where all the packed prototypes are to build a point instancer."); - return; - } - - // Check if we have an attribute for a custom prototypes scope. - string usdPrototypesScope; - GT_DataArrayHandle prototypesScopeAttr; - prototypesScopeAttr = sourcePrim->findAttribute("usdprototypesscope", owner, 0); - if(prototypesScopeAttr != NULL && prototypesScopeAttr->entries() > 0) { - usdPrototypesScope = prototypesScopeAttr->getS(0); - } - - m_prototypesScope = kReferenceProtoPath; - if (!usdPrototypesScope.empty()) { - std::string errMsg; - if (!SdfPath::IsValidPathString(usdPrototypesScope, &errMsg)) { - TF_WARN("Prototype scope '%s' is an invalid Usd scope, " - "using standard prototype scope instead.", - usdPrototypesScope.c_str()); - } else { - m_prototypesScope = SdfPath(usdPrototypesScope); - } - } - - // Get the prim path for the root (point instancer) to use as the parent - // scope for prototypes - SdfPath protoPath = m_usdPointInstancer.GetPath().AppendPath(m_prototypesScope); - - // Collect sops containing prototypes into a list. If usdPrototypesPath - // references a sop, it will be a length of one. If it references a subnet, - // it will contain all the renderable sops within the net. - std::vector protoNodes; - OBJ_Node* objNode; - UT_Matrix4D localToWorldMatrix; - double time = CHgetTimeFromFrame(GusdUSD_Utils::GetNumericTime(ctxt.time)); - OP_Context houdiniContext(time); - if (!usdPrototypesPath.empty()) { - objNode = OPgetDirector()->findOBJNode(usdPrototypesPath.c_str()); - if( objNode ) { - if(objNode->getObjectType()== OBJ_SUBNET) { - for(int child = 0; child < objNode->getNchildren(); child++) { - if(auto childObjNode = CAST_OBJNODE(objNode->getChild(child))){ - if (auto protoNode = childObjNode->getRenderSopPtr()) { - protoNodes.push_back(protoNode); - } - } - } - } else if (auto protoNode = objNode->getRenderSopPtr()) { - protoNodes.push_back(protoNode); - } - } else if (auto protoNode = OPgetDirector()->findSOPNode(usdPrototypesPath.c_str())) { - protoNodes.push_back(protoNode); - objNode = CAST_OBJNODE(protoNode->getCreator()); - } - - if( (protoNodes.empty() || !objNode) && !ctxt.writeOverlay ) { - TF_WARN("No node found at usdPrototypesPath '%s'", usdPrototypesPath.c_str()); - return; - } - - // Get the obj node transform - objNode->getLocalToWorldTransform( houdiniContext, localToWorldMatrix); - } - - // Populate a map from instance path to detail hanlde. Each detail will be - // refined then written as a prototype, and the instance path will be used - // to create a mapping to the usd path for indexing in the point instancer. - std::map, GU_DetailHandle> protoDetailMap; - - // Iterate through sops containing prototypes, and create a detail handle - // for each packed primitive. - for (int i=0; i < protoNodes.size(); i++) { - if(auto protoNode = protoNodes[i]){ - // If the sop is a subnetwork get the renderable node - if (protoNode->isSubNetwork(true)) { - protoNode = CAST_SOPNODE(protoNode->getRenderNodePtr()); - } - GU_DetailHandle cookedGeoHdl = protoNode->getCookedGeoHandle(houdiniContext); - GU_DetailHandleAutoReadLock detailLock( cookedGeoHdl ); - - // usdinstancepath can be any kind of attribute (may use detail if - // one proto) - const GA_AttributeOwner searchOrder[4] = {GA_ATTRIB_VERTEX, - GA_ATTRIB_POINT, - GA_ATTRIB_PRIMITIVE, - GA_ATTRIB_GLOBAL}; - GA_ROHandleS instancePathAttr( detailLock->findAttribute( - "usdinstancepath", - searchOrder, - 4 )); - - // If the usdinstancepath is a valid Sdf path, we use it as the - // names of each prototype. - bool generateProtoNames = false; - // We also support instancepath instead of usdinstancepath - if (!instancePathAttr.isValid()) { - instancePathAttr = GA_ROHandleS( detailLock->findAttribute( - "instancepath", - searchOrder, - 4 )); - // These are generall full paths to nodes and should not be - // used as prototype scopes. - generateProtoNames = true; - } - - // Iteratve over each primitive and create a detail handle - GA_Range primRange = detailLock->getPrimitiveRange(); - for(GA_Iterator offsetIt(primRange); !offsetIt.atEnd(); ++offsetIt) { - // Use the context's usdinstancepath as default if no attributes - std::tuple usdInstancePath(ctxt.usdInstancePath, generateProtoNames); - if (instancePathAttr.isValid()) { -#if SYS_VERSION_FULL_INT < 0x10050000 - string instancePathAttrVal = instancePathAttr.get(offsetIt.getOffset()); -#else - string instancePathAttrVal = instancePathAttr.get(offsetIt.getOffset()).toStdString(); -#endif - if (!instancePathAttrVal.empty()) { - std::get<0>(usdInstancePath) = instancePathAttrVal; - std::string errMsg; - if (!generateProtoNames && - !SdfPath::IsValidPathString(instancePathAttrVal, &errMsg)) { - TF_WARN("Instance name '%s' is an invalid Usd scope, " - "using standard prototype naming instead.", - instancePathAttrVal.c_str()); - std::get<1>(usdInstancePath) = true; - } - } - } - if (!std::get<0>(usdInstancePath).empty()) { - const GU_Detail *srcDetail = detailLock.getGdp(); - GA_PrimitiveGroup primGroup(*srcDetail); - primGroup.addOffset(offsetIt.getOffset()); - // Create a detail based on a prim group for each primitive - GU_Detail *detail = new GU_Detail(srcDetail, &primGroup); - GU_DetailHandle detailHandle; - // Handle owns the detail so it will free the memory - detailHandle.allocateAndSet(detail, true); - if(detailHandle) { - if ( protoDetailMap.count(usdInstancePath) ) { - TF_WARN ("Multiple prototypes found with instance " - "path '%s', may result in loss of prototypes.", - std::get<0>(usdInstancePath).c_str()); - } - protoDetailMap[usdInstancePath] = detailHandle; - } - } else { - TF_WARN("No instance path found for primitive in node %s",protoNode->getName().c_str()); - } - } - } - } - - // Map to store instance path and usd path, for generating mapping for index - // array - std::map protoPathsMap; - - // Index for naming prototypes - int protoIdx = 0; - - for ( const auto &pair : protoDetailMap ) { - GT_RefineParms refineParms; - // Tell the collectors (in particular the f3d stuff) that we are - // writing a USD file rather than doing interactive visualization. - // an interactive visualization - refineParms.set( "refineToUSD", true ); - - GusdContext newContext = GusdContext( ctxt ); - - // We don't want to force overlays of prototypes. If it has the same - // scope in an overlay all it will still overlay, but this way new - // prototypes won't be pure overs. - newContext.writeOverlay = false; - - // If a prototype is selecting a variant, make sure to set it - newContext.authorVariantSelections = true; - - GusdRefinerCollector refinerCollector; - - string protoUsdName; - if ( !std::get<1>(pair.first) ) { - protoUsdName = std::get<0>(pair.first); - } else { - protoUsdName = "prototype_"; - protoUsdName += std::to_string(protoIdx); - protoIdx++; - } - SdfPath protoUsdPath = protoPath.AppendPath(SdfPath(protoUsdName)); - - GusdRefiner refiner( - refinerCollector, - protoUsdPath, - "", - localToWorldMatrix ); - - refiner.m_refinePackedPrims = true; - - // Set the refiner to build prototypes (so we don't recurse and create - // another point instancer) - refiner.m_buildPrototypes = true; - - // Refine the detail handle - refiner.refineDetail( pair.second, refineParms ); - - // Build the instancer prims. - const GusdRefiner::GprimArray& gprimArray = refiner.finish(); - - // Sort the refined prim array by primitive paths. This ensures parents - // will be written before their children. - GusdRefinerCollector::GprimArray gPrims = gprimArray; - std::sort( gPrims.begin(), gPrims.end(), - []( const GusdRefinerCollector::GprimArrayEntry& a, - const GusdRefinerCollector::GprimArrayEntry& b ) -> bool - { return a.path < b.path; } ); - - GusdSimpleXformCache xformCache; - - // Iterate over the prims we need to write - for( auto& gtPrim : gPrims ) { - // Create a new USD prim - const SdfPath& primPath = gtPrim.path; - GT_PrimitiveHandle usdPrim; - usdPrim = GusdPrimWrapper::defineForWrite( - gtPrim.prim, stage, primPath, newContext ); - - if( !usdPrim ) { - TF_WARN( "prim did not convert. %s", gtPrim.prim->className() ); - } - else { - GusdPrimWrapper* primPtr - = UTverify_cast(usdPrim.get()); - primPtr->markVisible( true ); - } - - if(usdPrim) { - GusdPrimWrapper* primPtr - = UTverify_cast(usdPrim.get()); - - newContext.purpose = gtPrim.purpose; - - // Copy attributes from gt prim to USD prim. - primPtr->updateFromGTPrim(gtPrim.prim, - gtPrim.xform, - newContext, - xformCache ); - - // TODO: Grab material bindings for prims brought in with - // subroot references and copy them here so we don't lose - // shading - - // Create an array of prototype transforms for subtracting from - // instance transforms later - m_prototypeTransforms.push_back(gtPrim.xform); - } - } - - // Add the mapping from instance path (pair.first) to usd path - protoPathsMap[std::get<0>(pair.first)] = protoUsdPath; - } - - if(ctxt.writeOverlay && (!ctxt.overlayAll || usdPrototypesPath.empty())) { - - // If we are doing an overlay, build the map from the existing relationships - UsdRelationship prototypesRel = m_usdPointInstancer.GetPrototypesRel(); - SdfPathVector targets; - prototypesRel.GetForwardedTargets(&targets); - for(size_t i=0; i 0) { - // Set the targets as this forces the point instancer to explicitly - // only uses the new prototypes and not the ones from the file - // we are overlaying. - prototypesRel.SetTargets(relationshipPaths); - } - -} - -bool GusdInstancerWrapper:: -updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) -{ - if( !m_usdPointInstancer ) { - TF_WARN( "Can't update USD point instancer from GT prim '%s'", m_usdPointInstancer.GetPrim().GetPath().GetText() ); - return false; - } - - DBG(cerr << "GusdInstanceWrapper::updateFromGTPrim, " << - m_usdPointInstancer.GetPath().GetString() << endl); - - bool writeTransforms = !ctxt.writeOverlay || ctxt.overlayAll || - ctxt.overlayPoints || ctxt.overlayTransforms; - - //-------------------------------------------------------------------------- - - GfMatrix4d xform = computeTransform ( - m_usdPointInstancer.GetPrim().GetParent(), - ctxt.time, - houXform, - xformCache); - - // intrinsic attributes ---------------------------------------------------- - - GT_Owner attrOwner = GT_OWNER_INVALID; - GT_DataArrayHandle houAttr; - UsdAttribute usdAttr; - std::vector maskAtTime; - - // If this is not an overlay, write out the transform. - // (If it is an overlay, the instances themselves will be - // set to correct locations via their position attribute.) - if( !ctxt.writeOverlay ) { - - // transform - updateTransformFromGTPrim( xform, ctxt.time, - ctxt.granularity == GusdContext::PER_FRAME ); - } - - int numPoints = 0; - if( writeTransforms ) { - - UT_Matrix4D localToWorld; - GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - m_usdPointInstancer.GetPrim(), - ctxt.time, - localToWorld ); - UT_Matrix4D worldToLocal = localToWorld; - worldToLocal.invert(); - - // visibility - updateVisibilityFromGTPrim(sourcePrim, ctxt.time, - ctxt.granularity == GusdContext::PER_FRAME ); - - // P - houAttr = sourcePrim->findAttribute("P", attrOwner, 0); - if(houAttr) { - numPoints = houAttr->entries(); - } - - // Mask - // XXX We currently don't support the mask attribute, but it could - // be authored on a prim we're overlaying, in which case we write - // a constant value of true. - maskAtTime = m_usdPointInstancer.ComputeMaskAtTime(ctxt.time); - if( !maskAtTime.empty() ) { - m_usdPointInstancer.ActivateAllIds(); - m_usdPointInstancer.VisAllIds(ctxt.time); - } - - // Indices - usdAttr = m_usdPointInstancer.GetProtoIndicesAttr(); - - bool gotValidIndices = false; - - GT_Int32Array* idxArray = new GT_Int32Array(numPoints, 1); - GT_DataArrayHandle houAttr(idxArray); - - // define & update prototypes ---------------------------------------------- - - // Get the instance paths from attributes on the points. - GT_DataArrayHandle instancePathAttr; - if( auto pntAttrs = sourcePrim->getPointAttributes() ) { - instancePathAttr = pntAttrs->get( "usdinstancepath" ); - if (instancePathAttr == NULL) { - instancePathAttr = pntAttrs->get( "instancepath" ); - } - } - - // The instance paths for the points should match the mapping we created - // when we wrote the prototypes. - if(instancePathAttr != NULL ) { - if(instancePathAttr->entries() >= numPoints) { - for(int i=0; igetS(i); - - auto idxIt = m_relationshipIndexMap.find( TfToken(usdInstancePath) ); - if( idxIt != m_relationshipIndexMap.end()) { - - idxArray->set(idxIt->second, i); - } - else { - TF_WARN("Couldn't resolve prototype index for %s.", - usdInstancePath); - idxArray->set(0, i); - } - } - } - gotValidIndices = true; - } else if (!ctxt.usdInstancePath.empty()){ - // If the instancepath was set as a paramater and no attribute - // overwrote it, check the context for a usd instance path. - for(int i=0; iset(idxIt->second, i); - } - else { - TF_WARN("Couldn't resolve prototype index for %s.", - ctxt.usdInstancePath.c_str()); - idxArray->set(0, i); - } - } - gotValidIndices = true; - } else if (ctxt.writeOverlay && (ctxt.overlayPoints || ctxt.overlayAll)) { - // If we are writing an overlay points or all, but didn't construct - // a new prototypes relationship array, we can still find the - // instances' appropriate proto indices from the original instancer. - // This will be the new indices array, and does not have to be the - // the same length as the original. - - GT_DataArrayHandle indexAttr; - std::vector instanceIndexArray; - - // Get the houdini attribute defining the index of its position - // in the original point instancer. - if ( auto pntAttrs = sourcePrim->getPointAttributes() ) - indexAttr = pntAttrs->get( "__instanceindex" ); - - // Get the original proto indices array. - std::map preOverlayProtoIndices = boost::get>( - m_preOverlayDataMap[UsdGeomTokens->protoIndices]).preOverlayDataMap; - - // If we stored indices in the point instancer we are overlaying, - // get those. otherwise get them from the attribute. - VtIntArray usdProtoIndicies; - if (preOverlayProtoIndices.count(ctxt.time) > 0) { - usdProtoIndicies = preOverlayProtoIndices[ctxt.time]; - } else if (ctxt.granularity==GusdContext::PER_FRAME) { - m_usdPointInstancer.GetProtoIndicesAttr().Get(&usdProtoIndicies, ctxt.time); - } - - if (usdProtoIndicies.size() > 0) { - if (indexAttr) { - int numIndicies = indexAttr->entries(); - - // If we have an index for each instance: - if (numIndicies == numPoints) { - const GT_Size numVals = indexAttr->entries() * indexAttr->getTupleSize(); - instanceIndexArray = std::vector(numVals); - indexAttr->fillArray(instanceIndexArray.data(), 0, indexAttr->entries(), indexAttr->getTupleSize()); - - // For each instance, grab it's prototype index by - // accessing the original proto indices array at the - // index of it's place in the instancer. - for(int i=0; iset(index, i); - } - gotValidIndices = true; - } - } - } - } else if (!ctxt.writeOverlay || ctxt.overlayAll) { - TF_WARN( "Instance prototypes not specified as instance path or packed prim" ); - } - - // Set indicies array - if(gotValidIndices && usdAttr) { - GusdGT_Utils::setUsdAttribute(usdAttr, houAttr, ctxt.time); - } - - // When the instance has a transform, set everything here. - const GT_AttributeListHandle gtPointAttrs = sourcePrim->getPointAttributes(); - if( gtPointAttrs->hasName("__instancetransform") ) { - setTransformAttrsFromMatrices( - worldToLocal, - gtPointAttrs, - ctxt, - sourcePrim); - } - else { - // For nativ houdini instancing with just attributes on a point. - // v - houAttr = sourcePrim->findAttribute("v", attrOwner, 0); - usdAttr = m_usdPointInstancer.GetVelocitiesAttr(); - if(houAttr && usdAttr) { - GusdGT_Utils::setUsdAttribute(usdAttr, houAttr, ctxt.time); - } - - //w - houAttr = sourcePrim->findAttribute("w", attrOwner, 0); - usdAttr = m_usdPointInstancer.GetAngularVelocitiesAttr(); - if(houAttr && usdAttr) { - std::vector wArray; - setAngularVelocity(houAttr, wArray); - houAttr.reset(new GT_Real32Array(wArray.data(), houAttr->entries() , houAttr->getTupleSize())); - GusdGT_Utils::setUsdAttribute(usdAttr, houAttr, ctxt.time); - } - UsdAttribute usdPositionAttr = m_usdPointInstancer.GetPositionsAttr(); - UsdAttribute usdRotationAttr = m_usdPointInstancer.GetOrientationsAttr(); - UsdAttribute usdScalesAttr = m_usdPointInstancer.GetScalesAttr(); - - if (usdRotationAttr - && usdScalesAttr - && gtPointAttrs) { - - setTransformAttrsFromComponents( - usdPositionAttr, - usdRotationAttr, - usdScalesAttr, - gtPointAttrs, - ctxt.time); - } - } - - // extent ------------------------------------------------------------------ - - VtVec3fArray extent(2); - // Using utility function from UsdGeomPointInstancer - if(m_usdPointInstancer.ComputeExtentAtTime(&extent, ctxt.time, ctxt.time)) { - m_usdPointInstancer.GetExtentAttr().Set(extent, ctxt.time); - } - } - - // primvars ---------------------------------------------------------------- - - if( !ctxt.writeOverlay || ctxt.overlayAll || ctxt.overlayPrimvars ) { - - GusdGT_AttrFilter filter = ctxt.attributeFilter; - // Filter attributes which were used to construct the instance transform - // and prototype relationships. - filter.appendPattern(GT_OWNER_POINT, - "^__* ^orient ^rot ^scale ^instancepath ^usdinstancepath \ - ^usdprototypespath ^usdprototypesscope ^trans ^up"); - filter.appendPattern(GT_OWNER_POINT, "^P ^N ^v"); - filter.appendPattern(GT_OWNER_CONSTANT, "^usdprimpath ^instancepath \ - ^usdinstancepath ^usdprototypespath ^usdprototypesscope"); - if(const GT_AttributeListHandle pointAttrs = sourcePrim->getPointAttributes()) { - - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_POINT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( pointAttrs, filter, UsdGeomTokens->uniform, ctxt.time ); - } - if(const GT_AttributeListHandle constAttrs = sourcePrim->getDetailAttributes()) { - - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_CONSTANT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( constAttrs, filter, UsdGeomTokens->constant, ctxt.time ); - } - } - // ------------------------------------------------------------------------- - - return GusdPrimWrapper::updateFromGTPrim(sourcePrim, houXform, ctxt, xformCache); -} -void GusdInstancerWrapper::setTransformAttrsFromMatrices(const UT_Matrix4D &worldToLocal, - const GT_AttributeListHandle gtAttrs, - GusdContext ctxt, - GT_PrimitiveHandle sourcePrim) -{ - // Create a map from TfToken to UsdAttribute for each one we want to set. - std::map usdAttrMap; - for (const auto& token : m_usdGeomTokens) { - if (token != UsdGeomTokens->protoIndices) { - usdAttrMap[token] = - m_usdPointInstancer.GetPrim().GetAttribute(token); - if(!usdAttrMap[token].IsValid()) { - TF_WARN( "Missing '%s' attribute from point instancer. " - "Failed to update attributes.", token.GetText() ); - return; - } - } - } - - if (!gtAttrs) - return; - - UsdTimeCode time = ctxt.time; - - GT_DataArrayHandle houXformAttr = gtAttrs->get("__instancetransform", 0); - if(!houXformAttr || !(houXformAttr->getTupleSize() ==16)) - return; - - GT_DataArrayHandle houXformBuffer; - const fpreal64* houXformArray = houXformAttr->getF64Array(houXformBuffer); - - if(!houXformArray) - return; - - GT_Size numXforms = houXformAttr->entries(); - - int numPoints = 0; - - // If writing an overlay, get the indices of each instance into the original - // point instancer, and see if we are writing a partial overlay of some sort. - GT_DataArrayHandle indexAttr; - - // Map from index into point instancer to point number in houdini. - std::map instanceIndexMap; - - indexAttr = gtAttrs->get( "__instanceindex" ); - if (ctxt.writeOverlay && ctxt.overlayTransforms && - !(ctxt.overlayAll || ctxt.overlayPoints) && indexAttr) { - const GT_Size numVals = indexAttr->entries() * indexAttr->getTupleSize(); - std::vector instanceIndexArray = std::vector(numVals); - indexAttr->fillArray(instanceIndexArray.data(), 0, indexAttr->entries(), indexAttr->getTupleSize()); - for (int i =0; i < instanceIndexArray.size(); i++) { - instanceIndexMap[instanceIndexArray[i]] = i; - } - - // Get the number of points in the original point instancer. - std::map preOverlayProtoIndices = boost::get>( - m_preOverlayDataMap[UsdGeomTokens->protoIndices]).preOverlayDataMap; - if ( preOverlayProtoIndices.count(time) > 0 ) { - numPoints = preOverlayProtoIndices[time].size(); - } else { - VtIntArray indices; - m_usdPointInstancer.GetProtoIndicesAttr().Get( &indices, time); - numPoints = indices.size(); - } - } else { - // Just write out a point instancer with the data provided by houdini. - numPoints = numXforms; - } - - // Create a handle for data from houdini - std::map houHandlesMap; - GT_Real32Array* houPositions = new GT_Real32Array(numPoints, 3); - houHandlesMap[UsdGeomTokens->positions] = GT_DataArrayHandle(houPositions); - - GT_Real32Array* houRotations = new GT_Real32Array(numPoints, 4); - houHandlesMap[UsdGeomTokens->orientations] = GT_DataArrayHandle(houRotations); - - GT_Real32Array* houScales = new GT_Real32Array(numPoints, 3); - houHandlesMap[UsdGeomTokens->scales] = GT_DataArrayHandle(houScales); - - GT_Owner attrOwner = GT_OWNER_INVALID; - GT_DataArrayHandle houVAttr = sourcePrim->findAttribute("v", attrOwner, 0); - const float *houVArray=NULL; - GT_Real32Array* houVelocities=NULL; - if(houVAttr && houVAttr->getTupleSize() == 3) { - if (numPoints == numXforms) { - // We can set it directly with no further calculations - houHandlesMap[UsdGeomTokens->velocities] = houVAttr; - } else { - // We have to construct the array point by point, in order to get - // some data from the original point instancer. - GT_DataArrayHandle houVBuffer; - houVArray = houVAttr->getF32Array(houVBuffer); - houVelocities = new GT_Real32Array(numPoints, 3); - houHandlesMap[UsdGeomTokens->velocities] = GT_DataArrayHandle(houVelocities); - } - } - - GT_DataArrayHandle houWAttr = sourcePrim->findAttribute("w", attrOwner, 0); - GT_Real32Array* houAngularVelocities = NULL; - std::vector houWArray; - if (houWAttr && houWAttr->getTupleSize() == 3) { - setAngularVelocity(houWAttr, houWArray); - if (numPoints == numXforms) { - // We can set it directly with no further calculations - houWAttr.reset(new GT_Real32Array(houWArray.data(), houWAttr->entries() , houWAttr->getTupleSize())); - houHandlesMap[UsdGeomTokens->angularVelocities] = houWAttr; - } else { - // We have to construct the array point by point, in order to get - // some data from the original point instancer. - houAngularVelocities = new GT_Real32Array(numPoints, 3); - houHandlesMap[UsdGeomTokens->angularVelocities] = GT_DataArrayHandle(houAngularVelocities); - } - } - - - - // If we have transforms on prototypes, we have to remove them from our - // final instance transformation, as the point instancer schema accounts - // for prototype transforms. Will only be the case when writing out new - // prototypes (new geom or overlay all). - VtIntArray indices; - m_usdPointInstancer.GetProtoIndicesAttr().Get( &indices, time); - bool removeProtoTransforms = (indices.size() == numXforms) && - (m_prototypeTransforms.size() > 0); - - for(int pt=0; pt= numXforms * 3) { - angularVelocity = UT_Vector3(houWArray[i*3], - houWArray[i*3+1], - houWArray[i*3+2]); - } - } - } else { - // This point was in the original point instancer but not being - // overlaid, so get original values. Only in an overlay transform. - - TfToken token = UsdGeomTokens->positions; - GfVec3f ptPosition; - if (boost::get>( - m_preOverlayDataMap[token]).getPointValue(time, pt, ptPosition)) - position = GusdUT_Gf::Cast(ptPosition); - - token = UsdGeomTokens->scales; - GfVec3f ptScale; - if (boost::get>( - m_preOverlayDataMap[token]).getPointValue(time, pt, ptScale)) - scale = GusdUT_Gf::Cast(ptScale); - - token = UsdGeomTokens->orientations; - GfQuath ptOrientation; - if (boost::get>( - m_preOverlayDataMap[token]).getPointValue(time, pt, ptOrientation)) - GusdUT_Gf::Convert((GfQuatf)ptOrientation, q); - - token = UsdGeomTokens->velocities; - GfVec3f ptVelocity; - if (boost::get>( - m_preOverlayDataMap[token]).getPointValue(time, pt, ptVelocity)) - velocity = GusdUT_Gf::Cast(ptVelocity); - - token = UsdGeomTokens->angularVelocities; - GfVec3f ptAngularVelocity; - if (boost::get>( - m_preOverlayDataMap[token]).getPointValue(time, pt, ptAngularVelocity)) - angularVelocity = GusdUT_Gf::Cast(ptAngularVelocity); - - } - houPositions->setTuple( position.data(), pt ); - - houScales->setTuple(scale.data(), pt); - // Houdini quaternions are i,j,k,w - houRotations->setTuple( - UT_Vector4(q.x(), q.y(), q.z(), q.w()).data(), pt); - - // We only reconstruct the data if we are doing a partial overlay. - if (numPoints != numXforms ) { - if (houVelocities != NULL) - houVelocities->setTuple(velocity.data(), pt); - if (houAngularVelocities != NULL) - houAngularVelocities->setTuple(angularVelocity.data(), pt); - } - } - - // Set all the attributes' data. - for (const auto& pair : houHandlesMap) - GusdGT_Utils::setUsdAttribute(usdAttrMap[pair.first], pair.second, time); -} - -bool GusdInstancerWrapper:: -refine( GT_Refine& refiner, - const GT_RefineParms* parms ) const -{ - - UsdStagePtr stage = m_usdPointInstancer.GetPrim().GetStage(); - - DBG(cerr << "GusdInstancerWrapper::refine, " << m_usdPointInstancer.GetPrim().GetPath() << endl); - - UsdRelationship relationship = m_usdPointInstancer.GetPrototypesRel(); - SdfPathVector targets; - relationship.GetForwardedTargets( &targets ); - - // Build prototype prims on demand - vector protoPrims( targets.size() ); - - VtArray indices; - if( !m_usdPointInstancer.GetProtoIndicesAttr().Get( &indices, m_time ) ) - { - TF_WARN("error getting indices attribute"); - return false; - } - - VtArray frames; - if( !m_usdPointInstancer.ComputeInstanceTransformsAtTime( &frames, - m_time, - m_time, - UsdGeomPointInstancer::ProtoXformInclusion::IncludeProtoXform, - UsdGeomPointInstancer::MaskApplication::IgnoreMask ) ) - { - TF_WARN("ComputeFrames failed"); - return false; - } - - if( indices.size() != frames.size() ) - { - TF_WARN("Indices and frames arrays are not the same size"); - return false; - } - - for( size_t targetIndex = 0; targetIndex < targets.size(); ++targetIndex ) { - - UsdPrim p = stage->GetPrimAtPath( targets[targetIndex] ); - - if( !p ) { - TF_WARN( "getting proto prim failed '%s'", targets[targetIndex].GetText() ); - continue; - } - - GT_PrimitiveHandle gtPrim = GusdGT_PrimCache::GetInstance().GetPrim( - p, m_time, m_purposes ); - - - auto transforms = new GT_TransformArray(); - for( size_t i = 0; i < indices.size(); ++i ) { - - int idx = indices[i]; - if( idx != targetIndex ) - continue; - - if( idx < 0 || idx >= targets.size() ) - { - TF_WARN("Invalid prototype index: %d", idx);; - continue; - } - - const UT_Matrix4D& m = GusdUT_Gf::Cast( frames[i] ); - transforms->append( new GT_Transform( &m, 1 ) ); - } - if( transforms->entries() > 0 ) { - - refiner.addPrimitive( new GT_PrimInstance( gtPrim, transforms )); - } - } - return true; -} - -bool -GusdInstancerWrapper::unpack( - GU_Detail& gdr, - const UT_StringRef& fileName, - const SdfPath& primPath, - const UT_Matrix4D& xform, - fpreal frame, - const char* viewportLod, - GusdPurposeSet purposes ) -{ - - UsdPrim usdPrim = m_usdPointInstancer.GetPrim(); - - UsdRelationship relationship = m_usdPointInstancer.GetPrototypesRel(); - SdfPathVector targets; - relationship.GetForwardedTargets( &targets ); - - VtArray indices; - if( !m_usdPointInstancer.GetProtoIndicesAttr().Get( &indices, UsdTimeCode( frame ))) - { - TF_WARN( "error getting indicies" ); - return false; - } - - UT_Matrix4D instancerXform; - GusdUSD_XformCache::GetInstance(). - GetLocalToWorldTransform( usdPrim, - UsdTimeCode( frame ), - instancerXform ); - - VtArray frames; - if( !m_usdPointInstancer.ComputeInstanceTransformsAtTime( &frames, - UsdTimeCode(frame), - UsdTimeCode(frame), - UsdGeomPointInstancer::ProtoXformInclusion::IncludeProtoXform, - UsdGeomPointInstancer::MaskApplication::IgnoreMask ) ) - { - TF_WARN( "ComputeFrames failed" ); - return false; - } - - if( indices.size() != frames.size() ) - { - TF_WARN( "Indices and frames arrays are not the same size" ); - return false; - } - - // If the primPath of the instancer contains a variant selection, - // copy the variant selection to the prototype paths. - if( primPath.ContainsPrimVariantSelection() ) { - - SdfPath strippedPathHead(primPath.StripAllVariantSelections()); - for( size_t i = 0; i < targets.size(); ++ i ) { - targets[i] = targets[i].ReplacePrefix( strippedPathHead, primPath ); - } - } - - - GA_Offset start = GA_INVALID_OFFSET; - - for( size_t i = 0; i < indices.size(); ++i ) - { - const int idx = indices[i]; - if( idx < 0 || idx >= targets.size() ) - { - TF_WARN( "Invalid prototype index: %d", idx ); - continue; - } - - GU_PrimPacked *guPrim = - GusdGU_PackedUSD::Build( gdr, fileName, - targets[idx], - primPath, - i, - frame, - viewportLod, - purposes ); - - UT_Matrix4D m = GusdUT_Gf::Cast( frames[i] ) * xform; - UT_Vector3D p; - m.getTranslates( p ); - - guPrim->setLocalTransform( UT_Matrix3D( m ) ); - guPrim->setPos3(0,p); - - if( i == 0 ) { - start = guPrim->getPointOffset( 0 ); - } - } - - - // unpack any per-instance primvars to point attributes - - vector authoredPrimvars = m_usdPointInstancer.GetAuthoredPrimvars(); - for( const UsdGeomPrimvar &primvar : authoredPrimvars ) { - - if( primvar.GetInterpolation() == UsdGeomTokens->constant || - primvar.GetInterpolation() == UsdGeomTokens->uniform ) { - - // TODO: Constant and uniform primvars need to be replicated for each - // instance - TF_WARN( "%s:%s has %s interpolation. These are not supported yet.", - m_usdPointInstancer.GetPrim().GetPath().GetText(), - primvar.GetPrimvarName().GetText(), - primvar.GetInterpolation().GetText() ); - } - else { - - GT_DataArrayHandle pvData = GusdPrimWrapper::convertPrimvarData( primvar, UsdTimeCode( frame ) ); - GT_Storage storage = pvData->getStorage(); - - if( pvData->entries() < indices.size() ) { - TF_WARN( "Invalid primvar found: '%s:%s'. It has %zd values. It should have at least %zd.", - m_usdPointInstancer.GetPrim().GetPath().GetText(), - primvar.GetPrimvarName().GetText(), - pvData->entries(), indices.size() ); - continue; - } - - if(GTisFloat(storage)) { - - GA_RWAttributeRef attr = - gdr.addFloatTuple( GA_ATTRIB_POINT, - GusdUSD_Utils::TokenToStringHolder( - primvar.GetBaseName()), - pvData->getTupleSize(), - GA_Defaults(0.0), - /* creation_args */0, - /* attribute_options */0, - GT_Util::getGAStorage(storage) ); - - if( attr.isValid() ) { - attr->setTypeInfo( GT_Util::getGAType( pvData->getTypeInfo() )); - - // AIFTuples don't support half floats. Promote them to 32 bits. - GT_DataArrayHandle tmp; - if( storage == GT_STORE_REAL16 || - storage == GT_STORE_REAL32 ) { - attr->getAIFTuple()->setRange( - attr.getAttribute(), - GA_Range( attr->getIndexMap(), - start, start + pvData->entries() ), - pvData->getF32Array( tmp ) ); - } - if( storage == GT_STORE_REAL64 ) { - attr->getAIFTuple()->setRange( - attr.getAttribute(), - GA_Range( attr->getIndexMap(), - start, start + pvData->entries() ), - pvData->getF64Array( tmp ) ); - } - } - } - else if(GTisInteger(storage)) { - - GA_RWAttributeRef attr = - gdr.addIntTuple( GA_ATTRIB_POINT, - GusdUSD_Utils::TokenToStringHolder( - primvar.GetBaseName()), - pvData->getTupleSize(), - GA_Defaults(0.0), - /* creation_args */0, - /* attribute_options */0, - GT_Util::getGAStorage(storage) ); - - if( attr.isValid() ) { - attr->setTypeInfo( GT_Util::getGAType( pvData->getTypeInfo() )); - - // AIFTuples don't support 8 bit ints. promote to 32 bits. - GT_DataArrayHandle tmp; - if( storage == GT_STORE_UINT8 || - storage == GT_STORE_INT32 ) { - attr->getAIFTuple()->setRange( - attr.getAttribute(), - GA_Range( attr->getIndexMap(), - start, start + pvData->entries() ), - pvData->getI32Array( tmp ) ); - } - else { - attr->getAIFTuple()->setRange( - attr.getAttribute(), - GA_Range( attr->getIndexMap(), - start, start + pvData->entries() ), - pvData->getI64Array( tmp ) ); - } - } - } - else { - - // TODO: String primvars need to be implements. - - TF_WARN( "Found primvar with unsupported data type. %s:%s type = %s", - m_usdPointInstancer.GetPrim().GetPath().GetText(), - primvar.GetPrimvarName().GetText(), - primvar.GetTypeName().GetAsToken().GetText()); - } - } - } - return true; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/instancerWrapper.h b/third_party/houdini/gusd/instancerWrapper.h deleted file mode 100644 index 39841a8d3b..0000000000 --- a/third_party/houdini/gusd/instancerWrapper.h +++ /dev/null @@ -1,235 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_INSTANCER_WRAPPER_H -#define GUSD_INSTANCER_WRAPPER_H - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/pointInstancer.h" - -#include "primWrapper.h" - -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -class GusdInstancerWrapper : public GusdPrimWrapper -{ - typedef UT_Map RelationshipIndexMap; - -public: - - GusdInstancerWrapper( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext &ctxt, - bool isOverride = false ); - GusdInstancerWrapper( const UsdGeomPointInstancer& usdInstancer, - UsdTimeCode t, - GusdPurposeSet purposes ); - virtual ~GusdInstancerWrapper(); - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdPointInstancer; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) override; - - virtual bool isValid() const override; - - virtual bool refine( GT_Refine& refiner, - const GT_RefineParms* parms = NULL ) const override; - - virtual bool unpack( - GU_Detail& gdr, - const UT_StringRef& fileName, - const SdfPath& primPath, - const UT_Matrix4D& xform, - fpreal frame, - const char * viewportLod, - GusdPurposeSet purposes ) override; - -public: - - static GT_PrimitiveHandle - defineForWrite( const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - bool initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - void writePrototypes( const GusdContext& ctxt, - const UsdStagePtr& stage, - const GT_PrimitiveHandle& sourcePrim); - - void storePreOverlayData(bool justProtoIndices, const UsdTimeCode* time); - - void clearPreOverlayData(); - - void setTransformAttrsFromMatrices(const UT_Matrix4D &worldToLocal, - const GT_AttributeListHandle gtAttrs, - GusdContext ctxt, - GT_PrimitiveHandle sourcePrim); - -private: - UsdGeomPointInstancer m_usdPointInstancer; - - // A map of tokens to indexes in the point instancer's relationship array. - // The tokens could be unique ids built from USD packed prims or - // paths to SOP nodes (as in instancepath attributes). - RelationshipIndexMap m_relationshipIndexMap; - - // List of prototype transforms for "subtracting" from final instance - // transforms. - std::vector m_prototypeTransforms; - - // Scope to write prototypes to (usually ../Prototypes/..). - SdfPath m_prototypesScope; - - // List of attributes to write for point instancer. - std::vector m_usdGeomTokens = {UsdGeomTokens->protoIndices, - UsdGeomTokens->positions, - UsdGeomTokens->orientations, - UsdGeomTokens->scales, - UsdGeomTokens->velocities, - UsdGeomTokens->angularVelocities}; - - // Struct for helping store original data from a point instancer we are - // overlaying, so we can partially overlay a subset of points while - // writing out the original data for the others in an overlay transform. - template - struct PreOverlayDataEntry { - std::map> preOverlayDataMap; - UsdAttribute usdAttr; - - PreOverlayDataEntry(UsdAttribute usdAttr) : usdAttr(usdAttr) {} - - PreOverlayDataEntry() {} - ~PreOverlayDataEntry() {} - PreOverlayDataEntry(PreOverlayDataEntry &&other) { - preOverlayDataMap = std::move(other.preOverlayDataMap); - usdAttr = other.usdAttr; - } - PreOverlayDataEntry& operator=(PreOverlayDataEntry &&other) { - preOverlayDataMap = std::move(other.preOverlayDataMap); - usdAttr = other.usdAttr; - return *this; - } - PreOverlayDataEntry(PreOverlayDataEntry const& other){ - preOverlayDataMap = other.preOverlayDataMap; - usdAttr = other.usdAttr; - } - - // Store this attribute's data at the given time. - void storeAtTime(UsdTimeCode time) { - VtArray dataArray; - if (usdAttr.Get(&dataArray, time)){ - preOverlayDataMap[time] = dataArray; - } - } - - // Get the stored data for this attribute at the given point and time. - bool getPointValue(UsdTimeCode time, int ptNum, T& value) { - VtArray dataArray; - if (preOverlayDataMap.count(time) > 0) { - dataArray = preOverlayDataMap[time]; - if (dataArray.size() > ptNum) { - value = dataArray[ptNum]; - return true; - } - } else { - usdAttr.Get(&dataArray, time); - if (dataArray.size() > ptNum) { - value = dataArray[ptNum]; - return true; - } - } - return false; - } - }; - - - // Boost variant for the different types of data stored by attributes. - typedef boost::variant, - PreOverlayDataEntry, - PreOverlayDataEntry> dataEntry; - - // Map from attribute token to original data from base point instancer. - std::map m_preOverlayDataMap; - - // Visitor for the boost variant to call the store at time function. - struct StoreAtTime : public boost::static_visitor<> - { - StoreAtTime(UsdTimeCode time) : time(time){} - - UsdTimeCode time; - - template - void operator()(T& t) const { - t.storeAtTime(time); - } - }; - - // Visitor to clear stored data in a data entry. - struct ClearData : public boost::static_visitor<> - { - template - void operator()(T t) const { - t.preOverlayDataMap.clear(); - } - }; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_INSTANCER_WRAPPER_H - diff --git a/third_party/houdini/gusd/meshWrapper.cpp b/third_party/houdini/gusd/meshWrapper.cpp deleted file mode 100644 index dd04276064..0000000000 --- a/third_party/houdini/gusd/meshWrapper.cpp +++ /dev/null @@ -1,1263 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "meshWrapper.h" - -#include "context.h" -#include "GT_VtArray.h" -#include "tokens.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if SYS_VERSION_FULL_INT < 0x11050000 // Houdini 17.5 -#include -#endif -#include - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; -using std::string; -using std::map; - -#if SYS_VERSION_FULL_INT >= 0x10050000 -using osd = GT_UtilOpenSubdiv::SdcOptions; -#endif - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -namespace { - -void _reverseWindingOrder(GT_Int32Array* indices, - GT_DataArrayHandle faceCounts) -{ - GT_DataArrayHandle buffer; - int* indicesData = indices->data(); - const int32 *faceCountsData = faceCounts->getI32Array( buffer ); - size_t base = 0; - for( size_t f = 0; f < faceCounts->entries(); ++f ) { - int32 numVerts = faceCountsData[f]; - for( size_t p = 1, e = (numVerts + 1) / 2; p < e; ++p ) { - std::swap( indicesData[base+p], indicesData[base+numVerts-p] ); - } - base+= numVerts; - } -} - -void _validateAttrData( - const char* destName, // The Houdni name of the attribute - const char* srcName, // The USD name of the attribute - const char* primName, - GT_DataArrayHandle data, - const TfToken& interpolation, - int numFaces, - int numPoints, - int numVerticies, - GT_AttributeListHandle* vertexAttrs, - GT_AttributeListHandle* pointAttrs, - GT_AttributeListHandle* uniformAttrs, - GT_AttributeListHandle* detailAttrs ); - -} // anon namespace - -GusdMeshWrapper::GusdMeshWrapper( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - bool isOverride ) - : m_forceCreateNewGeo( false ) -{ - initUsdPrim( stage, path, isOverride ); - initialize( ctxt, sourcePrim ); -} - -GusdMeshWrapper::GusdMeshWrapper( - const UsdGeomMesh& mesh, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdPrimWrapper( time, purposes ) - , m_usdMesh( mesh ) - , m_forceCreateNewGeo( false ) -{ -} - -GusdMeshWrapper::GusdMeshWrapper( const GusdMeshWrapper &in ) - : GusdPrimWrapper( in ) - , m_usdMesh( in.m_usdMesh ) - , m_forceCreateNewGeo( false ) -{ -} - -GusdMeshWrapper:: -~GusdMeshWrapper() -{ -} - -bool GusdMeshWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - bool newPrim = true; - m_forceCreateNewGeo = false; - if( asOverride ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing ) { - newPrim = false; - m_usdMesh = UsdGeomMesh(stage->OverridePrim( path )); - } - else { - // When fracturing, we want to override the outside surfaces and create - // new inside surfaces in one export. So if we don't find an existing prim - // with the given path, create a new one. - m_usdMesh = UsdGeomMesh::Define( stage, path ); - m_forceCreateNewGeo = true; - } - } - else { - m_usdMesh = UsdGeomMesh::Define( stage, path ); - } - if( !m_usdMesh || !m_usdMesh.GetPrim().IsValid() ) { - TF_WARN( "Unable to create %s mesh '%s'.", newPrim ? "new" : "override", path.GetText() ); - } - return bool( m_usdMesh ); -} - -GT_PrimitiveHandle GusdMeshWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt ) -{ - return new GusdMeshWrapper( - sourcePrim, - stage, - path, - ctxt, - ctxt.writeOverlay); -} - -GT_PrimitiveHandle GusdMeshWrapper:: -defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdMeshWrapper( - UsdGeomMesh( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdMeshWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay ); - clearCaches(); - - initialize( ctxt, sourcePrim ); - - return true; -} - -void GusdMeshWrapper:: -initialize( const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - // Set defaults from source prim if one was passed in - if((m_forceCreateNewGeo || !ctxt.writeOverlay || ctxt.overlayAll) && - isValid() && sourcePrim) { - - UsdAttribute usdAttr; - - // Orientation - usdAttr = m_usdMesh.GetOrientationAttr(); - if( usdAttr ) { - - // Houdini uses left handed winding order for mesh vertices. - // USD can handle either right or left. If we are overlaying - // geo, we have to reverse the vertex order to match the original, - // otherwise just write the left handled verts directly. - TfToken orientation; - usdAttr.Get(&orientation, UsdTimeCode::Default()); - if( orientation == UsdGeomTokens->rightHanded ) { - usdAttr.Set(UsdGeomTokens->leftHanded, UsdTimeCode::Default()); - } - } - - // SubdivisionScheme - TfToken subdScheme = UsdGeomTokens->none; - if(const GT_PrimSubdivisionMesh* mesh - = dynamic_cast(sourcePrim.get())) { - if(GT_CATMULL_CLARK == mesh->scheme()) - subdScheme = UsdGeomTokens->catmullClark; - else if(GT_LOOP == mesh->scheme()) - subdScheme = UsdGeomTokens->loop; - } - setSubdivisionScheme(subdScheme); - } -} - -bool -GusdMeshWrapper::refine( - GT_Refine& refiner, - const GT_RefineParms* parms) const -{ - if(!isValid()) { - TF_WARN( "Invalid prim" ); - return false; - } - - bool refineForViewport = GT_GEOPrimPacked::useViewportLOD(parms); - - DBG(cerr << "GusdMeshWrapper::refine, " << m_usdMesh.GetPrim().GetPath() << endl); - VtFloatArray vtFloatArray; - VtIntArray vtIntArray; - VtVec3fArray vtVec3Array; - - // Houdini only supports left handed geometry. Right handed polys need to - // be reversed on import. - TfToken orientation; - bool reverseWindingOrder = - m_usdMesh.GetOrientationAttr().Get(&orientation, m_time) - && orientation == UsdGeomTokens->rightHanded; - - // vertex counts - UsdAttribute countsAttr = m_usdMesh.GetFaceVertexCountsAttr(); - if(!countsAttr) { - TF_WARN( "Invalid vertex count attribute" ); - return false; - } - - VtIntArray usdCounts; - countsAttr.Get(&usdCounts, m_time); - if( usdCounts.size() < 1 ) { - return false; - } - GT_DataArrayHandle gtVertexCounts = new GusdGT_VtArray( usdCounts ); - int numVerticiesExpected = std::accumulate( usdCounts.begin(), usdCounts.end(), 0 ); - - // vertex indices - UsdAttribute faceIndexAttr = m_usdMesh.GetFaceVertexIndicesAttr(); - if(!faceIndexAttr) { - TF_WARN( "Invalid face vertex indicies attribute for %s.", - m_usdMesh.GetPrim().GetPath().GetText()); - return false; - } - VtIntArray usdFaceIndex; - faceIndexAttr.Get(&usdFaceIndex, m_time); - if( usdFaceIndex.size() < numVerticiesExpected ) { - TF_WARN( "Invalid topology found for %s. " - "Expected at least %d verticies and only got %zd.", - m_usdMesh.GetPrim().GetPath().GetText(), numVerticiesExpected, usdFaceIndex.size() ); - return false; - } - - GT_DataArrayHandle gtIndicesHandle; - if( reverseWindingOrder ) { - // Make a copy and reorder - gtIndicesHandle = new GT_Int32Array(usdFaceIndex.cdata(), - usdFaceIndex.size(), 1); - _reverseWindingOrder(UTverify_cast(gtIndicesHandle.get()), - gtVertexCounts); - } - else { - gtIndicesHandle = new GusdGT_VtArray( usdFaceIndex ); - } - - // point positions - UsdAttribute pointsAttr = m_usdMesh.GetPointsAttr(); - if(!pointsAttr) { - TF_WARN( "Invalid point attribute" ); - return false; - } - VtVec3fArray usdPoints; - pointsAttr.Get(&usdPoints, m_time); - int maxPointIndex = *std::max_element( usdFaceIndex.begin(), usdFaceIndex.end() ) + 1; - if( usdPoints.size() < maxPointIndex ) { - TF_WARN( "Invalid topology found for %s. " - "Expected at least %d points and only got %zd.", - m_usdMesh.GetPrim().GetPath().GetText(), maxPointIndex, usdPoints.size() ); - return false; - } - - auto gtPoints = new GusdGT_VtArray(usdPoints,GT_TYPE_POINT); - - GT_AttributeListHandle gtPointAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtVertexAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtUniformAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtDetailAttrs = new GT_AttributeList( new GT_AttributeMap() ); - - gtPointAttrs = gtPointAttrs->addAttribute("P", gtPoints, true); - - UsdAttribute normalsAttr = m_usdMesh.GetNormalsAttr(); - if( normalsAttr.Get(&vtVec3Array, m_time) ) { - - GT_DataArrayHandle gtNormals = - new GusdGT_VtArray(vtVec3Array, GT_TYPE_NORMAL); - TfToken interp = m_usdMesh.GetNormalsInterpolation(); - - if( gtNormals ) { - _validateAttrData( - "N", - normalsAttr.GetBaseName().GetText(), - m_usdMesh.GetPrim().GetPath().GetText(), - gtNormals, - interp, - usdCounts.size(), - usdPoints.size(), - usdFaceIndex.size(), - >VertexAttrs, - >PointAttrs, - >UniformAttrs, - >DetailAttrs ); - } - } - - if( !refineForViewport ) { - - // point velocities - UsdAttribute velAttr = m_usdMesh.GetVelocitiesAttr(); - if ( velAttr.Get(&vtVec3Array, m_time) ) { - - GT_DataArrayHandle gtVel = - new GusdGT_VtArray(vtVec3Array, GT_TYPE_VECTOR); - if( gtVel ) { - _validateAttrData( - "v", - velAttr.GetBaseName().GetText(), - m_usdMesh.GetPrim().GetPath().GetText(), - gtVel, - UsdGeomTokens->varying, // Point attribute - usdCounts.size(), - usdPoints.size(), - usdFaceIndex.size(), - >VertexAttrs, - >PointAttrs, - >UniformAttrs, - >DetailAttrs ); - } - } - - loadPrimvars( m_time, parms, - usdCounts.size(), - usdPoints.size(), - usdFaceIndex.size(), - m_usdMesh.GetPath().GetString(), - >VertexAttrs, - >PointAttrs, - >UniformAttrs, - >DetailAttrs ); - } - - else { - - // When refining for the viewport, the only attributes we care about is color - // and opacity. Prefer Cd / Alpha, but fallback to displayColor and displayOpacity. - // In order to be able to coalesce meshes in the GT_PrimCache, we need to use - // the same attribute owner for the attribute in all meshes. So promote - // to vertex. - - UsdGeomPrimvar colorPrimvar = m_usdMesh.GetPrimvar(GusdTokens->Cd); - if( !colorPrimvar || !colorPrimvar.GetAttr().HasAuthoredValue() ) { - colorPrimvar = m_usdMesh.GetPrimvar(GusdTokens->displayColor); - } - - if( colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValue()) { - - GT_DataArrayHandle gtData = convertPrimvarData( colorPrimvar, m_time ); - if( gtData ) { - - _validateAttrData( - "Cd", - colorPrimvar.GetBaseName().GetText(), - m_usdMesh.GetPrim().GetPath().GetText(), - gtData, - colorPrimvar.GetInterpolation(), - usdCounts.size(), - usdPoints.size(), - usdFaceIndex.size(), - >VertexAttrs, - >PointAttrs, - >UniformAttrs, - >DetailAttrs ); - } - } - UsdGeomPrimvar alphaPrimvar = m_usdMesh.GetPrimvar(GusdTokens->Alpha); - if( !alphaPrimvar || !alphaPrimvar.GetAttr().HasAuthoredValue() ) { - alphaPrimvar = m_usdMesh.GetPrimvar(GusdTokens->displayOpacity); - } - - if( alphaPrimvar && alphaPrimvar.GetAttr().HasAuthoredValue()) { - - GT_DataArrayHandle gtData = convertPrimvarData( alphaPrimvar, m_time ); - if( gtData ) { - - _validateAttrData( - "Alpha", - alphaPrimvar.GetBaseName().GetText(), - m_usdMesh.GetPrim().GetPath().GetText(), - gtData, - alphaPrimvar.GetInterpolation(), - usdCounts.size(), - usdPoints.size(), - usdFaceIndex.size(), - >VertexAttrs, - >PointAttrs, - >UniformAttrs, - >DetailAttrs ); - } - } - } - - if( gtVertexAttrs->entries() > 0 ) { - if( reverseWindingOrder ) { - // Construct an index array which will be used to lookup vertex - // attributes in the correct order. - GT_Int32Array* vertexIndirect - = new GT_Int32Array(gtIndicesHandle->entries(), 1); - GT_DataArrayHandle vertexIndirectHandle(vertexIndirect); - for(int i=0; ientries(); ++i) { - vertexIndirect->set(i, i); - } - _reverseWindingOrder(vertexIndirect, gtVertexCounts ); - - gtVertexAttrs = gtVertexAttrs->createIndirect(vertexIndirect); - } - } - - // build GT_Primitive - TfToken subdScheme; - m_usdMesh.GetSubdivisionSchemeAttr().Get(&subdScheme, m_time); - bool isSubdMesh = (UsdGeomTokens->none != subdScheme); - - GT_PrimitiveHandle meshPrim; - if(isSubdMesh) { - meshPrim = _RefineSubdiv(refiner, subdScheme, - gtVertexCounts, - gtIndicesHandle, - gtPointAttrs, - gtVertexAttrs, - gtUniformAttrs, - gtDetailAttrs, - parms); - } - else { - meshPrim - = new GT_PrimPolygonMesh(gtVertexCounts, - gtIndicesHandle, - gtPointAttrs, - gtVertexAttrs, - gtUniformAttrs, - gtDetailAttrs); - } - meshPrim->setPrimitiveTransform( getPrimitiveTransform() ); - refiner.addPrimitive( meshPrim ); - return true; -} - -GT_PrimitiveHandle -GusdMeshWrapper::_RefineSubdiv( - GT_Refine& refiner, - const TfToken& subdScheme, - const GT_DataArrayHandle& gtVertexCounts, - const GT_DataArrayHandle& gtIndices, - const GT_AttributeListHandle& gtPointAttrs, - const GT_AttributeListHandle& gtVertexAttrs, - const GT_AttributeListHandle& gtUniformAttrs, - const GT_AttributeListHandle& gtDetailAttrs, - const GT_RefineParms* parms) const -{ - std::unique_ptr mesh( - new GT_PrimSubdivisionMesh(gtVertexCounts, - gtIndices, - gtPointAttrs, - gtVertexAttrs, - gtUniformAttrs, - gtDetailAttrs)); - - // See the houdini distribution's alembic importer for examples - // of how to use these tags: - // ./HoudiniAlembic/GABC/GABC_IObject.C - // inside HFS/houdini/public/Alembic/HoudiniAlembic.tgz - - // Scheme - if (subdScheme == UsdGeomTokens->catmullClark) { - mesh->setScheme(GT_CATMULL_CLARK); - } else if (subdScheme == UsdGeomTokens->loop) { - mesh->setScheme(GT_LOOP); - } else { - // Other values, like bilinear, have no equivalent in houdini. - } - - // Subdiv tags. - if (GT_RefineParms::getBool(parms, "subdiv:corners", true)) { - _RefineSubdivCorners(*mesh, refiner); - } - if (GT_RefineParms::getBool(parms, "subdiv:creases", true)) { - _RefineSubdivCreases(*mesh, refiner); - } - if (GT_RefineParms::getBool(parms, "subdiv:holes", true)) { - _RefineSubdivHoles(*mesh, refiner); - } - if (GT_RefineParms::getBool(parms, "osd:subdivTags", true)) { - _RefineSubdivOsdTags(*mesh, refiner); - } - - return mesh.release(); -} - -void -GusdMeshWrapper::_RefineSubdivCorners( - GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const -{ - UsdAttribute cornerIndicesAttr = m_usdMesh.GetCornerIndicesAttr(); - UsdAttribute cornerSharpnessAttr = m_usdMesh.GetCornerSharpnessesAttr(); - VtIntArray indices; - VtFloatArray sharpness; - if (cornerIndicesAttr.IsValid() && cornerSharpnessAttr.IsValid()) { - cornerIndicesAttr.Get(&indices, m_time); - cornerSharpnessAttr.Get(&sharpness, m_time); - if(!indices.empty() && !sharpness.empty()) { - GT_DataArrayHandle cornerArrayHandle - = new GT_Int32Array(indices.data(), indices.size(), 1); - mesh.appendIntTag("corner", cornerArrayHandle); - - GT_DataArrayHandle cornerWeightArrayHandle - = new GT_Real32Array(sharpness.data(), sharpness.size(), 1); - mesh.appendRealTag("corner", cornerWeightArrayHandle); - } - } -} - -void -GusdMeshWrapper::_RefineSubdivCreases( - GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const -{ - UsdAttribute creaseIndicesAttr = m_usdMesh.GetCreaseIndicesAttr(); - UsdAttribute creaseLengthsAttr = m_usdMesh.GetCreaseLengthsAttr(); - UsdAttribute creaseSharpnessesAttr = m_usdMesh.GetCreaseSharpnessesAttr(); - // creaseIndices are mandatory, so we validate as part of the guard - VtIntArray vtCreaseIndices; - if (creaseIndicesAttr.Get(&vtCreaseIndices, m_time)) { - // Extract vt arrays - VtIntArray vtCreaseLengths; - VtFloatArray vtCreaseSharpnesses; - creaseLengthsAttr.Get(&vtCreaseLengths, m_time); - creaseSharpnessesAttr.Get(&vtCreaseSharpnesses, m_time); - - // Unpack creases to vertex-pairs. - // Usd stores creases as N-length chains of vertices; - // Houdini expects separate creases per vertex pair. - std::vector creaseIndices; - std::vector creaseSharpness; - // XXX There is no validation that vtCreaseIndices is long enough! - if (vtCreaseLengths.size() == vtCreaseSharpnesses.size()) { - // We have exactly 1 sharpness per crease. - size_t i=0; - for (size_t creaseNum=0; creaseNum < vtCreaseLengths.size(); - ++creaseNum) { - const float length = vtCreaseLengths[creaseNum]; - const float sharp = vtCreaseSharpnesses[creaseNum]; - for (size_t indexInCrease=0; indexInCrease < length-1; - ++indexInCrease) { - creaseIndices.push_back( vtCreaseIndices[i] ); - creaseIndices.push_back( vtCreaseIndices[i+1] ); - creaseSharpness.push_back( sharp ); - ++i; - } - // Last index is only used once. - ++i; - } - UT_ASSERT(i == vtCreaseIndices.size()); - } else { - // We have N-1 sharpnesses for each crease that has N edges, - // i.e. the sharpness varies along each crease. - size_t i=0; - size_t sharpIndex=0; - for (size_t creaseNum=0; creaseNum < vtCreaseLengths.size(); - ++creaseNum) { - const float length = vtCreaseLengths[creaseNum]; - for (size_t indexInCrease=0; indexInCrease < length-1; - ++indexInCrease) { - creaseIndices.push_back( vtCreaseIndices[i] ); - creaseIndices.push_back( vtCreaseIndices[i+1] ); - const float sharp = vtCreaseSharpnesses[sharpIndex]; - creaseSharpness.push_back(sharp); - ++i; - ++sharpIndex; - } - // Last index is only used once. - ++i; - } - UT_ASSERT(i == vtCreaseIndices.size()); - UT_ASSERT(sharpIndex == vtCreaseSharpnesses.size()); - } - - // Store tag. - GT_Int32Array *index = - new GT_Int32Array( &creaseIndices[0], - creaseIndices.size(), 1); - GT_Real32Array *weight = - new GT_Real32Array( &creaseSharpness[0], - creaseSharpness.size(), 1); - UT_ASSERT(index->entries() == weight->entries()*2); - mesh.appendIntTag("crease", GT_DataArrayHandle(index)); - mesh.appendRealTag("crease", GT_DataArrayHandle(weight)); - } -} - - -void -GusdMeshWrapper::_RefineSubdivHoles( - GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const -{ - UsdAttribute holeIndicesAttr = m_usdMesh.GetHoleIndicesAttr(); - VtIntArray holeIndices; - holeIndicesAttr.Get(&holeIndices, m_time); - if (!holeIndices.empty()) { - mesh.appendIntTag("hole", GT_DataArrayHandle( - new GusdGT_VtArray(holeIndices))); - } -} - - -void -GusdMeshWrapper::_RefineSubdivOsdTags( - GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const -{ -#if SYS_VERSION_FULL_INT >= 0x10050000 - // The following attributes from the m_usdMesh need to be stored as - // specially named tags. (See the help docs for houdini's Subdivide - // SOP for more info). - UsdAttribute attr; - TfToken token; - - // Interpolate boundary -> "osd_vtxboundaryinterpolation" - attr = m_usdMesh.GetInterpolateBoundaryAttr(); - if (attr.IsValid() && attr.HasAuthoredValue() && - attr.Get(&token, m_time)) { - int value(-1); - if (token == UsdGeomTokens->none) { - value = osd::VTX_BOUNDARY_NONE; - - } else if (token == UsdGeomTokens->edgeOnly) { - value = osd::VTX_BOUNDARY_EDGE_ONLY; - - } else if (token == UsdGeomTokens->edgeAndCorner) { - value = osd::VTX_BOUNDARY_EDGE_AND_CORNER; - } - if (value != -1) { - mesh.appendIntTag("osd_vtxboundaryinterpolation", - GT_DataArrayHandle(new GT_IntConstant(1, value))); - } - } - - // Face varying linear interpolation -> "osd_fvarlinearinterpolation" - attr = m_usdMesh.GetFaceVaryingLinearInterpolationAttr(); - if (attr.IsValid() && attr.HasAuthoredValue() && - attr.Get(&token, m_time)) { - int value(-1); - if (token == UsdGeomTokens->none) { - value = osd::FVAR_LINEAR_NONE; - - } else if (token == UsdGeomTokens->cornersOnly) { - value = osd::FVAR_LINEAR_CORNERS_ONLY; - - } else if (token == UsdGeomTokens->cornersPlus1) { - value = osd::FVAR_LINEAR_CORNERS_PLUS1; - - } else if (token == UsdGeomTokens->cornersPlus2) { - value = osd::FVAR_LINEAR_CORNERS_PLUS2; - - } else if (token == UsdGeomTokens->boundaries) { - value = osd::FVAR_LINEAR_BOUNDARIES; - - } else if (token == UsdGeomTokens->all) { - value = osd::FVAR_LINEAR_ALL; - } - if (value != -1) { - mesh.appendIntTag("osd_fvarlinearinterpolation", - GT_DataArrayHandle(new GT_IntConstant(1, value))); - } - } - - // Triangle subdivision rule -> "osd_trianglesubdiv" - attr = m_usdMesh.GetTriangleSubdivisionRuleAttr(); - if (attr.IsValid() && attr.HasAuthoredValue() && - attr.Get(&token, m_time)) { - int value(-1); - if (token == UsdGeomTokens->catmullClark) { - value = osd::TRI_SUB_CATMARK; - - } else if (token == UsdGeomTokens->smooth) { - value = osd::VTX_BOUNDARY_EDGE_ONLY; - - } else if (token == UsdGeomTokens->edgeAndCorner) { - value = osd::TRI_SUB_SMOOTH; - } - if (value != -1) { - mesh.appendIntTag("osd_trianglesubdiv", - GT_DataArrayHandle(new GT_IntConstant(1, value))); - } - } -#else // for versions earliear than 16.5 - // Interpolation boundaries - UsdAttribute interpBoundaryAttr = m_usdMesh.GetInterpolateBoundaryAttr(); - if(interpBoundaryAttr.IsValid()) { - TfToken val; - interpBoundaryAttr.Get(&val, m_time); - GT_DataArrayHandle interpBoundaryHandle = new GT_IntConstant(1, 1); - mesh.appendIntTag("interpolateboundary", interpBoundaryHandle); - } -#endif -} - - -namespace { - -void -_validateAttrData( - const char* destName, // The Houdni name of the attribute - const char* srcName, // The USD name of the attribute - const char* primName, - GT_DataArrayHandle data, - const TfToken& interpolation, - int numFaces, - int numPoints, - int numVerticies, - GT_AttributeListHandle* vertexAttrs, - GT_AttributeListHandle* pointAttrs, - GT_AttributeListHandle* uniformAttrs, - GT_AttributeListHandle* detailAttrs ) -{ - if( interpolation == UsdGeomTokens->vertex || - interpolation == UsdGeomTokens->varying ) { - - if( data->entries() < numPoints ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - else { - *pointAttrs = (*pointAttrs)->addAttribute( destName, data, true ); - } - } - else if( interpolation == UsdGeomTokens->faceVarying ) { - - if( data->entries() < numVerticies ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - else { - *vertexAttrs = (*vertexAttrs)->addAttribute( destName, data, true ); - } - } - else if( interpolation == UsdGeomTokens->uniform ) { - if( data->entries() < numFaces ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - else { - *uniformAttrs = (*uniformAttrs)->addAttribute( destName, data, true ); - } - } - else if( interpolation == UsdGeomTokens->constant ) { - if( data->entries() < 1 ) { - TF_WARN( "Not enough values found for attribute: %s:%s", - primName, srcName ); - } - else { - *detailAttrs = (*detailAttrs)->addAttribute( destName, data, true ); - } - } -} -} - -//------------------------------------------------------------------------------ - - -bool GusdMeshWrapper:: -setSubdivisionScheme(const TfToken& scheme) -{ - if(!m_usdMesh) { - return false; - } - - UsdAttribute usdAttr = m_usdMesh.GetSubdivisionSchemeAttr(); - if(!usdAttr) return false; - - return usdAttr.Set(scheme, UsdTimeCode::Default()); -} - - -TfToken GusdMeshWrapper:: -getSubdivisionScheme() const -{ - TfToken scheme; - if(m_usdMesh) { - - m_usdMesh.GetSubdivisionSchemeAttr().Get(&scheme, UsdTimeCode::Default()); - } - return scheme; -} - - -const char* GusdMeshWrapper:: -className() const -{ - return "GusdMeshWrapper"; -} - - -void GusdMeshWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdMeshWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdMeshWrapper:: -getMemoryUsage() const -{ - cerr << "mesh wrapper, get memory usage" << endl; - return 0; -} - - -GT_PrimitiveHandle GusdMeshWrapper:: -doSoftCopy() const -{ - // TODO - return GT_PrimitiveHandle(new GusdMeshWrapper( *this )); -} - - -bool GusdMeshWrapper::isValid() const -{ - return static_cast(m_usdMesh); -} - -bool GusdMeshWrapper:: -updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) -{ - if(!isValid()) { - TF_WARN( "Can't update USD mesh from GT prim '%s'", m_usdMesh.GetPrim().GetPath().GetText() ); - return false; - } - - const GT_PrimPolygonMesh* gtMesh - = dynamic_cast(sourcePrim.get()); - if(!gtMesh) { - TF_WARN( "source prim is not a mesh. '%s'", m_usdMesh.GetPrim().GetPath().GetText() ); - return false; - } - - bool writeOverlay = ctxt.writeOverlay && !m_forceCreateNewGeo; - - // While I suppose we could write both points and transforms, it gets confusing, - // and I don't thik its necessary so lets not. - bool overlayTransforms = ctxt.overlayTransforms && !ctxt.overlayPoints; - - UsdTimeCode geoTime = ctxt.time; - if( ctxt.writeStaticGeo ) { - geoTime = UsdTimeCode::Default(); - } - - bool reverseWindingOrder = false; - GT_DataArrayHandle vertexIndirect; - if( writeOverlay && (ctxt.overlayPrimvars || ctxt.overlayPoints) && !ctxt.overlayAll ) { - - // If we are writing an overlay, we need to write geometry that matches - // the orientation of the underlying prim. All geometry in Houdini is left - // handed. - TfToken orientation; - m_usdMesh.GetOrientationAttr().Get(&orientation, geoTime); - if( orientation == UsdGeomTokens->rightHanded ) { - reverseWindingOrder = true; - - // Build a LUT that will allow us to map the vertex list or - // primvars using a "indirect" data array. - GT_Size entries = gtMesh->getVertexList()->entries(); - GT_Int32Array* indirect = new GT_Int32Array( entries, 1 ); - for(int i=0; iset(i, i); - } - _reverseWindingOrder(indirect, gtMesh->getFaceCounts() ); - vertexIndirect = indirect; - } - } - - // houXform is a transform from world space to the space this prim's - // points are defined in. Compute this space relative to this prims's - // USD parent. - - // Compute transform not including this prims transform. - GfMatrix4d xform = computeTransform( - m_usdMesh.GetPrim().GetParent(), - geoTime, - houXform, - xformCache ); - - // Compute transform including this prims transform. - GfMatrix4d loc_xform = computeTransform( - m_usdMesh.GetPrim(), - geoTime, - houXform, - xformCache ); - - // If we are writing points for an overlay but not writing transforms, - // then we have to transform the points into the proper space. - bool transformPoints = - writeOverlay && ctxt.overlayPoints && - !GusdUT_Gf::Cast(loc_xform).isIdentity(); - - if( !writeOverlay && ctxt.purpose != UsdGeomTokens->default_ ) { - m_usdMesh.GetPurposeAttr().Set( ctxt.purpose ); - } - - // intrinsic attributes ---------------------------------------------------- - - GT_Owner attrOwner = GT_OWNER_INVALID; - GT_DataArrayHandle houAttr; - UsdAttribute usdAttr; - - if( !writeOverlay || ctxt.overlayAll || - ctxt.overlayPoints || overlayTransforms ) { - // extent - houAttr = GusdGT_Utils::getExtentsArray(sourcePrim); - - usdAttr = m_usdMesh.GetExtentAttr(); - if(houAttr && usdAttr && transformPoints ) { - houAttr = GusdGT_Utils::transformPoints( houAttr, loc_xform ); - } - updateAttributeFromGTPrim( GT_OWNER_INVALID, "extents", houAttr, usdAttr, geoTime ); - } - - // transform --------------------------------------------------------------- - if( !writeOverlay || overlayTransforms ) { - - updateTransformFromGTPrim( xform, geoTime, - ctxt.granularity == GusdContext::PER_FRAME ); - } - - updateVisibilityFromGTPrim(sourcePrim, geoTime, - (!ctxt.writeOverlay || ctxt.overlayAll) && - ctxt.granularity == GusdContext::PER_FRAME ); - - // Points - if( !writeOverlay || ctxt.overlayAll || ctxt.overlayPoints ) { - - // P - houAttr = sourcePrim->findAttribute("P", attrOwner, 0); - usdAttr = m_usdMesh.GetPointsAttr(); - if( houAttr && usdAttr && transformPoints ) { - - houAttr = GusdGT_Utils::transformPoints( houAttr, loc_xform ); - } - updateAttributeFromGTPrim( attrOwner, "P", - houAttr, usdAttr, geoTime ); - - - // N - houAttr = sourcePrim->findAttribute("N", attrOwner, 0); - if( houAttr && houAttr->getTupleSize() != 3 ) { - TF_WARN( "normals (N) attribute is not a 3 vector. Tuple size = %zd.", - houAttr->getTupleSize() ); - } - usdAttr = m_usdMesh.GetNormalsAttr(); - if( updateAttributeFromGTPrim( attrOwner, "N", - houAttr, usdAttr, geoTime ) ) { - if (GT_OWNER_CONSTANT == attrOwner) { - m_usdMesh.SetNormalsInterpolation(UsdGeomTokens->constant); - } else if(GT_OWNER_PRIMITIVE == attrOwner) { - m_usdMesh.SetNormalsInterpolation(UsdGeomTokens->uniform); - } else if(GT_OWNER_VERTEX == attrOwner) { - m_usdMesh.SetNormalsInterpolation(UsdGeomTokens->faceVarying); - } else { - m_usdMesh.SetNormalsInterpolation(UsdGeomTokens->varying); - } - } - - // v - houAttr = sourcePrim->findAttribute("v", attrOwner, 0); - if( houAttr && houAttr->getTupleSize() != 3 ) { - TF_WARN( "velocity (v) attribute is not a 3 vector. Tuple size = %zd.", - houAttr->getTupleSize() ); - } - usdAttr = m_usdMesh.GetVelocitiesAttr(); - - updateAttributeFromGTPrim( attrOwner, "v", - houAttr, usdAttr, geoTime ); - } - - // Topology - if( !writeOverlay || ctxt.overlayAll ) { - - UsdTimeCode topologyTime = ctxt.time; - if( ctxt.writeStaticTopology ) { - topologyTime = UsdTimeCode::Default(); - } - - // FaceVertexCounts - GT_DataArrayHandle houVertexCounts = gtMesh->getFaceCounts(); - usdAttr = m_usdMesh.GetFaceVertexCountsAttr(); - updateAttributeFromGTPrim( GT_OWNER_INVALID, "facevertexcounts", - houVertexCounts, usdAttr, topologyTime ); - - // FaceVertexIndices - GT_DataArrayHandle houVertexList = gtMesh->getVertexList(); - if( reverseWindingOrder ) { - houVertexList = new GT_DAIndirect( vertexIndirect, houVertexList ); - } - usdAttr = m_usdMesh.GetFaceVertexIndicesAttr(); - updateAttributeFromGTPrim( GT_OWNER_INVALID, "facevertexindices", - houVertexList, usdAttr, topologyTime ); - - // Subdiv tags - if(const GT_PrimSubdivisionMesh* subdMesh - = dynamic_cast(gtMesh)) { - - // Creases - if (const GT_PrimSubdivisionMesh::Tag *tag = - subdMesh->findTag("crease")) { - const GT_Int32Array *index = - dynamic_cast(tag->intArray().get()); - const GT_Real32Array *weight = - dynamic_cast(tag->realArray().get()); - - if (index && weight) { - // We expect two index entries per weight - UT_ASSERT(index->entries() == weight->entries()*2); - - // Convert to vt arrays - const size_t numCreases = weight->entries(); - VtIntArray vtCreaseIndices; - VtIntArray vtCreaseLengths; - VtFloatArray vtCreaseSharpnesses; - vtCreaseIndices.resize(numCreases*2); - vtCreaseLengths.resize(numCreases); - vtCreaseSharpnesses.resize(numCreases); - for (size_t i=0; i < numCreases; ++i) { - vtCreaseIndices[i*2+0] = index->getValue(i*2+0); - vtCreaseIndices[i*2+1] = index->getValue(i*2+1); - vtCreaseSharpnesses[i] = weight->getValue(i); - // We leave creases as vertex-pairs; we do - // not attempt to stitch them into longer runs. - vtCreaseLengths[i] = 2; - } - - // Set usd attributes - UsdAttribute creaseIndicesAttr = - m_usdMesh.GetCreaseIndicesAttr(); - UsdAttribute creaseLengthsAttr = - m_usdMesh.GetCreaseLengthsAttr(); - UsdAttribute creaseSharpnessesAttr = - m_usdMesh.GetCreaseSharpnessesAttr(); - creaseIndicesAttr.Set(vtCreaseIndices, m_time); - creaseLengthsAttr.Set(vtCreaseLengths, m_time); - creaseSharpnessesAttr.Set(vtCreaseSharpnesses, m_time); - } - } - - // Holes - if (const GT_PrimSubdivisionMesh::Tag* tag = - subdMesh->findTag("hole")) { - - if (const GT_Int32Array* indices = - dynamic_cast(tag->intArray().get())) { - - // Convert to vt arrays - const size_t numIndices = indices->entries(); - VtIntArray vtHoleIndices(numIndices); - UTconvertArray(vtHoleIndices.data(), - indices->data(), numIndices); - - m_usdMesh.GetHoleIndicesAttr().Set(vtHoleIndices, m_time); - } - } - } - } - - // ------------------------------------------------------------------------- - - // primvars ---------------------------------------------------------------- - - if( !writeOverlay || ctxt.overlayAll || ctxt.overlayPrimvars ) { - - UsdTimeCode primvarTime = ctxt.time; - if( ctxt.writeStaticPrimvars ) { - primvarTime = UsdTimeCode::Default(); - } - - GusdGT_AttrFilter filter = ctxt.attributeFilter; - filter.appendPattern(GT_OWNER_POINT, "^P ^N ^v"); - filter.appendPattern(GT_OWNER_VERTEX, "^N ^creaseweight"); - if( !ctxt.primPathAttribute.empty() ) { - filter.appendPattern(GT_OWNER_UNIFORM, "^" + ctxt.primPathAttribute ); - } - if(const GT_AttributeListHandle pointAttrs = sourcePrim->getPointAttributes()) { - - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_POINT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( pointAttrs, filter, UsdGeomTokens->vertex, primvarTime ); - } - if(GT_AttributeListHandle vertexAttrs = sourcePrim->getVertexAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_VERTEX; - filter.setActiveOwners(owners); - - if( reverseWindingOrder ) { - // Use an index array (LUT) which will be used to lookup vertex - // attributes in the correct order. - vertexAttrs = vertexAttrs->createIndirect(vertexIndirect); - } - - updatePrimvarFromGTPrim( vertexAttrs, filter, UsdGeomTokens->faceVarying, primvarTime ); - } - - if(const GT_AttributeListHandle primAttrs = sourcePrim->getUniformAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_UNIFORM; - filter.setActiveOwners(owners); - - // When we import primvars from USD, both constant and uniform values get - // put into primitive attributes. At this point we don't really know - // which to write so we use the hueristic, if all the values in the array are - // identical, write the value as constant. - - for( auto it = primAttrs->begin(); !it.atEnd(); ++it ) { -#if SYS_VERSION_FULL_INT < 0x11000000 - if(!filter.matches( it.getName() )) - continue; -#else - if(!filter.matches( it.getName().toStdString() )) - continue; -#endif - - GT_DataArrayHandle data = it.getData(); - TfToken interpolation = UsdGeomTokens->uniform; - - // cerr << "primitive primvar = " << it.getName() << ", " - // << data->className() << ", " - // << GTstorage( data->getStorage() ) << ", " - // << data->entries() << endl; - // cerr << "face count = " << gtMesh->getFaceCount() << endl; - - if( GusdGT_Utils::isDataConstant( data ) ) { - interpolation = UsdGeomTokens->constant; - data = new GT_DASubArray( data, 0, 1 ); - } - - updatePrimvarFromGTPrim( - TfToken( it.getName() ), - GT_OWNER_UNIFORM, - interpolation, - primvarTime, - data ); - } - } - - if(const GT_AttributeListHandle constAttrs = sourcePrim->getDetailAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_CONSTANT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( constAttrs, filter, UsdGeomTokens->constant, primvarTime ); - } - - // If we have a "Cd" attribute, write it as both "Cd" and "displayColor". - // The USD guys promise me that this data will get "deduplicated" so there - // is not cost for doing this. - GT_Owner own; - if(GT_DataArrayHandle Cd = sourcePrim->findAttribute( "Cd", own, 0 )) { - - TfToken interpolation = s_ownerToUsdInterp[own]; - if ( own == GT_OWNER_PRIMITIVE ) { - - if( GusdGT_Utils::isDataConstant( Cd ) ) { - interpolation = UsdGeomTokens->constant; - Cd = new GT_DASubArray( Cd, 0, 1 ); - } - } - - updatePrimvarFromGTPrim( GusdTokens->displayColor, GT_OWNER_UNIFORM, - interpolation, primvarTime, Cd ); - } - // If we have a "Alpha" attribute, write it as both "Alpha" and "displayOpacity". - if(GT_DataArrayHandle Alpha = sourcePrim->findAttribute( "Alpha", own, 0 )) { - - TfToken interpolation = s_ownerToUsdInterp[own]; - if ( own == GT_OWNER_PRIMITIVE ) { - - if( GusdGT_Utils::isDataConstant( Alpha ) ) { - interpolation = UsdGeomTokens->constant; - Alpha = new GT_DASubArray( Alpha, 0, 1 ); - } - } - - updatePrimvarFromGTPrim( GusdTokens->displayOpacity, GT_OWNER_UNIFORM, - interpolation, primvarTime, Alpha ); - } - } - return GusdPrimWrapper::updateFromGTPrim(sourcePrim, houXform, ctxt, xformCache); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/meshWrapper.h b/third_party/houdini/gusd/meshWrapper.h deleted file mode 100644 index 778e312ffa..0000000000 --- a/third_party/houdini/gusd/meshWrapper.h +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_MESH_WRAPPER_H -#define GUSD_MESH_WRAPPER_H - -#include "primWrapper.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/mesh.h" - -class GT_PrimSubdivisionMesh; - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdMeshWrapper : public GusdPrimWrapper -{ -public: - GusdMeshWrapper( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - bool isOverride = false ); - - GusdMeshWrapper( - const UsdGeomMesh& mesh, - UsdTimeCode t, - GusdPurposeSet purposes ); - - GusdMeshWrapper( const GusdMeshWrapper &in ); - - virtual ~GusdMeshWrapper(); - - // GusdPrimWrapper interface ----------------------------------------------- - -public: - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdMesh; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) override; - - virtual bool isValid() const override; - - virtual bool refine(GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const override; - - // ------------------------------------------------------------------------- - -public: - - bool setSubdivisionScheme(const TfToken& scheme); - - TfToken getSubdivisionScheme() const; - - static GT_PrimitiveHandle - defineForWrite(const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - - GT_PrimitiveHandle - _RefineSubdiv(GT_Refine& refiner, - const TfToken& subdScheme, - const GT_DataArrayHandle& gtVertexCounts, - const GT_DataArrayHandle& gtIndices, - const GT_AttributeListHandle& gtPointAttrs, - const GT_AttributeListHandle& gtVertexAttrs, - const GT_AttributeListHandle& gtUniformAttrs, - const GT_AttributeListHandle& gtDetailAttrs, - const GT_RefineParms* parms) const; - - void _RefineSubdivCorners(GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const; - - void _RefineSubdivCreases(GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const; - - void _RefineSubdivHoles(GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const; - - void _RefineSubdivOsdTags(GT_PrimSubdivisionMesh& mesh, - GT_Refine& refiner) const; - - bool initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - void initialize( const GusdContext& ctxt, const GT_PrimitiveHandle& refPrim ); - - UsdGeomMesh m_usdMesh; - bool m_forceCreateNewGeo; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_MESH_WRAPPER_H - diff --git a/third_party/houdini/gusd/module.cpp b/third_party/houdini/gusd/module.cpp deleted file mode 100644 index 277f3b262d..0000000000 --- a/third_party/houdini/gusd/module.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "pxr/pxr.h" -#include "pxr/base/tf/pyModule.h" - -#include - -PXR_NAMESPACE_USING_DIRECTIVE - -TF_WRAP_MODULE -{ - // Indentation used to represent dependencies for load order. - TF_WRAP(GusdStageOpts); - TF_WRAP(GusdStageEdit); - TF_WRAP(GusdStageCache); -} diff --git a/third_party/houdini/gusd/packedUsdWrapper.cpp b/third_party/houdini/gusd/packedUsdWrapper.cpp deleted file mode 100644 index b1e58ec9d6..0000000000 --- a/third_party/houdini/gusd/packedUsdWrapper.cpp +++ /dev/null @@ -1,388 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "packedUsdWrapper.h" - -#include "pxr/usd/usd/variantSets.h" -#include "pxr/usd/usdShade/materialBindingAPI.h" -#include "pxr/usd/usdShade/material.h" -#include "pxr/base/tf/staticTokens.h" -#include "pxr/base/tf/stringUtils.h" - -#include "context.h" -#include "stageCache.h" -#include "USD_Utils.h" - -#include - -#include "GT_PackedUSD.h" -#include "GU_PackedUSD.h" - -PXR_NAMESPACE_OPEN_SCOPE - -using std::string; - -namespace { - -const string kLooksScope("Looks"); -const TfToken kLooksScopeToken("Scope"); - -} // anon namespace - -GusdPackedUsdWrapper::GusdPackedUsdWrapper( - const UsdStagePtr& stage, - const SdfPath& primPath, - bool isOverride ) -{ - - initUsdPrim( stage, primPath, isOverride ); -} - -GusdPackedUsdWrapper::GusdPackedUsdWrapper(const GusdPackedUsdWrapper& other ) - : GusdPrimWrapper(other) - , m_primRef(other.m_primRef) -{ -} - -GusdPackedUsdWrapper:: -~GusdPackedUsdWrapper() -{} - -bool GusdPackedUsdWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - if( asOverride ) { - m_primRef = stage->OverridePrim( path ); - if( !m_primRef || !m_primRef.IsValid() ) { - TF_WARN( "Unable to create override prim '%s'.", path.GetText() ); - } - } - else { - - SdfPath parentPath = path.GetParentPath(); - UsdPrim parent = stage->GetPrimAtPath( parentPath ); - if( !parent ) - UsdGeomXform::Define( stage, parentPath ); - - m_primRef = stage->DefinePrim( path ); - } - return bool( m_primRef ); -} - -GT_PrimitiveHandle GusdPackedUsdWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - return new GusdPackedUsdWrapper( stage, path, ctxt.writeOverlay ); -} - -bool GusdPackedUsdWrapper:: -redefine(const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim) -{ - SdfPath parentPath = path.GetParentPath(); - UsdPrim parent = stage->GetPrimAtPath( parentPath ); - if( !parent ) - UsdGeomXform::Define( stage, parentPath ); - - m_primRef = stage->DefinePrim( path ); - clearCaches(); - return true; -} - - -const char* GusdPackedUsdWrapper:: -className() const -{ - return "GusdPackedUsdWrapper"; -} - - -void GusdPackedUsdWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdPackedUsdWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdPackedUsdWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdPackedUsdWrapper:: -doSoftCopy() const -{ - return GT_PrimitiveHandle(new GusdPackedUsdWrapper(*this)); -} - - -bool -GusdPackedUsdWrapper::isValid() const -{ - return static_cast(m_primRef); -} - -// Recursively looks for ancestor path one below the root (ie "/") -SdfPath -_topPrimPath(const SdfPath primPath) -{ - if( primPath.IsEmpty() || - primPath.GetParentPath().IsEmpty() || - primPath.GetParentPath().GetParentPath().IsEmpty()) { - return primPath; - } - - return _topPrimPath(primPath.GetParentPath()); -} - -void -_rebindPrimAndChildren(UsdStageWeakPtr primStage, const SdfPath& primPath, - const UsdPrim& refPrim, const string& refFileName, - SdfPath looksPath=SdfPath()){ - - // Get the binding from the referenced prim and make sure it has a valid - // binding. - UsdShadeMaterialBindingAPI refBindingAPI(refPrim); - UsdPrim refMaterialPrim = refBindingAPI.ComputeBoundMaterial().GetPrim(); - if (!refMaterialPrim.IsValid()) - return; - - // If it doesn't exist, define a new looks scope to reference in the - // materials under. - if (looksPath.IsEmpty()) { - - // Get the ancestor prim one below the root. We want this to be a - // somewhat similar to a typical /default_prim - // /geom - // /looks - // setup, but we don't have a guarantee our top prim ancestor is the - // default prim. - SdfPath topPrimPath = _topPrimPath(primPath); - looksPath = topPrimPath.AppendPath(SdfPath(kLooksScope)); - primStage->DefinePrim(looksPath, kLooksScopeToken); - } - - // Get the path to the material on the original referenced prim. - SdfPath refMaterialPath = refMaterialPrim.GetPrimPath(); - - // Build a relative path to append to our looks scope that maps the - // original material path to one below our new looks scope. - SdfPath looksMaterialPath = refMaterialPath; - std::vector split = TfStringSplit( - refMaterialPath.GetString(), kLooksScope); - if (split.size() > 1) { - looksMaterialPath = SdfPath(split[split.size()-1]); - } - - // Append the relative path to the looks scope. At this point given an - // original material path on the referenced prim of "/Model/Looks/material" - // We should have a new path "/TopPrim/Looks/material". - looksMaterialPath = looksPath.AppendPath( - looksMaterialPath.MakeRelativePath(SdfPath("/"))); - - // Define a prim at constructed path where we want to reference the material - UsdPrim looksMaterialPrim = primStage->DefinePrim(looksMaterialPath); - - // Add a reference to the referenced prim's material - looksMaterialPrim.GetReferences().AddReference( - refFileName, refMaterialPath); - - // Unbind existing materials and bind the newly referenced material - UsdRelationship rel = refBindingAPI.GetDirectBindingRel(); - UsdPrim prim = primStage->GetPrimAtPath(primPath); - UsdShadeMaterialBindingAPI bindingAPI(prim); - if (rel) { - bindingAPI.UnbindDirectBinding(); - } - - UsdPrim materialPrim = bindingAPI.ComputeBoundMaterial().GetPrim(); - if (looksMaterialPrim != materialPrim) { - bindingAPI.Bind(UsdShadeMaterial( - primStage->GetPrimAtPath(looksMaterialPath))); - } - - // Recurse on all children of the referenced prim (same as children of the - // prim we are writing because it is a reference...). - UsdPrimSiblingRange refChidlren = refPrim.GetAllChildren(); - for (const UsdPrim& refChild : refChidlren){ - SdfPath childPrimPath = primPath.AppendPath( - SdfPath(refChild.GetPath().GetName())); - _rebindPrimAndChildren(primStage, childPrimPath, refChild, - refFileName, looksPath); - } -} - -bool -GusdPackedUsdWrapper::updateFromGTPrim( - const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) -{ - if( !m_primRef ) - return false; - - GusdGT_PackedUSD* gtPackedUSD - = dynamic_cast(sourcePrim.get()); - if(!gtPackedUSD) { - TF_WARN( "source prim is not a packed USD prim. '%s'", m_primRef.GetPrim().GetPath().GetText() ); - return false; - } - - if( !ctxt.writeOverlay ) { - - string fileName = gtPackedUSD->getAuxFileName().toStdString(); - if( fileName.empty() ) - fileName = gtPackedUSD->getFileName().toStdString(); - - SdfPath variantPrimPath = gtPackedUSD->getPrimPath(); - SdfPath primPath = variantPrimPath.StripAllVariantSelections(); - - // Get Layer Offset values from context in case set as node paramaters. - fpreal usdTimeOffset = ctxt.usdTimeOffset; - fpreal usdTimeScale = ctxt.usdTimeScale; - GT_Owner owner; - GT_DataArrayHandle usdTimeOffsetAttr; - GT_DataArrayHandle usdTimeScaleAttr; - // If attributes exists for Layer Offset values, override the context values. - usdTimeOffsetAttr = sourcePrim->findAttribute("usdtimeoffset", owner, 0); - if(usdTimeOffsetAttr != NULL ) { - usdTimeOffset = usdTimeOffsetAttr->getF64(0); - } - usdTimeScaleAttr = sourcePrim->findAttribute("usdtimescale", owner, 0); - if(usdTimeScaleAttr != NULL ) { - usdTimeScale = usdTimeScaleAttr->getF64(0); - } - // Create a layer offset for retiming references. - SdfLayerOffset layerOffset = SdfLayerOffset(usdTimeOffset, usdTimeScale); - - // Add the reference. Layer offset will only appear if not default values. - m_primRef.GetReferences().AddReference(fileName, primPath, layerOffset ); - - // Set variant selections. - if(ctxt.authorVariantSelections && - variantPrimPath.ContainsPrimVariantSelection()) { - SdfPath p(variantPrimPath); - - while(p != SdfPath::EmptyPath()) { - - if(p.IsPrimVariantSelectionPath()) { - auto vPair = p.GetVariantSelection(); - if(p.StripAllVariantSelections().IsRootPrimPath()) { - m_primRef.GetVariantSet( vPair.first ) - .SetVariantSelection( vPair.second ); - } - else { - // FIXME I don't think this is working. - UsdPrim prim = m_primRef.GetStage()->OverridePrim(p.GetPrimPath()); - prim.GetVariantSet(vPair.first) - .SetVariantSelection(vPair.second); - } - } - - p = p.GetParentPath(); - } - } - - if( ctxt.purpose != UsdGeomTokens->default_ ) { - UsdGeomImageable( m_primRef ).GetPurposeAttr().Set( ctxt.purpose ); - } - - // Bind shading if sub root reference - if( !primPath.IsRootPrimPath() ) { - - // Get the prim on its original stage - GusdStageCacheReader cache; - UT_StringRef stagePath(fileName.c_str()); - UsdStageRefPtr refStage = cache.FindOrOpen( stagePath ); - if (refStage) { - // Set modelingVariant to ALL_VARIANTS per pipeline convention. - // For some models, this will activate scopes that we might - // need to be present to properly load a variant to get access - // to its shader bindings - GusdUSD_Utils::SetModelingVariant(refStage, - refStage->GetDefaultPrim(), - GusdUSD_Utils::kAllVariantsToken); - - UsdPrim refPrim = refStage->GetPrimAtPath( primPath ); - if (refPrim.IsValid()) { - // Reference in needed materials and recursivley rebind - _rebindPrimAndChildren(m_primRef.GetStage(), - m_primRef.GetPrimPath(), - refPrim, fileName); - } - - // clear out the modelingVariant selection. - GusdUSD_Utils::ClearModelingVariant(refStage, - refStage->GetDefaultPrim()); - } - } - - // Make instanceable - if( ctxt.makeRefsInstanceable ) { - m_primRef.SetInstanceable( true ); - } - } - - updateVisibilityFromGTPrim(sourcePrim, ctxt.time, - (!ctxt.writeOverlay || ctxt.overlayAll) && - ctxt.granularity == GusdContext::PER_FRAME ); - - // transform --------------------------------------------------------------- - - if( !ctxt.writeOverlay || ctxt.overlayAll || - ctxt.overlayPoints || ctxt.overlayTransforms ) { - - GfMatrix4d xform = computeTransform( - m_primRef.GetPrim().GetParent(), - ctxt.time, - houXform, - xformCache ); - - updateTransformFromGTPrim( xform, ctxt.time, - ctxt.granularity == GusdContext::PER_FRAME ); - } - return GusdPrimWrapper::updateFromGTPrim(sourcePrim, houXform, ctxt, xformCache); -} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/packedUsdWrapper.h b/third_party/houdini/gusd/packedUsdWrapper.h deleted file mode 100644 index 57dcef9214..0000000000 --- a/third_party/houdini/gusd/packedUsdWrapper.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_PACKED_USD_WRAPPER_H -#define GUSD_PACKED_USD_WRAPPER_H - -#include "primWrapper.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/xform.h" - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdPackedUsdWrapper : public GusdPrimWrapper -{ -public: - GusdPackedUsdWrapper( const UsdStagePtr& stage, const SdfPath& path, - bool isOverride ); - GusdPackedUsdWrapper(const GusdPackedUsdWrapper& other); - virtual ~GusdPackedUsdWrapper(); - - // GusdPrimWrapper interface ----------------------------------------------- - -public: - - virtual const UsdGeomImageable getUsdPrim() const override { - return UsdGeomImageable(m_primRef); - } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) override; - - virtual bool isValid() const override; - - // ------------------------------------------------------------------------- - -public: - - static GT_PrimitiveHandle - defineForWrite( const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - -private: - - bool initUsdPrim( const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride ); - - UsdPrim m_primRef; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_PACKED_USD_WRAPPER_H - diff --git a/third_party/houdini/gusd/plugin.cpp b/third_party/houdini/gusd/plugin.cpp deleted file mode 100644 index 683dfeffc8..0000000000 --- a/third_party/houdini/gusd/plugin.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - * \file ext/houdinipkg/gusd/plugin.cpp - * \brief main plugin file - */ - -#include "gusd.h" -#include "GEO_IOTranslator.h" -#include "GT_PackedUSD.h" -#include "GT_Utils.h" -#include "GU_PackedUSD.h" -#include "GT_PointInstancer.h" -#include "curvesWrapper.h" -#include "NURBSCurvesWrapper.h" - -#include "meshWrapper.h" -#include "packedUsdWrapper.h" -#include "pointsWrapper.h" -#include "scopeWrapper.h" -#include "xformWrapper.h" -#include "instancerWrapper.h" -#include "USD_CustomTraverse.h" -#include "USD_Traverse.h" - -#include "pxr/usd/usdGeom/curves.h" -#include "pxr/usd/usdGeom/mesh.h" -#include "pxr/usd/usdGeom/points.h" -#include "pxr/usd/kind/registry.h" - -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; - -static bool libInitialized = false; - -void -GusdInit() -{ - if( libInitialized ) - return; - - // register GT_USD conversion functions keyed on GT type id - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GT_PRIM_CURVE_MESH, - &GusdCurvesWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GT_PRIM_POINT_MESH, - &GusdPointsWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GT_PRIM_PARTICLE, - &GusdPointsWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GT_PRIM_POLYGON_MESH, - &GusdMeshWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GT_PRIM_SUBDIVISION_MESH, - &GusdMeshWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GT_GEO_PACKED, - &GusdXformWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GusdGT_PackedUSD::getStaticPrimitiveType(), - &GusdPackedUsdWrapper::defineForWrite); - GusdPrimWrapper::registerPrimDefinitionFuncForWrite( - GusdGT_PointInstancer::getStaticPrimitiveType(), - &GusdInstancerWrapper::defineForWrite); - - - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("Mesh"), &GusdMeshWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("Points"), &GusdPointsWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("BasisCurves"), &GusdCurvesWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("NurbsCurves"), &GusdNURBSCurvesWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("Scope"), &GusdScopeWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("Xform"), &GusdXformWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("SkelRoot"), &GusdXformWrapper::defineForRead); - GusdPrimWrapper::registerPrimDefinitionFuncForRead( - TfToken("PointInstancer"), &GusdInstancerWrapper::defineForRead); - - GusdUSD_TraverseTable::GetInstance().SetDefault("std:components"); - GusdUSD_CustomTraverse::Initialize(); - libInitialized = true; -} - -void -GusdNewGeometryPrim( GA_PrimitiveFactory *f ) { - - GusdGU_PackedUSD::install(*f); -} - -static bool geomIOInitialized = false; - -void -GusdNewGeometryIO() -{ - if( geomIOInitialized ) - return; - - GU_Detail::registerIOTranslator(new GusdGEO_IOTranslator()); - - UT_ExtensionList* geoextension; - geoextension = UTgetGeoExtensions(); - if (!geoextension->findExtension("usd")) - geoextension->addExtension("usd"); - if (!geoextension->findExtension("usda")) - geoextension->addExtension("usda"); - if (!geoextension->findExtension("usdc")) - geoextension->addExtension("usdc"); - geomIOInitialized = true; -} - -static GusdPathComputeFunc gusdPathComputeFunc; - -void -GusdRegisterComputeRelativeSearchPathFunc( const GusdPathComputeFunc &func ) -{ - gusdPathComputeFunc = func; -} - -std::string -GusdComputeRelativeSearchPath( const std::string &path ) -{ - if( gusdPathComputeFunc ) { - return gusdPathComputeFunc( path ); - } - return path; -} - -static TfToken gusdAssetKind = KindTokens->component; - -void -GusdSetAssetKind( const TfToken &kind ) -{ - gusdAssetKind = kind; -} - -TfToken -GusdGetAssetKind() -{ - return gusdAssetKind; -} - -static GusdUsdPrimFunc gusdUsdPrimFunc; - -void -GusdRegisterOperateOnUsdPrimFunc( const GusdUsdPrimFunc &func ) -{ - gusdUsdPrimFunc = func; -} - -bool -GusdOperateOnUsdPrim( const UsdPrim &prim ) -{ - if( gusdUsdPrimFunc ) { - return gusdUsdPrimFunc( prim ); - } - return false; -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/pointsWrapper.cpp b/third_party/houdini/gusd/pointsWrapper.cpp deleted file mode 100644 index 13f2d2df10..0000000000 --- a/third_party/houdini/gusd/pointsWrapper.cpp +++ /dev/null @@ -1,384 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "pointsWrapper.h" - -#include "context.h" -#include "UT_Gf.h" -#include "GT_VtArray.h" - -#include -#include -#include -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; - -GusdPointsWrapper:: -GusdPointsWrapper( - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride ) -{ - initUsdPrim( stage, path, isOverride ); -} - -GusdPointsWrapper:: -GusdPointsWrapper( - const UsdGeomPoints& usdPoints, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdPrimWrapper( time, purposes ) - , m_usdPoints( usdPoints ) -{ -} - -GusdPointsWrapper:: -~GusdPointsWrapper() -{} - -bool GusdPointsWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - if( asOverride ) { - m_usdPoints = UsdGeomPoints(stage->OverridePrim( path )); - } - else { - m_usdPoints = UsdGeomPoints::Define(stage, path ); - } - return bool( m_usdPoints ); -} - -GT_PrimitiveHandle GusdPointsWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - return new GusdPointsWrapper( stage, path, ctxt.writeOverlay ); -} - -GT_PrimitiveHandle GusdPointsWrapper:: -defineForRead( - const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdPointsWrapper( - UsdGeomPoints( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdPointsWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay ); - clearCaches(); - return true; -} - -bool GusdPointsWrapper:: -refine(GT_Refine& refiner, const GT_RefineParms* parms) const -{ - if(!isValid()) return false; - - bool refineForViewport = GT_GEOPrimPacked::useViewportLOD(parms); - - const UsdGeomPoints& points = m_usdPoints; - - VtFloatArray vtFloatArray; - VtIntArray vtIntArray; - VtVec3fArray vtVec3Array; - - GT_AttributeListHandle gtPointAttrs = new GT_AttributeList( new GT_AttributeMap() ); - GT_AttributeListHandle gtDetailAttrs = new GT_AttributeList( new GT_AttributeMap() ); - - // point positions - UsdAttribute pointsAttr = points.GetPointsAttr(); - if(!pointsAttr) { - TF_WARN( "Invalid point attribute" ); - return false; - } - VtVec3fArray usdPoints; - pointsAttr.Get(&usdPoints, m_time); - auto gtPoints = new GusdGT_VtArray(usdPoints,GT_TYPE_POINT); - gtPointAttrs = gtPointAttrs->addAttribute("P", gtPoints, true); - - // normals - UsdAttribute normalsAttr = points.GetNormalsAttr(); - if(normalsAttr.HasAuthoredValue() && normalsAttr.Get(&vtVec3Array, m_time)) { - - if( vtVec3Array.size() < usdPoints.size() ) { - TF_WARN( "Not enough values found for normals in %s. Expected %zd, got %zd.", - points.GetPrim().GetPath().GetText(), - usdPoints.size(), vtVec3Array.size() ); - } - else { - GT_DataArrayHandle gtNormals = - new GusdGT_VtArray(vtVec3Array, GT_TYPE_NORMAL); - gtPointAttrs = gtPointAttrs->addAttribute("N", gtNormals, true); - } - } - - // widths - UsdAttribute widthsAttr = points.GetWidthsAttr(); - if( widthsAttr.HasAuthoredValue() && widthsAttr.Get(&vtFloatArray, m_time)) { - - if( vtFloatArray.size() < usdPoints.size() ) { - TF_WARN( "Not enough values found for widths in %s. Expected %zd, got %zd.", - points.GetPrim().GetPath().GetText(), - usdPoints.size(), vtFloatArray.size() ); - } - else { - auto s = vtFloatArray.size(); - auto gtWidths = new GT_Real32Array( s, 1 ); - fpreal32 *d = gtWidths->data(); - for( size_t i = 0; i < s; ++i ) { - *d++ = vtFloatArray[i] * .5; - } - gtPointAttrs = gtPointAttrs->addAttribute("pscale", gtWidths, true); - } - } - - if( !refineForViewport ) { - // velocities - UsdAttribute velAttr = points.GetVelocitiesAttr(); - if ( velAttr.HasAuthoredValue() && velAttr.Get(&vtVec3Array, m_time) ) { - - if( vtVec3Array.size() < usdPoints.size() ) { - TF_WARN( "Not enough values found for velocities in %s. Expected %zd, got %zd.", - points.GetPrim().GetPath().GetText(), - usdPoints.size(), vtVec3Array.size() ); - } - else { - GT_DataArrayHandle gtVel = - new GusdGT_VtArray(vtVec3Array, GT_TYPE_VECTOR); - gtPointAttrs = gtPointAttrs->addAttribute("v", gtVel, true); - } - } - - loadPrimvars( m_time, parms, - 0, - usdPoints.size(), - 0, - points.GetPath().GetString(), - NULL, - >PointAttrs, - NULL, - >DetailAttrs ); - } - - GT_PrimitiveHandle refinedPrimHandle - = new GT_PrimPointMesh(gtPointAttrs, - gtDetailAttrs ); - - refiner.addPrimitive(refinedPrimHandle); - return true; -} - - -const char* GusdPointsWrapper:: -className() const -{ - return "GusdPointsWrapper"; -} - - -void GusdPointsWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - cerr << "GusdPointsWrapper::enlargeBounds NOT YET IMPLEMENTED" << endl; - // TODO -} - - -int GusdPointsWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdPointsWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdPointsWrapper:: -doSoftCopy() const -{ - // TODO - return GT_PrimitiveHandle(new GusdPointsWrapper( *this )); -} - - -bool GusdPointsWrapper::isValid() const -{ - return static_cast(m_usdPoints); -} - -bool GusdPointsWrapper:: -updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) -{ - if( !m_usdPoints ) { - return false; - } - - GfMatrix4d xform = computeTransform( - m_usdPoints.GetPrim().GetParent(), - ctxt.time, - houXform, - xformCache ); - - GT_Owner attrOwner = GT_OWNER_INVALID; - GT_DataArrayHandle houAttr; - UsdAttribute usdAttr; - - // extent ------------------------------------------------------------------ - - houAttr = GusdGT_Utils::getExtentsArray(sourcePrim); - usdAttr = m_usdPoints.GetExtentAttr(); - updateAttributeFromGTPrim( GT_OWNER_INVALID, "extents", houAttr, usdAttr, ctxt.time ); - - // transform --------------------------------------------------------------- - - updateTransformFromGTPrim( xform, ctxt.time, - ctxt.granularity == GusdContext::PER_FRAME ); - - // intrinsic attributes ---------------------------------------------------- - - if( !ctxt.writeOverlay && ctxt.purpose != UsdGeomTokens->default_ ) { - m_usdPoints.GetPurposeAttr().Set( ctxt.purpose ); - } - - // visibility - updateVisibilityFromGTPrim(sourcePrim, ctxt.time, - (!ctxt.writeOverlay || ctxt.overlayAll) && - ctxt.granularity == GusdContext::PER_FRAME ); - - // P - houAttr = sourcePrim->findAttribute("P", attrOwner, 0); - usdAttr = m_usdPoints.GetPointsAttr(); - updateAttributeFromGTPrim( attrOwner, "P", houAttr, usdAttr, ctxt.time ); - - // N - houAttr = sourcePrim->findAttribute("N", attrOwner, 0); - usdAttr = m_usdPoints.GetNormalsAttr(); - updateAttributeFromGTPrim( attrOwner, "N", houAttr, usdAttr, ctxt.time ); - - // v - houAttr = sourcePrim->findAttribute("v", attrOwner, 0); - usdAttr = m_usdPoints.GetVelocitiesAttr(); - updateAttributeFromGTPrim( attrOwner, "v", houAttr, usdAttr, ctxt.time ); - - // pscale & width - houAttr = sourcePrim->findAttribute("widths", attrOwner, 0); - if(!houAttr) { - houAttr = sourcePrim->findAttribute("pscale", attrOwner, 0); - - // If we found pscale, multiply values by 2 before converting to width. - if(houAttr && houAttr->getTupleSize() == 1) { - const GT_Size numVals = houAttr->entries(); - std::vector pscaleArray(numVals); - houAttr->fillArray(pscaleArray.data(), 0, numVals, 1); - - std::transform( - pscaleArray.begin(), - pscaleArray.end(), - pscaleArray.begin(), - std::bind1st(std::multiplies(), 2.0)); - - houAttr.reset(new GT_Real32Array(pscaleArray.data(), numVals, 1)); - } - } - usdAttr = m_usdPoints.GetWidthsAttr(); - updateAttributeFromGTPrim( attrOwner, "widths", houAttr, usdAttr, ctxt.time ); - - // ------------------------------------------------------------------------- - - // primvars ---------------------------------------------------------------- - - GusdGT_AttrFilter filter = ctxt.attributeFilter; - filter.appendPattern(GT_OWNER_POINT, "^P ^N ^v ^widths ^pscale"); - if(const GT_AttributeListHandle pointAttrs = sourcePrim->getPointAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_POINT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( pointAttrs, filter, UsdGeomTokens->vertex, ctxt.time ); - } - if(const GT_AttributeListHandle constAttrs = sourcePrim->getDetailAttributes()) { - GusdGT_AttrFilter::OwnerArgs owners; - owners << GT_OWNER_CONSTANT; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( constAttrs, filter, UsdGeomTokens->constant, ctxt.time ); - } - - GT_Owner own; - if(GT_DataArrayHandle Cd = sourcePrim->findAttribute( "Cd", own, 0 )) { - GT_AttributeMapHandle attrMap = new GT_AttributeMap(); - GT_AttributeListHandle attrList = new GT_AttributeList( attrMap ); - attrList = attrList->addAttribute( "displayColor", Cd, true ); - GusdGT_AttrFilter filter( "*" ); - GusdGT_AttrFilter::OwnerArgs owners; - owners << own; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( attrList, filter, s_ownerToUsdInterp[own], ctxt.time ); - } - if(GT_DataArrayHandle Alpha = sourcePrim->findAttribute( "Alpha", own, 0 )) { - GT_AttributeMapHandle attrMap = new GT_AttributeMap(); - GT_AttributeListHandle attrList = new GT_AttributeList( attrMap ); - attrList = attrList->addAttribute( "displayOpacity", Alpha, true ); - GusdGT_AttrFilter filter( "*" ); - GusdGT_AttrFilter::OwnerArgs owners; - owners << own; - filter.setActiveOwners(owners); - updatePrimvarFromGTPrim( attrList, filter, s_ownerToUsdInterp[own], ctxt.time ); - } - - // ------------------------------------------------------------------------- - return GusdPrimWrapper::updateFromGTPrim(sourcePrim, houXform, ctxt, xformCache); -} - -PXR_NAMESPACE_CLOSE_SCOPE - - diff --git a/third_party/houdini/gusd/pointsWrapper.h b/third_party/houdini/gusd/pointsWrapper.h deleted file mode 100644 index c0d0060b43..0000000000 --- a/third_party/houdini/gusd/pointsWrapper.h +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_POINTS_WRAPPER_H -#define GUSD_POINTS_WRAPPER_H - -#include "primWrapper.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/points.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -class GusdPointsWrapper : public GusdPrimWrapper -{ -public: - GusdPointsWrapper( - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride = false ); - - GusdPointsWrapper( - const UsdGeomPoints& usdPoints, - UsdTimeCode t, - GusdPurposeSet purposes ); - - virtual ~GusdPointsWrapper(); - - // GusdGT_Primitive interface ----------------------------------------------- - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdPoints; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ) override; - - virtual bool isValid() const override; - - virtual bool refine(GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const override; - - // ------------------------------------------------------------------------- - -public: - - static GT_PrimitiveHandle - defineForWrite(const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - bool initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - UsdGeomPoints m_usdPoints; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_POINTS_WRAPPER_H - diff --git a/third_party/houdini/gusd/primWrapper.cpp b/third_party/houdini/gusd/primWrapper.cpp deleted file mode 100644 index 5d18c566ed..0000000000 --- a/third_party/houdini/gusd/primWrapper.cpp +++ /dev/null @@ -1,1139 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "primWrapper.h" - -#include "context.h" -#include "GT_VtArray.h" -#include "GU_USD.h" -#include "tokens.h" -#include "USD_XformCache.h" -#include "UT_Gf.h" - -#include "pxr/base/gf/half.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#if SYS_VERSION_FULL_INT >= 0x11050000 -#include -#endif - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cout; -using std::cerr; -using std::endl; -using std::string; -using std::map; -using std::set; -using std::vector; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -namespace { - -// XXX Temporary until UsdTimeCode::NextTime implemented -const double TIME_SAMPLE_DELTA = 0.001; - -GT_PrimitiveHandle _nullPrimReadFunc( - const UsdGeomImageable&, UsdTimeCode, GusdPurposeSet) -{ - return GT_PrimitiveHandle(); -} - -} // anon namespace - -GusdPrimWrapper::GTTypeInfoMap GusdPrimWrapper::s_gtTypeInfoMap; - -GusdPrimWrapper:: -USDTypeToDefineFuncMap GusdPrimWrapper::s_usdTypeToFuncMap - = USDTypeToDefineFuncMap(); - -GusdPrimWrapper:: -GTTypeSet GusdPrimWrapper::s_supportedNativeGTTypes - = GTTypeSet(); - -namespace { - -int -getPrimType( const GT_PrimitiveHandle &prim ) -{ - int primType = prim->getPrimitiveType(); - if( primType == GT_PRIM_INSTANCE ) { - const GT_PrimInstance *inst = - UTverify_cast(prim.get()); - if( inst && inst->geometry() ) { - primType = inst->geometry()->getPrimitiveType(); - } - } - return primType; -} - -} // close namespace - -/// static -GT_PrimitiveHandle GusdPrimWrapper:: -defineForWrite(const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - GT_PrimitiveHandle gtUsdPrimHandle; - - if( !sourcePrim || !stage ) - return gtUsdPrimHandle; - - int primType = getPrimType( sourcePrim ); - - auto mapIt = s_gtTypeInfoMap.find( primType ); - if( mapIt != s_gtTypeInfoMap.end() ) { - gtUsdPrimHandle = mapIt->second.writeFunc(sourcePrim, - stage, - path, - ctxt); - } - return gtUsdPrimHandle; -} - -// static -bool GusdPrimWrapper:: -getPrimName( const GT_PrimitiveHandle &sourcePrim, - std::string &primName ) -{ - int primType = getPrimType( sourcePrim ); - - auto mapIt = s_gtTypeInfoMap.find( primType ); - if( mapIt != s_gtTypeInfoMap.end() && - mapIt->second.primNameFunc ) { - return mapIt->second.primNameFunc(sourcePrim, primName); - } - return false; -} - -/* static */ -const char* GusdPrimWrapper:: -getUsdName( int primType ) -{ - auto mapIt = s_gtTypeInfoMap.find( primType ); - if( mapIt != s_gtTypeInfoMap.end() ) { - return mapIt->second.templateName; - } - return NULL; -} - -/* static */ -bool GusdPrimWrapper:: -isGroupType( int primType ) -{ - auto mapIt = s_gtTypeInfoMap.find( primType ); - if( mapIt != s_gtTypeInfoMap.end() ) { - return mapIt->second.isGroupType; - } - return false; -} - - -GT_PrimitiveHandle GusdPrimWrapper:: -defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - GT_PrimitiveHandle gtUsdPrimHandle; - - // Find the function registered for the source prim's type - // to define the prim from read and call that function. - if(sourcePrim) { - const TfToken& typeName = sourcePrim.GetPrim().GetTypeName(); - USDTypeToDefineFuncMap::const_accessor caccessor; - if(s_usdTypeToFuncMap.find(caccessor, typeName)) { - gtUsdPrimHandle = caccessor->second(sourcePrim,time,purposes); - } - else { - // If no function is registered for the prim's type, try to - // find a supported base type. - const TfType& baseType = TfType::Find(); - const TfType& derivedType - = baseType.FindDerivedByName(typeName.GetText()); - - vector ancestorTypes; - derivedType.GetAllAncestorTypes(&ancestorTypes); - - for(size_t i=1; i typeAliases = baseType.GetAliases(ancestorType); - typeAliases.push_back(ancestorType.GetTypeName()); - - for(auto const& typeAlias : typeAliases) { - if(s_usdTypeToFuncMap.find(caccessor, TfToken(typeAlias))) { - gtUsdPrimHandle = caccessor->second(sourcePrim,time,purposes); - USDTypeToDefineFuncMap::accessor accessor; - s_usdTypeToFuncMap.insert(accessor, typeName); - accessor->second = caccessor->second; - TF_WARN("Type \"%s\" not registered, using base type \"%s\".", - typeName.GetText(), typeAlias.c_str()); - break; - } - } - if(gtUsdPrimHandle) break; - } - - if(!gtUsdPrimHandle) { - // If we couldn't find a function for the prim's type or any - // of it's base types, register a function which returns an - // empty prim handle. - registerPrimDefinitionFuncForRead(typeName, _nullPrimReadFunc); - TF_WARN("Couldn't read unsupported USD prim type \"%s\".", - typeName.GetText()); - } - } - } - return gtUsdPrimHandle; -} - - -bool GusdPrimWrapper:: -registerPrimDefinitionFuncForWrite(int gtPrimId, - DefinitionForWriteFunction writeFunc, - GetPrimNameFunction primNameFunc, - bool isGroupType, - const char *typeTemplateName ) -{ - if(s_gtTypeInfoMap.find(gtPrimId) != s_gtTypeInfoMap.end()) { - return false; - } - - s_gtTypeInfoMap[gtPrimId] = GTTypeInfo( writeFunc, primNameFunc, - isGroupType, typeTemplateName ); - s_supportedNativeGTTypes.insert(gtPrimId); - - return true; -} - - -bool GusdPrimWrapper:: -registerPrimDefinitionFuncForRead(const TfToken& usdTypeName, - DefinitionForReadFunction func) -{ - USDTypeToDefineFuncMap::accessor accessor; - if(! s_usdTypeToFuncMap.insert(accessor, usdTypeName)) { - return false; - } - - accessor->second = func; - - return true; -} - -bool GusdPrimWrapper:: -isGTPrimSupported(const GT_PrimitiveHandle& prim) -{ - if (!prim) return false; - - const int primType = prim->getPrimitiveType(); - - return s_supportedNativeGTTypes.find(primType) - != s_supportedNativeGTTypes.end(); -} - -//------------------------------------------------------------------------- - -map GusdPrimWrapper::s_ownerToUsdInterp { - {GT_OWNER_POINT, UsdGeomTokens->vertex}, - {GT_OWNER_VERTEX, UsdGeomTokens->faceVarying}, - {GT_OWNER_UNIFORM, UsdGeomTokens->uniform}, - {GT_OWNER_CONSTANT, UsdGeomTokens->constant}}; - -map GusdPrimWrapper::s_ownerToUsdInterpCurve { - {GT_OWNER_VERTEX, UsdGeomTokens->vertex}, - {GT_OWNER_UNIFORM, UsdGeomTokens->uniform}, - {GT_OWNER_CONSTANT, UsdGeomTokens->constant}}; - -GusdPrimWrapper::GusdPrimWrapper() - : m_time( UsdTimeCode::Default() ) - , m_visible( true ) - , m_lastXformSet( UsdTimeCode::Default() ) - , m_lastXformCompared( UsdTimeCode::Default() ) -{ -} - -GusdPrimWrapper::GusdPrimWrapper( - const UsdTimeCode &time, - const GusdPurposeSet &purposes ) - : GT_Primitive() - , m_time( time ) - , m_purposes( purposes ) - , m_visible( true ) - , m_lastXformSet( UsdTimeCode::Default() ) - , m_lastXformCompared( UsdTimeCode::Default() ) -{ -} - -GusdPrimWrapper::GusdPrimWrapper( const GusdPrimWrapper &in ) - : GT_Primitive(in) - , m_time( in.m_time ) - , m_purposes( in.m_purposes ) - , m_visible( in.m_visible ) - , m_lastXformSet( in.m_lastXformSet ) - , m_lastXformCompared( in.m_lastXformCompared ) -{ -} - -GusdPrimWrapper::~GusdPrimWrapper() -{ -} - - -bool -GusdPrimWrapper::isValid() const -{ - return false; -} - -bool -GusdPrimWrapper::unpack( - GU_Detail& gdr, - const UT_StringRef& fileName, - const SdfPath& primPath, - const UT_Matrix4D& xform, - fpreal frame, - const char * viewportLod, - GusdPurposeSet purposes ) -{ - return false; -} - -bool -GusdPrimWrapper::redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - return false; -} - -bool -GusdPrimWrapper::updateFromGTPrim( - const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) -{ - // Set the active state of the UsdPrim if any "usdactive" attributes exist - updateActiveFromGTPrim(sourcePrim, ctxt.time); - - return true; -} - -void -GusdPrimWrapper::setVisibility(const TfToken& visibility, UsdTimeCode time) -{ - if( visibility == UsdGeomTokens->invisible ) { - m_visible = false; - } else { - m_visible = true; - } - - const UsdAttribute visAttr = getUsdPrim().GetVisibilityAttr(); - if( visAttr.IsValid() ) { - TfToken oldVal; - if( !visAttr.Get( &oldVal, - UsdTimeCode::Default() ) || oldVal != UsdGeomTokens->invisible ) { - visAttr.Set(UsdGeomTokens->invisible, UsdTimeCode::Default()); - } - visAttr.Set(visibility, time); - } -} - -void -GusdPrimWrapper::updateVisibilityFromGTPrim( - const GT_PrimitiveHandle& sourcePrim, - UsdTimeCode time, - bool forceWrite ) -{ - // If we're tracking visibility, set this prim's default state to - // invisible. File-per-frame exports rely on this if the prim isn't - // persistent throughout the frame range. - GT_Owner attrOwner; - GT_DataArrayHandle houAttr - = sourcePrim->findAttribute(GUSD_VISIBLE_ATTR, attrOwner, 0); - if(houAttr) { - GT_String visible = houAttr->getS(0); - if (visible) { - if (strcmp(visible, "inherited") == 0) { - setVisibility(UsdGeomTokens->inherited, time); - } else if (strcmp(visible, "invisible") == 0) { - setVisibility(UsdGeomTokens->invisible, time); - } - } - } - else if ( forceWrite ) { - if(isVisible()) { - setVisibility(UsdGeomTokens->inherited, time); - } else { - setVisibility(UsdGeomTokens->invisible, time); - } - } -} - -void -GusdPrimWrapper::updateActiveFromGTPrim( - const GT_PrimitiveHandle& sourcePrim, - UsdTimeCode time) -{ - UsdPrim prim = getUsdPrim().GetPrim(); - - GT_Owner attrOwner; - GT_DataArrayHandle houAttr - = sourcePrim->findAttribute(GUSD_ACTIVE_ATTR, attrOwner, 0); - if (houAttr) { - GT_String state = houAttr->getS(0); - if (state) { - if (strcmp(state, "active") == 0) { - prim.SetActive(true); - } else if (strcmp(state, "inactive") == 0) { - prim.SetActive(false); - } - } - } -} - -void -GusdPrimWrapper::updateTransformFromGTPrim( const GfMatrix4d &xform, - UsdTimeCode time, bool force ) -{ - UsdGeomImageable usdGeom = getUsdPrim(); - UsdGeomXformable prim( usdGeom ); - - // Determine if we need to clear previous transformations from a stronger - // opinion on the stage before authoring ours. - UsdStagePtr stage = usdGeom.GetPrim().GetStage(); - UsdEditTarget currEditTarget = stage->GetEditTarget(); - - // If the edit target does no mapping, it is most likely the session - // layer which means it is in the local layer stack and can overlay - // any xformOps. - if ( !currEditTarget.GetMapFunction().IsNull() && - !currEditTarget.GetMapFunction().IsIdentity() ) { - bool reset; - std::vector xformVec = prim.GetOrderedXformOps(&reset); - - // The xformOps attribute is static so we only check if we haven't - // changed anything yet. In addition nothing needs to be cleared if it - // was previously empty. - if (m_lastXformSet.IsDefault() && !xformVec.empty()) { - // Load the root layer for temp, stronger opinion changes. - stage->GetRootLayer()->SetPermissionToSave(false); - stage->SetEditTarget(stage->GetRootLayer()); - UsdGeomXformable stagePrim( getUsdPrim() ); - - // Clear the xformOps on the stronger layer, so our weaker edit - // target (with mapping across a reference) can write out clean, - // new transforms. - stagePrim.ClearXformOpOrder(); - stage->SetEditTarget(currEditTarget); - } - } - - if( !prim ) - return; - - // Try to avoid setting the transform when we can. - // If force it true, always write the transform (used when writting per frame) - bool setKnot = true; - if( !force ) { - - // Has the transform has been set at least once - if( !m_lastXformSet.IsDefault() ) { - - // Is the transform at this frame the same as the last frame - if( GfIsClose(xform, m_xformCache, 1e-10) ) { - setKnot = false; - m_lastXformCompared = time; - } - else { - // If the transform has been held for more than one frame, - // set a knot on the last frame - if( m_lastXformCompared != m_lastXformSet ) { - prim.MakeMatrixXform().Set( m_xformCache, m_lastXformCompared ); - } - } - } - else { - // If the transform is an identity, don't set it - if( GfIsClose(xform, GfMatrix4d(1), 1e-10) ) { - setKnot = false; - m_lastXformCompared = time; - } - else { - - // If the transform was identity and now isn't, set a knot on the last frame - if( !m_lastXformCompared.IsDefault() ) { - prim.MakeMatrixXform().Set( GfMatrix4d(1.0), m_lastXformCompared ); - } - } - } - } - - if( setKnot ) { - prim.MakeMatrixXform().Set( xform, time ); - m_xformCache = xform; - m_lastXformSet = time; - m_lastXformCompared = time; - } -} - -bool -GusdPrimWrapper::updateAttributeFromGTPrim( - GT_Owner owner, - const std::string& name, - const GT_DataArrayHandle& houAttr, - UsdAttribute& usdAttr, - UsdTimeCode time ) -{ - // return true if we need to set the value - if( !houAttr || !usdAttr ) - return false; - - // Check to see if the current value of this attribute has changed - // from the last time we set the value. - - AttrLastValueKeyType key(owner, name); - auto it = m_lastAttrValueDict.find( key ); - if( it == m_lastAttrValueDict.end()) { - - // Set the value for the first time - m_lastAttrValueDict.emplace( - key, AttrLastValueEntry( time, houAttr->harden())); - - GusdGT_Utils::setUsdAttribute(usdAttr, houAttr, time); - return true; - } - else { - AttrLastValueEntry& entry = it->second; - if( houAttr->isEqual( *entry.data )) { - - // The value are the as before. Don't set. - entry.lastCompared = time; - return false; - } - else { - if( entry.lastCompared != entry.lastSet ) { - // Set a value on the last frame the previous value was valid. - GusdGT_Utils::setUsdAttribute(usdAttr, entry.data, entry.lastCompared); - } - - // set the new value - GusdGT_Utils::setUsdAttribute(usdAttr, houAttr, time); - - // save this value to compare on later frames - entry.data = houAttr->harden(); - entry.lastSet = entry.lastCompared = time; - return true; - } - } - return false; -} - -bool -GusdPrimWrapper::updatePrimvarFromGTPrim( - const TfToken& name, - const GT_Owner& owner, - const TfToken& interpolation, - UsdTimeCode time, - const GT_DataArrayHandle& dataIn ) -{ - GT_DataArrayHandle data = dataIn; - UsdGeomImageable prim( getUsdPrim() ); - - // cerr << "updatePrimvarFromGTPrim: " - // << prim.GetPrim().GetPath() << ":" << name << ", " << interpolation - // << ", entries = " << dataIn->entries() << endl; - - AttrLastValueKeyType key(owner, name); - auto it = m_lastAttrValueDict.find( key ); - if( it == m_lastAttrValueDict.end() ) { - - // If we're creating an overlay this primvar might already be - // authored on the prim. If the primvar is indexed we need to - // block the indices attribute, because we flatten indexed - // primvars. - if( UsdGeomPrimvar primvar = prim.GetPrimvar(name) ) { - if( primvar.IsIndexed() ) { - primvar.BlockIndices(); - } - } - - m_lastAttrValueDict.emplace( - key, AttrLastValueEntry( time, data->harden())); - - GusdGT_Utils::setPrimvarSample( prim, name, data, interpolation, time ); - } - else { - AttrLastValueEntry& entry = it->second; - if( data->isEqual( *entry.data )) { - entry.lastCompared = time; - return false; - } - else { - if( entry.lastCompared != entry.lastSet ) { - GusdGT_Utils::setPrimvarSample( prim, name, entry.data, interpolation, entry.lastCompared ); - } - - if( UsdGeomPrimvar primvar = prim.GetPrimvar(name) ) { - if( primvar.IsIndexed() ) { - primvar.BlockIndices(); - } - } - - GusdGT_Utils::setPrimvarSample( prim, name, data, interpolation, time ); - entry.data = data->harden(); - entry.lastSet = entry.lastCompared = time; - return true; - } - } - return true; -} - -bool -GusdPrimWrapper::updatePrimvarFromGTPrim( - const GT_AttributeListHandle& gtAttrs, - const GusdGT_AttrFilter& primvarFilter, - const TfToken& interpolation, - UsdTimeCode time ) -{ - UsdGeomImageable prim( getUsdPrim() ); - const GT_AttributeMapHandle attrMapHandle = gtAttrs->getMap(); - - for(GT_AttributeMap::const_names_iterator mapIt=attrMapHandle->begin(); - !mapIt.atEnd(); ++mapIt) { - -#if SYS_VERSION_FULL_INT < 0x11000000 - string attrname = mapIt.name(); -#else - string attrname = mapIt->first.toStdString(); -#endif - - if(!primvarFilter.matches(attrname)) - continue; - - const int attrIndex = attrMapHandle->get(attrname); - const GT_Owner owner = attrMapHandle->getOriginalOwner(attrIndex); - GT_DataArrayHandle attrData = gtAttrs->get(attrIndex); - -#if SYS_VERSION_FULL_INT >= 0x11050000 - // Decode Houdini geometry attribute names to get back the original - // USD primvar name. This allows round tripping of namespaced - // primvars from USD -> Houdini -> USD. - UT_StringHolder name = UT_VarEncode::decode(attrname); -#else - UT_StringHolder name = attrname; -#endif - - updatePrimvarFromGTPrim( - TfToken( name.toStdString() ), - owner, - interpolation, - time, - attrData ); - } - return true; -} - -void -GusdPrimWrapper::clearCaches() -{ - m_lastAttrValueDict.clear(); -} - -void -GusdPrimWrapper::addLeadingBookend( double curFrame ) -{ - double bookendFrame = curFrame - TIME_SAMPLE_DELTA; - - // Ensure the stage start frame <= bookendFrame - UsdStagePtr stage = getUsdPrim().GetPrim().GetStage(); - if(stage) { - double startFrame = stage->GetStartTimeCode(); - if( startFrame > bookendFrame) { - stage->SetStartTimeCode(bookendFrame); - } - } - - const UsdAttribute attr = getUsdPrim().GetVisibilityAttr(); - attr.Set(UsdGeomTokens->invisible, UsdTimeCode(bookendFrame)); - attr.Set(UsdGeomTokens->inherited, UsdTimeCode(curFrame)); -} - -void -GusdPrimWrapper::addTrailingBookend( double curFrame ) -{ - double bookendFrame = curFrame - TIME_SAMPLE_DELTA; - - const UsdAttribute attr = getUsdPrim().GetVisibilityAttr(); - attr.Set(UsdGeomTokens->inherited, UsdTimeCode(bookendFrame)); - attr.Set(UsdGeomTokens->invisible, UsdTimeCode(curFrame)); -} - - -namespace { - - -const char* -Gusd_GetCStr(const std::string& o) { return o.c_str(); } - -const char* -Gusd_GetCStr(const TfToken& o) { return o.GetText(); } - -const char* -Gusd_GetCStr(const SdfAssetPath& o) { return o.GetAssetPath().c_str(); } - - -/// Convert a value to a GT_DataArray. -/// The value is either a POD type or a tuple of PODs. -template -GT_DataArray* -Gusd_ConvertTupleToGt(const VtValue& val) -{ - TF_DEV_AXIOM(val.IsHolding()); - - const auto& heldVal = val.UncheckedGet(); - - return new GTARRAY((const typename GTARRAY::data_type*)&heldVal, - 1, GusdGetTupleSize(), GT_TYPE); -} - - -/// Convert a VtArray to a GT_DataArray. -/// The elements of the array are either PODs, or tuples of PODs (eg., vectors). -template -GT_DataArray* -Gusd_ConvertTupleArrayToGt(const UsdGeomPrimvar& primvar, const VtValue& val) -{ - TF_DEV_AXIOM(val.IsHolding >()); - - const int tupleSize = GusdGetTupleSize(); - - const auto& array = val.UncheckedGet >(); - if (array.size() > 0) { - const int elementSize = primvar.GetElementSize(); - if (elementSize > 0) { - - // Only lookup primvar role for non POD types - // (vectors, matrices, etc.), and only if it has not - // been specified via template argument. - GT_Type type = GT_TYPE; - if (type == GT_TYPE_NONE) { - // A GT_Type has not been specified using template args. - // We can try to derive a type from the role on the primvar's - // type name, but only worth doing for types that can - // actually have roles (eg., not scalars) - if (tupleSize > 1) { - type = GusdGT_Utils::getType(primvar.GetTypeName()); - } - } - - if (elementSize == 1) { - return new GusdGT_VtArray(array, type); - } else { - const size_t numTuples = array.size()/elementSize; - const int gtTupleSize = elementSize*tupleSize; - - if (numTuples*elementSize == array.size()) { - return new GTARRAY( - (const typename GTARRAY::data_type*)array.cdata(), - numTuples, gtTupleSize); - } else { - GUSD_WARN().Msg( - "Invalid primvar <%s>: array size [%zu] is not a " - "multiple of the elementSize [%d].", - primvar.GetAttr().GetPath().GetText(), - array.size(), elementSize); - } - } - } else { - GUSD_WARN().Msg( - "Invalid primvar <%s>: illegal elementSize [%d].", - primvar.GetAttr().GetPath().GetText(), - elementSize); - } - } - return nullptr; -} - - -/// Convert a string-like value to a GT_DataArray. -template -GT_DataArray* -Gusd_ConvertStringToGt(const VtValue& val) -{ - TF_DEV_AXIOM(val.IsHolding()); - - auto gtString = new GT_DAIndexedString(1); - gtString->setString(0, 0, Gusd_GetCStr(val.UncheckedGet())); - return gtString; -} - - -/// Convert a VtArray of string-like values to a GT_DataArray. -template -GT_DataArray* -Gusd_ConvertStringArrayToGt(const UsdGeomPrimvar& primvar, const VtValue& val) -{ - TF_DEV_AXIOM(val.IsHolding >()); - - const auto& array = val.UncheckedGet >(); - if (array.size() > 0) { - const int elementSize = primvar.GetElementSize(); - if (elementSize > 0) { - const size_t numTuples = array.size()/elementSize; - if (numTuples*elementSize == array.size()) { - const ELEMTYPE* values = array.cdata(); - - auto gtStrings = new GT_DAIndexedString(numTuples, elementSize); - - for (size_t i = 0; i < numTuples; ++i) { - for (int cmp = 0; cmp < elementSize; ++cmp, ++values) { - gtStrings->setString(i, cmp, Gusd_GetCStr(*values)); - } - } - return gtStrings; - } else { - GUSD_WARN().Msg( - "Invalid primvar <%s>: array size [%zu] is not a " - "multiple of the elementSize [%d].", - primvar.GetAttr().GetPath().GetText(), - array.size(), elementSize); - } - } else { - GUSD_WARN().Msg( - "Invalid primvar <%s>: illegal elementSize [%d].", - primvar.GetAttr().GetPath().GetText(), - elementSize); - } - } - return nullptr; -} - - -} // namespace - - -/* static */ -GT_DataArrayHandle -GusdPrimWrapper::convertPrimvarData( const UsdGeomPrimvar& primvar, UsdTimeCode time ) -{ - VtValue val; - if (!primvar.ComputeFlattened(&val, time)) { - return nullptr; - } - return convertPrimvarData(primvar, val); -} - - -/* static */ -GT_DataArrayHandle -GusdPrimWrapper::convertPrimvarData( const UsdGeomPrimvar& primvar, - const VtValue& val ) -{ -#define _CONVERT_TUPLE(elemType, gtArray, gtType) \ - if (val.IsHolding()) { \ - return Gusd_ConvertTupleToGt(val); \ - } else if (val.IsHolding >()) { \ - return Gusd_ConvertTupleArrayToGt( \ - primvar, val); \ - } - - // Check for most common value types first. - _CONVERT_TUPLE(GfVec3f, GT_Real32Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec2f, GT_Real32Array, GT_TYPE_NONE); - _CONVERT_TUPLE(float, GT_Real32Array, GT_TYPE_NONE); - _CONVERT_TUPLE(int, GT_Int32Array, GT_TYPE_NONE); - - // Scalars - _CONVERT_TUPLE(double, GT_Real64Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfHalf, GT_Real16Array, GT_TYPE_NONE); - _CONVERT_TUPLE(int64, GT_Int64Array, GT_TYPE_NONE); - _CONVERT_TUPLE(unsigned char, GT_UInt8Array, GT_TYPE_NONE); - - // TODO: UInt, UInt64 (convert to int32/int64?) - - // Vec2 - _CONVERT_TUPLE(GfVec2d, GT_Real64Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec2h, GT_Real16Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec2i, GT_Int32Array, GT_TYPE_NONE); - - // Vec3 - _CONVERT_TUPLE(GfVec3d, GT_Real64Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec3h, GT_Real16Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec3i, GT_Int32Array, GT_TYPE_NONE); - - // Vec4 - _CONVERT_TUPLE(GfVec4d, GT_Real64Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec4f, GT_Real32Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec4h, GT_Real16Array, GT_TYPE_NONE); - _CONVERT_TUPLE(GfVec4i, GT_Int32Array, GT_TYPE_NONE); - - // Quat - _CONVERT_TUPLE(GfQuatd, GT_Real64Array, GT_TYPE_QUATERNION); - _CONVERT_TUPLE(GfQuatf, GT_Real32Array, GT_TYPE_QUATERNION); - _CONVERT_TUPLE(GfQuath, GT_Real16Array, GT_TYPE_QUATERNION); - - // Matrices - _CONVERT_TUPLE(GfMatrix3d, GT_Real64Array, GT_TYPE_MATRIX3); - _CONVERT_TUPLE(GfMatrix4d, GT_Real64Array, GT_TYPE_MATRIX); - // TODO: Correct GT_Type for GfMatrix2d? - _CONVERT_TUPLE(GfMatrix2d, GT_Real64Array, GT_TYPE_NONE); - -#undef _CONVERT_TUPLE - -#define _CONVERT_STRING(elemType) \ - if (val.IsHolding()) { \ - return Gusd_ConvertStringToGt(val); \ - } else if (val.IsHolding >()) { \ - return Gusd_ConvertStringArrayToGt(primvar, val); \ - } - - _CONVERT_STRING(std::string); - _CONVERT_STRING(TfToken); - _CONVERT_STRING(SdfAssetPath); - -#undef _CONVERT_STRING - - return nullptr; -} - -void -GusdPrimWrapper::loadPrimvars( - UsdTimeCode time, - const GT_RefineParms* rparms, - int minUniform, - int minPoint, - int minVertex, - const string& primPath, - GT_AttributeListHandle* vertex, - GT_AttributeListHandle* point, - GT_AttributeListHandle* primitive, - GT_AttributeListHandle* constant, - const GT_DataArrayHandle& remapIndicies ) const -{ - // Primvars will be loaded if they match a provided pattern. - // By default, set the pattern to match only "Cd". Then write - // over this pattern if there is one provided in rparms. - const char* Cd = "Cd"; - UT_String primvarPatternStr(Cd); - - if (rparms) { - rparms->import("usd:primvarPattern", primvarPatternStr); - } - - UT_StringMMPattern primvarPattern; - if (primvarPatternStr) { - primvarPattern.compile(primvarPatternStr); - } - - std::vector authoredPrimvars; - bool hasCdPrimvar = false; - - { - UsdGeomImageable prim = getUsdPrim(); - - UsdGeomPrimvar colorPrimvar = prim.GetPrimvar(GusdTokens->Cd); - if (colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValue()) { - hasCdPrimvar = true; - } - - // It's common for "Cd" to be the only primvar to load. - // In this case, avoid getting all other authored primvars. - if (primvarPatternStr == Cd) { - if (hasCdPrimvar) { - authoredPrimvars.push_back(colorPrimvar); - } else { - // There is no authored "Cd" primvar. - // Try to find "displayColor" instead. - colorPrimvar = prim.GetPrimvar(UsdGeomTokens->primvarsDisplayColor); - if (colorPrimvar && - colorPrimvar.GetAttr().HasAuthoredValue()) { - authoredPrimvars.push_back(colorPrimvar); - } - } - } else if (!primvarPattern.isEmpty()) { - authoredPrimvars = prim.GetAuthoredPrimvars(); - } - } - - // Is it better to sort the attributes and build the attributes all at once. - - for( const UsdGeomPrimvar &primvar : authoredPrimvars ) - { - DBG(cerr << "loadPrimvar " << primvar.GetPrimvarName() << "\t" << primvar.GetTypeName() << "\t" << primvar.GetInterpolation() << endl); - - UT_String name(primvar.GetPrimvarName()); - - // One special case we always handle here is to change - // the name of the USD "displayColor" primvar to "Cd", - // as long as there is not already a "Cd" primvar. - if (!hasCdPrimvar && - primvar.GetName() == UsdGeomTokens->primvarsDisplayColor) { - name = Cd; - } - - // If the name of this primvar doesn't - // match the primvarPattern, skip it. - if (!name.multiMatch(primvarPattern)) { - continue; - } - - // Compute the value before calling convertPrimvarData, so that - // we can distinguish between primvars with no authored value - // and primvars whose authored value can't be converted. - // Note that the 'authored' primvars above are only known to have - // scene description, and still may have no value! - VtValue val; - if (!primvar.ComputeFlattened(&val, time)) { - continue; - } - - GT_DataArrayHandle gtData = convertPrimvarData(primvar, val); - if( !gtData ) - { - TF_WARN( "Failed to convert primvar %s:%s %s.", - primPath.c_str(), - primvar.GetPrimvarName().GetText(), - primvar.GetTypeName().GetAsToken().GetText() ); - continue; - } - -#if SYS_VERSION_FULL_INT >= 0x11050000 - // Encode the USD primvar names into something safe for the Houdini - // geometry attribute name. This allows round tripping of namespaced - // primvars from USD -> Houdini -> USD. - UT_StringHolder attrname = UT_VarEncode::encode(name); -#else - UT_StringHolder attrname = name; -#endif - - const TfToken interpolation = primvar.GetInterpolation(); - - if( interpolation == UsdGeomTokens->vertex || - interpolation == UsdGeomTokens->varying ) - { - if( gtData->entries() < minPoint ) { - TF_WARN( "Not enough values found for primvar: %s:%s. " - "%zd values given for %d points.", - primPath.c_str(), - primvar.GetPrimvarName().GetText(), - gtData->entries(), minPoint ); - } else { - if (remapIndicies) { - gtData = new GT_DAIndirect( remapIndicies, gtData ); - } - if( point ) { - *point = (*point)->addAttribute( attrname.c_str(), gtData, true ); - } - } - } - else if( interpolation == UsdGeomTokens->faceVarying ) - { - if( gtData->entries() < minVertex ) { - TF_WARN( "Not enough values found for primvar: %s:%s. " - "%zd values given for %d vertices.", - primPath.c_str(), - primvar.GetPrimvarName().GetText(), - gtData->entries(), minVertex ); - } else if( vertex ) { - *vertex = (*vertex)->addAttribute( attrname.c_str(), gtData, true ); - } - } - else if( interpolation == UsdGeomTokens->uniform ) - { - if( gtData->entries() < minUniform ) { - TF_WARN( "Not enough values found for primvar: %s:%s. " - "%zd values given for %d faces.", - primPath.c_str(), - primvar.GetPrimvarName().GetText(), - gtData->entries(), minUniform ); - } else if( primitive ) { - *primitive = (*primitive)->addAttribute( attrname.c_str(), gtData, true ); - } - } - else if( interpolation == UsdGeomTokens->constant ) - { - if( constant ) { - *constant = (*constant)->addAttribute( attrname.c_str(), gtData, true ); - } - } - } -} - -/* static */ -GfMatrix4d -GusdPrimWrapper::computeTransform( - const UsdPrim& prim, - UsdTimeCode time, - const UT_Matrix4D& houXform, - const GusdSimpleXformCache& xformCache ) { - - // We need the transform into the prims space. - // If the prim is in a hierarchy that we have written on this frame, - // its transform will be in the xformCache. Otherwise, we can read it - // from the global cache. - // - // The transform cache is necessary because the gobal cache - // will only contain transform that we read from the stage and - // not anything that we have modified. - - UT_Matrix4D primXform; - if( !prim.GetPath().IsPrimPath() ) { - // We can get a invalid prim path if we are computing a transform relative to the parent of the root node. - primXform.identity(); - } - else { - auto it = xformCache.find( prim.GetPath() ); - if( it != xformCache.end() ) { - primXform = it->second; - } - else if( !GusdUSD_XformCache::GetInstance().GetLocalToWorldTransform( - prim, - time, - primXform )) { - TF_WARN( "Failed to get transform for %s.", prim.GetPath().GetText() ); - primXform.identity(); - } - } - return GusdUT_Gf::Cast( houXform ) / GusdUT_Gf::Cast( primXform ); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/primWrapper.h b/third_party/houdini/gusd/primWrapper.h deleted file mode 100644 index 499d2f7c3c..0000000000 --- a/third_party/houdini/gusd/primWrapper.h +++ /dev/null @@ -1,392 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_PRIM_WRAPPER_H -#define GUSD_PRIM_WRAPPER_H - -#include -#include - -#include "api.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usd/timeCode.h" -#include "pxr/usd/usdGeom/imageable.h" - -#include - -#include "GT_Utils.h" -#include "purpose.h" - -class GU_PackedImpl; - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdGT_AttrFilter; -class UsdGeomXformCache; -class GusdContext; - -/// \class GusdPrimWrapper -/// \brief A GT_Primitive that wraps a USD Prim. -/// -/// A GusdPrimWrapper is responsible for copying attribute data between -/// USD and GT. -/// -/// To write USD geometry, the following steps are taken: -/// -/// The ROP uses GusdRefiner to refine the cooked geometry to GT primitive types -/// that have a matching USD type. -/// -/// For each GT primitive we create a primWrapper by calling the defineForWrite -/// method. This will create a usd prim on the current stage. -/// -/// On each frame updateFromGTPrim is called to copy attribtutes from the -/// GT prim to the USD prim. -/// -/// We support: -/// Writing a sequence of frames from one process. -/// Writing each frame of a sequence to a seperate file from a seperate process. -/// Writing each frame of a sequence to a seperate file from one process. -/// -/// When writing all frames to a single file, we try and compress attribtute values. -/// The data we need to do this compression is kept in the prim wrapper. -/// -/// In the rare case where we want to sequentially write a sequence to per frame -/// files, we need the primWrapper to persist across the sequence so we can do -/// the attribute compression. However, we need to create the USD prim on each -/// per frame file. The "redefine" method is used for this. -/// -/// To read USD geometry we start with a GusdGU_PackedUSD prim. A GusdGT_PrimCollect -/// object has been registered to convert these prims to GT_Primitives for drawing -/// in the view port. This object will call the "fullGT" method of the GU prim -/// which in turn calls the "defineForRead" to create a GusdPrimWrapper. These -/// prims can be refined into native GT_Primitives that the viewport can draw. - - -typedef std::map GusdSimpleXformCache; - -class GUSD_API GusdPrimWrapper : public GT_Primitive -{ -public: - - typedef std::function - DefinitionForWriteFunction; - - typedef std::function - DefinitionForReadFunction; - - typedef std::function - GetPrimNameFunction; - - typedef std::function - ResampleArrayFunction; - - /// \brief Given a GT_Primitive, create a USD prim of the proper type. - /// - /// When writing a USD file, we refine the geometry to a set of prims that we - /// can deal with then we call this method on each of those prims. - static GT_PrimitiveHandle - defineForWrite( const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - /// If prim type can generate a useful name for a prim, sets primName - /// and returns true. - /// So far only F3D volumes do this. They can derive a name from meta - /// data stored in the f3d file. - static bool - getPrimName( const GT_PrimitiveHandle &sourcePrim, - std::string &primName ); - - // When we write USD for the given type, we will use a name like $USDNAME_0. - // where USDNAME is the name registered for this type - static const char* - getUsdName( int gtPrimId ); - - // When we USD for an object that is marked as a group type, we write - // the object and then all its children. - static bool - isGroupType( int gtPrimId ); - - /// \brief Given a USD prim, create a GusdPrimWrapper of the proper type. - /// - /// When reading a USD file, we call this function to create a Gusd_GTPrimitive - /// for each USD prim, we then refine that to something that can be - /// used in a detail. - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - - /// \brief Is this gt prim a point instancer? - /// - /// This is used to know if we need to write the instance prototypes. - static bool - isPointInstancerPrim(const GT_PrimitiveHandle& prim, - const GusdContext& ctxt); - - /// Register function for creating new USD prims from GT_Primitives and, optionally, - /// a function for giving these prims a name. - static bool registerPrimDefinitionFuncForWrite(int gtPrimId, - DefinitionForWriteFunction function, - GetPrimNameFunction getNameFunction = NULL, - bool isGroupType = false, - const char* usdName = NULL ); - - /// Register function for creating new GusdPrimWrappers from USD prim. - static bool registerPrimDefinitionFuncForRead(const TfToken& usdTypeName, - DefinitionForReadFunction function); - - /// Return true is the give prim can be supported directly in USD. This - /// is used by the refiner to know when to stop refining. - static bool isGTPrimSupported(const GT_PrimitiveHandle& prim); - - GusdPrimWrapper(); - GusdPrimWrapper( const UsdTimeCode &time, const GusdPurposeSet &purposes ); - GusdPrimWrapper( const GusdPrimWrapper &in ); - virtual ~GusdPrimWrapper(); - - /// Return true if the underlying USD prim is valid - virtual bool isValid() const; - - virtual const UsdGeomImageable getUsdPrim() const = 0; - - virtual bool unpack( - GU_Detail& gdr, - const UT_StringRef& fileName, - const SdfPath& primPath, - const UT_Matrix4D& xform, - fpreal frame, - const char * viewportLod, - GusdPurposeSet purposes ); - - /// \brief Create a new USD prim to match GT primitive. - /// - /// When writing per frame USD files, we need to recreate the stage - /// and all the primitives on it each frame. However, there is some - /// data we want to persist across frames. So we keep the GusdPrimWrappers - /// and ask them to redefine their USD prims on each frame. - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ); - - /// Fill a USD prim's attribute samples for a frame from the - /// attributes in a GT primitive. - /// - /// If \p sourcePrim is an instance, \p localXform is the instance transform - /// otherwise it is the primitive transform from the prim. - virtual bool updateFromGTPrim( - const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& houXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache ); - - /// Add a sample just before the current time that invises this prim. - /// For points and instances this means writing a empty point attribute. - /// Other prims set their visibility flag. - virtual void addLeadingBookend( double curFrame ); - - /// Add a sample at the current frame, invising this from. - virtual void addTrailingBookend( double curFrame ); - - /// Keep track of the visibility state of the prim for book marks. - void markVisible( bool in ) { m_visible = in; } - bool isVisible() const { return m_visible; } - - virtual void setVisibility(const TfToken& visibility, UsdTimeCode time); - - static GT_DataArrayHandle convertPrimvarData( - const UsdGeomPrimvar& primvar, - UsdTimeCode time ); - - static GT_DataArrayHandle convertPrimvarData( - const UsdGeomPrimvar& primvar, - const VtValue& val); - - /// Load primvars for prim from USD. - /// remapIndicies is used to expand curve primvars into point attributes if - /// needed. - void loadPrimvars( - UsdTimeCode time, - const GT_RefineParms* rparms, - int minUniform, - int minPoint, - int minVertex, - const std::string& primPath, - GT_AttributeListHandle* vertex, - GT_AttributeListHandle* point, - GT_AttributeListHandle* primitive, - GT_AttributeListHandle* constant, - const GT_DataArrayHandle& remapIndicies = GT_DataArrayHandle() ) const; - - // Map to translate from GT_Owner enums to USD interpolation type tokens - static std::map s_ownerToUsdInterp; - static std::map s_ownerToUsdInterpCurve; - -protected: - - /// Look for "visible" attribute on sourcePrim. If it doesn't exist - /// set a visibility sample based on isVisible() - void updateVisibilityFromGTPrim( const GT_PrimitiveHandle& sourcePrim, - UsdTimeCode time, - bool forceWrite = true ); - - /// Look for a "usdactive" attribute on sourcePrim. UsdPrim::SetActive - /// based on this value. If attribute doesn't exist, do nothing. - void updateActiveFromGTPrim( const GT_PrimitiveHandle& sourcePrim, - UsdTimeCode time ); - - void updateTransformFromGTPrim( const GfMatrix4d &xform, UsdTimeCode time, bool force ); - - bool updateAttributeFromGTPrim( GT_Owner owner, - const std::string& name, - const GT_DataArrayHandle& houAttr, - UsdAttribute& usdAttr, - UsdTimeCode time ); - - bool updatePrimvarFromGTPrim( - const TfToken& name, - const GT_Owner& owner, - const TfToken& interpolation, - UsdTimeCode time, - const GT_DataArrayHandle& data ); - - /// Write primvar values from a GT attribute list to USD. - bool updatePrimvarFromGTPrim( const GT_AttributeListHandle& gtAttrs, - const GusdGT_AttrFilter& primvarFilter, - const TfToken& interpolation, - UsdTimeCode time ); - - void clearCaches(); - - /// Compute a USD transform from a Houdini transform. - /// - /// \p houXform is the transform from world to the prim's space in Houdini. - /// This includes the object node transformation and the transform of any - /// containing packed prim. - /// - /// \p xformCache is a map of the transforms of any groups that have been - /// written on the current frame. - static GfMatrix4d computeTransform( - const UsdPrim& prim, - UsdTimeCode time, - const UT_Matrix4D& houXform, - const GusdSimpleXformCache& xformCache ); - -protected: - - UsdTimeCode m_time; - GusdPurposeSet m_purposes; - - bool m_visible; - - ////////////// - // Support for collapsing transform values across frames - - GfMatrix4d m_xformCache; - UsdTimeCode m_lastXformSet; - UsdTimeCode m_lastXformCompared; - - ////////////// - // Support from collapsing attribute values across frames - - struct AttrLastValueEntry { - - AttrLastValueEntry( const UsdTimeCode &time, GT_DataArrayHandle data_ ) { - data = data_; - lastSet = time; - lastCompared = time; - } - - GT_DataArrayHandle data; - UsdTimeCode lastSet; - UsdTimeCode lastCompared; - }; - - typedef std::pair AttrLastValueKeyType; - typedef UT_Map AttrLastValueDict; - - mutable AttrLastValueDict m_lastAttrValueDict; - - ////////////// - -private: - - struct GTTypeInfo { - DefinitionForWriteFunction writeFunc; - GetPrimNameFunction primNameFunc; - bool isGroupType; - const char * templateName; - - GTTypeInfo() : - writeFunc( NULL ), - primNameFunc( NULL ), - isGroupType( false ), - templateName(NULL) {} - GTTypeInfo( - DefinitionForWriteFunction writeFunc_, - GetPrimNameFunction primNameFunc_, - bool isGroupType_, - const char * templateName_ ) : - writeFunc( writeFunc_ ), - primNameFunc( primNameFunc_ ), - isGroupType( isGroupType_ ), - templateName( templateName_ ) {} - }; - - struct TfTokenHashCmp { - static bool equal(const TfToken& a, const TfToken& b) - { return a == b; } - - static size_t hash(const TfToken& key) - { return key.Hash(); } - }; - - typedef UT_Map GTTypeInfoMap; - typedef UT_Set GTTypeSet; - typedef UT_ConcurrentHashMap< - TfToken, DefinitionForReadFunction, TfTokenHashCmp> - USDTypeToDefineFuncMap; - - static GTTypeInfoMap s_gtTypeInfoMap; - static USDTypeToDefineFuncMap s_usdTypeToFuncMap; - static GTTypeSet s_supportedNativeGTTypes; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_PRIM_WRAPPER_H diff --git a/third_party/houdini/gusd/purpose.cpp b/third_party/houdini/gusd/purpose.cpp deleted file mode 100644 index 23851a60f7..0000000000 --- a/third_party/houdini/gusd/purpose.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "purpose.h" -#include "USD_Utils.h" - -#include "pxr/usd/usdGeom/imageable.h" - -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -GusdPurposeSet -GusdPurposeSetFromArray(const UT_StringArray& purposes) -{ - int p = GUSD_PURPOSE_NONE; - for(const auto& s : purposes) - p |= GusdPurposeSetFromName(s); - return GusdPurposeSet(p); -} - - -GusdPurposeSet -GusdPurposeSetFromArray(const TfTokenVector& purposes) -{ - int p = GUSD_PURPOSE_NONE; - for(const auto& t : purposes) - p |= GusdPurposeSetFromName(t); - return GusdPurposeSet(p); -} - - -TfTokenVector -GusdPurposeSetToTokens(GusdPurposeSet purposes) -{ - TfTokenVector tokens; - if(purposes&GUSD_PURPOSE_DEFAULT) - tokens.push_back(UsdGeomTokens->default_); - if(purposes&GUSD_PURPOSE_PROXY) - tokens.push_back(UsdGeomTokens->proxy); - if(purposes&GUSD_PURPOSE_RENDER) - tokens.push_back(UsdGeomTokens->render); - if(purposes&GUSD_PURPOSE_GUIDE) - tokens.push_back(UsdGeomTokens->guide); - return tokens; -} - - -UT_StringArray -GusdPurposeSetToStrings(GusdPurposeSet purposes) -{ - UT_StringArray names; - if(purposes&GUSD_PURPOSE_DEFAULT) - names.append(GusdUSD_Utils::TokenToStringHolder( - UsdGeomTokens->default_)); - if(purposes&GUSD_PURPOSE_PROXY) - names.append(GusdUSD_Utils::TokenToStringHolder( - UsdGeomTokens->proxy)); - if(purposes&GUSD_PURPOSE_RENDER) - names.append(GusdUSD_Utils::TokenToStringHolder( - UsdGeomTokens->render)); - if(purposes&GUSD_PURPOSE_GUIDE) - names.append(GusdUSD_Utils::TokenToStringHolder( - UsdGeomTokens->guide)); - return names; -} - - -GusdPurposeSet -GusdPurposeSetFromMask(const char* mask) -{ - int p = GUSD_PURPOSE_NONE; - - if(UTisstring(mask)) { - UT_StringMMPattern pat; - pat.compile(mask); - - for(const auto& t : UsdGeomImageable::GetOrderedPurposeTokens()) { - if(UT_String(t.GetText()).multiMatch(pat)) { - p |= GusdPurposeSetFromName(t); - } - } - } - return GusdPurposeSet(p); -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/purpose.h b/third_party/houdini/gusd/purpose.h deleted file mode 100644 index caeeb22837..0000000000 --- a/third_party/houdini/gusd/purpose.h +++ /dev/null @@ -1,115 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_PURPOSE_H -#define GUSD_PURPOSE_H - -#include -#include - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/tokens.h" - -#include "api.h" - - -PXR_NAMESPACE_OPEN_SCOPE - - -enum GusdPurposeSet { - GUSD_PURPOSE_NONE = 0x00, - GUSD_PURPOSE_DEFAULT = 0x01, - GUSD_PURPOSE_PROXY = 0x02, - GUSD_PURPOSE_RENDER = 0x04, - GUSD_PURPOSE_GUIDE = 0x08, -}; - - -GUSD_API -inline GusdPurposeSet -GusdPurposeSetFromName(const UT_StringRef& name) -{ - if(name == UsdGeomTokens->default_) - return GUSD_PURPOSE_DEFAULT; - else if(name == UsdGeomTokens->proxy) - return GUSD_PURPOSE_PROXY; - else if(name == UsdGeomTokens->render) - return GUSD_PURPOSE_RENDER; - else if(name == UsdGeomTokens->guide) - return GUSD_PURPOSE_GUIDE; - return GUSD_PURPOSE_NONE; -} - - -GUSD_API -inline GusdPurposeSet -GusdPurposeSetFromName(const TfToken& name) -{ - if(name == UsdGeomTokens->default_) - return GUSD_PURPOSE_DEFAULT; - else if(name == UsdGeomTokens->proxy) - return GUSD_PURPOSE_PROXY; - else if(name == UsdGeomTokens->render) - return GUSD_PURPOSE_RENDER; - else if(name == UsdGeomTokens->guide) - return GUSD_PURPOSE_GUIDE; - return GUSD_PURPOSE_NONE; -} - - -GUSD_API -inline bool -GusdPurposeInSet( const TfToken& name, GusdPurposeSet set ) -{ - return set&GusdPurposeSetFromName(name); -} - - -/// Create a purpose set from an array of purpose strings. -/// @{ -GUSD_API -GusdPurposeSet GusdPurposeSetFromArray(const UT_StringArray& purposes); - -GUSD_API -GusdPurposeSet GusdPurposeSetFromArray(const TfTokenVector& purposes); -/// @} - - -/// Extract an array of tokens for @a purposes. -GUSD_API -TfTokenVector GusdPurposeSetToTokens(GusdPurposeSet purposes); - - -/// Extract an array of strings for @a purposes. -GUSD_API -UT_StringArray GusdPurposeSetToStrings(GusdPurposeSet purposes); - - -/// Return a purpose set from a string providing a mask of purposes. -GUSD_API -GusdPurposeSet GusdPurposeSetFromMask(const char* mask); - - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_PURPOSE_H diff --git a/third_party/houdini/gusd/refiner.cpp b/third_party/houdini/gusd/refiner.cpp deleted file mode 100644 index cd24c38d78..0000000000 --- a/third_party/houdini/gusd/refiner.cpp +++ /dev/null @@ -1,891 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "refiner.h" - -#include "GT_OldPointInstancer.h" -#include "GT_PackedUSD.h" -#include "GT_PointInstancer.h" -#include "GU_USD.h" -#include "primWrapper.h" -#include "stageCache.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cout; -using std::cerr; -using std::endl; -using std::string; -using std::map; -using std::pair; -using std::vector; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - - -TF_DEFINE_PRIVATE_TOKENS( - _tokens, - (PointInstancer) - (PxPointInstancer) -); - - -namespace { - -GT_DataArrayHandle newDataArray( GT_Storage storage, GT_Size size, - int tupleSize, GT_Type typeInfo ); -void copyDataArrayItem( GT_DataArrayHandle dstData, GT_DataArrayHandle srcData, - GT_Offset dstOffset, GT_Offset srcOffset ); -GT_AttributeListHandle findAndAddStringAttribute( GT_AttributeListHandle attrs, - const std::string& attrName, - const GT_PrimitiveHandle& gtPrim); -} - -GusdRefiner::GusdRefiner( - GusdRefinerCollector& collector, - const SdfPath& pathPrefix, - const string& pathAttrName, - const UT_Matrix4D& localToWorldXform ) - : m_collector( collector ) - , m_pathPrefix( pathPrefix ) - , m_pathAttrName( pathAttrName ) - , m_localToWorldXform( localToWorldXform ) - , m_refinePackedPrims( false ) - , m_useUSDIntrinsicNames( true ) - , m_forceGroupTopPackedPrim( false ) - , m_isTopLevel( true ) - , m_buildPointInstancer( false ) - , m_buildPrototypes( false ) -{ -} - -void -GusdRefiner::refineDetail( - const GU_ConstDetailHandle& detail, - const GT_RefineParms& refineParms ) -{ - m_refineParms = refineParms; - - GU_DetailHandleAutoReadLock detailLock( detail ); - - GA_ROHandleS partitionAttr; - if( !m_pathAttrName.empty() ) { - partitionAttr = - detailLock->findStringTuple( - GA_ATTRIB_PRIMITIVE, - m_pathAttrName.c_str() ); - } - - std::vector partitions; - GA_Range primRange = detailLock->getPrimitiveRange(); - if(!partitionAttr.isValid() || primRange.getEntries() == 0) { - partitions.push_back(primRange); - } - else { - - typedef UT_Map PrimPartitionMap; - - PrimPartitionMap partitionMap; - for(GA_Iterator offsetIt(primRange); !offsetIt.atEnd(); ++offsetIt) { - GA_StringIndexType idx = partitionAttr.getIndex(offsetIt.getOffset()); - partitionMap[idx].append(offsetIt.getOffset()); - } - - partitions.reserve(partitionMap.size()); - for(PrimPartitionMap::const_iterator mapIt=partitionMap.begin(); - mapIt != partitionMap.end(); ++mapIt) { - partitions.push_back(GA_Range(detailLock->getPrimitiveMap(), - mapIt->second)); - } - } - - // Refine each geometry partition to prims that can be written to USD. - // The results are accumulated in buffer in the refiner. - for(vector::const_iterator rangeIt=partitions.begin(); - rangeIt != partitions.end(); ++rangeIt) { - - const GA_Range& range = *rangeIt; - - // Before we refine we need to decide if we want to coalesce packed - // fragments. We will coalesce unless we are writing transform - // overlays and the fragment has a name. - - GU_DetailHandleAutoReadLock detailLock( detail ); - - bool overlayTransforms = false; - GA_AttributeOwner order[] = { GA_ATTRIB_PRIMITIVE, GA_ATTRIB_DETAIL }; - const GA_Attribute *overTransformsAttr = - detailLock->findAttribute( GUSD_OVERTRANSFORMS_ATTR, order, 2 ); - if( overTransformsAttr ) { - GA_ROHandleI h( overTransformsAttr ); - if( overTransformsAttr->getOwner() == GA_ATTRIB_DETAIL ) { - overlayTransforms = h.get( GA_Offset(0) ); - } - else { - // assume all prims in the range have the same usdovertransforms - // attribute value - overlayTransforms = h.get( range.begin().getOffset() ); - } - } - if( overlayTransforms ) { - // prims must be named to overlay transforms - const GA_Attribute *primPathAttr = - detailLock->findPrimitiveAttribute( GUSD_PRIMPATH_ATTR ); - if( !primPathAttr ) { - overlayTransforms = false; - } - } - - GT_RefineParms newRefineParms( refineParms ); - newRefineParms.setCoalesceFragments( m_refinePackedPrims && !overlayTransforms ); - - GT_PrimitiveHandle detailPrim - = GT_GEODetail::makeDetail( detail, &range); - if(detailPrim) { - detailPrim->refine(*this, &newRefineParms ); - } - } -} - -const GusdRefiner::GprimArray& -GusdRefiner::finish() { - - m_collector.finish( *this ); - return m_collector.m_gprims; -} - -std::string -GusdRefiner::createPrimPath( const std::string& primName) { - std::string primPath; - if( !primName.empty() && primName[0] == '/' ) { - // Use an explicit absolute path - primPath = primName; - } - else { - // add prefix to relative path - primPath = m_pathPrefix.GetString(); - if( !primName.empty() ) { - if( primPath.empty() || primPath.back() != '/' ) { - primPath += "/"; - } - primPath += primName; - } - else if( !primPath.empty() && primPath.back() != '/' ) - primPath += '/'; - } - - // USD is persnikity about having a leading slash - if( primPath[0] != '/' ) { - primPath = "/" + primPath; - } - return primPath; -} - -void -GusdRefiner::addPrimitive( const GT_PrimitiveHandle& gtPrimIn ) -{ - if(!gtPrimIn) { - TF_WARN("Attempted to add invalid prim"); - return; - } - GT_PrimitiveHandle gtPrim = gtPrimIn; // copy to a non-const handle - int primType = gtPrim->getPrimitiveType(); - DBG( cerr << "GusdRefiner::addPrimitive, " << gtPrim->className() << endl ); - - string primName; - // Types can register a function to provide a prim name. - // Volumes do this to return a name stored in the f3d file. This is - // important for consistant cluster naming. - string n; - if( GusdPrimWrapper::getPrimName( gtPrim, n )) { - primName = n; - } - - bool refinePackedPrims = m_refinePackedPrims; - bool primHasNameAttr = false; - if( primName.empty() ) { - - GT_AttributeListHandle primAttrs; - if( primType == GT_GEO_PACKED ) { - primAttrs = UTverify_cast(gtPrim.get())->getInstanceAttributes(); - - } - if( !primAttrs ) { - primAttrs = gtPrim->getUniformAttributes(); - } - if( !primAttrs ) { - primAttrs = gtPrim->getDetailAttributes(); - } - - GT_DataArrayHandle dah; - if( primAttrs ) { - dah = primAttrs->get( m_pathAttrName.c_str() ); - } - - if( dah && dah->isValid() ) { - const char *s = dah->getS(0); - if( s != NULL ) { - primName = s; - primHasNameAttr = true; - } - } - if( primAttrs ) { - GT_DataArrayHandle overXformsAttr = primAttrs->get( GUSD_OVERTRANSFORMS_ATTR ); - if( overXformsAttr ) { - if( overXformsAttr->getI32(0) != 0 ) { - refinePackedPrims = false; - } - } - } - } - - - // The following is only necessary for point instancers. Prototypes - // can't be point instancers. - if (!m_buildPrototypes) { - - // Check per prim if we are building a point instancer. This may cause - // problems for point instancers with discontiguous packed prims. - bool localBuildPointInstancer = false; - // If we have imported USD geometry get the type to see if it is a - // point instancer we need to overlay. - if(auto packedUSD = dynamic_cast( gtPrim.get() )) { - if(packedUSD->getFileName()) { - - // Get the usd src prim path used for point instancers - const SdfPath& instancerPrimPath = - packedUSD->getSrcPrimPath(); - - GusdStageCacheReader cache; - if(UsdPrim prim = cache.GetPrimWithVariants( - packedUSD->getFileName(), instancerPrimPath).first) { - // Get the type name of the usd file to overlay - m_pointInstancerType = prim.GetTypeName(); - - // Make sure to set buildPointInstancer to true if we are overlaying a - // point instancer - if (m_pointInstancerType == _tokens->PointInstancer || - m_pointInstancerType == _tokens->PxPointInstancer) { - localBuildPointInstancer = true; - } - } - } - } - // If we find either an instancepath or usdinstancepath attribute, build a - // point instancer. - GT_Owner owner; - if(gtPrim->findAttribute("instancepath", owner, 0) || - gtPrim->findAttribute("usdinstancepath", owner, 0) ) { - localBuildPointInstancer = true; - } - - if (m_buildPointInstancer || localBuildPointInstancer) { - // If we are building point instancer, stash prims that can be - // point instanced. Build the point instancer in the finish method. - - // If given a prim path, pass it to the collector for a custom - // usd scope. Otherwise pass an empty SdfPath. - SdfPath instancerPrimPath; - if( !primName.empty() ) { - instancerPrimPath = SdfPath(createPrimPath(primName)); - } - - if( auto packedUSD = dynamic_cast( gtPrim.get() )) { - // Point instancer from packed usd - instancerPrimPath = instancerPrimPath.IsEmpty() ? packedUSD->getSrcPrimPath() : instancerPrimPath; - m_collector.addInstPrim( instancerPrimPath, gtPrim ); - return; - } - else if( gtPrim->getPrimitiveType() == GT_PRIM_INSTANCE ) { - // Point instancer from packed primitives - - // A GT_PrimInstance can container more than one instance. Create - // an entry for each. - auto instPrim = UTverify_cast( gtPrim.get() ); - - // TODO: If we put all geometry packed prims here, then we break - // grouping prims for purpose - for( size_t i = 0; i < instPrim->entries(); ++i ) { - m_collector.addInstPrim( instancerPrimPath, gtPrim, i ); - } - return; - } - - if( primType == GT_PRIM_PARTICLE || primType == GT_PRIM_POINT_MESH ) { - // Point instancer from points with instancepath attribute - - // Check for the usdprototypespath attribute in case it is not - // a point or primitivie attribute. - GT_AttributeListHandle uniformAttrs = gtPrim->getUniformAttributes(); - uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypespath", gtPrim); - - // Find and add a custom prototype scope attribute. - uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypesscope", gtPrim); - - gtPrim = new GusdGT_PointInstancer( - gtPrim->getPointAttributes(), - uniformAttrs ); - primType = gtPrim->getPrimitiveType(); - } - } - } - // We must refine packed prims that don't have a name - if( !primHasNameAttr && !refinePackedPrims ) { - refinePackedPrims = true; - } - - if( primName.empty() && - gtPrim->getPrimitiveType() == GusdGT_PackedUSD::getStaticPrimitiveType() ) { - - auto packedUsdPrim = UTverify_cast(gtPrim.get()); - SdfPath path = packedUsdPrim->getPrimPath().StripAllVariantSelections(); - if( m_useUSDIntrinsicNames ) { - primName = path.GetString(); - } - else { - primName = path.GetName(); - } - - // We want prototypes to be children of the point instancer, so we make - // the usd path a relative scope of just the usd prim name - if ( m_buildPrototypes && !primName.empty() && primName[0] == '/' ) { - size_t idx = primName.find_last_of("/"); - primName = primName.substr(idx+1); - } - } - // If the prim path was not explicitly set, try to come up with a reasonable - // default. - bool addNumericSuffix = false; - if( primName.empty() ) { - - int t = gtPrim->getPrimitiveType(); - if( t == GT_PRIM_POINT_MESH || t == GT_PRIM_PARTICLE ) - primName = "points"; - else if( t == GT_PRIM_POLYGON_MESH || t == GT_PRIM_SUBDIVISION_MESH ) - primName = "mesh"; - else if( t == GT_PRIM_CURVE_MESH ) - primName = "curve"; - else if( t == GusdGT_PointInstancer::getStaticPrimitiveType() ) - primName = "instances"; - else if(const char *n = GusdPrimWrapper::getUsdName( t )) - primName = n; - else - primName = "obj"; - - if( !primName.empty() ) { - addNumericSuffix = true; - } - } - - string primPath = createPrimPath(primName); - - TfToken purpose = UsdGeomTokens->default_; - { - GT_Owner own = GT_OWNER_PRIMITIVE; - GT_DataArrayHandle dah = gtPrim->findAttribute( GUSD_PURPOSE_ATTR, own, 0 ); - if( dah && dah->isValid() ) { - purpose = TfToken(dah->getS(0)); - } - } - - if( primType == GT_PRIM_INSTANCE ) { - - auto inst = UTverify_cast(gtPrim.get()); - const GT_PrimitiveHandle geometry = inst->geometry(); - - if ( geometry->getPrimitiveType() == GT_GEO_PACKED ) { - - // If we find a packed prim that has a name, this become a group (xform) in - // USD. If it doesn't have a name, we just accumulate the transform and recurse. - - auto packedGeo = UTverify_cast(geometry.get()); - for( GT_Size i = 0; i < inst->transforms()->entries(); ++i ) { - - UT_Matrix4D m; - inst->transforms()->get(i)->getMatrix(m); - - UT_Matrix4D newCtm = m_localToWorldXform; - newCtm = m* m_localToWorldXform; - - SdfPath newPath = m_pathPrefix; - bool recurse = true; - - if( primHasNameAttr || - ( m_forceGroupTopPackedPrim && m_isTopLevel )) { - - // m_forceGroupTopPackedPrim is used when we are writing instance - // prototypes. We need to add instance id attributes to the top - // level group. Here we make sure that we create that group, even - // if the user hasn't named it. - - newPath = m_collector.add( SdfPath(primPath), - addNumericSuffix, - gtPrim, - newCtm, - purpose, - m_writeCtrlFlags ); - - // If we are just writing transforms and encounter a packed prim, we - // just want to write it's transform and not refine it further. - recurse = refinePackedPrims; - } - - if( recurse ) { - GusdRefiner childRefiner( - m_collector, - newPath, - m_pathAttrName, - newCtm ); - - childRefiner.m_refinePackedPrims = refinePackedPrims; - childRefiner.m_forceGroupTopPackedPrim = m_forceGroupTopPackedPrim; - childRefiner.m_isTopLevel = false; - - childRefiner.m_writeCtrlFlags = m_writeCtrlFlags; - childRefiner.m_writeCtrlFlags.update( geometry ); - -#if UT_MAJOR_VERSION_INT >= 16 - childRefiner.refineDetail( packedGeo->getPackedDetail(), m_refineParms ); -#else - childRefiner.refineDetail( packedGeo->getPrim()->getPackedDetail(), m_refineParms ); -#endif - } - } - return; - } - } - - if( (primType != GT_GEO_PACKED || !refinePackedPrims) && - GusdPrimWrapper::isGTPrimSupported(gtPrim) ) { - - UT_Matrix4D m; - if( primType == GT_GEO_PACKED ) { - // packed fragment - UTverify_cast(gtPrim.get())->getFullTransform()->getMatrix(m); - } - else { - gtPrim->getPrimitiveTransform()->getMatrix(m); - } - - UT_Matrix4D newCtm = m_localToWorldXform; - newCtm = m* m_localToWorldXform; - - m_collector.add( SdfPath(primPath), - addNumericSuffix, - gtPrim, - newCtm, - purpose, - m_writeCtrlFlags ); - } - else { - gtPrim->refine( *this, &m_refineParms ); - } -} - -SdfPath -GusdRefinerCollector::add( - const SdfPath& path, - bool addNumericSuffix, - GT_PrimitiveHandle prim, - const UT_Matrix4D& xform, - const TfToken & purpose, - const GusdWriteCtrlFlags& writeCtrlFlagsIn ) -{ - // Update the write control flags from the attributes on the prim - GusdWriteCtrlFlags writeCtrlFlags = writeCtrlFlagsIn; - - writeCtrlFlags.update( prim ); - - // If addNumericSuffix is true, use the name directly unless there - // is a conflict. Otherwise add a numeric suffix to keep names unique. - int64 count = 0; - auto it = m_names.find( path ); - if( it == m_names.end() ) { - // Name has not been used before - m_names[path] = NameInfo(m_gprims.size() - 1); - if( !addNumericSuffix ) { - m_gprims.push_back(GprimArrayEntry(path,prim,xform,purpose,writeCtrlFlags)); - return path; - } - } - else { - if( !addNumericSuffix && it->second.count == 0 ) { - - for( GprimArray::iterator pit = m_gprims.begin(); pit != m_gprims.end(); ++pit ) { - if( pit->path == path ) { - // We have a name conflict. Go back and change the - // name of the first prim to use this name. - pit->path = SdfPath( pit->path.GetString() + "_0" ); - } - else if( TfStringStartsWith( pit->path.GetString(), path.GetString() ) ) { - pit->path = SdfPath( path.GetString() + "_0" + pit->path.GetString().substr( path.GetString().length() )); - } - } - } - ++it->second.count; - count = it->second.count; - } - - // Add a numeric suffix to get a unique name - SdfPath newPath( TfStringPrintf("%s_%" SYS_PRId64, path.GetText(), count)); - - m_gprims.push_back(GprimArrayEntry(newPath,prim,xform,purpose,writeCtrlFlags)); - return newPath; -} - -void -GusdRefinerCollector::finish( GusdRefiner& refiner ) -{ - // If we are building a point instancer, as packed prims are added they - // have been collected into m_instancePrims sorted by "srcPrimPath". - // Build a GT_PointPrimMesh for each entry in this map. - - for( auto const & instancerMapIt : m_instancePrims ) { - - const SdfPath &instancerPrimPath = instancerMapIt.first; - const vector& primArray = instancerMapIt.second; - - size_t nprims = primArray.size(); - DBG( cerr << "Create point instancers for \"" << instancerPrimPath - << "\" with " << nprims << " entries" << endl); - - GT_AttributeListHandle pAttrs = new GT_AttributeList( new GT_AttributeMap() ); - - // Allocate storage for all the attributes we want to copy. - - // Assume all entries in the primArray have the same set of attributes. - // (They all came from the same detail). - const GT_PrimitiveHandle& prim = primArray[0].prim; - - auto instPtAttrs = prim->getPointAttributes(); - GT_Real32Array* pivotArray = nullptr; - - if( instPtAttrs ) { - - for( size_t j = 0; j < instPtAttrs->entries(); ++j ) { - - // Filter attributes that begin with an underscore - const char *n = instPtAttrs->getName(j); - if( !n || strlen( n ) < 1 || n[0] == '_' ) { - continue; - } - GT_Storage storage = instPtAttrs->get( j )->getStorage(); - GT_Size tupleSize = instPtAttrs->get( j )->getTupleSize(); - GT_Type typeInfo = instPtAttrs->get( j )->getTypeInfo(); - pAttrs = pAttrs->addAttribute( - n, - newDataArray( storage, nprims, tupleSize, typeInfo ), - true ); - } - } - bool hasInstanceIndices = false; - if(auto packedUSD = dynamic_cast( prim.get() )) { - if (packedUSD->getInstanceIndex() >= 0) { - hasInstanceIndices = true; - } - } - - if( auto instUniAttrs = prim->getUniformAttributes() ) { - - for( size_t j = 0; j < instUniAttrs->entries(); ++j ) { - - // Filter out attributes that begin with an underscore and - // usdprimpath (usdprimpath on instances will confuse the - // instancerWrapper). - - const char *n = instUniAttrs->getName(j); - if( !n || strlen( n ) < 1 || n[0] == '_' || - string( n ) == GUSD_PRIMPATH_ATTR ) { - continue; - } - if( !pAttrs->hasName( n ) ) { - - GT_Storage storage = instUniAttrs->get( j )->getStorage(); - GT_Size tupleSize = instUniAttrs->get( j )->getTupleSize(); - GT_Type typeInfo = instUniAttrs->get( j )->getTypeInfo(); - pAttrs = pAttrs->addAttribute( - n, - newDataArray( storage, nprims, tupleSize, typeInfo ), - true ); - } - } - } - - - // Allocate xform attribute used to communicate about the instances - // with the instancerWrapper. - GT_Real64Array* xformArray = new GT_Real64Array(nprims, 16); - bool foundValidTransform = false; - GT_Int64Array* instanceIndices = hasInstanceIndices ? new GT_Int64Array(nprims, 1) : NULL; - - for( size_t primIndex = 0; primIndex < nprims; ++primIndex ) { - - const GT_PrimitiveHandle& prim = primArray[primIndex].prim; - - // copy point attribute data from the src prims into prims for - // the point instancer. - auto instPtAttrs = prim->getPointAttributes(); - if( instPtAttrs ) { - - for( size_t attrIndex = 0; attrIndex < instPtAttrs->entries(); ++attrIndex ) { - - const char *n = instPtAttrs->getName(attrIndex); - if( !n || strlen( n ) < 1 || n[0] == '_' ) { - continue; - } - - auto srcData = instPtAttrs->get( attrIndex ); - if( auto dstData = pAttrs->get( n ) ) { - copyDataArrayItem( dstData, srcData, primIndex, primArray[primIndex].index ); - } - } - if( pivotArray ) { - if( auto pos = instPtAttrs->get( "P" ) ) { - pivotArray->set( pos->getF32( 0, 0 ), primIndex, 0 ); - pivotArray->set( pos->getF32( 0, 1 ), primIndex, 1 ); - pivotArray->set( pos->getF32( 0, 2 ), primIndex, 2 ); - } - } - if (hasInstanceIndices) { - if(auto packedUSD = dynamic_cast( prim.get() )) { - exint index = packedUSD->getInstanceIndex(); - if (index >= 0) { - instanceIndices->setTuple(&index, primIndex); - } - } - } - } - - // copy uniform attribute data from the src prims into prims for - // the point instancer. - auto instUniAttrs = prim->getUniformAttributes(); - if( instUniAttrs ) { - - for( size_t attrIndex = 0; attrIndex < instUniAttrs->entries(); ++attrIndex ) { - - const char *n = instUniAttrs->getName(attrIndex); - if( !n || strlen( n ) < 1 || n[0] == '_' || string(n) == GUSD_PRIMPATH_ATTR ) { - continue; - } - - auto srcData = instUniAttrs->get( attrIndex ); - if( auto dstData = pAttrs->get( n ) ) { - copyDataArrayItem( dstData, srcData, primIndex, primArray[primIndex].index ); - } - } - } - - // For USD packed prims or geometry packed prims with a usdprimpath - // attributes, get the transforms and stuff them into arrays that - // can be passed as attributes to the instancerWrapper. - if( auto packedUSD = dynamic_cast( prim.get() )) { - - const SdfPath primpath(packedUSD->getPrimPath()); - - UT_Matrix4D xform; - packedUSD->getPrimitiveTransform()->getMatrix(xform); - - xformArray->setTuple(xform.data(), primIndex ); - - foundValidTransform = true; - } - else if( auto instance = dynamic_cast( prim.get() )) { - - UT_Matrix4D xform; - instance->transforms()->get(primArray[primIndex].index)->getMatrix( xform ); - xformArray->setTuple(xform.data(), primIndex ); - foundValidTransform = true; - } - } - - if( foundValidTransform ) { - pAttrs = pAttrs->addAttribute( "__instancetransform", xformArray, true ); - } - - if ( hasInstanceIndices ) { - pAttrs = pAttrs->addAttribute( "__instanceindex", instanceIndices, true ); - } - - // If the instance prims have a "srcPrimPath" intrinsic (typically - // because we are doing an overlay), set the "usdprimpath" attribute on - // the point mesh prim so that the point instancer prim gets named properly. - GT_AttributeListHandle uniformAttrs; - - if( !instancerPrimPath.IsEmpty() ) { - uniformAttrs = new GT_AttributeList( new GT_AttributeMap() ); - auto primPathArray = new GT_DAIndexedString(1); - primPathArray->setString( 0, 0, instancerPrimPath.GetText() ); - uniformAttrs = uniformAttrs->addAttribute( GUSD_PRIMPATH_ATTR, primPathArray, true ); - } - - // Check for the usdprototypespath attribute in case it is not - // a point or primitivie attribute. - uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypespath", prim); - - // Find and add a custom prototype scope attribute. - uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypesscope", prim); - - // Add the refined point instancer. If we are overlaying an old point - // instancer make sure to use the old type (temporary). - if (refiner.m_pointInstancerType == _tokens->PxPointInstancer) { - refiner.addPrimitive( new GusdGT_OldPointInstancer( pAttrs, uniformAttrs ) ); - } else { - refiner.addPrimitive( new GusdGT_PointInstancer( pAttrs, uniformAttrs ) ); - } - } -} - -void -GusdRefinerCollector::addInstPrim( const SdfPath &path, GT_PrimitiveHandle p, int index ) -{ - // When we are building point instancers, the refiner collects prims - // that can be instances until finish is called. - // - // GT_PrimInstance prims contain more than one instance of a prototype. - // Each instance in a entry in the m_instancePrims array and has an - // index into the GT_PrimInstance. - - DBG(cerr << "addInstPrim " << path << endl); - - auto instPrimsIt = m_instancePrims.find( path ); - if( instPrimsIt == m_instancePrims.end() ) { - m_instancePrims[ path ] = - vector( 1, InstPrimEntry( p, index )); - } - else { - instPrimsIt->second.push_back( InstPrimEntry( p, index )); - } -} - -namespace { - -GT_DataArrayHandle -newDataArray( GT_Storage storage, GT_Size size, int tupleSize, - GT_Type typeInfo=GT_TYPE_NONE ) -{ - if( storage == GT_STORE_REAL32 ) { - return new GT_Real32Array( size, tupleSize, typeInfo ); - } - else if( storage == GT_STORE_REAL16 ) { - return new GT_Real16Array( size, tupleSize, typeInfo ); - } - else if( storage == GT_STORE_REAL64 ) { - return new GT_Real64Array( size, tupleSize, typeInfo ); - } - else if( storage == GT_STORE_UINT8 ) { - return new GT_UInt8Array( size, tupleSize, typeInfo ); - } -#if SYS_VERSION_FULL_INT >= 0x11000000 - else if( storage == GT_STORE_INT8) { - return new GT_Int8Array( size, tupleSize, typeInfo ); - } - else if( storage == GT_STORE_INT16) { - return new GT_Int16Array( size, tupleSize, typeInfo ); - } -#endif - else if( storage == GT_STORE_INT32 ) { - return new GT_Int32Array( size, tupleSize, typeInfo ); - } - else if( storage == GT_STORE_INT64 ) { - return new GT_Int64Array( size, tupleSize, typeInfo ); - } - else if( storage == GT_STORE_STRING ) { - return new GT_DAIndexedString( size, tupleSize ); - } - return NULL; -} - -void -copyDataArrayItem( GT_DataArrayHandle dstData, GT_DataArrayHandle srcData, - GT_Offset dstOffset, GT_Offset srcOffset ) -{ - // copy a scalar data item into the destination array at the given offset. - GT_Storage storage = dstData->getStorage(); - if( storage == GT_STORE_REAL32 ) { - for( int i = 0; i < dstData->getTupleSize(); ++i ) { - auto dst = UTverify_cast(dstData.get()); - dst->set( srcData->getF32( srcOffset, i ), dstOffset, i ); - } - } - else if( storage == GT_STORE_REAL64 ) { - for( int i = 0; i < dstData->getTupleSize(); ++i ) { - auto dst = UTverify_cast(dstData.get()); - dst->set( srcData->getF64( srcOffset, i ), dstOffset, i ); - } - } - else if( storage == GT_STORE_INT32 ) { - for( int i = 0; i < dstData->getTupleSize(); ++i ) { - auto dst = UTverify_cast(dstData.get()); - dst->set( srcData->getI32( srcOffset, i ), dstOffset, i ); - } - } - else if( storage == GT_STORE_INT64 ) { - for( int i = 0; i < dstData->getTupleSize(); ++i ) { - auto dst = UTverify_cast(dstData.get()); - dst->set( srcData->getI64( srcOffset, i ), dstOffset, i ); - } - } - else if( storage == GT_STORE_STRING ) { - for( int i = 0; i < dstData->getTupleSize(); ++i ) { - auto dst = UTverify_cast(dstData.get()); - dst->setString( dstOffset, i, srcData->getS( srcOffset, i ) ); - } - } -} - -GT_AttributeListHandle -findAndAddStringAttribute( GT_AttributeListHandle attrs, - const std::string& attrName, - const GT_PrimitiveHandle& gtPrim) { - // find a string attribute on the prim and add it to the attribute list. - GT_Owner owner; - if(auto attrib = gtPrim->findAttribute(attrName.c_str(), owner, 0)){ - if (attrib->isValid()){ - if (!attrs) { - attrs = new GT_AttributeList( new GT_AttributeMap() ); - } - auto array = new GT_DAIndexedString(1); - array->setString( 0, 0, attrib->getS(0) ); - attrs = attrs->addAttribute( attrName.c_str(), array, true ); - } - } - return attrs; -} - -} /* close namespace */ - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/refiner.h b/third_party/houdini/gusd/refiner.h deleted file mode 100644 index 9960686f57..0000000000 --- a/third_party/houdini/gusd/refiner.h +++ /dev/null @@ -1,249 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_REFINER_H -#define GUSD_REFINER_H - -#include "api.h" - -#include -#include -#include -#include - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/tokens.h" -#include "pxr/usd/sdf/path.h" - -#include "writeCtrlFlags.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/// \class GusdRefiner -/// \brief Class used to refine GT prims so that they can be written to a USD file. -/// -/// When we write a USD file, we create a GT_GEODetail prim from the current detail, -/// then refine it using a GusdRefiner. -/// -/// The basic idea is that the refiner looks at each prim, if it is a type that can -/// be written to USD it adds it to the "gprim array", if not it continues to refine it. -/// -/// The refiner supports namespace hierarchy. Some prims types are added to the -/// the gprim array and then add thier children as well. Packed prims do this. The -/// packed prim becomes a group node in USD. A PackedF3DGroup is similar. -/// -/// The refiner calculates the primPath (location in the USD file). This can come from -/// an attribute on the prim being refined or it can be computed. The computed -/// path is based on a prefix provided by the client, a prim name and possibly -/// a hierarchy pf group names supplied by packed prims. -/// -/// The gprim array can contain prims from several OBJ nodes. The obj nodes provide -/// a coordinate space and a set of options. We stash this stuff with the prims -/// in the prim array. - - -class GusdRefinerCollector; - -class GUSD_API GusdRefiner : public GT_Refine -{ -public: - - // A struct representing GT prims refined to a USD prim. - // localXform is the transform from the prim's space to its parent. - // parentXform is the transform from the prim's parent's space to World. - struct GprimArrayEntry { - SdfPath path; - GT_PrimitiveHandle prim; - UT_Matrix4D xform; - TfToken purpose; - GusdWriteCtrlFlags writeCtrlFlags; - - GprimArrayEntry() {} - GprimArrayEntry( - const SdfPath& path, - const GT_PrimitiveHandle& prim, - const UT_Matrix4D& xform, - const TfToken& purpose, - const GusdWriteCtrlFlags& writeCtrlFlags ) - : path( path ) - , prim( prim ) - , xform( xform ) - , purpose(purpose) - , writeCtrlFlags(writeCtrlFlags) {} - }; - using GprimArray = std::vector; - - //////////////////////////////////////////////////////////////////////////// - - /// Construct a refiner for refining the prims in a detail. - /// Typically the ROP constructs a refiner for its cooked detail, - /// and then as we process GT prims, if a GEO Packed Prim is encountered, - /// We create a new refiner and recurse. - /// We need to keep track of the transform as we recurse through packed prims. Note - /// that we only write packed prims that have been tagged with a prim path. We - /// kee track of the transform of the last group we wrote in parentToWorldXform - /// \p localToWorldXform is initialized to the OBJ Node's transform by the ROP. - GusdRefiner( - GusdRefinerCollector& collector, - const SdfPath& pathPrefix, - const std::string& pathAttrName, - const UT_Matrix4D& localToWorldXform ); - - virtual ~GusdRefiner() {} - - virtual bool allowThreading() const override { return false; } - - virtual void addPrimitive( const GT_PrimitiveHandle& gtPrim ) override; - - void refineDetail( - const GU_ConstDetailHandle& detail, - const GT_RefineParms& parms ); - - const GprimArray& finish(); - - ////////////////////////////////////////////////////////////////////////// - - // If true, refine packed prims, otherwise return the prim on the - // prim array. This is set to false when we just want to capture - // the prims transform. - bool m_refinePackedPrims; - - // Use the "usdprimpath" intrinsic for the name of USD packed prims. - // Used when writing overlays. - bool m_useUSDIntrinsicNames; - - - // Normally we only write geometry packed prims as groups if they have - // been named. Force top level groups to always be written. This is so we - // can be assured we have a place to write instance ids. - bool m_forceGroupTopPackedPrim; - - // Set true if we have usdinstancepath or instancepath set. If true and we - // have packed usd, packed prims or points we will build a point instancer. - bool m_buildPointInstancer; - - // If true, build prototypes which means ignoring the instancepath and not - // building a point isntancer, and putting all geometry under the given - // prototypes scope. - bool m_buildPrototypes; - - // If we are overlaying a point instancer, this is set to the type of - // of point instancer we need to overlay (old - "PxPointInstancer" or new - // "PointInstancer"). - TfToken m_pointInstancerType; - - GusdWriteCtrlFlags m_writeCtrlFlags; - - ///////////////////////////////////////////////////////////////////////////// - -private: - - // Convert a prim's name into a prim path taking into account prefix and - // modifying to be a valid Usd prim path. - std::string createPrimPath( const std::string& primName); - - // Place to collect refined prims - GusdRefinerCollector& m_collector; - - // Refine parms are passed to refineDetail and then held on to. - GT_RefineParms m_refineParms; - - // Prefix added to all relative prim paths. - SdfPath m_pathPrefix; - - // The name of the attribute that specifies what USD object to write to. - const std::string& m_pathAttrName; - - // The coordinate space accumulated as we recurse into packed geometry prims. - UT_Matrix4D m_localToWorldXform; - - // false if we have recursed into a packed prim. - bool m_isTopLevel; -}; - -// As we recurse down a packed prim hierarchy, we create a new refiner at each -// level so we can carry the appropriate parametera. However, we need a object -// shared by all the refiners to collect the refined prims. -class GusdRefinerCollector { -public: - - using GprimArrayEntry = GusdRefiner::GprimArrayEntry; - using GprimArray = GusdRefiner::GprimArray; - - // Struct used to keep names unique - struct NameInfo { - size_t firstIdx; // index into gprim array of first use of name - size_t count; // number of times name has been used. - - NameInfo() : firstIdx( -1 ), count(0) {} - NameInfo( size_t idx ) : firstIdx(idx), count( 0 ) {} - }; - - // Struct to store instance prims in. - // A GT_PrimInstance may represent several point instancer array entries. - // Index identifies which one. - struct InstPrimEntry { - GT_PrimitiveHandle prim; - size_t index; - - InstPrimEntry() : prim(NULL), index(0) {} - InstPrimEntry( GT_PrimitiveHandle p, int i=0 ) : prim( p ), index(i) {} - }; - - //////////////////////////////////////////////////////////////////////////// - - SdfPath add( - const SdfPath& path, - bool explicitPrimPath, - GT_PrimitiveHandle prim, - const UT_Matrix4D& xform, - const TfToken & purpose, - const GusdWriteCtrlFlags& writeCtrlFlags ); - - /// Add a prim to be added to a point instancer during finish - void addInstPrim( const SdfPath& path, GT_PrimitiveHandle p, int index=0 ); - - // Complete refining all prims. - // When constructing point instancers, the refiner/collector gathers and - // holds on to all packed prims that are added. When finish is called, - // a GT_PrimPointMesh is created and added for each point instancer. - void finish( GusdRefiner& refiner ); - - //////////////////////////////////////////////////////////////////////////// - - // The results of the refine - GusdRefiner::GprimArray m_gprims; - - // Map used to generate unique names for each prim - std::map m_names; - - // We can refine several point instancers in one session. They are partitioned - // by a "srcPrimPath" intrinsic on USD packed prims. This map is used to - // sort the prims. If a prim does note have a srcPrimPath, it is added to - // a entry with a empty path. - std::map> m_instancePrims; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // __GUSD_GT_REFINER_H__ diff --git a/third_party/houdini/gusd/scopeWrapper.cpp b/third_party/houdini/gusd/scopeWrapper.cpp deleted file mode 100644 index ec3e4c3882..0000000000 --- a/third_party/houdini/gusd/scopeWrapper.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "scopeWrapper.h" - -#include "context.h" -#include "UT_Gf.h" - -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -// drand48 and srand48 defined in SYS_Math.h as of 13.5.153. and conflicts with imath. -#undef drand48 -#undef srand48 - -using std::cout; -using std::cerr; -using std::endl; -using std::vector; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -GusdScopeWrapper::GusdScopeWrapper( - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride ) -{ - initUsdPrim( stage, path, isOverride ); -} - -GusdScopeWrapper::GusdScopeWrapper( - const UsdGeomScope& scope, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdGroupBaseWrapper( time, purposes ) - , m_usdScope( scope ) -{ -} - -GusdScopeWrapper::GusdScopeWrapper( const GusdScopeWrapper &in ) - : GusdGroupBaseWrapper( in ) - , m_usdScope( in.m_usdScope ) -{ -} - -GusdScopeWrapper::~GusdScopeWrapper() -{} - -bool GusdScopeWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - bool newPrim = true; - if( asOverride ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing ) { - // Note that we are creating a Xformable rather than a Xform. - // If we are writing an overlay and the ROP sees a geometry packed prim, - // we want to write just the xform. In that case we can use a xform - // wrapper to write the xform on any prim type. - m_usdScope = UsdGeomScope(stage->OverridePrim( path )); - newPrim = false; - } - else { - m_usdScope = UsdGeomScope::Define( stage, path ); - } - } - else { - m_usdScope = UsdGeomScope::Define( stage, path ); - } - if( !m_usdScope || !m_usdScope.GetPrim().IsValid() ) { - TF_WARN( "Unable to create %s scope '%s'.", newPrim ? "new" : "override", path.GetText() ); - } - return bool(m_usdScope); -} - -GT_PrimitiveHandle GusdScopeWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - return new GusdScopeWrapper( stage, path, ctxt.writeOverlay ); -} - -GT_PrimitiveHandle GusdScopeWrapper:: -defineForRead( - const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdScopeWrapper( - UsdGeomScope( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdScopeWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay ); - clearCaches(); - return true; -} - - -const char* GusdScopeWrapper:: -className() const -{ - return "GusdScopeWrapper"; -} - - -void GusdScopeWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdScopeWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdScopeWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdScopeWrapper:: -doSoftCopy() const -{ - return GT_PrimitiveHandle(new GusdScopeWrapper( *this )); -} - - -bool GusdScopeWrapper:: -isValid() const -{ - return static_cast(m_usdScope); -} - -bool GusdScopeWrapper:: -refine( - GT_Refine& refiner, - const GT_RefineParms* parms) const -{ - //cerr << "GusdScopeWrapper::refine, enter: " << m_usdScope.GetPath() << endl; - - return refineGroup( m_usdScope.GetPrim(), refiner, parms ); -} - - -bool GusdScopeWrapper:: -updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& localXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) -{ - if( !m_usdScope ) { - return false; - } - - DBG( cout << "GusdScopeWrapper::updateFromGTPrim, primType = " << sourcePrim->className() << endl ); - - return updateGroupFromGTPrim( m_usdScope, sourcePrim, localXform, - ctxt, xformCache ); -} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/scopeWrapper.h b/third_party/houdini/gusd/scopeWrapper.h deleted file mode 100644 index ceb88a6665..0000000000 --- a/third_party/houdini/gusd/scopeWrapper.h +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_SCOPE_WRAPPER_H -#define GUSD_SCOPE_WRAPPER_H - -#include "groupBaseWrapper.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usdGeom/scope.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -class GusdScopeWrapper : public GusdGroupBaseWrapper -{ -public: - GusdScopeWrapper( const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride = false ); - GusdScopeWrapper( const GusdScopeWrapper &in ); - GusdScopeWrapper( const UsdGeomScope& scope, - UsdTimeCode t, - GusdPurposeSet purposes ); - virtual ~GusdScopeWrapper(); - - // GusdPrimWrapper interface ----------------------------------------------- - -public: - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdScope; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& localXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) override; - - virtual bool isValid() const override; - - virtual bool refine(GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const override; - - // ------------------------------------------------------------------------- - -public: - - static GT_PrimitiveHandle - defineForWrite(const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - - bool initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - UsdGeomScope m_usdScope; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_SCOPE_WRAPPER_H - diff --git a/third_party/houdini/gusd/shaderWrapper.cpp b/third_party/houdini/gusd/shaderWrapper.cpp deleted file mode 100644 index ea780a9ef9..0000000000 --- a/third_party/houdini/gusd/shaderWrapper.cpp +++ /dev/null @@ -1,644 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "shaderWrapper.h" - -#include "context.h" - -#include "pxr/usd/usdRi/materialAPI.h" -#include "pxr/usd/usdShade/connectableAPI.h" -#include "pxr/usd/usdShade/materialBindingAPI.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cout; -using std::cerr; -using std::endl; -using std::string; - -namespace { - -typedef UT_Set VopSet; -typedef UT_Map ParmDepMap; - - -bool -_buildCustomOslNode(const VOP_Node* vopNode, - UT_String& shaderName, - const std::string& shaderOutDir) -{ - // If shaderName doesn't begin with "op:", it's not - // a custom osl node. Just exit this function. - if (!shaderName.startsWith("op:")) { - return false; - } - - shaderName.replacePrefix("op:", ""); - shaderName.forceAlphaNumeric(); // replaces each '/' with '_' - shaderName.prepend(shaderOutDir.c_str()); - - // Create shaderOutDir path directories, if they don't exist. - if (!UT_FileUtil::makeDirs(shaderOutDir.c_str())) { - TF_CODING_ERROR("Failed to create dir '%s'", shaderOutDir.c_str()); - return false; - } - - const string shaderNameOsl = shaderName.toStdString() + ".osl"; - - // Update shaderName to include the .oso extension. - shaderName.append(".oso"); - - std::ofstream oslFile; - oslFile.open(shaderNameOsl, std::ios::out); - - VOP_CodeGenerator *cg = - const_cast(vopNode)->getVopCodeGenerator(); - cg->outputVflCode(oslFile, NULL, VEX_CG_DEFAULT, - vopNode->getOslContextType()); - oslFile.close(); - - string houRoot(UT_EnvControl::getString(ENV_HFS)); - string houErr = shaderOutDir + "err.log"; - string houInclude = houRoot + "/houdini/osl/include"; - - string oslcCmd = houRoot + "/bin/hrmanshader -e " + houErr + - " -cc oslc -I" + houInclude + " -o " + - shaderName.toStdString() + " " + shaderNameOsl; - std::shared_ptr pipe(popen(oslcCmd.c_str(), "r"), - [](FILE *f){ pclose(f); }); - if (!pipe) { - TF_CODING_ERROR("Failed to run command '%s'", oslcCmd.c_str()); - return false; - } - - return true; -} - -void _buildRampParmInputs(const PRM_Parm* parm, UsdShadeShader& shaderObject) -{ - std::string rampName(parm->getToken()); - bool isDefault = true; - - // Get the multiparm count. This will be divisible by 3 since each - // point in the ramp will have a position, value and interp type. - const int count = parm->getMultiParmCount() / 3; - - // Begin by extracting the list of positions. Set the list size to - // (count + 2) so that an extra end-condition point can be copied - // onto each end of the list. - VtArray positions(count + 2); - for (int i = 0; i < count; i++) { - PRM_Parm* position = parm->getMultiParm(i * 3); - isDefault = position->isTrueFactoryDefault() && isDefault; - - position->getValues(0, &(positions[i + 1]), SYSgetSTID()); - } - - // If any positions are not set to factory defaults, store the - // whole positions list as a shader input. - if (!isDefault) { - // Copy first and last positions onto ends of list. - positions[0] = positions[1]; - positions[positions.size() - 1] = positions[positions.size() - 2]; - - TfToken positionName(rampName + "_the_key_positions"); - UsdShadeInput positionsInput = - shaderObject.CreateInput(positionName, - SdfValueTypeNames->FloatArray); - positionsInput.Set(positions); - } - - // Next extract the list of values. Again keep track of whether all - // the values are set to factory defaults. - isDefault = true; - - // The values can either be colors or floats. - if (parm->isRampTypeColor()) { - // Color type. Set the list size to (count + 2) so that an extra - // end-condition value can be copied onto each end of the list. - VtArray values(count + 2); - - for (int i = 0; i < count; i++) { - // The +1 in the getMultiParm index is because the i'th value - // parm comes right after the i'th position parm. - PRM_Parm* value = parm->getMultiParm((i * 3) + 1); - isDefault = value->isTrueFactoryDefault() && isDefault; - - fpreal32 color[3]; - value->getValues(0, color, SYSgetSTID()); - values[i + 1].Set(color); - } - - // If any values are not set to factory defaults, store the - // whole values list as a shader input. - if (!isDefault) { - // Copy first and last color values onto ends of list. - values[0] = values[1]; - values[values.size() - 1] = values[values.size() - 2]; - - TfToken valueName(rampName + "_the_key_values"); - UsdShadeInput valuesInput = - shaderObject.CreateInput(valueName, - SdfValueTypeNames->Color3fArray); - valuesInput.Set(values); - } - } else { - // Float type. Set the list size to (count + 2) so that an extra - // end-condition value can be copied onto each end of the list. - VtArray values(count + 2); - - for (int i = 0; i < count; i++) { - // The +1 in the getMultiParm index is because the i'th value - // parm comes right after the i'th position parm. - PRM_Parm* value = parm->getMultiParm((i * 3) + 1); - isDefault = value->isTrueFactoryDefault() && isDefault; - - value->getValues(0, &(values[i + 1]), SYSgetSTID()); - } - - // If any values are not set to factory defaults, store the - // whole values list as a shader input. - if (!isDefault) { - // Copy first and last float values onto ends of list. - values[0] = values[1]; - values[values.size() - 1] = values[values.size() - 2]; - - TfToken valueName(rampName + "_the_key_values"); - UsdShadeInput valuesInput = - shaderObject.CreateInput(valueName, - SdfValueTypeNames->FloatArray); - valuesInput.Set(values); - } - } - - // Lastly, extract the interp type. Even though there is a separate - // interp parm provided with each position and value, the shader only - // uses the first. Use a getMultiParm index of 2 because the first - // interp parm comes right after the first position and value parms. - PRM_Parm* interp = parm->getMultiParm(2); - - // If the parm is not set to its factory default, - // store it as a shader input. - if (!interp->isTrueFactoryDefault()) { - UT_String str; - interp->getValue(0, str, 0, true, SYSgetSTID()); - - TfToken interpName(rampName + "_the_basis_strings"); - UsdShadeInput interpInput = - shaderObject.CreateInput(interpName, SdfValueTypeNames->String); - interpInput.Set(str.toStdString()); - } -} - -SdfValueTypeName -_vopTypeToSdfType(const VOP_Type& vopType) { - switch(vopType) { - case VOP_TYPE_INTEGER: return SdfValueTypeNames->Int; - case VOP_TYPE_FLOAT: return SdfValueTypeNames->Float; - case VOP_TYPE_STRING: return SdfValueTypeNames->String; - case VOP_TYPE_POINT: return SdfValueTypeNames->Point3f; - case VOP_TYPE_NORMAL: return SdfValueTypeNames->Normal3f; - case VOP_TYPE_COLOR: return SdfValueTypeNames->Color3f; - case VOP_TYPE_VECTOR: return SdfValueTypeNames->Vector3f; - case VOP_TYPE_VECTOR2: return SdfValueTypeNames->Float2; - case VOP_TYPE_VECTOR4: return SdfValueTypeNames->Float4; - case VOP_TYPE_MATRIX2: return SdfValueTypeNames->Matrix2d; - case VOP_TYPE_MATRIX3: return SdfValueTypeNames->Matrix3d; - case VOP_TYPE_MATRIX4: return SdfValueTypeNames->Matrix4d; - case VOP_TYPE_STRUCT: return SdfValueTypeNames->Token; - - case VOP_TYPE_INTEGER_ARRAY: return SdfValueTypeNames->IntArray; - case VOP_TYPE_FLOAT_ARRAY: return SdfValueTypeNames->FloatArray; - case VOP_TYPE_STRING_ARRAY: return SdfValueTypeNames->StringArray; - case VOP_TYPE_POINT_ARRAY: return SdfValueTypeNames->Point3fArray; - case VOP_TYPE_NORMAL_ARRAY: return SdfValueTypeNames->Normal3fArray; - case VOP_TYPE_COLOR_ARRAY: return SdfValueTypeNames->Color3fArray; - case VOP_TYPE_VECTOR_ARRAY: return SdfValueTypeNames->Vector3fArray; - case VOP_TYPE_VECTOR2_ARRAY: return SdfValueTypeNames->Float2Array; - case VOP_TYPE_VECTOR4_ARRAY: return SdfValueTypeNames->Float4Array; - case VOP_TYPE_MATRIX2_ARRAY: return SdfValueTypeNames->Matrix2dArray; - case VOP_TYPE_MATRIX3_ARRAY: return SdfValueTypeNames->Matrix3dArray; - case VOP_TYPE_MATRIX4_ARRAY: return SdfValueTypeNames->Matrix4dArray; - // VOP_TYPE_STRUCT_ARRAY doesn't exist - - default: return SdfValueTypeName(); - } -} - -UsdShadeShader -_vopGraphToUsdTraversal(const VOP_Node* vopNode, - UsdStagePtr& stage, - const SdfPath& lookPath, - VopSet& visitedVops, - ParmDepMap& parmDeps, - const string& shaderOutDir) -{ - const string nodeName = vopNode->getName().toStdString(); - const VOP_Type nodeType = vopNode->getShaderType(); - - UT_String shaderName(vopNode->getShaderName(false, nodeType)); - - _buildCustomOslNode(vopNode, shaderName, shaderOutDir); - - const VtValue pathAttr(TfToken(shaderName.toStdString())); - - const SdfPath shaderObjectPath = lookPath.AppendPath(SdfPath(nodeName)); - UsdShadeShader shaderObject; - - // Check if this node has already been visited. If so, retrieve - // its corresponding UsdRiRisObject from the usd stage. - if(visitedVops.find(nodeName) != visitedVops.end()) { - shaderObject = UsdShadeShader(stage->GetPrimAtPath(shaderObjectPath)); - } else { - // The node hasn't been visited yet. - shaderObject = UsdShadeShader::Define(stage, shaderObjectPath); - shaderObject.CreateIdAttr(pathAttr); - visitedVops.insert(nodeName); - } - - if(!shaderObject.GetPrim().IsValid()) { - TF_CODING_ERROR("Error creating or retrieving USD prim '%s'.", - nodeName.c_str()); - return UsdShadeShader(); - } - - // - // Iterate through each parameter in vopNode's parm list. - // - const PRM_ParmList* nodeParams = vopNode->getParmList(); - for (int i=0; igetEntries(); ++i) { - - const PRM_Parm* parm = nodeParams->getParmPtr(i); - - // - // Handle ramp parameters as a special-case. (Their multi-parms - // need to be processed all together rather than individually). - // - if (parm->isRampType()) { - _buildRampParmInputs(parm, shaderObject); - continue; - } - - int inIdx = vopNode->getInputFromName(parm->getToken()); - bool isConnected = inIdx >= 0 - && const_cast(vopNode)->isConnected(inIdx, true); - - // - // Create a UsdShadeInput for each connected input, and - // for each parameter that is set to a non-default value. - // - if (isConnected || !parm->isTrueFactoryDefault()) { - const char* type = NULL; - - // Figure out if this parm has spare data named "script_ritype". - // (This would have been added to this parm when the otl/hda for - // this vopNode was generated.) - if (auto* spare = parm->getSparePtr()) { - type = spare->getValue("script_ritype"); - } - - if (type == NULL) { - continue; - } - - // - // For each type, multiparms are treated the same as parms, - // ie. int and int[] are handled as the same type; float and - // float[], string and string[], etc. - // This works because a multiparm doesn't actually "contain" its - // elements; instead, its elements just show up as regular parms - // alongside the multiparm. Thus, this loop will process all parms. - // - // TODO: This will probably need to be changed at some point so - // that instead of multiparms and their element parms being handled - // individually, some mechanism needs to be put in place to combine - // these elements into a single array. - // - if (strcmp(type, "string") == 0 || - strcmp(type, "string[]") == 0) { - - UsdShadeInput shadeInput; - - // If the parameter is a menu, it may be a string which represents - // a numeric value. - // TODO Add metadata to the parameter templates to distinguish this - // case. - UT_String str; - parm->getValue(0, str, 0, true, SYSgetSTID()); - bool isInteger = parm->getChoiceListPtr() && str.isInteger(); - - if(isInteger) { - shadeInput = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Int); - - } - else { - shadeInput = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->String); - } - - parmDeps[parm] = shadeInput; - - if(!isConnected) { - if(isInteger) { - shadeInput.Set(str.toInt()); - } - else { - shadeInput.Set(str.toStdString()); - } - } - } - else if (strcmp(type, "float") == 0 || - strcmp(type, "float[]") == 0) { - - UsdShadeInput shadeInput - = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Float); - parmDeps[parm] = shadeInput; - - if(!isConnected) { - fpreal val; - parm->getValue(0, val, 0, SYSgetSTID()); - shadeInput.Set((float)val); - } - } - else if (strcmp(type, "int") == 0 || - strcmp(type, "int[]") == 0) { - - UsdShadeInput shadeInput - = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Int); - parmDeps[parm] = shadeInput; - - if(!isConnected) { - int val; - parm->getValue(0, val, 0, SYSgetSTID()); - shadeInput.Set(val); - } - } - else if (strcmp(type, "color") == 0 || - strcmp(type, "color[]") == 0) { - - UsdShadeInput shadeInput - = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Color3f); - parmDeps[parm] = shadeInput; - - if(!isConnected) { - fpreal32 color[3]; - parm->getValues(0, color, SYSgetSTID()); - shadeInput.Set(GfVec3f(color)); - } - } - else if (strcmp(type, "normal") == 0 || - strcmp(type, "normal[]") == 0) { - - UsdShadeInput shadeInput - = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Normal3f); - parmDeps[parm] = shadeInput; - - if(!isConnected) { - fpreal32 normal[3]; - parm->getValues(0, normal, SYSgetSTID()); - shadeInput.Set(GfVec3f(normal)); - } - } - else if (strcmp(type, "point") == 0 || - strcmp(type, "point[]") == 0) { - - UsdShadeInput shadeInput - = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Point3f); - parmDeps[parm] = shadeInput; - - if(!isConnected) { - fpreal32 point[3]; - parm->getValues(0, point, SYSgetSTID()); - shadeInput.Set(GfVec3f(point)); - } - } - else if (strcmp(type, "vector") == 0 || - strcmp(type, "vector[]") == 0) { - - UsdShadeInput shadeInput - = shaderObject.CreateInput(TfToken(parm->getToken()), - SdfValueTypeNames->Vector3f); - parmDeps[parm] = shadeInput; - - if(!isConnected) { - fpreal32 vector[3]; - parm->getValues(0, vector, SYSgetSTID()); - shadeInput.Set(GfVec3f(vector)); - } - } - } - } - - // - // Add connected nodes in depth-first order - // - for(int inIdx=0; inIdxnInputs(); ++inIdx) { - // XXX Assuming the need for const_casts below is oversight in - // VOP API. - bool hasInput = const_cast(vopNode)->isConnected(inIdx, true); - if(hasInput) { - VOP_Node* inputVop - = const_cast(vopNode)->findSimpleInput(inIdx); - int outIdx - = inputVop->whichOutputIs(const_cast(vopNode), inIdx); - - UsdShadeShader inputPrim = _vopGraphToUsdTraversal(inputVop, - stage, - lookPath, - visitedVops, - parmDeps, - shaderOutDir); - - UT_String inputName, outputName; - vopNode->getInputName(inputName, inIdx); - inputVop->getOutputName(outputName,outIdx); - - TfToken inputToken(inputName.toStdString()); - UsdShadeInput shadeInput = shaderObject.GetInput(inputToken); - - // - // It's possible that no UsdShadeInput has been created for this - // connection yet. Only input connections with corresponding parms - // have been visited so far. This must be an input with no parm. - // - if (!shadeInput) { - VOP_Type vopType = vopNode->getInputType(inIdx); - auto sdfType = _vopTypeToSdfType(vopType); - if (sdfType) { - shadeInput = shaderObject.CreateInput(inputToken, sdfType); - } - } - - if (shadeInput) { - UsdShadeConnectableAPI::ConnectToSource(shadeInput, - inputPrim, TfToken(outputName.toStdString())); - } else { - TF_CODING_ERROR("Error creating or retrieving input '%s' on " - "shader '%s'.", inputToken.GetText(), nodeName.c_str()); - } - } - } - - return shaderObject; -} - - -void -_vopGraphToUsd(const VOP_Node* vopNode, - UsdShadeMaterial& material, - const ParmDepMap& parmDeps) -{ - // Look for interface inputs. - // We iterate through the vop creator's paramters and see if any of our - // vop graph's paramters are dependents. - const OP_Node* creatorNode = vopNode->getCreator(); - const PRM_ParmList* creatorParams = creatorNode->getParmList(); - - for(int i=0; igetEntries(); ++i) { - - const PRM_Parm* parm = creatorParams->getParmPtr(i); - - UT_ValArray curDeps; - UT_IntArray curDepSubIdxs; - const_cast(creatorNode)->getParmsThatReference( - parm->getToken(), curDeps, curDepSubIdxs); - - UsdShadeInput interfaceInput; - - for(UT_ValArray::const_iterator curDepIt=curDeps.begin(); - curDepIt != curDeps.end(); ++curDepIt) { - - auto parmDepIt = parmDeps.find(*curDepIt); - if(parmDepIt != parmDeps.end()) { - const UsdShadeInput& shadeInput = parmDepIt->second; - - if(!interfaceInput.IsDefined()) { - interfaceInput = material.CreateInput( - TfToken(parm->getToken()), - shadeInput.GetAttr().GetTypeName()); - } - - UsdShadeConnectableAPI::ConnectToSource(shadeInput, - interfaceInput); - } - } - } -} - -} // anon namespace - - -GusdShaderWrapper:: -GusdShaderWrapper(const VOP_Node* terminalNode, - const UsdStagePtr& stage, - const std::string& path, - const std::string& shaderOutDir) -{ - m_usdMaterial = UsdShadeMaterial::Define(stage, SdfPath(path)); - m_shaderOutDir = shaderOutDir; - - // Make sure m_shaderOutDir ends with "/". - if (!m_shaderOutDir.empty() && m_shaderOutDir.back() != '/') { - m_shaderOutDir += "/"; - } - - buildLook(terminalNode); -} - - -void GusdShaderWrapper:: -buildLook(const VOP_Node* terminalNode) -{ - if(!isValid()) { - TF_CODING_ERROR("Usd look prim isn't valid. Can't create shader '%s'.", - terminalNode->getFullPath().buffer()); - return; - } - - if(terminalNode->getShaderType() != VOP_BSDF_SHADER) { - TF_CODING_ERROR("Assigned shader node must be a bxdf. Can't create shader '%s'.", - terminalNode->getFullPath().buffer()); - return; - } - - UsdStagePtr stage = m_usdMaterial.GetPrim().GetStage(); - VopSet visitedVops; - ParmDepMap parmDeps; - - _vopGraphToUsdTraversal(terminalNode, - stage, - m_usdMaterial.GetPath(), - visitedVops, - parmDeps, - m_shaderOutDir); - - _vopGraphToUsd(terminalNode, m_usdMaterial, parmDeps); - - - SdfPath bxdfPath = m_usdMaterial.GetPath().AppendChild(TfToken( - terminalNode->getName().toStdString())); - - auto riMatAPI = UsdRiMaterialAPI::Apply(m_usdMaterial.GetPrim()); - riMatAPI.SetSurfaceSource(bxdfPath); -} - - -bool GusdShaderWrapper:: -bind(UsdPrim& prim) const -{ - if(!isValid()) - return false; - - return UsdShadeMaterialBindingAPI(prim).Bind(m_usdMaterial); -} - - -bool GusdShaderWrapper:: -isValid() const -{ - return m_usdMaterial.GetPrim().IsValid(); -} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/gusd/shaderWrapper.h b/third_party/houdini/gusd/shaderWrapper.h deleted file mode 100644 index f3a1285fa5..0000000000 --- a/third_party/houdini/gusd/shaderWrapper.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_SHADER_WRAPPER_H -#define GUSD_SHADER_WRAPPER_H - -#include "pxr/pxr.h" -#include "pxr/usd/usdShade/material.h" - -#include "api.h" - -class VOP_Node; - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdContext; - -class GusdShaderWrapper -{ -public: - - GUSD_API - GusdShaderWrapper( - const VOP_Node* terminalNode, - const UsdStagePtr& stage, - const std::string& path, - const std::string& shaderOutDir); - - GUSD_API - bool bind(UsdPrim& prim) const; - - GUSD_API - bool isValid() const; - -private: - - void buildLook(const VOP_Node* terminalNode); - - UsdShadeMaterial m_usdMaterial; - std::string m_shaderOutDir; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_SHADER_WRAPPER_H diff --git a/third_party/houdini/gusd/site/icons/pxh_gusdIcon.png b/third_party/houdini/gusd/site/icons/pxh_gusdIcon.png deleted file mode 100644 index 24a9adf717ac8698a113f346a9c905eace0a374c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3477 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 diff --git a/third_party/houdini/gusd/stageCache.cpp b/third_party/houdini/gusd/stageCache.cpp deleted file mode 100644 index 0d87654704..0000000000 --- a/third_party/houdini/gusd/stageCache.cpp +++ /dev/null @@ -1,1895 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "stageCache.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debugCodes.h" -#include "error.h" -#include "USD_DataCache.h" - -#include "pxr/base/arch/hints.h" -#include "pxr/base/tf/envSetting.h" -#include "pxr/base/tf/notice.h" -#include "pxr/usd/ar/resolver.h" -#include "pxr/usd/ar/resolverContext.h" -#include "pxr/usd/ar/resolverContextBinder.h" -#include "pxr/usd/kind/registry.h" -#include "pxr/usd/sdf/changeBlock.h" -#include "pxr/usd/usd/modelAPI.h" -#include "pxr/usd/usd/notice.h" -#include "pxr/usd/usd/primRange.h" -#include "pxr/usd/usd/stagePopulationMask.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - - -TF_DEFINE_ENV_SETTING(GUSD_STAGEMASK_EXPANDRELS, true, - "Expand stage masks to include targets of relationships. " - "It may be possible to disable this option, which may " - "provide performance gains, but correctness cannot be " - "guaranteed when doing so."); - - -TF_DEFINE_ENV_SETTING(GUSD_STAGEMASK_EXPANDMODELS, true, - "Expand stage masks to encapsulating models. " - "This helps limit the number of masked stages, by " - "causing stage sharing across different prims within " - "each encapsulating model. Disabling this may cause a " - "signficant reduction in performance."); - - -TF_DEFINE_ENV_SETTING(GUSD_STAGEMASK_ENABLE, true, - "Enable use of stage masks when accessing prims from " - "the cache. Note that disabling this feature may " - "be very detrimental to performance when separately " - "querying many prims with variant selections " - "(or other types of stage edits)."); - - -namespace { - - -/// Micro node that dirties itself based on Tf -/// change notifications on a USD stage. -class _StageChangeMicroNode final : public DEP_MicroNode, - public TfWeakBase // Required for TfNotice -{ -public: - - _StageChangeMicroNode(const UsdStagePtr& stage) - : DEP_MicroNode(), TfWeakBase(), - _identifier(stage->GetRootLayer()->GetIdentifier()) - { - _noticeKey = TfNotice::Register( - TfCreateWeakPtr(this), - &_StageChangeMicroNode::_HandleStageDidChange, stage); - } - - virtual ~_StageChangeMicroNode() - { - TfNotice::Revoke(_noticeKey); - } - - /// Propagate dirty state to outputs. - /// This is unsafe outside of the main event queue. - void SetDirty() - { - // Dirty propagation is not thread safe. - // This should only occur on the main event queue, as happens - // with stage reloads on the GusdStageCache. - if(UT_Thread::isMainThread()) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] Propagating dirty state for stage %s\n", - _identifier.c_str()); - - OP_Node* node = OPgetDirector(); - node->propagateDirtyMicroNode(*this, OP_INPUT_CHANGED, - /*data*/ nullptr, - /*send_root_event*/ false); - } else { - TF_WARN("Change notification received for stage @%s@ outside of " - "the main event queue. This may indicate unsafe mutation " - "of stages owned by the GusdUsdStageCache.", - _identifier.c_str()); - } - } - -private: - - void - _HandleStageDidChange(const UsdNotice::StageContentsChanged& n) - { - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] StageContentsChanged notice for stage " - "%s: dirtying state.\n", _identifier.c_str()); - - SetDirty(); - } - -private: - TfNotice::Key _noticeKey; - std::string _identifier; -}; - - -} /*namespace*/ - - -void -GusdStageCache::ReloadStages(const UT_Set& stages) -{ - if(!UT_Thread::isMainThread()) { - TF_WARN("Reloading USD stages on a secondary thread. " - "Beware that stage reloading is not thread-safe, and reloading " - "a stage may affect other stages, including stages for which a " - "reload request was not made! To ensure safety of reload " - "operations, stages should only be reloaded from within " - "Houdini's main thread."); - } - for(const auto& stage : stages) - stage->Reload(); -} - - -void -GusdStageCache::ReloadLayers(const UT_Set& layers) -{ - if(!UT_Thread::isMainThread()) { - TF_WARN("Reloading USD layers on a secondary thread. " - "Beware that layer reloading is not thread-safe, and reloading " - "a layer may affect any USD stages that reference that layer! " - "To ensure safety of reload operations, stages should only be " - "reloaded from within Houdini's main thread."); - } - for(const auto& layer : layers) - layer->Reload(); -} - - -namespace { - - -template -bool -_PointerTypesMatch(const T& a, const T& b) -{ - if(a == b) - return true; - if(a && b) - return *a == *b; - return false; -} - - -/// Key for a looking up a stage for a set of layers and load opts. -struct _StageKey -{ - _StageKey() = default; - _StageKey(const UT_StringHolder& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit) - : _path(path), _opts(opts), _edit(edit) {} - - const UT_StringHolder& GetPath() const { return _path; } - const GusdStageOpts& GetOpts() const { return _opts; } - const GusdStageEditPtr& GetEdit() const { return _edit; } - -private: - UT_StringHolder _path; - GusdStageOpts _opts; - GusdStageEditPtr _edit; -}; - - -struct _StageKeyHashCmp -{ - static bool equal(const _StageKey& a, const _StageKey& b) - { - return a.GetPath() == b.GetPath() && - a.GetOpts() == b.GetOpts() && - _PointerTypesMatch(a.GetEdit(), b.GetEdit()); - } - - static bool hash(const _StageKey& key) - { - size_t hash = SYShash(key.GetPath()); - SYShashCombine(hash, key.GetOpts().GetHash()); - if(key.GetEdit()) - SYShashCombine(hash, key.GetEdit()->GetHash()); - return hash; - } -}; - - -struct _SdfPathHashCmp -{ - static bool equal(const SdfPath& a, const SdfPath& b) - { return a == b; } - - static size_t hash(const SdfPath& path) - { return path.GetHash(); } -}; - - -/// Returns true if this is a valid prim path for referencing a prim on a stage. -bool -_IsValidPrimPath(const SdfPath& path) -{ - return (path.IsPrimPath() && - (path.IsAbsolutePath() || - path == GusdUSD_Utils::GetDefaultPrimIdentifier())) || - path == SdfPath::AbsoluteRootPath(); -} - - -} /*namespace*/ - - -/// Cache holding stages for different sets of masked prims. -/// These caches are created for a common set of stage options. -class GusdStageCache::_MaskedStageCache -{ -public: - _MaskedStageCache(GusdStageCache::_Impl& stageCache, const _StageKey& key) - : _stageCache(stageCache), _stageKey(key) {} - - UsdStageRefPtr FindStage(const SdfPath& primPath); - - /// Find or open a new stage, masking the prim at \p primPath. - /// If population mask expansion causes a newly opened stage to include - /// the entire contents of the stage (I.e., with no masking), then - /// \p loadedFullStage will be set to true. Otherwise, it is not modified. - UsdStageRefPtr FindOrOpenStage(const SdfPath& primPath, - bool* loadedFullStage, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - void Clear() { _map.clear(); } - - /// Append all stages held by this cache to @a stages. - void GetStages(UT_Set& stages) const - { - for(const auto& pair : _map) - stages.insert(pair.second); - } - - /// Load a range of [start,end) prims from this cache. The range corresponds - /// to a *subset* of the prims in \p primPaths. - /// The \p rangeFn functor must implement `operator()(exint)` which, given - /// an index of an element in the [start,end) range, returns the index in - /// \p primPaths identifying which primitive should be loaded. - /// The resulting UsdPrim is written into \p prims at the same index. - template - bool LoadPrimRange(const PrimRangeFn& rangeFn, - exint start, exint end, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - -private: - /// Open a new stage with the given mask. - /// The \p invokingPrimPath is the path at which FindOrOpenStage() was - /// called to begin the stage opening procedure. This may be set to an - /// empty path for other loading scenarios. - UsdStageRefPtr _OpenStage(const UsdStagePopulationMask& mask, - const SdfPath& invokingPrimPath, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - SdfPath _GetDefaultPrimPath(UT_ErrorSeverity sev=UT_ERROR_ABORT) const; - -private: - using _StageMap = UT_ConcurrentHashMap; - - GusdStageCache::_Impl& _stageCache; - _StageMap _map; - const _StageKey _stageKey; -}; - - -/// Primary internal cache implementation. -class GusdStageCache::_Impl -{ -public: - ~_Impl(); - - UT_RWLock& GetMapLock() { return _mapLock; } - - /// Methods accessible to GusdStageCacheReader. - /// These require only a shared lock to the stage. - - UsdStageRefPtr OpenNewStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UsdStagePopulationMask* mask, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - SdfLayerRefPtr CreateSessionLayer(const GusdStageEdit& edit, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - SdfLayerRefPtr FindOrOpenLayer(const UT_StringRef& path, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - UsdStageRefPtr FindStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit) const; - - UsdStageRefPtr FindOrOpenStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - UsdStageRefPtr FindMaskedStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const SdfPath& primPath); - - UsdStageRefPtr FindOrOpenMaskedStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const SdfPath& primPath, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Open a new stage with an explicit mask. - /// This is used when externally requesting a set of prims, so that - /// prims may still be loaded behind masks, but in a batch that allows - /// them to share the same stage. - UsdStageRefPtr OpenMaskedStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UsdStagePopulationMask& mask, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Load each prim from \p primPaths from the cache, writing resulting - /// UsdPrim instances to \p prim. The \p paths and \p edits arrays are - /// indexed at the same element from \p primPaths being loaded. - /// Although the cache attempts to batch prims together when it's possible - /// for them to share the same stage, there are no guarantees that prims - /// returned by this method will be sharing the same stage. - bool LoadPrims(const GusdDefaultArray& paths, - const UT_Array& primPaths, - const GusdDefaultArray& edits, - UsdPrim* prims, - const GusdStageOpts& opts, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Variant of the above method when a range of prims is being pulled from - /// a common stage configuration. - bool LoadPrims(const UT_StringHolder& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - DEP_MicroNode* FindStageMicroNode(const UsdStagePtr& stage); - - DEP_MicroNode* GetStageMicroNode(const UsdStagePtr& stage); - - - /// Methods accessible to GusdStageCacheWriter. - /// These require an exclusive lock to the stage. - - void Clear(bool propagateDirty=false); - void Clear(const UT_StringSet& paths, bool propagateDirty=false); - - void AddDataCache(GusdUSD_DataCache& cache) - { - UT_AutoLock lock(_dataCacheLock); - _dataCaches.append(&cache); - } - - void RemoveDataCache(GusdUSD_DataCache& cache) - { - UT_AutoLock lock(_dataCacheLock); - exint idx = _dataCaches.find(&cache); - if(idx >= 0) - _dataCaches.removeIndex(idx); - } - - void FindStages(const UT_StringSet& paths, - UT_Set& stages) const; - - void InsertStage(UsdStageRefPtr &stage, - const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit); - - /// Load a range of [start,end) prims from the cache. The range corresponds - /// to a *subset* of the prims in \p primPaths. - /// The \p rangeFn functor must implement `operator()(exint)` which, given - /// an index of an element in the range [start,end), returns the index in - /// \p primPaths identifying which primitive should be loaded. - /// The resulting UsdPrim is written into \p prims at the same index. - /// - /// If \p sev is less than UT_ERROR_ABORT, prim loading will continue even - /// after load errors have occurred. - template - bool LoadPrimRange(const PrimRangeFn& rangeFn, - exint start, exint end, - const UT_StringHolder& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Returns an SdfPath referring to the defaultPrim defined on the layer. - /// Returns an empty SdfPath if the layer either defines no defaultPrim, - /// or if the defaultPrim is invalid. - SdfPath GetDefaultPrimPath(const UT_StringRef& path, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - -protected: - /// Expand the set of masked prims on a stage. - void _ExpandStageMask(UsdStageRefPtr& stage); - - /// Get a range of prims from \p stage, using the same range - /// encoding as LoadPrimRange. - template - bool _GetPrimsInRange(const PrimRangeFn& rangeFn, - exint start, exint end, - const UsdStageRefPtr& stage, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - -private: - using _StageMap = UT_ConcurrentHashMap<_StageKey,UsdStageRefPtr, - _StageKeyHashCmp>; - - using _MaskedStageCacheMap = - UT_ConcurrentHashMap<_StageKey, - GusdStageCache::_MaskedStageCache*, - _StageKeyHashCmp>; - - struct _StageHashCmp - { - static bool equal(const UsdStagePtr& a, const UsdStagePtr& b) - { return a == b; } - - static bool hash(const UsdStagePtr& stage) - { return SYShash(stage); } - }; - - - using _MicroNodeMap = - UT_ConcurrentHashMap, - _StageHashCmp>; - - /// Mutex around the concurrent maps. - /// An exclusive lock must be acquired when iterating over the maps. - UT_RWLock _mapLock; - - /// Data cache mutex. - /// Must be acquired when accessing data caches in any way. - UT_Lock _dataCacheLock; - - /// Cache of stages without any masks. - _StageMap _stageMap; - /// Cache of sub-caches for masked stages. - _MaskedStageCacheMap _maskedCacheMap; - - /// Cache of micro nodes for layers (created on request only). - _MicroNodeMap _microNodeMap; - - UT_Array _dataCaches; -}; - - -GusdStageCache::_Impl::~_Impl() -{ - // Clear entries, but don't propagate dirty states, as we - // cannot guarantee that state propagation is safe. - Clear(/*propagateDirty*/ false); -} - - -UsdStageRefPtr -GusdStageCache::_Impl::OpenNewStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UsdStagePopulationMask* mask, - UT_ErrorSeverity sev) -{ - // Catch Tf errors. - GusdTfErrorScope errorScope(sev); - - // TODO: Should consider including the context as a member of the - // stage opts, so that it can be reconfigured across different hip files. - ArResolverContext resolverContext = ArGetResolver().GetCurrentContext(); - ArResolverContextBinder binder(resolverContext); - - // The root layer is shared, and not modified. - if(SdfLayerRefPtr rootLayer = FindOrOpenLayer(path, sev)) { - - // Need a unique session layer on which to apply any edits. - SdfLayerRefPtr sessionLayer; - if(edit) { - sessionLayer = CreateSessionLayer(*edit); - if(!sessionLayer) - return TfNullPtr; - } - - UsdStageRefPtr stage = - mask ? UsdStage::OpenMasked(rootLayer, sessionLayer, - resolverContext, - *mask, opts.GetLoadSet()) - : UsdStage::Open(rootLayer, sessionLayer, - resolverContext, opts.GetLoadSet()); - - if(stage) { - if(edit) { - // Edits must apply on the session layer. - stage->SetEditTarget(UsdEditTarget(sessionLayer)); - - if(!edit->Apply(stage, sev)) { - return TfNullPtr; - } - - stage->SetEditTarget(UsdEditTarget(rootLayer)); - } - - if(mask) - _ExpandStageMask(stage); - return stage; - } else { - GUSD_GENERIC_ERR(sev).Msg( - "Failed opening stage @%s@", path.c_str()); - } - } - return TfNullPtr; -} - - -SdfLayerRefPtr -GusdStageCache::_Impl::CreateSessionLayer(const GusdStageEdit& edit, - UT_ErrorSeverity sev) -{ - static const std::string layerTag("GusdStageCache_SessionLayer.usda"); - - if(SdfLayerRefPtr layer = SdfLayer::CreateAnonymous(layerTag)) - return edit.Apply(layer, sev) ? layer : TfNullPtr; - - GUSD_GENERIC_ERR(sev).Msg("Internal error creating session layer."); - return TfNullPtr; -} - - -namespace { - - -/// Returns true if \p prim is a reasonable encapsulating model -/// at which to expand a stage population mask. -bool -_ShouldExpandPopulationMaskAtPrim(const UsdPrim& prim) -{ - // It's reasonable to treat models as valid encapsulation points - // for mask expansion. It is not, however, reasonable to expand - // at groups: Under model hierarchy rules, all ancestors of prims - // with a 'group'-derived kind must also be groups, so expanding - // by group-derived kinds would lead us to expand to the full stage. - return prim.IsModel() && !prim.IsGroup(); - - // XXX: A possible alternative to the above rule is to expand - // to prims of 'component'-derived kinds. This rule has been deactiveated - // for now because we also wish to consider cameras as reasonable - // expansion points, but cameras are not currently component-derived. - // - // TfToken kind; - // return UsdModelAPI(prim).GetKind(&kind) && - // KindRegistry::IsA(kind, KindTokens->component); -} - - -/// Expand the prim paths in \p mask to include ancestor prims of -/// the existing mask that appear to be reasonable 'encapsulating models' -/// of their child prims. Returns true if the population mask was modified, -/// or false otherwise. -bool -_ExpandPopulationMaskToEncapsulatingModels(const UsdStageRefPtr& stage) -{ - UT_ASSERT_P(stage); - - bool didChangeMask = false; - - const auto modelSearchPredicate = - UsdPrimIsDefined && UsdPrimIsModel - && UsdPrimIsActive && !UsdPrimIsAbstract; - - UsdStagePopulationMask mask = stage->GetPopulationMask(); - - // Iterate over ancestor prims at each masked path, - // looking for possible points at which to expand the mask. - UsdPrimRange range = stage->Traverse(modelSearchPredicate); - for(auto it = range.begin(); it != range.end(); ++it) { - - if(mask.IncludesSubtree(it->GetPath())) { - // Don't traverse beneath the masking points, because - // masking guarantees that subtrees of the masking points - // are fully expanded and present. - it.PruneChildren(); - continue; - } - - if (_ShouldExpandPopulationMaskAtPrim(*it)) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] Expanding population mask of masked stage " - "@%s@ to the encapsulating prim at <%s>.\n", - stage->GetRootLayer()->GetIdentifier().c_str(), - it->GetPath().GetText()); - - mask.Add(it->GetPath()); - - didChangeMask = true; - - // Since this location is included in the mask, don't - // need to consider any of its descendants. - it.PruneChildren(); - } - } - - if (didChangeMask) - stage->SetPopulationMask(mask); - - return didChangeMask; -} - - -/// Check if there are any models on \p stage that can be considered as -/// valid 'encapsulating models'. -bool -_StageContainsEncapsulatingModels(const UsdStageRefPtr& stage) -{ - const auto modelSearchPredicate = - UsdPrimIsDefined && UsdPrimIsModel - && UsdPrimIsActive && !UsdPrimIsAbstract; - - for (const UsdPrim& prim : stage->Traverse(modelSearchPredicate)) { - if (_ShouldExpandPopulationMaskAtPrim(prim)) { - return true; - } - } - return false; -} - - -} // namespace - - -void -GusdStageCache::_Impl::_ExpandStageMask(UsdStageRefPtr& stage) -{ - UT_ASSERT_P(stage); - UT_ASSERT_P(!stage->GetPopulationMask().IsEmpty()); - - if (TfGetEnvSetting(GUSD_STAGEMASK_EXPANDMODELS)) { - - // Expand the population mask to include enclosing model prims. - // This expansion can help limit the number of masked stages being - // created on the cache. For instance, if the user attempted to load - // individual leaf prim paths, we might otherwise end up creating a new - // masked stage for each of those leaf prims. By expanding the mask to - // common, encapsulating ancestor prims, we are able to still allow only - // a subset of a stage to be loaded, but while ensuring that some stages - // can be shared across multiple prims that live beneath a common, - // encapsulating model. - - if (!_ExpandPopulationMaskToEncapsulatingModels(stage)) { - - // Couldn't expand the population mask at any encapsulating models. - // This might mean that the encapsulating models are descendants of - // the already-masked prim paths. Find out if that's the case. - // (Note that unlike the above attempt at prim mask expansion, - // which traversed from the root of stage down to the masked prim - // paths, this traverses *beneath* the masking sites. - - if (!_StageContainsEncapsulatingModels(stage)) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] Masked stage @%s@ has no encapsulating " - "models either above or beneath the masking site. " - "Expanding to a complete stage.\n", - stage->GetRootLayer()->GetIdentifier().c_str()); - - // We were not able to find any encapsulating models -- either - // in prims already present on the masked stage, or at ancestor - // prims. This can happen if a stage isn't defining a proper - // model hierarchy with 'kind' metadata, or if a stage is using - // a non-standard kind hierarchy. Rather than risking creating a - // stage per leaf-prim queried from the cache -- which is very - // non-scalable! -- it's better to expand the population mask to - // the full stage. - stage->SetPopulationMask(UsdStagePopulationMask::All()); - return; - } - } - } - - if (TfGetEnvSetting(GUSD_STAGEMASK_EXPANDRELS)) { - // Expand the population mask to include relationship targets. - // TODO: This currently will test all relationships, and may be very - // expensive. For performance, it may be necessary to limit the set - // of relationships that are searched (skipping, say, shaders). - stage->ExpandPopulationMask(); - } -} - - -SdfLayerRefPtr -GusdStageCache::_Impl::FindOrOpenLayer(const UT_StringRef& path, - UT_ErrorSeverity sev) -{ - // Catch Tf errors. - GusdTfErrorScope errorScope(sev); - - SdfLayerRefPtr layer = SdfLayer::FindOrOpen(path.toStdString()); - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::FindOrOpenLayer] Returning layer %s for @%s@\n", - (layer ? layer->GetIdentifier().c_str() : "(null)"), path.c_str()); - - if(!layer) { - GUSD_GENERIC_ERR(sev).Msg("Failed opening layer @%s@", path.c_str()); - } - - return layer; -} - - -UsdStageRefPtr -GusdStageCache::_Impl::FindStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit) const -{ - // XXX: empty paths should be caught earlier. - UT_ASSERT_P(path); - - _StageMap::const_accessor a; - if(_stageMap.find(a, _StageKey(UTmakeUnsafeRef(path), opts, edit))) - return a->second; - return TfNullPtr; -} - - -UsdStageRefPtr -GusdStageCache::_Impl::FindOrOpenStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - UT_ErrorSeverity sev) -{ - if(UsdStageRefPtr stage = FindStage(path, opts, edit)) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::FindOrOpenStage] Returning %s for @%s@\n", - UsdDescribe(stage).c_str(), path.c_str()); - - return stage; - } - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::FindOrOpenStage] Cache miss for @%s@\n", - path.c_str()); - - _StageMap::accessor a; - if(_stageMap.insert(a, _StageKey(path, opts, edit))) { - - a->second = OpenNewStage(path, opts, edit, /*mask*/ nullptr, sev); - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::FindOrOpenStage] Returning %s for @%s@\n", - UsdDescribe(a->second).c_str(), path.c_str()); - - if(!a->second) { - _stageMap.erase(a); - return TfNullPtr; - } - } - return a->second; -} - - -UsdStageRefPtr -GusdStageCache::_Impl::FindOrOpenMaskedStage(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const SdfPath& primPath, - UT_ErrorSeverity sev) -{ - // XXX: empty paths and invalid prim paths should be caught earlier. - UT_ASSERT_P(path); - UT_ASSERT_P(_IsValidPrimPath(primPath)); - - if(primPath == SdfPath::AbsoluteRootPath() || - !TfGetEnvSetting(GUSD_STAGEMASK_ENABLE)) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] Load a complete stage for @%s@\n", path.c_str()); - - // Access full stages. - return FindOrOpenStage(path, opts, edit, sev); - } - - // May have an unmasked stage that matches our criteria. - // If so, no need to create a masked stage, as the unmasked - // stage will contain everything we need. - - if(UsdStageRefPtr stage = FindStage(path, opts, edit)) - return stage; - - // Look for an existing masked stage. - { - _MaskedStageCacheMap::const_accessor a; - if(_maskedCacheMap.find( - a, _StageKey(UTmakeUnsafeRef(path), opts, edit))) { - UT_ASSERT_P(a->second); - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] Found existing masked stage cache " - "for @%s@<%s>\n", path.c_str(), primPath.GetText()); - - bool loadedFullStage = false; - UsdStageRefPtr stage = - a->second->FindOrOpenStage(primPath, &loadedFullStage, sev); - - if (loadedFullStage) { - // Despite trying to load a masked stage, the entire stage - // has been loaded. Store this stage on the non-masked stage - // map so that all future cache lookups will find it. - _StageMap::accessor stageMapAcc; - if (_stageMap.insert( - stageMapAcc, _StageKey(path, opts, edit))) { - stageMapAcc->second = stage; - } - } - - return stage; - } - } - - // Make a new sub cache to hold the masked stages - // for this stage configuration. - _MaskedStageCacheMap::accessor a; - _StageKey newKey(path, opts, edit); - if(_maskedCacheMap.insert(a, newKey)) { - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache] No existing masked stage cache " - "for @%s@<%s>. Creating a new subcache.\n", - path.c_str(), primPath.GetText()); - - a->second = new GusdStageCache::_MaskedStageCache(*this, newKey); - } - - UT_ASSERT_P(a->second); - - bool loadedFullStage = false; - UsdStageRefPtr stage = - a->second->FindOrOpenStage(primPath, &loadedFullStage, sev); - - if (loadedFullStage) { - // Same case as above. - _StageMap::accessor stageMapAcc; - if (_stageMap.insert(stageMapAcc, _StageKey(path, opts, edit))) { - stageMapAcc->second = stage; - } - } - return stage; -} - - -template -bool -GusdStageCache::_Impl::_GetPrimsInRange(const PrimRangeFn& rangeFn, - exint start, exint end, - const UsdStageRefPtr& stage, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev) -{ - // XXX: Could do this in parallel, but profiling suggests it's not worth it. - - UT_AutoInterrupt task("Get prims from stage"); - - char bcnt = 0; - - for(exint i = start; i < end; ++i) { - if(ARCH_UNLIKELY(!++bcnt && task.wasInterrupted())) - return false; - - exint primIndex = rangeFn(i); - UT_ASSERT_P(primIndex >= 0 && primIndex < primPaths.size()); - - const SdfPath& primPath = primPaths(primIndex); - if(!primPath.IsEmpty()) { - prims[primIndex] = - GusdUSD_Utils::GetPrimFromStage(stage, primPath, sev); - if(!prims[primIndex] && sev >= UT_ERROR_ABORT) { - return false; - } - } - } - return !task.wasInterrupted(); -} - - -template -bool -GusdStageCache::_Impl::LoadPrimRange(const PrimRangeFn& rangeFn, - exint start, exint end, - const UT_StringHolder& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev) -{ - // XXX: Empty paths should be caught earlier. - UT_ASSERT(path); - - if(start == end) - return true; - - bool useFullStage = !TfGetEnvSetting(GUSD_STAGEMASK_ENABLE); - if(!useFullStage) { - // Check if any of the prims in the range are the absolute root; - // If so, we should load a complete stage. - for(exint i = start; i < end; ++i) { - if(primPaths(rangeFn(i)) == SdfPath::AbsoluteRootPath()) { - useFullStage = true; - break; - } - } - } - - if(useFullStage) { - if(UsdStageRefPtr stage = FindOrOpenStage(path, opts, edit, sev)) { - return _GetPrimsInRange(rangeFn, start, end, - stage, primPaths, prims, sev); - } else { - // Whether or not this is an error depends on the - // reporting severity. - return sev < UT_ERROR_ABORT; - } - } - - { - // Find an existing _MaskedStageCache for this configuration. - - _MaskedStageCacheMap::const_accessor a; - if(_maskedCacheMap.find( - a, _StageKey(UTmakeUnsafeRef(path), opts, edit))) { - UT_ASSERT_P(a->second); - return a->second->LoadPrimRange(rangeFn, start, end, - primPaths, prims, sev); - } - } - - // Make a new sub cache to hold the masked stages - // for this stage configuration. - _MaskedStageCacheMap::accessor a; - _StageKey newKey(path, opts, edit); - if(_maskedCacheMap.insert(a, newKey)) - a->second = new GusdStageCache::_MaskedStageCache(*this, newKey); - UT_ASSERT_P(a->second); - return a->second->LoadPrimRange(rangeFn, start, end, primPaths, prims, sev); -} - - -SdfPath -GusdStageCache::_Impl::GetDefaultPrimPath(const UT_StringRef& path, - UT_ErrorSeverity sev) -{ - // Catch Tf errors. - GusdTfErrorScope errorScope(sev); - - // TODO: Should consider including the context as a member of the - // stage opts, so that it can be reconfigured across different hip files. - ArResolverContext resolverContext = ArGetResolver().GetCurrentContext(); - ArResolverContextBinder binder(resolverContext); - - // Open layer with metadataOnly to reduce parsing costs. - // TODO: The cache will likely need to do a full layer parse with - // SdfLayer::FindOrOpen() shortly after this point. Would be better to find - // a way of loading the layer once, and sharing the result downstream. - if (const SdfLayerRefPtr layer = - SdfLayer::OpenAsAnonymous(path.toStdString(), /*metadataOnly*/ true)) { - const TfToken name = layer->GetDefaultPrim(); - if (SdfPath::IsValidIdentifier(name)) { - return SdfPath::AbsoluteRootPath().AppendChild(name); - } else { - GUSD_GENERIC_ERR(sev).Msg( - "No valid defaultPrim defined in layer @%s@", path.c_str()); - } - } else { - GUSD_GENERIC_ERR(sev).Msg("Failed opening layer @%s@", path.c_str()); - } - return SdfPath(); -} - - -namespace { - - -/// Key used in batched prim loading. -/// This identifies the stage for a prim, as well the index that the -/// entry maps into inside of a range during batched loads. -struct _PrimLoadKey -{ - _PrimLoadKey() = default; - - _PrimLoadKey(const UT_StringHolder& path, - const GusdStageEditPtr& edit, - exint primIndex) - : path(path), edit(edit), primIndex(primIndex) {} - - /// Check if a prim loaded with this key can be loaded on the same - /// stage as a prim loaded for key \p o. - bool CanShareStage(const _PrimLoadKey& o) const - { return edit == o.edit && path == o.path; } - - bool operator<(const _PrimLoadKey& o) const - { - UT_ASSERT_P(path); - UT_ASSERT_P(o.path); - return path < o.path || - (path == o.path && - (edit < o.edit || - (edit == o.edit && primIndex < o.primIndex))); - } - - UT_StringHolder path; - GusdStageEditPtr edit; - exint primIndex; -}; - - -/// Object holding a set of prim load keys. -/// This object is compatible as a range functor on the the LoadPrimRange() -/// methods of the cache. -struct _PrimLoadRange -{ - exint operator()(exint i) const { return keys(i).primIndex; } - - /// Sort the load keys. This is done in order to - /// produce contiguous load sets. - void Sort(); - - /// Compute ranges of elements in the array that share the same stage. - void ComputeSharedStageRanges( - UT_Array >& ranges) const; - - UT_Array<_PrimLoadKey> keys; -}; - - -void -_PrimLoadRange::Sort() -{ - UTparallelSort::iterator>( - keys.begin(), keys.end()); -} - - -void -_PrimLoadRange::ComputeSharedStageRanges( - UT_Array >& ranges) const -{ - if(keys.size() == 0) - return; - - exint start = 0; - auto prev = keys(0); - - for(exint i = 1; i < keys.size(); ++i) { - if(!keys(i).CanShareStage(prev)) { - ranges.emplace_back(start, i); - prev = keys(i); - start = i; - } - } - // Handle the last entry. - ranges.emplace_back(start, keys.size()); -} - - -} // namespace - - -bool -GusdStageCache::_Impl::LoadPrims( - const GusdDefaultArray& paths, - const UT_Array& primPaths, - const GusdDefaultArray& edits, - UsdPrim* prims, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - const exint count = primPaths.size(); - if(count == 0) { - return true; - } - - UT_AutoInterrupt task("Load USD prims"); - - if(paths.IsConstant() && !paths.GetDefault()) { - // No file paths, so will get back only invalid prims. - return true; - } - - if(paths.IsConstant() && edits.IsConstant()) { - // Optimization: all file paths and edits are the same, - // so prims can be pulled from the same stage. - return LoadPrims(paths.GetDefault(), opts, - edits.GetDefault(), primPaths, prims, sev); - } - - UT_ASSERT(edits.IsConstant() || edits.size() == count); - UT_ASSERT(paths.IsConstant() || paths.size() == count); - - // Build up keys for loading. - - _PrimLoadRange primRange; - primRange.keys.setCapacity(count); - for(exint i = 0; i < count; ++i) { - // Only include valid entries. - if(paths(i) && _IsValidPrimPath(primPaths(i))) { - primRange.keys.emplace_back(paths(i), edits(i), i); - } - } - - // Sort the entries. This means that all entries that should reference - // the same stage -- I.e., the same (path,edit) pair -- will be - // contiguous on the array. - primRange.Sort(); - - // Identify the ranges of prims that may be able to share the same stage. - UT_Array > ranges; - primRange.ComputeSharedStageRanges(ranges); - - // We now have contiguous ranges of prims, identifying which - // prims can be loaded on the same stage. - // Dispatch across these ranges to load prims. - - std::atomic_bool workerInterrupt(false); - - GusdErrorTransport errTransport; - - UTparallelFor( - UT_BlockedRange(0, ranges.size()), - [&](const UT_BlockedRange& r) - { - GusdAutoErrorTransport autoErrTransport(errTransport); - - auto* boss = UTgetInterrupt(); - - for(size_t i = r.begin(); i < r.end(); ++i) { - if(ARCH_UNLIKELY(boss->opInterrupt() || workerInterrupt)) { - return; - } - - const auto& range = ranges(i); - - // Can get the file/edit from the first key in the range. - const auto& key = primRange.keys(range.first); - - if(!LoadPrimRange(primRange, range.first, range.second, - key.path, opts, key.edit, - primPaths, prims, sev)) { - // Interrupt the other worker threads. - workerInterrupt = true; - break; - } - } - }); - - return !task.wasInterrupted() && !workerInterrupt; -} - - -namespace { - - -struct _IdentityPrimRangeFn -{ - exint operator()(exint i) const { return i; } -}; - - -} /*namespace*/ - - -bool -GusdStageCache::_Impl::LoadPrims(const UT_StringHolder& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev) -{ - if(!path) { - // Not an error: no prims are loaded. - return true; - } - - // Optimization: - // May already have a full stage loaded that we can reference. - if(UsdStageRefPtr stage = FindStage(path, opts, edit)) { - return _GetPrimsInRange(_IdentityPrimRangeFn(), 0, primPaths.size(), - stage, primPaths, prims, sev); - } - - return LoadPrimRange(_IdentityPrimRangeFn(), 0, primPaths.size(), - path, opts, edit, primPaths, prims, sev); -} - - -DEP_MicroNode* -GusdStageCache::_Impl::GetStageMicroNode(const UsdStagePtr& stage) -{ - if(!stage) - return nullptr; - - { - _MicroNodeMap::const_accessor a; - if(_microNodeMap.find(a, stage)) - return a->second.get(); - } - - _MicroNodeMap::accessor a; - if(_microNodeMap.insert(a, stage)) - a->second.reset(new _StageChangeMicroNode(stage)); - return a->second.get(); -} - - -void -GusdStageCache::_Impl::Clear(bool propagateDirty) -{ - // XXX: Caller should have an exclusive map lock! - - _stageMap.clear(); - - for(auto& pair : _maskedCacheMap) - delete pair.second; - _maskedCacheMap.clear(); - - { - UT_AutoLock lock(_dataCacheLock); - for(auto* cache : _dataCaches) { - UT_ASSERT_P(cache); - cache->Clear(); - } - _dataCaches.clear(); - } - - if(propagateDirty) { - for(auto& pair : _microNodeMap) { - pair.second->SetDirty(); - } - } - _microNodeMap.clear(); -} - - -void -GusdStageCache::_Impl::Clear(const UT_StringSet& paths, bool propagateDirty) -{ - // XXX: Caller should have an exclusive map lock! - - UT_Array<_StageKey> keysToRemove; - UT_Set stagesBeingRemoved; - - for(const auto& pair : _stageMap) { - if(paths.contains(pair.first.GetPath())) { - keysToRemove.append(pair.first); - stagesBeingRemoved.insert(pair.second); - } - } - for(const auto& key : keysToRemove) - _stageMap.erase(key); - - keysToRemove.clear(); - for(auto& pair : _maskedCacheMap) { - if(paths.contains(pair.first.GetPath())) { - keysToRemove.append(pair.first); - pair.second->GetStages(stagesBeingRemoved); - delete pair.second; - } - } - for(const auto& key : keysToRemove) - _maskedCacheMap.erase(key); - - // Update and clear micro nodes. - for(const UsdStageRefPtr& stage : stagesBeingRemoved) { - - if(propagateDirty) { - _MicroNodeMap::accessor a; - if(_microNodeMap.find(a, stage)) { - a->second->SetDirty(); - } - } - _microNodeMap.erase(stage); - } - - - { - UT_AutoLock lock(_dataCacheLock); - for(auto* cache : _dataCaches) { - UT_ASSERT_P(cache); - cache->Clear(paths); - } - } -} - - -void -GusdStageCache::_Impl::FindStages(const UT_StringSet& paths, - UT_Set& stages) const -{ - // Unmasked stages. - for(const auto& pair : _stageMap) { - if(paths.contains(pair.first.GetPath())) { - stages.insert(pair.second); - } - } - // Masked stages. - for(const auto& pair : _maskedCacheMap) { - if(paths.contains(pair.first.GetPath())) { - UT_ASSERT_P(pair.second); - pair.second->GetStages(stages); - } - } -} - - -void -GusdStageCache::_Impl::InsertStage(UsdStageRefPtr &stage, - const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit) -{ - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::InsertStage] Inserting stage @%s@\n", - path.c_str()); - - _StageMap::accessor a; - if(stage && _stageMap.insert(a, _StageKey(path, opts, edit))) { - a->second = stage; - } -} - - -UsdStageRefPtr -GusdStageCache::_MaskedStageCache::FindStage(const SdfPath& primPath) -{ - UT_ASSERT_P(_IsValidPrimPath(primPath)); - - _StageMap::const_accessor ancestorAcc; - if(_map.find(ancestorAcc, primPath)) - return ancestorAcc->second; - - // The cache holds a map of primPath->stage. When a prim is loaded - // with masking, all of its descendant prims are fully loaded. - // So, to find a stage that has our prim, we only need to find an - // existing stage that has one of our ancestors. - - if (primPath.IsAbsolutePath()) { - int distanceToMatchingAncestor = 1; - for(SdfPath ancestorPath = primPath.GetParentPath(); - ancestorPath != SdfPath::AbsoluteRootPath(); - ancestorPath = ancestorPath.GetParentPath(), - ++distanceToMatchingAncestor) { - - if(_map.find(ancestorAcc, ancestorPath)) { - // Insert an entry on the cache for this prim if we traversed - // further than we would like to find a loaded prim, - // in order to speed up future lookups. - // We don't always store a new entry because that might - // flood the cache, harming rather than improving lookups. - - const int maxSearchDistance = 4; // Non-scientific guess. - if(distanceToMatchingAncestor > maxSearchDistance) { - _StageMap::accessor primAcc; - if(_map.insert(primAcc, primPath)) - primAcc->second = ancestorAcc->second; - return primAcc->second; - } - return ancestorAcc->second; - } - } - } - return TfNullPtr; -} - - -UsdStageRefPtr -GusdStageCache::_MaskedStageCache::FindOrOpenStage(const SdfPath& primPath, - bool* loadedFullStage, - UT_ErrorSeverity sev) -{ - if(UsdStageRefPtr stage = FindStage(primPath)) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::_MaskedStageCache::FindOrOpenStage] Returning " - "%s for <%s>\n", UsdDescribe(stage).c_str(), primPath.GetText()); - - return stage; - } - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::_MaskedStageCache::FindOrOpenStage] " - "Cache miss for <%s>\n", primPath.GetText()); - - _StageMap::accessor a; - if(_map.insert(a, primPath)) { - - SdfPath maskPath = primPath; - if (!primPath.IsAbsolutePath()) { - // Expecting defaultPrim. - UT_ASSERT_P(primPath == GusdUSD_Utils::GetDefaultPrimIdentifier()); - maskPath = _GetDefaultPrimPath(sev); - if (maskPath.IsEmpty() && sev >= UT_ERROR_ABORT) { - _map.erase(a); - return TfNullPtr; - } - } - - const UsdStagePopulationMask mask(std::vector({maskPath})); - - a->second = _OpenStage(mask, primPath, sev); - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::_MaskedStageCache::FindOrOpenStage] " - "Returning %s for <%s>\n", UsdDescribe(a->second).c_str(), - primPath.GetText()); - - if(!a->second) { - _map.erase(a); - return TfNullPtr; - } - - // Check if the masked stage was expanded to the full stage. - static const UsdStagePopulationMask maskAll( - UsdStagePopulationMask::All()); - - UT_ASSERT_P(loadedFullStage); - *loadedFullStage = (a->second->GetPopulationMask() == maskAll); - } - return a->second; -} - - -UsdStageRefPtr -GusdStageCache::_MaskedStageCache::_OpenStage( - const UsdStagePopulationMask& mask, - const SdfPath& invokingPrimPath, - UT_ErrorSeverity sev) -{ - UsdStageRefPtr stage = - _stageCache.OpenNewStage(_stageKey.GetPath(), _stageKey.GetOpts(), - _stageKey.GetEdit(), &mask, sev); - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::_MaskedStageCache::_OpenStage] " - "%p -- Opened stage %s\n", this, UsdDescribe(stage).c_str()); - - if(stage) { - // Make sure that all paths included in the mask are - // mapped on the cache. - // Pull the stage mask from the stage itself when doing this, - // since the mask may have been expanded to include more prims - // than our initial mask. - for(const auto& maskedPath : stage->GetPopulationMask().GetPaths()) { - - // If the stage is being opened via FindOrOpenStage(), we already - // have an accessor with exclusive write access at the - // invokingPrimPath. The mutex on element access in not recursive, - // so be careful to avoid attempting to re-lock that same prim, - // or else we'll hit a deadlock. - - if(maskedPath != invokingPrimPath) { - _StageMap::accessor other; - if(_map.insert(other, maskedPath)) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::_MaskedStageCache::_OpenStage] " - "%p -- Mapping prim <%s> to stage %s\n", - this, maskedPath.GetText(), UsdDescribe(stage).c_str()); - - other->second = stage; - } - } - } - // Determine if the mask included the stage's defaultPrim. - // If so, place an entry for the generic 'defaultPrim' path on the map. - if (stage->GetDefaultPrim()) { - // Just like the above case, take care to avoid deadlocks; the - // invokingPrimPath is already locked. - if (GusdUSD_Utils::GetDefaultPrimIdentifier() != invokingPrimPath) { - _StageMap::accessor acc; - if (_map.insert( - acc, GusdUSD_Utils::GetDefaultPrimIdentifier())) { - - TF_DEBUG(GUSD_STAGECACHE).Msg( - "[GusdStageCache::_MaskedStageCache::_OpenStage] " - "%p -- Mapping defaultPrim to stage %s\n", - this, UsdDescribe(stage).c_str()); - - acc->second = stage; - } - } - } - } - return stage; -} - - -SdfPath -GusdStageCache::_MaskedStageCache::_GetDefaultPrimPath( - UT_ErrorSeverity sev) const -{ - return _stageCache.GetDefaultPrimPath(_stageKey.GetPath(), sev); -} - - -template -bool -GusdStageCache::_MaskedStageCache::LoadPrimRange( - const PrimRangeFn& rangeFn, - exint start, exint end, - const UT_Array& primPaths, - UsdPrim* prims, - UT_ErrorSeverity sev) -{ - if(start == end) - return true; - - UT_ASSERT_P(end > start); - UT_ASSERT_P(prims); - - // Extract prims that can be found on existing stages. - // If the prims can't be found, append them to arrays for batched loading. - UT_Array primIndicesForBatchedLoad; - std::vector primPathsForBatchedLoad; - - for(exint i = start; i < end; ++i) { - exint primIndex = rangeFn(i); - UT_ASSERT_P(primIndex >= 0 && primIndex < primPaths.size()); - - const SdfPath& primPath = primPaths(primIndex); - if(!primPath.IsEmpty()) { - if(UsdStageRefPtr stage = FindStage(primPath)) { - prims[primIndex] = - GusdUSD_Utils::GetPrimFromStage(stage, primPath, sev); - if(!prims[primIndex] && sev >= UT_ERROR_ABORT) - return false; - } else { - // No existing stage may contain this prim. - // Append to the mask for batched loading. - primIndicesForBatchedLoad.append(primIndex); - if (primPath.IsAbsolutePath()) { - primPathsForBatchedLoad.emplace_back(primPath); - } else { - // Path must refer to the defaultPrim. - UT_ASSERT_P(primPath == - GusdUSD_Utils::GetDefaultPrimIdentifier()); - - // Lookup the actual defaultPrim from the layer, and add - // it to the batched load set. - const SdfPath defaultPrimPath = _GetDefaultPrimPath(sev); - - if (!defaultPrimPath.IsEmpty()) { - primPathsForBatchedLoad.emplace_back(defaultPrimPath); - } else if (sev >= UT_ERROR_ABORT) { - return false; - } - } - } - } - } - - if(primPathsForBatchedLoad.size() > 0) { - UT_ASSERT_P(primIndicesForBatchedLoad.size() == - primPathsForBatchedLoad.size()); - - // Open a stage with a mask holding all currently unloaded prims. - if(UsdStageRefPtr stage = - _OpenStage(UsdStagePopulationMask( - std::move(primPathsForBatchedLoad)), - SdfPath(), sev)) { - - // Get all prims in the range. - for(exint i = 0; i < primIndicesForBatchedLoad.size(); ++i) { - exint primIndex = primIndicesForBatchedLoad(i); - const SdfPath& primPath = primPaths(primIndex); - - UT_ASSERT_P(!primPath.IsEmpty()); - - prims[primIndex] = - GusdUSD_Utils::GetPrimFromStage(stage, primPath, sev); - - if(!prims[primIndex] && sev >= UT_ERROR_ABORT) - return false; - - // Map this prim onto the cache so that future prim lookups will - // return this stage. This is also needed in order for the cache - // to take ownership of the stage. - _StageMap::accessor acc; - _map.insert(acc, primPath); - acc->second = stage; - } - } else { - if(sev >= UT_ERROR_ABORT) - return false; - } - } - return true; -} - - -GusdStageCache& -GusdStageCache::GetInstance() -{ - static GusdStageCache cache; - return cache; -} - - -GusdStageCache::GusdStageCache() - : _impl(new _Impl) -{} - - -GusdStageCache::~GusdStageCache() -{ - delete _impl; -} - - -void -GusdStageCache::AddDataCache(GusdUSD_DataCache& cache) -{ - _impl->AddDataCache(cache); -} - - -void -GusdStageCache::RemoveDataCache(GusdUSD_DataCache& cache) -{ - _impl->RemoveDataCache(cache); -} - - -GusdStageCacheReader::GusdStageCacheReader(GusdStageCache& cache, bool writer) - : _cache(cache), _writer(writer) -{ - if(writer) - _cache._impl->GetMapLock().writeLock(); - else - _cache._impl->GetMapLock().readLock(); -} - - -GusdStageCacheReader::~GusdStageCacheReader() -{ - if(_writer) - _cache._impl->GetMapLock().writeUnlock(); - else - _cache._impl->GetMapLock().readUnlock(); -} - - -UsdStageRefPtr -GusdStageCacheReader::Find(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit) const -{ - return path ? _cache._impl->FindStage(path, opts, edit) : TfNullPtr; -} - - -UsdStageRefPtr -GusdStageCacheReader::FindOrOpen(const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit, - UT_ErrorSeverity sev) -{ - return path ? _cache._impl->FindOrOpenStage( - path, opts, edit, sev) : TfNullPtr; -} - - -DEP_MicroNode* -GusdStageCacheReader::GetStageMicroNode(const UsdStagePtr& stage) -{ - return _cache._impl->GetStageMicroNode(stage); -} - - -GusdStageCacheReader::PrimStagePair -GusdStageCacheReader::GetPrim(const UT_StringRef& path, - const SdfPath& primPath, - const GusdStageEditPtr& edit, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - PrimStagePair pair; - if (path && _IsValidPrimPath(primPath)) { - if((pair.second = _cache._impl->FindOrOpenMaskedStage( - path, opts, edit, primPath, sev))) { - - pair.first = - GusdUSD_Utils::GetPrimFromStage(pair.second, primPath, sev); - } - - } - return pair; -} - - -GusdStageCacheReader::PrimStagePair -GusdStageCacheReader::GetPrimWithVariants(const UT_StringRef& path, - const SdfPath& primPath, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - GusdStageEditPtr edit; - SdfPath primPathWithoutVariants; - GusdStageEdit::GetPrimPathAndEditFromVariantsPath( - primPath, primPathWithoutVariants, edit); - return GetPrim(path, primPathWithoutVariants, edit, opts, sev); -} - - -GusdStageCacheReader::PrimStagePair -GusdStageCacheReader::GetPrimWithVariants(const UT_StringRef& path, - const UT_StringRef& primPath, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - if(primPath) { - SdfPath usdPrimPath; - if(GusdUSD_Utils::CreateSdfPath(primPath, usdPrimPath, sev)) - return GetPrimWithVariants(path, usdPrimPath, opts, sev); - } - return PrimStagePair(); -} - - -GusdStageCacheReader::PrimStagePair -GusdStageCacheReader::GetPrimWithVariants(const UT_StringRef& path, - const SdfPath& primPath, - const SdfPath& variants, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - GusdStageEditPtr edit; - if(variants.ContainsPrimVariantSelection()) { - edit.reset(new GusdStageEdit); - edit->GetVariants().append(variants); - } - return GetPrim(path, primPath, edit, opts, sev); -} - - -GusdStageCacheReader::PrimStagePair -GusdStageCacheReader::GetPrimWithVariants(const UT_StringRef& path, - const UT_StringRef& primPath, - const UT_StringRef& variants, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - if(primPath) { - SdfPath sdfPrimPath, sdfVariants; - if(GusdUSD_Utils::CreateSdfPath(primPath, sdfPrimPath, sev) && - GusdUSD_Utils::CreateSdfPath(variants, sdfVariants, sev)) { - return GetPrimWithVariants(path, sdfPrimPath, - sdfVariants, opts, sev); - } - } - return PrimStagePair(); -} - - -bool -GusdStageCacheReader::GetPrims( - const GusdDefaultArray& filePaths, - const UT_Array& primPaths, - const GusdDefaultArray& edits, - UsdPrim* prims, - const GusdStageOpts& opts, - UT_ErrorSeverity sev) -{ - return _cache._impl->LoadPrims(filePaths, primPaths, - edits, prims, opts, sev); -} - - -GusdStageCacheWriter::GusdStageCacheWriter(GusdStageCache& cache) - : GusdStageCacheReader(cache, /*writer*/ true) -{} - - -void -GusdStageCacheWriter::Clear() -{ - _cache._impl->Clear(/*propagateDirty*/ true); -} - - -void -GusdStageCacheWriter::Clear(const UT_StringSet& paths) -{ - _cache._impl->Clear(paths, /*propagateDirty*/ true); -} - - -void -GusdStageCacheWriter::FindStages(const UT_StringSet& paths, - UT_Set& stages) -{ - _cache._impl->FindStages(paths, stages); -} - - -void -GusdStageCacheWriter::InsertStage(UsdStageRefPtr &stage, - const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit) -{ - _cache._impl->InsertStage(stage, path, opts, edit); -} - -void -GusdStageCacheWriter::ReloadStages(const UT_StringSet& paths) -{ - UT_Set stages; - FindStages(paths, stages); - - UT_Set stagePtrs; - for(const auto& refPtr : stages) - stagePtrs.insert(UsdStagePtr(refPtr)); - - GusdStageCache::ReloadStages(stagePtrs); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/stageCache.h b/third_party/houdini/gusd/stageCache.h deleted file mode 100644 index 8456c076ef..0000000000 --- a/third_party/houdini/gusd/stageCache.h +++ /dev/null @@ -1,360 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_STAGE_CACHE_H -#define GUSD_STAGE_CACHE_H - -#include -#include -#include - -#include "defaultArray.h" -#include "stageEdit.h" -#include "stageOpts.h" -#include "USD_Utils.h" - -#include "pxr/pxr.h" -#include "pxr/usd/sdf/layer.h" -#include "pxr/usd/usd/stage.h" - - -class DEP_MicroNode; -class UT_StringHolder; -class UT_StringSet; - - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdUSD_DataCache; -class UsdPrim; - -/// Cache for USD stages. -/// Clients interact with the cache via the GusdStageCacheReader -/// and GusdStageCacheWriter classes. -class GUSD_API GusdStageCache -{ -public: - GusdStageCache(); - - ~GusdStageCache(); - - GusdStageCache(const GusdStageCache&) = delete; - - GusdStageCache& operator=(const GusdStageCache&) = delete; - - static GusdStageCache& GetInstance(); - - /// Add/remove auxiliary data caches. - /// Auxiliary data caches are cleared in response to changes - /// to stages on this cache. - /// @{ - void AddDataCache(GusdUSD_DataCache& cache); - - void RemoveDataCache(GusdUSD_DataCache& cache); - /// @} - - /// \section GusdStageCache_Reloading Reloading - /// - /// Stages and layers may be reloaded during an active session, but it's - /// important to understand the full implications of doing so. - /// When a layer is reloaded, change notifications are sent to any stages - /// referencing that layer, causing those stages to recompose, if necessary. - /// This operation is not thread-safe, and may result in a crash if another - /// thread is attempting to read from an affected stage at the same time. - /// Further, it must be noted that simply loading stages within separate - /// GusdStageCache instances also does not mean that that change - /// propopagation will be isolated only to stages of the stage cache - /// instance: Although it is possible to isolate the effect of changes - /// on the root layers of stages to some extent, secondary layers -- such - /// as sublayers and reference arcs -- are shared on a global cache. - /// The effect of reloading layers is _global_ and _immediate_. - /// - /// Rather than attempting to solve this problem with intrusive and - /// expensive locking -- which would only solve the problem for stages - /// held internally in a GusdStageCache, not for stages referenced from - /// other caches -- we prefer to address the problem by requiring that - /// reloading only be performed at certain points of Houdini's main event - /// loop, where it is known to be safe. - /// An example of a 'safe' way to exec stage reloads is via a callback - /// triggered by a button in a node's GUI. - /// Users should never attempt to reload stages or layers during node - /// cook methods. - - /// Mark a set of stages for reload on the event queue. - static void ReloadStages(const UT_Set& stages); - - /// Mark a set of layers for reload on the event queue. - static void ReloadLayers(const UT_Set& layers); - - -private: - class _MaskedStageCache; - - class _Impl; - _Impl* const _impl; - - friend class GusdStageCacheReader; - friend class GusdStageCacheWriter; -}; - - -/// Helper for reading from a GusdStageCache. -/// Cache readers can both open existing stages on the cache, -/// as well as cause additional stages to be inserted into the cache. -/// Cache readers cannot clear out any existing stages or mutate -/// auxiliary data caches. -/// -/// Example usage: -/// @code -/// GusdStageCacheReader cache; -/// -/// // Pull a stage from the cache. -/// UsdStageRefPtr stage = cache.FindOrOpen(stagePath); -/// -/// // Access a prim on the cache. -/// UsdPrim prim = cache.GetPrim(stagePath, primPath).first; -/// -/// // Access a prim with a variant selection. -/// SdfPath primPath("/foo{variant=sel}bar"); -/// UsdPrim prim = cache.GetPrim(stagePath, primPath); -/// @endcode -class GUSD_API GusdStageCacheReader -{ -public: - using PrimStagePair = std::pair; - - /// Construct a reader for the cache singleton. - GusdStageCacheReader(GusdStageCache& cache=GusdStageCache::GetInstance()) - : GusdStageCacheReader(cache, false) {} - - GusdStageCacheReader(const GusdStageCacheReader&) = delete; - - GusdStageCacheReader& operator=(const GusdStageCacheReader&) = delete; - - ~GusdStageCacheReader(); - - /// Find an existing stage on the cache. - UsdStageRefPtr - Find(const UT_StringRef& path, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - const GusdStageEditPtr& edit=nullptr) const; - - /// Return a stage from the cache, if one exists. - /// If not, attempt to open the stage and add it to the cache. - /// If \p path is a non-empty path and stage opening fails, errors - /// are reporting to the currently scoped error manager at a severity - /// of \p sev. - UsdStageRefPtr - FindOrOpen(const UT_StringRef& path, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - const GusdStageEditPtr& edit=nullptr, - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Get a micro node for a stage. - /// Micro nodes are created on demand, and are dirtied both for - /// stage reloading and cache evictions. - DEP_MicroNode* - GetStageMicroNode(const UsdStagePtr& stage); - - /// \section Prim Accessors - /// - /// These helpers return prims on masked stages, where only the - /// parts of the stage required to produce a given prim are composed. - /// This helps support workflows such as setting variants on packed prims, - /// where either many stage mutations may be made that conflict with each - /// other, or in isolation, such that different mutations can't be made - /// to share stages without intrusive locking. - /// In all cases, if a full stage which satisfies the stage options and - /// edits has already been loaded on the cache, the prim will fetched from - /// that stage instead. - /// - /// This use of masking may be disabled by way of the GUSD_STAGEMASK_ENABLE - /// environment variable, but beware that doing so may significantly degrade - /// performance for certain access patterns, such as if many separate prims - /// are being queried from the cache with different stage edits. - /// - /// \subsection Primitive Encapsulation - /// - /// Because primitives are masked to include a subset of a stage, - /// there is an expectation that the caller follows _encapsulation_ rules. - /// When we read in a prim, we consider that prim to be encapsulated, - /// which means that if any other primitives from the stage are required - /// to process an encapsulated primitive, they are expected to either - /// be descendants or ancestors of the encapsulated prim, or the dependency - /// to that external prim must be discoverable using either relationships - /// or attribute connections. - /// Following those encapsulation rules, neither _siblings_ of the prim - /// being requested, nor other prims in separate branches of the stage - /// are guaranteed to be loaded. Any attempt to reach other prims that - /// can't be discovered using the above rules for discovering dependencies - /// may either fail or introduce non-deterministic behavior. - - /// Get a prim from the cache, on a masked stage. - /// If \p path and \p primPath are both valid, and either a stage load - /// error occurs or no prim can be found, errors are reported on the - /// currently scoped error manager at a severity of \p sev. - /// If \p primPath is equal to 'defaultPrim', the stage's defaultPrim - /// is returned. - /// If \p primPath is equal to '/', the entire stage is loaded, - /// and the pseudo-root is returned. - PrimStagePair - GetPrim(const UT_StringRef& path, - const SdfPath& primPath, - const GusdStageEditPtr& stageEdit=GusdStageEditPtr(), - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Get multiple prims from the cache (in parallel). - /// If the configured error severity is less than UT_ERROR_ABORT, - /// prim loading will continue even after load errors have occurred. - /// If any stage load errors occur, or if any prims cannot be found, errors - /// are reported on the currently scoped error manager with a severity of - /// \p sev. If \p sev is less than UT_ERROR_ABORT, prim loading will - /// continue even when errors occur for some prims. Otherwise, loading - /// aborts upon the first error. - /// If a path in \p primPaths is equal to `defaultPrim`, the stage's - /// defaultPrim will be returned for that element. - /// If a path in \p primPaths is equal to `/` -- I.e., the absolute root -- - /// then the full stage of the corresponding element is loaded, and the - /// pseudo-root is returned. - bool - GetPrims(const GusdDefaultArray& filePaths, - const UT_Array& primPaths, - const GusdDefaultArray& edits, - UsdPrim* prims, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Get a prim from the cache, given a prim path that may contain - /// variant selections. This is a convenience method for the common case - /// of accessing a prim given parameters for just a file path and - /// prim path. - /// If \p primPath is equal to 'defaultPrim', the stage's defaultPrim - /// is returned. - /// If \p primPath is equal to `/`, the entire stage is loaded, - /// and the pseudo-root is returned. - /// @{ - PrimStagePair - GetPrimWithVariants(const UT_StringRef& path, - const SdfPath& primPath, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - PrimStagePair - GetPrimWithVariants(const UT_StringRef& path, - const UT_StringRef& primPath, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - /// Different variations of the above the variants are stored separately. - PrimStagePair - GetPrimWithVariants(const UT_StringRef& path, - const SdfPath& primPath, - const SdfPath& variants, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - UT_ErrorSeverity sev=UT_ERROR_ABORT); - - PrimStagePair - GetPrimWithVariants(const UT_StringRef& path, - const UT_StringRef& primPath, - const UT_StringRef& variants, - const GusdStageOpts& opts=GusdStageOpts::LoadAll(), - UT_ErrorSeverity sev=UT_ERROR_ABORT); - /// @} - -protected: - GusdStageCacheReader(GusdStageCache& cache, bool writer); - -protected: - GusdStageCache& _cache; - const bool _writer; -}; - - -/// Write accessor for a stage cache. -/// Write accessors have all of the capabilities of readers, -/// and can also remove elements from the cache and manipulate -/// child data caches. -/// Writers gain exclusive locks to the cache, and should be used sparingly. -class GUSD_API GusdStageCacheWriter : public GusdStageCacheReader -{ -public: - GusdStageCacheWriter(GusdStageCache& cache=GusdStageCache::GetInstance()); - - GusdStageCacheWriter(const GusdStageCacheWriter&) = delete; - - GusdStageCacheWriter& operator=(const GusdStageCacheWriter&) = delete; - - /// Find all stages on the cache matching the given paths. - /// Multiple stages may be found for each path. - void FindStages(const UT_StringSet& paths, - UT_Set& stages); - - /// Insert a stage into our cache. The lifetime of this stage is not - /// fully controlled by this cache. The cache is just a holder for the - /// stage for as long as the gusd library is allowed access to it (until - /// it is destroyed by the external owner, which must then call Clear() - /// with the same path. - void InsertStage(UsdStageRefPtr &stage, - const UT_StringRef& path, - const GusdStageOpts& opts, - const GusdStageEditPtr& edit); - - /// \section GusdStageCacheWriter_ReloadAndClear Reloading And Clearing - /// - /// During active sessions, the contents of a cache may be refreshed - /// by either reloading a subset of the stages that it contains, or by - /// removing stage entries from the cache. - /// In either case, if a stage is reloaded or evicted from the cache, - /// and if that stage has a micro node - /// (see: \ref GusdStageCacheReader::GetMicroNode), then that micro - /// node, and any OP_Node instances that reference it, are dirtied. - /// This means that any nodes whose cook is based on data from a cached - /// stage will properly update in response to Clear()/Reload() actions. - /// - /// \warn Dirty state propagation is not thread safe, and should only be - /// called at a safe point on the main thread, such as through a callback - /// triggered by a UI button. Also note that there may be side effects - /// from reloading stages that affect stages from *other caches*. See - /// \ref GusdStageCache_Reloading for more information on the caveats of - /// reloading. - - /// Clear out all cached items. - /// Note that layers are owned by a different cache, and may stay - /// active beyond this point. - void Clear(); - - /// Variant of Clear() that causes any stages whose root layer has - /// an asset path in the \p paths set to be removed from the cache. - void Clear(const UT_StringSet& paths); - - /// Reload all stages matching the given paths. - void ReloadStages(const UT_StringSet& paths); - -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /*GUSD_STAGE_CACHE_H*/ diff --git a/third_party/houdini/gusd/stageEdit.cpp b/third_party/houdini/gusd/stageEdit.cpp deleted file mode 100644 index 1d5df8640b..0000000000 --- a/third_party/houdini/gusd/stageEdit.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "stageEdit.h" - -#include "USD_Utils.h" - -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -bool -GusdStageEdit::Apply(const SdfLayerHandle& layer, - UT_ErrorSeverity sev) const -{ - SdfChangeBlock changeBlock; - - UT_ASSERT_P(layer); - for(const auto& variantsPath : _variants) - GusdUSD_Utils::SetVariantsFromPath(variantsPath, layer); - return true; -} - - -bool -GusdStageEdit::Apply(const UsdStagePtr& stage, - UT_ErrorSeverity sev) const -{ - UT_ASSERT_P(stage); - - stage->MuteAndUnmuteLayers( - _layersToMute, /*unmute*/ std::vector()); - return true; -} - - -size_t -GusdStageEdit::GetHash() const -{ - size_t hash = SYShashRange(_variants.begin(), _variants.end()); - SYShashCombine(hash, SYShashRange(_layersToMute.begin(), - _layersToMute.end())); - return hash; -} - - -bool -GusdStageEdit::operator==(const GusdStageEdit& o) const -{ - return _variants == o._variants && _layersToMute == o._layersToMute; -} - - -void -GusdStageEdit::GetPrimPathAndEditFromVariantsPath( - const SdfPath& pathWithVariants, - SdfPath& primPath, - GusdStageEditPtr& edit) -{ - SdfPath variants; - GusdUSD_Utils::ExtractPrimPathAndVariants(pathWithVariants, - primPath, variants); - if(!variants.IsEmpty()) { - if(!edit) - edit.reset(new GusdStageEdit); - edit->GetVariants().append(variants); - } -} - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/stageEdit.h b/third_party/houdini/gusd/stageEdit.h deleted file mode 100644 index 815e2bcb57..0000000000 --- a/third_party/houdini/gusd/stageEdit.h +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_STAGE_EDIT_H -#define GUSD_STAGE_EDIT_H - -#include "api.h" - -#include "pxr/pxr.h" -#include "pxr/usd/sdf/path.h" -#include "pxr/usd/sdf/layer.h" -#include "pxr/usd/usd/stage.h" - -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -using GusdStageEditPtr = UT_IntrusivePtr; - - -/// Basic stage edit covering common types of edits. -/// -/// This class provides a single point for describing all of the common -/// types of edits so that, at least in the typical cases, code pulling -/// data from the stage cache are using a common type of edit. -/// -/// Note that when applying variant edits, variant selection paths should be -/// stripped of any trailing path components following the variant selection. -/// For example, rather than creating an edit applying variant selection -/// `/foo{a=b}bar`, it is better to use path `/foo{a=b}` as the variant -/// selection path. The GetPrimPathAndEditFromVariantsPath helper automatically -/// strips all such trailing path components. -class GUSD_API GusdStageEdit - : public UT_IntrusiveRefCounter -{ -public: - - /// Extract a prim path and an edit from a path string, - /// which may include variant selections. - /// This covers the common case where a single parameter - /// provides a prim path, which may include variant selections - /// (Eg., as /foo{variant=sel}bar). - static void - GetPrimPathAndEditFromVariantsPath(const SdfPath& pathWithVariants, - SdfPath& primPath, - GusdStageEditPtr& edit); - - bool Apply(const SdfLayerHandle& layer, - UT_ErrorSeverity sev=UT_ERROR_ABORT) const; - - bool Apply(const UsdStagePtr& stage, - UT_ErrorSeverity sev=UT_ERROR_ABORT) const; - - size_t GetHash() const; - - bool operator==(const GusdStageEdit& o) const; - - const UT_Array& GetVariants() const - { return _variants; } - - UT_Array& GetVariants() - { return _variants; } - - const std::vector& GetLayersToMute() const - { return _layersToMute; } - - std::vector& GetLayersToMute() - { return _layersToMute; } - -private: - UT_Array _variants; - std::vector _layersToMute; -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_STAGE_EDIT_H*/ diff --git a/third_party/houdini/gusd/stageOpts.cpp b/third_party/houdini/gusd/stageOpts.cpp deleted file mode 100644 index 48f46cb001..0000000000 --- a/third_party/houdini/gusd/stageOpts.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "stageOpts.h" - -#include - - -GusdStageOpts::GusdStageOpts(UsdStage::LoadSet loadSet) - : _loadSet(loadSet) -{} - - -size_t -GusdStageOpts::GetHash() const -{ - return SYShash(_loadSet); -} diff --git a/third_party/houdini/gusd/stageOpts.h b/third_party/houdini/gusd/stageOpts.h deleted file mode 100644 index a11ae28081..0000000000 --- a/third_party/houdini/gusd/stageOpts.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_STAGE_OPTS_H -#define GUSD_STAGE_OPTS_H - -#include - -#include "api.h" - -#include "pxr/pxr.h" -#include "pxr/usd/usd/stage.h" - - -PXR_NAMESPACE_OPEN_SCOPE - - -/// Options for configuring creation of a new stage. -/// This currently just includes the initial load set, -/// but may include other options in the future. -class GUSD_API GusdStageOpts -{ -public: - using InitialLoadSet = UsdStage::InitialLoadSet; - - GusdStageOpts(const GusdStageOpts& o) = default; - - GusdStageOpts(InitialLoadSet loadSet=UsdStage::LoadAll) - : _loadSet(loadSet) {} - - /// Return options that a configure a stage to be loaded with payloads. - static GusdStageOpts LoadAll() - { return GusdStageOpts(UsdStage::LoadAll); } - - /// Return options that a configure a stage to be loaded without payloads. - static GusdStageOpts LoadNone() - { return GusdStageOpts(UsdStage::LoadNone); } - - InitialLoadSet GetLoadSet() const - { return _loadSet; } - - void SetLoadSet(InitialLoadSet loadSet) - { _loadSet = loadSet; } - - size_t GetHash() const - { return SYShash(_loadSet); } - - bool operator==(const GusdStageOpts& o) const - { return _loadSet == o._loadSet; } - -private: - InitialLoadSet _loadSet; -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /*GUSD_STAGE_OPTS_H*/ diff --git a/third_party/houdini/gusd/testenv/testGusdErrors.cpp b/third_party/houdini/gusd/testenv/testGusdErrors.cpp deleted file mode 100644 index fef32e7bbf..0000000000 --- a/third_party/houdini/gusd/testenv/testGusdErrors.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include -#include -#include - -#include - -#include "gusd/error.h" - -#include "pxr/base/tf/stringUtils.h" - - -PXR_NAMESPACE_USING_DIRECTIVE - - -template -void _TestBasicErrorFn(UT_ErrorSeverity sev, - const FN1& oneArgFn, - const FN2& twoArgFn) -{ - { - UT_ErrorManager::Scope scope; - oneArgFn("foo"); - - TF_AXIOM(scope.getSeverity() == sev); - TF_AXIOM(sev == UT_ERROR_NONE || GusdGetErrors() == "foo"); - } - { - UT_ErrorManager::Scope scope; - twoArgFn("foo %s", "bar"); - - TF_AXIOM(scope.getSeverity() == sev); - TF_AXIOM(sev == UT_ERROR_NONE || GusdGetErrors() == "foo bar"); - } -} - - -const char* -_ConstructStringNeverReached() -{ - // Should never reach this point. This indicates that GUSD_GENERIC_ERR - // is failing to elide its message-posting as expected. - TF_AXIOM(false); - - return "invalid"; -} - - -/// Test basic error posting helpers. -void _TestGusdBasicErrors() -{ - std::cout << "Testing basic error reporting" << std::endl; - - _TestBasicErrorFn(UT_ERROR_ABORT, - [](const char* msg) - { GUSD_ERR().Msg(msg); }, - [](const char* fmt, const char* arg) - { GUSD_ERR().Msg(fmt, arg); }); - - _TestBasicErrorFn(UT_ERROR_WARNING, - [](const char* msg) - { GUSD_WARN().Msg(msg); }, - [](const char* fmt, const char* arg) - { GUSD_WARN().Msg(fmt, arg); }); - - _TestBasicErrorFn(UT_ERROR_MESSAGE, - [](const char* msg) - { GUSD_MSG().Msg(msg); }, - [](const char* fmt, const char* arg) - { GUSD_MSG().Msg(fmt, arg); }); - - for(int i = 0; i < UT_NUM_ERROR_SEVERITIES; ++i) { - UT_ErrorSeverity sev = static_cast(i); - _TestBasicErrorFn(sev, - [&](const char* msg) - { GUSD_GENERIC_ERR(sev).Msg(msg); }, - [&](const char* fmt, const char* arg) - { GUSD_GENERIC_ERR(sev).Msg(fmt, arg); }); - } - - // GUSD_GENERIC_ERR with UT_ERROR_NONE should not end up - // invoking any code that builds the error string. - { - UT_ErrorManager::Scope scope; - GUSD_GENERIC_ERR(UT_ERROR_NONE).Msg(_ConstructStringNeverReached()); - } -} - - -void _TestGusdErrorTransport() -{ - std::cout << "Test GusdErrorTransport" << std::endl; - - // Basic parallel transport test. - { - UT_ErrorManager::Scope scope; - - GusdErrorTransport transport; - - auto fn = [&]() { - UT_ErrorManager::Scope threadScope; - - // XXX: Sleep to trick tbb into thinking this is an expensive - // task. Otherwise it might run single-threaded. - sleep(1); - GusdAutoErrorTransport autoTransport(transport); - GUSD_ERR().Msg("error"); - }; - - UTparallelInvoke(true, fn, fn); - - TF_AXIOM(scope.getErrorManager().getNumErrors() == 2); - std::string msg = GusdGetErrors(); - TF_AXIOM(TfStringContains(msg, "error")); - } -} - - -void _TestGusdTfErrorScope() -{ - std::cout << "Test GusdTfErrorScope" << std::endl; - - // Severity is user-configured. Test each severity level. - for(int i = UT_ERROR_MESSAGE; i < UT_NUM_ERROR_SEVERITIES; ++i) { - - auto sev = static_cast(i); - - UT_ErrorManager::Scope scope; - { - GusdTfErrorScope tfErrScope(sev); - TF_CODING_ERROR("(coding error)"); - TF_RUNTIME_ERROR("(runtime error)"); - } - TF_AXIOM(scope.getErrorManager().getNumErrors() == 2); - TF_AXIOM(scope.getSeverity() == sev); - TF_AXIOM(TfStringContains(GusdGetErrors(), "(coding error)")); - TF_AXIOM(TfStringContains(GusdGetErrors(), "(runtime error)")); - } - - // Setting severity of NONE means errors are ignored. - { - UT_ErrorManager::Scope scope; - { - GusdTfErrorScope tfErrScope(UT_ERROR_NONE); - TF_CODING_ERROR("(coding error)"); - TF_RUNTIME_ERROR("(runtime error)"); - } - TF_AXIOM(scope.getErrorManager().getNumErrors() == 0); - TF_AXIOM(scope.getSeverity() == UT_ERROR_NONE); - } - - // Test workaround for errors containing '<>' chars, which normally - // won't display in node MMB menus due to HTML formatting. - { - UT_ErrorManager::Scope scope; - { - GusdTfErrorScope tfErrScope; - TF_CODING_ERROR(""); - } - TF_AXIOM(TfStringContains(GusdGetErrors(), "[foo]")); - } -} - - -int main(int argc, char* argv[]) -{ - static UT_Interrupt boss("testGusdError"); - boss.setEnabled(1,1); - UTsetInterrupt(&boss); - - _TestGusdBasicErrors(); - _TestGusdErrorTransport(); - _TestGusdTfErrorScope(); - - return 0; -} diff --git a/third_party/houdini/gusd/testenv/testGusdStageCache/defaultPrim.usda b/third_party/houdini/gusd/testenv/testGusdStageCache/defaultPrim.usda deleted file mode 100644 index a4a5290f82..0000000000 --- a/third_party/houdini/gusd/testenv/testGusdStageCache/defaultPrim.usda +++ /dev/null @@ -1,15 +0,0 @@ -#usda 1.0 -( - defaultPrim = "DefaultPrim" -) - -def "DefaultPrim" ( - kind = "assembly" -) -{ - def Scope "Child" ( - kind = "component" - ) - { - } -} \ No newline at end of file diff --git a/third_party/houdini/gusd/testenv/testGusdStageCache/test.usda b/third_party/houdini/gusd/testenv/testGusdStageCache/test.usda deleted file mode 100644 index d13d2f402c..0000000000 --- a/third_party/houdini/gusd/testenv/testGusdStageCache/test.usda +++ /dev/null @@ -1,50 +0,0 @@ -#usda 1.0 - - -def "Root" ( - kind = "assembly" -) -{ - def Scope "Component" ( - kind = "component" - ) - { - def "A" - { - } - - def "B" - { - rel dependency = - } - } - - def "NonReferencedPrim" { - } - - def "ComponentlessHierarchy" - { - } - - def "ExternalDependency" - { - } - - def "ModelWithVariants" ( - variants = { - string var = "A" - } - add variantSets = "var" - ) - { - variantSet "var" = { - "A" {} - "B" {} - "C" {} - } - } -} - -def "Root2" -{ -} \ No newline at end of file diff --git a/third_party/houdini/gusd/testenv/testGusdStageCache/test2.usda b/third_party/houdini/gusd/testenv/testGusdStageCache/test2.usda deleted file mode 100644 index 97b8892606..0000000000 --- a/third_party/houdini/gusd/testenv/testGusdStageCache/test2.usda +++ /dev/null @@ -1,23 +0,0 @@ -#usda 1.0 - -def "A" ( - kind = "assembly" -) -{ - def Scope "Child" ( - kind = "component" - ) - { - } -} - -def "B" ( - kind = "assembly" -) -{ - def Scope "Child" ( - kind = "component" - ) - { - } -} diff --git a/third_party/houdini/gusd/testenv/testGusdStageCache/test3.usda b/third_party/houdini/gusd/testenv/testGusdStageCache/test3.usda deleted file mode 100644 index fd90b096af..0000000000 --- a/third_party/houdini/gusd/testenv/testGusdStageCache/test3.usda +++ /dev/null @@ -1,23 +0,0 @@ -#usda 1.0 - -def "C" ( - kind = "assembly" -) -{ - def Scope "Child" ( - kind = "component" - ) - { - } -} - -def "D" ( - kind = "assembly" -) -{ - def Scope "Child" ( - kind = "component" - ) - { - } -} diff --git a/third_party/houdini/gusd/testenv/testGusdStageCache/testGusdStageCache.py b/third_party/houdini/gusd/testenv/testGusdStageCache/testGusdStageCache.py deleted file mode 100644 index 6ea8a0132b..0000000000 --- a/third_party/houdini/gusd/testenv/testGusdStageCache/testGusdStageCache.py +++ /dev/null @@ -1,432 +0,0 @@ -# -# Copyright 2018 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. - -# XXX: The try-except block here is a workaround for -# Pixar-internal build system issues. -try: - from pxr import Gusd -except ImportError: - import Gusd - -from pxr import Sdf, Tf -import unittest - - -def FindOrOpen(cache, path, **kwargs): - stage = cache.FindOrOpen(path, **kwargs) - assert stage - - assert cache.Find(path, **kwargs) == stage - - # Repeating the same query should give the same answer. - assert cache.FindOrOpen(path, **kwargs) == stage - - # The cached stage should be discoverable by FindStages(). - assert stage in cache.FindStages([path]) - - return stage - - -def GetPrim(cache, path, primPath, **kwargs): - primPath = Sdf.Path(primPath) - - prim,stage = cache.GetPrim(path, primPath, **kwargs) - assert prim - assert stage - assert prim.GetPath() == primPath - - # Repeating the same query should give the same answer. - prim2,stage2 = cache.GetPrim(path, primPath, **kwargs) - assert prim2 == prim - assert stage2 == stage - - # The cached stage should be discoverable by FindStages(). - assert stage in cache.FindStages([path]) - - return (prim,stage) - - -class TestGusdStageCache(unittest.TestCase): - - def test_FindOrOpen(self): - """ - Tests basic Find() and FindOrOpen() queries. - """ - path = "test.usda" - cache = Gusd.StageCache() - - assert not cache.Find(path) - - stage = FindOrOpen(cache, path) - - # Stages use LoadAll by default. - # Querying with LoadNone should give a different stage. - - assert not cache.Find(path, opts=Gusd.StageOpts.LoadNone()) - - stage2 = FindOrOpen(cache, path, opts=Gusd.StageOpts.LoadNone()) - assert stage2 - assert stage2 != stage - - # Likewise, stage edits also form a unique part of the - # cache key, and should return different stages. - edit = Gusd.StageEdit.New() - edit.SetVariants([Sdf.Path("/foo{a=b}")]) - - assert not cache.Find(path, edit=edit) - stage3 = FindOrOpen(cache, path, edit=edit) - assert stage3 - assert stage3 != stage and stage3 != stage2 - - - def test_StageMaskComponentExpansion(self): - """ - Tests kind-based population mask expansion. - """ - if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"): - return - - path = "test.usda" - cache = Gusd.StageCache() - - prim,stage = GetPrim(cache, path, "/Root/Component/A") - - # Mask should have been expanded to include full /Root/Component. - assert Sdf.Path("/Root/Component") in \ - stage.GetPopulationMask().GetPaths() - - # Make sure the mask composed prims as expected. - assert stage.GetPrimAtPath("/Root/Component/B") - assert not stage.GetPrimAtPath("/Root/NonReferencedPrim") - assert not stage.GetPrimAtPath("/Root2") - - if not Tf.GetEnvSetting("GUSD_STAGEMASK_EXPANDRELS"): - assert not stage.GetPrimAtPath("/Root/ExternalDependency") - - - def test_StageMaskDependencyExpansion(self): - """ - Tests dependency based (rels, attr connections) population expansion. - """ - if not (Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE") and - Tf.GetEnvSetting("GUSD_STAGEMASK_EXPANDRELS")): - return - - path = "test.usda" - cache = Gusd.StageCache() - - prim,stage = GetPrim(cache, path, "/Root/Component/B") - - # External prim should have been detected as a dependency and - # included in the mask. - assert Sdf.Path("/Root/ExternalDependency") in \ - stage.GetPopulationMask().GetPaths() - - # Make sure the mask composed prims as expected. - assert stage.GetPrimAtPath("/Root/ExternalDependency") - assert not stage.GetPrimAtPath("/Root/NonReferencedPrim") - assert not stage.GetPrimAtPath("/Root2") - - - def test_StageMaskDescendantComponentExpansion(self): - """ - Tests kind-based population mask expansion when expanding - a primitve that contains a descendant that is a component. - """ - if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"): - return - - path = "test.usda" - cache = Gusd.StageCache() - - prim,stage = GetPrim(cache, path, "/Root") - - # Since /Root contains a component prim, expansion should - # have gone no further than /Root. - - assert stage.GetPopulationMask().GetPaths() == [Sdf.Path("/Root")] - - # Make sure the mask composed prims as expected. - assert stage.GetPrimAtPath("/Root") - assert not stage.GetPrimAtPath("/Root2") - - - def test_StageMaskRootExpansion(self): - """ - Test the fallback behavior of expanding to the root in - componentless hierarchcies. - """ - if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"): - return - - path = "test.usda" - cache = Gusd.StageCache() - - prim,stage = GetPrim(cache, path, "/Root/ComponentlessHierarchy") - - # Since there's no component as an ancestor or descendant - # of this prim, we should have expanded out to the full stage. - assert stage.GetPopulationMask().GetPaths() == \ - [Sdf.Path.absoluteRootPath] - - # Make sure the mask composed prims as expected. - assert stage.GetPrimAtPath("/Root") - assert stage.GetPrimAtPath("/Root2") - - - def test_StageMaskPreemption(self): - """ - Test that the presence of a full stage on the cache preempts - the use of masked stage queries. - """ - if not Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"): - return - - path = "test.usda" - cache = Gusd.StageCache() - - # Pre-populate a complete stage on the cache. - stage = FindOrOpen(cache, path) - - # Individual prim queries should now return the same stage. - assert GetPrim(cache, path, "/Root/Component")[1] == stage - assert GetPrim(cache, path, "/Root/NonReferencedPrim")[1] == stage - assert GetPrim(cache, path, "/Root/ExternalDependency")[1] == stage - assert GetPrim(cache, path, "/Root/ModelWithVariants")[1] == stage - - - def test_GetPrim(self): - """ - Tests basic stage mask queries. - """ - path = "test.usda" - cache = Gusd.StageCache() - - prim,stage = GetPrim(cache, path, "/Root") - - # Querying any descendant prims should give the same stage, - # regardless of whatever masking behavior is enabled. - assert GetPrim(cache, path, "/Root/Component")[1] == stage - assert GetPrim(cache, path, "/Root/NonReferencedPrim")[1] == stage - assert GetPrim(cache, path, "/Root/ExternalDependency")[1] == stage - assert GetPrim(cache, path, "/Root/ModelWithVariants")[1] == stage - - - def test_GetPrims(self): - """ - Tests cache's GetPrims() methods for pulling in multiple prims - across different stages, with different edits. - """ - - cache = Gusd.StageCache() - - # Input spec has arbitrary ordering, and a mix of complete and - # incomplete specs (null file or prim paths) - paths = ["test2.usda", "", "test2.usda", "test3.usda", "test2.usda", "test3.usda"] - primPaths = [Sdf.Path(), "/foo", "/A", "/C", "/B", "/D"] - - prims = cache.GetPrims(paths, primPaths) - - self.assertEqual(len(prims), len(primPaths)) - - # First two elems should be invalid (this is not an error!) - self.assertFalse(prims[0]) - self.assertFalse(prims[1]) - - # The remaining prims should be present - self.assertTrue(all(prims[2:])) - - # Validate that all *valid* prims are what we expect. - validPrims = prims[2:] - validPrimPaths = primPaths[2:] - self.assertTrue( - all(validPrims[i].GetPath() == Sdf.Path(validPrimPaths[i]) - for i in xrange(len(validPrims)))) - - # Prims should have been batched during loading, so prims referring - # to the same stage on the input spec should be referencing - # the same stage. Note that this is only true on a fresh cache, - # since some prims may otherwise refer to previously cached stages. - self.assertEqual(prims[2].GetStage(), prims[4].GetStage()) - self.assertEqual(prims[3].GetStage(), prims[5].GetStage()) - - - def test_GetPrims_StageMaskPreemption(self): - """ - Test that the presence of a full stage on the cache preempts - the use of masked stage queries, using the GetPrims() method. - """ - - cache = Gusd.StageCache() - - stage = cache.FindOrOpen("test2.usda") - - paths = ["test2.usda", "test2.usda"] - primPaths = ["/A", "/B"] - - prims = cache.GetPrims(paths, primPaths) - - self.assertTrue(all(p.GetStage() == stage) for p in prims) - - - def test_GetPrimWithVariants(self): - """ - Tests queries of prims with variant selections. - """ - path = "test.usda" - cache = Gusd.StageCache() - - primPath = Sdf.Path("/Root/ModelWithVariants") - variantNames = ("A", "B", "C") - - prims = set() - for name in variantNames: - variants = primPath.AppendVariantSelection("var",name) - - prim,stage = cache.GetPrimWithVariants(path, primPath, - variants=variants) - assert prim.GetVariantSets().GetVariantSelection("var") == name - - prims.add(prim) - - # Should have ended up with unique prims, each on their own stage. - # And if that is true, no prims will have expired. - assert(all(prims)) - - - def test_GetDefaultPrim(self): - """ - Tests prim queries using defaultPrim. - """ - path = "defaultPrim.usda" - cache = Gusd.StageCache() - - defaultPrimPath = Sdf.Path("/DefaultPrim") - - prim,stage = cache.GetPrim(path, "defaultPrim") - self.assertTrue(stage) - self.assertEqual(prim.GetPath(), defaultPrimPath) - - prim,stage = cache.GetPrimWithVariants(path, "defaultPrim") - self.assertTrue(stage) - self.assertEqual(prim.GetPath(), defaultPrimPath) - - paths = [path, path] - primPaths = [defaultPrimPath, defaultPrimPath] - prims = cache.GetPrims(paths, primPaths) - self.assertTrue(all(p.GetPath() == defaultPrimPath for p in prims)) - - # If we query a child of the defaultPrim, the cache - # should utilize the same stage. - childPath = Sdf.Path("/DefaultPrim/Child") - childPrim,childStage = cache.GetPrim(path, childPath) - self.assertEqual(childPrim.GetPath(), childPath) - self.assertEqual(childStage, stage) - - - def test_Clear(self): - """ - Tests cache clearing. - """ - path = "test.usda" - cache = Gusd.StageCache() - - stage = FindOrOpen(cache, path) - assert stage - - stage2 = cache.Find(path) - - cache.Clear(["test.usda"]) - # should not longer find the stage on the cache. - assert not cache.Find("test.usda") - assert not cache.FindStages(["test.usda"]) - # but our stage variable should still be valid. - assert stage - - if Tf.GetEnvSetting("GUSD_STAGEMASK_ENABLE"): - # Make sure this clearing behavior extends to masked stages. - - prim,primStage = GetPrim(cache, path, "/Root/Component") - - cache.Clear(["test.usda"]) - - assert not cache.Find("test.usda") - assert not cache.FindStages(["test.usda"]) - - assert prim - assert primStage - - # the above primStage should be the only stage reference; - # release it, and our prim should expire. - primStage = None - assert not prim - - - def _TestLoadWithInvalidPrimPath(self, cache, path, primPath): - # No matter how we attempt to load this prim, we should - # always get back an invalid prim, and no stage should be loaded. - - # GetPrim() - prim,stage = cache.GetPrim(path, primPath) - - self.assertFalse(prim) - self.assertFalse(stage) - self.assertFalse(cache.FindStages([path])) - - # GetPrimWithVariants() - prim,stage = cache.GetPrimWithVariants(path, primPath, - Sdf.Path("/foo{a=b}")) - self.assertFalse(prim) - self.assertFalse(stage) - self.assertFalse(cache.FindStages([path])) - - # GetPrims() - prims = cache.GetPrims([path], [primPath]) - self.assertFalse(any(prims)) - self.assertFalse(cache.FindStages([path])) - - - def test_UnsafePrimPaths(self): - """ - Tests that the cache is well-behaved given different types of - invalid prim paths. - """ - - path = "test.usda" - - cache = Gusd.StageCache() - - # Empty path. - self._TestLoadWithInvalidPrimPath(cache, path, Sdf.Path()) - - # Relative path. - # These are dangerous because algorithms that traverse parent paths - # may have infinite loops given relative paths (eg., because - # recursively calling GetParentPath() on a relative path will always - #produce a new path). - self._TestLoadWithInvalidPrimPath(cache, path, Sdf.Path("foo")) - - - -if __name__ == "__main__": - unittest.main() diff --git a/third_party/houdini/gusd/tokens.cpp b/third_party/houdini/gusd/tokens.cpp deleted file mode 100644 index 533079cee3..0000000000 --- a/third_party/houdini/gusd/tokens.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "tokens.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -TF_DEFINE_PUBLIC_TOKENS(GusdTokens, GUSD_TOKENS); - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/tokens.h b/third_party/houdini/gusd/tokens.h deleted file mode 100644 index fe8b6f9927..0000000000 --- a/third_party/houdini/gusd/tokens.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_TOKENS_H -#define GUSD_TOKENS_H - -#include "pxr/base/tf/staticTokens.h" - -#include "pxr/pxr.h" - - -PXR_NAMESPACE_OPEN_SCOPE - - -#define GUSD_TOKENS \ - (Alpha) \ - (Cd) \ - (displayColor) \ - (displayOpacity) \ - ((usdOutPrimPath, "name")) \ - ((usdAgentPath, "usdagentpath")) \ - ((usdAgentPrimPath, "usdagentprimpath")) - -TF_DECLARE_PUBLIC_TOKENS(GusdTokens, GUSD_TOKENS); - - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*GUSD_TOKENS_H*/ diff --git a/third_party/houdini/gusd/treemodel.py b/third_party/houdini/gusd/treemodel.py deleted file mode 100644 index a37c947606..0000000000 --- a/third_party/houdini/gusd/treemodel.py +++ /dev/null @@ -1,751 +0,0 @@ -# -# Copyright 2017 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# -import hou - -from hutil.Qt.QtGui import * -from hutil.Qt.QtCore import * -from hutil.Qt.QtWidgets import * - -from pxr import Usd, Sdf, UsdGeom, Ar - -# -# Column headers and ID numbers -# -COL_HEADERS = ("Name", "Import", "Type", "Variants", "") -COL_NAME, COL_IMPORT, COL_TYPE, COL_VARIANT, COL_END = range(len(COL_HEADERS)) - -# Method for comparing 2 Sdf.Path objects. -def ComparePaths(x, y): - xPath = Sdf.Path(x).StripAllVariantSelections() - yPath = Sdf.Path(y).StripAllVariantSelections() - return xPath.pathElementCount - yPath.pathElementCount - -class VariantInfo(object): - def __init__(self, name, choices, initialSelection, enabled): - self._name = name - self._choices = choices - self._initialSelection = initialSelection - self._currentSelection = initialSelection - self._enabled = enabled - -class TreeItem(object): - def __init__(self, data, parent, primPath, hasUnloadedPayload): - self._data = data - self._parent = parent - self._primPath = primPath - self._hasUnloadedPayload = hasUnloadedPayload - self._children = [] - - if parent: - parent._children.append(self) - - def children(self): - return self._children - - def child(self, row): - return self._children[row] - - def childCount(self): - return len(self._children) - - def clearChildren(self): - self._children = [] - - def columnCount(self): - return len(self._data) - - def data(self, column): - try: - return self._data[column] - except IndexError: - return None - - def parent(self): - return self._parent - - def row(self): - if self._parent: - return self._parent._children.index(self) - return 0 - - def setData(self, column, value): - if column < 0 or column >= len(self._data): - return False - - self._data[column] = value - return True - - def primPath(self): - return self._primPath - - def hasUnloadedPayload(self): - return self._hasUnloadedPayload - - def setHasUnloadedPayload(self, hasUnloadedPayload): - self._hasUnloadedPayload = hasUnloadedPayload - - def matchesFilter(self, filterString): - if len(filterString) == 0: - return None - # - # In order for primPath to be considered a match with filterString, - # filterString has to match at least part of the actual name shown - # on the row in the treeview. In other words, the match can't be - # completetly from the ancestor part of primPath; it has to overlap - # the piece that follows the final '/'. - # - filterHead, slash, filterTail =\ - filterString.lower().rpartition('/') - - ancestorPath, slash, name =\ - self._primPath.pathString.lower().rpartition('/') - - start = name.find(filterTail) - if start == -1 or\ - (start == 0 and not ancestorPath.endswith(filterHead)) or\ - (start > 0 and len(filterTail) < len(filterString)): - return None - - # Return the position in name where the match begins, - # and also the length of the matching section. - return (start, len(filterTail)) - -class TreeModel(QAbstractItemModel): - # Static members - parmNameUsdFile = '_parmname_usdfile' - parmNamePrimPaths = '_parmname_primpaths' - parmUiExpandState = '_parm_uiexpandstate' - - def __init__(self, headers, node=None): - super(TreeModel, self).__init__(parent=None) - - self._rootItem = TreeItem(headers,\ - parent=None,\ - primPath='/',\ - hasUnloadedPayload=False) - self._stage = None - self._primPathToItemMap = {} - - # _importedPrimPaths is the list of prim paths that are switched on - # in the tree view's import column, and matches the import node's - # _namePrimPaths parameter. - self._importedPrimPaths = [] - - self._sessionId = -1 - self._nameUsdFile = '' - self._namePrimPaths = '' - - # This model will own a QItemSelectionModel so it can - # be shared by all views that operate on this model. - self._selectionModel = QItemSelectionModel(self) - - self.BuildAll(node) - - def BuildAll(self, node, clearExisting=False): - if clearExisting: - self.ClearAll(node) - - if node: - self._sessionId = node.sessionId() - self._nameUsdFile = node.parm(TreeModel.parmNameUsdFile).eval() - self._namePrimPaths = node.parm(TreeModel.parmNamePrimPaths).eval() - - usdFile = node.parm(self._nameUsdFile).eval() - resolverContext = Ar.GetResolver().GetCurrentContext() - try: - self._stage = Usd.Stage.Open(usdFile, resolverContext,\ - Usd.Stage.LoadNone) - except: - if usdFile != '': - print('Error: Tree View failed to open "%s"' % usdFile) - - if self._stage: - rootPrim = self._stage.GetPseudoRoot() - primPath = rootPrim.GetPath() - - self._primPathToItemMap[primPath] = self._rootItem - self.BuildTree(rootPrim) - - # Copy the import state from the node and apply it to the new tree. - self.CopyImportedPrimPathsFromNode(node) - - def ClearAll(self, node): - if node: - # Clear node's list of expanded items. - node.parm(TreeModel.parmUiExpandState).set('') - - self.beginResetModel() - self._rootItem.clearChildren() - self._stage = None - self._primPathToItemMap.clear() - self._importedPrimPaths = [] - self._sessionId = -1 - self._nameUsdFile = '' - self._namePrimPaths = '' - self._selectionModel.reset() - self.endResetModel() - - def SyncModelWithNode(self, node): - # Check if the node's usdFile parameter resolves to a different - # path than that stored in self._stage's rootLayer. If they differ, - # clear and rebuild this model. - paramPath = node.parm(self._nameUsdFile).eval() - storedPath = self._stage.GetRootLayer().realPath if self._stage else '' - if Ar.GetResolver().Resolve(paramPath) != storedPath: - self.BuildAll(node, clearExisting=True) - else: - # The node's usdFile hasn't changed, but its primPaths may - # have, so copy them from the node to the this model. - self.CopyImportedPrimPathsFromNode(node) - - def IsPrimBoundable(self, prim, predicate): - if prim.IsA(UsdGeom.Boundable): - return True - - # If this prim has a payload, consider it boundable. - if prim.HasAuthoredPayloads(): - return True - - for child in prim.GetFilteredChildren(predicate): - if self.IsPrimBoundable(child, predicate): - return True - - return False - - def BuildTree(self, startPrim): - startItem = self._primPathToItemMap.get(startPrim.GetPath()) - if not startItem: - return - - # Add traversal of instances to predicate - predicate = Usd.TraverseInstanceProxies( - Usd.PrimIsActive & Usd.PrimIsDefined & ~Usd.PrimIsAbstract) - childCount = len(startPrim.GetFilteredChildren(predicate)) - - first = startItem.childCount() - last = first + childCount - 1 - - self.beginInsertRows(self.indexFromItem(startItem), first, last) - - prims = list(Usd.PrimRange(startPrim, predicate)) - - # Iterate through prims, but skip the startPrim - for prim in prims[1:]: - if not self.IsPrimBoundable(prim, predicate): - continue - - parentPrim = prim.GetParent() - - parentItem = self._primPathToItemMap.get(parentPrim.GetPath()) - if parentItem: - - primName = prim.GetName() - primTypeName = prim.GetTypeName() - primPath = prim.GetPath() - hasUnloadedPayload = prim.HasAuthoredPayloads() - - # Use parentItem's import state to determine its child's - # import state. (Note it is intentional that the parentItem's - # data is tested to be equal to Checked or PartiallyChecked, - # instead of just testing that it's *not* equal to Unchecked. - # This is because when parentItem is the top-most root item, - # its data is a header string instead of a CheckState). - importState = Qt.Unchecked - if parentItem.data(COL_IMPORT) == Qt.Checked or\ - parentItem.data(COL_IMPORT) == Qt.PartiallyChecked: - importState = Qt.PartiallyChecked - - # Retrieve variants from the prim. - variants = [] - variantSets = prim.GetVariantSets() - for name in variantSets.GetNames(): - variantSet = variantSets.GetVariantSet(name) - variants.append(VariantInfo(\ - name = name,\ - choices = variantSet.GetVariantNames(),\ - initialSelection = variantSet.GetVariantSelection(),\ - enabled = False)) - - data = [primName, importState, primTypeName, variants] - childItem = TreeItem(data, parentItem, primPath, hasUnloadedPayload) - - self._primPathToItemMap[primPath] = childItem - - self.endInsertRows() - - def ClearTree(self, item): - # If the item has no children, there is nothing to do. - if item.childCount() == 0: - return - - # Traverse all of item's descendants, removing - # them from _primPathToItemMap. - descendants = item.children() - - for descendant in descendants: - descendants.extend(descendant.children()) - - self._primPathToItemMap.pop(descendant.primPath()) - - self.beginRemoveRows(self.indexFromItem(item), 0, item.childCount()) - item.clearChildren() - self.endRemoveRows() - - def columnCount(self, parent): - return self.itemFromIndex(parent).columnCount() - - def data(self, index, role): - if not index.isValid(): - return None - - if role != Qt.DisplayRole and role != Qt.EditRole: - return None - - item = index.internalPointer() - - return item.data(index.column()) - - def flags(self, index): - if not index.isValid(): - return Qt.NoItemFlags - - return Qt.ItemIsEnabled | Qt.ItemIsSelectable - - def headerData(self, section, orientation, role): - if orientation == Qt.Horizontal and role == Qt.DisplayRole: - return self._rootItem.data(section) - - return None - - def index(self, row, column, parent): - if not self.hasIndex(row, column, parent): - return QModelIndex() - - parentItem = self.itemFromIndex(parent) - - childItem = parentItem.child(row) - if childItem: - return self.createIndex(row, column, childItem) - else: - return QModelIndex() - - def parent(self, index): - if not index.isValid(): - return QModelIndex() - - childItem = index.internalPointer() - parentItem = childItem.parent() - - return self.indexFromItem(parentItem) - - def itemFromIndex(self, index): - if index.isValid(): - return index.internalPointer() - else: - return self._rootItem - - def indexFromItem(self, item, column = 0): - if not item or item == self._rootItem: - return QModelIndex() - - return self.createIndex(item.row(), column, item) - - def rowCount(self, parent): - if parent.column() > 0: - return 0 - - return self.itemFromIndex(parent).childCount() - - def setData(self, index, value, role=Qt.EditRole): - if role != Qt.EditRole: - return False - - column = index.column() - - if column == COL_IMPORT: - return self.ChangeImport(index, value) - - elif column == COL_VARIANT: - return self.ChangeVariants(index, value) - - else: - item = self.itemFromIndex(index) - if item.setData(column, value): - self.EmitDataChanged(index) - return True - return False - - def hasChildren(self, parent): - item = self.itemFromIndex(parent) - - # Report that this parent has children if either its - # childCount is above zero, or it has an unloaded payload. - return item.childCount() > 0 or item.hasUnloadedPayload() - - def SetImportState(self, item, state): - # If attempting to unimport an item that has an imported parent, - # set the item's state to PartiallyChecked instead of Unchecked. - if state == Qt.Unchecked and item.parent() is not None: - parentState = item.parent().data(COL_IMPORT) - # (Note it is intentional that the parentState is tested to be - # equal to Checked or PartiallyChecked, instead of just testing - # that it's *not* equal to Unchecked. This is because when item's - # parent is the top-most root item, its data is a header string - # instead of a CheckState). - if parentState == Qt.Checked or parentState == Qt.PartiallyChecked: - state = Qt.PartiallyChecked - - item.setData(COL_IMPORT, state) - index = self.createIndex(item.row(), COL_IMPORT, item) - self.EmitDataChanged(index) - - for child in [item.child(i) for i in range(item.childCount())]: - # Only continue unimporting children that are PartiallyChecked. - # (So, if child is Checked or Unchecked, the recursion stops). - if state == Qt.Unchecked and\ - child.data(COL_IMPORT) == Qt.PartiallyChecked: - self.SetImportState(child, Qt.Unchecked) - - # Only continue importing children that are Unchecked. (So, if - # child is Checked or PartiallyChecked, the recursion stops). - elif state != Qt.Unchecked and\ - child.data(COL_IMPORT) == Qt.Unchecked: - self.SetImportState(child, Qt.PartiallyChecked) - - def GetPrim(self, item): - if not self._stage: - return None - return self._stage.GetPrimAtPath(item.primPath()) - - def GetNode(self): - if self._sessionId != -1: - return hou.nodeBySessionId(self._sessionId) - else: - return None - - def LoadPrimAndBuildTree(self, prim, item): - if prim: - if not prim.IsLoaded(): - prim.Load() - item.setHasUnloadedPayload(False) - self.BuildTree(prim) - - def ChangeImport(self, index, value): - indexesToChange = [] - indexIsSelected = False - - # Get all selected indexes that are in the 'Import' column. - for selected in self._selectionModel.selectedIndexes(): - if selected.column() == COL_IMPORT: - indexesToChange.append(selected) - - # If the provided index is part of the selection, set a flag. - if selected == index: - indexIsSelected = True - - # If the provided index is not part of the selection, then replace - # the indexesToChange list with only the provided index. - if not indexIsSelected: - indexesToChange = [index] - - # Helper function for items that get unchecked as a result - # of a selected item changing its import/unimport state. - def UncheckNonSelected(item): - # First make sure the item is imported. If not, do nothing. - if item.data(COL_IMPORT) != Qt.Checked: - return - # Now, if the item is NOT currently selected, unimport it. - if self.indexFromItem(item, COL_IMPORT) not in indexesToChange: - self.RemoveImportedPrimPath(self.VariantPrimPathFromItem(item)) - self.SetImportState(item, Qt.Unchecked) - - changed = False - for item in [self.itemFromIndex(i) for i in indexesToChange]: - # If new value is same as current value, skip this item. - if value == item.data(COL_IMPORT): - continue - - if value == Qt.Unchecked: - self.RemoveImportedPrimPath(self.VariantPrimPathFromItem(item)) - - elif value == Qt.Checked: - self.AddImportedPrimPath(self.VariantPrimPathFromItem(item)) - - # When an item gets Checked, also Uncheck all of its ancestors. - # (Since any Checked ancestor would mean this item is already - # in an imported state, the assumption is that the user means - # to keep only this item imported, and unimport its siblings). - # This behavior is overridden by including in the current - # selection any parents that are meant to remain Checked. - parent = item.parent() - while parent is not None: - UncheckNonSelected(parent) - parent = parent.parent() - - # Likewise, when an item gets Checked, also Uncheck all of its - # children. (This is meant to prevent having duplicate items - # imported, since importing an item will also import all of its - # children). Again, this behavior is overridden by including in - # the current selection any children that are meant to remain - # Checked. - children = [item.child(i) for i in range(item.childCount())] - for child in children: - UncheckNonSelected(child) - children.extend(\ - [child.child(i) for i in range(child.childCount())]) - - self.SetImportState(item, value) - changed = True - return changed - - def ChangeVariants(self, index, newVariants): - item = self.itemFromIndex(index) - - # Store item's variantPrimPath and variants before they change. - oldVariantPrimPath = self.VariantPrimPathFromItem(item) - oldVariants = item.data(COL_VARIANT) - - # Set the new variants. - item.setData(COL_VARIANT, newVariants) - - variantsEnabledChanged = False - variantSelectionsChanged = False - prim = self.GetPrim(item) - - for old, new in zip(oldVariants, newVariants): - if new._enabled != old._enabled: - variantsEnabledChanged = True - - if new._currentSelection != old._currentSelection: - variantSelectionsChanged = True - variantSet = prim.GetVariantSet(new._name) - variantSet.SetVariantSelection(new._currentSelection) - - # If any variant selections changed AND if the prim is already loaded, - # clear and rebuild this prim's sub tree. (If the prim hasn't been - # loaded yet, then its sub tree hasn't been built yet and still doesn't - # need to be). - if variantSelectionsChanged and prim.IsLoaded(): - self.ClearTree(item) - self.BuildTree(prim) - - # If any variants have been enabled or changed, iterate through the - # paths in _importedPrimPaths to update their variant selections. - if variantsEnabledChanged or variantSelectionsChanged: - importedPrimPathsChanged = False - paths = [Sdf.Path(path) for path in self._importedPrimPaths] - for i, path in enumerate(paths): - # Non-absolute paths (relative paths) are not supported. - if not path.IsAbsolutePath(): - continue - - # If a common prefix exists between oldVariantPrimPath and path - # that IS oldVariantPrimPath, then this path either represents - # item or a descendant of item. - if path.GetCommonPrefix(oldVariantPrimPath) ==\ - oldVariantPrimPath: - pathItem = self.ItemFromVariantPrimPath(path) - if pathItem: - self._importedPrimPaths[i] =\ - self.VariantPrimPathFromItem(pathItem) - self.SetImportState(pathItem, Qt.Checked) - importedPrimPathsChanged = True - - if importedPrimPathsChanged: - self.CopyImportedPrimPathsToNode() - - self.EmitDataChanged(index) - return True - return False - - def MakeTreeIncludePrimPath(self, primPath): - if not self._stage: - return None - - # Non-absolute paths (relative paths) are not supported. - if not primPath.IsAbsolutePath(): - return None - - item = None - - paths = primPath.GetPrefixes() - i = 0 - while i < len(paths): - item = self._primPathToItemMap.get(\ - paths[i].StripAllVariantSelections(), None) - - # Not finding this item means this primPath can't be included, - # so break from this loop and return None. - if not item: - break - - prim = self.GetPrim(item) - newVariants = [] - oldVariants = item.data(COL_VARIANT) - - # Copy each oldVariant into newVariants. However, don't copy the - # _enabled flag. Instead, start all the newVariants as disabled. - for oldVariant in oldVariants: - newVariants.append(VariantInfo(oldVariant._name,\ - oldVariant._choices,\ - oldVariant._initialSelection,\ - enabled = False)) - i += 1 - # Update prim and newVariants from variant selections in primPath. - while i < len(paths) and paths[i].IsPrimVariantSelectionPath(): - name, selection = paths[i].GetVariantSelection() - variantSet = prim.GetVariantSet(name) - variantSet.SetVariantSelection(selection) - - for newVariant in newVariants: - if newVariant._name == name: - newVariant._enabled = True - newVariant._currentSelection = selection - i += 1 - - # Now check for changes between the old and new variants. - variantsChanged = False - for old, new in zip(oldVariants, newVariants): - if old._enabled != new._enabled or\ - old._currentSelection != new._currentSelection: - variantsChanged = True - break - - if variantsChanged: - self.ClearTree(item) - self.LoadPrimAndBuildTree(prim, item) - - item.setData(COL_VARIANT, newVariants) - self.EmitDataChanged(self.indexFromItem(item)) - - elif item.hasUnloadedPayload(): - self.LoadPrimAndBuildTree(prim, item) - - return item - - def VariantPrimPathFromItem(self, item): - parentItem = item.parent() - if parentItem: - parentPath = self.VariantPrimPathFromItem(parentItem) - if not parentPath.endswith('}'): - parentPath += '/' - - variants = item.data(COL_VARIANT) - variantsString = '' - for variantInfo in variants: - if variantInfo._enabled: - variantsString += '{' - variantsString += variantInfo._name - variantsString += '=' - variantsString += variantInfo._currentSelection - variantsString += '}' - - return parentPath + item.data(COL_NAME) + variantsString - else: - return '' - - def ItemFromVariantPrimPath(self, variantPrimPath): - primPath = Sdf.Path(variantPrimPath).StripAllVariantSelections() - return self._primPathToItemMap.get(primPath, None) - - def AddImportedPrimPath(self, primPath): - if primPath not in self._importedPrimPaths: - self._importedPrimPaths.append(primPath) - self.CopyImportedPrimPathsToNode() - - def RemoveImportedPrimPath(self, primPath): - if primPath in self._importedPrimPaths: - self._importedPrimPaths.remove(primPath) - self.CopyImportedPrimPathsToNode() - - def CopyImportedPrimPathsToNode(self, node=None): - if not node: - node = self.GetNode() - - if node: - parm = node.parm(self._namePrimPaths) - - src = '\n'.join(self._importedPrimPaths) - dst = parm.eval() - - if src != dst: - parm.set(src) - - def CopyImportedPrimPathsFromNode(self, node=None): - if not node: - node = self.GetNode() - - if node: - parm = node.parm(self._namePrimPaths) - - src = parm.eval() - dst = '\n'.join(self._importedPrimPaths) - - if src != dst: - srcImportedPrimPaths = src.split('\n') - - # First un-import any path in self._importedPrimPaths that - # isn't included in srcImportedPrimPaths. - for primPath in self._importedPrimPaths[:]: - if primPath not in srcImportedPrimPaths: - item = self.ItemFromVariantPrimPath(primPath) - if item: - self.SetImportState(item, Qt.Unchecked) - - # Clear the self._importedPrimPaths list. - self._importedPrimPaths = [] - - # Append each path from srcImportedPrimPaths into - # self._importedPrimPaths. - for primPath in srcImportedPrimPaths: - self._importedPrimPaths.append(primPath) - - item = self.MakeTreeIncludePrimPath(Sdf.Path(primPath)) - if item: - self.SetImportState(item, Qt.Checked) - - def GetImportedIndexes(self): - indexes = [] - for primPath in self._importedPrimPaths: - item = self.ItemFromVariantPrimPath(primPath) - indexes.append(self.indexFromItem(item)) - return indexes - - def GetIndexFromPrimPath(self, primPath): - item = self._primPathToItemMap.get(Sdf.Path(primPath), None) - if item: - return self.indexFromItem(item) - return QModelIndex() - - def EmitDataChanged(self, index): - # The PySide2 version of the dataChanged signal requires a - # 3rd argument. Check the houdini version number to determine - # whether to use the PySide or PySide2 version. - if hou.applicationVersion()[0] >= 16: - self.dataChanged.emit(index, index, []) - else: - self.dataChanged.emit(index, index) - - def GetSelectionModel(self): - return self._selectionModel diff --git a/third_party/houdini/gusd/treeview.py b/third_party/houdini/gusd/treeview.py deleted file mode 100644 index d7f8042dfc..0000000000 --- a/third_party/houdini/gusd/treeview.py +++ /dev/null @@ -1,956 +0,0 @@ -# -# Copyright 2017 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# -import hou - -from hutil.Qt.QtGui import * -from hutil.Qt.QtCore import * -from hutil.Qt.QtWidgets import * - -import types -from treemodel import * - -# -# Global variables -# -NodeTypeLowerCase = 'usdimport' - -# -# Return a list of hou.NodeType that are considered the only -# compatible node types that this plugin will work with. -# -def CompatibleNodeTypes(): - nodeTypes = [] - - for category in [hou.objNodeTypeCategory, hou.sopNodeTypeCategory]: - for key,value in category().nodeTypes().items(): - if NodeTypeLowerCase not in key.lower(): - continue - - parms = value.parmTemplateGroup() - - nameUsdFile = parms.find(TreeModel.parmNameUsdFile) - if not nameUsdFile or\ - not parms.find(nameUsdFile.defaultValue()[0]): - continue - - namePrimPaths = parms.find(TreeModel.parmNamePrimPaths) - if not namePrimPaths or\ - not parms.find(namePrimPaths.defaultValue()[0]): - continue - - if not parms.find(TreeModel.parmUiExpandState): - continue - - nodeTypes.append(value) - - return nodeTypes - -# -# Note CheckBoxStyled() is NOT a class definition, but rather is a method -# that returns an instance of a customized QCheckBox. This enables us to -# invoke hou.qt.createCheckBox() and bind override methods onto the instance -# it returns. (The other way to do this would have been to inherit from the -# class type returned by hou.qt.createCheckBox(), but this isn't possible -# because that class definition isn't exposed in the houpythonportion module). -# -def CheckBoxStyled(): - # - # The methods defined here are the overrides that will be bound to the - # QCheckBox return instance below. - # - def paintEvent(self, event): - opt = QStyleOptionButton() - self.initStyleOption(opt) - - style = self.style() - opt.rect = style.subElementRect(QStyle.SE_CheckBoxClickRect, opt, self) - - # Set 'base' color (the color inside the box). - opt.palette.setColor(QPalette.Base, hou.qt.getColor('TextboxBG')) - - painter = QStylePainter(self) - painter.drawControl(QStyle.CE_CheckBox, opt) - - def nextCheckState(self): - if self.checkState() == Qt.Checked: - self.setCheckState(Qt.Unchecked) - else: - # Not Checked, which means either Unchecked or PartiallyChecked. - # The next state for either of these is Checked. - self.setCheckState(Qt.Checked) - - # To preserve backward compatibility, houdini versions before 16.5 - # use a standard QCheckBox with a customized paintEvent. Starting - # with houdini 16.5, use a hou.qt.createCheckBox() instance. - (major, minor, build) = hou.applicationVersion() - if major >= 16 and minor >= 5: - checkBox = hou.qt.createCheckBox() - else: - checkBox = QCheckBox() - checkBox.paintEvent = types.MethodType(paintEvent, checkBox) - - # In all versions, override the nextCheckState method. - checkBox.nextCheckState = types.MethodType(nextCheckState, checkBox) - return checkBox - -class ComboBoxStyled(QComboBox): - def __init__(self, parent = None): - super(ComboBoxStyled, self).__init__(parent) - - # Set 'combobox-popup' to 0 on self (the QComboBox itself) to prevent - # the maxVisibleItems member of the QComboBox from being ignored. When - # ignored, the popup displays as one long list that gets clipped when - # too long. By not ignoring it, the size of the popup will be clamped - # and will provide a vertical scroll bar for browsing items. - self.setStyleSheet('QComboBox { combobox-popup: 0; }') - - # Create a QListView to replace the QComboBox's view. This allows the - # item padding and border to be customized. - listview = QListView() - listview.setStyleSheet('QListView::item { padding: 2px; }\ - QListView::item::selected { border: 0; }') - self.setView(listview) - - def SetDisabledBgColor(self, color): - styleSheet = 'QComboBox:disabled { background: rgb%s; }'\ - % str(color.toTuple()) - self.setStyleSheet(styleSheet) - -class FilterMenu(ComboBoxStyled): - # Signals - textEntered = Signal('QString') - - def __init__(self, parent): - super(FilterMenu, self).__init__(parent) - - self.setEditable(True) - - self.addItem("Clear Filter") - self.clearEditText() - self.text = self.currentText() - - self.activated[int].connect(self.OnActivated) - self.lineEdit().returnPressed.connect(self.EnterText) - - def EnterText(self): - if self.text != self.currentText(): - self.text = self.currentText() - self.textEntered.emit(self.text) - - def OnActivated(self, index): - if index == 0: - self.clearEditText() - self.EnterText() - - def OnStyleChanged(self): - styleSheet = 'QComboBox { padding: 2px; background: rgba%s; }'\ - % str(hou.qt.getColor('TextboxBG').toTuple()) - self.setStyleSheet(styleSheet) - -class ActiveNodeMenu(ComboBoxStyled): - # Signals - activeNodeChanged = Signal('QString') - - def __init__(self, parent): - super(ActiveNodeMenu, self).__init__(parent) - - # Set minimum contents length to 16 characters. - self.setMinimumContentsLength(16) - self.setDuplicatesEnabled(False) - - self.ResetMenu() - - # Store a string to hold the path of the last selected node. - self.lastSelected = "" - - self.ignoreCurrentIndexChanged = False - self.currentIndexChanged[int].connect(self.OnCurrentIndexChanged) - - def showPopup(self): - # The choices in this popup menu need to be updated. Turn on the - # ignoreCurrentIndexChanged flag so that calls to setCurrentIndex - # will not trigger the "activeNodeChanged" signal. - self.ignoreCurrentIndexChanged = True - - # Store whatever the current selection is, then clear the menu. - selected = self.currentText() - self.ResetMenu() - - # Rebuild the menu. - for nodeType in TreeView.nodeTypes: - for instance in nodeType.instances(): - if TreeView.IsNodeCompatible(instance): - # Each menu item stores both the node's path - # and its session id. - self.addItem(instance.path(), instance.sessionId()) - - # Restore whatever the selection was before the menu was cleared. - index = self.findText(selected) - self.setCurrentIndex(index if index > -1 else 0) - - # Disable the ignoreCurrentIndexChanged flag so that calls to - # setCurrentIndex will again trigger the "activeNodeChanged" signal. - self.ignoreCurrentIndexChanged = False - - # Now show the popup. - super(ComboBoxStyled, self).showPopup() - - def ResetMenu(self): - self.clear() - # The 1st choice (at index 0) is named "Last Selected". - self.addItem("Last Selected") - - def OnCurrentIndexChanged(self, index): - # Only emit "activeNodeChanged" signal if the - # ignoreCurrentIndexChanged flag is off. - if self.ignoreCurrentIndexChanged: - return - - if index < 0: - self.activeNodeChanged.emit('') - elif index == 0: - self.activeNodeChanged.emit(self.lastSelected) - else: - self.activeNodeChanged.emit(self.itemText(index)) - - def RemoveNodeChoice(self, node): - # If the node choice to remove is currently - # selected, change current to "Last Selected". - current = self.itemData(self.currentIndex()) - if current == node.sessionId(): - self.setCurrentIndex(0) # "Last Selected" is always 0th item. - - if self.lastSelected == node.path(): - self.lastSelected = "" - - def RenameNodeChoice(self, node): - # Use the node's sessionId to find a menu choice, which - # has the name that the node had before it was renamed. - index = self.findData(node.sessionId()) - if index != -1: - oldPath = self.itemText(index) - newPath = node.path() - - if self.currentIndex() == index: - self.setItemText(index, newPath) - - if self.lastSelected == oldPath: - self.lastSelected = newPath - - def GetLastSelected(self): - return self.lastSelected - - def SetLastSelected(self, nodePath): - if self.lastSelected != nodePath: - self.lastSelected = nodePath - - if self.currentIndex() == 0: - self.activeNodeChanged.emit(nodePath) - -class TreeItemEditor(QFrame): - # Signals - edited = Signal() - styleChanged = Signal('QColor') - - # Static members used for computing size hint. - margins = QMargins(2, 2, 2, 2) - checkBoxHeight = CheckBoxStyled().sizeHint().height() - comboBoxHeight = ComboBoxStyled().sizeHint().height() - - @staticmethod - def ItemHeight(index): - height = TreeItemEditor.margins.top() + TreeItemEditor.margins.bottom() - - if index.column() == COL_IMPORT: - height += TreeItemEditor.checkBoxHeight - elif index.column() == COL_VARIANT: - variants = index.data() - height += TreeItemEditor.comboBoxHeight * len(variants) - - return height - - def __init__(self, parent, index): - super(TreeItemEditor, self).__init__(parent) - - layout = QGridLayout() - layout.setContentsMargins(TreeItemEditor.margins) - - if index.column() == COL_IMPORT: - self._checkBox = CheckBoxStyled() - self._checkBox.setCheckState(Qt.CheckState(index.data())) - self._checkBox.stateChanged.connect(self.DataChanged) - layout.addWidget(self._checkBox, 0, 0, Qt.AlignHCenter) - - elif index.column() == COL_VARIANT: - variants = index.data() - - # Only the 3rd column should stretch. - layout.setColumnStretch(0, 0) - layout.setColumnStretch(1, 0) - layout.setColumnStretch(2, 1) - - layout.setColumnMinimumWidth(1, 100) - layout.setHorizontalSpacing(layout.spacing()) - layout.setVerticalSpacing(0) - - self._checkBoxes = [] - self._comboBoxes = [] - - for row, item in enumerate(variants): - self._checkBoxes.append(CheckBoxStyled()) - self._comboBoxes.append(ComboBoxStyled()) - - checkBox = self._checkBoxes[-1] - checkBox.setCheckState(Qt.Checked if item._enabled\ - else Qt.Unchecked) - checkBox.stateChanged.connect(self.DataChanged) - - label = QLabel(item._name, self) - label.setStyleSheet("background: transparent;") - label.setEnabled(item._enabled) - checkBox.stateChanged.connect(label.setEnabled) - - comboBox = self._comboBoxes[-1] - comboBox.addItems(item._choices) - index = comboBox.findText(item._initialSelection) - if index != -1: - comboBox.setCurrentIndex(index) - comboBox.setEnabled(item._enabled) - comboBox.currentIndexChanged.connect(self.DataChanged) - checkBox.stateChanged.connect(comboBox.setEnabled) - - # Starting with houdini 16.5, disabled combobox text - # displays with a strange shadow; Manually setting the - # background color seems to hide the issue. - (major, minor, build) = hou.applicationVersion() - if major >= 16 and minor >= 5: - comboBox.SetDisabledBgColor(hou.qt.getColor('ButtonGradLow')) - self.styleChanged.connect(comboBox.SetDisabledBgColor) - - layout.addWidget(checkBox, row, 0, Qt.AlignHCenter) - layout.addWidget(label, row, 1, Qt.AlignLeft) - layout.addWidget(comboBox, row, 2) - - self.setLayout(layout) - - def changeEvent(self, event): - if event.type() == QEvent.StyleChange: - self.styleChanged.emit(hou.qt.getColor('ButtonGradLow')) - super(TreeItemEditor, self).changeEvent(event) - - def DataChanged(self): - self.edited.emit() - - def GetData(self, index): - if index.column() == COL_IMPORT: - return self._checkBox.checkState() - - elif index.column() == COL_VARIANT: - variants = index.data() - - dstItems = [] - for row, srcItem in enumerate(variants): - dstItem = VariantInfo(srcItem._name,\ - srcItem._choices,\ - srcItem._initialSelection,\ - bool(self._checkBoxes[row].checkState())) - if dstItem._enabled: - dstItem._currentSelection =\ - str(self._comboBoxes[row].currentText()) - else: - dstItem._currentSelection = dstItem._initialSelection - dstItems.append(dstItem) - return dstItems - - def SetData(self, index): - if index.column() == COL_IMPORT: - self._checkBox.setCheckState(Qt.CheckState(index.data())) - - elif index.column() == COL_VARIANT: - variants = index.data() - for row, item in enumerate(variants): - - checkBox = self._checkBoxes[row] - comboBox = self._comboBoxes[row] - index = -1 - if item._enabled: - checkBox.setCheckState(Qt.Checked) - index = comboBox.findText(item._currentSelection) - else: - checkBox.setCheckState(Qt.Unchecked) - index = comboBox.findText(item._initialSelection) - if index != -1: - comboBox.setCurrentIndex(index) - -class TreeItemDelegate(QStyledItemDelegate): - def __init__(self): - QStyledItemDelegate.__init__(self) - - def displayText(self, value, locale): - if not isinstance(value, basestring): - return '' - return super(TreeItemDelegate, self).displayText(value, locale) - - def createEditor(self, parent, option, index): - editor = TreeItemEditor(parent, index) - editor.edited.connect(self.commitAndCloseEditor) - return editor - - def setEditorData(self, editor, index): - editor.SetData(index) - - def setModelData(self, editor, model, index): - model.setData(index, editor.GetData(index)) - - def sizeHint(self, option, index): - width = 0 - if index.column() == COL_NAME: - (style, opt) = self.SetupStyleOption(option, index) - margin = style.pixelMetric(QStyle.PM_FocusFrameHMargin,\ - opt, opt.widget) + 1 - width = QFontMetrics(opt.font).width(opt.text) + margin - return QSize(width, TreeItemEditor.ItemHeight(index)) - - def commitAndCloseEditor(self): - editor = self.sender() - self.commitData.emit(editor) - self.closeEditor.emit(editor, QAbstractItemDelegate.NoHint) - - def paint(self, painter, option, index): - if index.column() == COL_NAME: - (style, opt) = self.SetupStyleOption(option, index) - (widget, text) = opt.widget, opt.text - - # Draw the expand/collapse control for this item. Clear the opt's - # text so that no text will be drawn yet. Text will be drawn next. - opt.text = '' - style.drawControl(QStyle.CE_ItemViewItem, opt, painter, widget) - - # Prepare an empty FormatRange, and grab the filterString from - # the TreeView widget. - formatRange = QTextLayout.FormatRange() - filterString = '' if widget is None\ - else widget.parent().filterMenu.currentText() - # If filterString matches this item, set up the formatRange - # to draw the matching section as highlighted text. - if len(filterString) > 1: - match = index.internalPointer().matchesFilter(filterString) - if match is not None: - formatRange.start, formatRange.length = match - - # Make highlight color a bit more opaque than the default. - highlight = opt.palette.color(QPalette.Highlight) - highlight.setAlphaF(0.7) - opt.palette.setColor(QPalette.Highlight, highlight) - formatRange.format.setBackground(opt.palette.highlight()) - - # Make the text elided (replace end with '...') if it is too wide. - rect = style.subElementRect(QStyle.SE_ItemViewItemText, opt, widget) - metrics = QFontMetrics(opt.font) - if metrics.width(text) > rect.width(): - text = metrics.elidedText(text, opt.textElideMode, rect.width()) - - # The position of the text should be at the vertical center - # of the rectangle, adjusted for the height of the font. - pos = QPoint(rect.left(), rect.center().y() - (metrics.height()/2)) - - # Draw the text (with the section that matches filter highlighted). - textLayout = QTextLayout(text, opt.font) - textLayout.beginLayout() - textLayout.createLine() - textLayout.endLayout() - textLayout.draw(painter, pos, [formatRange], rect) - else: - super(TreeItemDelegate, self).paint(painter, option, index) - - # Helper function for setting up a QStyle and QStyleOptionViewItem. - def SetupStyleOption(self, option, index): - opt = QStyleOptionViewItem(option) - self.initStyleOption(opt, index) - style = qApp.style() if opt.widget is None else opt.widget.style() - return (style, opt) - -class TreeView(QFrame): - # Signals - styleChanged = Signal() - - # Declare nodeTypes as a static member of TreeView. - nodeTypes = CompatibleNodeTypes() - - # Static model to use for views with no "Active Node". - emptyModel = TreeModel(COL_HEADERS) - - def __init__(self): - QFrame.__init__(self) - - # Houdini styling is not automatically applied to custom widgets. - # Set the "houdiniStyle" property to True on this top-level widget - # so it matches the style of other houdini widgets. - self.setProperty("houdiniStyle", True) - - # Keep a list of prim paths that are expanded in this tree view. - self.expandedPrimPaths = [] - - expandToImported = QPushButton("+", self) - expandToImported.setMaximumSize(QSize(20,20)) - expandToImported.setToolTip("Expand tree to show all imported prims.") - expandToImported.clicked.connect(self.OnExpandToImported) - - self.filterMenu = FilterMenu(self) - self.filterMenu.textEntered['QString'].connect(self.OnFilterApplied) - self.styleChanged.connect(self.filterMenu.OnStyleChanged) - - self.switchShowVariants = CheckBoxStyled() - self.switchShowVariants.stateChanged.connect(self.ShowVariants) - - self.activeNodeMenu = ActiveNodeMenu(self) - self.activeNodeMenu.activeNodeChanged.connect(\ - self.OnActiveNodeChanged) - - toolbarLayout = QHBoxLayout() - toolbarLayout.setSpacing(4) - toolbarLayout.addWidget(expandToImported) - toolbarLayout.addSpacing(8) - toolbarLayout.addWidget(QLabel("Filter")) - toolbarLayout.addWidget(self.filterMenu, 1) - toolbarLayout.addSpacing(20) - toolbarLayout.addWidget(self.switchShowVariants) - toolbarLayout.addWidget(QLabel("Show Variants")) - toolbarLayout.addSpacing(20) - toolbarLayout.addWidget(QLabel("Active Node")) - toolbarLayout.addWidget(self.activeNodeMenu) - - self.view = QTreeView() - self.view.setModel(TreeView.emptyModel) - - self.view.setItemDelegate(TreeItemDelegate()) - - self.view.setColumnWidth(COL_NAME, 300) - self.view.resizeColumnToContents(COL_IMPORT) - self.view.setColumnWidth(COL_TYPE, 60) - self.view.setColumnWidth(COL_VARIANT, 340) - self.view.resizeColumnToContents(COL_END) - - self.view.setSelectionMode(QAbstractItemView.ExtendedSelection) - self.view.setContextMenuPolicy(Qt.CustomContextMenu) - self.view.customContextMenuRequested.connect(self.PopupRightClickMenu) - self.view.installEventFilter(self) - - self.view.setAlternatingRowColors(True) - self.view.verticalScrollBar().valueChanged.connect(\ - self.view.updateGeometries) - self.view.horizontalScrollBar().valueChanged.connect(\ - self.view.updateGeometries) - - self.view.expanded.connect(self.OnExpanded) - self.view.collapsed.connect(self.OnCollapsed) - - mainLayout = QVBoxLayout() - mainLayout.setSpacing(0) - mainLayout.setContentsMargins(2, 2, 2, 2) - mainLayout.addLayout(toolbarLayout) - mainLayout.addWidget(self.view) - - self.setLayout(mainLayout) - - self.ShowVariants(self.switchShowVariants.checkState()) - - hou.ui.addEventLoopCallback(self.CheckNodeSelection) - - def changeEvent(self, event): - if event.type() == QEvent.StyleChange: - self.styleChanged.emit() - super(TreeView, self).changeEvent(event) - - def closeEvent(self, event): - try: - hou.ui.removeEventLoopCallback(self.CheckNodeSelection) - except hou.Error: - pass - self.UnsyncViewWithModel() - event.accept() - - def keyPressEvent(self, event): - if event.key() == Qt.Key_Escape and\ - self.view.selectionModel() is not None: - self.view.selectionModel().clearSelection() - super(TreeView, self).keyPressEvent(event) - - def eventFilter(self, source, event): - if event.type() == QEvent.KeyPress and\ - event.matches(QKeySequence.Copy): - self.OnSelectionCopied() - return True - return super(TreeView, self).eventFilter(source, event) - - @staticmethod - def IsNodeCompatible(node, ignoreNodeType = True): - if not ignoreNodeType and node.type() not in TreeView.nodeTypes: - return False - - namePrimPaths = node.parm(TreeModel.parmNamePrimPaths).eval() - parm = node.parm(namePrimPaths) - - # If the primpaths parm is channel-referenced to another parameter, it - # won't work with this plugin. This case happens when there is a usd - # import SOP embedded in a usd import OTL. Only one of the two should - # be used by the plugin, not both. This check allows the OTL to pass, - # and causes the embedded SOP to fail. - if parm.getReferencedParm().path() != parm.path(): - return False - return True - - def CheckNodeSelection(self): - selectedNodes = hou.selectedNodes() - - # Exit early if there are no nodes selected OR if there is only one - # node selected and it matches activeNodeMenu's "Last Selected" node. - if len(selectedNodes) == 0 or (len(selectedNodes) == 1 and\ - selectedNodes[0].path() == self.activeNodeMenu.GetLastSelected()): - return - - # Look for the first usd import node in houdini's current selection - # to update the activeNodeMenu's "Last Selected" node path. - for node in selectedNodes: - if TreeView.IsNodeCompatible(node, ignoreNodeType=False): - self.activeNodeMenu.SetLastSelected(node.path()) - break - - def OnActiveNodeChanged(self, nodePath): - node = hou.node(str(nodePath)) - if not node: - self.SyncViewWithModel(TreeView.emptyModel) - return - - key = node.sessionId() - model = hou.session.UsdImportDict.get(key, None) - - if model: - if model != self.view.model(): - # Just in case any node parameters have changed since last - # time this model was viewed, sync the model with the node, - # then sync the view with the model. - model.SyncModelWithNode(node) - self.SyncViewWithModel(model) - else: - # Create a new model, then sync the view with the model. - model = TreeModel(COL_HEADERS, node) - self.SyncViewWithModel(model) - - hou.session.UsdImportDict[key] = model - - def UnsyncViewWithModel(self): - # Attempt to disconnect the current model. - model = self.view.model() - try: - node = model.GetNode() - if node is not None: - node.removeEventCallback(\ - (hou.nodeEventType.BeingDeleted,), self.OnNodeDeleted) - node.removeEventCallback(\ - (hou.nodeEventType.NameChanged,), self.OnNodeRenamed) - node.removeEventCallback(\ - (hou.nodeEventType.ParmTupleChanged,), self.OnParmChanged) - - except RuntimeError: - # This error happens the first time this method is called - # because none of these connections have been made yet. - pass - - # Clear the expandedPrimPaths stored in the view - self.expandedPrimPaths = [] - - def SyncViewWithModel(self, model): - # First unsync from the existing model. - self.UnsyncViewWithModel() - - # Now actually set the new model as the view's model. - self.view.setModel(model) - - # Open persistent editors for the top index. - topIndex = model.index(0, 0, QModelIndex()) - if topIndex.isValid(): - self.OpenPersistentEditors(topIndex) - - expandState = '' - node = model.GetNode() - if node is not None: - node.addEventCallback(\ - (hou.nodeEventType.BeingDeleted,), self.OnNodeDeleted) - node.addEventCallback(\ - (hou.nodeEventType.NameChanged,), self.OnNodeRenamed) - node.addEventCallback(\ - (hou.nodeEventType.ParmTupleChanged,), self.OnParmChanged) - - expandState = node.parm(TreeModel.parmUiExpandState).eval() - - # Get the list of indexes that should be expanded - # from expandState, then expand each of them. - if expandState != '': - self.expandedPrimPaths = expandState.split() - # Sort the expandedPrimPaths using the ComparePaths - # method (which is defined in the treemodel module). - self.expandedPrimPaths.sort(cmp=ComparePaths) - for primPath in self.expandedPrimPaths: - index = model.GetIndexFromPrimPath(primPath) - if index.isValid(): - self.view.expand(index) - else: - # If there are no paths specified to be expanded, the - # default is to expand the first 2 levels of the tree. - self.view.expandToDepth(2) - - # Now set the view's selectionModel. This triggers a call to - # CopyExpandedPrimPathsToNode, so it's important that this - # happen only after self.expandedPrimPaths has been updated. - self.view.setSelectionModel(model.GetSelectionModel()) - - # Apply the current filter to this tree view. - self.OnFilterApplied(self.filterMenu.currentText()) - - def OnNodeDeleted(self, **kwargs): - node = kwargs['node'] - self.activeNodeMenu.RemoveNodeChoice(node) - - key = node.sessionId() - model = hou.session.UsdImportDict.get(key, None) - if model: - if model == self.view.model(): - self.SyncViewWithModel(TreeView.emptyModel) - model.ClearAll(node) - hou.session.UsdImportDict.pop(key) - - def OnNodeRenamed(self, **kwargs): - self.activeNodeMenu.RenameNodeChoice(kwargs['node']) - - def OnParmChanged(self, **kwargs): - parm = kwargs['parm_tuple'] - if not parm: - return - - parmName = parm.name() - model = self.view.model() - - if parmName == model._nameUsdFile: - node = kwargs['node'] - model.BuildAll(node, clearExisting=True) - self.SyncViewWithModel(model) - - elif parmName == model._namePrimPaths: - node = kwargs['node'] - model.CopyImportedPrimPathsFromNode(node) - - def OnExpanded(self, index): - model = self.view.model() - item = model.itemFromIndex(index) - - primPath = item.primPath().pathString - if primPath not in self.expandedPrimPaths: - self.expandedPrimPaths.append(primPath) - self.CopyExpandedPrimPathsToNode() - - # If the item being expanded has no children AND - # has an unloaded payload, load that payload now. - if item.childCount() == 0 and item.hasUnloadedPayload(): - model.LoadPrimAndBuildTree(model.GetPrim(item), item) - - # Now that this item is expanded, open - # persistent editors for its children. - for row in range(model.rowCount(index)): - self.OpenPersistentEditors(index.child(row, 0)) - - # Increase the columnWidth, if needed. - columnWidth = self.view.sizeHintForColumn(COL_NAME) - if self.view.columnWidth(COL_NAME) < columnWidth: - self.view.setColumnWidth(COL_NAME, columnWidth) - - def OnCollapsed(self, index): - model = self.view.model() - item = model.itemFromIndex(index) - - primPath = item.primPath().pathString - if primPath in self.expandedPrimPaths: - self.expandedPrimPaths.remove(primPath) - self.CopyExpandedPrimPathsToNode() - - def CopyExpandedPrimPathsToNode(self): - node = self.view.model().GetNode() - if node is not None: - parm = node.parm(TreeModel.parmUiExpandState) - # Note this parm never gets set to the empty string by this - # function. There will always be at least one '\n'. This is to - # help differentiate between cases when the parm is still set to - # its initial empty value and cases when all former entries have - # been removed (collapsed). - parm.set('\n'.join(self.expandedPrimPaths) + '\n') - - def OpenPersistentEditors(self, index): - row = index.row() - self.view.openPersistentEditor(index.sibling(row, COL_IMPORT)) - self.view.openPersistentEditor(index.sibling(row, COL_VARIANT)) - - def ShowVariants(self, state): - if state == Qt.Checked: - self.view.showColumn(COL_VARIANT) - elif state == Qt.Unchecked: - self.view.hideColumn(COL_VARIANT) - - topIndex = self.view.model().index(0, 0, QModelIndex()) - if topIndex.isValid(): - self.UpdateSizeHints(topIndex) - - def UpdateSizeHints(self, index): - # Only items that have variants will ever - # need to change their size hints. - if len(index.internalPointer().data(COL_VARIANT)) > 0: - self.view.itemDelegate(index).sizeHintChanged.emit(index) - - # If this item is expanded, recursively - # update size hints for its children. - if self.view.isExpanded(index): - rowCount = self.view.model().rowCount(index) - for row in range(rowCount): - self.UpdateSizeHints(index.child(row, 0)) - - def PopupRightClickMenu(self, pos): - if self.focusWidget() == self.view: - menu = QMenu(self) - importAction = menu.addAction("Import") - unimportAction = menu.addAction("Unimport") - action = menu.exec_(self.view.mapToGlobal(pos)) - if action is not None: - state = Qt.Checked if action == importAction else Qt.Unchecked - for index in self.view.selectedIndexes(): - # Skip items from every column except the import column. - if index.column() == COL_IMPORT: - self.view.model().setData(index, state, Qt.EditRole) - - def OnSelectionCopied(self): - indexes = self.view.selectionModel().selectedRows() - if len(indexes) == 0: - return - - # If there is more than one selected index, sort them. - if len(indexes) > 1: - profiles = [] - for index in indexes: - profile = '' - while index.isValid(): - profile = str(index.row()) + profile - index = index.parent() - profiles.append(profile) - zipped = zip(profiles, indexes) - zipped.sort() - profiles, indexes = zip(*zipped) - - selection = '' - for i, index in enumerate(indexes): - item = index.internalPointer() - if i > 0: - selection += '\n' - selection += self.view.model().VariantPrimPathFromItem(item) - - qApp.clipboard().setText(selection) - - def OnExpandToImported(self): - first = True - for index in self.view.model().GetImportedIndexes(): - parent = index.parent() - while parent.isValid(): - if self.view.isRowHidden(index.row(), parent): - self.view.setRowHidden(index.row(), parent, False) - self.view.expand(parent) - if first: - first = False - self.view.scrollTo(index,\ - QAbstractItemView.PositionAtCenter) - index = parent - parent = index.parent() - - def OnFilterApplied(self, filterString): - # Helper method to traverse the tree and hide all rows that don't - # match filterString. - def Hide(index): - rowHidden = [] - rowCount = self.view.model().rowCount(index) - for row in range(rowCount): - rowHidden.append(Hide(index.child(row, 0))) - - if False in rowHidden: - # This index has at least one row to be unhidden, so expand - # the index to make sure its unhidden row(s) will be showing. - self.view.expand(index) - - # Now go through each row to actually hide or unhide it. (Note - # that only siblings of unhidden rows are ever truly hidden. - # Rows without unhidden siblings are just collapsed instead). - for row in range(rowCount): - self.view.setRowHidden(row, index, rowHidden[row]) - - # Return False to indicate this index will NOT be hidden. - return False - else: - # This index has only hidden rows. Instead of hiding them - # (which essentially removes them), just collapse this index - # so the rows aren't immediately visible. - self.view.collapse(index) - - # Now go through each row and actually *unhide* any that may - # be currently hidden. This may seem counter-intuitive, but - # this is done to have as few removed rows as possible. Having - # them collapsed is enough to hide them. - for row in range(rowCount): - if self.view.isRowHidden(row, index): - self.view.setRowHidden(row, index, False) - - # Check if this index itself matches filterString so its parent - # can be notified whether to hide or unhide it. - match = index.internalPointer().matchesFilter(filterString) - return (match == None) - - # Helper method to traverse the tree and unhide all items. - def Unhide(index): - if self.view.isRowHidden(index.row(), index.parent()): - self.view.setRowHidden(index.row(), index.parent(), False) - for row in range(self.view.model().rowCount(index)): - Unhide(index.child(row, 0)) - - # If filterString is only 1 char, do nothing. (A single char would - # match far too many paths to be useful and it could get pretty slow.) - if len(filterString) == 1: - return - - topIndex = self.view.model().index(0, 0, QModelIndex()) - # topIndex will be invalid when model is the emptyModel. - if not topIndex.isValid(): - return - - # If filterString is empty, unhide all items. - if filterString == '': - Unhide(topIndex) - return - - # Recursively hide items that don't match filterString. - hide = Hide(topIndex) - self.view.setRowHidden(topIndex.row(), topIndex.parent(), hide) diff --git a/third_party/houdini/gusd/valueUtils.cpp b/third_party/houdini/gusd/valueUtils.cpp deleted file mode 100644 index f9959111be..0000000000 --- a/third_party/houdini/gusd/valueUtils.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -// -// Copyright 2019 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "valueUtils.h" - -#include "error.h" -#include "USD_Utils.h" -#include "UT_TypeTraits.h" - -#include "pxr/base/arch/hints.h" -#include "pxr/usd/sdf/types.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -namespace { - - -/// Helper for periodically polling for interrupts. -class _InterruptPoll -{ -public: - _InterruptPoll(UT_Interrupt* boss=UTgetInterrupt()) : _boss(boss) - { UT_ASSERT_P(boss); } - - SYS_FORCE_INLINE bool operator()() - { return ARCH_UNLIKELY(!++_bcnt && _boss->opInterrupt()); } - -private: - UT_Interrupt* const _boss; - unsigned char _bcnt = 0; -}; - - -/// Struct giving the elem type of a VtArray, or the input arg for non-arrays. -template -struct _ElemType { using type = T; }; - -template -struct _ElemType::value>::type> -{ using type = typename T::value_type; }; - - -/// Struct giving the best matching scalar type supported by GA API, -/// for interacting with a USD scalar type. -template -struct _UsdScalarToGaScalar { using type = T; }; - -// Cast bools to integers for purposes of GA_AIFTuple/GA_AIFNumericArray -// queries. Group attributes are handled separately. -template <> -struct _UsdScalarToGaScalar { using type = int32; }; - -template <> -struct _UsdScalarToGaScalar { using type = int32; }; - -// XXX: potentially lossy -template <> -struct _UsdScalarToGaScalar { using type = int32; }; - -// XXX: potentially lossy -template <> -struct _UsdScalarToGaScalar { using type = int64; }; - -template <> -struct _UsdScalarToGaScalar { using type = fpreal32; }; - -template <> -struct _UsdScalarToGaScalar { using type = fpreal32; }; - - -template -constexpr bool _UsdValueIsNumeric() -{ - using ElemType = typename _ElemType::type; - return (std::is_arithmetic::value || - GfIsGfMatrix::value || - GfIsGfQuat::value || - GfIsGfVec::value); -} - - -template -constexpr bool _UsdValueIsString() -{ - using ElemType = typename _ElemType::type; - return (SYSisSame() || - SYSisSame() || - SYSisSame()); -} - - -/// Traits of a numeric scalar/tuple types. -template -struct _UsdNumericValueTraits -{ - using UsdTupleType = T; - using UsdScalarType = typename GusdPodTupleTraits::ValueType; - using GaScalarType = typename _UsdScalarToGaScalar::type; - - static const int tupleSize = GusdGetTupleSize(); - - static void ResizeByTupleCount(const T& value, size_t count) {} - - static void ResizeByScalarCount(const T& value, size_t count) {} - - static size_t GetNumScalars(const T& value) { return tupleSize; } - - static size_t GetNumTuples(const T& value) { return 1; } - - static UsdScalarType* GetScalarDataPtr(T& value) - { - return reinterpret_cast< - UsdScalarType*>(&value); - } - - static const UsdScalarType* GetConstScalarDataPtr(const T& value) - { - return reinterpret_cast< - const UsdScalarType*>(&value); - } -}; - - -/// Traits of a VtArray holding a numeric scalar/tuple. -template -struct _UsdNumericValueTraits< - T, typename std::enable_if::value>::type> -{ - using UsdTupleType = typename T::value_type; - using UsdScalarType = typename GusdPodTupleTraits::ValueType; - using GaScalarType = typename _UsdScalarToGaScalar::type; - - static const int tupleSize = GusdGetTupleSize(); - - static void ResizeByTupleCount(T& value, size_t size) - { value.resize(size); } - - static void ResizeByScalarCount(T& value, size_t size) - { value.resize(size/tupleSize + (size%tupleSize ? 1 : 0)); } - - static size_t GetNumScalars(const T& value) - { return value.size()*tupleSize; } - - static size_t GetNumTuples(const T& value) { return value.size();} - - static UsdScalarType* GetScalarDataPtr(T& value) - { - return reinterpret_cast( - value.data()); - } - - static const UsdScalarType* GetConstScalarDataPtr(const T& value) - { - return reinterpret_cast< - const UsdScalarType*>(value.cdata()); - } -}; - - -// -------------------------------------------------- -// _NumericAttrToUsdValues -// -------------------------------------------------- - - -template -struct _NumericAttrToUsdValues -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { return false; } -}; - - -/// Direct numeric value extraction. -/// Extracts to scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. -template -struct _NumericAttrToUsdValues< - T, typename std::enable_if< - _UsdValueIsNumeric() && - SYSisSame::UsdScalarType, - typename _UsdNumericValueTraits::GaScalarType>()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - - const auto* aif = attr.getAIFTuple(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from numeric attr"); - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - T& value = values[i]; - - Traits::ResizeByScalarCount(value, attr.getTupleSize()); - - const int numScalarsToExtract = - SYSmin(attr.getTupleSize(), - static_cast(Traits::GetNumScalars(value))); - - aif->get(&attr, offsets[i], - Traits::GetScalarDataPtr(value), - numScalarsToExtract); - } - }); - return !task.wasInterrupted(); - } -}; - - -/// Indirect numeric value extraction. -/// Extracts to scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. This form is used for values that require temporary -/// storage when extracting values, due to limited type support of the -/// GA_AIFTuple API. For example, GA_AIFTuple::get() has no method -/// using uint64 precision, so we must first get() the value with a type -/// that GA_AIFTuple supports, then cast it to our given USD type. -template -struct _NumericAttrToUsdValues< - T, typename std::enable_if< - _UsdValueIsNumeric() && - !SYSisSame< - typename _UsdNumericValueTraits::UsdScalarType, - typename _UsdNumericValueTraits::GaScalarType>()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - - const auto* aif = attr.getAIFTuple(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from numeric attr"); - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - UT_Array gaValues; - gaValues.setSize(attr.getTupleSize()); - - _InterruptPoll interrupt; - - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - if (aif->get(&attr, offsets[i], - gaValues.data(), attr.getTupleSize())) { - - T& value = values[i]; - Traits::ResizeByScalarCount(value, attr.getTupleSize()); - - const int numScalarsToExtract = - SYSmin(attr.getTupleSize(), - static_cast( - Traits::GetNumScalars(value))); - - UsdScalarType* dst = - Traits::GetScalarDataPtr(values[i]); - for (int si = 0; si < numScalarsToExtract; ++si) { - dst[si] = static_cast(gaValues[si]); - } - } - } - }); - return !task.wasInterrupted(); - } -}; - - -// -------------------------------------------------- -// _GroupAttrToUsdValues -// -------------------------------------------------- - - -template -struct _GroupAttrToUsdValues -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { return false; } -}; - - -template -struct _GroupAttrToUsdValues< - T, typename std::enable_if<_UsdValueIsNumeric()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - - const auto* groupAttr = GA_ATIGroupBool::cast(&attr); - if (!groupAttr) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from group attr"); - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - T& value = values[i]; - - Traits::ResizeByScalarCount(value, 1); - - if (Traits::GetNumScalars(value) > 0) { - *Traits::GetScalarDataPtr(value) = - static_cast( - groupAttr->contains(offsets[i])); - } - } - }); - return !task.wasInterrupted(); - } -}; - - -// -------------------------------------------------- -// _NumericArrayAttrToUsdValues -// -------------------------------------------------- - - -template -struct _NumericArrayAttrToUsdValues -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { return false; } -}; - - -/// Direct numeric array extraction. -/// Extracts to scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. -template -struct _NumericArrayAttrToUsdValues< - T, typename std::enable_if< - _UsdValueIsNumeric() && - SYSisSame::UsdScalarType, - typename _UsdNumericValueTraits::GaScalarType>()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - - const auto* aif = attr.getAIFNumericArray(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from numeric array attr"); - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - - UT_Array gaArray; - - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - const exint arraySize = aif->arraySize(&attr, offsets[i]); - if (arraySize == 0) { - continue; - } - - T& value = values[i]; - Traits::ResizeByScalarCount(value, arraySize); - - if (Traits::GetNumScalars(value) >= arraySize) { - // XXX: Using unsafeShareData to avoid an extra copy. - // This is safe for core ATIs, but could fail in custom - // types, depending on the implementation. - // If failures occur, consider white-listing types. - gaArray.unsafeShareData( - Traits::GetScalarDataPtr(value), - Traits::GetNumScalars(value)); - - UT_ASSERT_P(gaArray.data() == - Traits::GetScalarDataPtr(value)); - UT_ASSERT_P(gaArray.size() == - Traits::GetNumScalars(value)); - - aif->get(&attr, offsets[i], gaArray); - - // Verify that the array is still referencing the - // same data. - UT_ASSERT_P(gaArray.data() == - Traits::GetScalarDataPtr(value)); - UT_ASSERT_P(gaArray.size() == - Traits::GetNumScalars(value)); - - gaArray.unsafeClearData(); - } else { - // Our value can't be resized as expected for - // this array. Will need to extract a copy - // into our temporary array, then convert. - if (aif->get(&attr, offsets[i], gaArray)) { - const exint numScalarsToExtract = - SYSmin(gaArray.size(), - static_cast( - Traits::GetNumScalars(value))); - - std::copy(gaArray.data(), - gaArray.data() + numScalarsToExtract, - Traits::GetScalarDataPtr(value)); - } - } - } - }); - return !task.wasInterrupted(); - } -}; - - -/// Indirect numeric array extraction. -/// Extracts to scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. This form is used for values that require temporary storage -/// when extracting values, due to limited type support of the -/// GA_AIFNumericArray API. -template -struct _NumericArrayAttrToUsdValues< - T, typename std::enable_if< - _UsdValueIsNumeric() && - !SYSisSame< - typename _UsdNumericValueTraits::UsdScalarType, - typename _UsdNumericValueTraits::GaScalarType>()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - - const auto* aif = attr.getAIFNumericArray(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from numeric array attr"); - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - - UT_Array gaArray; - - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - if (aif->get(&attr, offsets[i], gaArray)) { - - T& value = values[i]; - Traits::ResizeByScalarCount(value, gaArray.size()); - - const exint numScalarsToExtract = - SYSmin(gaArray.size(), - static_cast( - Traits::GetNumScalars(value))); - - UsdScalarType* dst = Traits::GetScalarDataPtr(value); - for (exint si = 0; si < numScalarsToExtract; ++si) { - dst[si] = static_cast(gaArray[si]); - } - } - } - }); - return !task.wasInterrupted(); - } -}; - - -// -------------------------------------------------- -// _UsdValuesToNumericAttr -// -------------------------------------------------- - - -template -struct _UsdValuesToNumericAttr -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { return false; } -}; - - -/// Numeric value writes. -/// Writes scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. -template -struct _UsdValuesToNumericAttr< - T, typename std::enable_if<_UsdValueIsNumeric()>::type> -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - using PageHandle = typename GA_PageHandleScalar::RWType; - - if (PageHandle(&attr).isInvalid()) { - return false; - } - - UT_AutoInterrupt task("Write USD values to numeric attr"); - - UTparallelForLightItems( - GA_SplittableRange(range), - [&](const GA_SplittableRange& r) - { - // Bind a page handle per tuple component. - UT_Array pageHandles; - pageHandles.setSize(attr.getTupleSize()); - for (int i = 0; i < attr.getTupleSize(); ++i) { - pageHandles[i].bind(&attr, i); - } - - _InterruptPoll interrupt; - - GA_Offset o,end; - for (GA_Iterator it(r); it.blockAdvance(o,end); ) { - if (interrupt()) { - return; - } - - for (auto& pageHandle : pageHandles) { - pageHandle.setPage(o); - } - - for ( ; o < end; ++o) { - const GA_Index index = rangeIndices[o]; - - const T& value = values[index]; - const UsdScalarType* src = - Traits::GetConstScalarDataPtr(value); - - const int numScalarsToWrite = - SYSmin(attr.getTupleSize(), - static_cast( - Traits::GetNumScalars(value))); - - for (int si = 0; si < numScalarsToWrite; ++si) { - pageHandles[si].set( - o, static_cast(src[si])); - } - } - } - }); - return !task.wasInterrupted(); - } -}; - - -// -------------------------------------------------- -// _UsdValuesToGroupAttr -// -------------------------------------------------- - - -template -struct _UsdValuesToGroupAttr -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { return false; } -}; - - -/// Numeric value writes. -/// Writes scalars or the first value of an array of scalars to a group attr. -template -struct _UsdValuesToGroupAttr< - T, typename std::enable_if<_UsdValueIsNumeric()>::type> -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - - auto* groupAttr = GA_ATIGroupBool::cast(&attr); - if (!groupAttr) { - return false; - } - - UT_AutoInterrupt task("Write USD values to group attr"); - - _InterruptPoll interrupt; - - GA_Offset o,end; - for (GA_Iterator it(range); it.blockAdvance(o,end); ) { - if (interrupt()) { - return false; - } - - for ( ; o < end; ++o) { - const GA_Index index = rangeIndices[o]; - const T& value = values[index]; - - if (Traits::GetNumScalars(value) > 0) { - const bool isMember = - static_cast( - *Traits::GetConstScalarDataPtr(value)); - - groupAttr->setElement(o, isMember); - } - } - } - return true; - } -}; - - -// -------------------------------------------------- -// _UsdValuesToNumericArrayAttr -// -------------------------------------------------- - - -template -struct _UsdValuesToNumericArrayAttr -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { return false; } -}; - - -/// Direct numeric array writes. -/// Writes scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. -template -struct _UsdValuesToNumericArrayAttr< - T, typename std::enable_if< - _UsdValueIsNumeric() && - SYSisSame< - typename _UsdNumericValueTraits::UsdScalarType, - typename _UsdNumericValueTraits::GaScalarType>()>::type> -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - - const auto* aif = attr.getAIFNumericArray(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Write USD values to numeric array attr"); - - // TODO: Can this be done in parallel? - - _InterruptPoll interrupt; - - UT_Array gaArray; - - GA_Offset o, end; - for (GA_Iterator it(range); it.blockAdvance(o,end); ) { - if (interrupt()) { - return false; - } - - for ( ; o < end; ++o) { - const T& value = values[rangeIndices[o]]; - - // XXX: Using unsafeShareData to avoid an extract copy. - // This is safe for core ATIs, but could fail in custom - // types, depending on the implementation. - // If failures occur, consider white-listing types. - gaArray.unsafeShareData( - SYSconst_cast(Traits::GetConstScalarDataPtr(value)), - Traits::GetNumScalars(value)); - - aif->set(&attr, o, gaArray); - - gaArray.unsafeClearData(); - } - } - return true; - } -}; - - -/// Indirect numeric array writes. -/// Writes scalars, vectors, matrices and quaternions, as well as their -/// VtArray forms. This form is used for types that require temporary -/// storage when extracting values, due to limited type support of the -/// GA_AIFNumericArray API. -template -struct _UsdValuesToNumericArrayAttr< - T, typename std::enable_if< - _UsdValueIsNumeric() && - !SYSisSame< - typename _UsdNumericValueTraits::UsdScalarType, - typename _UsdNumericValueTraits::GaScalarType>()>::type> -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { - using Traits = _UsdNumericValueTraits; - using UsdScalarType = typename Traits::UsdScalarType; - using GaScalarType = typename Traits::GaScalarType; - - const auto* aif = attr.getAIFNumericArray(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Write USD values to numeric array attr"); - - // TODO: Can this be done in parallel? - - _InterruptPoll interrupt; - - UT_Array gaArray; - - GA_Offset o, end; - for (GA_Iterator it(range); it.blockAdvance(o,end); ) { - if (interrupt()) { - return false; - } - - for ( ; o < end; ++o) { - const T& value = values[rangeIndices[o]]; - - const size_t numScalars = Traits::GetNumScalars(value); - gaArray.setSize(numScalars); - - const UsdScalarType* src = Traits::GetConstScalarDataPtr(value); - for (size_t si = 0; si < numScalars; ++si) { - gaArray[si] = static_cast(src[si]); - } - - aif->set(&attr, o, gaArray); - } - } - return true; - } -}; - -// -------------------------------------------------- -// String Types -// -------------------------------------------------- - - -/// Traits of a string type. -template -struct _UsdStringValueTraits -{ - using UsdStringType = T; - - static void Resize(const T& value, size_t size) {} - - static size_t GetSize(const T& value) { return 1; } - - static UsdStringType* GetStringDataPtr(T& value) - { return &value; } - - static const UsdStringType* GetConstStringDataPtr(const T& value) - { return &value; } -}; - - -/// Traits of a VtArray holding a string type. -template -struct _UsdStringValueTraits< - T, typename std::enable_if::value>::type> -{ - using UsdStringType = typename T::value_type; - - static void Resize(T& value, size_t size) - { value.resize(size); } - - static size_t GetSize(const T& value) - { return value.size(); } - - static UsdStringType* GetStringDataPtr(T& value) - { return value.data(); } - - static const UsdStringType* GetConstStringDataPtr(const T& value) - { return value.cdata(); } -}; - - -template struct _UsdStringOps {}; - -template <> -struct _UsdStringOps -{ - - static std::string FromStringRef(const UT_StringRef& str) - { return str.toStdString(); } - - static UT_StringHolder ToStringHolder(const std::string& str) - { return UT_StringHolder(str); } -}; - -template <> -struct _UsdStringOps -{ - - static TfToken FromStringRef(const UT_StringRef& str) - { return TfToken(str.toStdString()); } - - static UT_StringHolder ToStringHolder(const TfToken& token) - { return GusdUSD_Utils::TokenToStringHolder(token); } -}; - -template <> -struct _UsdStringOps -{ - static SdfAssetPath FromStringRef(const UT_StringRef& str) - { return SdfAssetPath(str.toStdString()); } - - static UT_StringHolder ToStringHolder(const SdfAssetPath& path) - { return UT_StringHolder(path.GetAssetPath()); } -}; - - -// -------------------------------------------------- -// _StringAttrToUsdValues -// -------------------------------------------------- - - -template -struct _StringAttrToUsdValues -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { return false; } -}; - - -template -struct _StringAttrToUsdValues< - T, typename std::enable_if<_UsdValueIsString()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdStringValueTraits; - using UsdStringType = typename Traits::UsdStringType; - using Ops = _UsdStringOps; - - const auto* aif = attr.getAIFSharedStringTuple(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from string attr"); - - // Pre-extract all unique string values. - UT_Array uniqueValues; - uniqueValues.setSize(aif->getTableEntries(&attr)); - - UTparallelForLightItems( - UT_BlockedRange(0, uniqueValues.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - uniqueValues[i] = - Ops::FromStringRef(aif->getTableString(&attr, i)); - } - }); - if (task.wasInterrupted()) { - return false; - } - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - T& value = values[i]; - Traits::Resize(value, attr.getTupleSize()); - - const int numStringsToExtract = - SYSmin(attr.getTupleSize(), - static_cast(Traits::GetSize(value))); - - UsdStringType* dst = Traits::GetStringDataPtr(value); - for (int si = 0; si < numStringsToExtract; ++si) { - const GA_StringIndexType handle = - aif->getHandle(&attr, offsets[i], si); - if (handle >= 0) { - dst[si] = uniqueValues[handle]; - } - } - } - }); - return !task.wasInterrupted(); - } -}; - - -// -------------------------------------------------- -// _StringArrayToUsdValues -// -------------------------------------------------- - - -template -struct _StringArrayAttrToUsdValues -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { return false; } -}; - - -template -struct _StringArrayAttrToUsdValues< - T, typename std::enable_if<_UsdValueIsString()>::type> -{ - bool operator()(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) const - { - using Traits = _UsdStringValueTraits; - using UsdStringType = typename Traits::UsdStringType; - using Ops = _UsdStringOps; - - const auto* aif = attr.getAIFSharedStringArray(); - if (!aif) { - return false; - } - - UT_AutoInterrupt task("Extract USD values from string array attr"); - - // Pre-extract all unique string values. - UT_Array uniqueValues; - uniqueValues.setSize(aif->getTableEntries(&attr)); - - UTparallelForLightItems( - UT_BlockedRange(0, uniqueValues.size()), - [&](const UT_BlockedRange& r) - { - _InterruptPoll interrupt; - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - uniqueValues[i] = - Ops::FromStringRef(aif->getTableString(&attr, i)); - } - }); - if (task.wasInterrupted()) { - return false; - } - - UTparallelForLightItems( - UT_BlockedRange(0, offsets.size()), - [&](const UT_BlockedRange& r) - { - UT_Array handles; - - _InterruptPoll interrupt; - for (size_t i = r.begin(); i < r.end(); ++i) { - if (interrupt()) { - return; - } - - aif->getStringIndex(&attr, offsets[i], handles); - if (handles.size() > 0) { - T& value = values[i]; - Traits::Resize(value, handles.size()); - - const exint numStringsToExtract = - SYSmin(handles.size(), - static_cast(Traits::GetSize(value))); - - UsdStringType* dst = Traits::GetStringDataPtr(value); - for (exint si = 0; si < numStringsToExtract; ++si) { - const auto handle = handles[si]; - if (handle >= 0) { - dst[si] = uniqueValues[handle]; - } - } - } - } - }); - return !task.wasInterrupted(); - } -}; - - -// -------------------------------------------------- -// _UsdValuesToStringAttr -// -------------------------------------------------- - - -template -struct _UsdValuesToStringAttr -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { return false; } -}; - - -template -struct _UsdValuesToStringAttr< - T, typename std::enable_if<_UsdValueIsString()>::type> -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { - using Traits = _UsdStringValueTraits; - using UsdStringType = typename Traits::UsdStringType; - using Ops = _UsdStringOps; - - GA_RWHandleS hnd(&attr); - if (hnd.isInvalid()) { - return false; - } - - UT_AutoInterrupt task("Write USD values from string attr"); - - // TODO: Can we do thsi in parallel? - - _InterruptPoll interrupt; - GA_Offset o, end; - for (GA_Iterator it(range); it.blockAdvance(o,end); ) { - if (interrupt()) { - return false; - } - - for ( ; o < end; ++o) { - const T& value = values[rangeIndices[o]]; - - const int numStringsToWrite = - SYSmin(attr.getTupleSize(), - static_cast(Traits::GetSize(value))); - - const UsdStringType* src = Traits::GetConstStringDataPtr(value); - for (int si = 0; si < numStringsToWrite; ++si) { - hnd.set(o, si, Ops::ToStringHolder(src[si])); - } - } - } - return true; - } -}; - - -// -------------------------------------------------- -// _UsdValuesToStringArrayAttr -// -------------------------------------------------- - - -template -struct _UsdValuesToStringArrayAttr -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { return false; } -}; - - -template -struct _UsdValuesToStringArrayAttr< - T, typename std::enable_if<_UsdValueIsString()>::type> -{ - bool operator()(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) const - { - using Traits = _UsdStringValueTraits; - using UsdStringType = typename Traits::UsdStringType; - using Ops = _UsdStringOps; - - GA_RWHandleSA hnd(&attr); - if (hnd.isInvalid()) { - return false; - } - - UT_AutoInterrupt task("Write USD values from string array attr"); - - // TODO: Can we do this in parallel? - - UT_StringArray gaArray; - _InterruptPoll interrupt; - - GA_Offset o, end; - for (GA_Iterator it(range); it.blockAdvance(o,end); ) { - if (interrupt()) { - return false; - } - - for ( ; o < end; ++o) { - const T& value = values[rangeIndices[o]]; - - gaArray.setSize(Traits::GetSize(value)); - - const UsdStringType* src = Traits::GetConstStringDataPtr(value); - for (exint si = 0; si < gaArray.size(); ++si) { - gaArray[si] = Ops::ToStringHolder(src[si]); - } - - hnd.set(o, gaArray); - } - } - return true; - } -}; - - -} // namespace - - -template -bool -GusdReadUsdValuesFromAttr(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values) -{ - if (offsets.size() != values.size()) { - GUSD_WARN().Msg("offsets size [%zu] != values size [%zu]", - offsets.size(), values.size()); - return false; - } - - if (GA_ATIString::isType(&attr)) { - return _StringAttrToUsdValues()(attr, offsets, values); - } else if (GA_ATIStringArray::isType(&attr)) { - return _StringArrayAttrToUsdValues()(attr, offsets, values); - } else if (GA_ATINumericArray::isType(&attr)) { - return _NumericArrayAttrToUsdValues()(attr, offsets, values); - } else if (GA_ATIGroupBool::isType(&attr)) { - return _GroupAttrToUsdValues()(attr, offsets, values); - } else { - // Try and process all other types as numerics. - return _NumericAttrToUsdValues()(attr, offsets, values); - } -} - -// Instantiate templated method for all Sdf value types. - -#define GUSD_DEFINE_READ_ATTR(r, unused, elem) \ - template bool GusdReadUsdValuesFromAttr( \ - const GA_Attribute&, \ - const TfSpan&, \ - const TfSpan&); \ - \ - template bool GusdReadUsdValuesFromAttr( \ - const GA_Attribute&, \ - const TfSpan&, \ - const TfSpan>&); - -BOOST_PP_SEQ_FOR_EACH(GUSD_DEFINE_READ_ATTR, ~, SDF_VALUE_TYPES); - -#undef GUSD_DEFINE_READ_ATTR - - -template -bool -GusdWriteUsdValuesToAttr(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values) -{ - if (rangeIndices.size() != values.size()) { - GUSD_WARN().Msg("rangeIndices size [%zu] != values size [%zu]", - rangeIndices.size(), values.size()); - return false; - } - UT_ASSERT_P(range.getEntries() == rangeIndices.size()); - - if (GA_ATIString::isType(&attr)) { - return _UsdValuesToStringAttr()( - attr, range, rangeIndices, values); - } else if (GA_ATIStringArray::isType(&attr)) { - return _UsdValuesToStringArrayAttr()( - attr, range, rangeIndices, values); - } else if (GA_ATINumericArray::isType(&attr)) { - return _UsdValuesToNumericArrayAttr()( - attr, range, rangeIndices, values); - } else if (GA_ATIGroupBool::isType(&attr)) { - return _UsdValuesToGroupAttr()( - attr, range, rangeIndices, values); - } else { - // Try and process all other types as numerics. - return _UsdValuesToNumericAttr()( - attr, range, rangeIndices, values); - } -} - -// Instantiate templated method for all Sdf value types. - -#define GUSD_DEFINE_WRITE_ATTR(r, unused, elem) \ - template bool GusdWriteUsdValuesToAttr( \ - GA_Attribute&, const GA_Range&, \ - const TfSpan&, \ - const TfSpan&); \ - \ - template bool GusdWriteUsdValuesToAttr( \ - GA_Attribute&, const GA_Range&, \ - const TfSpan&, \ - const TfSpan>&); - -BOOST_PP_SEQ_FOR_EACH(GUSD_DEFINE_WRITE_ATTR, ~, SDF_VALUE_TYPES); - -#undef GUSD_DEFINE_WRITE_ATTR - - -namespace { - - -/// Returns the array-valued form of \p nonArrayType if \p isArray is true. -/// Otherwise returns the \p nonArrayType. -inline SdfValueTypeName -_GetTypeName(const SdfValueTypeName& nonArrayType, bool isArray) -{ - return isArray ? nonArrayType.GetArrayType() : nonArrayType; -} - - -/// Return the underlying GA_STORAGE type for \p attr. -GA_Storage -_GetAttrStorage(const GA_Attribute& attr) -{ - if (const auto* aif = attr.getAIFTuple()) { - return aif->getStorage(&attr); - } - if (const auto* aif = attr.getAIFNumericArray()) { - return aif->getStorage(&attr); - } - if (const auto* aif = attr.getAIFSharedStringArray()) { - return aif->getStorage(&attr); - } - // String attributes do not have a GA_AIFTuple implementation. - // For strings, refer to the storage class instead. - if (attr.getStorageClass() == GA_STORECLASS_STRING) { - return GA_STORE_STRING; - } - return GA_STORE_INVALID; -} - - -} // namespace - - -SdfValueTypeName -GusdGetSdfTypeNameForAttr(const GA_Attribute& attr) -{ - - const bool isArray = - GA_ATINumericArray::isType(&attr) || GA_ATIStringArray::isType(&attr); - const int tupleSize = attr.getTupleSize(); - const GA_Storage storage = _GetAttrStorage(attr); - const GA_TypeInfo typeInfo = attr.getTypeInfo(); - - switch (storage) - { - case GA_STORE_BOOL: - return _GetTypeName(SdfValueTypeNames->Bool, - isArray || tupleSize != 1); - case GA_STORE_UINT8: - return _GetTypeName(SdfValueTypeNames->UChar, - isArray || tupleSize != 1); - case GA_STORE_INT8: - case GA_STORE_INT16: - case GA_STORE_INT32: - if (tupleSize == 1) { - return _GetTypeName(SdfValueTypeNames->Int, isArray); - } else if (tupleSize == 2) { - return _GetTypeName(SdfValueTypeNames->Int2, isArray); - } else if (tupleSize == 3) { - return _GetTypeName(SdfValueTypeNames->Int3, isArray); - } - return SdfValueTypeNames->IntArray; - - case GA_STORE_REAL16: - if (tupleSize == 1) { - return _GetTypeName(SdfValueTypeNames->Half, isArray); - } else if (tupleSize == 2) { - if (typeInfo == GA_TYPE_TEXTURE_COORD) { - return _GetTypeName(SdfValueTypeNames->TexCoord2h, isArray); - } else { - return _GetTypeName(SdfValueTypeNames->Half2, isArray); - } - } else if (tupleSize == 3) { - switch (typeInfo) - { - case GA_TYPE_POINT: - return _GetTypeName(SdfValueTypeNames->Point3h, isArray); - case GA_TYPE_VECTOR: - return _GetTypeName(SdfValueTypeNames->Vector3h, isArray); - case GA_TYPE_NORMAL: - return _GetTypeName(SdfValueTypeNames->Normal3h, isArray); - case GA_TYPE_COLOR: - return _GetTypeName(SdfValueTypeNames->Color3h, isArray); - case GA_TYPE_TRANSFORM: - return _GetTypeName(SdfValueTypeNames->Matrix2d, isArray); - case GA_TYPE_TEXTURE_COORD: - return _GetTypeName(SdfValueTypeNames->TexCoord3h, isArray); - default: - return _GetTypeName(SdfValueTypeNames->Half3, isArray); - } - } else if (tupleSize == 4) { - if (typeInfo == GA_TYPE_COLOR) { - return _GetTypeName(SdfValueTypeNames->Color4h, isArray); - } else { - return _GetTypeName(SdfValueTypeNames->Half4, isArray); - } - } else if (tupleSize == 9 && typeInfo == GA_TYPE_TRANSFORM) { - return _GetTypeName(SdfValueTypeNames->Matrix3d, isArray); - } else if (tupleSize == 16 && typeInfo == GA_TYPE_TRANSFORM) { - return _GetTypeName(SdfValueTypeNames->Matrix4d, isArray); - } - return SdfValueTypeNames->HalfArray; - - case GA_STORE_REAL32: - if (tupleSize == 1) { - return _GetTypeName(SdfValueTypeNames->Float, isArray); - } else if (tupleSize == 2) { - if (typeInfo == GA_TYPE_TEXTURE_COORD) { - return _GetTypeName(SdfValueTypeNames->TexCoord2f, isArray); - } else { - return _GetTypeName(SdfValueTypeNames->Float2, isArray); - } - } else if (tupleSize == 3) { - switch (typeInfo) - { - case GA_TYPE_POINT: - return _GetTypeName(SdfValueTypeNames->Point3f, isArray); - case GA_TYPE_VECTOR: - return _GetTypeName(SdfValueTypeNames->Vector3f, isArray); - case GA_TYPE_NORMAL: - return _GetTypeName(SdfValueTypeNames->Normal3f, isArray); - case GA_TYPE_COLOR: - return _GetTypeName(SdfValueTypeNames->Color3f, isArray); - case GA_TYPE_TRANSFORM: - return _GetTypeName(SdfValueTypeNames->Matrix2d, isArray); - case GA_TYPE_TEXTURE_COORD: - return _GetTypeName(SdfValueTypeNames->TexCoord3f, isArray); - default: - return _GetTypeName(SdfValueTypeNames->Float3, isArray); - } - } else if (tupleSize == 4) { - if (typeInfo == GA_TYPE_COLOR) { - return _GetTypeName(SdfValueTypeNames->Color4f, isArray); - } else { - return _GetTypeName(SdfValueTypeNames->Float4, isArray); - } - } else if (tupleSize == 9 && typeInfo == GA_TYPE_TRANSFORM) { - return _GetTypeName(SdfValueTypeNames->Matrix3d, isArray); - } else if (tupleSize == 16 && typeInfo == GA_TYPE_TRANSFORM) { - return _GetTypeName(SdfValueTypeNames->Matrix4d, isArray); - } - return SdfValueTypeNames->FloatArray; - - case GA_STORE_REAL64: - if (tupleSize == 1) { - return _GetTypeName(SdfValueTypeNames->Double, isArray); - } else if (tupleSize == 2) { - if (typeInfo == GA_TYPE_TEXTURE_COORD) { - return _GetTypeName(SdfValueTypeNames->TexCoord2d, isArray); - } else { - return _GetTypeName(SdfValueTypeNames->Double2, isArray); - } - } else if (tupleSize == 3) { - switch (typeInfo) - { - case GA_TYPE_POINT: - return _GetTypeName(SdfValueTypeNames->Point3d, isArray); - case GA_TYPE_VECTOR: - return _GetTypeName(SdfValueTypeNames->Vector3d, isArray); - case GA_TYPE_NORMAL: - return _GetTypeName(SdfValueTypeNames->Normal3d, isArray); - case GA_TYPE_COLOR: - return _GetTypeName(SdfValueTypeNames->Color3d, isArray); - case GA_TYPE_TRANSFORM: - return _GetTypeName(SdfValueTypeNames->Matrix2d, isArray); - case GA_TYPE_TEXTURE_COORD: - return _GetTypeName(SdfValueTypeNames->TexCoord3d, isArray); - default: - return _GetTypeName(SdfValueTypeNames->Double3, isArray); - } - } else if (tupleSize == 4) { - if (typeInfo == GA_TYPE_COLOR) { - return _GetTypeName(SdfValueTypeNames->Color4d, isArray); - } else { - return _GetTypeName(SdfValueTypeNames->Double4, isArray); - } - } else if (tupleSize == 9 && typeInfo == GA_TYPE_TRANSFORM) { - return _GetTypeName(SdfValueTypeNames->Matrix3d, isArray); - } else if (tupleSize == 16 && typeInfo == GA_TYPE_TRANSFORM) { - return _GetTypeName(SdfValueTypeNames->Matrix4d, isArray); - } - return SdfValueTypeNames->DoubleArray; - - case GA_STORE_STRING: - // TODO: String, Token and Asset are all valid answers here. - // Should the attribute store metadata telling us which type - // to use? Should it be based on the name? - return _GetTypeName(SdfValueTypeNames->String, - isArray || tupleSize != 1); - default: - return SdfValueTypeName(); - }; -} - - -GA_TypeInfo -GusdGetTypeInfoForSdfRole(const TfToken& role, int tupleSize) -{ - // TODO: Determine if Houdini assumes a specific tupleSize - // for some of these type infos. Eg., is a color always - // assumed to have tupleSize == 3? Is it legitimate to - // attach GA_TYPE_TRANSFORM to a float of tupleSize == 9? - - if (role == SdfValueRoleNames->Point) { - if (tupleSize < 0 || tupleSize == 3) { - return GA_TYPE_POINT; - } else if (tupleSize == 4) { - return GA_TYPE_HPOINT; - } - } else if (role == SdfValueRoleNames->Normal) { - if (tupleSize < 0 || tupleSize == 3) { - return GA_TYPE_NORMAL; - } - } else if (role == SdfValueRoleNames->Vector) { - if (tupleSize < 0 || tupleSize == 3) { - return GA_TYPE_VECTOR; - } - } else if (role == SdfValueRoleNames->Color) { - if (tupleSize < 0 || tupleSize == 3 || tupleSize == 4) { - return GA_TYPE_COLOR; - } - } else if (role == SdfValueRoleNames->TextureCoordinate) { - if (tupleSize < 0 || tupleSize == 2 || tupleSize == 3) { - return GA_TYPE_TEXTURE_COORD; - } - } else if (role == SdfValueRoleNames->Frame || - role == SdfValueRoleNames->Transform) { - if (tupleSize < 0 || tupleSize == 16) { - return GA_TYPE_TRANSFORM; - } - } - - return GA_TYPE_VOID; -} - - -namespace { - - -template -struct _AttrScalarType -{ using type = T; }; - -template -struct _AttrScalarType::value>::type> -{ using type = typename T::value_type; }; - - -} // namespace - - -template -GA_Attribute* -GusdCreateAttrForUsdValueType(GEO_Detail& gd, - const GA_AttributeScope scope, - const GA_AttributeOwner owner, - const UT_StringHolder& name, - const UT_Options* creationArgs) -{ - const GA_Storage storage = GusdGetUsdValueTypeAttrStorage(); - if (storage == GA_STORE_INVALID) { - return nullptr; - } - - const int tupleSize = GusdGetUsdValueTypeTupleSize(); - - GA_Attribute* attr = nullptr; - - if (!VtIsArray()) { - attr = gd.addTuple(storage, owner, scope, name, tupleSize); - } else { - if (GAisFloatStorage(storage)) { - attr = gd.addFloatArray(owner, scope, name, tupleSize, creationArgs, - /*attr options*/ nullptr, storage); - } else if (GAisIntStorage(storage)) { - attr = gd.addIntArray(owner, scope, name, tupleSize, creationArgs, - /*attr options*/ nullptr, storage); - } else if (storage == GA_STORE_STRING) { - attr = gd.addStringArray(owner, name, tupleSize, creationArgs); - } - } - if (attr && GfIsGfQuat::type>::value) { - // XXX: GA_TYPE_QUATERNION is the only type info that can be inferred - // from the value type alone. For all other GA_TypeInfo values, the - // caller must query the 'role' from the SdfValueTypeName of the - // corresponding USD attribute. - // - // If the SdfValueTypeName was passed in as an argument to this method, - // then we could configure the GA_AIFType for non-quaternion types at - // this point as well. The reason we don't do that is because an - // attribute's SdfValueTypeName is *not* cached, and must be composed - // and potentially read from disk, so querying the type on every value - // read introduces extra overhead. - // Instead, the caller of this method should apply type info on the - // resulting attribute, if necessary, using - // GusdUsdValueTypeMayHaveRole() and GusdGetTypeInfoForUsdRole(). - attr->setTypeInfo(GA_TYPE_QUATERNION); - } - return attr; -} - -// Instantiate templated method for all Sdf value types. - -#define GUSD_CREATE_ATTR(r, unused, elem) \ - template GA_Attribute* \ - GusdCreateAttrForUsdValueType( \ - GEO_Detail&, const GA_AttributeScope, \ - const GA_AttributeOwner, const UT_StringHolder&, \ - const UT_Options*); \ - \ - template GA_Attribute* \ - GusdCreateAttrForUsdValueType>( \ - GEO_Detail&, const GA_AttributeScope, \ - const GA_AttributeOwner, const UT_StringHolder&, \ - const UT_Options*); - -BOOST_PP_SEQ_FOR_EACH(GUSD_CREATE_ATTR, ~, SDF_VALUE_TYPES); - -#undef GUSD_CREATE_ATTR - - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/valueUtils.h b/third_party/houdini/gusd/valueUtils.h deleted file mode 100644 index 430348aab1..0000000000 --- a/third_party/houdini/gusd/valueUtils.h +++ /dev/null @@ -1,232 +0,0 @@ -// -// Copyright 2019 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_VALUE_UTILS_H -#define GUSD_VALUE_UTILS_H - -#include "api.h" -#include "UT_Gf.h" - -#include "pxr/pxr.h" - -#include "pxr/base/gf/traits.h" -#include "pxr/base/tf/span.h" -#include "pxr/base/vt/array.h" -#include "pxr/usd/sdf/types.h" -#include "pxr/usd/sdf/valueTypeName.h" - -#include -#include - - -class GA_Attribute; -class GA_Range; -class GEO_Detail; -class UT_Options; -class UT_StringHolder; - - -PXR_NAMESPACE_OPEN_SCOPE - - -/// Extract attribute values as USD value type \p T, -/// for each offset in \p range. The \p values span must be -/// sized to the number of entries in \p range. -template -GUSD_API -bool GusdReadUsdValuesFromAttr(const GA_Attribute& attr, - const TfSpan& offsets, - const TfSpan& values); - -template -GUSD_API -bool GusdWriteUsdValuesToAttr(GA_Attribute& attr, - const GA_Range& range, - const TfSpan& rangeIndices, - const TfSpan& values); - - -/// Returns the type name best suited for storing the data in \p attr. -GUSD_API -SdfValueTypeName GusdGetSdfTypeNameForAttr(const GA_Attribute& attr); - - -/// Returns the GA_TYPE_INFO best matching the given USD role. -/// If \p tupleSize is a value greater than zero, the matching type info -/// is only returned if it is appropriate for a value type with the given -/// tuple size. -GUSD_API -GA_TypeInfo GusdGetTypeInfoForUsdRole(const TfToken& role, - const int tupleSize=-1); - - -/// Create an attribute on \p gd, using the attribute type best suited -/// for \p T, which must be a valid USD value type. -/// With the exception of quaternion types, this method does not apply -/// GA_TypeInfo for the role stored in the SdfTypeName; it is up to -/// the caller to apply that after. -/// -/// An example for properly configuring an attribute is as follows: -/// \code -/// if (GA_Attribute* attr = GusdCreateAttrForUsdValueType(...)) { -/// if (GusdUsdValueTypeMayHaveRole()) { -/// // XXX: Note that the type name is not cached! -/// const SdfValueTypeName typeName = usdAttr.GetTypeName(); -/// attr->setTypeInfo( -/// GusdGetTypeInfoForUsdRole(typeName.GetRole())); -/// } -/// } -/// \endcode -template -GUSD_API -GA_Attribute* -GusdCreateAttrForUsdValueType(GEO_Detail& gd, - const GA_AttributeScope scope, - const GA_AttributeOwner owner, - const UT_StringHolder& name, - const UT_Options* creationArgs=nullptr); - - -template -struct GusdUsdValueTypeAttrStorage -{ - static const GA_Storage value = GA_STORE_INVALID; -}; - -#define GUSD_DEFINE_USD_ATTR_STORAGE(Type, Storage) \ - template <> \ - struct GusdUsdValueTypeAttrStorage \ - { \ - static const GA_Storage value = Storage; \ - }; - -GUSD_DEFINE_USD_ATTR_STORAGE(bool, GA_STORE_BOOL); -GUSD_DEFINE_USD_ATTR_STORAGE(unsigned char, GA_STORE_UINT8); -GUSD_DEFINE_USD_ATTR_STORAGE(int, GA_STORE_INT32); -GUSD_DEFINE_USD_ATTR_STORAGE(unsigned int, GA_STORE_INT32); -GUSD_DEFINE_USD_ATTR_STORAGE(long, GA_STORE_INT64); -GUSD_DEFINE_USD_ATTR_STORAGE(unsigned long, GA_STORE_INT64); -GUSD_DEFINE_USD_ATTR_STORAGE(GfHalf, GA_STORE_REAL16); -GUSD_DEFINE_USD_ATTR_STORAGE(float, GA_STORE_REAL32); -GUSD_DEFINE_USD_ATTR_STORAGE(double, GA_STORE_REAL64); -GUSD_DEFINE_USD_ATTR_STORAGE(std::string, GA_STORE_STRING); -GUSD_DEFINE_USD_ATTR_STORAGE(TfToken, GA_STORE_STRING); -GUSD_DEFINE_USD_ATTR_STORAGE(SdfAssetPath, GA_STORE_STRING); - -// For vectors, derive storage from the scalar type. -template -struct GusdUsdValueTypeAttrStorage< - T, typename std::enable_if::value|| - GfIsGfQuat::value|| - GfIsGfMatrix::value>::type> -{ - static const GA_Storage value = - GusdUsdValueTypeAttrStorage::value; -}; - - -// For arrays, derive storage from the element type. -template -struct GusdUsdValueTypeAttrStorage< - T, typename std::enable_if::value>::type> -{ - static const GA_Storage value = - GusdUsdValueTypeAttrStorage::value; -}; - - -/// Returns the GA_Storage value best matching a USD value type. -template -constexpr GA_Storage -GusdGetUsdValueTypeAttrStorage() -{ - return GusdUsdValueTypeAttrStorage::value; -} - - -/// Struct for determining whether or not an SdfValueTypeName -/// corresponding to a USD value type might hold a role. -/// This is useful in determining whether or not to compose an -/// attribute's type name. -template -struct _GusdUsdValueTypeMayHaveRole -{ - const bool value = false; -}; - -// Matrices may have roles... -template -struct _GusdUsdValueTypeMayHaveRole< - T, typename std::enable_if::value>::type> -{ - const bool value = true; -}; - -// Non-integer vectors may have roles. -template -struct _GusdUsdValueTypeMayHaveRole< - T, typename std::enable_if::value>::type> -{ - using ScalarType = typename T::ScalarType; - const bool value = (SYSisSame() || - SYSisSame() || - SYSisSame()); -}; - - -/// Returns true if the SdfTypeName of a USD attribute storing a value of -/// the given type may have a role. -template -constexpr bool GusdUsdValueTypeMayHaveRole() -{ - return _GusdUsdValueTypeMayHaveRole::value; -} - - -template -struct GusdUsdValueTypeTupleSize -{ - static const int value = GusdGetTupleSize(); -}; - - -template -struct GusdUsdValueTypeTupleSize< - T, typename std::enable_if::value>::type> -{ - static const int value = - GusdUsdValueTypeTupleSize::value; -}; - - -template -constexpr int GusdGetUsdValueTypeTupleSize() -{ - return GusdUsdValueTypeTupleSize::value; -} - - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif // GUSD_VALUE_UTILS_H diff --git a/third_party/houdini/gusd/wrapStageCache.cpp b/third_party/houdini/gusd/wrapStageCache.cpp deleted file mode 100644 index bb40844a61..0000000000 --- a/third_party/houdini/gusd/wrapStageCache.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "stageCache.h" - -#include "pxr/base/tf/makePyConstructor.h" -#include "pxr/base/tf/pyResultConversions.h" - -#include - -#include - - -using namespace boost::python; - -PXR_NAMESPACE_USING_DIRECTIVE - - -UT_StringSet _ListToStringSet(const list& list) -{ - UT_StringSet set; - const size_t size = len(list); - for(size_t i = 0; i < size; ++i) - set.insert(UT_StringHolder(extract(list[i]))); - return set; -} - - -/// Helper for extracting a pointer from \p obj, which may hold -/// a correct pointer type, or None. -/// This is a hack to help handle possibly null intrusive pointers, -/// which boost python otherwise doesn't know how to convert by default. -template -T _ExtractPtr(const object& obj) -{ - if(obj) { - T val = extract(obj); - return val; - } - return nullptr; -} - - -/// Helper for creating a python object holding a stage ref ptr. -/// Note that normal object creation produces a weak ptr. -object -_StageRefToObj(const UsdStageRefPtr& stage) -{ - using RefPtrFactory = - Tf_MakePyConstructor::RefPtrFactory<>::apply::type; - return object(handle<>(RefPtrFactory()(stage))); -} - - -UsdStageRefPtr -_Find(GusdStageCache& self, - const std::string& path, - const GusdStageOpts& opts, - const object& edit) -{ - return GusdStageCacheReader(self).Find( - UT_StringRef(path), opts, _ExtractPtr(edit)); -} - - -UsdStageRefPtr -_FindOrOpen(GusdStageCache& self, - const std::string& path, - const GusdStageOpts& opts, - const object& edit) -{ - return GusdStageCacheReader(self).FindOrOpen( - UT_StringRef(path), opts, _ExtractPtr(edit)); -} - - -tuple -_GetPrim(GusdStageCache& self, - const std::string& path, - const SdfPath& primPath, - const object& edit, - const GusdStageOpts& opts) -{ - auto pair = GusdStageCacheReader(self).GetPrim( - UT_StringRef(path), primPath, - _ExtractPtr(edit), opts); - return boost::python::make_tuple(pair.first, _StageRefToObj(pair.second)); -} - - -template -GusdDefaultArray -_ObjectToDefaultArray(const object& o) -{ - GusdDefaultArray array; - if(!o) { - return array; - } - - extract constVal(o); - if(constVal.check()) { - array.SetDefault(T(constVal)); - } - - list vals = extract(o); - array.GetArray().setSize(len(vals)); - for(exint i = 0; i < array.size(); ++i) { - array(i) = T(extract(vals[i])); - } - return array; -} - - -template -UT_Array -_ListToArray(const list& l) -{ - UT_Array array; - array.setSize(len(l)); - for(exint i = 0; i < array.size(); ++i) - array(i) = extract(l[i]); - return array; -} - - -std::vector -_GetPrims(GusdStageCache& self, - const object& filePaths, - const list& primPaths, - const object& edits, - const GusdStageOpts& opts) -{ - std::vector prims(len(primPaths)); - - GusdStageCacheReader(self).GetPrims( - _ObjectToDefaultArray(filePaths), - _ListToArray(primPaths), - _ObjectToDefaultArray(edits), - prims.data(), opts); - - return prims; -} - - -tuple -_GetPrimWithVariants(GusdStageCache& self, - const std::string& path, - const SdfPath& primPath, - const SdfPath& variants, - const GusdStageOpts& opts) -{ - auto pair = GusdStageCacheReader(self).GetPrimWithVariants( - UT_StringRef(path), primPath, variants, opts); - return boost::python::make_tuple(pair.first, _StageRefToObj(pair.second)); -} - - -void -_Clear_Full(GusdStageCache& self) -{ - GusdStageCacheWriter(self).Clear(); -} - - -void -_Clear_Partial(GusdStageCache& self, const list& paths) -{ - GusdStageCacheWriter(self).Clear(_ListToStringSet(paths)); -} - - -list -_FindStages(GusdStageCache& self, const list& paths) -{ - UT_Set stages; - GusdStageCacheWriter(self).FindStages(_ListToStringSet(paths), stages); - - list stageList; - for(const auto& stage : stages) { - stageList.append(_StageRefToObj(stage)); - } - return stageList; -} - - -void -_ReloadStages(GusdStageCache& self, const list& paths) -{ - GusdStageCacheWriter(self).ReloadStages(_ListToStringSet(paths)); -} - - -void wrapGusdStageCache() -{ - using This = GusdStageCache; - - class_("StageCache") - - .def("GetInstance", &This::GetInstance, - return_value_policy()) - .staticmethod("GetInstance") - - .def("Find", &_Find, - (arg("path"), - arg("opts")=GusdStageOpts::LoadAll(), - arg("edit")=GusdStageEditPtr()), - return_value_policy >()) - - .def("FindOrOpen", &_FindOrOpen, - (arg("path"), - arg("opts")=GusdStageOpts::LoadAll(), - arg("edit")=GusdStageEditPtr()), - return_value_policy >()) - - .def("GetPrim", &_GetPrim, - (arg("path"), - arg("primPath"), - arg("edit")=GusdStageEditPtr(), - arg("opts")=GusdStageOpts::LoadAll())) - - .def("GetPrims", &_GetPrims, - (arg("filePaths"), - arg("primPaths"), - arg("edits")=object(), - arg("opts")=GusdStageOpts::LoadAll()), - return_value_policy()) - - .def("GetPrimWithVariants", &_GetPrimWithVariants, - (arg("path"), - arg("primPath"), - arg("variants")=SdfPath(), - arg("opts")=GusdStageOpts::LoadAll())) - - .def("Clear", &_Clear_Full) - .def("Clear", &_Clear_Partial, (arg("paths")=object())) - - .def("FindStages", &_FindStages, (arg("paths"))) - - .def("ReloadStages", &_ReloadStages, (arg("paths"))) - ; -} diff --git a/third_party/houdini/gusd/wrapStageEdit.cpp b/third_party/houdini/gusd/wrapStageEdit.cpp deleted file mode 100644 index 225ab716d8..0000000000 --- a/third_party/houdini/gusd/wrapStageEdit.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "stageEdit.h" - -#include "pxr/base/tf/pyResultConversions.h" - -#include -#include - -using namespace boost::python; - -PXR_NAMESPACE_USING_DIRECTIVE - - -namespace { - - -template -VEC _ListToVector(const list& list) -{ - const size_t size = len(list); - VEC vec(size); - for(size_t i = 0; i < size; ++i) { - vec[i] = extract(list[i]); - } - return vec; -} - - -template -ARRAY _ListToArray(const list& list) -{ - ARRAY array; - const size_t size = len(list); - array.setSize(size); - for(size_t i = 0; i < size; ++i) { - array[i] = extract(list[i]); - } - return array; -} - - -GusdStageEditPtr _New() -{ - return GusdStageEditPtr(new GusdStageEdit); -} - - -const UT_Array& -_GetVariants(const GusdStageEdit& self) -{ - return self.GetVariants(); -} - - -void _SetVariants(GusdStageEdit& self, const list& variants) -{ - self.GetVariants() = _ListToArray >(variants); -} - - -const std::vector& -_GetLayersToMute(const GusdStageEdit& self) -{ - return self.GetLayersToMute(); -} - - -void _SetLayersToMute(GusdStageEdit& self, const list& layers) -{ - self.GetLayersToMute() = _ListToVector >(layers); -} - -bool _Apply(const GusdStageEdit& self, const object& obj) -{ - extract x(obj); - if (x.check()) - return self.Apply(x); - return self.Apply(extract(obj)); -} - - -} // namespace - - -PXR_NAMESPACE_OPEN_SCOPE - -/// Extract of underlying value in a UT_IntrusivePtr. -/// Required for conversion in boost python. -template -T* get_pointer(const UT_IntrusivePtr& p) -{ - return p.get(); -} - -PXR_NAMESPACE_CLOSE_SCOPE - - -namespace boost { namespace python { - - /// Boilerplate needed to use UT_IntrusivePtr types in boost python. - template - struct pointee > { - typedef T type; - }; - -} // namespace python -} // namespace boost - - - -void wrapGusdStageEdit() -{ - using This = GusdStageEdit; - using ThisPtr = UT_IntrusivePtr; - - class_("StageEdit", no_init) - - .def("New", &_New) - .staticmethod("New") - - .def("Apply", &_Apply) - - .def("GetVariants", &_GetVariants, - return_value_policy()) - - .def("SetVariants", &_SetVariants) - - .def("GetLayersToMute", _GetLayersToMute, - return_value_policy()) - - .def("SetLayersToMute", &_SetLayersToMute) - ; -} diff --git a/third_party/houdini/gusd/wrapStageOpts.cpp b/third_party/houdini/gusd/wrapStageOpts.cpp deleted file mode 100644 index a20bb15b74..0000000000 --- a/third_party/houdini/gusd/wrapStageOpts.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "stageOpts.h" - -#include - - -using namespace boost::python; - -PXR_NAMESPACE_USING_DIRECTIVE - - -void wrapGusdStageOpts() -{ - using This = GusdStageOpts; - - class_("StageOpts", init( - arg("loadSet")=UsdStage::LoadAll)) - - .def("LoadAll", &This::LoadAll) - .staticmethod("LoadAll") - - .def("LoadNone", &This::LoadNone) - .staticmethod("LoadNone") - - .def("GetLoadSet", &This::GetLoadSet) - - .def("SetLoadSet", &This::SetLoadSet) - ; -} diff --git a/third_party/houdini/gusd/writeCtrlFlags.cpp b/third_party/houdini/gusd/writeCtrlFlags.cpp deleted file mode 100644 index e00ed2a014..0000000000 --- a/third_party/houdini/gusd/writeCtrlFlags.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// - -#include "writeCtrlFlags.h" -#include "GU_USD.h" - -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -void -GusdWriteCtrlFlags::update( const GT_PrimitiveHandle &sourcePrim ) -{ - overPoints = getBoolAttr( sourcePrim, GUSD_OVERPOINTS_ATTR, overPoints ); - overTransforms = getBoolAttr( sourcePrim, GUSD_OVERTRANSFORMS_ATTR, overTransforms ); - overPrimvars = getBoolAttr( sourcePrim, GUSD_OVERPRIMVARS_ATTR, overPrimvars ); - overAll = getBoolAttr( sourcePrim, GUSD_OVERALL_ATTR, overAll ); - writeStaticGeo = getBoolAttr( sourcePrim, GUSD_WRITESTATICGEO_ATTR, writeStaticGeo ); - writeStaticTopology = getBoolAttr( sourcePrim, GUSD_WRITESTATICTOPOLOGY_ATTR, writeStaticTopology ); - writeStaticPrimvars = getBoolAttr( sourcePrim, GUSD_WRITESTATICPRIMVARS_ATTR, writeStaticPrimvars ); -} - -/* static */ -bool -GusdWriteCtrlFlags::getBoolAttr( - const GT_PrimitiveHandle& prim, - const char *attrName, - bool defaultValue ) -{ - if( prim ) { - GT_DataArrayHandle data; - if( prim->getPrimitiveType() == GT_GEO_PACKED ) { - GT_AttributeListHandle instAttrs = - UTverify_cast(prim.get())->getInstanceAttributes(); - if( instAttrs ) { - data = instAttrs->get( attrName ); - } - } - if( !data ) { - GT_Owner own; - data = prim->findAttribute( attrName, own, 0 ); - } - if( data ) { - return bool( data->getI32(0) ); - } - - } - return defaultValue; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/writeCtrlFlags.h b/third_party/houdini/gusd/writeCtrlFlags.h deleted file mode 100644 index 5cbfb790d8..0000000000 --- a/third_party/houdini/gusd/writeCtrlFlags.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// - -#ifndef GUSD_WRITE_CTRL_FLAGS_H -#define GUSD_WRITE_CTRL_FLAGS_H - -#include "api.h" -#include "pxr/pxr.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -// Flags indicating how we want to write geometry to a USD file. These flags -// are initialized by the ROP but they may be modified by primitive attributes. -// Values set in geometry packed prims will be inherited by the children of that -// prim. - -struct GusdWriteCtrlFlags { - - // Flags indicating what data to write when we are writing overlays - bool overPoints; // For point instancers, overlayPoints and overlayTransforms are synonymous. - bool overTransforms; - bool overPrimvars; - bool overAll; // Completely replace prims, including topology. - // For point instancers, if overlayAll is set and - // prototypes are specified, replace the prototypes. - - bool writeStaticGeo; - bool writeStaticTopology; - bool writeStaticPrimvars; - - GusdWriteCtrlFlags() - : overPoints( false ) - , overTransforms( false ) - , overPrimvars( false ) - , overAll( false ) - , writeStaticGeo( false ) - , writeStaticTopology( false ) - , writeStaticPrimvars( false ) - {} - - // Update flags with values read from prims attributes. - GUSD_API - void update( const GT_PrimitiveHandle &prim ); - - static bool getBoolAttr( - const GT_PrimitiveHandle& prim, - const char *attrName, - bool defaultValue ); -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // GUSD_WRITE_CTRL_FLAGS_H diff --git a/third_party/houdini/gusd/xformWrapper.cpp b/third_party/houdini/gusd/xformWrapper.cpp deleted file mode 100644 index 4ef56f0522..0000000000 --- a/third_party/houdini/gusd/xformWrapper.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "xformWrapper.h" - -#include "context.h" -#include "UT_Gf.h" - -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -// drand48 and srand48 defined in SYS_Math.h as of 13.5.153. and conflicts with imath. -#undef drand48 -#undef srand48 - -using std::cout; -using std::cerr; -using std::endl; -using std::vector; -using std::string; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -GusdXformWrapper::GusdXformWrapper( - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride ) -{ - initUsdPrim( stage, path, isOverride ); -} - -GusdXformWrapper::GusdXformWrapper( - const UsdGeomXform& usdXform, - UsdTimeCode time, - GusdPurposeSet purposes ) - : GusdGroupBaseWrapper( time, purposes ) - , m_usdXform( usdXform ) -{ -} - -GusdXformWrapper::GusdXformWrapper( const GusdXformWrapper &in ) - : GusdGroupBaseWrapper( in ) - , m_usdXform( in.m_usdXform ) -{ -} - -GusdXformWrapper::~GusdXformWrapper() -{} - -bool GusdXformWrapper:: -initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride) -{ - bool newPrim = true; - if( asOverride ) { - UsdPrim existing = stage->GetPrimAtPath( path ); - if( existing ) { - // Note that we are creating a Xformable rather than a Xform. - // If we are writing an overlay and the ROP sees a geometry packed prim, - // we want to write just the xform. In that case we can use a xform - // wrapper to write the xform on any prim type. - m_usdXform = UsdGeomXformable(stage->OverridePrim( path )); - newPrim = false; - } - else { - m_usdXform = UsdGeomXform::Define( stage, path ); - - // Make sure our ancestors have proper types. - UsdPrim p = m_usdXform.GetPrim().GetParent(); - while( p && p.GetTypeName().IsEmpty() ) { - UsdGeomXform::Define( stage, p.GetPath() ); - p = p.GetParent(); - } - } - } - else { - m_usdXform = UsdGeomXform::Define( stage, path ); - } - if( !m_usdXform || !m_usdXform.GetPrim().IsValid() ) { - TF_WARN( "Unable to create %s xform '%s'.", newPrim ? "new" : "override", path.GetText() ); - } - return bool(m_usdXform); -} - -GT_PrimitiveHandle GusdXformWrapper:: -defineForWrite( - const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt) -{ - return new GusdXformWrapper( - stage, - path, - ctxt.writeOverlay ); -} - -GT_PrimitiveHandle GusdXformWrapper:: -defineForRead( - const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ) -{ - return new GusdXformWrapper( - UsdGeomXform( sourcePrim.GetPrim() ), - time, - purposes ); -} - -bool GusdXformWrapper:: -redefine( const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) -{ - initUsdPrim( stage, path, ctxt.writeOverlay ); - clearCaches(); - return true; -} - - -const char* GusdXformWrapper:: -className() const -{ - return "GusdXformWrapper"; -} - - -void GusdXformWrapper:: -enlargeBounds(UT_BoundingBox boxes[], int nsegments) const -{ - // TODO -} - - -int GusdXformWrapper:: -getMotionSegments() const -{ - // TODO - return 1; -} - - -int64 GusdXformWrapper:: -getMemoryUsage() const -{ - // TODO - return 0; -} - - -GT_PrimitiveHandle GusdXformWrapper:: -doSoftCopy() const -{ - return GT_PrimitiveHandle(new GusdXformWrapper( *this )); -} - - -bool GusdXformWrapper:: -isValid() const -{ - return static_cast(m_usdXform); -} - -bool GusdXformWrapper:: -refine( - GT_Refine& refiner, - const GT_RefineParms* parms) const -{ - return refineGroup( m_usdXform.GetPrim(), refiner, parms ); -} - - -bool GusdXformWrapper:: -updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& localXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) -{ - if( !m_usdXform ) - return false; - - DBG( cout << "GusdXformWrapper::updateFromGTPrim, primType = " << sourcePrim->className() << endl ); - - return updateGroupFromGTPrim( m_usdXform, sourcePrim, localXform, ctxt, xformCache ); -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/gusd/xformWrapper.h b/third_party/houdini/gusd/xformWrapper.h deleted file mode 100644 index 6db98ecaa1..0000000000 --- a/third_party/houdini/gusd/xformWrapper.h +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef GUSD_XFORM_WRAPPER_H -#define GUSD_XFORM_WRAPPER_H - -#include "pxr/pxr.h" - -#include "api.h" - -#include "groupBaseWrapper.h" - -#include "pxr/usd/usdGeom/xform.h" - -PXR_NAMESPACE_OPEN_SCOPE - - -class GusdXformWrapper : public GusdGroupBaseWrapper -{ -public: - - GUSD_API - GusdXformWrapper( - const UsdStagePtr& stage, - const SdfPath& path, - bool isOverride = false ); - - GUSD_API - GusdXformWrapper( const GusdXformWrapper& in ); - - GUSD_API - GusdXformWrapper( - const UsdGeomXform& usdXform, - UsdTimeCode t, - GusdPurposeSet purposes ); - - virtual ~GusdXformWrapper(); - - // GusdPrimWrapper interface ----------------------------------------------- - -public: - - virtual const UsdGeomImageable getUsdPrim() const override { return m_usdXform; } - - virtual bool redefine( - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt, - const GT_PrimitiveHandle& sourcePrim ) override; - - virtual const char* className() const override; - - virtual void enlargeBounds(UT_BoundingBox boxes[], int nsegments) const override; - - virtual int getMotionSegments() const override; - - virtual int64 getMemoryUsage() const override; - - virtual GT_PrimitiveHandle doSoftCopy() const override; - - virtual bool - updateFromGTPrim(const GT_PrimitiveHandle& sourcePrim, - const UT_Matrix4D& localXform, - const GusdContext& ctxt, - GusdSimpleXformCache& xformCache) override; - - virtual bool isValid() const override; - - virtual bool refine(GT_Refine& refiner, - const GT_RefineParms* parms=NULL) const override; - - // ------------------------------------------------------------------------- - -public: - - static GT_PrimitiveHandle - defineForWrite(const GT_PrimitiveHandle& sourcePrim, - const UsdStagePtr& stage, - const SdfPath& path, - const GusdContext& ctxt); - - static GT_PrimitiveHandle - defineForRead( const UsdGeomImageable& sourcePrim, - UsdTimeCode time, - GusdPurposeSet purposes ); - -private: - - bool initUsdPrim(const UsdStagePtr& stage, - const SdfPath& path, - bool asOverride); - - UsdGeomXformable m_usdXform; -}; - -PXR_NAMESPACE_CLOSE_SCOPE -#endif // GUSD_XFORM_WRAPPER_H - diff --git a/third_party/houdini/plugin/CMakeLists.txt b/third_party/houdini/plugin/CMakeLists.txt deleted file mode 100644 index 65ac0efe2f..0000000000 --- a/third_party/houdini/plugin/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(OP_gusd) - - diff --git a/third_party/houdini/plugin/OP_gusd/CMakeLists.txt b/third_party/houdini/plugin/OP_gusd/CMakeLists.txt deleted file mode 100644 index 8b81360ad2..0000000000 --- a/third_party/houdini/plugin/OP_gusd/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -set(PXR_PACKAGE OP_gusd) - -pxr_plugin(${PXR_PACKAGE} - - LIBRARIES - ar - gf - js - kind - plug - sdf - tf - usd - usdGeom - usdRi - usdShade - usdUtils - gusd - - INCLUDE_DIRS - ${HOUDINI_INCLUDE_DIRS} - - PRIVATE_CLASSES - OBJ_usdcamera - OP_Utils - ROP_usdoutput - SOP_usdimport - SOP_usdunpack - - CPPFILES - plugin.cpp -) - -install( - DIRECTORY - help - DESTINATION - ${PXR_INSTALL_SUBDIR} -) - -install( - FILES - ROP_usdcoalesce.otl - ROP_usdlayer.otl - ROP_usdreference.otl - SOP_camerafrustum.otl - SOP_usdbindproxy.otl - SOP_usdexportattributes.hda - SOP_usdinstanceprototypes.hda - SOP_usdretime.hda - DESTINATION - ${PXR_INSTALL_SUBDIR}/otls -) - -install( - FILES - ROP_usdcoalesce.py - ROP_usdlayer.py - ROP_usdreference.py - DESTINATION - ${PXR_INSTALL_SUBDIR}/soho/python2.7 -) - -install( - FILES - UsdImport.pypanel - DESTINATION - ${PXR_INSTALL_SUBDIR}/python_panels -) - -install( - FILES - obj/pixar-usdcamera.py - DESTINATION - ${PXR_INSTALL_SUBDIR}/scripts/obj -) - diff --git a/third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.cpp b/third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.cpp deleted file mode 100644 index 92fb240714..0000000000 --- a/third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.cpp +++ /dev/null @@ -1,734 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "OBJ_usdcamera.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gusd/PRM_Shared.h" -#include "gusd/stageCache.h" -#include "gusd/UT_Assert.h" -#include "gusd/UT_Gf.h" - -#include "pxr/base/arch/hints.h" -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usdGeom/camera.h" -#include "pxr/usd/usdGeom/xform.h" -#include "pxr/usd/usdGeom/xformCache.h" -#include "pxr/usd/usdUtils/pipeline.h" - -PXR_NAMESPACE_OPEN_SCOPE - -typedef enum -{ - _POSTMULTCTM_TRANSFORM, - _CTM_TRANSFORM, - _OBJ_TRANSFORM, - _IGNORE_TRANSFORM -} _TransformMode; - - -void -GusdOBJ_usdcamera::Register(OP_OperatorTable* table) -{ - OP_Operator* op = new OP_Operator("pixar::usdcamera", - "USD Camera", - creator, - GetTemplates(), -#if UT_MAJOR_VERSION_INT >= 16 - SOP_TABLE_NAME, -#endif - /* min inputs*/ 0, - /* max inputs*/ 1, - GetVariables()); - op->setIconName("pxh_gusdIcon.png"); - op->setOpTabSubMenuPath( "Pixar" ); - table->addOperator(op); - table->setOpFirstName("pixar::usdcamera", "usdcam"); -} - - -OP_VariablePair* -GusdOBJ_usdcamera::GetVariables() -{ - static CH_LocalVariable vars[] = { - {"SCREENASPECT", VAR_SCREENASPECT, CH_VARIABLE_TIME}, - {"YRES", VAR_YRES, CH_VARIABLE_TIME}, - {"PROJECTION", VAR_PROJECTION, CH_VARIABLE_TIME}, - {"FOCAL", VAR_FOCAL, CH_VARIABLE_TIME}, - {"HAPERTURE", VAR_HAPERTURE, CH_VARIABLE_TIME}, - {"VAPERTURE", VAR_VAPERTURE, CH_VARIABLE_TIME}, - {"NEAR", VAR_NEAR, CH_VARIABLE_TIME}, - {"FAR", VAR_FAR, CH_VARIABLE_TIME}, - {"FOCUS", VAR_FOCUS, CH_VARIABLE_TIME}, - {"FSTOP", VAR_FSTOP, CH_VARIABLE_TIME}, - {"HAPERTUREOFFSET", VAR_HAPERTUREOFFSET, CH_VARIABLE_TIME}, - - // for backwards compatibility with old stereo attributes { - {"ISSTEREO", VAR_ISSTEREO, CH_VARIABLE_TIME}, - {"CONVERGENCEDISTANCE", VAR_CONVERGENCEDISTANCE, CH_VARIABLE_TIME}, - {"INTEROCULARDISTANCE", VAR_INTEROCULARDISTANCE, CH_VARIABLE_TIME}, - {"LEFTEYEBIAS", VAR_LEFTEYEBIAS, CH_VARIABLE_TIME}, - // } - - {0, 0, 0} - }; - static OP_VariablePair oldVarPair(ourLocalVariables, NULL); - static OP_VariablePair varPair(vars, &oldVarPair); - return &varPair; -}; - - -OP_TemplatePair* -GusdOBJ_usdcamera::GetTemplates() -{ - /* Our common camera params come from the same initialization script - as the standard camera.*/ - - static PRM_Default primPathDef(0, "/World/main_cam"); - static PRM_Name frameName("frame", "Frame"); - static PRM_Default frameDef(0, "$FF"); - - static PRM_Name xformName("xformmode", "Transform Mode"); - static PRM_Name xformNames[] = { - PRM_Name("postmultctm", "Object to World"), - PRM_Name("ctm", "Parent to World"), - PRM_Name("obj", "Object"), - PRM_Name("none", "None"), - PRM_Name() - }; - static PRM_ChoiceList xformMenu(PRM_CHOICELIST_SINGLE, xformNames); - - GusdPRM_Shared prmShared; - - static PRM_Template camTemplates[] = { - PRM_Template(PRM_FILE, 1, &prmShared->filePathName, 0, - /*choicelist*/ 0, /*range*/ 0, - /*callback*/ 0, &prmShared->usdFileROData), - PRM_Template(PRM_STRING, 1, &prmShared->primPathName, - &primPathDef), - PRM_Template(PRM_FLT, 1, &frameName, &frameDef), - PRM_Template(PRM_ORD, 1, &xformName, - /* default*/ 0, - /* choice list */ &xformMenu, - /* range */0, - /* callback */0, - /* spare */0, - /* group */0, - "If this node is included in a OBJ hierarchy this " - "should be set to 'Object'. If not, it should " - "be set to 'Object to World'"), - PRM_Template() - }; - unsigned numCamTemplates = PRM_Template::countTemplates(camTemplates); - - // for backwards compatibility with old stereo attributes { - static PRM_Name isStereoName("isstereo", "Is Stereo"); - static PRM_Name rightEyeName( "isrighteye", "Is Right Eye" ); - static PRM_Name convergenceDistanceName("convergencedistance", - "Convergence Distance"); - static PRM_Name interocularDistanceName("interoculardistance", - "Interocular Distance"); - static PRM_Name leftEyeBiasName("lefteyebias", "Left Eye Bias"); - - static PRM_Template stereoAttrsTemplates[] = { - PRM_Template(PRM_TOGGLE | PRM_TYPE_INVISIBLE, 1, &isStereoName, - /* defaults */ 0, - /* choice list */ 0, - /* range ptr */0, - /* callback */0, - /* spare */ 0, - /* parmgroup*/ 1, - "Show mono view if off. Right or left eye view if on."), - PRM_Template(PRM_TOGGLE | PRM_TYPE_INVISIBLE, 1, &rightEyeName, - /* defaults */ 0, - /* choice list */ 0, - /* range ptr */0, - /* callback */0, - /* spare */ 0, - /* parmgroup*/ 1, - "If checked, show right eye view. " - "Otherwise show left eye view."), - PRM_Template(PRM_FLT | PRM_TYPE_INVISIBLE, 1, &convergenceDistanceName, 0), - PRM_Template(PRM_FLT | PRM_TYPE_INVISIBLE, 1, &interocularDistanceName, 0), - PRM_Template(PRM_FLT | PRM_TYPE_INVISIBLE, 1, &leftEyeBiasName, - /* defaults */ 0, - /* choice list */ 0, - /* range ptr */0, - /* callback */0, - /* spare */ 0, - /* parmgroup*/ 1, - "If 0, left eye view matches mono view. " - "If 1, right eye view matches mono view." ), - PRM_Template() - }; - - unsigned numStereoAttrsTemplates = - PRM_Template::countTemplates(stereoAttrsTemplates); - // } - - static PRM_Name displayFrustumName( "displayFrustum", "Display Frustum"); - static PRM_Template displayFrustum(PRM_TOGGLE, 1, &displayFrustumName, 0); - - const PRM_Template* const objTemplates = getTemplateList(OBJ_PARMS_PLAIN); - unsigned numObjTemplates = PRM_Template::countTemplates(objTemplates); - - /* First template in common obj parms is a switcher. - We need to modify the switcher to include our own tab.*/ - - UT_IntArray numSwitchersOnPages, numNonSwitchersOnPages; - PRM_Template::getSwitcherStats(objTemplates, - numSwitchersOnPages, - numNonSwitchersOnPages); - unsigned oldSwitcherSize = numNonSwitchersOnPages.entries(); - - static std::vector tabs(oldSwitcherSize+1); - - static PRM_Default renderPaneDefault; - - for(int i = 0; i < oldSwitcherSize; ++i) - { - tabs[i] = objTemplates->getFactoryDefaults()[i]; - - // We want to add an item to the Render pane, displayFrustum. - // We need to increase the item count in the switcher default. - if(UT_String(tabs[i].getString()) == "Render") - { - renderPaneDefault.setString(tabs[i].getString()); - renderPaneDefault.setFloat(tabs[i].getFloat() + 1); - tabs[i] = renderPaneDefault; - } - } - tabs[oldSwitcherSize] = - PRM_Default(numCamTemplates + numStereoAttrsTemplates, "USD"); - - static PRM_Name switcherName = *objTemplates->getNamePtr(); - - static std::vector templates; - templates.push_back( - PRM_Template(PRM_SWITCHER, tabs.size(), &switcherName, &tabs[0])); - - for(std::size_t i = 1; i < numObjTemplates; ++i) - { - templates.push_back( objTemplates[i] ); - if(UT_String(objTemplates[i].getNamePtr()->getToken()) == "caching") - templates.push_back(displayFrustum); - } - templates.insert(templates.end(), camTemplates, - camTemplates + numCamTemplates); - templates.insert(templates.end(), stereoAttrsTemplates, - stereoAttrsTemplates + numStereoAttrsTemplates); - templates.push_back(PRM_Template()); - - static OP_TemplatePair templatePair(&templates[0], NULL); - return &templatePair; -} - - -bool -GusdOBJ_usdcamera::updateParmsFlags() -{ - int changed = 0; - - return changed; -} - - -void -GusdOBJ_usdcamera::loadStart() -{ - _isLoading = true; - OBJ_Camera::loadStart(); -} - - -void -GusdOBJ_usdcamera::loadFinished() -{ - OBJ_Camera::loadFinished(); - _isLoading = false; -} - - -OP_Node* -GusdOBJ_usdcamera::creator(OP_Network *net, const char* name, OP_Operator* op) -{ - return new GusdOBJ_usdcamera(net, name, op); -} - - -GusdOBJ_usdcamera::GusdOBJ_usdcamera(OP_Network* net, const char* name, OP_Operator* op) - : OBJ_Camera(net, name, op), _isLoading(false), _camParmsMicroNode(*this) -{ - GusdPRM_Shared prmShared; - - const PRM_ParmList* parms = GusdUTverify_ptr(getParmList()); - - _camParmsMicroNode.addParm( - parms->getParmIndex(prmShared->filePathName.getToken())); - _camParmsMicroNode.addParm( - parms->getParmIndex(prmShared->primPathName.getToken())); - - _frameIdx = parms->getParmIndex("frame"); - UT_ASSERT(_frameIdx >= 0); -} - - -struct _NameDefaultPair -{ - const char* name; - int vi; - PRM_Default def; -}; - - -bool -GusdOBJ_usdcamera::runCreateScript() -{ - static _NameDefaultPair pairs[] = { - {"iconscale", 0, PRM_Default(500,"")}, - {"res", 0, PRM_Default(1920, "")}, - {"res", 1, PRM_Default(803, "$YRES")}, - {"projection", 0, PRM_Default(0, "$PROJECTION")}, - {"focal", 0, PRM_Default(50, "$FOCAL")}, - {"orthowidth", 0, PRM_Default(1000, "$HAPERTURE * .1")}, - {"aperture", 0, PRM_Default(41.2136, "$HAPERTURE")}, - {"near", 0, PRM_Default(0.001, "$NEAR")}, - {"far", 0, PRM_Default(10000, "$FAR")}, - {"focus", 0, PRM_Default(5, "$FOCUS")}, - {"fstop", 0, PRM_Default(5.6, "$FSTOP")}, - {"win", 0, PRM_Default(0, "$HAPERTUREOFFSET/$HAPERTURE")}, - - // for backwards compatibility with old stereo attributes { - {"isstereo", 0, PRM_Default(0, "$ISSTEREO")}, - {"convergencedistance", 0, PRM_Default(1000, "$CONVERGENCEDISTANCE")}, - {"interoculardistance", 0, PRM_Default(50, "$INTEROCULARDISTANCE")}, - {"lefteyebias", 0, PRM_Default(0.0, "$LEFTEYEBIAS")}, - // } - - {NULL, 0, PRM_Default()} - }; - - if(OBJ_Camera::runCreateScript()) /* run the obj/GusdOBJ_usdcamera.cmd setup - script. This gives us our common - camera and usd properties. */ - { - /* Loop over relevant camera properties and setup new defaults. - We want cam parms to use expressions by default. We have variable - expansions reference the relevant usd properties. - The point of this design is that it allows users the ability to - override any of the properties coming from usd, wrap expressions - around them, etc. - */ - PRM_ParmList* parms = GusdUTverify_ptr(getParmList()); - for(_NameDefaultPair* pair = pairs; pair->name; pair++) - { - if(PRM_Parm* parm = parms->getParmPtr(pair->name)) - { - if(PRM_Template* tmpl = parm->getTemplatePtr()) - { - tmpl->setDefault(pair->vi, pair->def); - parm->revertToDefaults(0); - } - } - } - -#if 0 - // Replace the choices for the resolution menu with ones that - // we read from our configuration script. - if(PRM_Parm *parm = parms->getParmPtr("resMenu")) - { - if(PRM_Template *tmpl = parm->getTemplatePtr()) - { - PRM_ChoiceList *myChoices = - new PRM_ChoiceList( - PRM_CHOICELIST_SINGLE, - "__import__('pxh_config')." - "GetResolutionChoiceList(False)", - CH_PYTHON_SCRIPT); - tmpl->setChoiceListPtr(myChoices); - } - - } -#endif - return true; - } - return false; -} - - -namespace { - - -/** Simple index stack.*/ -struct _VarEvalStack -{ - _VarEvalStack() - : _stack(4) /* very unlikely that a larger stack is needed! */ - {} - - int Last() const { return _stack.isEmpty() ? -1 : _stack.last(); } - - void Push(int idx) { _stack.append(idx); } - - void Pop() { - UT_ASSERT_P(_stack.size() > 0); - _stack.setSize(_stack.size()-1); - } - -private: - UT_Array _stack; -}; - -UT_ThreadSpecificValue<_VarEvalStack*> _varEvalStack; - - -} /*namespace*/ - - -bool -GusdOBJ_usdcamera::evalVariableValue(fpreal& val, int idx, int thread) -{ - if(idx >= NUM_VARS) - return OBJ_Node::evalVariableValue(val, idx, thread); - - /* Protect against cyclic variable referencing when eval'ing cam vars. - Most vars eval the 'frame' parm in order to pull animated data - from USD. If someone were to put, say, $YRES on the frame number, - then evaluating the frame would require evaluation of the YRES - variable, which requires evaluation of the frame parm...and we're - stuck in a loop.*/ - _VarEvalStack*& stack = _varEvalStack.getValueForThread(thread); - if(ARCH_UNLIKELY(!stack)) stack = new _VarEvalStack; - - if(stack->Last() != idx) { - stack->Push(idx); - bool res = _EvalCamVariable(val, idx, thread); - stack->Pop(); - return res; - } - return false; -} - - -bool -GusdOBJ_usdcamera::_EvalCamVariable(fpreal& val, int idx, int thread) -{ - UT_ASSERT_P(idx >= 0 && idx < NUM_VARS); - - const fpreal t = CHgetEvalTime(thread); - - if(UsdGeomCamera cam = _LoadCamera(t, thread)) - { - float frame = evalFloatT(_frameIdx, 0, t, thread); - switch(idx) - { - case VAR_SCREENASPECT: - { - val = cam.GetCamera(frame).GetAspectRatio(); - return true; - } - case VAR_YRES: - { - // XXX This is redundant since resy can be set to - // "ch(\"resx\")/$SCREENASPECT" in runCreateScript, - // however it's needed to get around a Houdini bug - // (see bug 94389) - const float screenAspect = - cam.GetCamera(frame).GetAspectRatio(); - float xRes = evalFloatT("res", 0, t, thread); - val = xRes / screenAspect; - return true; - } - case VAR_PROJECTION: - { - TfToken proj; - if(cam.GetProjectionAttr().Get(&proj) && - proj == UsdGeomTokens->orthographic) - val = OBJ_PROJ_ORTHO; - else - val = OBJ_PROJ_PERSPECTIVE; - return true; - } - case VAR_FOCAL: - { - float focal = 50; - cam.GetFocalLengthAttr().Get(&focal, frame); - val = focal; - return true; - } - case VAR_HAPERTURE: - { - float aperture = 41.2136; - cam.GetHorizontalApertureAttr().Get(&aperture, frame); - val = aperture; - return true; - } - case VAR_VAPERTURE: - { - float aperture = 41.2136; - cam.GetVerticalApertureAttr().Get(&aperture, frame); - val = aperture; - return true; - } - case VAR_NEAR: - { - GfVec2f clipping; - val = cam.GetClippingRangeAttr().Get(&clipping, frame) ? - clipping[0] : 0.001; - return true; - } - case VAR_FAR: - { - GfVec2f clipping; - val = cam.GetClippingRangeAttr().Get(&clipping, frame) ? - clipping[1] : 10000; - return true; - } - case VAR_FOCUS: - { - float focus = 5; - cam.GetFocusDistanceAttr().Get(&focus, frame); - val = focus; - return true; - } - case VAR_FSTOP: - { - float fstop = 5.6; - cam.GetFStopAttr().Get(&fstop, frame); - val = fstop; - return true; - } - case VAR_HAPERTUREOFFSET: - { - float apertureOffset = 41.2136; - cam.GetHorizontalApertureOffsetAttr().Get(&apertureOffset, frame); - val = apertureOffset; - return true; - } - // for backwards compatibility with old stereo attributes { - - // XXX:-matthias - // We are just writing out dummy values so that old assets do not - // break. - // The following code together with the definitions of - // VAR_ISSTEREO, ... should eventually be removed. - - case VAR_ISSTEREO: - { - bool isStereo = false; - val = isStereo; - return true; - } - case VAR_CONVERGENCEDISTANCE: - { - float convergenceDistance = 1000; - val = convergenceDistance; - return true; - } - case VAR_INTEROCULARDISTANCE: - { - float interocularDistance = 50; - val = interocularDistance; - return true; - } - case VAR_LEFTEYEBIAS: - { - float leftEyeBias = 0.0; - val = leftEyeBias; - return true; - } - // } - }; - } - - /* Couldn't load a camera. Just return defaults.*/ - switch(idx) - { - case VAR_SCREENASPECT: val = 1.0; break; - case VAR_YRES: val = 1080; break; - case VAR_PROJECTION: val = OBJ_PROJ_PERSPECTIVE; break; - case VAR_FOCAL: val = 50; break; - case VAR_HAPERTURE: val = 41.2136; break; - case VAR_VAPERTURE: val = 41.2136; break; - case VAR_NEAR: val = 0.001; break; - case VAR_FAR: val = 10000; break; - case VAR_FOCUS: val = 5; break; - case VAR_FSTOP: val = 5.6; break; - case VAR_HAPERTUREOFFSET: val = 41.2136; break; - // for backwards compatibility with old stereo attributes - case VAR_ISSTEREO: val = 0; break; - case VAR_CONVERGENCEDISTANCE: val = 1000; break; - case VAR_INTEROCULARDISTANCE: val = 50; break; - case VAR_LEFTEYEBIAS: val = 0.0; break; - }; - /* Return true so that the variables are still considered valid, - even in the absence of the camera. This is done to prevent - evaluation errors during saves.*/ - return true; -} - - -int -GusdOBJ_usdcamera::applyInputIndependentTransform(OP_Context& ctx, UT_DMatrix4& mx) -{ - mx.identity(); - fpreal t = ctx.getTime(); - - if(UsdGeomCamera cam = _LoadCamera(t, ctx.getThread())) - { - float frame = evalFloat(_frameIdx, 0, t); - - GfMatrix4d ctm(1.); - bool stat = true; - bool resetsXformStack = false; - - switch(evalInt("xformmode", 0, t)) - { - case _POSTMULTCTM_TRANSFORM: - stat = true; - ctm = cam.ComputeLocalToWorldTransform(frame); - break; - case _CTM_TRANSFORM: - stat = true; - ctm = cam.ComputeParentToWorldTransform(frame); - break; - case _OBJ_TRANSFORM: - // XXX: how do we reset xformStack here? - // Is that (or should that - // be) handled by the Compute calls above? - stat = cam.GetLocalTransformation(&ctm, &resetsXformStack, frame); - break; - default: // _IGNORE_TRANSFORM: - stat = true; - ctm.SetIdentity(); - break; - } - if(!stat) - { - stealErrors(_errors, /*borrow*/ true); - return 0; - } - - mx = GusdUT_Gf::Cast(ctm); - } - return OBJ_Camera::applyInputIndependentTransform(ctx, mx); -} - - -OP_ERROR -GusdOBJ_usdcamera::_Cook(OP_Context& ctx) -{ - _LoadCamera(ctx.getTime(), ctx.getThread()); - - /* XXX: There's a potential race condition here, between - loading and stealing cached errors. - Would be better to keep the camera cache locked - until the error stealing is done.*/ - - UT_AutoReadLock readLock(_lock); - stealErrors(_errors, /*borrow*/ true); - return error(); -} - - -OP_ERROR -GusdOBJ_usdcamera::cookMyObj(OP_Context& ctx) -{ - if(_Cook(ctx) <= UT_ERROR_ABORT) - OBJ_Camera::cookMyObj(ctx); - return error(); -} - - -UsdGeomCamera -GusdOBJ_usdcamera::_LoadCamera(fpreal t, int thread) -{ - /* XXX: Disallow camera loading until the scene has finished loading. - What happens otherwise is that some parm values are pulled on - during loading, causing a _LoadCamera request. If this happens before - the node's parm values have been loaded, then we'll end up loading - the camera using defaults (which reference the shot conversion). - So if we don't block this, we end up always loading the shot conversion, - even if we don't need it! */ - - if(_isLoading) - return UsdGeomCamera(); - - /* Always return a null camera while saving. - This is to prevent load errors from prematurely interrupting saves, - which can lead to corrupt files.*/ - if(GusdUTverify_ptr(OPgetDirector())->getIsDoingExplicitSave()) - return UsdGeomCamera(); - - { - UT_AutoReadLock readLock(_lock); - if(!_camParmsMicroNode.requiresUpdate(t)) - return _cam; - } - - UT_AutoWriteLock writeLock(_lock); - - /* Other thread may already have loaded the cam, so only update if needed.*/ - if(_camParmsMicroNode.updateIfNeeded(t, thread)) - { - _cam = UsdGeomCamera(); - - _errors.clearAndDestroyErrors(); - UT_ErrorManager::Scope errorScope(_errors); - - GusdPRM_Shared prmShared; - UT_String usdPath, primPath; - - evalStringT(usdPath, prmShared->filePathName.getToken(), 0, t, thread); - evalStringT(primPath, prmShared->primPathName.getToken(), 0, t, thread); - - GusdStageCacheReader cache; - if(UsdPrim prim = cache.GetPrimWithVariants( - usdPath, primPath, GusdStageOpts::LoadAll()).first) { - - // Track changes to the stage (eg., reloads) - DEP_MicroNode* stageMicroNode = - cache.GetStageMicroNode(prim.GetStage()); - UT_ASSERT_P(stageMicroNode); - _camParmsMicroNode.addExplicitInput(*stageMicroNode); - - _cam = GusdUSD_Utils::MakeSchemaObj(prim); - return _cam; - } - } - return UsdGeomCamera(); -} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.h b/third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.h deleted file mode 100644 index 74b9e5ffde..0000000000 --- a/third_party/houdini/plugin/OP_gusd/OBJ_usdcamera.h +++ /dev/null @@ -1,152 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -/** - \file - \brief USD Camera. -*/ -#ifndef OP_GUSD_OBJ_USDCAMERA_H -#define OP_GUSD_OBJ_USDCAMERA_H - -#include -#include -#include - -#include "gusd/OP_ParmChangeMicroNode.h" - -#include -#include "pxr/usd/usdGeom/camera.h" - -PXR_NAMESPACE_OPEN_SCOPE - -/** USD camera object node. - - Houdini cameras are evaluated based on a combination of node parameters - and the object's computed transform. This implementation works by using - custom local variables in expressions to pull in the corresponding data - from USD. The reason for doing it this way is that, by default, - we're able to have everything come from USD, but at any point, - users are free to delete or modify the default expressions to change - behavior (eg., maybe we want 2x the authored near/far range). - - An additional oddity is that the camera parameters come from creation - scripts. Specifically, see obj/pixar-usdcamera.py, which simply calls - out to the standard camera startup script. We do this because it means - we don't have to replicate the parm interface ourselves. It also means - we're guaranteed to get a default setup that looks just like a regular - cam. That should be the goal here: a plain old cam that's driven by USD. - The use of startup scripts is not without precedent; it's exactly - how the standard camera node works.*/ -class GusdOBJ_usdcamera : public OBJ_Camera -{ -public: - - enum - { - VAR_SCREENASPECT, - VAR_YRES, - VAR_PROJECTION, - VAR_FOCAL, - VAR_HAPERTURE, - VAR_VAPERTURE, - VAR_NEAR, - VAR_FAR, - VAR_FOCUS, - VAR_FSTOP, - VAR_HAPERTUREOFFSET, - - // for backwards compatibility with old stereo attributes { - VAR_ISSTEREO, - VAR_CONVERGENCEDISTANCE, - VAR_INTEROCULARDISTANCE, - VAR_LEFTEYEBIAS, - // } - - NUM_VARS, - }; - - static OP_TemplatePair* GetTemplates(); - static OP_VariablePair* GetVariables(); - - static OP_Node* creator(OP_Network* net, const char* name, - OP_Operator* op); - - /** Overridden to modify defaults of scripted properties. */ - virtual bool runCreateScript() override; - - /** Evaluate the float value of a variable. - This is where we hook in most of our USD queries. */ - virtual bool evalVariableValue(fpreal& val, - int idx, int thread) override; - virtual bool evalVariableValue(UT_String& val, - int idx, int thread) override - { - return OP_Network::evalVariableValue( - val, idx, thread); - } - -protected: - GusdOBJ_usdcamera(OP_Network* net, const char* name, OP_Operator* op); - - virtual ~GusdOBJ_usdcamera() {} - - virtual int applyInputIndependentTransform(OP_Context& ctx, - UT_DMatrix4& mx) override; - - virtual bool updateParmsFlags() override; - - virtual void loadStart() override; - virtual void loadFinished() override; - - virtual OP_ERROR cookMyObj(OP_Context& ctx) override; - -private: - OP_ERROR _Cook(OP_Context& ctx); - - UsdGeomCamera _LoadCamera(fpreal t, int thread); - - bool _EvalCamVariable(fpreal& val, int idx, int thread); - -private: - UT_ErrorManager _errors; - UsdGeomCamera _cam; - - int _frameIdx; /*! Cached index of the frame parm.*/ - - UT_RWLock _lock; - bool _isLoading; - - /** Micro node for tracking changes to the parms that affect our - camera selection. - The camera is queried within variable evaluation, so the - lookup needs to be fast.*/ - GusdOP_ParmChangeMicroNode _camParmsMicroNode; - -public: - static void Register(OP_OperatorTable* table); -}; - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif /* OP_GUSD_OBJ_USDCAMERA_H */ diff --git a/third_party/houdini/plugin/OP_gusd/OP_Utils.cpp b/third_party/houdini/plugin/OP_gusd/OP_Utils.cpp deleted file mode 100644 index ddfd34837e..0000000000 --- a/third_party/houdini/plugin/OP_gusd/OP_Utils.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "OP_Utils.h" - -PXR_NAMESPACE_OPEN_SCOPE - -namespace GusdOP_Utils -{ - -void -ClearAllCaches() { - GusdStageCacheWriter cache; - cache.Clear(); - GusdUSD_XformCache::GetInstance().Clear(); - GusdUSD_VisCache::GetInstance().Clear(); - GusdGT_PrimCache::GetInstance().Clear(); - -} - -void -ReloadStagesAndClearCaches(const UT_StringSet& paths) { - GusdStageCacheWriter cache; - cache.ReloadStages(paths); - GusdUSD_XformCache::GetInstance().Clear(paths); - GusdUSD_VisCache::GetInstance().Clear(paths); - GusdGT_PrimCache::GetInstance().Clear(paths); -} - -} /*namespace GusdOP_Utils*/ - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/plugin/OP_gusd/OP_Utils.h b/third_party/houdini/plugin/OP_gusd/OP_Utils.h deleted file mode 100644 index 7b94b1fc21..0000000000 --- a/third_party/houdini/plugin/OP_gusd/OP_Utils.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2018 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef OP_GUSD_OP_UTILS_H -#define OP_GUSD_OP_UTILS_H - -#include "gusd/stageCache.h" -#include "gusd/GT_PrimCache.h" -#include "gusd/USD_XformCache.h" -#include "gusd/USD_VisCache.h" - -PXR_NAMESPACE_OPEN_SCOPE - -namespace GusdOP_Utils -{ - -/// Clear all caches stored by the stage cache, prim cache, xform cache, and -/// visibility cache. -void ClearAllCaches(); - -/// Reload any prims on stages that match the passed in set of layer -/// identifiers (stage paths). Clear the prim, xform, and visibility caches of -/// those prims. -void ReloadStagesAndClearCaches(const UT_StringSet& paths); - -} /*namespace GusdOP_Utils*/ - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*OP_GUSD_OP_UTILS_H*/ diff --git a/third_party/houdini/plugin/OP_gusd/OPcustomize_gusd b/third_party/houdini/plugin/OP_gusd/OPcustomize_gusd deleted file mode 100644 index 6a3f7cd3c0..0000000000 --- a/third_party/houdini/plugin/OP_gusd/OPcustomize_gusd +++ /dev/null @@ -1 +0,0 @@ -opdefaultshape Sop pixar::usdrop clipped_left \ No newline at end of file diff --git a/third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.otl b/third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.otl deleted file mode 100644 index 05d630bdfdb8c6ec98a8c04ab9f6ff47082741f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40521 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 A`v3p{ diff --git a/third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.py b/third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.py deleted file mode 100644 index 087658fa0d..0000000000 --- a/third_party/houdini/plugin/OP_gusd/ROP_usdcoalesce.py +++ /dev/null @@ -1,237 +0,0 @@ -# -# Copyright 2017 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# -# ROP used to create a USD file that references a set of per frame USD files. -# -# To export efficiently on the farm, we want to export per frame files. To make -# the fx easier to reference from USD, we want to create one file that -# references all the per frame files. -# -# To do that with USD, we are using a feature called model clips. Model clips -# were designed for crowds but we can use there here too. To use them -# we need to declare a scene topology that doesn't change from frame to frame. - -from __future__ import print_function - -import soho -from glob import glob -import os, os.path, re, sys, logging, traceback -from pxr import Usd,UsdUtils,Sdf,Kind - -def parseFileName( fileName ): - - # Frame numbers must be at the beginning of the name or - # be bracketed by '.'s. - return re.search( '(^|\.)([0-9]+)\.', os.path.basename(fileName) ) - -def extractNum( fileName ): - m = parseFileName( fileName ) - if m: - return int( m.groups()[1] ) - - return sys.maxint - -def inrange( v, min, max ): - return v >= min and v <= max - -def coalesceFiles( - outFile, - srcFilePat, - frameRange, - stride ): - - logging.info( "coalesceFiles " + srcFilePat + ", frame range = " + str(min(frameRange)) + " - " + str(max(frameRange)) ) - - perFrameFiles = glob( srcFilePat ) - templatePath = srcFilePat.replace('%','#').replace('*','#') - templatePath = './' + os.path.basename(templatePath) - - # create a list of tuples with frame number / file pairs - fileList = [(extractNum(f),f) for f in perFrameFiles] - # throw away any files that are outside of the frame range - ff = min( frameRange ) - lf = max( frameRange ) - fileList = [f for f in fileList if f[0] >= ff and f[0] <= lf] - - if not fileList: - logging.info( "No files found to coalesce." ) - return - - fileList.sort() - startFrame = fileList[0][0] - endFrame = fileList[-1][0] - - sortedFiles = [e[1] for e in fileList] - - # try opening all files - openedFiles = [Sdf.Layer.FindOrOpen(fname) for fname in sortedFiles] - # grab the index of all, if any, files which failed to open - unopened = [i for i, unopened in enumerate(openedFiles) if unopened == None ] - # grab the filenames of the failed files for error messaging - erroredFiles = ' '.join([sortedFiles[i] for i in unopened]) - # if we failed to open any files, error out - assert len(unopened) == 0, 'unable to open file(s) %s' %erroredFiles - - # Open the layer that corresponds to outFile, if - # it exists. Otherwise, create a new layer for it. - if Sdf.Layer.Find(outFile): - outLayer = Sdf.Layer.FindOrOpen(outFile) - else: - outLayer = Sdf.Layer.CreateNew(outFile) - - # Find out where the extension begins in the outFile string. Note that this - # search for '.usd' will also find usda (or even usdc) extensions. - extension = outFile.rfind('.usd') - assert extension != -1, 'unable to find extension on file %s' % outFile - - # generate an aggregate topology from the input files - topologyLayerName = outFile.replace( outFile[extension:], '.topology.usda' ) - - # Open the layer that corresponds to topologyLayerName layer, if - # it exists. Otherwise, create a new layer for it. - if Sdf.Layer.Find( topologyLayerName ): - topologyLayer = Sdf.Layer.FindOrOpen( topologyLayerName ) - else: - topologyLayer = Sdf.Layer.CreateNew( topologyLayerName ) - - UsdUtils.StitchClipsTopology( topologyLayer, sortedFiles ) - - if len( topologyLayer.rootPrims ) == 0: - print( "No geometry found when coalescing USD files." ) - return - - # Find the names of all the prim with authored attributes in the - primsWithAttributes = set() - for p in topologyLayer.rootPrims: - walkPrim( p, primsWithAttributes ) - - modelPath = None - if len(primsWithAttributes) > 0: - modelPath = getCommonPrefix( list( primsWithAttributes ) ) - elif len(topologyLayer.rootPrims) > 0: - modelPath = str( topologyLayer.rootPrims[0].path ) - else: - return - - logging.info( "Highest populated prim = " + modelPath ) - - clipPath = Sdf.Path(modelPath) - clipPrim = topologyLayer.GetPrimAtPath(clipPath) - if not clipPrim: - raise Exception( "Can't find prim to create clip for" ) - - logging.info( "model clip root = " + str(clipPath) ) - - # If the thing we are coalescing is a root prim, if can be the default prim. - p = str( clipPath ) - if p[0] == '/' and p[1:].find( '/' ) < 0: - outLayer.defaultPrim = p - - # Stitch the output usda as an fx template - UsdUtils.StitchClipsTemplate( outLayer, topologyLayer, clipPath, - templatePath, startFrame, endFrame, stride ) - outLayer.Save() - -def walkPrim( p, primsWithAttributes ): - '''Walk the prim hierarchy looking for prims with attributes''' - - if p.attributes: - primsWithAttributes.add( str(p.path) ) - - for child in p.nameChildren: - walkPrim( child, primsWithAttributes ) - -def getCommonPrefix( paths ): - '''Find the common prefix of a list of paths''' - - if not paths: - return '' - - s1 = min( paths ) - s2 = max( paths ) - p1 = s1.split('/') - p2 = s2.split('/') - - for i, c in enumerate( p1 ): - if c != p2[i]: - return '/'.join(p1[:i]) - - return s1 - -############################################################################### -# parameters -############################################################################### - -parameterDefines = { - 'ropname' : soho.SohoParm('object:name', 'string', key = 'ropname'), - 'trange' : soho.SohoParm('trange', 'int', [0], False), - 'f' : soho.SohoParm('f', 'real', [1, 1, 1], False), - 'fps' : soho.SohoParm('state:fps', 'real', [24.0], False, key = 'fps'), - 'now' : soho.SohoParm('state:time', 'real', [0], False, key = 'now'), - 'sourcefiles': soho.SohoParm('sourcefiles', 'string', [], False ), - 'outfile' : soho.SohoParm('outfile', 'string', [''], False ), -} - -def main(): - - parameters = soho.evaluate(parameterDefines) - - # - # init soho - # - logger = logging.getLogger() - oldHandlers = logger.handlers - handler = logging.StreamHandler( stream = sys.__stderr__ ) - logger.handlers = [handler] - - ropName = parameters['ropname'].Value[0] - node = hou.node( ropName ) - vStr = node.type().nameComponents()[-1] - version = 0 if not vStr else int( vStr ) - - now = parameters['now'].Value[0] - - soho.initialize(now, '') - soho.lockObjects(now) - - if parameters['trange'].Value[0] == 0: - ff = lf = int(now * parameters['fps'].Value[0] + 1) - else: - ff = int(parameters['f'].Value[0]) - lf = int(parameters['f'].Value[1]) - stride = int(parameters['f'].Value[2]) - - sourcefiles = parameters['sourcefiles'].Value[0] - outfile = parameters['outfile'].Value[0] - - try: - - coalesceFiles( outfile, sourcefiles, range(ff,lf+1), stride ) - - except Exception as e: - soho.error( 'Failed to stitch USD files: ' + str(e) + '\n' + traceback.format_exc()) - - finally: - logger.handlers = oldHandlers - -main() diff --git a/third_party/houdini/plugin/OP_gusd/ROP_usdlayer.otl b/third_party/houdini/plugin/OP_gusd/ROP_usdlayer.otl deleted file mode 100644 index 96b401fbfad76426b835a19798e645e02107fa28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41939 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gusd/gusd.h" -#include "gusd/error.h" -#include "gusd/primWrapper.h" -#include "gusd/refiner.h" -#include "gusd/stageCache.h" -#include "gusd/shaderWrapper.h" -#include "gusd/UT_Gf.h" -#include "gusd/UT_Version.h" -#include "gusd/context.h" -#include "gusd/xformWrapper.h" - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cout; -using std::cerr; -using std::endl; -using std::string; -using std::map; -using std::pair; -using std::vector; - -#ifdef DEBUG -#define DBG(x) x -#else -#define DBG(x) -#endif - -namespace { - -void setKind( const string &path, UsdStagePtr stage ); -string getStringUniformOrDetailAttribute( - GT_PrimitiveHandle prim, - const char* attrName ); -bool setCamerasAreZup(UsdStageWeakPtr const &stage, bool isZup); - -template -void addShaderToMap(const ShaderT& shader, const SdfPath& primPath, - UT_Map >& map); - -OP_Node* -creator(OP_Network* network, - const char* name, - OP_Operator* op) -{ - return new GusdROP_usdoutput(network, name, op); -} - -//------------------------------------------------------------------------------ -// paramters -//------------------------------------------------------------------------------ -OP_TemplatePair* -getTemplates() -{ - static PRM_Name sopPathName("soppath", "SOP Path"); - - static PRM_Name usdFileName("usdfile", "USD File"); - static PRM_Default usdFileDefault(0, "$HIP/out.usd"); - - static PRM_Name granularityChoiceNames[] = { - PRM_Name( "oneFile", "One File" ), - PRM_Name( "perFrame", "Per Frame Files" ), - PRM_Name() - }; - - static PRM_ChoiceList granularityMenu( PRM_CHOICELIST_SINGLE, - granularityChoiceNames ); - - static PRM_Name granularityName("granularity","Granularity"); - - static PRM_Name pathsHeadingName("pathsheading", "Paths"); - static PRM_Name pathPrefixName("pathprefix", "Prefix"); - static PRM_Default pathPrefixDefault(0, "/FxAsset"); - static PRM_Name enablePathAttrName("enablepathattrib", ""); - static PRM_Name pathAttrName("pathattrib", "Path attribute"); - static PRM_Default pathAttrDefault(0, "usdprimpath"); - static PRM_Conditional pathAttrConditional("{ enablepathattrib == 0 }"); - static PRM_Name alwaysWriteRootName( "alwayswriteroot", "Always Write Root Prim" ); - - static PRM_Name primvarHeadingName("primvarheading", "Primvars"); - static PRM_Name varyingPrimvarsName("varyingprimvars", "Varying"); - static PRM_Name faceVaryingPrimvarsName("facevaryingprimvars", "Facevarying"); - static PRM_Name uniformPrimvarsName("uniformprimvars", "Uniform"); - static PRM_Name constantPrimvarsName("constantprimvars", "Constant"); - - static PRM_Name multiSegHeadingName("multisegheading", "Multi-Seg"); - static PRM_Name multiSegName("enablemultiseg", "Enable Multi-Seg"); - static PRM_Name samplesName("samples", "Samples"); - static PRM_Default samplesDefault(2); - static PRM_Range samplesRange(PRM_RANGE_RESTRICTED, 2, PRM_RANGE_UI, 10); - static PRM_Name shutterName("shutter", "Shutter"); - static PRM_Default shutterDefault[2] = {PRM_Default(0), PRM_Default(1)}; - static PRM_Range shutterRange[2] = { - PRM_Range(PRM_RANGE_RESTRICTED, -1, PRM_RANGE_RESTRICTED, 1), - PRM_Range(PRM_RANGE_RESTRICTED, -1, PRM_RANGE_RESTRICTED, 1)}; - static PRM_Name samplingModeName("samplingmode", "Sampling Mode"); - static PRM_Name samplingModeChoiceNames[] = { - PRM_Name("forward", "Forward"), - PRM_Name("backward", "Backward"), - PRM_Name()}; - static PRM_ChoiceList samplingModeMenu(PRM_CHOICELIST_SINGLE, - samplingModeChoiceNames); - static PRM_Conditional multiSegConditional("{ enablemultiseg == 0 }"); - - static PRM_Name shaderHeadingName("shaderheading", "Shaders"); - static PRM_Name enableShadersName("enableshaders", "Output Shaders"); - static PRM_Name usdShadingFileName("usdshadingfile", "USD Shading File"); - static PRM_Name usdShaderName("usdshader", "USD Shader"); - static PRM_Name shaderOutDirName("shaderoutdir", "Shader Output Dir"); - static PRM_Conditional shaderOutConditional("{ enableshaders == 0 }"); - - static PRM_Name scriptsHeadingName("scriptsheading", "Scripts"); - static PRM_Name pxhPreRenderName("pxhprerenderscript", "Pxh Pre-Render Script"); - - static PRM_Name geometryHeadingName("geometryheading", "Geometry"); - static PRM_Name useObjTransformName("useobjtransform","Use Object Transform"); - static PRM_Name instanceRefsName("usdinstancing","Enable USD Instancing"); - static PRM_Name authorVariantSelName("authorvariantselection", "Author Variant Selections"); - - static PRM_Name overlayHeadingName( "overlayheading", "Overlay"); - static PRM_Name overlayName("overlay", "Overlay Existing Geometry"); - static PRM_Conditional overlayConditional("{ overlay == 0 }"); - - static PRM_Name referenceFileName( "referencefile", "Overlay Reference File" ); - static PRM_Name overlayAllName( "overlayall", "Overlay All" ); - static PRM_Default overlayAllDefault( 1 ); - static PRM_Name overlayXformsName( "overlayxforms", "Overlay Transforms" ); - static PRM_Name overlayPointsName( "overlaypoints", "Overlay Points" ); - static PRM_Name overlayPrimvarsName( "overlayprimvars", "Overlay Primvars" ); - - static PRM_Name tinaProgressScriptName( "tinaprogressscript", "Tina Progress Script" ); - - static PRM_Template templates[] = { - PRM_Template( - PRM_STRING_OPREF, - PRM_TYPE_DYNAMIC_PATH, - 1, - &sopPathName, - 0, // default - 0, // choice - 0, // range - 0, // callback - &PRM_SpareData::sopPath, - 0, // paramgroup (leave default) - "SOP to export", // help string - 0), // disable rules - - PRM_Template( - PRM_FILE, - 1, - &usdFileName, - &usdFileDefault, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "USD file to write to", // help string - 0), // disable rules - - PRM_Template( - PRM_ORD, - 1, - &granularityName, - 0, - &granularityMenu ), - - PRM_Template( - PRM_HEADING, - 1, - &pathsHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &pathPrefixName, - &pathPrefixDefault, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "A prefix to the locations objects will be written to in the USD file. " - "This prefix will be ignored if using a path attribute.", - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - PRM_TYPE_TOGGLE_JOIN, - 1, - &enablePathAttrName, - PRMoneDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &pathAttrName, - &pathAttrDefault, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Primitive attribute which specifies a path for each gprim. " - "If this attribute exists for a prim them that prim will be written " - "to the location in the USD file contained in the attribute. For overlays, " - "objects are imported with a location in the attribute, modified and " - "them written back out to the right location using that attribute. " - "The path prefix is ignored when this attribute exists.", - &pathAttrConditional), - - PRM_Template( - PRM_TOGGLE, - 1, - &alwaysWriteRootName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "If the file would otherwise be empty, write an empty group prim at " - "the location specified in the the prefix parm.", - 0), // disable rules - - PRM_Template( - PRM_HEADING, - 1, - &geometryHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &useObjTransformName, - PRMoneDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "When not selected, Write out the USD data in local space, ignoring" - " any object level transforms.", - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &instanceRefsName, - PRMzeroDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Make references to USD primitives instanceable.", - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &authorVariantSelName, - PRMzeroDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Write variant selections with USD packed prims if a variant was " - "explicity set when the packed prim was created. This is useful " - "when writing prototypes for point instancers.", - 0), // disable rules - - PRM_Template( - PRM_HEADING, - 1, - &overlayHeadingName, - 0, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, - 0), - - PRM_Template( - PRM_TOGGLE, - 1, - &overlayName, - 0, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Write USD file that modifies an existing file", - 0), - - PRM_Template( - PRM_FILE, - 1, - &referenceFileName, - 0, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "USD file to be modified by overlaying changes", - &overlayConditional), - - PRM_Template( - PRM_TOGGLE, - 1, - &overlayAllName, - &overlayAllDefault, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Export transforms, points, primvars and topology for each object", - &overlayConditional), - - PRM_Template( - PRM_TOGGLE, - 1, - &overlayXformsName, - 0, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Export only transforms for each object", - &overlayConditional), - - PRM_Template( - PRM_TOGGLE, - 1, - &overlayPointsName, - 0, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Export only points for each object", - &overlayConditional), - - PRM_Template( - PRM_TOGGLE, - 1, - &overlayPrimvarsName, - 0, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Export only primvars for each object", - &overlayConditional), - - PRM_Template( - PRM_HEADING, - 1, - &primvarHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &varyingPrimvarsName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Varying primvar exports", // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &faceVaryingPrimvarsName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Facevarying primvar exports", // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &uniformPrimvarsName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Uniform primvar exports", // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &constantPrimvarsName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Constant primvar exports", // help string - 0), // disable rules - - PRM_Template( - PRM_HEADING, - 1, - &multiSegHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &multiSegName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Enable writing multi-seg samples to the USD file", - 0), - - PRM_Template( - PRM_INT, - 1, - &samplesName, - &samplesDefault, - 0, // menu choices - &samplesRange, - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Number of multi-seg samples to be written", - &multiSegConditional), - - PRM_Template( - PRM_FLT, - 2, - &shutterName, - shutterDefault, - 0, // menu choices - shutterRange, - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "The open/close shutter interval for writing multi-seg samples", - &multiSegConditional), - - PRM_Template( - PRM_ORD, - 1, - &samplingModeName, - 0, - &samplingModeMenu, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "\"Forward\" means the sampling interval follows the frame begin time." - "\"Backward\" means the sampling interval precedes the frame begin time.", - &multiSegConditional), - - PRM_Template( - PRM_HEADING, - 1, - &shaderHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &usdShadingFileName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Absolute path to USD shading file", // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &usdShaderName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "USD Shader name", // help string - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &enableShadersName, - PRMzeroDefaults, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Enable houdini materials to be " - "converted into usd shaders.", // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &shaderOutDirName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Directory where shaders built from " - "houdini materials will go.", // help string - &shaderOutConditional), // disable rules - - PRM_Template( - PRM_HEADING, - 1, - &scriptsHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_STRING, - 1, - &pxhPreRenderName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Python script to execute before any USD file is written. " - "Similar to prerender, but more reliable." - ), - - // predefined render script templates from ROP_Templates.h - theRopTemplates[ROP_TPRERENDER_TPLATE], - theRopTemplates[ROP_PRERENDER_TPLATE], - theRopTemplates[ROP_LPRERENDER_TPLATE], - theRopTemplates[ROP_TPREFRAME_TPLATE], - theRopTemplates[ROP_PREFRAME_TPLATE], - theRopTemplates[ROP_LPREFRAME_TPLATE], - theRopTemplates[ROP_TPOSTFRAME_TPLATE], - theRopTemplates[ROP_POSTFRAME_TPLATE], - theRopTemplates[ROP_LPOSTFRAME_TPLATE], - theRopTemplates[ROP_TPOSTRENDER_TPLATE], - theRopTemplates[ROP_POSTRENDER_TPLATE], - theRopTemplates[ROP_LPOSTRENDER_TPLATE], - - PRM_Template( - PRM_STRING | PRM_TYPE_INVISIBLE, - 1, - &tinaProgressScriptName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Reservered for use by tina", // help string - 0), // disable rules - - PRM_Template(), - }; - - static OP_TemplatePair usdTemplates(templates); - static OP_TemplatePair ropTemplates(ROP_Node::getROPbaseTemplate(), &usdTemplates); - return &ropTemplates; -} - -static PRM_Name protoFileName("protofile", "Inst Proto File"); -static PRM_Default protoFileNameDefault(0, ""); - -static PRM_Name instanceHeadingName("instancingheading", "Instancing"); -static PRM_Name instancePackedUsdName("instancepackedusd", "Instance Packed USD Prims"); -static PRM_Name writeProtoIdsName("writeprotoids", "Write Instance Prototype Ids"); -static PRM_Name coalesceFragmentsName("coalescefragments", "Coalesce Fragments" ); - -static PRM_Name objPathName("objpath", "OBJ Path"); - -PRM_Template obsoleteParameters[] = -{ - PRM_Template( - PRM_HEADING, - 1, - &instanceHeadingName, - 0, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - 0, // help string - 0), // disable rules - - PRM_Template( - PRM_FILE, - 1, - &protoFileName, - &protoFileNameDefault, - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Reference to add to USD file", // help string - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &instancePackedUsdName, - PRMzeroDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "When enabled, any PackedUSD primitives found on export will be " - "gathered into a pointInstancer primitive. This allows you to copy " - "PackedUSD prims with a copy SOP and convert the output to point " - "instances. Prototype PackedUSD prims must still be specified in " - "the Prototype Paths parameter below.", - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &writeProtoIdsName, - PRMzeroDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Include an attribute that contains a unique instance id. " - "This is required when writing prototypes for point instancers. ", - 0), // disable rules - - PRM_Template( - PRM_STRING_OPREF, - PRM_TYPE_DYNAMIC_PATH, - 1, - &objPathName, - 0, // default - 0, // choice - 0, // range - 0, // callback - &PRM_SpareData::objPath, - 0, // paramgroup (leave default) - "OBJ network to export", // help string - 0), // disable rules - - PRM_Template( - PRM_TOGGLE, - 1, - &coalesceFragmentsName, - PRMoneDefaults, // default - 0, // menu choices - 0, // range - 0, // callback - 0, // thespareptr (leave default) - 0, // paramgroup (leave default) - "Coalesce packed fragments into a single mesh.", - 0), // disable rules - - PRM_Template(), -}; - -//------------------------------------------------------------------------------ - - -OP_VariablePair* -getVariablePair() -{ - static OP_VariablePair* pair = 0; - if (!pair) { - pair = new OP_VariablePair(ROP_Node::myVariableList); - } - return pair; -} - -} // namespace - -void GusdROP_usdoutput:: -Register(OP_OperatorTable* table) -{ - OP_Operator* usdOutROP = new OP_Operator( - "pixar::usdoutput", - "USD Output", - creator, - getTemplates(), - (unsigned int)0, - (unsigned int)1024, - getVariablePair(), - OP_FLAG_GENERATOR ); - usdOutROP->setIconName("pxh_gusdIcon.png"); - usdOutROP->setObsoleteTemplates(obsoleteParameters); - usdOutROP->setOpTabSubMenuPath( "Pixar" ); - table->addOperator(usdOutROP); - table->setOpFirstName( "pixar::usdoutput", "usdoutput" ); - - // We can use this ROP in a sop context. - OP_Operator* usdOutSOP = new OP_Operator( - "pixar::usdrop", - "ROP USD Output", - creator, - getTemplates(), - (unsigned int)0, - (unsigned int)1, - getVariablePair(), - OP_FLAG_GENERATOR|OP_FLAG_MANAGER); - usdOutSOP->setIconName("pxh_gusdIcon.png"); - usdOutSOP->setOpTabSubMenuPath( "Pixar" ); - - - // Note: This is reliant on the order of operator table construction and - // may not be safe to do in all cases. - OP_OperatorTable* sopTable - = OP_Network::getOperatorTable(SOP_TABLE_NAME, SOP_SCRIPT_NAME); - sopTable->addOperator(usdOutSOP); - sopTable->setOpFirstName( "pixar::usdrop", "usdrop" ); -} - - -GusdROP_usdoutput:: -GusdROP_usdoutput(OP_Network* network, - const char* name, - OP_Operator* entry) - : ROP_Node(network, name, entry) -{} - - -GusdROP_usdoutput:: -~GusdROP_usdoutput() -{} - -bool -GusdROP_usdoutput::updateParmsFlags() -{ - bool inSopContext = CAST_SOPNODE(getInput(0)) != NULL; - bool changed = ROP_Node::updateParmsFlags(); - changed |= enableParm("soppath", !inSopContext); - return changed; -} - -ROP_RENDER_CODE GusdROP_usdoutput:: -openStage(fpreal tstart, int startTimeCode, int endTimeCode) -{ - // Always reset the temporary file descriptor to be invalid. - m_fdTmpFile = -1; - - UT_String fn; - evalString(fn, "usdfile", 0, tstart); - std::string fileName = fn.toStdString(); - - if (fileName == "") { - return abort("Unable to create new usd file, no usdfile path given."); - } - - // Each task on the farm shold write to a seperate file. However, several - // tasks my try to create the directory at the same time. Try and avoid - // erroring when this happens. Note we may have to try multiple times - // if we need to create multiple directories in the hierarchy. - string dir = TfGetPathName(fileName); - dir = TfStringTrimRight( dir, "/" ); - if( dir.empty() ) { - dir = "."; - } - - if( !TfIsDir(dir, true) ) { - size_t maxRetries = 5; - do { - TfMakeDirs(dir); - } while( --maxRetries > 0 && !TfIsDir(dir, true) ); - - if (!TfIsDir(dir, true)) { - - const std::string errorMessage = "Unable to create directory: " + dir; - return abort(errorMessage); - } - } - - if( access( fileName.c_str(), F_OK ) == 0 && - access( fileName.c_str(), W_OK ) != 0 ) { - return abort( "Don't have permissions to write file: " + fileName ); - } - - bool overlay = evalInt( "overlay", 0, tstart ); - if (overlay) { - UT_String refFile; - evalString( refFile, "referencefile", 0, tstart ); - - // To apply an overlay, the usd stage will be edited in - // place, via its SessionLayer. This SessionLayer will - // later be saved to disk (writing out all overlay edits) - // and once saved, will then be cleared back out. - - { - UT_ErrorManager::Scope scope; - GusdStageCacheReader cache; - m_usdStage = cache.FindOrOpen(refFile, GusdStageOpts::LoadAll(), - GusdStageEditPtr()); - if (!m_usdStage) { - return abort(GusdGetErrors()); - } - } - - // BUG: Mutating stages returned from the cache is not safe! - // Crashes, non-deterministic cooks, cats and dogs living together... - // The only safe way to mutate a stage is to make a new stage, - // and put locks around it if there's any possibility of other - // threads trying to access it at the same time. - if (m_usdStage->GetSessionLayer()) { - m_usdStage->GetSessionLayer()->Clear(); - } else { - m_usdStage = UsdStage::Open(m_usdStage->GetRootLayer(), - SdfLayer::CreateAnonymous()); - if (!m_usdStage) { - const std::string errorMessage = "Unable to open: " - + refFile.toStdString(); - return abort(errorMessage); - } - } - // Set m_usdStage's EditTarget to be its SessionLayer. - m_usdStage->SetEditTarget(m_usdStage->GetSessionLayer()); - - // Set modelingVariant to ALL_VARIANTS per pipeline convention. - // For some models, this will activate scopes that we might need to - // be present to properly export overlay data. - GusdUSD_Utils::SetModelingVariant(m_usdStage, - m_usdStage->GetDefaultPrim(), - GusdUSD_Utils::kAllVariantsToken); - - // If given model path and asset name detail attributes, we set up an - // edit target to remap the output of the overlay to the specfied - // model's scope. For exmaple, uutput would be /model/geom/... instead - // of /World/sets/model/geom... - - // Cook the node to get detail attributes. - OP_Context houdiniContext(tstart); - GU_DetailHandle cookedGeoHdl = m_renderNode->getCookedGeoHandle(houdiniContext); - - // Get the model path and asset name - UT_String modelPath; - if (cookedGeoHdl.isValid()) { - GU_DetailHandleAutoReadLock detailLock( cookedGeoHdl ); - const GEO_AttributeHandle modelPathHandle = detailLock->getDetailAttribute("usdmodelpath"); - const GEO_AttributeHandle assetNameHandle = detailLock->getDetailAttribute("usdassetname"); - const GEO_AttributeHandle defaultPrimPathHandle = detailLock->getDetailAttribute("usddefaultprimpath"); - modelPathHandle.getString(modelPath); - UT_String assetName; - if(assetNameHandle.getString(assetName)) { - m_assetName = assetName.toStdString(); - } - UT_String defaultPrimPath; - if(defaultPrimPathHandle.getString(defaultPrimPath)) { - m_defaultPrimPath = defaultPrimPath.toStdString(); - } - } - - // If we have both, proceed to remapping through edit target. - if (!m_assetName.empty() && m_assetName != "None" && - modelPath.isstring() && modelPath.toStdString() != "None") { - - // Add a reference from the model path to the asset name. This - // allows us to create a pcp mapping function through that reference - // arc. The result is we can write to the normal shot convert - // usdprimpath, but it will automatically map to a prim path with - // the model as the root. Use the root later for temporary edits we - // don't want to save. - m_usdStage->GetRootLayer()->SetPermissionToSave(false); - m_usdStage->SetEditTarget(m_usdStage->GetRootLayer()); - - // Get the prim whose scope we are mapping to. - m_modelPrim = m_usdStage->GetPrimAtPath(SdfPath(modelPath.toStdString() )); - - // Make sure model prim exists on stage. - if( !m_modelPrim.IsValid() ){ - const std::string errorMessage = "Unable to find model at: " - + modelPath.toStdString(); - return abort(errorMessage); - } - - // Create an overlay of the asset name as a root scope. - UsdPrim refPrim = m_usdStage->OverridePrim(SdfPath("/" + m_assetName )); - - // Reference that new root scope. - SdfReference ref = SdfReference(); - ref.SetPrimPath(SdfPath("/" + m_assetName )); - UsdReferences refs = m_modelPrim.GetReferences(); - refs.AddReference( ref ); - - // Get the model's prim index (contains all opinions on this node) - const PcpPrimIndex idx = m_modelPrim.ComputeExpandedPrimIndex(); - - // Find the node that referenced in the model. - PcpNodeRef node; - for (const PcpNodeRef& child : idx.GetNodeRange()) { - if (child.GetArcType() == PcpArcTypeReference && - child.GetDepthBelowIntroduction() == 0 && - child.GetPath() == SdfPath("/" + m_assetName ) ) { - node = child; - break; - } - } - - // Can't remap if the node is invalid. - if (!node) { - const std::string errorMessage = "Unable to find valid node " - "for remapping with asset " - "name:" + m_assetName; - return abort(errorMessage); - } - - // Create the edit target with the node (and its mapping). - UsdEditTarget editTarget = UsdEditTarget(m_usdStage->GetSessionLayer(), node); - m_usdStage->SetEditTarget(editTarget); - - // Remove the temp reference. - refs.ClearReferences(); - } - } else { - - // Find out if a layer with this fileName already exists. - if (SdfLayer::Find(fileName) || SdfLayer::Find(TfRealPath(fileName))) { - // Get the SdfFileFormat from fileName. - SdfFileFormatConstPtr format = - SdfFileFormat::FindByExtension(fileName); - if (!format) { - return abort("Unable to determine USD format of: " + fileName); - } - - // Create a temporary file in the same dir as fileName. - std::string tmpFileName; - m_fdTmpFile = ArchMakeTmpFile(dir, TfGetBaseName(fileName), - &tmpFileName); - if (m_fdTmpFile == -1) { - return abort("Unable to create temporary file in: " + dir); - } - // Copy file permissions from fileName to tmpFileName. - int mode; - if (!ArchGetStatMode(fileName.c_str(), &mode)) { - mode = 0664; // Use 0664 (-rw-rw-r--) if stat of fileName fails. - } - ArchChmod(tmpFileName.c_str(), mode); - - // Create a rootLayer and stage with tmpFileName. - SdfLayerRefPtr tmpLayer = SdfLayer::CreateNew(format, tmpFileName); - m_usdStage = UsdStage::Open(tmpLayer); - - if (!m_usdStage) { - ArchUnlinkFile(tmpFileName.c_str()); - return abort("Unable to create new stage: " + tmpFileName); - } - - } else { - m_usdStage = UsdStage::CreateNew(fileName); - - if (!m_usdStage) { - return abort("Unable to create new stage: " + fileName); - } - } - } - - m_usdStage->SetStartTimeCode(startTimeCode); - m_usdStage->SetEndTimeCode(endTimeCode); - - return ROP_CONTINUE_RENDER; -} - -namespace { -void -copyKindMetaDataForOverlays( UsdStageRefPtr stage, SdfPrimSpecHandle p ) -{ - UsdPrim usdPrim = stage->GetPrimAtPath( p->GetPath() ); - if( !usdPrim ) - return; - - TfToken kind; - UsdModelAPI( usdPrim ).GetKind(&kind); - - if( !kind.IsEmpty() ) { - p->SetKind( kind ); - } - - // Recurse until we find a model - if( usdPrim.IsGroup() ) { - for (const auto& child : p->GetNameChildren()) { - copyKindMetaDataForOverlays( stage, child ); - } - } -} -} // close namespace - -ROP_RENDER_CODE GusdROP_usdoutput:: -closeStage(fpreal tend) -{ - // m_usdStage will be invalid if something failed. - if( !m_usdStage ) - return ROP_CONTINUE_RENDER; - - TfToken upAxis = UsdGeomGetFallbackUpAxis(); - UsdGeomSetStageUpAxis(m_usdStage, upAxis); - - setCamerasAreZup(m_usdStage, /* zUp= */ false); - - UT_String usdFile; - evalString(usdFile, "usdfile", 0, tend); - - bool overlay = evalInt("overlay", 0, tend); - if (overlay) { - // clear out the modelingVariant selection made during openStage(). - GusdUSD_Utils::ClearModelingVariant(m_usdStage, - m_usdStage->GetDefaultPrim()); - - m_usdStage->GetSessionLayer()->Export(usdFile.toStdString()); - - // Now that the SessionLayer has been exported into a file, - // clear out all the changes in the SessionLayer to restore - // it to the way it was before any overlay edits were applied. - m_usdStage->GetSessionLayer()->Clear(); - } else { - // traverse stage and define any typeless prims as xforms - // XXX should there be a user option for xforms, overs, possibly others? - bool hasPrims = false; - for(UsdPrim prim: UsdPrimRange::Stage(m_usdStage)) { - if(!prim.HasAuthoredTypeName()) { - prim.SetTypeName(TfToken("Xform")); - } - hasPrims = true; - } - - if( !hasPrims && evalInt("alwayswriteroot", 0, tend) ) { - - // If we are writing per frame files and an a prim does not have - // geometry on a frame, the USD file will be empty. Reading a packed - // USD prim from an empty is funky. So we add the option of always - // writing an empty group. - if( SdfPath::IsValidPathString( m_pathPrefix ) ) { - UsdGeomXform prim = UsdGeomXform::Define( m_usdStage, SdfPath( m_pathPrefix ) ); - setKind( m_pathPrefix, m_usdStage ); - } - } - - m_usdStage->GetRootLayer()->Save(); - - // If m_fdTmpFile is valid, then the rootLayer of m_usdStage is just - // a temporary file. It was just saved to disk, and now it needs to - // be renamed to replace usdFile. - if (m_fdTmpFile != -1) { - // Release the file descriptor. - close(m_fdTmpFile); - m_fdTmpFile = -1; - - const char* tmpFilePath = - m_usdStage->GetRootLayer()->GetRealPath().c_str(); - - const char* targetPath = usdFile.c_str(); - if (unlink(targetPath) != 0 || - std::rename(tmpFilePath, targetPath) != 0) { - - unlink(tmpFilePath); - return abort("Failed to replace file: " + usdFile.toStdString()); - } - - // Reload any stages on the cache matching this path. - // Note that this is not thread-safe. - UT_StringSet paths; - paths.insert(targetPath); - paths.insert(TfRealPath(targetPath)); - GusdOP_Utils::ReloadStagesAndClearCaches(paths); - } - } - - return ROP_CONTINUE_RENDER; -} - -int GusdROP_usdoutput:: -startRender(int frameCount, - fpreal tstart, - fpreal tend) -{ - resetState(); - - DBG(cerr << "GusdROP_usdoutput::startRender " << CHgetSampleFromTime(tstart) << ", " << CHgetSampleFromTime(tend) << endl); - - // Validate inputs as much as possible before we start doing any real work - m_renderNode = NULL; - - // Check to see it the ROP is being used is in a SOP context. If so, - // output the SOP connected to our input. - if(SOP_Node* sopNode = CAST_SOPNODE( getInput( 0 ) )) { - m_renderNode = sopNode; - } else { - - UT_String sopPath; - evalString(sopPath, "soppath", 0, tstart); - if( !sopPath.isstring() ) { - return abort( "SOP Path not set to a valid value." ); - } - else { - - sopNode = findSOPNode(sopPath); - if(!sopNode) { - const std::string errorMessage = "Unable to find sop: " - + std::string(sopPath); - return abort(errorMessage); - } - m_renderNode = sopNode; - } - } - - UT_String fn; - evalString(fn, "usdfile", 0, tstart); - if( !fn.isstring() ) { - return abort( "USD File is not set to a valid value." ); - } - - if( evalInt( "overlay", 0, 0 ) ) { - - UT_String refFile; - evalString( refFile, "referencefile", 0, tstart ); - if( !refFile.isstring() ) { - return abort( "Overlay reference file is not set to a valid value." ); - } - } - - - // The ROP_Node built in preRenderScript does not always run when you expect it to. - // It seems to be unreliable when chaining networks. - // Add a new property and run the script ourselves so we can be sure it runs - // at the right time. - UT_String preRenderScript; - evalString( preRenderScript, "pxhprerenderscript", 0, tstart ); - if( preRenderScript.isstring() ) { - OP_ERROR err = executeScript( preRenderScript, CH_PYTHON_SCRIPT, tstart ); - if( err != UT_ERROR_NONE ) { - return abort("Pre render script failed."); - } - } - - m_startFrame = CHgetSampleFromTime(tstart); - m_endFrame = CHgetSampleFromTime(tend); - - m_granularity = - static_cast(evalInt( "granularity", 0, tstart )); - - if( m_granularity == ONE_FILE ) { - int rv = openStage( tstart, m_startFrame, m_endFrame ); - if( rv != ROP_CONTINUE_RENDER ) - return rv; - } - - // Path prefix - UT_String pathPrefix; - evalString(pathPrefix, "pathprefix", 0, tstart); - pathPrefix.trimBoundingSpace(); - pathPrefix.harden(); - if(pathPrefix.isstring()) { - string s = pathPrefix.toStdString(); - - if( s.front() != '/' ) { - s = string("/") + s; - } - // remove trailing slashes just to be consistant - if( s.back() == '/' ) - s.pop_back(); - m_pathPrefix = s; - } - - // Partition by attribute - if(evalInt("enablepathattrib", 0, tstart)) { - UT_String partitionAttr; - evalString(partitionAttr, "pathattrib", 0, tstart); - partitionAttr.trimBoundingSpace(); - if(partitionAttr.isstring()) { - m_hasPartitionAttr = true; - m_partitionAttrName = partitionAttr.toStdString(); - } - } - - // Fill primvar filter - UT_String primvars; - evalString(primvars, "varyingprimvars", 0, tstart); - m_primvarFilter.setPattern(GT_OWNER_POINT, primvars.toStdString()); - evalString(primvars, "facevaryingprimvars", 0, tstart); - m_primvarFilter.setPattern(GT_OWNER_VERTEX, primvars.toStdString()); - evalString(primvars, "uniformprimvars", 0, tstart); - m_primvarFilter.setPattern(GT_OWNER_UNIFORM, primvars.toStdString()); - evalString(primvars, "constantprimvars", 0, tstart); - m_primvarFilter.setPattern(GT_OWNER_CONSTANT, primvars.toStdString()); - - // This was copied from a SSI example. I strongly suspect this is a no-op. - executePreRenderScript(tstart); - - return ROP_CONTINUE_RENDER; -} -namespace { - -void -setKind( const string &path, UsdStagePtr stage ) -{ - // When we are creating new geometry (not doing overlays), the path prefix - // parm specifies the root of our asset. This prim needs to be marked as a - // component (model) and all its ancestors need to be marked group. - // - // Unless we are writing a group of references to other assets. This is the - // case if our chidren are models. - - if( path.empty() ) - return; - - UsdPrim p = stage->GetPrimAtPath( SdfPath( path ) ); - if( !p.IsValid() ) - return; - UsdModelAPI model( p ); - TfToken kind; - if( model && !model.GetKind( &kind )) { - - bool hasModelChildren = false; - for( const auto& child : p.GetChildren() ) { - TfToken childKind; - UsdModelAPI( child ).GetKind( &childKind ); - if( KindRegistry::IsA( childKind, KindTokens->model )) { - hasModelChildren = true; - break; - } - } - if( hasModelChildren ) - model.SetKind( KindTokens->group ); - else - model.SetKind( GusdGetAssetKind() ); - } - for( UsdPrim p = model.GetPrim().GetParent(); p.IsValid(); p = p.GetParent() ) { - UsdModelAPI m( p ); - if( m && !m.GetKind( &kind )) - m.SetKind( KindTokens->group ); - } -} - -} // close namespace - -ROP_RENDER_CODE GusdROP_usdoutput:: -renderFrame(fpreal time, - UT_Interrupt* interupt) -{ - executePreFrameScript(time); - - const double frame = CHgetSampleFromTime(time); - - DBG(cerr << "GusdROP_usdoutput::renderFrame " << frame << endl); - - if( m_granularity == PER_FRAME ) { - ROP_RENDER_CODE rv = openStage( time, frame, frame ); - if( rv != ROP_CONTINUE_RENDER ) - return rv; - } - - GT_RefineParms refineParms; - - // Tell the collectors (in particular the f3d stuff) that we are - // writing a USD file rather than doing interactive visualization. - // an interactive visualization - refineParms.set( "refineToUSD", true ); - - const bool overlayGeo = evalInt( "overlay", 0, 0 ); - const bool overlayAll = evalInt( "overlayall", 0, 0 ); - const bool overlayPoints = evalInt( "overlaypoints", 0, 0 ); - const bool overlayXforms = evalInt( "overlayxforms", 0, 0 ); - const bool overlayPrimvars = evalInt( "overlayprimvars", 0, 0 ); - - // Find the obj node that contains to SOP we are exporting - OBJ_Node *objNode = CAST_OBJNODE(m_renderNode->getCreator()); - - // If parms have been added to the obj node that will cause the meshs - // to be rendered in houdini as a subdivs, output the USD to render as a subdiv. - int polysAsSubd = 0; - if ((objNode->evalParameterOrProperty("ri_rendersubd", 0, time, polysAsSubd) - && polysAsSubd != 0) - ||(objNode->evalParameterOrProperty("ri_renderhsubd", 0, time, polysAsSubd) - && polysAsSubd != 0) - ||(objNode->evalParameterOrProperty("vm_rendersubd", 0, time, polysAsSubd) - && polysAsSubd != 0)) { - - refineParms.setPolysAsSubdivision( true ); - } - - // This ROP supports binding shaders from 2 different sources: - // 1. A shader that is already defined in a usd file somewhere can be - // referenced into this stage. - // 2. A material (shop network) inside houdini can be converted into - // a usd shader and authored into this stage. - // - // Store maps of per-prim assignments for both shader types. - UsdRefShaderMap usdRefShaderMap; - HouMaterialMap houMaterialMap; - - // Set up the variables needed for doing multi-seg writing of samples. - // The default behavior is to write a single sample at the given frame. - size_t samples = 1; - float shutterOpen = 0; - float shutterClose = 1.0; - - // If "enablemultiseg" is on, update variables with user-specified values. - if (evalInt("enablemultiseg", 0, 0)) { - samples = evalInt("samples", 0, 0); - if (evalInt("samplingmode", 0, 0) == 0) { // samplingmode == "Forward" - shutterOpen = evalFloat("shutter", 0, 0); - shutterClose = evalFloat("shutter", 1, 0); - } else { // samplingmode == "Backward" - // Reverse the open/close shutter times. - shutterOpen = -(evalFloat("shutter", 1, 0)); - shutterClose = -(evalFloat("shutter", 0, 0)); - } - } - - // If there are 2 or more samples being taken, compute the time length of - // the segment(s). If only 1 sample is being taken, there is no segment. - double segment = samples < 2 ? 0.0 : - (shutterClose - shutterOpen) / double(samples - 1); - - // Loop through multi-seg samples, write out data for each sample. - for (size_t s = 0; s < samples; s++) { - double sampleFrame = frame + shutterOpen + (segment * s); - - OP_Context houdiniContext(CHgetTimeFromFrame(sampleFrame)); - - bool useObj = static_cast(evalInt( "useobjtransform", 0, 0 )); - // Get the OBJ node transform - UT_Matrix4D localToWorldMatrix; - if (useObj) - objNode->getLocalToWorldTransform( houdiniContext, localToWorldMatrix); - else - localToWorldMatrix.identity(); - - // Cook our input - GU_DetailHandle cookedGeoHdl = m_renderNode->getCookedGeoHandle(houdiniContext); - if (!cookedGeoHdl.isValid()) { - const std::string errorMessage = "invalid cooked geometry from sop: " - + std::string(m_renderNode->getName()); - return abort(errorMessage); - } - - GusdRefinerCollector refinerCollector; - GusdRefiner refiner( - refinerCollector, - m_pathPrefix.empty() ? SdfPath() : SdfPath(m_pathPrefix), - m_partitionAttrName, - localToWorldMatrix ); - - // If we ae only overlaying transforms and encounter a packed prim, - // just write the transform and don't refine further. - refiner.m_refinePackedPrims = !overlayGeo || !( overlayXforms && !(overlayAll || overlayPoints )); - - // If writing an overlay and a prim has an instinsic path, write the prim to that path - refiner.m_useUSDIntrinsicNames = overlayGeo; - - // Check for a (usd)instancepath paramter/property to set as the default - // value. This tells us to build a point instancer. - UT_String usdInstancePath; - if(!evalParameterOrProperty("usdinstancepath", 0, 0, usdInstancePath)) { - if(!objNode->evalParameterOrProperty("usdinstancepath", 0, 0, usdInstancePath)) { - if(!evalParameterOrProperty("instancepath", 0, 0, usdInstancePath)) { - objNode->evalParameterOrProperty("instancepath", 0, 0, usdInstancePath); - } - } - } - if(usdInstancePath.isstring()) { - refiner.m_buildPointInstancer = true; - } - - refiner.m_writeCtrlFlags.overAll = overlayAll; - refiner.m_writeCtrlFlags.overPoints = overlayPoints; - refiner.m_writeCtrlFlags.overTransforms = overlayXforms; - refiner.m_writeCtrlFlags.overPrimvars = overlayPrimvars; - - refiner.refineDetail( cookedGeoHdl, refineParms ); - - // If we are building a point instancer, the refiner will have accumulated all the - // instances. Now we can build the instancer prims. - const GusdRefiner::GprimArray& gprimArray = refiner.finish(); - - DBG( cerr << "Num of refined gt prims = " << gprimArray.size() << endl ); - - // Build a structure to hold the data that the wrapper prims need to - // write to USD. - GusdContext ctxt( UsdTimeCode(sampleFrame), - GusdContext::Granularity(m_granularity), - m_primvarFilter ); - - if(usdInstancePath.isstring()) { - ctxt.usdInstancePath = usdInstancePath; - } - - ctxt.writeOverlay = overlayGeo; - - // Check for a usdprototypespath paramter/property to set as the default - // for point instancing. - UT_String usdPrototypesPath; - if(!evalParameterOrProperty("usdprototypespath", 0, 0, usdPrototypesPath)) { - objNode->evalParameterOrProperty("usdprototypespath", 0, 0, usdPrototypesPath); - } - if(usdPrototypesPath.isstring()) { - ctxt.usdPrototypesPath = usdPrototypesPath.toStdString(); - } - - // Check for usd Layer Offset attributes (offset and scale). - fpreal usdTimeOffset = 0; - if(!evalParameterOrProperty("usdtimeoffset", 0, 0, usdTimeOffset)) { - objNode->evalParameterOrProperty("usdtimeoffset", 0, 0, usdTimeOffset); - } - ctxt.usdTimeOffset = usdTimeOffset; - - fpreal usdTimeScale = 1.0; - if(!evalParameterOrProperty("usdtimescale", 0, 0, usdTimeScale)) { - objNode->evalParameterOrProperty("usdtimescale", 0, 0, usdTimeScale); - } - ctxt.usdTimeScale = usdTimeScale; - - if( m_hasPartitionAttr ) - ctxt.primPathAttribute = m_partitionAttrName; - - ctxt.authorVariantSelections = evalInt( "authorvariantselection", 0, 0 ); - - ctxt.makeRefsInstanceable = - static_cast(evalInt( "usdinstancing", 0, 0 )); - - // Sort the refined prim array by primitive paths. This ensures parents - // will be written before their children. - GusdRefinerCollector::GprimArray gPrims = gprimArray; - std::sort( gPrims.begin(), gPrims.end(), - []( const GusdRefinerCollector::GprimArrayEntry& a, - const GusdRefinerCollector::GprimArrayEntry& b ) -> bool - { return a.path < b.path; } ); - - UT_Set gprimsProcessedThisFrame; - bool needToUpdateModelExtents = false; - - GusdSimpleXformCache xformCache; - - // If we are not writing an overlay (and we are not ignoring objject - // level transforms, assume we are writing an asset rooted at the prim - // named m_pathPrefix. Write the obj space transform at this prim on all - // frames. This is needed to make sure that transform motion blur is - // right when the object space is animated. - if( useObj && !overlayGeo && !m_pathPrefix.empty() ) { - - SdfPath assetPrimPath( m_pathPrefix ); - - // Check to make sure the asset prim isn't going to be written anyway. - bool assetPrimFound = false; - for( auto& gtPrim : gPrims ) { - - if( gtPrim.path == assetPrimPath ) { - assetPrimFound = true; - break; - } - } - - if( !assetPrimFound ) { - - GT_PrimitiveHandle assetPrim; - - GprimMap::iterator gpit = m_gprimMap.find(assetPrimPath); - if( gpit == m_gprimMap.end() ) { - GT_PrimitiveHandle assetXformWrapper = new GusdXformWrapper( m_usdStage, assetPrimPath ); - m_gprimMap[assetPrimPath] = assetXformWrapper; - assetPrim = assetXformWrapper; - } - else { - assetPrim = gpit->second; - - // If a USD version of this prim doesn't exist on the current edit - // target's layer, create a new USD prim. This happens when we are - // writing per frame files. - SdfPrimSpecHandle ph = m_usdStage->GetEditTarget().GetPrimSpecForScenePath( assetPrimPath ); - if( !ph ) { - dynamic_cast(assetPrim.get())-> - redefine( m_usdStage, assetPrimPath, ctxt, NULL); - } - } - - if(assetPrim) { - - GusdPrimWrapper* primPtr - = UTverify_cast(assetPrim.get()); - - // Copy attributes from gt prim to USD prim. - primPtr->updateFromGTPrim( NULL, - localToWorldMatrix, - ctxt, - xformCache ); - gprimsProcessedThisFrame.insert(assetPrimPath); - } - } - } - - // Iterate over the refined prims and write - for( auto& gtPrim : gPrims ) { - - const SdfPath& primPath = gtPrim.path; - - DBG(cerr << "Write prim: " << primPath << ", type = " << gtPrim.prim->className() << endl); - - // Copy properties that were accumulated in the refiner and stored with - // the refined prim to the context. - ctxt.purpose = gtPrim.purpose; - const GusdWriteCtrlFlags& flags = gtPrim.writeCtrlFlags; - ctxt.overlayPoints = overlayGeo && (flags.overPoints || flags.overAll); - ctxt.overlayTransforms = overlayGeo && (flags.overTransforms || flags.overAll); - ctxt.overlayPrimvars = overlayGeo && (flags.overPrimvars || flags.overAll); - ctxt.overlayAll = overlayGeo && flags.overAll; - - ctxt.writeStaticGeo = flags.writeStaticGeo; - ctxt.writeStaticTopology = flags.writeStaticTopology; - ctxt.writeStaticPrimvars = flags.writeStaticPrimvars; - - // If doing an overlay of points or xforms, then bounds are likely - // changing due to prims being deformed or moved. The "extentsHint" - // attribute will need to be updated. - if( ctxt.overlayPoints || ctxt.overlayTransforms ) { - needToUpdateModelExtents = true; - } - - gprimsProcessedThisFrame.insert(primPath); - - // If we're attempting to overlay instanced geometry, set the root - // of the instance to 'instanceable = false'. Recurse on the parent - // in case it itself is an instance. - SdfPath currPath = primPath; - UsdPrim currPrim = m_usdStage->GetPrimAtPath( currPath ); - std::vector instancePrimPaths; - while ( currPrim.IsInstanceProxy() ) { - // Get the master prim which corresponds to each instance - UsdPrim masterPrim = currPrim.GetPrimInMaster(); - const SdfPath& masterPath = masterPrim.GetPath(); - // Removing common suffices results in just the path that was - // instance for our prim (and /__master_* for the master path) - const pair pathsPair = currPath.RemoveCommonSuffix(masterPath); - currPath = pathsPair.first; - if ( currPath.IsEmpty() ) { - // We shouldn't get here - break; - } - // Get the prim on the stage (not on the master) - UsdPrim instancePrim = m_usdStage->GetPrimAtPath( currPath ); - // Check to make sure we're deinstancing an instance - if ( instancePrim.IsInstance() ) { - instancePrimPaths.push_back(currPath); - } - // Recurse on the parent prim in case it's nested as another instance - currPrim = instancePrim; - } - - // Reverse the order to actually deinstance, as we can't edit nested - // instance proxies without first deinstancing their parent instances. - for (int i = instancePrimPaths.size()-1; i >=0; i--) { - UsdPrim instancePrim = m_usdStage->GetPrimAtPath( instancePrimPaths[i] ); - instancePrim.SetInstanceable(false); - DBG(cerr << "Deinstanced prim at: " << instancePrimPaths[i].GetText() << endl); - } - - GT_PrimitiveHandle usdPrim; - - // Have we seen this prim on a previous frame? - GprimMap::iterator gpit = m_gprimMap.find(primPath); - if( gpit == m_gprimMap.end() ) { - - // Create a new USD prim - usdPrim = GusdPrimWrapper::defineForWrite( - gtPrim.prim, m_usdStage, primPath, ctxt ); - - if( !usdPrim ) { - TF_WARN( "prim did not convert. %s", gtPrim.prim->className() ); - } - else { - m_gprimMap[primPath] = usdPrim; - - GusdPrimWrapper* primPtr - = UTverify_cast(usdPrim.get()); - - // If we're writing many frames to a single file, write - // "bookend" visibility samples if this prim is not first - // appearing on the start frame. - if ( m_granularity == ONE_FILE ) { - if ( !SYSisEqual(sampleFrame, m_startFrame + shutterOpen, 1e-6) ) { - primPtr->addLeadingBookend( sampleFrame ); - } - } - primPtr->markVisible( true ); - } - } - else { - - // Add samples to a existing prim - usdPrim = gpit->second; - - SdfLayerHandle layer = overlayGeo ? - m_usdStage->GetSessionLayer() : m_usdStage->GetRootLayer(); - - // If a USD version of this prim doesn't exist on the current edit - // target's layer, create a new USD prim. This happens when we are - // writing per frame files. - SdfPrimSpecHandle ph = m_usdStage->GetEditTarget().GetPrimSpecForScenePath( primPath ); - if( !ph ) { - dynamic_cast(usdPrim.get())-> - redefine( m_usdStage, SdfPath( primPath ), ctxt, gtPrim.prim ); - } - - GusdPrimWrapper* primPtr - = UTverify_cast(usdPrim.get()); - if( !primPtr->isVisible() ) { - primPtr->markVisible( true ); - } - } - - if(usdPrim) { - - GusdPrimWrapper* primPtr - = UTverify_cast(usdPrim.get()); - - // Copy attributes from gt prim to USD prim. - primPtr->updateFromGTPrim(gtPrim.prim, - gtPrim.xform, - ctxt, - xformCache ); - - // Get prim-level usdShadingFile and usdShader if they exist - string primUsdShadingFile = - getStringUniformOrDetailAttribute(gtPrim.prim, "usdShadingFile"); - string primUsdShader = - getStringUniformOrDetailAttribute(gtPrim.prim, "usdShader"); - - if( !primUsdShadingFile.empty() && !primUsdShader.empty() ) { - UsdRefShader usdRefShader = std::make_pair(primUsdShadingFile, - primUsdShader); - addShaderToMap(usdRefShader, SdfPath(gtPrim.path.GetString()), - usdRefShaderMap); - } - - // Get prim-level shop_materialpath attribute if it exists. - string primMaterialPath = - getStringUniformOrDetailAttribute(gtPrim.prim, - "shop_materialpath"); - if (!primMaterialPath.empty()) { - addShaderToMap(primMaterialPath, - SdfPath(gtPrim.path.GetString()), - houMaterialMap); - } - - // Check for a hero prim to operate on. - GT_Owner owner = GT_OWNER_UNIFORM; - GT_DataArrayHandle heroAttr = gtPrim.prim->findAttribute( "usdheroprim", owner, 0); - if(heroAttr != NULL && heroAttr->getI32(0) > 0) { - - // Get the hero prim from the stage. - UsdPrim heroPrim = m_usdStage->GetPrimAtPath( primPath ); - - // Call the registered operate on usd prim function on our hero. - if ( heroPrim && m_modelPrim.IsValid() ) { - std::string modelPath = m_modelPrim.GetName().GetString(); - do { - GusdOperateOnUsdPrim( heroPrim ); - if (heroPrim.GetName().GetString() == modelPath) { - break; - } - heroPrim = heroPrim.GetParent(); - } while ( heroPrim.IsValid()); - } - } - } - } - - // If we're holding prims which weren't processed on this frame, they should - // become invisible on this frame - for(GprimMap::iterator gprimIt=m_gprimMap.begin(); - gprimIt!=m_gprimMap.end();++gprimIt) { - - if(gprimsProcessedThisFrame.find(gprimIt->first) - == gprimsProcessedThisFrame.end()) { - - const SdfPath& primPath = gprimIt->first; - - GusdPrimWrapper* primPtr - = UTverify_cast(gprimIt->second.get()); - - SdfPrimSpecHandle ph = m_usdStage->GetRootLayer()->GetPrimAtPath( SdfPath( primPath ) ); - if( !ph ) { - primPtr->redefine( m_usdStage, primPath, ctxt, GT_PrimitiveHandle() ); - } - - if ( m_granularity == ONE_FILE ) { - primPtr->addTrailingBookend( sampleFrame ); - // Remove prim from the persistent gprim map. - m_gprimMap.erase( gprimIt ); - } - else { - primPtr->setVisibility( UsdGeomTokens->invisible, ctxt.time ); - } - } - } - - // Now the "extentsHint" attribute needs to be updated - // for prims and their ancestors. - if (needToUpdateModelExtents) { - // Create a UsdGeomBBoxCache for computing extents. - TfTokenVector includedPurposes = {UsdGeomTokens->default_ , UsdGeomTokens->render}; - UsdGeomBBoxCache cache(ctxt.time, includedPurposes, - /*useExtentsHint*/ false); - - // Maintain a set of paths of ancestors visited during the following - // loop. This is an optimization to avoid computing/setting the - // extentsHint multiple times for the same prim. - std::set visitedPaths; - const SdfPath rootPath("/"); - - for (GprimMap::const_iterator it = m_gprimMap.begin(); - it != m_gprimMap.end(); ++it) { - - SdfPath path = SdfPath(it->first).GetParentPath(); - - while (path != rootPath && path != SdfPath::EmptyPath()) { - UsdGeomModelAPI model(m_usdStage->GetPrimAtPath(path)); - - if (model.GetExtentsHintAttr() && - visitedPaths.find(path) == visitedPaths.end()) { - const VtVec3fArray extentsHint = - model.ComputeExtentsHint(cache); - model.SetExtentsHint(extentsHint, ctxt.time); - } - visitedPaths.insert(path); - path = path.GetParentPath(); - } - } - } - } // end loop through multi-seg samples - - // If not writing an overlay and if m_pathPrefix is not empty, - // assume an asset rooted at the prim named m_pathPrefix has - // just been created. Bind any obj level shaders to this prim. - if( !overlayGeo && !m_pathPrefix.empty() ) { - - const SdfPath assetPrimPath(m_pathPrefix); - UsdPrim assetPrim = m_usdStage->GetPrimAtPath(assetPrimPath); - - if (assetPrim) { - - // Look for obj node USD shader assignment - UT_String usdShadingFile, usdShader; - evalString(usdShadingFile, "usdshadingfile", 0, 0); - evalString(usdShader, "usdshader", 0, 0); - - if( usdShadingFile.isstring() && usdShader.isstring() && - usdShader.toStdString() != "None") - { - UsdRefShader usdRefShader = - std::make_pair(usdShadingFile.toStdString(), - usdShader.toStdString()); - addShaderToMap(usdRefShader, assetPrimPath, usdRefShaderMap); - } - - UT_String materialPath; - if (objNode->evalParameterOrProperty("shop_materialpath", - 0, 0, materialPath) - && materialPath.isstring()) { - addShaderToMap(materialPath.toStdString(), assetPrimPath, - houMaterialMap); - } - } - - bindAndWriteShaders(usdRefShaderMap, houMaterialMap); - } - - if (overlayGeo) { - // Turn off pruning for all prims that have been overlayed. - for (GprimMap::const_iterator it = m_gprimMap.begin(); - it != m_gprimMap.end(); ++it) { - - const SdfPath path(it->first); - // Check if there is anything authored at this path on m_usdStage's - // current EditTarget. If so, also author an attribute to disable - // pruning. - if (m_usdStage->GetEditTarget().GetPrimSpecForScenePath(path)) { - if (UsdPrim prim = m_usdStage->GetPrimAtPath(path)) { - if (UsdAttribute pruneAttr = - prim.CreateAttribute(TfToken("pruning:prunable"), - SdfValueTypeNames->Bool, false, - SdfVariabilityUniform)) { - pruneAttr.Set(false); - } - } - } - } - } - - // Set the default prim path (to default or m_defaultPrimPath if set). - if( m_granularity == PER_FRAME ) { - if( !m_defaultPrimPath.empty() ) { - setKind( m_defaultPrimPath, m_usdStage ); - - SdfLayerHandle layer = overlayGeo ? - m_usdStage->GetSessionLayer() : m_usdStage->GetRootLayer(); - if( m_defaultPrimPath[0] == '/' && m_defaultPrimPath.find( '/', 1 ) == string::npos ) { - SdfPrimSpecHandle defPrim = layer->GetPrimAtPath( SdfPath(m_defaultPrimPath) ); - if( defPrim ) { - layer->SetDefaultPrim( TfToken(m_defaultPrimPath.substr(1) ) ); - } - } - } else if( !overlayGeo ) { - setKind( m_pathPrefix, m_usdStage ); - - if( m_pathPrefix[0] == '/' && m_pathPrefix.find( '/', 1 ) == string::npos ) { - UsdPrim defPrim = m_usdStage->GetPrimAtPath( SdfPath(m_pathPrefix) ); - if( defPrim ) { - m_usdStage->SetDefaultPrim( defPrim ); - } - } - } - - ROP_RENDER_CODE rv = closeStage(time); - if( rv != ROP_CONTINUE_RENDER ) - return rv; - - m_usdStage = NULL; - } - - executePostFrameScript(time); - - // Tina needs to output progress messages and trigger TINA_DO on every - // frame. - UT_String script; - evalString( script, "tinaprogressscript", 0, time ); - if( script.isstring() ) { - executeScript( script, CH_PYTHON_SCRIPT, time ); - } - return ROP_CONTINUE_RENDER; -} - - -ROP_RENDER_CODE GusdROP_usdoutput:: -bindAndWriteShaders(UsdRefShaderMap& usdRefShaderMap, - HouMaterialMap& houMaterialMap) -{ - // - // This ROP supports binding shaders from 2 different sources: - // 1. A shader that is already defined in a usd file somewhere can be - // referenced into this stage. - // 2. A material (shop network) inside houdini can be converted into - // a usd shader and authored into this stage. - // - // In the unlikely case that a prim maps to both a referenced usd shader - // and a houdini material, the houdini material will win. Here, this is - // accomplished by binding all referenced usd shaders first, and binding - // all houdini materials last. - // - - // TODO: For now, only support houdini materials if the "enableshaders" - // parameter is turned on. This toggle is our temporary way for enabling - // houdini materials for exported assests, but disabling them for items - // written from a cacher SOP. Turning this feature on inside a cacher SOP - // (thus attempting to build the same houdini material in multiple tasks - // at the same time) is currently unsupported/undefined behavior. - bool enableHouShaders = evalInt("enableshaders", 0, 0); - if (!enableHouShaders) { - houMaterialMap.clear(); - } - - // If there are no shaders, exit now before defining a "Looks" scope. - if (usdRefShaderMap.empty() && houMaterialMap.empty()) { - return ROP_CONTINUE_RENDER; - } - - SdfPath looksPath = SdfPath(m_pathPrefix).AppendChild(TfToken("Looks")); - UsdGeomScope looksScope = UsdGeomScope::Define(m_usdStage, looksPath); - - // - // Handle all referenced usd shaders first. - // - for (auto assignmentIt = usdRefShaderMap.begin(); - assignmentIt != usdRefShaderMap.end(); ++assignmentIt) { - - UsdRefShader usdRefShader = assignmentIt->first; - vector& primPaths = assignmentIt->second; - - string shaderFile = usdRefShader.first; - string shaderName = usdRefShader.second; - if (shaderName.front() != '/') { - shaderName = string("/") + shaderName; - } - - // The shaderName string is expected to contain either a single name, - // like "/FxFire", or a longer path, like "/Chair/Looks/Plastic". - // Take the substring after the last '/' as the material name. - string materialName = shaderName.substr(shaderName.rfind("/") + 1); - - UsdShadeMaterial usdMaterial = UsdShadeMaterial::Define(m_usdStage, - looksPath.AppendChild(TfToken(materialName))); - - UsdReferences refs = usdMaterial.GetPrim().GetReferences(); - shaderFile = GusdComputeRelativeSearchPath(shaderFile); - - UsdPrim shaderPrim; - UsdStageRefPtr shaderStage = UsdStage::Open(shaderFile); - if (!shaderStage) { - TF_WARN("Could not open shader file '%s'", shaderFile.c_str()); - } else { - shaderPrim = shaderStage->GetPrimAtPath(SdfPath(shaderName)); - if (!shaderPrim) { - TF_WARN("Could not find shader '%s' in file '%s'", - shaderName.c_str(), shaderFile.c_str()); - } - else { - // Reference shaderPrim on the usdMaterial prim that - // was just defined on m_usdStage. - refs.AddReference(shaderFile, shaderPrim.GetPath()); - } - } - if (shaderPrim) { - for (auto primPathIt = primPaths.begin(); - primPathIt != primPaths.end(); ++primPathIt) { - UsdPrim prim = m_usdStage->GetPrimAtPath(*primPathIt); - UsdShadeMaterialBindingAPI(prim).Bind(usdMaterial); - } - } - } - - UT_String shaderOutDir; - evalString(shaderOutDir, "shaderoutdir", 0, 0); - - // - // Handle all houdini material shaders last. - // - for (auto assignmentIt = houMaterialMap.begin(); - assignmentIt != houMaterialMap.end(); ++assignmentIt) { - - VOP_Node* materialVop = findVOPNode(assignmentIt->first.c_str()); - if (materialVop == NULL || - strcmp(materialVop->getRenderMask(),"RIB") != 0) { - continue; - } - - UT_String vopPath(materialVop->getFullPath()); - vopPath.forceAlphaNumeric(); - SdfPath path = looksPath.AppendPath(SdfPath(vopPath.toStdString())); - - GusdShaderWrapper shader(materialVop, m_usdStage, path.GetString(), - shaderOutDir.toStdString()); - - vector& primPaths = assignmentIt->second; - for (auto primPathIt = primPaths.begin(); - primPathIt != primPaths.end(); ++primPathIt) { - UsdPrim prim = m_usdStage->GetPrimAtPath(*primPathIt); - shader.bind(prim); - } - } - - return ROP_CONTINUE_RENDER; -} - - -void GusdROP_usdoutput::resetState() -{ - m_usdStage = NULL; - - m_startFrame = 0; - m_endFrame = 0; - m_houdiniContext = OP_Context(); - m_pathPrefix = ""; - m_hasPartitionAttr = false; - m_partitionAttrName = ""; - m_renderNode = NULL; - - m_fdTmpFile = -1; - - m_gprimMap.clear(); -} - - -ROP_RENDER_CODE GusdROP_usdoutput:: -endRender() -{ - double endTimeCode = CHgetTimeFromFrame( m_endFrame ); - - // Set the default prim path (to default or m_defaultPrimPath if set). - if( m_granularity == ONE_FILE ) { - bool overlayGeo = evalInt( "overlay", 0, endTimeCode ); - if( !m_defaultPrimPath.empty() ) { - setKind( m_defaultPrimPath, m_usdStage ); - - SdfLayerHandle layer = overlayGeo ? - m_usdStage->GetSessionLayer() : m_usdStage->GetRootLayer(); - if( m_defaultPrimPath[0] == '/' && m_defaultPrimPath.find( '/', 1 ) == string::npos ) { - SdfPrimSpecHandle defPrim = layer->GetPrimAtPath( SdfPath(m_defaultPrimPath) ); - if( defPrim ) { - layer->SetDefaultPrim( TfToken(m_defaultPrimPath.substr(1) ) ); - } - } - } else if( !overlayGeo && m_usdStage ) { - setKind( m_pathPrefix, m_usdStage ); - - if( m_pathPrefix[0] == '/' && m_pathPrefix.find( '/', 1 ) == string::npos ) { - UsdPrim defPrim = m_usdStage->GetPrimAtPath( SdfPath(m_pathPrefix) ); - if( defPrim ) { - m_usdStage->SetDefaultPrim( defPrim ); - } - } - } - - ROP_RENDER_CODE rv = closeStage(endTimeCode); - if( rv != ROP_CONTINUE_RENDER ) - return rv; - } - - - resetState(); - - executePostRenderScript(endTimeCode); - - return ROP_CONTINUE_RENDER; -} - - -ROP_RENDER_CODE GusdROP_usdoutput:: -abort(const std::string& errorMessage) -{ - resetState(); - addError(ROP_MESSAGE, errorMessage.c_str()); - return ROP_ABORT_RENDER; -} - -namespace { - -string -getStringUniformOrDetailAttribute( - GT_PrimitiveHandle prim, - const char* attrName ) -{ - // If a uniform attribute exists with the give name, return it. Otherwise - // fallback to a detail attribute. - if( auto uniformAttrs = prim->getUniformAttributes() ) { - if( auto attr = uniformAttrs->get( attrName ) ) { - GT_String v = attr->getS(0); - if( v != NULL ) { - return v; - } - } - } - if( auto detailAttrs = prim->getDetailAttributes() ) { - if( auto attr = detailAttrs->get( attrName )) { - GT_String v = attr->getS(0); - if( v != NULL ) { - return v; - } - } - } - return string(); -} - -bool -setCamerasAreZup(UsdStageWeakPtr const &stage, bool isZup) -{ - if (!stage){ - return false; - } - bool anySet = false; - - for (const auto& prim : stage->GetPseudoRoot(). - GetFilteredChildren(UsdPrimIsDefined && - !UsdPrimIsAbstract)) { - prim.SetCustomDataByKey(TfToken("zUp"), VtValue(isZup)); - anySet = true; - } - return anySet; -} - -template -void addShaderToMap(const ShaderT& shader, const SdfPath& primPath, - UT_Map >& map) -{ - auto assignmentIt = map.find(shader); - if (assignmentIt == map.end()) { - map[shader] = vector(1, primPath); - } else { - assignmentIt->second.push_back(primPath); - } -} - - -} // close namespace - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/plugin/OP_gusd/ROP_usdoutput.h b/third_party/houdini/plugin/OP_gusd/ROP_usdoutput.h deleted file mode 100644 index 297828b9cd..0000000000 --- a/third_party/houdini/plugin/OP_gusd/ROP_usdoutput.h +++ /dev/null @@ -1,109 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef OP_GUSD_ROP_USDOUTPUT_H -#define OP_GUSD_ROP_USDOUTPUT_H - -#include -#include "pxr/base/tf/refPtr.h" - -#include "pxr/usd/usd/prim.h" -#include "pxr/usd/usd/stage.h" - -#include -#include -#include -#include -#include - -#include "gusd/GT_Utils.h" - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdROP_usdoutput : public ROP_Node -{ - typedef UT_Map GprimMap; - - typedef std::pair UsdRefShader; - typedef UT_Map > UsdRefShaderMap; - typedef UT_Map > HouMaterialMap; - - enum Granularity { ONE_FILE, PER_FRAME }; - -public: - - static void Register(OP_OperatorTable* table); - - GusdROP_usdoutput(OP_Network* network, - const char* name, - OP_Operator* op); - - virtual ~GusdROP_usdoutput(); - - virtual bool updateParmsFlags() override; - - virtual int startRender(int frameCount, - fpreal tstart, - fpreal tend) override; - - virtual ROP_RENDER_CODE renderFrame(fpreal time, - UT_Interrupt* interrupt) override; - - virtual ROP_RENDER_CODE endRender() override; - -private: - - ROP_RENDER_CODE openStage(fpreal tstart, int startTimeCode, int endTimeCode); - ROP_RENDER_CODE closeStage(fpreal tend); - - ROP_RENDER_CODE bindAndWriteShaders(UsdRefShaderMap& usdRefShaderMap, - HouMaterialMap& houMaterialMap); - void resetState(); - - ROP_RENDER_CODE abort(const std::string& errorMessage); - -private: - - double m_startFrame; - double m_endFrame; - std::string m_pathPrefix; - bool m_hasPartitionAttr; - std::string m_partitionAttrName; - OP_Context m_houdiniContext; - - SOP_Node* m_renderNode; - - UsdStageRefPtr m_usdStage; - int m_fdTmpFile; - GusdGT_AttrFilter m_primvarFilter; - GprimMap m_gprimMap; - std::string m_defaultPrimPath; - UsdPrim m_modelPrim; - std::string m_assetName; - - Granularity m_granularity; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /* OP_GUSD_ROP_USDOUTPUT_H */ diff --git a/third_party/houdini/plugin/OP_gusd/ROP_usdreference.otl b/third_party/houdini/plugin/OP_gusd/ROP_usdreference.otl deleted file mode 100644 index d02d765bf09e2cd2d0c93a273269e61f0d502513..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41179 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 E1Ffz?IsgCw diff --git a/third_party/houdini/plugin/OP_gusd/ROP_usdreference.py b/third_party/houdini/plugin/OP_gusd/ROP_usdreference.py deleted file mode 100644 index b695180c96..0000000000 --- a/third_party/houdini/plugin/OP_gusd/ROP_usdreference.py +++ /dev/null @@ -1,212 +0,0 @@ -# -# Copyright 2017 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# -# ROP used to create a reference to a USD file. -# We use this to create links from a container USD file to the individual assets. -# -# We want to be able to rename assets or move them in the USD namespace without -# rewriting a ton of data. To accomplish this we create a prim in the referencing -# file (the container) that is named the right thing. Then the referenced files -# can contain data in some generic namespace. - -from __future__ import print_function - -import soho -from glob import glob -import os, sys -from pxr import Usd,UsdGeom,UsdUtils,Sdf,Kind - -def insertReference( destFile, path, reffile, primPath=None, offset=0, scale=1 ): - - if os.path.exists( destFile ): - stage = Usd.Stage.Open( destFile ) - if not stage: - soho.error("Could not open USD file: " + destFile) - - frameRange, defaultPrim, firstRoot = getMetaData( reffile ) - - existingRefPath = None - returnVal = None - for p in stage.GetRootLayer().rootPrims: - returnVal = findMatchingReference( p, reffile ) - if returnVal: - break - - layerOffset = Sdf.LayerOffset(offset, scale) - if returnVal: - existingRefPath, existingPrimPath, existingLayerOffset = returnVal - keepPrimPath = True - if primPath: - if primPath != existingPrimPath: - keepPrimPath = False - elif defaultPrim and defaultPrim != existingPrimPath: - keepPrimPath = False - elif firstRoot and firstRoot.pathString != existingPrimPath: - keepPrimPath = False - - if ( existingRefPath == path and layerOffset == existingLayerOffset - and keepPrimPath ): - # Our exact link already exists. - sys.exit() - else: - # There is a existing link to our file but we want to rename it, - # target a new prim path or add/change the layer offset. - # Delete the old link. - prim = stage.GetPrimAtPath( existingRefPath ) - refList = prim.GetReferences() - existingRef = Sdf.Reference( reffile, - existingPrimPath, - layerOffset=existingLayerOffset ) - refList.RemoveReference(existingRef) - else: - frameRange, defaultPrim, firstRoot = getMetaData( reffile ) - stage = Usd.Stage.CreateNew( destFile ) - if not stage: - soho.error( "Could not create USD file: " + destFile ) - - if frameRange and not stage.HasAuthoredTimeCodeRange(): - stage.SetStartTimeCode(frameRange[0]) - stage.SetEndTimeCode(frameRange[1]) - - # If the the file that we are referencing defines a default prim, - # we can use it (targetPrim = None). Otherwise, use rootPrim. An existing - # or provided prim path overrides either. - if not primPath: - primPath = firstRoot if not defaultPrim else None - addReference( stage, path, reffile, primPath, layerOffset=layerOffset ) - stage.GetRootLayer().Save() - -def findMatchingReference( sdfPrim, fileName ): - ''' - Recursivly introspect prims looking for references to the given file name. - If a reference to the file is found, return the path of the prim it was - found in. - ''' - - for ref in sdfPrim.referenceList.GetAddedOrExplicitItems(): - if ref.assetPath == fileName: - return sdfPrim.path, ref.primPath, ref.layerOffset - - for child in sdfPrim.nameChildren: - returnVal = findMatchingReference( child, fileName ) - if returnVal: - path, primPath, layerOffset = returnVal - return path, primPath, layerOffset - - return None - -def addReference( stage, path, fileName, targetPrim, layerOffset=None ): - ''' - Add a reference to the given USD stage at the given path. - - If defaultPrim is not None, the the referencee contains a default prim and - we can contruct the reference to use it. - - Otherwise, create the reference to point to the first found rootPrim. - (We are assume these files will only have one root prim) - ''' - - prim = stage.GetPrimAtPath( path ) - if not prim: - # Create groups (xforms) for all the intermediate scopes in the namespace - for ancestor in Sdf.Path( path ).GetParentPath().GetPrefixes(): - p = UsdGeom.Xform.Define(stage, ancestor) - Usd.ModelAPI(p).SetKind(Kind.Tokens.group) - - # Create an over to hold the actual reference. This is so that - # the composited prim is named what we see in the referencing file. - prim = stage.OverridePrim( path ) - else: - prim = stage.GetPrimAtPath( path ) - - refList = prim.GetReferences() - if targetPrim: - refList.AddReference( Sdf.Reference( fileName, - targetPrim, - layerOffset=layerOffset )) - else: - refList.AddReference( Sdf.Reference( fileName, - layerOffset=layerOffset )) - -def getMetaData( fileName ): - ''' - Grab some meta data from a USD file - ''' - - frameRange = None - defaultPrim = None - firstRoot = None - - stage = Usd.Stage.Open( fileName, load=Usd.Stage.LoadNone ) - refLayer = stage.GetRootLayer() - if refLayer: - if stage.HasAuthoredTimeCodeRange(): - frameRange = (stage.GetStartTimeCode(), stage.GetEndTimeCode()) - if refLayer.HasDefaultPrim(): - defaultPrim = refLayer.defaultPrim - if len(refLayer.rootPrims) > 0: - firstRoot = refLayer.rootPrims[0].path - else: - print( "opening %s failed" % fileName ) - - return (frameRange, defaultPrim, firstRoot) - - -############################################################################### -# parameters -############################################################################### - -parameterDefines = { - 'f' : soho.SohoParm('f', 'real', [1, 1, 1], False), - 'now' : soho.SohoParm('state:time', 'real', [0], False, key = 'now'), - 'destfile' : soho.SohoParm('destfile', 'string', [''], False ), - 'path' : soho.SohoParm('path', 'string', [''], False ), - 'reffile' : soho.SohoParm('reffile', 'string', [''], False ), - 'primpath' : soho.SohoParm('primpath', 'string', [''], False ), - 'offset' : soho.SohoParm('offset', 'real', [0, 1], False), -} - -parameters = soho.evaluate(parameterDefines) - -# -# init soho -# -now = parameters['now'].Value[0] -soho.initialize(now, '') -soho.lockObjects(now) - -destFile = parameters['destfile'].Value[0] -path = parameters['path'].Value[0] -reffile = parameters['reffile'].Value[0] -primPath = parameters['primpath'].Value[0] -offset = parameters['offset'].Value[0] -scale = parameters['offset'].Value[1] - -try: - - insertReference( destFile, path, reffile, primPath=primPath, offset=offset, - scale=scale ) - -except Exception as e: - - soho.error( 'Failed to add USD file reference: ' + str(e) ) \ No newline at end of file diff --git a/third_party/houdini/plugin/OP_gusd/SOP_camerafrustum.otl b/third_party/houdini/plugin/OP_gusd/SOP_camerafrustum.otl deleted file mode 100644 index 6ec079468f45429464b4ca19c9e3be6818de7e5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696871 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

gIz671O}>UZW$y%&%foGF!SP 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

  • {0a@i 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 z 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�J*pZh|;=dVswKRW?t~yOvQ|B$N=bH$XzG%t|);^ z?L){|>~Ca3SsMVyIWt|z;I4)Cq!o_V=G= z26W_njW9UMP$Kq8p`YQkJs$iSe}_%Zv1g(QZGyc4@!mk`s0K~N0_>|8$Y0Jc|8M4Y zY0D>M4Ineq<2NMpYaZ?N;~vA?Lo^DFg+*Nhe_>3sCF&-O?E4%f+dUQdA9SCpyqS|! zA3Cc6jB0`DQ1@!RQ>T*tA75v(ttys9(Z0Vz1F4~Dg@_1vP?RPPU?x zIr7EGh zp+8e99OE`L@wRz(Hn_lP)+A;3E5EbtuQuGCUp^wAwLfn9vkRGY+f`@H9KC@{9&5_hhfo}6V`p{ztgg(4u`Be zx^urXPT)@`*jfli%)aLHzMjAed!Zgb;N~|ZJ=(>^GJU8o@^YazzbHeC-)MF7QBc@F zWAfhu4@8zlN5v_-jBTqX6+mwfX6V020_g1adx8BtIYzJO0YNQunNJ49TxB z#wMEpCGv4MdbL*~*;(!#m=!~nESpFRj&Em|3wP!2IZq+Dlt-(14)^i3eV)DR%?;nk zM=$g(Y_j39w{iNohX@7bmLPSn*_kr#FoE0rExz7K6xA-lmZ=3<*UCK6na;|t^|m|5 zy#NU;_Di1J8!0~1qb%0*ym6kc{hjd=_E8AGoTw}N;HR`cj|Z4e@~uB4S*cb%KQ7~)h?vLX;l;iJm-NE&E#wr*y<)m0xqyEtD4_3@-yL*w*VYsxW0g}8YR?ND%G2cDvYK|0L}iEo^XVtuzXKW&V)tR@$^#mXe^U1= zA12r7IAu4E0C#A6*YFMWKasJ6zl9iU3xJnLxQ#5~^ShyUe=@2_#lZKIL|@(7L~zLs zcP^WL3!^%_NPHYGiFFQfa{0{iHT;GWee$Tc?t7I3M69ximW;1T~mP? zkA(fhzt!l6e#7J(;WF<4s=xbe!am$lP5xrs_c0K|X}S@;y$@YDwXZ7GCRRHwS0bH! z00r=S7e7ZM{lE)(AEsLw(wT#VfZCbiCi2sAHu*-|L%ohmBENb zlEKZq4zqjPW8~orh}RyK2mzb<`~7-+!uKe=&J80ACoBgaHzFbH5qxmd($zuB!**V` z>NnU?)9HeFw=2b7{q&RDcmnslMHWp_jIvuVIKg@oa}eog)Sd#>Mp9p=>o3?o2?@+5 zp{|7!gc{fdk-04~p0VOtJv@=)Xy`ju4mhGU<)dtFxRkMT9)#GBdbD!Y&|tzaZ9`so zUES&&BBPXq3+^XR?-aE?kathI$`|?m4pJ&0INIcN-(sI9`Wk(@t#E&{dwnbWw_gOW z+AC(7?7T^1qs+A{YL-y6eK=#P=v>D5RqQV(pd}(u&yHo1j0g)R-@LkwA3v&#$NB5N zwDYIC;+6Yd!!~HT3oN9;LwV^j_LswVVK+59HH423-%)@N(K@%RY z=69d_oAqU|MEmnlZdK`7v+Ytlxzwm=OX3rk)^U;S^SAVQh}9;tI&nhSrkHpfrBAgd zxnA+@Ln--8mmL<0PZjG#)6{{YgdoRr4l$8~>XX*((eSzW92xTJ{=$;Qce90(?sV9x z$1lo}#SHcfVA~FoCVO{(KV=7q%V~l`?!%2QwscLFN6bo;{G5QbbZPr_kx4sR?Z?O) z$wt*h?qn$1g_jG_KX@M(p-^hOo)8btD^0klRgMSRe*S8E%?;&PWp2Sp5FDX>u2hP- z!yKkpwN8Z?(G_Xm?H&kwcSL^vF6Ap)pNYHPw!D)W%xiV(L49I44sLgS6{&r;o*MNJ zvAYzdq-VLBtk?sSp>B%F#*=>ZWs8J|%|Y+}qvyih5hRKspMf^yN<&Zdtj~z=I0<2- zuC%vH44t>t$-7_eu!t_7KK}y<-hSnIbI);G)ECrJ)j}m+BPx?_+OdXvi{p<0B+jE= z6Y>3*r};K}lm<0z(!=N53eUxvdH0|5;@Gx)jAXdjb%+PFb#cER(@!w=yOhmE#s$vS z7Ro`@u{sXlEI#ZM#1ao(t}b}-Y$00Q>D~PB`A2qJDWP~=;`deBu)?v7gOk|UT@kZu zzK?BvAJgCFk8`r_a38@m=DQCxc9fNE9Wv_a+J-7QHtFkZY{3U|&Wn+p?WcDH7$}XT z91h8h=yqxdB_|%bhwJnwfEknAafFMY5EMX%-nd zfD6*JUoDKER9R%SH5BxQDPc0|$9t$-p5t}1`!iW5%;8LqI*60V&21-DY@i3u_WwQu_jp@k!l+ zTkGSiIocOov{4M$JkzAOzGo@I?mB>=?ioE;g>J!J>DaSke!$aPWd<9gGEDEG9oy3- z(bbQp#4mcKFZ426O_|W~Dtp1^zSFK+`u4p@qxzjAO)WyB*!V-;u`WySxb5iu*!MU6 z)A3iqI!mq6RC1N;548E-@m~LpK#x1RwNrqNUXdo&_T=evke^@u8GPm{#&Z3l>-lcE z$Z%kbCSHKeSCp%2Y6K^3 zQjQhwad^XjpMChg@dNkFuh+w!!CcneZ}k8af32$D_0Z_Ecf85y!G1qSzdOt`rR=+GoTK}#-bb3 zokX2pb>|}{8}7#&P9;F8ch)5e>UcQNP|Gpz_}Cc6)hv`45CMI&is$W>`*E zvZ$_l3O^6Ep!DBqZ&~yn($JR?QMALmOtDBZ^1_e>kncLb{(uv6IV23uIi@DhzL1tY zcx(guR($WxDn~D=>KwcWACQ6@U%P@&qsF7fZieZ>I``F_F&*dmS<)9^Z$CJn?Q^S= z11mvx19E}ReB1{rh~Bu>*@ol`2kg5m6wrYSd_et2p@%uX{sEKp4ycW;+{7=aWzNJx zZDcRiegpA{sK)8{+Kxf?Kml)ApW!Hv1KxX?a;+m>2M`<_?b@9wsZ+=9KJ~K{x-ouA zc?H*UZ4W)YIkE*lJ(Lnov~#%L?ZaDi#4_#&USt;MB1)&h3HI+omLqTp)V*(l|5RL5nPaJ074M2-mqo^ zdC7d_?`a=K;B#JQeJz%=*`Dm3T&|+9i8VV1SpH~WLa056Kawf;WT7Tgbd`<9(xR{OzYfe zoKB^zj?dFTZu{-alEYt=jj$-4O2WP8PZzKHVGxcOWzmvC31>ahFbGjVxT893pH=qqhzk$>`?7YA~0LY%X{hVN*BO_ka^2SaX z7YWXz>>-|wnC`t6s$Bg7{&!+{kH_B8TodtFdu#46FO{83uv+$0yboSyDm<@4b$*26 zIBy^;c4>k+lE-KhDip9mA?ode8PwEyrke95ha8q+Y-fAQZ0?1g9vDwaeQW8Nj#UR< zDTJGoZM5Q}(%x1LPo(bsL>~SvUEWxD(Laqc4!URY?)nmVuhv0b-xZ!H9pa;LRo=uL z@@Gl1<+~BDuL%u9cRaGs!Tn7pWjjS{ zi9c%w@s+9lr~AMSc8|Sfd{Ku>%&%nuBnq}`^y?L2ptb2f$mV~N+dxU-fqSgEJ&2Hp zA)D$Ka3{cQ@q;PY;6s z(ak=rp4`YUB&4^R%z(NNi(BrsvjZ{6!5K(u%35ZS`+%%oTl?-$CiCr4jzgKn-#l-< ziHNWL0NivaIiGkRWhH|o3`4-PfSpc@R8vn~{6S@}Bt2*LT2FDzB@5kdj|;GkEr;Cv zz^!c#MVvsY{&PD}i$*6g*lGbnJ|BI}cPk}U74l;k)O>~DD?ifl1U`7hNPDJOT~l9B z43i*=(mC_-zzk_a+|LJ`tyaJ5o-${sd+W6WA$pxYtqf9ksoXlP;6?-pWD$pXZEF^u!>Ri`P&)WJ1rB!i=;zdwDQaO^eh-vk8Yc>9a@G1iklo*@zevNh z=RT1Nm#*8L?)`9h+fO($mkB~0V1&O3$GbhTlM4?gUfF6B9jUW+RA$SX3pA*l=ON-i z`rI6NVoyo{9N1SH@aaB%mrXmd*NZiN*f(weYy>3g-JXQ$o#}tj(WO-dgL(6MuR%ud z0r!2@mxoo~Id8)Q^Fs5XaRUa|+cwd*!h%=U{WZQvC&!`ZYf!$JYk!sp`tj`6c%{~b zMl}DL-?X95DJ8l7ewCo<+h7x@%jtP>jyeb(N3n7x71Idx;H=-xeoqclYDjlmB34n` z+warSK#rZ2+dLoB;8zL*jK%%8pPx>`AwODgJCb6K^6+?#s(jvi-ckh9U3Q?c+}*lz zK2RBTYuD3F3Ir`3`h3?feD$i|U-h}&Y0XhS*=mkWphIlJNtya(kqh%K9V(UMpWaxi zyiMhzg(phWF8~O*eVYvQ?u-ks<3YX~l<%;5(jL0)Nvooeep(8YvNkd_>JO|lj(wQL z?@nQ;3;!VWIL1)f?${3*-OJB+Z+^x+KY{@K+U;HH7Y%7ZQVa3i-y&T)xhzL}3i4Jq zX#x%}#`x!OWuq*-pilFb!Y~OO@mFf5+y`xaKBfa%yZyHF_dXc1e0x>;u{xv($W|^m zWbyOG!J9Lqnj>YhdB-Ce-KnH=Xu%VI_((np?g)e5)^2}gu+Y=x<6WFvgiPD{wfjB3 z;~t|`y+1A0B!oj?Vg~ckr{Q;{F)v4%innI%Rfvm24M)Cx86bAV1`&xA%(=u=L;pd>Y;DV8_$e3Y!zC36~0F|Co2#W4`&DV^bgm0y`Ym#a7j(bQ89!hCD( z+vefB_f9(M4U<7enLd<<3l@?;SAk7%^E`j$<@D_i$z|1rjt&RAOe1Yq3R!ceW`EZMt>6-?H<&oQ zorQWuoN&1wX(t4)B^bV^BbT(#NRI3rYKY5{U3>9fG#Ng$Jbccth=_5ioHGxoJ-WES zvO`wK#=S8_Xe z_98yInvSuH^r8q1G@q|BTI7KVv&>8Eg9kmtD6r-fly8aS`{8vXIc+t3)ygt0Z+yl0 zCgqobxPv$GH0~0h$(>purF{XP9%k(4>hV?p%9?$9A10^y3ut@NaKBX@j1wE6+NJe) z8H^j)ete_fG#R~&U~g5+dH?0h?-nzlZ(mwMDH?aL%iQ#HV;;dWH$w1)M*|V`<#&a< ziYhkpYxR~r!O-p*b+dKdJM2^`xCVS2COG{O2zM=V3*@fJp13Yfm(_aClsIsY-D@&@ zX4Hz`iVgR#3cZaW!{sFOJ0gC0pUUMXW4xZo3y?bnQoy6DiZ4m5MW}f1Xj1G_6h_0J z*c>xk{wn6(fRRWGaytN4JleRyNvH6nE$fr)*}jpFfw}tbR=j|TOg_V26p902sOObO zoPHY@C;x)VDC{MPlojt+%=z!y91w51b?y zm=@6d7=`M2Yewd+)J2h(+p0c|tE1Y~?^q+Bj{SVP-MAlAJ&i8i|Gpfq%;Ni2d=_YY zoloD*?|hSjxuJ`5|=Mxq@EYkqM`DV_Zlf-6nEHLwL=-df7qZjL&;j2Y@;K79+! z<}IDL*gburmGv3}D_X}VZ@>@`htqaMmMcS$jMt-2ESI}i?4OuVC|aNTI9$6kUMRYE zfBt$4J{$_8kN(O>f~}dB^Vl8)VSR};CX(}gzk0P+?t(1Q0l2t=JPgYhFu=-T5%7bG zpQZKVH|kr)w9-3<5sr8F2U1OV`2Pqo!ZV4_sB?ZPmk4_aLUsy9Qo=lvu}L@{9of4a zuaKf+^nF$bs-fa><61UmGvni)>FV)q-HJz#Szn{Q85Sg<&?%bRUkjGn8T{??t16kA z=F=zq*==|EX2166asA|s?qO`OC3d=F|FL13yhjIbsBcDUf1bFNa$9{^;rwRIQ#Ru|aOCbs>l7|ddmv(}XB#=ruZF4no4_5^{q92KfwJ0*v!zMs zRWE0BYbYK9)(cN){XTmjOV-}R6a^|)Da+w+^(E8S*VME$aGeeF`#SV%)4jH?(N!0y zLR>Q#C~PZK6W4`En{NQ3nLFjWUPTOGZebWSowMKHt1oqPKi~VhdyD#VbK%F+FVALI zZ??Rj$0l{i`ThX$CfEz6+G7NM<(2)Cxb08a)~(&(fVQexw);3Y*b|d>D+bg%r-tbw zN8N3pEAsd2HqseU{pvuykZPs`CN>Ic%+=^LcLC+uDVVd-H=@CQ}t z-~&cSL8WihZ@8U*#Q1Y|?eBx24-}$F*=sJM#>aTx%+Jp?c?O7#%055S&YMT-LTh&i zvM2W4F+BhbyTrF=n_1b8%?4Q;-iM!aeU;tmea(4{6=(VL!EwEV&*Vv1QwNe zI4mt{A1~odeWOI+5`*>9Xxb{hV~W8{P|)ms3yw=JiZW;wl350@eG|J_scKi4kG7G1 z4y5@|j;7co-R{LZE+*C?Uc(=(m2h^eFhniNS0=|`iNxoGo@QCz;o_1O@(dfB{2a^t ze7tOyn{%+2(`Ae2sU$r{1*^6T9Ez6viYEoLbL~JrejR-W+*OLUw13Lpr&C!+AKqs9 z@;+*{y0Eiy*!%XTfg2E`rGa~YuQ%cs<~f5*gYe4h$d8!)ReEaY9DZwq)^ELdWp(J# zRq!1A2#_^>RKxFj@ZZ(rnL+HH>GR!0^m6C1cb})ecDX@%oVCrkpLmF?ta~jnhu7mTrT?bNc9);_2krKJ zKYauOk@IZ!j?Jn~mDE&=M3rN_90Dfrr>+FJ3s&yNDekXoy_hv3E)mPhNk2Ln-n2XIKqth zjff3t-bN39=am%l4yEp|Es_LTW&$N7lt74IQ@qFIm?5tr)FfAsdY1Vb#j8N*fo^>q zrG;cNCh8@L*l0e<9R*1wv$ml{JsZagHE@DV&FoL$#B&w7B?Rf~Q!|-lW5cCGl#=zE z5;8xc#Y||VRABjjaZ67ebpkdVi9?cJYQ57;Ga+VaL=gF+>!V42s2( z0Gavt$w!Z2WWY(Nui1xr(<2#_L-2`pg_It*XevcBCl5Z&B_p*6%|?H%AelLL{5*-L z#`8nQtS&3I54Ves(NBtZ29YWE??^8G%8(pC3}gEd7!P;F1O)Jt=h<9B;^!$6n-;XB z%v8vz5i*2LbNn%DMDLAC9~p26FM~?&P31z7odNAK2Q=BRUb9rH7!?UCzNv-*u1_W& zKSi{OsgB`30jz`+)0b9Tlk9h8Gch2eOvAESo& zeo%2@^twlDJlbm{DFRis(OGg>hHX|&aXRDA;&mZ=@eFTt{zlC|HA8`jj5idm;KeRt z<}x&`v!P@fhKH{LwUVjeQfUX`1&r8nHcdy;0Te(O8G&W3ww87&5zPWdO-Mx5$@r-2 z_rvkyIie>_s>WfQ#cYlq)SP`rK^)!Kur%TtrW+|CNDrh+ayJvGuzz}d$dA%P+_v~k z;NwljW}A_#<`RQJ@1;wTT9&d~2PW&Q$|F?a{0G)lF zHlMDCvu?RvLz^J^oll?bXklraehg(61-`#IvzhK^G9^uZWe9v2mF<>%kU9b_3VFUn zwpqpI;B0RCuI_-*rqrw9vE<0AsSy$GQAq?F6Ryf;bOt~8yS zBzkmHM+>V0LVV=)`TmPA$KL@N-zn*cvDvyN^7*n)Ge9lKdkNSA&fuR}EB#ND;^IHqP)#B)=P6T5#AE&Xbtccj@gKhS1T@x+6{6c)H&a4(<;LXyow>z>byA7+vHd`N zOnGFwTI{Gm6bWklmwa99fYQ&2QI9H(Z*6W;50>ez=3}w3fUl6m{seS!CV{w`*@j3B zZ~tBQ8T#4M%lxau1NPk#QpHMV4TDV52X84IKlKhTvQ_+hbv|?r8f}je7y%wF@z#zk z%ZQG-xwWC>SZl}ku?a0bL=_1?9toqzkF}fz#1uO+$MeKrI+0=VI8%ASxZ zd_NK9j*>_`YUvF*1dX%(WWYNg7vjhhJ(CP%hD|Wu2P0iYZAze)drZfAK_Q^mS<&Q2 zM^CvMjVVw|Y4Y{DS7(8gPFp4+ zn&fHr-E#hMU&5Ok-3dL|T&=RAuG-q#n{qsd{#gPgNhoka!dE)5i$`8Q*c*GH@Hczd zS1AnMVT$t*ONaz`q`?m#<2|X1qmRC)iRIIei8hVtnb;RPcusAd(CFqKhCwVCN&6tm{ zxyL&!)GB-zqT_iswR5;O_6ZO1)r@FBB?pTTcMP!*sehb^F>4)8H{Sq%)WjN8Bt)AF zQFG2_HR()M6t4&^yTU6-ad0>btv;1(iS+uE6-7pWNVO0C{OE@SwF+OL2qAx?&qC|! zYYZswXUrf{tv90|twe=xVdl<$H6V75_Qn;w|Am=7RCE}+tv!PIjEO`40;}VwD55kJ zsEI$VJ)b^n^<|Xum%@+}0l>m$jCHYIx%qD0PG~S$!?+;K#ogj7w8u7AIrE zwD??Q8t&eBnMBJ#vQpdai8}XBohN1IYfX~I;m0Y38RMrYZw$Nm1@g_KzomK!@cpDj zz~C#AI`Z!Wu?z3`Mh;urt&i|i(tT?YC|UxYb2`AyRHdU=Ajmj4J6nV&CG(B=V9FK2&mC1BOOakh>aim0#1HxEr z)XkZl7Za{xplqg<2=vjl5^5H?vynl(RTFRV6rVG)WE|FFZ|F#%>q*Y*N+!xFyGe3x zvNTPwu}CrN1|iVT*pu}WY(<7KZxU_JIC^{P`hBi8IG3VfaNPr~8EM1^VL?ABlD7}i znUZbajYje-Zk#kkE>0~Qa=dD$K;VE|lK{IO&;*1t2fDx+=lPiFCw_=}L1MGaTx5Ke zT7vVLaF=zlLO%-fh?MZ0(b6x|33)^LPdv~Xn(jD{mdeJU`rgE!BK}w#f^>U7A%%V+ z4A!s39U|Ek);|d<6+g+Sd<|#i2~hw9El0m+Hb>e0(#hk}>Vp{x{t_(YM($jpDu+ffd`X$$&7 zeFAM2E+>ODTW9 zNPEc^d5p60**JKJV=vJ#Fa?+?~ka4^*&xX!2iVDs>_IcDiplpcAEs{hk zA&A6s9t(51GN%YfCX%6ezFn0RQu01}9r4!IyW>akjA*Fu#vq8~w3D_N6$mK^>IT4L z(yl5ul_K#j*`vpgCNLUmwuf^iHhcv6G+iOZYt~ni7u8kQs0`6^mMa(=xvR=N)c~Uuc zA5T7Si4rpL!yPDuFdHtZbn~rtq?(5Tp;Yuv@a8L} zbnkxrdy{S7*n(Hc8{#64b7czIMK1L{Jg{`|Baz|5zrc}Rxnd%%q7GXa`%aq+oX3!VdJalpa*1{=sy@y#zu zOCV!{V%Rm?+}tw@+dipcf6FzH>7Z)6mwc#af^fdq2EE}r!DBAut{S`Ixni0py$S3L z2M5SshTC#IU*>g8bKP1p`j8nMF5%cNM7W^SubTkk+W~*oRtS1UjmcVZo3C{CnNHb< z-;=kOIfet>e;%I$(Hz5rLkAHA&kw(#FpD3?xVGQ@JRkf?)HtdCl`VUlUxcbmnFU$)x++uW+i&)}Ijo(suus@TmOkY54Y=rfAop56_eOF4E zNFb%n%u?LXcO8XUuI4MMxi5(ZEQxzKG=xkPp;M%$^^TPGKXSt2w}fmZao~(6D+-TG z@p}gWa(x*Y1cQc$7uc(C!?O*_$))T;0~+GvXzul5gS_*g8%o2*!HAw7g}DB z1|bns7R|WIyurO3$EGl*-_6-urkgPaN_0d(u?i3P+-At`;nfyMiGxe7QLWHguahM1 zkD63YBtssti*MyF^j=Dh6MAheBRdEE##zjW&pt#W^FO&Zv9upv$8;Kfn!ZWZnIvbT zL%XQL=GEkTRBUfJ4L?(yda6~&zfB5Dc?cK9fSU5ANq>9##E_DXsR+T1pYnXtYab`m z0N4Lr_TvMFHiy+2?cXr&$T94t?{ec`yhuW3A$`babvNn>GpySN8|Hh0np1c3N5-lA zN%vbCSv@A9x{nb+t}QS%Jx;HMJwCB*{ARe#pJg3{mG7-+CDZyGy|+fWJ&NZ?%(4ij z&ZzudiG;}>Y}x<|)o|dCThmtHgk+w`EZ9oIIeOyj?2(_o7Z_-fbdUg#4t_o6nLT7e z?WPCvD>IskFyUM4%y9N&`%Vs%Yg0C%tl69C9(hb)qj&ppnSk@uM0l>?MNj9Hf$(M) zxF9lYD6F^RM#50fjU++Gn}Me?4*JEjn8^u?@Ss6zmFb`qk}$c&p(<>1*UKF13Guib zaD&^D;!6ByrWx>>|X7Ixx4ambjjFxOsYOP%i1G zpMml}Td8*0Uu@&?gp17qccm=Qu)1!}JtzjMEz)AZ-cKScsiV_zVrV2QP5JYgR_Mc0 zTcqku4T^*(gFd&Ew5oh-XKt>v zNz)PW6`&)lG6@=bOngaQNPE4_@Z5%8w~@CQTlr+JM4|g4O{`Y2-&m}T(RRd|f2^73 z-YvT~rpALs17vVAc*fCm=mO*d}S z-G#?o1gn?R1xYfKXliE56VMGmut+-oAQ%EFQzB53OS2519gOkMdks5l6>i2sAy(4q z?31;8{p%)U{FReNfvoU<_?cM-7y@zl8=ptRn@xOBrc@dfkRcgG{!E7C zm#svKU(DCdk*^7Cq6qVI!}CG1N1wcs_&Ee?6_661n@3y~laa^OswJD6q>?gY3OJ@P zhs;QBB!mFe0B^)Nr6z^qJLcRb{Rm2ToLUFrf!V#L%(H+zkkn2^k=8#rF@C4cTnHf3 zW&PqjJ*^|8!+KMHL_!=gB~UFSCuh*C72evE!g`+pkG=UPEoSC4tV|OEAEIp`6Hy(1NZIO1Oeeu>j$$kQ<=-k$F3uf8%@Es zih|**1~c?$V?p~&KEj8_#VVlI4`?K2F=!+=gk$tINBkg)1$i`XCYmC>#kQ}ApoxBu z8TWv#-qa6uh}-{htyS;%H2lu8Yoz6Oj{hrap4F*$%+>At8r+!R17N{+>B|p!R@GZ4 z6WfWGu~63X@iqk;4T_qdSk^_7ChMgKHpPFgSnEErA7vORB(&$*4gimm&{js8$7s>{ zSUV^Gmdu%b_*9{x zi_bRlZCdJ@$aa2XLAqLvLjR0*G||QP;<{>n@2QCQQa*l}sjvKH(-XtIHcOQHnHvo7 zkQ(W=nY#WuU*jWeIV};}XWU(j$S;*kOF!dc5HJw09-bfLM6^(T75Xlg1x&vYW=%_! z{UPl1AgN`hHoh;u@IT2UrFCSyE>g$+Ttj*`L0OjDIJjZ=@#T4z=&&>-h(OeFH?ep^ zY2}UfQLwL19y%c=oLm8M_w|@|S5%NmP9V=3uQ%Fm2cPNk#?}OyPRG^>#J%7mURnxg z$w@!bn+BKE)uAc!5wtn;E5bE<9_rmVB;8z`FdBKNSK_1@$!S>%<{9R`t)4v zGPCAIVP0J6l~qL{?1%QhIk&L1yX65jP>m@{a2H>A!x_1fRDLm zZizLz@{4#_IM=w-C@poMj+H)79^~sI+GHja)QjL}L4eOakOOYaLBbjQ4p^gl0swL@ zB^`xUIQaI10RORVgCuO5{UV(p9knNY_$GA;0nrnS`~6WpYQMNYcif5}$+n!T~(aXu5p zTu)yl2@|aza-JglWcICq2i7zBlq{CKP(ox=2=-j9WQAmbUxe)F zM~@pQVi*I>3glC*hKT8XT8`Ac{^&-jzA>MYt0zfEu9xxlbfwPZ!Muq)RX^f&bd`6= zEuh1J{&TS z6Kpw`A8e_v>#u~CijppA+HR9C>9ht( z?S#sLkTwr=huVHHn54cg*QvNC*}n8+%Z@0J>mqSe|+|J~k9vx3&)QUPz zR)dv8v?6-{`%qQZoO}!E`z2Cs2f~RK#j!)QeNnLFHl6SK{evci4Ja0gauDS@U4G&b zHy8<1mp6AuVn=KsRCc4c!=3r0E?^72j2*AE3H3=bZKa79&(6MBY1YU04^US7P$AIfs?+Kf|%FNR-WROJWevkKTqxy((3H*T5xyhZff-7|^8G$mb+PwZT$ zTs>_(jCO9x_&xgpKLL4@+=HBXdQEeJXXbL_FK6j^km}XcBSq~TRuQM;*{YXR4^(9N zL?62WO`*SdHE^2~c)fB4)W2*94_mP<_PlL>2kIzNLq&Xk#6&zxrH%QV{}~NHnOSs6 z1?BJUin&*S0Qa8AA70BEvc`hi4Xvc-tXx?KUsqtZKQmY_`@XN*y5wC zdp`FSiMbMd92E($@$&eVDSKzhtb}_6Ot+!$11xDC(n`rA~+{)*9-r1cl?!?aMPT;46t zGh4*B69IDBPjk)=m7Sf0@2ldVbO%_<^)DsPm^I`SMq@eZmMj20jW*+V&$gUNv=sgA z=I>{vZ|=VR1&PnK)2btWnGP`|ZzP01K|q-=%i8W;O@OBMZAcx*nz zaGaF{QN-AB_#=qRhBN}+3#i!fi8|O4a7|JCZC7kG9F;m02bf>25lsrTD{QDWNw_aDVUZ=XQ?a_ackuDyt?@r&XYU#81*{N#9*fEQXiN?fPk z%lpb@AQN#(MSZ@U6}saRxemI4o1WGl30!5vul#GkewtU)9&;4GuQC$cS=!+f_4{$& zV}2%W{*$vbu_miv)Z+gK%jx2fZC;WBmdUSVm5sL$_WSYil75^cD> z;mI?#$PUXjs?c*^t8G~Dztcqs8ztXDaYPo-`Yk7P{9avz&qwf-Cwtg(+*p6i*PWFN zkcUc^LZl#9*lwcj{dPQ02j7v;_JBW6z}whN3i=L`Xi6cEIbwVZI0-JoVKOU@ozEzKOhmWz?)mpC zQ~DyiM`?c&-dTW)*}5d$iWf!`4Pk=A$!-ICrW^c#_k`Q##>uijJ|d4tt}n~FDo#nWDFS@Aa1!X7`K_+r3OSTflKbyH_3*a$NUKdgVUilYvb6`C z0_tLYm#rbeBvNd|&p~BeN%$gg|8SvMdq%I=$*j=}>zD~}{byHq-imlE^oohw8!v}w zMR4Yoo7w&`T746EsK?boBW+wsl%p@zm@rgS^YL_C^rX3Uw&gn|=^jL*cVA#SH-`?| zD~Z#^GYEXk@r5vXa=Y~IW6wXQ0|x`K@r7+`q~WxMDWsX3S{xEEcANfS4w}uxF7-l& ziMfN}>b;LJg?2%FV3#OqU*Z!uBS$BGh#10#NG_V9ZB|ZUZ2t0ugw1GrOH+vF`-2S8 z_Z`h20L;t+5t)<>cKM4XMQhLB?%d<@-LA{6ZJ5c^Q}vlHp${9}w4sirc6+q*O*h(s z&CM~Xz9;o}M49l=joln24^_JFQOG2Yntrl`r!Jr3(yX)BH1A8xGOy$Uru$A65fmTV zmQNpfuJ2RpL3-{8NKTPNxi^n;H+}4pUl?yFmC#8rS0#IS8VB7NZwe6Z+^3E?*`;NPj1iu&etztUCX?!*A?6pVp( z>aKH>1SRjlR6Dj+|-gGE9kd-!Bp`A)kcQX~fhWM^_y zN~1#Oc#eYi`o^`%^6c~%ev2&!3FQ`3CtA+>K&%({HSXIzyq!}u>C6V5S%Y-$*28GM zSDqrW=&;WR3g-SQ=TJoSUAn;Zd{iC>Wextv*LiHYYHd-puV0}d1PD-*97WDO5Qrp_ zK%}qtE`Pvn+QWXnuS$Y*_FijF7-9*sHx?O+mtJ}TSZ?35c1+(!UgzQEI~zCWH*p>9 z`?+RAQ;0tr5Ry!z-|hyPlcujmb1=y*BuYb_4_Ie31KZQKg#CkgA&l)A{_ynGGlK|C z252I?aK#>gn5N79V6Ze4npR`>Tvr9B4?kd1T~)*0j10HZx1KVyAs|BEs<{t`lSK{> zyCZEY2b9e6n-jIqZLSP#_=vct{Ywsj+oYdb>sQM}smO+8mc0U`!35zkB9EK18=bSe zGbk${eF~9MXgmhO#RS9@(=D%iecRQv$Bi5O1+Wrgv)^xZi zbNci3WatwP*S?)Y8&QLEhTnkB58ww*+T6RK0+uHRI5vcxoj#pdIDoV?NREP6JotQ2 z6CXjf@Di6DFsPZs;5VIL)|gSiC2vk&gDKBz!X;8bu^pv7FMJ;p)n>g$06W=OZ|cj?BcJ;!6^I`qQogyW!Lp4z#n zkJ|Zoj4zNtv`|5C9h!lCnxm$|D=3PG`XlBdKcEf+@|=Y}A@>H7CQzy~=_&95bfVJ4 zWfTdPiDj@u>W}lq=-VCM(|%2KK;@2MJotG4b22;JbPMK45NWw)f5X`A{a$+#7D@$$ z74Iw3UoWsL0>pXM_c!D@h#wqLS8o&h*WSW%!|X*jDGA{`L``ocry8ARux$xD`AQPFu%&5io1%7{t%Y*;-cJ8+*zm3G{F@1M>=)qF6m|IK%Yl3J_o8l z6&FEma9Ly_E&l!{0|Etf*(3m5zXylsj4Ohl8yK$&h|JhA&`5U)JRew7sz+U%FF-i{ z|9}4lfwE+iNb`wZyum_U$LvdM8o>Nkz4KG5U(hrvo@lBfDEv!=hh-?_J>U*Zd5nBN zo(^iziDfk#TxZ{+7t7%E<37yALV)@g06pU708W0bUNHN{P2{kOv}Y``L_p_Bm+vdZ zb)|J~5sVn%Dtkkjm9etao?%=BfV8|v0bO#rWAHY6=QSuU!s=8%k*+P#!@#g7QECMY@Q+y@_n+Wq+AqO zjlFTuhL2nZup3X)zlEDtTv{k-qzTWv=d?oxzsYZG!?%UgM>nwS&%1u!c5c=-Dx=w> z;tv&hJ}+Y|!=EEQ4&anli!Nwk#RICoCrXTZofIQ0gY&NR$yW!0k6uthFvdeL{{F=9 zWbzsjI4S273UM#fMkT>yo``NQpuO1X2yekPj==F{8 zH;9fy3j?BHuo#D|;O_w?6Kg}hCNv-(kK$^OP!T~dSykT#R^ghaP&jymv+>4N=oacd%nJa3+PCw zIG~ps8)ippGzNDIKx*58C;xB^e^2A_O7v57BWe5!k~df`zUCaIwHy(aFT z&fhtB$lgUg5uxz8v_f0@{C3&5`0Dqi1P7imAz9ZSOX$8?p*X}Wf197AheGh&UNap=J+AmBW>hVaMElt7o#93X1jlMJ zj8)q+>1aLm^^BBq3o(Y|&QydS6h^XNn01~)%$e`oWk?7Gxeb1?RQE`ow)I1Xa4VY< zV0?*SEV!{-5RyTfhH%Q42ld&A?$#zO?JDZJs{II%g@CTY8?{q4GhjdQgFc<-&)UDL!X3DUNgbsuB^W6LfCMA`5Rfz9Vb z*^~y#TK)9nDAj}u9=VNU?P-wQn+0D4*LY6^L~`!YQRKh}_U%dDfLM%g1vuJS>Butx zk}o$b0Ha0yh3V-p7V?Qvx30O=I5Yae5^NH*Qa^Zw-LJIxvzs4kyOV4r4eif(Uvm>c z2}N2SHDLnmpbLrq`uq?-ZZ5tpW$;>EO72UK9y&~ zP3u-&T!l9PW-3{PP(`oI+CfNShA|c(IJDMh{K?l1XxTG+1qsjkkc#veHcIIRz!dFg zWqF?Yoq6nhrQG}*8^zG&WTB|JMdT(kJW-4dXxT#n5HUFj#MJYQVNf=_{A(1>!L_t! zod$TIGo!76LN9>lC8#Y)EtUsV`8+>Ran>#|12EEn>kdxf;+^V6-@RGfbpNKLVQ4ji9o(h!&)AEH1&f;-K79|8QPY?) z_^aH5KHzx|k3^)oQ_6$CcycZxh}RiX+=G(js};bDs89zC19E@?cL;HwJMhk!T+{Wm zOAoAuhp0b+vHd=N?+}@Gpp3z)6uy@E+ZM z^D=+Ai^9l3iX9I(zuO)$F97U?Ayq)#>dc5Fe)+(6XQ9jQmqTrv=?`XPt6hLqqXb3_ zqH;@ST1QB0{8-^}X;WQ=;*0($RVN(YaniYD@?w;jK8Z2p>Ca{pVp{Cuxs+_9a^ib{ ze|L_`3F=a~J6(?$>`mX?oxAb!x?A}Mrx`Z##^eF%rRYpj)jwcEgRQvA z5Mali@+03hD005&k3vc}5Sk%Y9)W;*_a5d`sv+{aLU_u#;M%5p+bwzR&UmYmVHl?R zQmw4SQ`jx|hFE5iQe+fM_p_}hecW>N8U zy#cxCr}IBSs9btX?D;iS$`w5b$!(s!*g!nm6OO9wSeWw&;!6nXHwXH|5KFx|`VsczYuCFt+JT_!vFuL|4 zp8lOcP==nMJs_G00bTgzw%|W%8i~OM4K_fF0-~buT^XhfB*^ZiA`9t{SoPkEr9+K&~xp^8BXdiVdjZRdo$h36ln6-a+KY*$)hZRYo?LH^03sq z0Ov>l4f<5>Bfg|pBwNONhvOY=^7e~dx&6VwnF}!3!EJVCL(f9=s9)(ZcuZo@T&0Cs`cTVA&1C0w|t^qPKKTlEK>_ zV}I;RC2o+!ZvkxVIp6M{k0;-c6Pbdw;=v|p3R}_Gdc8xIK=ezQ%Gv&L6uMzXr-AIe zvT@H$u|H1~bur%Y3(|~rSHD|M%3;FTRoJqL{0hJ;h_+91M0@WL)>&On{w@UmKIowe zf40KoJn&Ot&Ukm~5zKqF7gXBRsUt^BVJzkusvfiU*@X|pDMF~$r>%TOy`@J0a)3F` zc`;`d80UnxEqtYZm_{T%)%C4hhaw(-j344V-hw7Up-k*2%akTJ%cif{tg0DZ=0o=W{wxR@$U80;P?Ntx55X-J8kw1W87grRsvRBw2ZuWd9t-E{y#ylzEF&F}0GiyNv z7M`p1g6_Y^eI2}&p)BeB7_+C$_;&Ysv3j=lXJR%RAc1f07xmUO+8gCZ

    |^sd4xo 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

    0y@7LnL_=N6-& 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 `u99`E*?&&UP(OgPZ4C2x_udQ1`YkNp5 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 KGBp4DqyG)P-15Z$ diff --git a/third_party/houdini/plugin/OP_gusd/SOP_usdbindproxy.otl b/third_party/houdini/plugin/OP_gusd/SOP_usdbindproxy.otl deleted file mode 100644 index 231d7181118b34fab78cc5322c64880fae8dbad5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21154 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 ONP4KPapfHs;ru^sf!fgk diff --git a/third_party/houdini/plugin/OP_gusd/SOP_usdimport.cpp b/third_party/houdini/plugin/OP_gusd/SOP_usdimport.cpp deleted file mode 100644 index 1eb00a5cd3..0000000000 --- a/third_party/houdini/plugin/OP_gusd/SOP_usdimport.cpp +++ /dev/null @@ -1,697 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "SOP_usdimport.h" - -#include "OP_Utils.h" - -#include "gusd/error.h" -#include "gusd/GU_USD.h" -#include "gusd/PRM_Shared.h" -#include "gusd/stageCache.h" -#include "gusd/stageEdit.h" -#include "gusd/USD_Traverse.h" -#include "gusd/USD_Utils.h" -#include "gusd/UT_Assert.h" -#include "gusd/UT_StaticInit.h" -#include "gusd/GT_PrimCache.h" -#include "gusd/USD_XformCache.h" -#include "gusd/USD_VisCache.h" - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; -using std::string; - -namespace { - -enum ErrorChoice { MISSINGFRAME_ERR, MISSINGFRAME_WARN }; - -#define _NOTRAVERSE_NAME "none" - - -int _TraversalChangedCB(void* data, int idx, fpreal64 t, - const PRM_Template* tmpl) -{ - auto& sop = *reinterpret_cast(data); - sop.UpdateTraversalParms(); - return 0; -} - - -void _ConcatTemplates(UT_Array& array, - const PRM_Template* templates) -{ - int count = PRM_Template::countTemplates(templates); - if(count > 0) { - exint idx = array.size(); - array.bumpSize(array.size() + count); - UTconvertArray(&array(idx), templates, count); - } -} - - -PRM_ChoiceList& _CreateTraversalMenu() -{ - static PRM_Name noTraverseName(_NOTRAVERSE_NAME, "No Traversal"); - - static UT_Array names; - names.append(noTraverseName); - - const auto& table = GusdUSD_TraverseTable::GetInstance(); - for(const auto& pair : table) - names.append(pair.second->GetName()); - - names.stdsort( - [](const PRM_Name& a, const PRM_Name& b) - { return UT_String(a.getLabel()) < UT_String(b.getLabel()); }); - names.append(PRM_Name()); - - static PRM_ChoiceList menu(PRM_CHOICELIST_SINGLE, &names(0)); - return menu; -} - -int -_onTreeView(void *data, int index, fpreal t, const PRM_Template *tplate) -{ - GusdSOP_usdimport* sop = static_cast(data); - UT_String path; - sop->getFullPath(path); - - const std::string statement = TfStringPrintf( - "hou.node('%s').setSelected(1)\n" - "treePane = hou.ui.curDesktop().createFloatingPaneTab(" - "hou.paneTabType.PythonPanel, (1200, 600), (800, 500))\n" - "treePane.setActiveInterface(hou.pypanel.interfaceByName('UsdImport'))\n", - path.c_str()); - - PYrunPythonStatements(statement.c_str()); - return 1; -} - -int -_onReload(void *data, int index, fpreal t, const PRM_Template *tplate) -{ - GusdSOP_usdimport* sop = static_cast(data); - sop->Reload(); - return 1; -} - -PRM_Template* _CreateTemplates() -{ - /* XXX: All names should be prefixed to ensure they don't - collide with the templates of the traversal plugins.*/ - - static PRM_Name className("import_class", "Class"); - static PRM_Name groupName("import_group", "Group"); - - static PRM_Name fileName("import_file", "USD File"); - static PRM_Name primPathName("import_primpath", "Prim Path"); - static PRM_SpareData primPathSpareData( - PRM_SpareArgs() - << PRM_SpareToken("fileprm", fileName.getToken()) - << PRM_SpareToken("primpathprm", primPathName.getToken()) - << PRM_SpareToken(PRM_SpareData::getEditorToken(), "1") - << PRM_SpareToken(PRM_SpareData::getEditorLinesRangeToken(), - "1-10")); - - static PRM_Name treeViewName( "treeview", "Tree View"); - - static PRM_Name reloadName( "reload", "Reload" ); - static PRM_Name timeName("import_time", "Time"); - static PRM_Default timeDef(0, "$RFSTART"); - - static PRM_Name traversalName("import_traversal", "Traversal"); - static PRM_Default traversalDef(0, "none" ); - - static PRM_Name deloldName("import_delold", "Delete Old Points/Prims"); - - static PRM_Name viewportlodName("viewportlod", "Display As"); - static PRM_Default viewportlodDefault(0, "full"); - - static PRM_Conditional disableWhenNotPrims("{ import_class != \"primitive\" }"); - - static PRM_Name purposeName("purpose", "Purpose"); - static PRM_Default purposeDefault(0, "proxy"); - static PRM_Name purposeChoices[] = { - PRM_Name("proxy", "proxy"), - PRM_Name("render", "render"), - PRM_Name("guide", "guide"), - PRM_Name(0) - }; - static PRM_ChoiceList purposeMenu(PRM_CHOICELIST_TOGGLE, purposeChoices ); - - static PRM_Name missingFrameName("missingframe", "Missing Frame"); - static PRM_Default missingFrameDefault(1, "warning"); - - static PRM_Name errorChoices[] = { - PRM_Name("error", "Report Error"), - PRM_Name("warning", "Report Warning"), - PRM_Name(0) - }; - - static PRM_ChoiceList errorMenu(PRM_CHOICELIST_SINGLE, - errorChoices); - - // These next 3 parameters are required by the DT_importUsd - // plugin, which uses these 3 hidden parameters to read/write - // to this OP_Node. - static PRM_Name parmNameUsdfile("_parmname_usdfile", - "_parmname_usdfile"); - static PRM_Name parmNamePrimpaths("_parmname_primpaths", - "_parmname_primpaths"); - static PRM_Name parmUiExpandState("_parm_uiexpandstate", - "_parm_uiexpandstate"); - static PRM_Default parmDefaultUsdfile(0, fileName.getToken()); - static PRM_Default parmDefaultPrimpaths(0, primPathName.getToken()); - static PRM_Default parmDefaultUiExpandState(0, ""); - - // Make the uiExpandState template here, so it can be - // configured to not cook this SOP when it changes. - PRM_Template uiExpandState(PRM_STRING | PRM_TYPE_INVISIBLE, 1, - &parmUiExpandState, &parmDefaultUiExpandState); - uiExpandState.setNoCook(true); - - GusdPRM_Shared shared; - - static PRM_Template templates[] = { - PRM_Template(PRM_STRING, 1, &groupName, /*default*/ 0), - PRM_Template(PRM_ORD, 1, &className, /*default*/ 0, - &PRMentityMenuPointsAndPrimitives), - PRM_Template(PRM_TOGGLE, 1, &deloldName, PRMoneDefaults), - PRM_Template(PRM_FILE, 1, &fileName, - /*default*/ 0, /*choicelist*/ 0, /*range*/ 0, - /*callback*/ 0, &shared->usdFileROData), - PRM_Template(PRM_CALLBACK, 1, &treeViewName, 0, 0, 0, &_onTreeView ), - PRM_Template(PRM_STRING, 1, &primPathName, - /*default*/ 0, &shared->multiPrimMenu, - /*range*/ 0, /*callback*/ 0, &primPathSpareData), - PRM_Template(PRM_CALLBACK, 1, &reloadName, 0, 0, 0, &_onReload ), - - PRM_Template(PRM_FLT, 1, &timeName, &timeDef), - PRM_Template(PRM_ORD, 1, &traversalName, - &traversalDef, &_CreateTraversalMenu(), - /*range*/ 0, _TraversalChangedCB), - PRM_Template(PRM_SEPARATOR), - PRM_Template(PRM_ORD, 1, &viewportlodName, - &viewportlodDefault, &PRMviewportLODMenu, - 0 /* range */, - 0 /* callback */, - 0 /* spare */, - 0 /* group */, - 0 /* help */, - &disableWhenNotPrims ), - PRM_Template(PRM_STRING, 1, - &purposeName, - &purposeDefault, - &purposeMenu ), - PRM_Template(PRM_ORD, 1, &missingFrameName, - &missingFrameDefault, &errorMenu ), - PRM_Template(PRM_STRING | PRM_TYPE_INVISIBLE, 1, - &parmNameUsdfile, &parmDefaultUsdfile), - PRM_Template(PRM_STRING | PRM_TYPE_INVISIBLE, 1, - &parmNamePrimpaths, &parmDefaultPrimpaths), - uiExpandState, - PRM_Template() - }; - - return templates; -} - - -auto _mainTemplates(GusdUT_StaticVal(_CreateTemplates)); - - -} /*namespace*/ - - -void -GusdSOP_usdimport::Register(OP_OperatorTable* table) -{ - OP_Operator* op = - new OP_Operator("pixar::usdimport", - "USD Import", - Create, - *_mainTemplates, - /* min inputs */ 0, - /* max inputs */ 1, - /* variables */ 0, - OP_FLAG_GENERATOR); - op->setIconName("pxh_gusdIcon.png"); - op->setOpTabSubMenuPath( "Pixar" ); - table->addOperator(op); - table->setOpFirstName( "pixar::usdimport", "usdimport" ); -} - - -OP_Node* -GusdSOP_usdimport::Create(OP_Network* net, const char* name, OP_Operator* op) -{ - return new GusdSOP_usdimport(net, name, op); -} - - -GusdSOP_usdimport::GusdSOP_usdimport( - OP_Network* net, const char* name, OP_Operator* op) - : SOP_Node(net, name, op), _group(NULL) -{} - - -bool -GusdSOP_usdimport::updateParmsFlags() -{ - bool haveInput = getInput(0); - - return enableParm("import_group", haveInput) + - enableParm("import_delold", haveInput) + - enableParm("import_file", !haveInput) + - enableParm("import_primpath", !haveInput); -} - - -void -GusdSOP_usdimport::UpdateTraversalParms() -{ - if(getIsChangingSpareParms()) - return; - - UT_String traversal; - evalString(traversal, "import_traversal", 0, 0); - - const auto& table = GusdUSD_TraverseTable::GetInstance(); - - const PRM_Template* customTemplates = NULL; - if(traversal != _NOTRAVERSE_NAME) { - if(const auto* type = table.Find(traversal)) - customTemplates = type->GetTemplates(); - } - - _templates.clear(); - const int nCustom = customTemplates ? - PRM_Template::countTemplates(customTemplates) : 0; - if(nCustom > 0) { - /* Build a template list that puts the main - templates in one tab, and the custom templates in another.*/ - static const int nMainTemplates = - PRM_Template::countTemplates(*_mainTemplates); - - _tabs[0] = PRM_Default(nMainTemplates, "Main"); - _tabs[1] = PRM_Default(nCustom, "Advanced"); - - static PRM_Name tabsName("import_tabs", ""); - - _templates.append(PRM_Template(PRM_SWITCHER, 2, &tabsName, _tabs)); - - _ConcatTemplates(_templates, *_mainTemplates); - _ConcatTemplates(_templates, customTemplates); - } - _templates.append(PRM_Template()); - - - /* Add the custom templates as spare parms.*/ - PI_EditScriptedParms parms(this, &_templates(0), /*spare*/ true, - /*skip-reserved*/ false, /*init links*/ false); - UT_String errs; - GusdUTverify_ptr(OPgetDirector())->changeNodeSpareParms(this, parms, errs); - - _AddTraversalParmDependencies(); -} - - -void -GusdSOP_usdimport::_AddTraversalParmDependencies() -{ - PRM_ParmList* parms = GusdUTverify_ptr(getParmList()); - for(int i = 0; i < parms->getEntries(); ++i) { - PRM_Parm* parm = GusdUTverify_ptr(parms->getParmPtr(i)); - if(parm->isSpareParm()) { - for(int j = 0; j < parm->getVectorSize(); ++j) - addExtraInput(parm->microNode(j)); - } - } -} - -void -GusdSOP_usdimport::Reload() -{ - UT_String file; - const fpreal t = CHgetEvalTime(); - evalString(file, "import_file", 0, t); - if(!file.isstring()) { - return; - } - - UT_StringSet paths; - paths.insert(file); - GusdOP_Utils::ReloadStagesAndClearCaches(paths); - forceRecook(); -} - -OP_ERROR -GusdSOP_usdimport::_Cook(OP_Context& ctx) -{ - fpreal t = ctx.getTime(); - - UT_String traversal; - evalString( traversal, "import_traversal", 0, t ); - - ErrorChoice errorMode = static_cast(evalInt("missingframe", 0, t )); - - UT_ErrorSeverity errorSev = - errorMode == MISSINGFRAME_WARN ? UT_ERROR_WARNING : UT_ERROR_ABORT; - - const GusdUSD_Traverse* trav = NULL; - if(traversal != _NOTRAVERSE_NAME) { - const auto& table = GusdUSD_TraverseTable::GetInstance(); - trav = table.FindTraversal(traversal); - - if(!trav) { - GUSD_ERR().Msg("Failed locating traversal '%s'", traversal.c_str()); - return error(); - } - } - return getInput(0) ? _ExpandPrims(ctx, trav, errorSev) - : _CreateNewPrims(ctx, trav, errorSev); -} - - -namespace { - - -GusdStageEdit* -_CreateEdit(const SdfPath& variantSelPath) -{ - if(!variantSelPath.IsEmpty()) { - GusdStageEdit* edit = new GusdStageEdit(); - edit->GetVariants().append(variantSelPath); - return edit; - } - return nullptr; -} - - -void -_GetStageEditsForVariants(const UT_Array& variants, - GusdDefaultArray& edits) -{ - if(variants.size() > 0) { - // Check if there are any variant selections, and if so, if they all match. - bool varying = false; - SdfPath firstVariant = variants(0); - for(exint i = 1; i < variants.size(); ++i) { - if(variants(i) != firstVariant) { - varying = true; - break; - } - } - - if(varying) { - edits.GetArray().setSize(variants.size()); - for(exint i = 0; i < variants.size(); ++i) { - edits.GetArray()(i).reset(_CreateEdit(variants(i))); - } - } else { - edits.Clear(); - edits.GetDefault().reset(_CreateEdit(firstVariant)); - } - } -} - - -} // namespace - - -OP_ERROR -GusdSOP_usdimport::_CreateNewPrims(OP_Context& ctx, - const GusdUSD_Traverse* traverse, - UT_ErrorSeverity sev) -{ - fpreal t = ctx.getTime(); - - UT_String file, primPath; - evalString(file, "import_file", 0, t); - evalString(primPath, "import_primpath", 0, t); - if(!file.isstring() || !primPath.isstring()) { - // Nothing to do. - return UT_ERROR_NONE; - } - - /* The prim path may be a list of prims. - Additionally, those prim paths may include variants - (eg., /some/model{variant=sel}/subscope ). - Including multiple variants may mean that we need to access - multiple stages. - - Resolve the actual set of prims and variants first.*/ - - UT_Array primPaths, variants; - if(!GusdUSD_Utils::GetPrimAndVariantPathsFromPathList( - primPath, primPaths, variants, sev)) - return error(); - - GusdDefaultArray filePaths; - filePaths.SetConstant(file); - - // Get stage edits applying any of our variants. - GusdDefaultArray edits; - _GetStageEditsForVariants(variants, edits); - - // Load the root prims. - UT_Array rootPrims; - { - rootPrims.setSize(primPaths.size()); - - GusdStageCacheReader cache; - if(!cache.GetPrims(filePaths, primPaths, edits, - rootPrims.data(), - GusdStageOpts::LoadAll(), sev)) - return error(); - } - - GusdDefaultArray times; - times.SetConstant(evalFloat("import_time", 0, t)); - - UT_String purpose; - evalString(purpose, "purpose", 0, t); - - GusdDefaultArray purposes; - purposes.SetConstant(GusdPurposeSet( - GusdPurposeSetFromMask(purpose)| - GUSD_PURPOSE_DEFAULT)); - - UT_Array prims; - if(traverse) { - // Before traversal, make a copy of the variants list. - const UT_Array variantsPreTraverse(variants); - - UT_Array primIndexPairs; - - UT_UniquePtr opts(traverse->CreateOpts()); - if(opts) { - if(!opts->Configure(*this, t)) - return error(); - } - - if(!traverse->FindPrims(rootPrims, times, purposes, primIndexPairs, - /*skip root*/ false, opts.get())) { - return error(); - } - - // Resize the prims and variants lists to match the size of - // primIndexPairs. - exint size = primIndexPairs.size(); - prims.setSize(size); - variants.setSize(size); - - // Now iterate through primIndexPairs to populate the prims - // and variants lists. - for (exint i = 0; i < size; i++) { - prims(i) = primIndexPairs(i).first; - exint index = primIndexPairs(i).second; - - variants(i) = index < variantsPreTraverse.size() ? - variantsPreTraverse(index) : SdfPath(); - } - - } else { - std::swap(prims, rootPrims); - } - - /* Have the resolved set of USD prims. - Now create prims or points on the detail.*/ - - bool packedPrims = !evalInt("import_class", 0, t); - if(packedPrims) { - UT_String vpLOD; - evalString(vpLOD, "viewportlod", 0, t); - - - GusdDefaultArray lods; - lods.SetConstant(vpLOD); - - GusdGU_USD::AppendPackedPrims(*gdp, prims, variants, - times, lods, purposes); - } else { - GusdGU_USD::AppendRefPoints(*gdp, prims, GUSD_PATH_ATTR, - GUSD_PRIMPATH_ATTR); - } - return error(); -} - -OP_ERROR -GusdSOP_usdimport::_ExpandPrims(OP_Context& ctx, - const GusdUSD_Traverse* traverse, - UT_ErrorSeverity sev) -{ - if(!traverse) - return UT_ERROR_NONE; // Nothing to do! - - fpreal t = ctx.getTime(); - - // Construt a range and bind prims. - bool packedPrims = !evalInt("import_class", 0, t); - GA_AttributeOwner owner = packedPrims ? - GA_ATTRIB_PRIMITIVE : GA_ATTRIB_POINT; - GA_Range rng(gdp->getIndexMap(owner), - UTverify_cast(_group)); - - UT_Array rootPrims; - GusdDefaultArray times; - GusdDefaultArray purposes; - { - GusdStageCacheReader cache; - if(!GusdGU_USD::BindPrims(cache, rootPrims, *gdp, rng, - /*variants*/ nullptr, - &purposes, ×, sev)) { - return error(); - } - } - if(!times.IsVarying()) - times.SetConstant(evalFloat("import_time", 0, t)); - - // Traverse to find a new prim selection. - UT_Array expandedPrims; - { - UT_UniquePtr opts(traverse->CreateOpts()); - if(opts) { - if(!opts->Configure(*this, t)) - return error(); - } - - if(!traverse->FindPrims(rootPrims, times, purposes, expandedPrims, - /*skip root*/ true, opts.get())) - return error(); - } - - GA_AttributeFilter filter(GA_AttributeFilter::selectPublic()); - GusdGU_USD::AppendExpandedRefPoints( - *gdp, *gdp, rng, expandedPrims, filter, - GUSD_PATH_ATTR, GUSD_PRIMPATH_ATTR); - - if(evalInt("import_delold", 0, t)) { - if(packedPrims) - gdp->destroyPrimitives(rng, /*and points*/ true); - else - gdp->destroyPoints(rng); // , GA_DESTROY_DEGENERATE); - } - return error(); -} - - -OP_ERROR -GusdSOP_usdimport::cookInputGroups(OP_Context& ctx, int alone) -{ - if(!getInput(0)) - return UT_ERROR_NONE; - - int groupIdx = getParmList()->getParmIndex("import_group"); - int classIdx = getParmList()->getParmIndex("import_class"); - bool packedPrims = !evalInt(classIdx, 0, ctx.getTime()); - - GA_GroupType groupType = packedPrims ? - GA_GROUP_PRIMITIVE : GA_GROUP_POINT; - - return cookInputAllGroups(ctx, _group, alone, - /* do selection*/ true, - groupIdx, classIdx, groupType); -} - - -OP_ERROR -GusdSOP_usdimport::cookMySop(OP_Context& ctx) -{ - OP_AutoLockInputs lock(this); - if(lock.lock(ctx) >= UT_ERROR_ABORT) - return error(); - - // Local var support. - setCurGdh(0, myGdpHandle); - setupLocalVars(); - - if(getInput(0)) - duplicateSource(0, ctx); - else - gdp->clearAndDestroy(); - - /* Extra inputs have to be re-added on each cook.*/ - _AddTraversalParmDependencies(); - - if(cookInputGroups(ctx, 0) < UT_ERROR_ABORT) - _Cook(ctx); - - resetLocalVarRefs(); - - return error(); -} - - -void -GusdSOP_usdimport::finishedLoadingNetwork(bool isChildCall) -{ - SOP_Node::finishedLoadingNetwork(isChildCall); - - if(isChildCall) { - /* Update our traversal parms. - Needs to happen post-loading since loading could - have changed the traversal mode.*/ - UpdateTraversalParms(); - } -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/third_party/houdini/plugin/OP_gusd/SOP_usdimport.h b/third_party/houdini/plugin/OP_gusd/SOP_usdimport.h deleted file mode 100644 index 704c28a1f0..0000000000 --- a/third_party/houdini/plugin/OP_gusd/SOP_usdimport.h +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef OP_GUSD_SOP_USDIMPORT_H -#define OP_GUSD_SOP_USDIMPORT_H - -#include -#include - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdUSD_Traverse; - - -class GusdSOP_usdimport : public SOP_Node -{ -public: - static OP_Node* Create(OP_Network* net, - const char* name, - OP_Operator* op); - - void UpdateTraversalParms(); - - void Reload(); - -protected: - GusdSOP_usdimport(OP_Network* net, const char* name, OP_Operator* op); - - virtual ~GusdSOP_usdimport() {} - - virtual bool updateParmsFlags(); - - virtual OP_ERROR cookMySop(OP_Context& ctx); - - virtual OP_ERROR cookInputGroups(OP_Context& ctx, int alone); - - OP_ERROR _Cook(OP_Context& ctx); - - OP_ERROR _CreateNewPrims(OP_Context& ctx, - const GusdUSD_Traverse* traverse, - UT_ErrorSeverity sev); - - OP_ERROR _ExpandPrims(OP_Context& ctx, - const GusdUSD_Traverse* traverse, - UT_ErrorSeverity sev); - - - /** Add micro nodes of all traversal parms as dependencies - to this node's data micro node.*/ - void _AddTraversalParmDependencies(); - - virtual void finishedLoadingNetwork(bool isChildCall); - -private: - UT_Array _templates; - PRM_Default _tabs[2]; - const GA_Group* _group; - -public: - static void Register(OP_OperatorTable* table); -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif /*OP_GUSD_SOP_USDIMPORT_H*/ diff --git a/third_party/houdini/plugin/OP_gusd/SOP_usdinstanceprototypes.hda b/third_party/houdini/plugin/OP_gusd/SOP_usdinstanceprototypes.hda deleted file mode 100644 index 43a4d28accdd3e15e29fe9eb3e9ce0ae31ed4142..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41749 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 diff --git a/third_party/houdini/plugin/OP_gusd/SOP_usdretime.hda b/third_party/houdini/plugin/OP_gusd/SOP_usdretime.hda deleted file mode 100644 index 9e6006ac4b9a263cf7e662957faec370cfeee8ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5117 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -using std::cerr; -using std::endl; -using std::string; - -namespace { - -#define _NOTRAVERSE_NAME "none" -#define _GPRIMTRAVERSE_NAME "std:boundables" - -int _TraversalChangedCB(void* data, int idx, fpreal64 t, - const PRM_Template* tmpl) -{ - auto& sop = *reinterpret_cast(data); - sop.UpdateTraversalParms(); - return 0; -} - - -void _ConcatTemplates(UT_Array& array, - const PRM_Template* templates) -{ - int count = PRM_Template::countTemplates(templates); - if(count > 0) { - exint idx = array.size(); - array.bumpSize(array.size() + count); - UTconvertArray(&array(idx), templates, count); - } -} - - -PRM_ChoiceList& _CreateTraversalMenu() -{ - static PRM_Name noTraverseName(_NOTRAVERSE_NAME, "No Traversal"); - - static UT_Array names; - names.append(noTraverseName); - - const auto& table = GusdUSD_TraverseTable::GetInstance(); - for(const auto& pair : table) { - names.append(pair.second->GetName()); - } - - names.stdsort( - [](const PRM_Name& a, const PRM_Name& b) - { return UT_String(a.getLabel()) < UT_String(b.getLabel()); }); - names.append(PRM_Name()); - - static PRM_ChoiceList menu(PRM_CHOICELIST_SINGLE, &names(0)); - return menu; -} - -PRM_Template* _CreateTemplates() -{ - //const auto& table = GusdUSD_TraverseTable::GetInstance(); - - /* XXX: All names should be prefixed to ensure they don't - collide with the templates of the traversal plugins.*/ - - static PRM_Name className("unpack_class", "Class"); - static PRM_Name groupName("unpack_group", "Group"); - - static PRM_Name traversalName("unpack_traversal", "Traversal"); - static PRM_Default traversalDef(0, _GPRIMTRAVERSE_NAME); - - static PRM_Name geomTypeName("unpack_geomtype", "Geometry Type"); - static PRM_Name geomTypeChoices[] = - { - PRM_Name("packedprims", "Packed Prims"), - PRM_Name("polygons", "Polygons"), - PRM_Name(0) - }; - static PRM_ChoiceList geomTypeMenu(PRM_CHOICELIST_SINGLE, geomTypeChoices); - - - static PRM_Name deloldName("unpack_delold", "Delete Old Points/Prims"); - - static PRM_Name timeName("unpack_time", "Time"); - static PRM_Default timeDef(0, "$RFSTART"); - static PRM_Conditional - disableWhenNotPoints("{ unpack_class != \"point\" }"); - - static PRM_Name attrsHeadingName("attrs_heading", "Attributes"); - - static PRM_Name attrsName("transfer_attrs", "Transfer Attributes"); - static const char* attrsHelp = "Specifies a list of attributes to " - "transfer from the input prims to the result geometry."; - - static PRM_Name primvarsName("import_primvars", "Import Primvars"); - static PRM_Default primvarsCdDef(0, "Cd"); - static const char* primvarsHelp = "Specifies a list of primvars to " - "import from the traversed USD prims."; - - static PRM_Conditional - disableWhenNotPolygons("{ unpack_geomtype != \"polygons\" }"); - - - GusdPRM_Shared shared; - - static PRM_Template templates[] = { - PRM_Template(PRM_STRING, 1, &groupName, /*default*/ 0), - PRM_Template(PRM_ORD, 1, &className, /*default*/ 0, - &PRMentityMenuPointsAndPrimitives), - PRM_Template(PRM_TOGGLE, 1, &deloldName, PRMoneDefaults), - - PRM_Template(PRM_FLT, 1, &timeName, &timeDef, - // choicelist, range, callback, spare, group, help - 0, 0, 0, 0, 0, 0, - &disableWhenNotPoints), - PRM_Template(PRM_ORD, 1, &traversalName, - &traversalDef, &_CreateTraversalMenu(), - 0, // range - _TraversalChangedCB), - PRM_Template(PRM_ORD, 1, &geomTypeName, PRMoneDefaults, &geomTypeMenu), - - PRM_Template(PRM_HEADING, 1, &attrsHeadingName, 0), - PRM_Template(PRM_STRING, 1, &attrsName, 0, - // choicelist, range, callback, spare, group, help - 0, 0, 0, 0, 0, attrsHelp), - - PRM_Template(PRM_STRING, 1, &primvarsName, &primvarsCdDef, - // choicelist, range, callback, spare, group, help - 0, 0, 0, 0, 0, primvarsHelp, - &disableWhenNotPolygons), - PRM_Template() - }; - - return templates; -} - - -auto _mainTemplates(GusdUT_StaticVal(_CreateTemplates)); - - -} /*namespace*/ - - -void -GusdSOP_usdunpack::Register(OP_OperatorTable* table) -{ - OP_Operator* op = - new OP_Operator("pixar::usdunpack", - "USD Unpack", - Create, - *_mainTemplates, - /* min inputs */ (unsigned int)0, - /* max input */ (unsigned int)1); - op->setIconName("pxh_gusdIcon.png"); - op->setOpTabSubMenuPath( "Pixar" ); - table->addOperator(op); - table->setOpFirstName( "pixar::usdunpack", "usdunpack" ); -} - - -OP_Node* -GusdSOP_usdunpack::Create(OP_Network* net, const char* name, OP_Operator* op) -{ - return new GusdSOP_usdunpack(net, name, op); -} - - -GusdSOP_usdunpack::GusdSOP_usdunpack( - OP_Network* net, const char* name, OP_Operator* op) - : SOP_Node(net, name, op), _group(NULL) -{} - - -void -GusdSOP_usdunpack::UpdateTraversalParms() -{ - if(getIsChangingSpareParms()) - return; - - UT_String traversal; - evalString(traversal, "unpack_traversal", 0, 0); - - const auto& table = GusdUSD_TraverseTable::GetInstance(); - - const PRM_Template* customTemplates = NULL; - if(traversal != _NOTRAVERSE_NAME) { - if(const auto* type = table.Find(traversal)) { - customTemplates = type->GetTemplates(); - } - } - - _templates.clear(); - const int nCustom = customTemplates ? - PRM_Template::countTemplates(customTemplates) : 0; - if(nCustom > 0) { - /* Build a template list that puts the main - templates in one tab, and the custom templates in another.*/ - static const int nMainTemplates = - PRM_Template::countTemplates(*_mainTemplates); - - _tabs[0] = PRM_Default(nMainTemplates, "Main"); - _tabs[1] = PRM_Default(nCustom, "Advanced"); - - static PRM_Name tabsName("unpack_tabs", ""); - - _templates.append(PRM_Template(PRM_SWITCHER, 2, &tabsName, _tabs)); - - _ConcatTemplates(_templates, *_mainTemplates); - _ConcatTemplates(_templates, customTemplates); - } - _templates.append(PRM_Template()); - - - /* Add the custom templates as spare parms.*/ - PI_EditScriptedParms parms(this, &_templates(0), /*spare*/ true, - /*skip-reserved*/ false, /*init links*/ false); - UT_String errs; - GusdUTverify_ptr(OPgetDirector())->changeNodeSpareParms(this, parms, errs); - - _AddTraversalParmDependencies(); -} - - -void -GusdSOP_usdunpack::_AddTraversalParmDependencies() -{ - PRM_ParmList* parms = GusdUTverify_ptr(getParmList()); - for(int i = 0; i < parms->getEntries(); ++i) { - PRM_Parm* parm = GusdUTverify_ptr(parms->getParmPtr(i)); - if(parm->isSpareParm()) { - for(int j = 0; j < parm->getVectorSize(); ++j) - addExtraInput(parm->microNode(j)); - } - } -} - -template -void RemapArray(const UT_Array& pairs, - const UT_Array& srcArray, - const T& defaultValue, - UT_Array& dstArray) -{ - const exint size = pairs.size(); - dstArray.setSize(size); - for (exint i = 0; i < size; ++i) { - const exint index = pairs(i).second; - dstArray(i) = (index >= 0 && index < size) ? - srcArray(index) : defaultValue; - } -} - -OP_ERROR -GusdSOP_usdunpack::_Cook(OP_Context& ctx) -{ - fpreal t = ctx.getTime(); - - UT_String traversal; - evalString(traversal, "unpack_traversal", 0, t); - - UT_String geomType; - evalString(geomType, "unpack_geomtype", 0, t); - bool unpackToPolygons = (geomType == "polygons"); - - bool packedPrims = !evalInt("unpack_class", 0, ctx.getTime()); - - // If there is no traversal AND geometry type is not - // polygons, then the output prims would be the same as the inputs, - // so nothing left to do. - if (traversal == _NOTRAVERSE_NAME && !unpackToPolygons) { - return UT_ERROR_NONE; - } - - GA_AttributeOwner owner = packedPrims ? - GA_ATTRIB_PRIMITIVE : GA_ATTRIB_POINT; - - // Construct a range and bind prims. - GA_Range rng(gdp->getIndexMap(owner), - UTverify_cast(_group)); - - UT_Array variants; - GusdDefaultArray purposes; - GusdDefaultArray times; - UT_Array rootPrims; - { - GusdStageCacheReader cache; - if(!GusdGU_USD::BindPrims(cache, rootPrims, *gdp, rng, - &variants, &purposes, ×)) { - return error(); - } - } - - if(!times.IsVarying()) - times.SetConstant(evalFloat("unpack_time", 0, t)); - - // Run the traversal and store the resulting prims in traversedPrims. - // If unpacking to polygons, the traversedPrims will need to contain - // gprim level prims, which means a second traversal may be required. - - UT_Array traversedPrims; - if (traversal != _NOTRAVERSE_NAME) { - // For all traversals except gprim level, skipRoot must be true to - // get the correct results. For gprim level traversals, skipRoot - // should be false so the results won't be empty. - bool skipRoot = (traversal != _GPRIMTRAVERSE_NAME); - if (!_Traverse(traversal, t, rootPrims, times, purposes, - skipRoot, traversedPrims)) { - return error(); - } - } else if (unpackToPolygons) { - // There is no traversal specified, but unpackToPolygons is true. - // A second traversal will be done upon traversedPrims to make - // sure it contains gprim level prims, but for now, just copy the - // original packed prims from primHnd into traversedPrims. - const exint size = rootPrims.size(); - traversedPrims.setSize(size); - for (exint i = 0; i < size; ++i) { - traversedPrims(i) = std::make_pair(rootPrims(i), i); - } - } - - // If unpacking to polygons AND the traversal was anything other than - // gprim level, we need to traverse again to get down to the gprim - // level prims. - if (unpackToPolygons && traversal != _GPRIMTRAVERSE_NAME) { - const exint size = traversedPrims.size(); - - // Split up the traversedPrims pairs into 2 arrays. - UT_Array prims(size, size); - UT_Array indices(size, size); - for (exint i = 0; i < size; ++i) { - prims(i) = traversedPrims(i).first; - indices(i) = traversedPrims(i).second; - } - - GusdDefaultArray - traversedPurposes(purposes.GetDefault()); - if(purposes.IsVarying()) { - // Purposes must be remapped to align with traversedPrims. - RemapArray(traversedPrims, purposes.GetArray(), - GUSD_PURPOSE_DEFAULT, traversedPurposes.GetArray()); - } - - GusdDefaultArray traversedTimes(times.GetDefault()); - if(times.IsVarying()) { - // Times must be remapped to align with traversedPrims. - RemapArray(traversedPrims, times.GetArray(), - times.GetDefault(), traversedTimes.GetArray()); - } - - // Clear out traversedPrims so it can be re-populated - // during the new traversal. - traversedPrims.clear(); - - // skipRoot should be false so the result won't be empty. - bool skipRoot = false; - if (!_Traverse(_GPRIMTRAVERSE_NAME, t, prims, - traversedTimes, traversedPurposes, - skipRoot, traversedPrims)) { - return error(); - } - - // Each index in the traversedPrims pairs needs - // to be remapped back to a prim in primHnd. - for (exint i = 0; i < traversedPrims.size(); ++i) { - const exint primsIndex = traversedPrims(i).second; - traversedPrims(i).second = indices(primsIndex); - } - } - - // Build an attribute filter using the transfer_attrs parameter. - UT_String transferAttrs; - evalString(transferAttrs, "transfer_attrs", 0, t); - - GA_AttributeFilter filter( - GA_AttributeFilter::selectAnd( - GA_AttributeFilter::selectByPattern(transferAttrs.c_str()), - GA_AttributeFilter::selectPublic())); - - if (!packedPrims) { - GusdGU_USD::AppendExpandedRefPoints( - *gdp, *inputGeo(0), rng, traversedPrims, filter, - GUSD_PATH_ATTR, GUSD_PRIMPATH_ATTR); - - } else { - // The variants array needs to be expanded to - // align with traversedPrims. - UT_Array expandedVariants; - RemapArray(traversedPrims, variants, - SdfPath::EmptyPath(), expandedVariants); - - GusdDefaultArray traversedTimes(times.GetDefault()); - if(times.IsVarying()) { - // Times must be remapped to align with traversedPrims. - RemapArray(traversedPrims, times.GetArray(), - times.GetDefault(), traversedTimes.GetArray()); - } - - UT_String importPrimvars; - evalString(importPrimvars, "import_primvars", 0, t); - - GusdGU_USD::AppendExpandedPackedPrims( - *gdp, *inputGeo(0), rng, traversedPrims, - expandedVariants, traversedTimes, filter, - unpackToPolygons, importPrimvars); - } - - if(evalInt("unpack_delold", 0, t)) { - - // Only delete prims or points that were successfully - // binded to prims in primHnd. - GA_OffsetList delOffsets; - delOffsets.reserve(rootPrims.size()); - exint i = 0; - for (GA_Iterator it(rng); !it.atEnd(); ++it, ++i) { - if (rootPrims(i).IsValid()) { - delOffsets.append(*it); - } - } - GA_Range delRng(gdp->getIndexMap(owner), delOffsets); - - if(packedPrims) - gdp->destroyPrimitives(delRng, /*and points*/ true); - else - gdp->destroyPoints(delRng); // , GA_DESTROY_DEGENERATE); - } - - return error(); -} - -bool -GusdSOP_usdunpack::_Traverse(const UT_String& traversal, - const fpreal time, - const UT_Array& prims, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - bool skipRoot, - UT_Array& traversed) -{ - const auto& table = GusdUSD_TraverseTable::GetInstance(); - - const GusdUSD_Traverse* traverse = table.FindTraversal(traversal); - if (!traverse) { - GUSD_ERR().Msg("Failed locating traversal '%s'", traversal.c_str()); - return false; - } - - UT_UniquePtr opts(traverse->CreateOpts()); - if (opts) { - if (!opts->Configure(*this, time)) { - return false; - } - } - - if (!traverse->FindPrims(prims, times, purposes, traversed, - skipRoot, opts.get())) { - return false; - } - - return true; -} - - -OP_ERROR -GusdSOP_usdunpack::cookInputGroups(OP_Context& ctx, int alone) -{ - if(!getInput(0)) - return UT_ERROR_NONE; - - int groupIdx = getParmList()->getParmIndex("unpack_group"); - int classIdx = getParmList()->getParmIndex("unpack_class"); - bool packedPrims = !evalInt(classIdx, 0, ctx.getTime()); - - GA_GroupType groupType = packedPrims ? - GA_GROUP_PRIMITIVE : GA_GROUP_POINT; - - return cookInputAllGroups(ctx, _group, alone, - /* do selection*/ true, - groupIdx, classIdx, groupType); -} - - -OP_ERROR -GusdSOP_usdunpack::cookMySop(OP_Context& ctx) -{ - OP_AutoLockInputs lock(this); - if(lock.lock(ctx) >= UT_ERROR_ABORT) - return error(); - - // Local var support. - setCurGdh(0, myGdpHandle); - setupLocalVars(); - - if(getInput(0)) - duplicateSource(0, ctx); - else - gdp->clearAndDestroy(); - - /* Extra inputs have to be re-added on each cook.*/ - _AddTraversalParmDependencies(); - - if(cookInputGroups(ctx, 0) < UT_ERROR_ABORT) - _Cook(ctx); - - resetLocalVarRefs(); - - return error(); -} - - -void -GusdSOP_usdunpack::finishedLoadingNetwork(bool isChildCall) -{ - SOP_Node::finishedLoadingNetwork(isChildCall); - - if(isChildCall) { - /* Update our traversal parms. - Needs to happen post-loading since loading could - have changed the traversal mode.*/ - UpdateTraversalParms(); - } -} - -PXR_NAMESPACE_CLOSE_SCOPE - diff --git a/third_party/houdini/plugin/OP_gusd/SOP_usdunpack.h b/third_party/houdini/plugin/OP_gusd/SOP_usdunpack.h deleted file mode 100644 index 7559e0a972..0000000000 --- a/third_party/houdini/plugin/OP_gusd/SOP_usdunpack.h +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#ifndef OP_GUSD_SOP_USDUNPACK_H -#define OP_GUSD_SOP_USDUNPACK_H - -#include -#include - -#include "gusd/defaultArray.h" -#include "gusd/purpose.h" -#include "gusd/USD_Traverse.h" - -#include -#include "pxr/usd/usd/prim.h" - -PXR_NAMESPACE_OPEN_SCOPE - -class GusdUSD_Traverse; - - -class GusdSOP_usdunpack : public SOP_Node -{ -public: - static OP_Node* Create(OP_Network* net, - const char* name, - OP_Operator* op); - - void UpdateTraversalParms(); - -protected: - GusdSOP_usdunpack(OP_Network* net, const char* name, OP_Operator* op); - - virtual ~GusdSOP_usdunpack() {} - - virtual OP_ERROR cookMySop(OP_Context& ctx); - - virtual OP_ERROR cookInputGroups(OP_Context& ctx, int alone); - - OP_ERROR _Cook(OP_Context& ctx); - - bool _Traverse(const UT_String& traversal, - const fpreal time, - const UT_Array& prims, - const GusdDefaultArray& times, - const GusdDefaultArray& purposes, - bool skipRoot, - UT_Array& traversed); - - - /** Add micro nodes of all traversal parms as dependencies - to this node's data micro node.*/ - void _AddTraversalParmDependencies(); - - virtual void finishedLoadingNetwork(bool isChildCall); - -private: - UT_Array _templates; - PRM_Default _tabs[2]; - const GA_Group* _group; - -public: - static void Register(OP_OperatorTable* table); -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // OP_GUSD_SOP_USDUNPACK_H diff --git a/third_party/houdini/plugin/OP_gusd/UsdImport.pypanel b/third_party/houdini/plugin/OP_gusd/UsdImport.pypanel deleted file mode 100644 index e25cd7846c..0000000000 --- a/third_party/houdini/plugin/OP_gusd/UsdImport.pypanel +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - diff --git a/third_party/houdini/plugin/OP_gusd/help/USDPackedPrims.txt b/third_party/houdini/plugin/OP_gusd/help/USDPackedPrims.txt deleted file mode 100644 index 976ac69d60..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/USDPackedPrims.txt +++ /dev/null @@ -1,111 +0,0 @@ -#type: include - -= USD Packed Prims = - -USD Packed Prims are lightweight, file backed primitives. Each USD Packed Prim represents a primitive in USD file. A USD primitive may be a single [gprim|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim] like a mesh or a curve or it might be a group containing many [gprims|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim]. - -The only data that USD Packed Prims hold are their intrinsic attributes. - - -==== Intrinsic Attributes ==== - -usdFileName: - The referenced USD file - -usdPrimPath: - The referenced USD prim - -usdFrame: - The frame to read the prim from. - Typically this is set to the current frame but if the geometry is not - moving, it is more efficient to set this to a constant frame. - -usdType: - This is a read only attribute useful for debugging and for writing - wrangler snippets. - -usdLocalToWorldTransform: - This is a read only attribute that can be read in vex. - -usdAltFileName: - When writing a USD Packed Prim to a USD file, it may be useful to use - a different file path than the path we used to read from (For example, - we might want to use a relative path). If this attribute is set, use - this path. - -usdSrcPrimPath: - If a USD Packed Prim is created by unpacking a point instancer, this - attribute contains the name of the point instancer. This is used for - writing overlays. - -usdIndex: - If a USD Packed Prim is created by unpacking a point instancer, this - attribute contains the index into the point instancer's array. This is - used from writing overlays. - -usdViewportPurpose: - A list of strings indicating which "purpose" types to draw. - -=== Hierarchy and Traversal === - -USD arranges geometry into a hierarchy. In Houdini SOPs, we can represent hierarchy using packed primitives. - -How we import USD depends on how we want to use it. If we want to transform a model rigidly, we can import that model as a single packed prim. If we need to deform the model, then we need to load each [gprim|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim] in the model as a packed prim and then unpack them to Houdini geometry. - -The process of walking the USD hierarchy collecting primitives to load is called "Traversal". Both the USD import node and the USD unpack node have options for traversal. The traversal starts and the prims you have explicitly selected and then traverses the hierarchy belows these prims to select -descendant prims bases on a criteria. For example you can traverse to find all the [gprims|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim] contained in a asset. - -Both the USD Import and the USD Unpack SOPs have a custom traversal mode that lets you select prims based on many different USD concepts. - -=== Transforms === - -USD Packed Prims, like all packed prims in Houdini, have attributes for rigid transforms. - -=== Viewport Drawing === - -Like most packed prims in Houdini, USD packed prims can be drawn in the viewport as points, bounding boxes or full geometry. - -=== Purpose === - -Sections of a USD hierarchy can be marked to have a specific purpose. For example, an asset might have a lightweight proxy representation that is used to view the asset in interactive applications and a more detailed representation used for rendering. Often these two representations are siblings in the hierarchy. When walking down the hierarchy to draw a USD prim, if a section is found that is marked as a purpose we don't want to draw, it is ignored. - -=== Variants === - -Variants are another way to have version of a asset that are used for different purposes. Variants can be specified with the prim path by including the variant name in curly braces. "/BicycleHero{modelingVariant=Layout}" for example. The tree view panel on the USD import SOP can be used to select variants from a list. - -=== Unpacking === - -USD Packed Prims can be unpacked using Houdini's Unpack SOP or the more specialized USD Unpack SOP. USD arranges geometry in a hierarchy. When we unpack a prim that prim is replaced with prims that represent the children of that prim. Once we have unpacked the hierarchy down to [gprims|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim], unpacking again will convert to Houdini geometry. - -When a USD prim is unpacked to Houdini geometry, a "usdpath" and "usdprimpath" attribute will be created so that the deformed geometry can be written back to a USD file. - -If you turn off iterations on the unpack SOP, the Houdini unpack SOP can be used to convert to Houdini geometry in one step. However, for deep hierarchies, the USD Unpack SOP will be faster. - -=== Primvars === - -In USD, prims may have attributes that describe shading signals. These attributes are called primvars. When a USD prim is unpacked to Houdini geometry, houdini attributes are created to contain the primvars. - -There is not a perfect match between USD primvars and Houdini attributes. In USD each prim can contain a different set of primvars. In Houdini, all prims in a SOP chain share attributes. If you unpack one USD [gprim|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim] all the primvars will be unpacked to attribute correctly. If you unpack many [gprims|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Gprim] at once, things get tricky. - -If you unpack USD to Houdini geometry using the Houdini Unpack SOP it will unpack all primvars. If you use the USD Unpack SOP you can set patterns to select which primvars to unpack. - -=== Point Instancers === - -Point instancers can be imported and unpacked in the same way as other USD geometry types, though they -will not unpack to native Houdini point instancers. The simplest workflow for working with imported -USD point instancers is to import it, apply transformations to the instances, then write out an overlay -with the Overlay Transform option. For more complicated operations, and to generate new USD point instancers -from Houdini, there is the USD Instance Prototypes SOP. - -=== Related Nodes === - -[USD Import|nodes/sop/pixar--usdimport] - -[USD Output|nodes/out/pixar--usdoutput] - - - - - - - diff --git a/third_party/houdini/plugin/OP_gusd/help/UsdOutputOverview.txt b/third_party/houdini/plugin/OP_gusd/help/UsdOutputOverview.txt deleted file mode 100644 index ef67ac55e6..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/UsdOutputOverview.txt +++ /dev/null @@ -1,119 +0,0 @@ - -#type: include -#tags: usd - -= USD Output Overview = - -"""USD ROP Nodes""" - -Exporting USD from Houdini is handled by a few ROP nodes that can be wired together -using ROP networks in flexible ways. - -Our most common workflows involve an existing USD scene that we want to either add -new geometry to or to modify some existing geometry. The ["USD Output" node|/nodes/out/pixar--usdoutput] -is used to write the bulk of the geometry and then a ["USD Reference" node|/nodes/out/pixar--usdreference] -or a ["USD Sublayer" node|/nodes/out/pixar--usdlayer] is used to add the geometry -into the existing scene. A USD reference is used when we are adding new -geometry to a scene and sublayers are used to modify existing geometry. - -If you can run a Houdini job on many machines at once, it is often very efficient to -run multiple frames in parallel and write the results to per frame files. When we -do this, we use a ["USD coalesce" node|/nodes/out/UsdCoalesce] to build a "USD clip". -These clips join the per frame data so that it looks to clients exactly the same -as if they had been written to a single file. - -=== Modifying USD ==== - -To modify existing USD geometry, the ["USD Output" ROP|/nodes/out/pixar--usdoutput] has an "overlay" -mode. In overlay mode, the ROP does not write a full USD prim definition but instead -writes attribute definitions that replace the original attributes. For example, -to deform a mesh, the ROP writes new attribute definitions for just the point -positions. - -The ROP has a few overlay options that can be used in combination, points, -transforms, and primvars. In addition there is an "overlay all" option. This is -used when you need to replace the entire primitive with a new one. This is needed -if you are changing the topology of a primitive. - -To modify USD, the original geometry is loaded into Houdini as "USD Packed Primitives". -If we are rigidly transforming the geometry then it should be possible to keep -the geometry packed. To just modify the transforms we can pass these prims directly -to the ["USD Output" ROP|/nodes/out/pixar--usdoutput] and select the "overlay transforms" option on the ROP. - -To deform the geometry, we need to unpack the USD geometry into native Houdini geometry. -The unpack will add a "usdprimpath" primitive attribute to the geometry. The ROP will -use this attribute to know which prims to write. The "overlay points" option on the -ROP can be used to modify just the geometry's points. You can use the standard Houdini [unpack SOP|/nodes/sop/unpack] SOP or -[USD unpack SOP|/nodes/sop/pixar--usdunpack] if you require custom options. - -=== Naming Geometry === - -In USD, all geometry is organized into a name hierarchy but in Houdini the geometry -is a flat list of primitives in a SOP context. On output we need to assign a -path to each primitive. - -If geometry primitives don't have name attributes, the ROP will automatically name the -primitives. By default, each prim will named something -like $PREFIX/mesh_0, where $PREFIX is the value of the "Prefix" parameter on the ROP. - -To use attributes to name primitives, the "Path attribute" parameter -on the ROP sets which attribute to use. The default is "usdprimpath". - -If you are modifying existing geometry, your geometry needs to know the name of the thing -that it is modifying. This name can either be a ["USD Packed Prim"|/USDPackedPrims] intrinsic or a -name attribute. - -The value in a name attribute can either be an absolute or relative. Absolute names -have a leading slash. If you are importing geometry and modifying it, the name -will be absolute. - -If the name attribute contains a relative name, the ROP will build the full path -to the prim using the "prefix" parameter and the packed prim hierarchy. - -One simple use for relative names is to partition geometry. If you are outputting -a collection of polygon primitives, they will be partitioned into meshes based -on the name attribute. - -You can build geometry hierarchies by repeatedly using the pack node and assigning a -relative name to each packed prim. - -=== Primvars === - -Any Houdini attribute that is not written as part of the basic schema for a -prim, can be written as a prim var. The ROP has parameters that can be used -to filter the attributes. - -=== Writing subdivision surfaces === - -When writing meshes, the ROP looks for parameters on the OBJ node indicating -that the meshes should be written as subdivision surfaces. These parms can -be added using the "Edit Rendering Parameters" entry in the "gear" menu. The -parameters for either Mantra or PrMan will work. - -=== Purpose === - -USD prims can have an attribute called "purpose". As a renderer iterates over the -USD prim hierarchy, if it finds a prim that has a purpose that it doesn't care about, -it skips that prim. So we can create a two sibling groups, one called "render" and -one called "proxy". The renderer can choose to ignore one of them. - -There is a OTL called UsdBindProxy that demonstrates this. - -=== Writing USD Packed Prims as references === - -USD packed prims are a reference to a prim in a USD file with an applied transform. -When a USD packed prim is passed to the Usd Output ROP, it writes the reference with -the transform. This reference can be a normal USD reference or it can be a entry -in a point instancer. - -=== Granularity === - -It can sometimes be very efficient to execute a SOP network in parallel using -one process to compute each frame. In this case we need to be able to write each -frame individually and then coalesce the results with a post process. - - - -=== Partitioning Meshes === - - diff --git a/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdlayer.txt b/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdlayer.txt deleted file mode 100644 index 5f73dfe0df..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdlayer.txt +++ /dev/null @@ -1,71 +0,0 @@ -#type: node -#context: out -#internal: USDLayer -#tags: usd layer - -= USD Layer = - -"""inserts, appends, or removes USD primitives to/from a USD scene as sublayers""" - -== Overview == - -This ROP will insert,append, or remove the contents of source USD files into/from destination USD Files as [USD sublayers.|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-SubLayers]. - - -@parameters - - -Render to Disk: - Saves the usd reference to disk. - -Controls...: - #id: renderdialog - - Opens the control dialog to allow adjustments of the render parameters - before rendering. - - -[Include:standard#valid_frame_range] - -Start/End/Inc: - Specifies the range of frames to render (start frame, end frame, and increment). All values may be floating point values. The range is inclusive. - - These parameters determine the values of the local variables for the output driver. - - `$NRENDER`: - The number of frames to be rendered by the output driver. - `$N`: - The current frame being rendered (starting at 1 and going to `$NRENDER`). - -Render with Take: - #id: take - - Uses the settings in a particular take while rendering. Choose - __Current__ to use the current take when rendering. - - -== Settings == -Loop Range: - This allows you to loop the operation over multiple files by using the token %d as the loop iteration string. For example, say you wanted to insert the following files: source1.usd, source2.usd, source3.usda into a - the file destination.usd. You would set your Source parameter to file%d.usda, the Destination to detination.usd and the loop range to 1 ,3 ,1. - -Source: - File paths to USD files that will be inserted into or removed from the corresponding Destinatation USD file. -Destination: - File Paths in/from which to insert/remove the corresponding Source USD file. -Operation: - insert into: - Inserting places the sublayer at the top of the layer stack making it the strongest opinon, this is most desirable for overlays. - append into: - Appending places the sublayer at the bottom of the stack giving it the weakest opinion which is useful for installing new geometry into a USD scene. - remove from: - Removes Source sublayer if it exist in the Destination USD file. - -@related -* [Node:sop/pixar--usdimport] -* [Node:sop/pixar--usdunpack] -* [Node:out/pixar--usdoutput] -* [Node:out/pixar--usdlayer] - - - diff --git a/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdoutput.txt b/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdoutput.txt deleted file mode 100644 index c2721a727a..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdoutput.txt +++ /dev/null @@ -1,92 +0,0 @@ -#type: node -#context: out -#internal: USDOutput -#tags: usd output - -= USD Output = - -"""Export geometry to a USD file""" - -This ROP writes geometry to the USD format. Meshes, curves, points are written directly -to USD. Most other geometry can be refined into one of these three types. - -This ROP can write references to USD primitives in other USD files. - -This ROP can write concrete geometry or it can write overlays that modify -existing geometry. - -A more complete overview of exporting USD files from Houdini can be found [here|/UsdOutputOverview]. - -@parameters - -SOP Path: - Geometry to export -USD File: - File to write to -Granularity: - Write one file per frame or write all frames to one file -== Paths == -Prefix: - Prefix used to build USD prim names -Path attribute: - Attribute used to partition geometry and to build the names of USD prims. -Always Write Root Prim: - If this option is checked, if no geometry is cooked in the SOP, write - an empty group into the file with the name given in the "Prefix" parameter. -== Geometry == -Coalesce Fragments: - Coalesce packed fragments into a single mesh(see [pack SOP|/ for more information) -== Overlay == -Overlay Existing Geometry: - If checked, write USD primitive overs rather than USD primitive defs. -Overlay Reference File: - This should be set to the file that you are overriding. -== Primvars == - -A full description of suppoted primvar intrepolation can be found in the [Usd api documentation|http://graphics.pixar.com/usd/docs/api/class_usd_geom_primvar.html#Usd_InterpolationVals] - -Varying: - Varying primvars to export -FaceVarying: - FaceVarying primvars to export -Uniform: - Uniform primvars to export -Constant: - Varying primvars to export -== Shaders == -Output Shaders: - Enable USD shading on export -USD Shading File: - Absolute path to shading file -USD Shader: - USD shader Name - -== Scripts == - -Each script command refers to an hscript command which will be run, regardless of the expression language selected for the parameter. The resulting string will be run as an hscript command. - -NOTE: - It is possible to use the python, unix or source hscript commands to perform complex processing. - -The commands are always run when rendering occurs. The command checks the parameters of the output driver when it is rendering a range or sending output to a command. - -Before the render occurs, Houdini will automatically set the current hscript directory to point to the output driver. - -Pre-Render Script: - This command is run before any USD file is generated. It is only run once per render. - -Pre-Frame Script: - This command is run before each USD file is generated. - -Post-Frame Script: - This command is run after each USD file is generated. - - -Post-Render Script: - This command is run one time, after all RIBs have been generated. - - - - - - diff --git a/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdreference.txt b/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdreference.txt deleted file mode 100644 index 009f1624e5..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/nodes/out/pixar--usdreference.txt +++ /dev/null @@ -1,56 +0,0 @@ -#type: node -#context: out -#internal: USDReference -#tags: usd reference - -= USD Reference = - -"""insert a USD primative from one usd file to another as a reference""" - -== Overview == - -This ROP will insert a [reference|http://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-References] to a usd primative into a usd file. - -@parameters - -Render to Disk: - Saves the usd reference to disk. - -Controls...: - #id: renderdialog - - Opens the control dialog to allow adjustments of the render parameters - before rendering. - - -[Include:standard#valid_frame_range] - -Start/End/Inc: - Specifies the range of frames to render (start frame, end frame, and increment). All values may be floating point values. The range is inclusive. - - These parameters determine the values of the local variables for the output driver. - - `$NRENDER`: - The number of frames to be rendered by the output driver. - `$N`: - The current frame being rendered (starting at 1 and going to `$NRENDER`). - -Render with Take: - #id: take - - Uses the settings in a particular take while rendering. Choose - __Current__ to use the current take when rendering. - -== USD == -Destination File: - The USD file to which the reference will be inserted. -Reference Prim Path: - USD location in the destination scene. -Reference File: - The USD file to be inserted as a reference. - -@related -* [Node:sop/pixar--usdimport] -* [Node:sop/pixar--usdunpack] -* [Node:out/pixar--usdoutput] -* [Node:out/pixar--usdlayer] diff --git a/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdimport.txt b/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdimport.txt deleted file mode 100644 index 0eba56ef3d..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdimport.txt +++ /dev/null @@ -1,129 +0,0 @@ -= USDImport = - -#type: node -#context: sop -#internal: USDImport -#tags: usd import - -= USD Import = - -This node will import the USD primitives specified by the file name and prim path parameters. The imported primitives are represented as ["USD Packed Prims"|/USDPackedPrims]. - -The primitives to be imported are specified by first selecting the paths of one or more USD Primitives and then specify how to traverse the USD hierarchy below those prims. You can choose to import only the prims listed in "Prim Path" (No Traversal), or import all the gprims or components contained in the USD hierarchies below the prims list in "Prim Path". - -If you select "Custom Traversal" from the "Traversals" menu. The "Advanced" parameter pane is shown. The parameters on this pane allow you to search for prims using a bunch of different USD attributes and concepts. Note that doing custom traversals can be much slower than the other traversal types. - - - - -@parameters - Group: - Group of points to process from input - Class: - If set to primitive, the OP will create USD Packed USD prims. If set to points, the SOP will create points with attributes that describe the USD packed prims. The points method is not currently fully supported. - Delete Old Points/Prims: - How to treat points or prims from connected input. - USD File: - USD file to import from. You can use the "View" button to launch [usdview|http://graphics.pixar.com/usd/docs/USD-Toolset.html#USDToolset-usdview] - Tree View: - Open a tree view panel to select prims to import - Prim Path: - One or more prims to import. The easiest way to add things to this list is using the Tree View but you can also type directly into this field. - Note that USD prim paths must begin with a "/". - Reload: - Reload the current USD file. - Time: - The time to load the USD prims. When importing animated geometry this could be set to $FF. For static geometry, it is much more efficient to set this to $RFSTART. Any time value will work though. - Traversal: - For each name listed in the Prim Path parameter, we can create a USD Packed Prim for just that prim or we can traverse the USD hierarchy contained in that prim and create USD Packed Prims the USD prims that match a criteria. - - No Traversal: - Create one USD Packed Prim for each entry in the Prim Path parameter - Components: - Create one USD Packed Prim for each prim with kind "component". - - Gprims: - Create one USD Packed Prim for each gprim - - Groups: - Create one USD Packed Prim for each prim of type "group" - - Custom Traversal : - Add a new "Advanced" parameter pane that allows you to choose prims based on many criteria - Display As: - How to display the pack prims created by this node. - - Full Geometry: - The full geometry will be displayed in the viewport. - Point Cloud: - Only the points of the geometry will be displayed. This will take less memory and be faster to render. - Bounding Box: - Only display the bounding box of the geometry in the viewport. - Centroid: - Display a single point at the center of the bounding box. - Hidden: - Don't display the geometry in the viewport. - Proxy: - Unsupported - Purpose: - Sections of a USD hierarchy can be marked to be used for a a specific purpose. Only sections mark as default purpose or one of the purposes listed here will be loaded. - - Missing Frame: - What to do when a file is missing. - - Prim Types: - USD prim types to select when doing a custom traversal of the USD hierarchy. The pulldown menu list all the valid types. Multiple types and wildcards are supported. - - Purposes: - USD prim purposes to select when doing a custom traversal of the USD hierarchy. The pulldown menu lists all the valid purposes. Multiple purposes and wildcards are supported. - - Kinds: - USD prim kinds to select when doing a custom traversal of the USD hierarchy. The pulldown menu lists all the valid kinds. Multiple kinds and wildcards are supported. - - Name Mask: - Pattern used match against prim names when doing a custom traversal of the USD hierarchy. Wildcards are supported. - - Path Mask: - Pattern used match against prim paths when doing a custom traversal of the USD hierarchy. Wildcards are supported. - - Traverse Matched: - If this is on, when a matching prim is found, that prim is returned and the traverse will continue looking for matches among the prims descendants. Is "Traverse Matched" is off, - the traverse will not match any of the prims descendants. - - Is Active: - Return only prims that are active. - - Is Visible: - Return only prims that are visible. - - Is Imageable: - Return only prims that are imageable. - - Is Defined: - Return only prims that are defined. - - Is Abstract: - Return only prims that are abstract. - - Is Group: - Return only prims that are groups. - - Is Model: - Return only prims that are models. - - Is Instance: - Return only prims that are instances. - - Is Instance Master: - Return only prims that are instance masters. - - Has Clips: - Return only prims that have clips. - - - -:load_example: - #path: /examples/nodes/sop/pixar--usdimport/UsdImportStage - #include: yes - - diff --git a/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdinstanceprototypes.txt b/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdinstanceprototypes.txt deleted file mode 100644 index 64018c9174..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdinstanceprototypes.txt +++ /dev/null @@ -1,18 +0,0 @@ -= USDInstancePrototypes = - -#type: node -#context: sop -#internal: USDInstancePrototypes -#tags: usd instance prototypes point instancer - -= USD Instance Prototypes = - -This node will add the required attributes to insure proper exporting of a USD Point Instancer. The input must contain merged prototypes with one packed prim per expected prototype. Each prim can either be a native Houdini packed prim or a USD packed prim. These must not change per frame, for reasons explained below involving the USD Point Instancer. - -In the node, we then add a primitive attribute "usdinstancepath" per prim. This provides a unique id per prototype for each instance to indicate which prototype to use. It is comparable to the native houdini instancing attribute ("instancepath"), though it does not actually need to point to a real node. In fact, by default we just set it to prototype_# where the number is decided by primnum. This must be copied along with the prototype to your instances in order to indicate to USD which prototype each instance is using. - -In addition, we create a detail attribute "usdprototypespath" which must point to an actual sop containing all the merged prototypes, with their "usdinstancepath" attributes already attached. As indicated above, this must be consistent across all frames, regardless of whether a prototype is being used in every frame. This is due to USD creating a static mapping from a prototype index id to the actual prototype geometry. An instance then can indicate its prototype in USD with just that index id. - -These attributes make most sense as primitive for the instance path and detail for the prototypes path, but can be set as any attribute or even a paramater with the same name on the USD output ROP. In addition, "instancepath" will behave the same way as "usdinstancepath" in order to support native Houdini point instancing (points with a transform and "instancepath" point attribute pointing to a prototype OBJ node). - - diff --git a/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdunpack.txt b/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdunpack.txt deleted file mode 100644 index a952af30fe..0000000000 --- a/third_party/houdini/plugin/OP_gusd/help/nodes/sop/pixar--usdunpack.txt +++ /dev/null @@ -1,88 +0,0 @@ -#type: node -#context: sop -#internal: USDUnpack -#tags: usd import - -= USD Unpack = - -Unpack ["USD Packed Prims"|/USDPackedPrims] or points representing USD prims into their constituant parts. - -The USD Unpack SOP traverses the USD hieriarchy represented by the input packed prims or points to find descendant prims that match a search criteria. - -If the "Geometry Type" is "Packed Prims" the results of the traversal are returned directly. If the "Geometry Type" is set to "Polygons" the prims found in the traversal are converted to Houdini geometry. - -When we convert a USD prim to Houdini geometry, any primvars on the USD prim that match the pattern in the "Import Primvars" param will be converted to Houdini attributes. - -@parameters - Group: - Group of points to process from input - - Class: - If set to primitive, the OP will create USD Packed USD prims. If set to points, the SOP will create points with attributes that describe the USD packed prims. - - Delete Old Points/Prims: - How to treat points or prims from connected input. - - Time: - Time assigned to useach unpacked prim. - - Traversal: - Method to use to find prims to unpack within the USD hierarchy of the input prims. - - Geometry Type: - Unpacked to USD Packed Prims or Houdini geometry. - - Transfer Attributes: - Specifies a list of attributes to transfer from the input prims to the result geometry. - - Import Primvars: - Specifies a list of primvars to import from the traversed USD prims. - - Prim Types: - USD prim types to select when doing a custom traversal of the USD hierarchy. The pulldown menu list all the valid types. Multiple types and wild cards are supported. - - Purposes: - USD prim purposes to select when doing a custom traversal of the USD hierarchy. The pulldown menu lists all the valid purposes. Multiple purposes and wild cards are supported. - - Kinds: - USD prim kinds to select when doing a custom traversal of the USD hierarchy. The pulldown menu lists all the valid kinds. Multiple kinds and wild cards are supported. - - Name Mask: - Pattern used match against prim names when doing a custom traversal of the USD hierarchy. Wild cards are supported. - - Path Mask: - Pattern used match against prim paths when doing a custom traversal of the USD hierarchy. Wild cards are supported. - - Traverse Matched: - If this is on, when a matching prim is found, that prim is returned and the traverse will continue looking for matches amoung the prims descendants. Is "Traverse Matched" is off, - the traverse will not match any of the prims descendants. - - Is Active: - Return only prims that are active. - - Is Visible: - Return only prims that are visible. - - Is Imageable: - Return only prims that are imageable. - - Is Defined: - Return only prims that are defined. - - Is Abstract: - Return only prims that are abtract. - - Is Group: - Return only prims that are groups. - - Is Model: - Return only prims that are models. - - Is Instance: - Return only prims that are instances. - - Is Instance Master: - Return only prims that are instance masters. - - Has Clips: - Return only prims that have clips. diff --git a/third_party/houdini/plugin/OP_gusd/obj/pixar-usdcamera.py b/third_party/houdini/plugin/OP_gusd/obj/pixar-usdcamera.py deleted file mode 100644 index 043c50ea61..0000000000 --- a/third_party/houdini/plugin/OP_gusd/obj/pixar-usdcamera.py +++ /dev/null @@ -1,40 +0,0 @@ - -# This script will be run every time a usd camera node is created. - -node = kwargs['node'] -if node: - - hou.hscript( 'obj/cam.cmd ' + node.path()) - node.setName( 'main_cam', unique_name = True ) - - frustum = node.createNode( 'pixar::camerafrustum', 'frustum' ) - visibility = node.createNode( 'visibility', 'visibility' ) - merge = node.createNode( 'merge', 'merge' ) - - xform = node.node( 'xform1' ) - merge.insertInput( 0, xform ) - merge.insertInput( 1, visibility ) - visibility.insertInput( 0, frustum ) - - node.layoutChildren() - - visibility.parm( 'action' ).setExpression( "ch('../displayFrustum' )", - hou.exprLanguage.Hscript ) - - merge.setDisplayFlag(True) - xform.setRenderFlag(True) - - # Lock all params in the Transform folder - for parm in node.parmsInFolder(["Transform"]): - parm.lock(True) - - # If a site specific customization file exists, run it. - # A Pixar we use this to set default values to point to a - # shot specific USD file. - try: - f = hou.findFile( 'scripts/obj/pixar-usdcamera-site.py' ) - if( f ): - execfile( f ) - - except: - pass diff --git a/third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.png b/third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.png deleted file mode 100644 index 0cbbb5f77be120233ee10a5aa862189ecb7d4717..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6921 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 P00000NkvXXu0mjfcZ8au diff --git a/third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.svg b/third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.svg deleted file mode 100644 index 755d40834d..0000000000 --- a/third_party/houdini/plugin/OP_gusd/pixar-camerafrustum.svg +++ /dev/null @@ -1,8515 +0,0 @@ - - - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - 2007-10-30T20:20:41Z - 2007-10-30T20:28:56Z - Illustrator - - - - JPEG - 256 - 208 - /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA -AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK -DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f -Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA0AEAAwER -AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA -AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB -UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE -1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ -qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy -obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp -0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo -+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 -FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWE/mP+cXkT8vrQya9fA3 -zLyt9Kt6S3cnhSOo4Kf5nKr74q+Y/wA4vzW/OPzT5Yl1Sa3byr5OnkW3h05HZbq5EnIgzPRXZKLu -KIpFNm65iQ1uKeU4om5gWa6NpwyEeIjZ9pZltTsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd -irsVdirsVdirsVdirsVdirsVdirsVSvzJ5p8veWdLk1XX9Qh06wi+1PO1Kn+VFFWdj2VQScVeA69 -+e35g/mDPLpX5V6e2maMGMVz5sv14mnQ+gpDBPuZ9waJmBru08OmF5Dv3dT8PwG7FglkOwW+Ufyg -0DQro6vqcsmv+ZJW9SfVr4mRhJ3aNWLUP+UxLe+cTr+382o9MfRDuHM+8/j4u40+ihDc7lIv+ckP -/Jer/wAx0H/EXzK9mP8AGD/UP3xY9pf3Y9/631jndujdirsVdirsVdirsVdirsVdirsVdirsVdir -sVdirsVdirsVdirsVdirsVdirsVdiq2aaKGJ5pnWOKNS8kjkKqqoqWYnYADFXh/nb/nJe1Oov5b/ -ACy04+bPMRqpukB+oQ9uRcFfUAPU8lT/AC+2U59RjwwM8hEYjvZRiZGgxLTvyh1rzHqieYvzU1aT -X9UG8OlqxWytwTXgAvEEeKoqr48uucT2l7VmVx04ofzjz+A/X8g7LDoRzn8npUNrbWtultaxJBbx -KEihiUIiqOgVVoAM5SWSUzxSJJPUuziABQWPlsWwPJv+ckP/ACXq/wDMdB/xF86f2Y/xg/1D98XA -7S/ux7/1vrHO7dG7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8 -1/Mz8/fJHkVm09pG1jzISFh0OxIebm32RKw5LFWvQ1bwU4CaV5Vd+W/zb/NiRbrz9ev5a8qFg8Hl -eyPCWReq+vWu/TeSpBrREzke1Pa3DhuGD95Pv/hH/FfDbzczFpDLeWwej+XPKfl3yxpy6fodjHZW -wpz4CruQKcpHNWdvdjnB6vX5tTPiyy4j9g9w6Ozx44wFBMHyqLaEO+XxbAh3y+LMPJv+ckP/ACXq -/wDMdB/xF86f2Y/xg/1D98XA7S/ux7/1vrHO7dG7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F -XYq7FXYq7FXYq7FXYqxzzv8AmJ5P8kaYdQ8yajHZxkH0IK8p5iP2Yol+N/oFB3IxV4de+fvzk/Nx -mt/J8D+S/JUlQ2uXFReXEZNKxFaEfKIgdjJ2zQ9re0Wm0W0jxZP5o5/H+b8d+4Ftx4ZS9zK/If5P -+TfJSetY25vNXavravd0kuGLfa4mlIwfBfpJzzXtP2i1OtNSPDj/AJo5fHv+7ydjiwRj72YSdM1M -XJCGfL4swovl8WQQ75fFsCHfL4sw8m/5yQ/8l6v/ADHQf8RfOn9mP8YP9Q/fFwO0v7se/wDW+sc7 -t0bsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqG1PVNN0qwm1DUrqKysbdec9 -zO6xxoo7szEAYq8I8xf85DeY/NeoS+Xvyd0ltSuFPC48yXSFLSAfzIsnEfIydeyNmJrNfh00OPLI -RH3+4dWUYk8neUfyCsY9T/xJ5+v383eaJCHaS6LPaxEdFSN/7wKTtzHHwRc807a9sc2YGGD93Dv/ -AIj/AMT8N/NzMenA57vVSqqoVQFVRRVGwAHYZxAJJs83LCg+XxZhQk6ZkRZhDPl8WYUXy+LIId8v -i2BDvl8WYeTf85If+S9X/mOg/wCIvnT+zH+MH+ofvi4HaX92Pf8ArfWOd26N2KuxV2Ksc8/+ffL3 -kXy1ca/rsxS1iISGFKGWeZgeEUSkjkzUJ9gCTsMVfON555/PD8xK3yat/gny9NVrKzsgxumjO6s8 -oMchqO/JAeoTFUOmhfm5pzi50n8ydVluU3WLUJJbiJiOlRLJMtP9gcVZ3+XH/OQ+swa9beUPzPtI -9P1S6YRabr0A42lyxPFRIPsozH9pdqmhVcVe/Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXkH5hf85H+ -WdCvv8P+VYH82+bZW9OHT7CskKSeEsqBqle6pU/zccjOYiLJoBWGWv5R+ffzDvotb/N7VnForerZ -+U7F/Tgir2kZCQppseJZyP8AdnbOU7T9phC44BZ/nHl8B1+P2t8MN83sOj6JpGiafFp2kWcNhYw/ -3dvAgRBXqaDqT3J3Oee63UZM0jKZMpeblRAHJGHpmmzNoUnymLMId8yIswoSdMyIswhny+LMKL5f -FkEO+XxbAh3y+LMPJv8AnJD/AMl6v/MdB/xF86f2Y/xg/wBQ/fFwO0v7se/9b6xzu3RuxV2KuxV8 -n/mFqrfmV+dF1bSN6vlTyQxtooP91zX3KkrMD1/eIV8OKD+bFWU4q7FUi86eVLLzPoM+m3ACykc7 -ScipimA+Fvl2YeGKvSf+ca/zDvfNPkmTSdZct5k8sS/o7UuZq7otRDKx3qSEZGNd2Unvir1vFXYq -7FXYq7FXYq7FXYq7FWE/mR+cXkX8vrQvrt8Gv3Xlb6Vb0ku5fCiVHBT/ADOQvviryG4/5XZ+ctfr -rP5D8hzVpaJy+vXUfg9fTdlYePFKfsvmt1naePDsPVL8dWUY29M8i/ln5N8j2P1Xy/YLFK4AuL6T -95czU/35KRWnfitFHYDON1+ty5z6zt3dHIjEBk7ZosraFpzV5WYWnpmszNgUnymLMId8yIswoSdM -yIswhny+LMKL5fFkEO+XxbAh3y+LMPJv+ckP/Jer/wAx0H/EXzp/Zj/GD/UP3xcDtL+7Hv8A1vrH -O7dG7FXYqkvnbzAvlzyfrevGhOmWNxdIp/aeKNmRf9kwAxV8tfk7pr2vkuG8nq13qsst7cSMasxd -uKkn3VQ304qzjFXYq7FUj/LG9by3/wA5HfVVPGy84ac6sp2T6zApkB/1qW5/4PFX1HirsVdirsVd -irsVdiqV+ZPNPl3yxpcmq6/qEOm2EfWaduNTSvFF3Z2PZVBJxV4TqP5y/mX+ZtzLpP5T6Y+l6GG9 -K783agvCn83oqeSqfkHfcbJleTLGA3VkX5f/AJCeVfLF3+mtVd/MnmqRvVn1jUP3nGWtS8MbFuJr -+2xZ/cdM0mr1k5bDYMwHpZzQ5W0LTmtyswtbNblbAtOavKzC09M1mZsCk+UxZhDvmRFmFCTpmRFm -EM+XxZhRfL4sgh3y+LYEO+XxZh5N/wA5If8AkvV/5joP+IvnT+zH+MH+ofvi4HaX92Pf+t9Y53bo -3YqgdW17Q9Gg+savqNrp1vv++u5o4E26/FIVGKvCv+ciPzp/LvUPyt1zQtD8wWuoaxfCCKKG1ZpQ -U+sRvL8agp/dhv2sVSny3aLZeXdLtFNRb2kEQPjwjUV7dcVTLFXYq7FWET3r3/57eQrHREa71PTb -z1NTWGh9K2kaMyF2Ow4Qh2YeFO5xV9fYq7FXYq7FXYq7FWI/m15u1Dyf+XWt+ZNOjilvtPhVrdJw -xj5PKkdWClSac60rirx7yR+TNz55j03z5+Z+sS+ZLnUbaK9sNJBaOzgiuEWWNWVeHQMKogVa9eWV -5JEIt7ja2lpZ20VrZwx21rAoSGCFQkaKNgqqoAAHgM1eYsgqHNblZhYc1mVsC05rcrMLWzW5WwLT -mryswtPTNZmbApPlMWYQ75kRZhQk6ZkRZhDPl8WYUXy+LIId8vi2BDvl8WYeTf8AOSH/AJL1f+Y6 -D/iL50/sx/jB/qH74uB2l/dj3/rfSvnLzp5c8m6DPrnmC7W0sYfhH7TySEHjFEg3d2psB8zsCc7t -0b501f8AOD84PzFLDywo8meVpKiO/cc7+dD+0rfs+P7vjT+c4qkVt+Tnl6W4a98wXd5r+oyUM1ze -TvVmHf4Tz/4JzirIbXyN5NtePo6JZAr9l2gjdh/smBbFU8AAFBsB0GKuxV2KsF88+dr+G+Tyt5YT -6z5luxRnG6WsbCvqOTtypuK9Op7AqpX5G8tfnP5IlvJ/L2qaPBd6ga3l5MjXE8m9aGSa3dgOW5A6 -nc4qy3/F/wDzlB/1Mmj/APSOn/ZLiqVeYfza/wCcifLUdld6rr+nTWtzdxWhS3tomesgZt+UEe1E -PfFX17iqje31lYWkt5fTx2tpApee4mZY40UdWZmIAHzxV5BB/wA5P+S9V/MDSvJ3lq3l1U6hci2m -1Yn0bZNiSYgwLy/Zp0UdwTir2XFXmv8Azkj/AOSS80/8YIf+oqLFUZ+Vv/ksfKH/AGxNO/6hI8py -sGStmtytgaOa3KzCw5rMrYFpzW5WYWtmtytgWnNXlZhaemazM2BSfKYswh3zIizChJ0zIizCGfL4 -swovl8WQQ75fFsCHfL4sw8m/5yQ/8l6v/MdB/wARfOn9mP8AGD/UP3xcDtL+7Hv/AFqfnLUX/ND8 -3tTe+b1vKXk6VrHTrPrFNcg8ZZG7NyeMk/5IQbite7dGy0AAAAUA2AGKt4q7FXYq7FWD+evPV1Z3 -Uflvy3H9c8z3nwqq0ZbZWFfUkrtypuAdgNztQFVH+RfItr5atZJppPrmt3nx6hqD1ZnZjyKqW341 -+knc+yrKcVdirzv87nSPy9pDuQqJq9uzMegAilJOKvefOX/OSP5W+XNIXULbVYNekMqxfUdMmhln -AYMfUKs6/COND88VeFXvmDzX+d142p65cHTPJNrOUsvL9q5/eMlDyncU5tuPiI/1QvXFUXb6Vpul -/nB+WVnp1tHa20d3PxiiUKK0Tc+JPcnfFX15irzX/nJH/wAkl5p/4wQ/9RUWKoz8rf8AyWPlD/ti -ad/1CR5TlYMlbNblbA0c1uVmFhzWZWwLTmtyswtbNblbAtOavKzC09M1mZsCk+UxZhDvmRFmFCTp -mRFmEM+XxZhRfL4sgh3y+LYEO+XxZh5N/wA5If8AkvV/5joP+IvnT+zH+MH+ofvi4HaX92Pf+tJf -yOJbypeSykm7k1Gdrst9r1eEda53bo3omKuxV2KuxVhXnvz3Nps0egaBH9e80X3wwQLRhAGH95J2 -rTcA7U3O3VVFeRPIsXl2CW7vJfruv33x6hfsSxJJ5FEJ34179WO/gAqyvFXYq7FXnP54oknlvSkc -ckfVrdWU9wYpgcVSL86vKflvSPKtrc6Zp0FncPfRxtJEvFihhlYr8qqMVT/8if8AlBv+jub9S4qn -N5/5Oz8tf+Yyf9SYq+ssVea/85I/+SS80/8AGCH/AKiosVRn5W/+Sx8of9sTTv8AqEjynKwZK2a3 -K2Bo5rcrMLDmsytgWnNblZha2a3K2Bac1eVmFp6ZrMzYFJ8pizCHfMiLMKEnTMiLMIZ8vizCi+Xx -ZBDvl8WwId8vizDyb/nJD/yXq/8AMdB/xF86f2Y/xg/1D98XA7S/ux7/ANaj5y0uX8qPzS1CO7Ux -+SvNsz3un3lP3dvcseUkTU2UKzU/1eJ7NndujZdHIkiLJGwdHAZXU1BB3BBGKrsVdirDfPfnttHa -LRtGi+veZr74bS0X4vT5f7sk/WAfmdsVVPIXkVfL8U1/qEv13zDqB5396d6FjyMcZP7Nep/aP0AK -suxV2KqV1dW9pbS3VzIsVvAjSTSsaKqKKkn5DFXm9v5l/MPznI83lZYtF0FWKR6ldKHlm4mjFFIk -X/hf9lXFUi/MDQPzQg0mOXVL2LXdKsbiO8doY1jnj9IMOTKqLVKOa7tTrsBiqE/Nb8x/LPmfyxaW -emSS/Wku47iSKWMpxURSKQW3WoLjocVZj+RP/KDf9Hc36lxVObz/AMnZ+Wv/ADGT/qTFX1lirzX/ -AJyR/wDJJeaf+MEP/UVFiqM/K3/yWPlD/tiad/1CR5TlYMlbNblbA0c1uVmFhzWZWwLTmtyswtbN -blbAtOavKzC09M1mZsCk+UxZhDvmRFmFCTpmRFmEM+XxZhRfL4sgh3y+LYEO+XxZh5N/zkh/5L1f -+Y6D/iL50/sx/jB/qH74uB2l/dj3/rfTfmnyp5e81aLPouv2Ud/p1wPjikG6sAQHRhRkda7MpqM7 -t0b5z1z8jfzV8gSvN5Euh5o8tAl/0Ldsq3cK1qVjJKq238hFT+wcVY7B+b2kWt0bDzPp975c1JAP -Vt7yCSgPSgook/4JBiqt5h/MzTlgtrLyqya75g1NxBp1la/vaSNsGkC7ildl6n5VIVSj8kdPhutL -vfM15W51q+uZI5buTdwihTxXwqTvT28MVenYq7FXYqwf8555ovy+v/SJX1HhSQj+QyrUbeNKYqyz -RrO1s9IsrW0ULbQwRpCB04hRQ171xVEGW3aRoC6NJSrRVBbifFfDfFUi/ID8v/K/nHSPPPlbXLQ3 -OgadrqzaeqO8RVwJY6LIhU04Iu1cVWebvyh87flRdz6t5MSXzF5Ilb1LzR2q93aV+0y8RV1H86jp -9tdueKsc8v8AnLQ/NH5v/lxc6XKzGK8lFxBIpWSJmVSAw6djupIxV9nYq81/5yR/8kl5p/4wQ/8A -UVFiqM/K3/yWPlD/ALYmnf8AUJHlOVgyVs1uVsDRzW5WYWHNZlbAtOa3KzC1s1uVsC05q8rMLT0z -WZmwKT5TFmEO+ZEWYUJOmZEWYQz5fFmFF8viyCHfL4tgQ75fFmHk3/OSH/kvV/5joP8AiL50/sx/ -jB/qH74uB2l/dj3/AK31jndujdiqB1fQtE1m2+q6xp9tqVt19C7hjnjr/qyBhiqQ+Xfyn/Ljy3rT -a1oWgWun6myNH9YhVhxV/tBFJKJXp8IG23TFXzL5O/LT/nIzyto/6LtfJlvcReq0vqS39kGq4AI+ -G5A7Yqnv6A/5yX/6kW0/6T7P/sqxV36A/wCcl/8AqRbT/pPs/wDsqxV36A/5yX/6kW0/6T7P/sqx -VL9f8i/85Fa5o91pV75EtTb3acGK39nyUg1VlrckVVgCMVSWw13zv+W1lb6L+YugXlrbwqqWWpwi -OeL06UWNpImaJinT4X5dKjvirBLCw80eYvzJudR/L2G81e7uZZZYpvRKrCZ1YFZHc+miRhqKXIHT -FX2p+TP5ZQ/l35Kh0ZphdancSNd6teLWklzIAG48vi4oqhRXrSu1cVZ1irCr38nPy8uvN1l5vTSk -s/MFlP8AWVvLQmH1X3r60a/u3rXdivL3xVmuKvNf+ckf/JJeaf8AjBD/ANRUWKoz8rf/ACWPlD/t -iad/1CR5TlYMlbNblbA0c1uVmFhzWZWwLTmtyswtbNblbAtOavKzC09M1mZsCk+UxZhDvmRFmFCT -pmRFmEM+XxZhRfL4sgh3y+LYEO+XxZh5N/zkh/5L1f8AmOg/4i+dP7Mf4wf6h++Lgdpf3Y9/631j -ndujdirsVdirsVdirsVdirsVcQGBBFQdiD0IxVbFFFEgjiRY41+yigAD5AYquxV2KuxV2KpB598n -2fnLyhqflm8nktrfUoxG1xDxLoUdZFIDAg/EgqPDwxV4RDrn5vfkpDDp/mex/wAWeQbRVhtNasVC -z2tvGAqLIn7IVQNpNuwk7ZCcLRT13yd598p+c9NGoeXdQjvIgB60Q+GaFj+zLE1HQ/MUPauazPAj -myCfnNXlZhYc1mVsC05rcrMLWzW5WwLTmryswtPTNZmbApPlMWYQ75kRZhQk6ZkRZhDPl8WYUXy+ -LIId8vi2BDvl8WYeTf8AOSH/AJL1f+Y6D/iL50/sx/jB/qH74uB2l/dj3/rfWOd26N2KuxV2KuxV -2KuxV2KuxV2KuxV2KuxV2KuxV2KtOiOjI6hkYEMpFQQdiCDirxbzz/zjXpdxqR8y/l5fN5O80xku -ptiUspSdyrxJ/dhqCvAFfFDgMQRRVj+k/nj5m8oalF5d/OHSH0q6b4bbzFbJzs7gDbmwjqPmY607 -ouarVdnk7w+TISey6fqOn6lZRX2n3MV5ZzrzhuYHWSN1PdWUkHOazxMTRFFtCsc1eVsC1s1uVsC0 -5q8rMLT0zWZmwKT5TFmEO+ZEWYUJOmZEWYQz5fFmFF8viyCHfL4tgQ75fFmHk3/OSH/kvV/5joP+ -IvnT+zH+MH+ofvi4HaX92Pf+t9Y53bo3Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqgN -d0DRNf0ybS9asYdQ0+cUltrhA6GnQivRh2YbjtirwjWPyK89/l/eza5+T+qvJZMxluvKN+/OGT2i -dyAxpsORVx/OemY+o0uPMKmP1pBpNPI35/eX9avzoHme2k8qea4mEU2m39Y43k8I5HCUJ7I4B325 -dc5HtHsXLjuUPXH7fl+pvhkBeotnKZW8LTmryswtPTNZmbApPlMWYQ75kRZhQk6ZkRZhDPl8WYUX -y+LIId8vi2BDvl8WYeTf85If+S9X/mOg/wCIvnT+zH+MH+ofvi4HaX92Pf8ArfWOd26N2KuxV2Ku -xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KsR/MH8qfJHn6w+reYtPWWdFK22oRUju4f+Mco -BNO/Fqr4jFXjFzov51/k2C1kX89+QoesJ5fXrSIeAHNwqjw5pTsmaXtLsPDqd/on3j9I6/f5tkMh -D0LyD+a/kvz1a+pol6BeKvKfTJ6R3UfjWOp5KP5kJX3zzjtXsjPpT6x6f5w5fs+Ll48gky49M5jM -3hSfKYswh3zIizChJ0zIizCGfL4swovl8WQQ75fFsCHfL4sw8m/5yQ/8l6v/ADHQf8RfOn9mP8YP -9Q/fFwO0v7se/wDW+sc7t0bsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVe -U/mR/wA47+UfNd0db0h38s+bEYyxaxp9U5y9eU0alAxr1dSreJORlESFEWCrAE/Mr8zPyxu4tK/N -XTG1DRmYRWvm7T15o3YeqAFBPsQj7E8X65w/bPsXjy3PTHgl/NP0n3fzftHucnHqCOb1nQ/MeheY -dNj1PRL6K/sZfszQtUA/ysPtKw7qwBGea6rRZtNPgyxMJef6Oh+DnQkJCwinyMW0KEnTMiLMIZ8v -izCi+XxZBDvl8WwId8vizDyb/nJD/wAl6v8AzHQf8RfOn9mP8YP9Q/fFwO0v7se/9b6xzu3RuxV2 -KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KqN7ZWd9aS2d7BHdWk6lJ7eZFk -jdT1V0YFWHscVeF+af8AnHDUNE1GXzH+UWrP5f1Q/FNosrlrGcA1Kjlz4+yuGXw45i6zQ4dTDgyx -Eo+f6DzHwZRmYmwlnl789Gs9UHlr8y9Mfyp5iSi+tKCLObenNXPLgpI2bkyf5eed9q+xuTFc9OeO -P83+Ie7+d9h97nYtUDtLZ6iJY5YllidZI3AZHUgqQdwQR1GcjwmJoiiHOiVF8ti2BRfL4sgh3y+L -YEO+XxZh5N/zkh/5L1f+Y6D/AIi+dP7Mf4wf6h++Lgdpf3Y9/wCt9Y53bo3Yq7FXYq7FXYq7FXYq -7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUj84eR/KvnHSm0vzHp0WoWpr6ZkFJImP7c -Ugo8bbdVIxV4Pqn5T/mv+V0kl9+Xl4/mjyqrF5fLN58VzEnU+hSnM9f7uhJ/YbNR2l2Jp9YPWKn/ -ADhz/b8W7FnlDknHkb84vKnm5/qSs2l66hKTaPefBMHX7QjJoJKUPT4vFRnnvaXs9qNJcvrx/wA4 -fpHT7vN2mHUxntyLNHzURcoId8vi2BDvl8WYeTf85If+S9X/AJjoP+IvnT+zH+MH+ofvi4HaX92P -f+t9Y53bo3Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXn -35mfkb5F8/objUbY2WtqB6Gt2dI7lSv2eZpxkUeDCo7EYq8c1C4/OH8o29PzVbv5v8mR7Jr9qCbm -CMGgM4NWH/PQ0rsJDnNdpezOHPcsf7uf+xPw6fD5FzMOslHY7hnXlnzl5b802H13Q71LqMU9WMfD -LGT2kjPxL9I37Zw+r7PzaaXDkjXn0PuLt8WaMxYKZPlUXIDyb/nJD/yXq/8AMdB/xF86f2Y/xg/1 -D98XA7S/ux7/ANb6xzu3RuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K -uxV2KuxV2KuxVp0R0ZHUMjAhlIqCDsQQcVeK+fv+cZ9Gv79vMXkG9byj5nUlwbfktlMx34vEv92G -IFeA4+KNleXFDJHhmBKJ6FlGRibDAYvzM80+T9Sj0D81dJfS7ljxt9dgXnZzj+YlOS/Ph07quclr -/ZmvVgP+af0H9fzdng7R6T+aB/5yDvbO+/LOG7sp47m1mvIGiniYOjKVfdWWoOUezmOUNVKMhRED -98W7tCQliBHK/wBb63zuHSOxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2 -KuxV2KuxV2KuxV2KuxVAa5oGia9psuma1Yw6hp8395bXCCRCR0ND0YdiNxir5m/NL/nEzWLbT7l/ -y6v5ZdLlf6xN5XupTT1FrxNvKx4sQDQCShp+2emR4BfFW/emzVP/2Q== - - - - - - - image/svg+xml - - - - - - - - - - - - - - 2007-10-30T20:20:41Z - 2007-11-06T04:26:34Z - Illustrator - - - - JPEG - 256 - 176 - /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAsAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXlP5gf8AOSHkDyrO2mWD v5l8xE8I9K0yktJP5ZJlDIprsQvJh/LgJAFlQHgP5yedvzy1vytJq+vzp5d0CeZLeLy9ZuySOsgY 1uGFXcUXdXalf2BmDg7Tw5cpxwPEQLvp8/i3z004R4pCn2pme0OxV2KuxV2KuxV2KuxV2KuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuJAFTsB1OKvJfP3/OSnkTy1cnStH9TzT5jYmO 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 - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 -G5ASqsaBjJsidU1YsKs1UMAQ+1qgjwKslUUC28Nwjq2F2fG5GjFS0CPDPVBMBP+TKoM4/Xq2F9bE -OWfrRZFZV5cwklAZXqi7ig22OyKWsty8YhqDtcv7ZpQWy0gXQ7ebDfDpmJZTVkO8KpaWQvfjGvxf -eaF9TerDVmw7eTX2RScKeYHAR+OpCbACSnF3OxhO21CbNAb+9EMAib+bKucJMsikw2AVTjLqcH52 -h3HZTzPCyG6jnKViQHeWbj2rTNwyOLNxHuxSyqTgMQesikmFbuakw+SGwdkP5Sd0Ad4aGwvgYoRt -D7Ff+2e3DNaeeyNFLSutS0HrpqWEkOm+LYNhbu4cOnGyDrAm6Y9RqTBrhzkcWgIKqvHOwxSAjUPm -mlrcqDUpzGR3n67Ur8xcjWmemZXFHMVG7qlrqD/jczTFVm4rKXbWtmqOnHg8Aq8MVjUihifHdtkD -2rKGljUnWDqQQql2nsPnqpfMqyw22Wyu5gnTcc0Wx3B/0k4qAMX4+qIkTVJ1ObxfwFM4OVUzydJO -fE7bIDoltIIOV3hrGE+Nj6Ui3ksF4cXeSGXPKgB/k0HwqeuxieNYiyMCfqjKY6WkAx7WziHsyawy -DLeHWLR+eEqQKpaYJQj9lCK5DEyl6j4TYiw43GE9oUDgUJ0aTSKTpO0a12uP+fv0AvYTdAaiTFjt -HLNKJKg3frWtW8IaZyMBIvo6w1we4aWFIoSen0kD7AgxHTFW/pAp/a4QrQl6UipwBdRNK+qIxlog -m1J47i+jltcad4wQVF5NX9/HL5Tnuf7UcrehVMxlJJ1XhnXl/nXCNHXl8UN2krobrUPuHxrrja7Q -vN49H2+UbDhwPtyN2XreJL686zSaQ8fmu5Pb2cnVrkznaNrSwvrfY4g1cPX4eo6rcY9mrssYdmKH -s0+/vh8pmw/KCru0r9Rz9sNsnvb5+/mQ9U3LPd2WfSaklmVfWapt2fOdZc+fLbvf/euWPd5Zdn1n -2T+naLA4v7Ps+bNlX+a+Lbv+bNln8Pyw7PbOsuc7y57vLLv+bNnlnqtu2eNny06nuZtl3/PfR3Oe -a8q27PGzZedzNPsauPjOssfPln3OlsOy28+Wfdnrtuz6zrLnz5Z9Wt3vLdrd6ujyeTIAZClJmnyP -JBiepuL+u4PBJ4Svk7tzXRnWlUdj1NZZTpPxKxH8WPfs5qFBwnRdCRmX4kHj9etdsQtkhXZjsa+f -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 -cvH6vwaQQB+yS/bhikJuSziE3UjctmUeiNm/dukvs09emif9gRwEf8f+yZhQNzHt4LmSKjnkui+1 -+/MRKBpxqSDVrJ0gpVfb6sDhN8s/T4PHWgpFtCuyaXYhWqfaDeTa1wCrhqnAvqWgFfdo4fCTNyQV -qLUV28Q0GePE3gWU8xJxbiWUwXswHCxbVBvfzYXEnduAyR3Yc2MAPcRAbpovnStnhCr++0pYiyRF -ofNG4BNL+AKr8g71O8v2EM9FtR/N2k2jV7XWFHO1Dv9qNGkgAd/rvb/dwbq5HmNk+CcRIjBzuhHv -X8Z7iNrBvEXryI408CTy5puT9nuxvew32aOJKgG9fhPUisxoCHu8s+2meQ+mlvLxh35OrPkc2hUt -ajYbi+jToJ/mR10zUxLU0s23tJikBN761qvUa4pPj0E75RlzyOi5UThyHRFvt7BOiBoVngo1sY+w -R1ZXaCw7iZggr5GxtgOgqLziHae/agTKdu1nTN2KYgq33u8hbs9w73TGGqJZatbWzVPtK6Xp2Qjx -H0TgtJRDnJpUXHkfeP3makhqLMNLH9sVEqMZBC/aqA+Qg+1nxhGo+xTp0s8XkxkNwWvamMp6v4Pv -+819HjtuTi30isSYzDhjNSm4uZb4FRW8eHfDOsvC7KDXbzJvMg5WTgy7ttyCxqK8CwI7FgnpOB2v -p/nrP/tX85c//4tf/uZ/++l//9d/+T/c//6//+3f/9Xv/vn//j//l7/7/e//4Xe/pfWv/uE//NNv -P9v//K9/+9u/+/iHv//l+gtjvPyl/eNv/tOf/at/9n+nX/Ivyf/1N//Z/tf/+Ppv/9fL9p9+ab/8 -T7/87/9H+uXv/+z1//3b1xO+zqEbR+Rtvkij63i/TvzXN/g6LsP87QdzYefbbz+M8mRfw/yWN/k/ -v/7hbVpclLP5f7zWjR2T5Zff+M91rwN3+/MMSNeH7H7IwO7a8y+jqRy8Nlg3euIKxtZuXukf01eM -wJ7CGKHH31/8MeSK/ZemoQPc2Av9Dre7crfbr9puXnxZbs6N7tkfnwEL41//+3/zl7/7/X/3T99/ -/0//8bd/97v//Mt/Y7Y/N/mJ18dw/cUv/+Z//f3v/um3/+GXP/+rv/rL79//+ePf/sff/51d+xe/ -/Nd25X9r/8C9eGPGi89Yk95hZ/ss2G1Hh23qIV2MyG3bHOlQh91wKbC3u/Hi9TjZ1JFoNJ8Mz8gQ -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 -xYjKdYZJu8FX6x2Ui6Z0cLrAC/t+BsDeCoHSycMYrfRfA4fuFLuiCpUKglsEiKh6i0LxFjjXqQs2 -9Q22L9/iqdXoMcuCyrJQQg7G1obd75dO4Webw0HtUP8Zx+1sJOok55dIHHuLmO/aO9LNw4yReJTm -0zrbNGZ9xClvP8qdsAg6UVuI1aLz+jEOH9fFm0zTklgfFcab7cGd2wxFFAFVLekFxIhzFYvlhGDI -yMUCTyEI0kCe99SvHa7SIlWERVgcwHRWCLC/Sps2Q2Lb9b02XEfiEElnbj6T46lQvLnJy4xHCBXT -qPSf8lcu5ioKM+pahh3+ek7ghnbXb3BK9YLGhtAwO2NMt8K4NYwiJ9ssXbh+5NvJaozCXimSYfFH -fNxQPyiXLm5TqHx6b9GX0bT9ZtzzIzzpWgeUt9VMV70FxIlLNlvMZkfYzceWD466VYEtnV5u9SGL -vBw6NDPRQn93CgSLio/i1lrAhEBCLMYiYX5tYLGoqBUT4Jqmdn1rlrwUOgU+o+mYNHZbzXme8Gtw -GRSJR4kQbxAl3k5dVVX+X/JrQlbJH08eR1Tf+J5P2/6tF+7h+nc6ecoLWUB5MLhy+tuo6gR6Bjk3 -xG4jBKwXU70REtcD6/x7byN6kbOtgparLZaMuUhQVISwP5YeMnLYtxcjzvW1P69Sqs8k/fx3D/d/ -eH17//b2/s8XFypnqvX+b376k999zX/nnfzlZ3/859/cvqpN/fQn/2B/fvaP9X/96bcvfvfw8ob+ -/PMvWfx3z/7hs7e1oT8/+/lf717d17+8oP8Qc/vfPfv7n/5k/NffXL16J3/vn/3Dv9y/3f3bt99+ -LX/5D798/frq28Nfvvm3d6+/ePfq5v765m/0+79oX1x/dfvq5eube/ni17fXb28f7q9eH3ZTmnl/ -937+9rGRtK5O32lXu8/qtnl9+8W7tzdv+MP6N63ZfkCvb968e/X2qCFtaTDo9v5wvrh6c/Ob1zf/ -9a7O/rePjopQblsa1V7v9wd3/+7u99dvr76hf/DIyKYtDavv9/6Y3ry9fXv91b/dvjpiUPcPn/HX -WxrbTv///v0f74/9y5vLh7uvH97cvt3ylXd7/+jCfPbw7vX1zT+/vvr6q9vrLa3O7f3hjru9Xzsc -273uuM/7A3n4+ub11duHR5/r9RX8QcbSuv34cXnKfj3i2v/ZluZjcNH/9SMbwl8Ph/CX25dv1y7q -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 -RUWbjwvgqOBZE/fF2nWKHnLgjmj4oRu3l7n4qtDdhM/1bV2RdnCJfD68rUOCsV5W6Vm48n1roR1U -0BSF6faDmpXPvbh10kIjk6dOk9P69uqKVXVz4+Xb8EyruMzPFDKA+ELT7UllD0gMwmF7TrX7M5Uh -zjMa76oMwYMSjCQePz/K/XM8yaJ+W1eow2b6sQ7bQZfSUxPqIon9vNLsbBRujXePVaWdMlbpvr6S -Z40P8lQ74Nt2pUWpAaJPCOYc7rkvtTmL/Yy+GTcCy7Xi8YrIhNZwnTI2VSV4VcPAuvnPPqwklj79 -83/1699/+rO//FdH+vT1N99++5s//PrvPv3H//tvf/urT99+83e/+vNP/w1u++/wD/z/3/zX+Kfd -f/ybv/3973/1u1//6z/8/se///Wv/sff/O6vf/u7v/3jr353/5vlOeA3/t3/8Ou/++s/fvu/fvOj -DP/iV//h738t05+9/+233/6H36ETf/6nf5I+/SX+8Tf/6U//5A9/+ifHp7/8Lf7nX+Ef/xr/wP8d -qB2Of/n//Js/4n/9T9d//T+X7T99qp/+l0//x/+ZPv3dn17X/lcvZF4EsBQWS/n2aK/KZbD/ajwv -hGh4V2lSGd+tAcjNOFFIdi8Eh2OkM0S2RpBBkLUB8Nc2G3vGhsNuP7Eanpt4Z5ZEavyaXeY8iK7J -6C2vR5HdW17PvTWyXtD2c5uRfXv/4C1/9irw/Ir+f173XUJClvr3Te+Sh3DEaNCs113F2f2Q+MVr -O8WE3G40ZA8RfmS/tQNetnOyHtrfu/gjnyTGH/5wiiCkP+SDJEmAgcuPrYMNgrgnsQ2jDf34QTs/ -/lNqAb78lrFePn39yC94OVheDqunMRgr6dOo/fx8ZY3xl5Phaea8Pz3UNqcWKvc0NV/N4aeRuPmK -D2P38/OVbai/nBRPb30tu/8lLLj/8nf45fcf//Afr6af1tx/Zuvu9664oCWcLmN4+CHpm+zV9+C+ -BN4yKz0gxEDd1TBVJ/x81V+79QyurGX1msCoJQcJ4ovKrs1D1D4tr+k/b7dCeaqq1pvYgHDHsg1N -pHavJRlRs0TNzFJOCTKrouCInFeE+ZqX6qPRewB1QxdE327G+yEerg7I1KfjW/7XYW1RgQj6sYfH -UJYCOeJtLvjfD09Z8/6jBBADFcmrHXgLkl48XYjy1mybgaR4D2otUbvJDwfdzlwUrA== - - - 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 -pLBkt2X15LVOdjay2/f5H/6UB60/xz979zDS5P8qvttn8q2+ZOW6lc9bNtmdq37jR+6yzSM3+v// -6O//ejiv9XBe7H89jNf66796+K71yIdv5j7yCY//u4frWo/b9Jn/+2G61KM26+MTH6ZrPfPF27z4 -mQ/PpZ60xc677tA/+uG41ONfuGL1vnts/dSH41qb77zfmw9es8OmD8OlnrTtmsOPPXLdq5/7MFyr -2fPQd5x6wpt2eRiu9eTt15145pnvOGinZz3010oLR5zxvrNP3H/bJzzkl3ri/LqT3/f+M49e1T3k -l9pos90OP+P955765odjagyvP+7s895z9OuXP/SP8AnbrX/nOee888Dtn/aQX2qjTXc55NT3nnHE -bs9+6C81eV2Hveusdx740ofhUhttvvuhp5x2/NrnP6QXUcNpbte3nHTKUasf2gn/iEfwP5610/pj -TnzbXukhvdZf/zX/4/Fb73vY0YesjA/ptf5ObZm0+0GHvWmPB7jWX8BK3fhRf8v/3HSHfQ86YPfm -obzW3z/hif/E//K4F++2uHaPLR675JmP+LNN4sc+8xlqpG267Z777Pmypy955l/9uRbxP21SP1eH -8uh+xz12325uyVMf8bd/5sWekp5XP17//YkvetWuO77o/yx57t/8/Z91sceGLbZItrA/a+udV2yX -ljTZ/uof/hzz+7H18m1eEmw6PKbf4TUrtl569f27f/ybP/1S4aXbbbfFc//ZGjbZetc9Vyx/ylLn -//U//8ufOrLHxa132PHlg+v6sc/fea+9d91y2VK/+MfHPuYf/rRLpZftuPMOy+f+xbU9e/tVb9hv -z5cttV/+7WOe8pTH/uOfcqltXrXLjlvVxVR43JavO/DQg1+/3SZL/OgfnvKc527yP3aaJpfaacVO -L4ujdaLa9U3HnnjUATstNUEev/nznr/ZY/6US22THjdqf/L2699x9ntPfeuum8/+3T9vvuW2L23+ -R+bPY+LLXjXrUhtt9MI3nPKRiz5x7rGrXzz7pT1rq51XvGL4H1zsUdVWS1xqo7DPqRd+9RuXfuK0 -A3d+zqyfPnObPfbZ61XDjF8u8ff0LV9Jl3r8jENP3fOUz17+k59895Jz3/bqWTPkaduuWrd+9Ssf -tMH6+Oe9YsXO2zaz7+0VJ33+R7+98boff+UDh7xyhtf3uJe+/pC3v3nVSx7kwB6d5lfssl07a1ST -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 -P/rcSbtvov3ue/hxR6133dLbeO0hJ5/x7qPXbJOTrNud/J80je/+xSVHic354jd9+NvX3TV1sdt+ -+tnjtt9ol9P/C1/EH274wSfeprtsu3DYSe84YvFlfi4+8eVvPP6Ms05+y67ZxNh8/Sd+egdd6wtH -y7WevuLYi75//T3ja915zSXHb7PRlkd8DvvNhruv+9Z5i/IU53Y95OR3v+MtKwrrPu15+KlnnXbU -aucN7Pye79zE49JrbbTZnid95r9vHF/srl9+8fitN3rOmol5gNXyjp994aTXsiXwxO0PfMdZpx29 -d+FkPHm7A44/48yT1m+XH+JLj7908n1O3teRL9GWzfY69eIrbxxN/Lt/+YVjt9poo+3f8SVZQyd/ -997wvY++mSfURi9ce+J7zj55/fZFAjzuefi7zjr1sNfmhzh30GeuuXvDnT/7zOFboCmsOuXiH91U -Xuyuay4+cuLVPO+gj2N20CbwxVN242Wo2efYs889/bDSRXrS9utOPOO0o/dxS+fC+T+78/7bf3zh -wbmt2vvdl/z45mJZvPNnnzxk8oietvu7v3Yd7uLe3337/fvxF73ZHkeedd5ZR72utISahbe/6/ST -Dtg+O057X/DzO++75YcfWeMMnLj3uy75ye/9xW7/0ccW6YS0/oIf2yfx+x9+/GA2E5+84yGnnfue -Y1aVBtlTXnHgSWecetju9hDrt37+V/fc9/vvneO39cladfqXrro175kbbrnivbvwkR1O+6bNjtt+ -fNFb5YVtse6d7z3rmFWjEES797FnnnXcvmZF7PDub95w3/03X37WK4vT0urTL736jnytm79z+g56 -b5dciwHf/pNPHipv+XlrTzzr9CMXRu7cU3c98uz3n2bea33gJ35yO3V1xshyD2vO+eZv8lO86bJ3 -qxO690W/uMfGdeEhYpP2+x532qmH71GVfWy07dvOO/9Dx8M42eWMb9JK8PvLzxx7Cd3+H73yNj8u -PWF1vtYtP/zYenlA3eqjTz3pza8ee47bHvUfX/j8h97C7zSuOOkLvDXf8r33vHJ03kbPP+HrN9gb -u+WKs3fi1nj4F6/T4dJOJNv5Rv3qI99x7Bu2HQNMdjrl4u9872sfOWbVa1asPPzsL8sMuP2H5716 -fK2N1l58na34t//ko6vk52d952Ztu+9333j3jnLqC9ccecLb9x4HJ577hg9+6+pfXw== - - - c8WXz//A+z92yeW/vI1v/a6fnb8wfa3P/8au9YdfX3rci2mwb/vc1ViZ77n2S8fL6vuk7Q845vhD -V44jYdsc9/mrbr7zjpuv+9mPrrzq2pt1wbn3uq8c9cLRmctP/RZGwPPgU4e+lPzsH96MB3vnzz/9 -VhnKZq99y/HHv+W1o6kxca4uv54+/HvvuuOOu/I6dOuVHz/Q+7/P3Wq34y6+2u0t99505efefci7 -Pv2DG+xHt1354TViTg37HPGO49+088jT3PbYS66e3uPJ6bvsQ+tl/j77hVtvv2L98edNPmZ/xr23 -XPO9b3z36pvz/f3+u++R7/tJOxx44qnHHzBfTg0a1owtfgNtR9/5+DELr97xVa95w2HHnXrOJy69 -4le33V+ccf/dt950612u7aZvn6bf98rJwnfc4gvKYU3e1gzThf/uuv7KSz9+3tlnn/fxz375v664 -6te/v3v2efnvxm+9S77vLfY/+b1nHbtPMx7Wd2+YOSx6jLded9UPr7jiBz+5+tfX33LnlOE2/TcZ -F3/fz3jtkWd/8L1HrywTB9seM/tt6d+9d952yy233XH3H+5f+hz3N3lfvPxssf6Mj53/vrfv/GR/ -qWfve953lhzW//xv4q/sQb0uvOM/Pvepc99SxuO2OupzP7/jj/fxYP/u+uXn3jb5Tl5+xEe//LVL -znvTi/2lNln13m/97t4/3seD/bv/pis+uHLyeX/ka1dccen71xfgiBcccuGPb/vjXTz4v3t+850P -vu30T13+819d9fXz3lhMw/mTLr12yvD7s/7u/t2Pvv3dn11/6y3XfvOcvT2y7xn7vO87Nz64Gfag -/+69/ZZb77r3/nt+962zin2iO+jjV976x3/+p/zdf9N3ztrRX+vFb/v0z/6Cs7D4u+V7793JX+sl -R33+mmmn4C/zd/t/f/C1/lovPeaSX/zRNe5P/LvrZxet84Hhlx790F3rD9d+6SifWFh+5Oeufqie -4f03fPs0F8uhaNJPH6q5seG2H318nQscN+s+9sOHaM6TnXPpSfP5Wk/f+5zLbvgLf8v2d//N3//I -Wjc7tjvpy798qCbHhrt+8cVjX+7W3rd84spbHqqB3Xfjdz/4xux/bbJw5teufcgGdsfVl5z82mzQ -Lz/0gh/c+BfcwIq/P/z22x88+OUWT3nm7qd84WcP1VS874bvX3jsbjkqVe937jeufQDj5s/5u+d3 -37vwhIU+B39fcuh/XP6bh+Ri99169dc/9LbX1Plaz9j1+Iu+91Bc7N5bf3nZhSfvu9yb2ZvtecJF -l//69r/wzL//rht/9s0LTl4cwYHmVp5w/rd+cetfdDbe8/trf/DlDx2z1wvHScXNdj38A1/96Y1/ -ue/snlt/feXXPvHug1ZsttHU3zO3OeCsz//g17f9RYZ23923XPejb1z0nsNet+XsCom09zsu+K+f -/u72P/dq9//h9ht/+d9f/+RZh+39kiUzipvvdvg5n7vs5zfc8edc7d6JI3zVdy+94MzD99rqgXDO -z9xqnyPPu/g7V/32lrv+lMvdf+/dt0887u999dMfOOn/Ze+9o6wq0r3h89f33u++7103zJp734m3 -nRkdnDvd7BzUT4UGBAXBIYgRmu4WGjrRCRgEs6IoS0XFAAaWilkwLhXM2aWCophdBoyYXQoi9FdP -qqpzzj4dCNqOnDt3pqmzT+3ataueqnqe3/P7za6u7A5R3W9o/elL73xi3dsfffH1xu82f7+lZ9Ng -65bvNn79xScfvvPqmkduv3rhidMO3rcUEs3+/M+wqSctvnnV48+/8sY769//8ONPP//62+82b9my -NfOuW7du2bzpG3WXd9985fmnHll1y1XnHjdt1P49zlToN6Rm9hkXXr38zpX3PfjI48+oEyXcc8OG -T4o/GzZ89OF7b7+69qlH7rtrxbJLzp03Z+rI/XqXVrL73geMmTrzhFNPP/Ps8y6+esXd9z30yKOP -Pf74E4Wfxx9/7NGH7r/7lqsuPOeMk2dNGzd80N496bri+yUDBh0w9MCDxzXMOXX+gnPOXXhexmfh -uecsOOOUWXVjhx9QudcOSPHot1flkGHDDjwo63PggcOGDh4Y/wCJJH32AwmlgxtrIJ0Uk2SH6oxY -VWryYQ8ulXarc20HDEvLhrT//e+zyiARt5BUB9N2DU+OIdlpaeNLHaloUF1r1aR6nbaryyvr65qb -6xonF5YPa+yobWnT1++NTZlQ3AjKo4UE4+5IdZB4p8ZKOi5JzVPONHrAJwJJ3DGQbBD9jivCLUC/ -o1PWgXAbSUlcvyIBChbNleBTir3nEPkkcQcwAa6r7iH6rY6oYwFlRB63A9NhANcF3c0qiytilrxS -FaByLFHqeInwDKh7JEHC9GVxwFxWwLwhPLZIstEhnAJOIjLMmpRA83Krr5HMiwojYrPAJ3MsZgVU -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 - - - diff --git a/third_party/houdini/plugin/OP_gusd/pixar-usdrop.json b/third_party/houdini/plugin/OP_gusd/pixar-usdrop.json deleted file mode 100644 index c5cc9b2382..0000000000 --- a/third_party/houdini/plugin/OP_gusd/pixar-usdrop.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "nodetype" : "pixar::usdrop", - - "flagmapping" : { - "3" : { - "flag" : "r", - "color" : "GraphRenderFlag", - "icon" : "NETVIEW_render_flag" - } - } -} diff --git a/third_party/houdini/plugin/OP_gusd/plugin.cpp b/third_party/houdini/plugin/OP_gusd/plugin.cpp deleted file mode 100644 index 49d06538c2..0000000000 --- a/third_party/houdini/plugin/OP_gusd/plugin.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright 2017 Pixar -// -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. -// -#include "ROP_usdoutput.h" -#include "SOP_usdimport.h" -#include "SOP_usdunpack.h" -#include "OBJ_usdcamera.h" - -#include "pxr/base/arch/export.h" -#include "gusd/gusd.h" - -#include -#include - -using std::cerr; -using std::endl; - -ARCH_EXPORT -void -newDriverOperator(OP_OperatorTable* operators) -{ - PXR_NS::GusdInit(); - PXR_NS::GusdROP_usdoutput::Register(operators); -} - -ARCH_EXPORT -void -newSopOperator( OP_OperatorTable* operators) -{ - PXR_NS::GusdInit(); - PXR_NS::GusdSOP_usdimport::Register(operators); - PXR_NS::GusdSOP_usdunpack::Register(operators); -} - -ARCH_EXPORT -void -newObjectOperator(OP_OperatorTable *operators) -{ - PXR_NS::GusdInit(); - PXR_NS::GusdOBJ_usdcamera::Register(operators); -} - -ARCH_EXPORT -void -newGeometryPrim( GA_PrimitiveFactory *f ) -{ - PXR_NS::GusdInit(); - PXR_NS::GusdNewGeometryPrim( f ); -} - -ARCH_EXPORT -void -newGeometryIO( void * ) -{ - PXR_NS::GusdInit(); - PXR_NS::GusdNewGeometryIO(); -} -

    O2EAI+8k!BKkT?Gf1aMBD%n{d5}10uVQ9om*PFH?_46R$%?j?HG0k1~E@ z49j-g?B$Wb!HtozME;vaEAnqcS!*$oNgtI4g*eR2()ErQU1+#wx0UP;HB79FRG=R1 zND4y=4Pcb{#(KHS0*5YDHxefFZdB&Tj3nDdrePuViXiM*Q3gJSocHrECARr5%_a^F zder zZ(uprKR-)GbBp)p?tbp&xA{0>vemkUEv zYa11Ue0-A1(O(Y8;LrmVEPDW@tX?M(FiK(o*vP2bREAQYP^`v+H>%|4?>upWzY(n=}()PiQ_>2 znmRzlfnDk}2pxgCTYx;gk1wBsJxcxQ&HZuc--qAwe?o7j)zcHnBnotd!7Y2o3m79( z6?#(Tt%9G@d4ngHFJ7cUAGSxTUt#JH?zRAFM|rEX8#+aEFH2?uSJm=JL(PMGzpok0Lh@K5s$_dV8-WO=y!CE;Fn+;?# zxD0@LxM5)wL`VixP$kdrnqVWV{yV_1>aK8w+!rS^jPQwXbEv{N1obE870^j794XoE zX9h_-qbCkH3cnTxdiDnzuTb{OF@C0e7@tu*HYE?i^&%y_z8jhAjP{+#ms$G(S1&I4 z?m7cb>;8J@FA~Tg``Hx^S@5f-M6(T%$Z1)zcPabucG~f;t2|<)WfJFBwNx9)U#Fs9 zml4O{X#H6ow$sj+Ez$v! zL2wgFPgoD4y}^83MHBPOxIs1Qyv-xyqbsrcu?*K|0ydt)XgT@dwwkL2XyH7p#D<(} zn?s^^;ej*bfy@%3uO=X_Sx|S63g2CrJ^c=6ZUU?8%#?K`T#5bcc#M8&TF)Ukuw`6U z(rT9i%e3E{0-m`BubHFlZ{eMVdHyJHF?Xt5G+$og6HeQ@z^ofC-Hk8$Ev=pR#|lMR z-Ffp9!`VMekl_$_8mda5FS(6y-maZo3`?mA`VL-cItC=_;X<)1BwlXfF2*B8agMgy zukYgpI(Y18g9I!CVKQ~nAgg6+)W;Gb1|E#J9U&d<8J)#u{chLS47lq>yS%Q%onmUI zli$WFUpYpiTi8p!=g%s*enxoq2SRA&X9J9s(5uljf}y*S39#oFHdHdXj6wBZy{sK5$IMdY)Fum*u-=N019d2wM z78aQ=<@lnvi~pU%#9$y96cRNKI%^Cp9yXaW&+S%Dk1D)c(l3_?Og*`9I}{2y%NQaZ zX@6y!AE4+#yIXb>5`yve!he?P5rc0e&%kjWCLWYnjJj2|5?c(gv#$`{__06(Tx|uM z%R^G|VM0%Y9Nm7IvIjqC*f}f$1G4yYxhrw#tl|wS$D^8QxN3g1VC=SM3!FR8M&_T! zEZ#={9%zvhRlEBVq>}mdExMLf?TP2h=noNY@ClJFDWLrx8h``oyWh1trwJ(k^90pe z;cN86q)OvIKAhdXvz_3^7=e=TS;82%Rtq-aq8q)4%62BmX|d21U+0ZyysI>4&{%$C zP@88R{QZsu6$Yow?ZfU_0!zuK(muoY z%Yei0&+(wg0#=+$!5T?>P|RI`I)Xd5wYfS#M>rq6qlVlpCu6mM4lR^A8C}Ciay)6( zOFC9A;nB4RobSW7*8Ir;U*xn{dUCwpx?M9Nq;h9|NqxyPF=U=p2tOc*o57P#%l%4S z0G)Fn?&FHVK=#)&s$O`S_mU%n+F!T;WCpJrQfMd|$<;6-7o~~6ttjm%%LP5Yk6zR)AUR$D4hx8wXvs2h$n4jg$PcqP`(__sN}f5d`jtI zExe*RmjdT}x}``wB>^2AK^5wGz1Jlmvm#oYno|`27(>&Q&U(rOaC?O_Jf)w{A6cbX z9YC$$zSDF3J_qpT^aL&`+)sO&(a(%mISYF5^$<_bVBv(oYw%tDg$7S%Apj6-7i6H4 zbFe;(OZ}Q1qM3Q&{Nxa!q4xKMnb2Q<-;$S5(mu*>c8lTV5O z6OYWN3=+b*BZIi#Ibb6KyQ0ePC?g{X$QE7#_JopLs}n+?|0q-r1N%z5&o66bYm0-k zsM|+TD5F=3Vp5!e%lba;cB#8^IF%3|?TTNFXk@Mx2ysE}B6hdX#a6I(swgyYF~I{C z(T#F6zl7dB2XnuxoBg2TW}Y5EyfL%@U^I0 zQ9o=rCGwd_0jSOhVVKh4IQj1PP}TZg-&wDG569y%oHf}((rZbr-1HMA zkLrc-D)odZzC#JiWzZzeaWE52zKyV|40gO60{Kd2)G^~4v08t$G*Dv;%vwU0xgF!= z8PiA6n*&=T5<3(aTO&@kao_DiGUkB6QY@F3t^-%OGyGf&C0CH)fU#E#NoWAq!-VJ| ztYDWMA-G=9?^K|{<_Uw61Hj8(bo49AcI__=qzHetc=lHqg6T8IEbV>!276)uUYNtgFB2I7)CijU@3>rKF`4`KJLjoQg}P_H46r23 zEwhw~)PjL3Er#MZB6uj^u*AmZ2i)o?55s=3H2#ow0kl~)aP#)%p6JDBelcz^KPb9A zB~!$*@CJ0bz_Z=hGmo*9es57*3*rmRK4%uIu!GWWU3RmM);&4zRly+gJ_Cc^0_pS!C7WwtUwWOx*lH+esDPC6o3Ge!mKXr_emW$M ze^|U3_JPLb#ty#31}OsL+5=0jp$8obq_DG7f5vTj+`}B)4NVc*F9kaMcmei^^$YLa zc5S_77~>XSg>TPeyq$QcO#T$eNqH^bCXn0Yw~eVEFU0^T;&Z+OI5oyn zFSP$@IszfxpaKqCtZwkZ0meQfZN=g7X+9|eaW9)+ej?17l8&&(#msgPewD5>RPZJA zzz5JgB8bvn>~SZ6E#m5MeZe9fT28u2I)lWX`L(;NkIJOmNx=XC)FTa5g$+5#(*v|= z9g*Va=kpS`Ik`dQ7ZM1y&~lnQh1&3i|q^( z;5MP%xqxvv?!>VFo*$)`*!<^ug2lT>9|mGzam7OC!HM{K;WMbR+QS?8*orBRXbN%E zC%&6py2v08k5h@fQLG3%He9>g5aG|a8EUgbrkh`7l{J`n6lSX_ecg)Y{=Fn)jsUpx zh!(Q|-OkkLo?GXGH&lrZ3d#+NN^M(PFFS`YnR6sK{ze}``Ib+U1Jm%mcz0bmc+M&? z+-2LEu70N_@^qu!QH?dZ!<%L+JRXvSh8RMTT0!@{8)Y^VZK``M(f9TZ9w<@1Bw8Z< zuz39TAtm_Jy9j+%OJ-Q^=D1c9;DWm%to~YV}ppZui9E21jAtWjDl~AZCLw)6&1qeFfJlxm)H$ zELl6qLzvg}l3pzX8B922TfeJqkZE^uUIqEfKbVLtu^hkPM4ip%*P3S3I2+<#jjz+_ zg(QM4d5k7=lhCFCY-HyJg1#y=i2FToqTpbt`heV5lVc&*O_KfgK3f566;3QgMhdEf zkiq*sb!0fsa23nX`jB2q_Fmpx$;f%*!tLcWm+&$4ikZ#uxW6O&xsq4xDi^V~$gORt4|@UXO({pp@q3U8Q5pir*r?4^+tq$rc=6!S zi!Vh!;6=Y*2F6u1)-ahok}w*rzpn%Q?q%gewO_o#r#ADkhXK@!#Qp8k@LhB&Xw|Iw zsFvH}`F)j>3m-=|1mEZYE|`D_woBT&zp4rG&AZ0Dst0ESfV%`(<;=%POM@0(G=pl6 zwB5NvkPSSVI(KH@b6D0dq=6fyeP=!+FKovbap5$h=PsY#)R`<*Ln%ZU&T{{i!}L<`vZ7@q!%y0|sP`GFC&I=xJ>sge*W0$0pP* ztwHC2fX$MUZ~XhJYq$nb7MFaD(wvH-&URooqLk=TM)>)-nd>S?LoaqeFsQw|#;??~jnC z`(7c-DM56P#D>%&04|4=z5?B_tw9&zw#TZV4VAF0UVng`&q(kne5zB(bMUjVn;? z3~N+%2)`L6B$X+k1cA9#TC7s2O-6g=^8?pJSj2#i(t!~PeK+=W8LM9y!bvhU# zFp|VnXdP&ldGf3f=Qd;+9Bfc5EAr9POGJ&U-$AjS9ex^50@D~3kc z6n!5zr!YJXUdJy6WUDAVFsb#V_;UI5*Hmwt_!4*%8r&TshNV5cYY~jGpagrGiQyhd zQ!3E%sDEa+Sb;wW50^DF1Kf|V5sNoI(mfNRDG-lOAoXnsm%z6-A0dHk0U}=k7B<;} zJ--^12Uh|!B}Iw11Aq9|yXsY%C~9&Ss$ zXT|f-lUtq_ViSRn;OTWuHp}NNK;9lbC@-d1o5>3)z5_wvIx1iK+PcXbhG-v*h9uv< zG4N>kVKu|bWHC)repj_il`b3#q~GV$;9;$T-)V`EsV0>z{i?Wt!rOm24_-j8U~zR2 z%7SZu4zZmdWF_G8w79PYG5ANn!oBkH1+OD#p#;BNKRcl0!VS+HxIL%(x8}+(c7t;G zpXJ%a-oq(FWAh>Y@*d`-B#72vn>(jA%+ARBV~&3pQs(R}vL^DgVh~5+DNif92l!_0 zrgUJ?1`6M>@rtTmEPwcpk!|&I9v|SE2~}50i_}T{S84!Vw!;#7`)mhr1uck!854|% zQ~&K@x&0-Bmf5H%!S+BLW1Tmx(%nC<#QXFY;qMg8ahYTFR|4M@d8e~HC= z@nWKLG^3XLMsE>fw6FxA4veLIc;7vX@Exk_5x$@1{QUE zJdVgvS)NM~6`}85W5qvp`(U4O)jG6rAb(_YuYC_BErd@u=f@L!Fc3PFRfvVLa{Xp| zw7%`lvpXmTmgZnL&MizVJ zL-t?ojtco%+2daI4jPJ>o$0#Cl=1>Sn-xx&cONYc>->1_?<#8IkVi+Wd#3V3YfpeN z_)8J&eOtlc_GYa#;U94#N7Oo4vu~*66+KosG_p`25}$5DqFAUdf_sWjOKMO?AApWyTH@n2Dbh{>9(l{WS*= zBpt>b-NCRpSSOnY_Wmd&1}{3(7CYxhG_>*Ca-QOyc*vRuG^9P`#yQQ92vwY4mFD32 z-u|?Wy*$aq=&-ve)Z#Jze&s>nGMtw&g=kB|%LecM&0n0l7>dz9IdebX`(%n`WWQ?M zdp_Q(nK(#WmyJi?OAgLPe$sb{jB}AKu5<>|oZQ|Zb>$lIF2#O1+0)Ig_oyJ?whTVX zC8^hz2_35xS|!yc<&PTg*YI`nUdu}4csL&ZTJ`)la)u)pOY)9pSrr*>8AmHWZ--yB zu}m5quG`8OtxWwDopDMjr@Ft?nv$dCOBqlua-z2+j=Y;t&?DGkT@PwM6`*ALfh{H{ z|FNng1kqKO-yc9l+?)gt{-j(7By9X(_03?%u9SY_H>-M&jKu|VH&W}g|BkTe&H%3nhv3hojc8@B#`%HS?27f0wHYw?QFAC9p z3jvcp9A|yX-|pG zEF!$-uDRkEat?yZgy<3uNr;GC?jC@%4OHOKjq*Ab63bJKDdrlPZ;w}4x)eZBLaQK> z@69FY{bhR&O9tJJ6%UBPq1)dfL#J$<)r%V&->tsc>GJGc+pVXNsp_eBp;S{vVNY`J z@@sN>Z^;$8y8&DvFo8={lFm(F__qHC?ebF~?m4l34oV}91MKlTUzE^i@q_OrlW$Wj zVinSqHq{kSY|d(b0XD?i>N^8##o=H>U&@lz_wSVA?@529Sv!d0;}oCTzl*K9 zXWPf_;+oU^vGmae=0$fMJc5c zVaT{8j#>PRgc|!{gDNzHUp=* zGhi&na{9zpFun9n!z&dHUCnh1Rh$J6XxDGp_0Lskn$b44!1I#kUpw?Dmu+7k-@$>;fR{@qG)ER^dr_POBr_q$G=QRem?Y)CMll)e2Iiq_8@ z^9YU**s*Sp4fQgWUw7UnU8LvlxgPps_rAy8d)gN_6xkkc7a97#_*_0~EItbqq{U?) z5~Hr*u9YO|nPF(iH9%*TM9gnbdIo4N$Q3YesW1AwV8iy9>+|o88T3mp!lk;0p7GZ} z3|h$7H6}9hCzC19D)xQ_V<}U(Nn0-Mq(rq%RjqyIrrl{f$V> z{-SKF+<&9=xC%2WvM+gHVkbRG$Yq^fuP)Kb21!C&1t15d`>$}V=aFryFH>BW??PQR%E^5(Dcr7Z zgd6M^SMAa6@u1&{*ZF1Ne<^Q$C{gv4mBy}H^sS%s{(jpCsh0U#EQLHVx88CiZO=3s*!Nz*gg%GJCo()Ca^*VPcvi8G|qPtBDyYlWz%m;@t|Q z`s*uAsu!A5x+h%_YJX$~MpW9oA3Bm%^* zz4dBl{cTdkb5)>?)sL2NA++yfm*_fp+5P-G2s?&Mo`Tb)`j?Zw zT#Q@jg=_X`iv5Yc^Ns#g4lX21Lt+Mj&vWy*1eB)px3L$Nv#XZtWo={}%g81+ie24T z@psks*6;E1ri*9)&6ZoPgz8R z#TWF{k~nP~pFnCBBh3u9FVr|0zqwn$ zZjJS;)a9Z6VT^5@bUGLh(xktXGQ93}pk1mFNB8AB825N2JSS!!?S?)%q-#} zJ24=&6$Q0@Jat%Eu>z>}_e1B$?U1#r1m>;YvOg5r48dNyG8tOW-G`r~^)XLy=%7+wUuiLvn!B&C8Q*5VU<8)h&oNZ>&Id)s~>~>Mf_gu>qmlQs>X^ z_VQHnRce#x46n9)9%Qb>yVX3Ra*NA0|H-OmOG4q4J}m*tE{;zl;v+H^W>bg^w`O_O zkO6H-??UXdI|p1UicMsB5!34RI%UY%5)-u_zi2!ZVc0JnBPx~DvQ`cJfIWTBZ8mSL zReIK?h8dV$0GH`gf!{H6Gn~%XECdj&jOc85R2WR7p?v(4e5}M3-^1PF$k&I^RY&gq zP0n9cK+2>F<(u^CA&(=96PBzKcn<8;@n?C&Bxn!g7PI>n(b?@-wt;i*3wCPfL7nBaqHh=D0e_D@%zH>ipLC{rV?nTo z)4#C<4b`P|#OPZ&U1aHe`LU+`(XR#$#;TU!{6%AFamgT^yFL!WpVPk;XGeA{rlIup z61;vYooi85mJx?*IdZFt_dCfRxGbVW|7sh1;y(p2no0y7LCQ<=g^N|uoB9YiLcQ?D z&QA}@$O;2lu9KOXSp(pa`}gNL(bQePxkxNer0LZ_hbeFDoRh`MMuN`@x#H-P5UifF z!?%TVHm1ehCmO!T9BhdnZLwc3QrdBR%7WS$t(c}V$?kP>``lV&F3DHku0=;-&#GW^ zz{v~vFw1{uZmo{EK{u%My-MP|ux9bkoIe+gZb_yS$<3qXw9v1wukrT0OD$EPUo$1o z;ECd%w(Q^$?ojCW#i!zOM^Ef*Omk?u$h~~|{Mf79$GZ2Ob^b|rHI7HiRYNy5S?Z3} z9Dc}zxo1}@5d`U_`rmM>pVv)t3K2q?sl1c#PcPY5Yfu^PcZvFn(`H7&p}8&rU_UcD z6WzK$>V%E^jEnb^Z1!qy9iF{>J-UOaj%DbJ9+cp_wg_3v*APlU5mvzFK~femXxpQs zPMRIE^zU&$Y5Yxim-ko?E%HMv6Tzwi6Kf4x3twG&B(uGnx*2or{r+jHsj^MN z-OnA$yteAGka7&4&ZUagD4IqX*o2yVq9TY{*58TH`Q%yM@Q&B3??;Bo8XF+622<-- z06WxRrA&WcFP9MDCJ@{h7+MbBCDchcp=V8zjilct`~pk^idq_2&bZTL@GJ$Xz7Xa(LfJK)X6W+@3{BSf-8Ub;tX5YKz$~#%|s>a1$WO*g#Go> z$W>S4*59qs<#z9dHB0r3SA|50>HRkK!L`5uC`N!9<@1`jWCfR0`}6Ioyg>R<-Qz9z z6X69+Y`h7Uk|2u$+vC3$?2G7b-2|t2EOUKQdOQHTYajJvj4hoy6Szc~_9p)cT-(DwSOm`l5D;p1Fi)rQXQjr==vT^&QuV@N4S$;Te zRIh&a-SQit0Gr41#<{-?df;*T-Ied@VpX^c^&IG5>+a9HG8&k<>PNQe!&pQBB3c^v z*AC&W{0j{wJSm|+RVLe>7$;{=Auf{^oOrqs_cT&$@#nhPu*8!rwR_kkJsh@(JvTA- z!M|a%&K>auG_$FurlFKpsi~|O|x*nVjI%M z<}hYO90r7Mft^CDE0ZUl`Hh8o_w6ZqL#DN?-`PF4yhDg4c#gK z`p>^VE$Y$Md4!>2gfGPFMoHh1pXwdVqewrlKctY8BfipX2_ns~JofL)hQ3_B*TJ_s zRL5{4@W(Lm@0_}LP1P*JMt7SlOh|DoyBT-TE7=@*dpxf1ZF)t8KnO#mB<`PCUz406 z`?5pRmderP^2FoLeG}Jt`s5FxR5CRJ57HC8 zI9TiWUg6FVMvnv}VE&LfCeYi5sTzem*#0J9=QmCcK$XcHGH+I6EG=6_Byq`j%@QmKI>TSR9$}2oq7*b__ zo?*D`Nn@7@#?QwM6Uk#5*@-`b6o)53xy2=Zz2(vH)P8JSx_^)tM2_nGd{b0G0fU4O zox>1aiMLD&UHA*g3gP;~ZmV;Tiq##IzCwN$xJB=uzav82*;K?Vm<0H7#D`3O8)tiL z2#h16Sa!de-7in&(Z?RJD_`f7zrN=@QUdcYFQK8X_mv z?qn<~O;{%$V`KH)E_kWDf2L3$!>6XP@Ho6y?!G>&BTOvIbxm?V2!$)RmFw$9kCa0< zntXc;dxFU99cdeYO8&`Sqqz#Vz9Y}5ukS4L%pXc?jlvE$*G>7xx5AAaPF7+@-(?9F z$<0a(PF?F`(1b~zXk?~#gLipW^QVP40OU}%CPykd6<}&ve}fIFQC3f|z?#nM^EX7a zv1CGky!;=H1|XE7HxGEUo@t(hB7fo?q9mLE3sP(elYctnPT*FB@dvB3|1#d^y;UUv zOeq1rh^OEAN0pa)ww@)<$P6Ns>*=XeCzg82a^70I7tPBiC`=E2a&7l{{%IkOjm95o zkkr}zf^g%G&fSF2x&}1cXX&U5p*ecE?5&s(b36HLHnX8@OP6{lKA_<-SA+kv8x4u$ zu|5de0uoB?GKwakD0m);tjdNEBQFh{9kSwan-?IIxgMSC;QS4_O5(PBJx{wM%D^HD ztbDWG==!;R;8{B%IhWaU4%(Q`_>&Li-enp+M#DeRp84akCiu20W4U9v=+pcIhGQ`A zrMp9%`e;}Wmav!P4%0QwJ0J2+szaFI%>5n1+BmHSbt%+)0O{zF??%@UDqwRizI7zv zndasDd5@MzuoHDF?GZ@7093N5(W^2n@9>VZEImRHoTG~v{=Vos z*}=wX!j-?5b`fzem3k@oBEA#U|1U9{?o@fXxm<)v^FFkx!-_CW9EH!)^#8~@G1o8P z3AZ_PxI$HNbZn8Yew+e^Outo^X)Hv~8F4|%IZ5(;nM=&T6_Hxrd*U=Pk&!ZkL@%9?_Q~fkx8V*~zLzgN3)V$nZ5eBy# zQeC7|4Dz4w7sh09!n_*r!^`uLi&)|ww2G)#WhU>&hj^L|t)+FlodE2A^C*4T4{+38Ww?-dnjpb)AR3#!qL+2!qS_*Aufe zt$TY{ski<%;L+{;!9RO?5Zs>xrSFSlfsNk!@^%;zW!IxC8WTmzUWnl)v0Ag8>Atq& zh_0`Pym{Sww&q53D<`3&s%87wm?uCfbCHo-pz(qww^rgh*3v?9rU3XbU(5NFmRpJ% zzxJbX#abWp7Lvp}+Fv`BtU%!9YgE$icqgB@AM1=1LJ{!o;+8i#?J#KjV$(;E8W;PZ zw0}gPSA_Hi?#Q^mH4?dmbIl@CBqnYDWp`}wq_rz6D5J)ue&ov#WFT}n}kS&i;nDf;srYEgDO`qu+LihIpYYKkU6Oi6)P-t*$uWld|hev$3; zBzfH{ug8a3?w9>b*Y&eKF*sWn*o!8L@g2R<`N?%2z^Wj_Ffj3_Aw5)MxzM6UBMQM#*cl1hh+4r^-=e!x7h{G%95O0 zd-`mi;1OnlHYj(zv=*d`d2Tilt)$(v=x4nfWy`)7cDYV}6rzAMA~oL)FSf{G zu4KILnfppld-ZHF(vQt`%1U>1POM?kBPug?TZ93;k@gDA#fx1a5>w@6i{Lqd)JSD%B~ehw6FVK z;;i#*Z1=i)`LY9zYoR=py(N?TqQD6+bMQal2lJdvySt2`4zu}J-t6$z&Y`A2 zbuib#E#G{$r%=W(L!Dd1D}gOI=YrMmlXP(z-{M>$aTAak+jQ1A?k@e`p+RKEd8`@J zPvM)^gob@Qk9eN8r}4NJllL!raoEQ^Xn5D_!cnL9`BwnrEJ?hA-X*|L;)20zydyr9 z^UIdccZfd&L&X(y#dRSF6YG?N!_X`HpjE1)Od^~C^~(309NO>>fUX#Q023hY9p^cnlxMPOhmodx!O%6xe9P||8mbAJXy%Ukhi$&h(}GNZia z)8+wUj2QJ=o=Dr<-A{f$y-*KnPZU7XgyxiIz78f=cFACi?#AtT?yF-uYC-IEd|dwI z8i)c?CSS@SNXY#5j$h>J$Y87O&g&uHE4ARF6$k(^e5p=87$P6>%v#^#>X$McinGek zDefUn8Z&T#qP!Bl&SW7m!!KC31PwjnWPF*9H0* zHjMo64x3<9R0k@`Mq`)+H1@K_I$YKCtn#Wale$kt4FS1%6_AKFD>N2@$sO;SeE)vn zBy?ztczpjnQ9|n_{;Z_zU%X{H83Y{IGvCUgr5;<02VVuSJCKRQc-r|x z9Y;^GDsG_d-wK>pdYTQ#@(2Eh9zOJ|c|HNqN^#7LzEhUWf4Ec^$}_+XzILh_TZ7w5 zT-^hx1v@{yOZrm}teiV$S>AJ2(cH@RMUUluF9-KRmSm97MqNvyaw2-~=MtqF5vA}Q zJ3)=7*t)4~si|@=?=r{Q_n|oD+@I{U6?Vj#X>_DDbn7+yyb?dAS*$g_8JlZWuGzo+ zD@h)(iDNtbI{mRBXHCe&g*vddJ5#gRL584Z%2f~CI%gB>oN=@y?YCL3>ECfQoUP^N zzbp9tP;kP_+qF;4eQZP4-s;oSZl+>hfj*LU$+t3tkquyWjNb1@kV-erE)c9d&cNT8 z278!fKS#=3X5cr2u0dIV&`Nb5i;U(#%&8z;#k^3j=VQC8p3W)1Iqd%NXsh{A>HImL zJ+tMb$$Y+7aI!Cwe&QQvyA20zN$TokAF2CQ``Ii{^0FKvRI?{|Z|%=tET6myYLN&lYT{E_UpWZ}QcCqw#X7z(6Bz<=y&SYN!62 z-7yl=D1WRPXWj`*dNjLNLiL%MvCi85n{Kt_{ItERR_ejcsQ1F)%L}2OCs5X}^+jH^ z60hANK&om4Tq8+|X~csb(CM)MaXTSRKRuEgfTkK&pt#tX9PNko_5dNO;^k?Q$AH@= z4W%CeZ#BN3IFtXL8b4A$w87-5pdK5!`|gWBefK!`^!hOFcAg%u@tfeHF5TlVMfc`p z+~liXwOI}%3IBIfXf&FYEInN8!-Fi=xEOBr@4qLvhsLc&#=aUbzRL=6QXw*L(|CXZ zNqEbRTGz)$!1pejX^-R-O0B(BvVV4>Q{TPtFDT(b?Rrf+PrvU3#N$6vZAz9>5?MU* z2Y)qX#L%wh2+(ETF5&o1qel_*(Bu)M&lbL{<292^wq|UFq?|RHQh4$O7@b5 zxR0dviuRVapgUuTyqNdo4?}cMpZ8caGdI~HJd=^`EyJUo^Fk?jRl{e3F>amGj}x3i zR zUK7w(#6-KWWKg;RKu*ru?wHC{_f3UUJs*0%v_ChCM>}`9R600TxEO%`Mi1<9dO$4` z?uAD9n&3nllwo16`CGr7paY91?@9b7Y~^o}Wkmz0Ub6#DUUfQLP(R$$Us?ps_Q|Jt zA`9p?2^+k-9v+#&{kmmDonQ06V7R#7q==t|anI|W{ML+2WdW+0$6$SSB{t=85fHBTWmvO&L={(f?G=A^cYxf&n z=K}n?<$QpKIgf<~;H{5twEPa7Lkz9$xki}-M}sS=J!340uG{JG^>Ag!qDf~hVcGw# z-{rpJ3JhU4YIz5eNdCPxb+j(RTEzU8hlhv{tx4G<6up1aVVC45gU1U3gW7w5eb+B5PxxZdkyZ4Q{gAKW+N)*Mgb$!T zTWqa-_eH%E;d&MZt!fD$k6SSlIDnAEosUu1k+cFd*?L+L#pNn~8;w5gD@*P65U|(h zMmCNmz|0T#Axc|@WQ(fRG8%Y4Vv{mxx+(GdQ(c=jR(jM@qtZ39U~l-IuP< z<1x`HOXe}nC%H`0EJCkyv5W^T!B%Ywy`As~dY~TGZ{hvoK5qze@Xl5Y<#7jJ*71M{ zyRc%rRWIatz05!1Js!CGlFO3#?jqw{E)yv4S^K@2@7qz8E8*F9w?RZC?ep*B;5}$$ z93=H;2l2us%a6F zXLf6@=w$rq59PDBkZ8+K-0plL*K&G2D_*1CdH{vSe80VY*WzT~Oh?oG{>jB1fw}|e z3&$I8i68myx`%0>r+`Xj2eDT72A5V9gxmBln)acV@Xsv&93MRTEqeX#V^Lt{It5df zy*OIqQ2zZzF73X5I-K#=CR^Z;MXGKJu!M=*dT{xk{2dhaC7B$K1b%aBe(qtAoJbCM zp%2JJYuae6BhuaLe&rKAIKDln)USg&-(7$?ePKF1 zH(+8RtKNIOTMV;Lf$HOZrLkN;Tc=M4?38u6A7kTI?r-^{fp@HgodNFuupE z#=qN6Ql_jFnj<3#Qlneu-!IH${>_S~vird9(V(a_hFaE!$47s^GvN)pk`rcH=!MAD zS!jOJZ7lm5iO+P0!Wh?&^B|n~vq(54fuSz~T|?)57E{W941&GX5hb&|aD*}Tpu7-U z1X@bBF36HL+bSJbqhfG2xK_JixRq3!G(Pk*hYlB$ql25G&<5Hsh=?f{+4=TBp90DB z;CzgI{Zbt6=;Zbfz8)LhW%@#7Y1=yx-+agZ<7P>xb&4<2%Pj4GF0I4G@NQJ4-?3Vt z{bweR?z}$db)Gaso<{D`&FC2D_pF-$j8bC2b*t;^mF#e`ZNx}=&#kW9C`pbO`+U&v zHNBkj1CMGMn@jo0T>SB8ng zUOyPHXVY$WpWnCmF8}bm7h`m$G~_W|8xsZVw1L`qUDs?#3nAM>Mgc$aLRb@D@J~UKq{Gox|<+L7+Fd5M#1j_Nvr#X&z^JdL=d+_^e0kMkF%2w9`-A{2e}>(BegvS(w?GCMg-FkD$546)=q_dT&-X6Ao zMXwT;oR(v-M_ArWq0y1oBRpf2S>QCo?=75DHM0LQzGcmuBymS!jngO$8_Tlq%9`%r zzCCuo&NLpvGxe_213kRt2TIh%a#B;0mCrYoif^Bsuh1?sR;APPHRyGGpCQnBaiNr5 zp0jpan@!!_7A)8?nIib>RGQQt!AX9<$K3N)7}|bbaF4J#T2@#T;gzZIUQ(8keJR11 z^C^S?5u4zN#bI%XXd6?=>3-Y{PQyRtgos8x?A86pS@8kwNe4jSjEc_f{f?#Z2TH(d z0%%ao6W)|a_NJdbTu-@6ha2&}D|e)W(z%mWHws1M)f*lOZqb1PPv{)4*S~cRkvdAD z69EP6uB7l2nxhWiMLC@vvAFF$?@m=L)Zgo0wYx{8b9h|2gLv6LN#xARh4%r?c6n<1L@!%&p_v6)3<(Y zK(#x?pNfUaaM}h%U=icfQNP|N@L}@_8<6sSxL|HB?eEf2qi;aB6)CfCciP;Q?I}Eq zCqIbrMF%Y{PI@%p*)5lk(29M`T=>n)ngxdoa%sb*e+Np?8P96D?>#)_4)=O#iSwHB zNCTS`B0_cmXiLRdrQ_VG;I@Cy>0cfR6B?pAH!cV8x5#*J%5TjA`-|d?`_&EqURV2_ z9<1S`pOuRuBG_AN`5VHlsrAAiO@zfZ70#6`!ylBz%~>$OCKqZ6HuzE`#&+iTzc*%AC>ShK3M z^Cb9pW8-PXU=?)`wZF__@zZr|uhZqk1FFh~+HK*=ZuV~FC*Rf3xQH^W0bvP#OIQeB zvi>u1kb)0H>hFf{@GAyujp6+YN|x+ukJZEEjBSkMg^n%JhcrE-9l0*l+Rvo zecjaDJ;RuCv|T!KkzsnheA~#I$8Yu1l-~=sA91&HZyW(BN>+QoKRTESB1)5@& zt8XfPXTTy}>jKupg9vsv>qTvQCPGt)K0=vurNaGN*PteG)SCU%SWQ_Z;Rj|?MAM93 z3~xw3vALiv?8#lyF3!Iz$i*ba`j6cRnjG_3&r>4dMb+>3`=;QwJ>ipHG_Qrf*NNU> zyJZ}<%)%*t9(Xank5gWA0-O*-(6m?eZ}H1JlkL1%NS$J|*e=KnZHi{1vVb0su&!Pl zBPAK?AA9Go(#f$6{R^mA_64uyM@hGr`*1fQ)rqJdKE3zM>`L)fq3GK5z^C>=HfkgH z>&7Y)KzaL1ym?gi+^ywgTPzgBsg}<8runMh=@BRSd@{REL#xG$y%M=THZar=3~MzN zjnh#U%N`kbD|H{5pDpR@bo2t*WRP@@ZY@zrQGGZJfI3i7Ed8EMjy%xm-}{-)V2s)s zphk}$?{K~NuQr7X=)#03_HbGJKy>3>(zDI{6vTD?+baK=?g+hbzF`rMmI(!N=*e)m z>h`3SK;7?3Si>y7AGWW{B}8@Ny@Ty^{Ud&Q@f`A``R&*T8l8>UY=SV!t*@0{m%~w> zm$2h*Y(8RF8XWHLnBQSy(+K3&APhTmpth2S_hFv%jJfY|e9Vh87cc4AD3|XVALX>52;X; z8l(MUV73!Jd+mKafpHKGP`1q-eWiUXIKTY2xU=~$RF;R>x|c$!+BM_m(xZRaChUMh zT^#v|{TWQ4%wn!?1#k29rjuktF>nZ*nu2Y@>!=TUDC11AJBiK1MZT2bLDSv_tkn1| zZmH1Y(I7(QZI8~6&zn((2>r!moRr`+vd zgNs1{xPkWmcwk0wX*eJ_kgu-{OI*CAberZynO{C=bimq234N5`#Rt zp+fV|Uh=+ty*~sXU}r}U_VJmMPaSA?f%+*rCs&^tm8?XT)jfwCEf(Aa$7Fq2)pryC zEdM)hAv))O##-+I0Z)bntJI0qANqs2M$3M6e{iQ)ekPo2?i#Fn7OkFYh1?@UDdu>@96aVX%GFIfuHQhu9nOD< z2`e~@5vVu@ldY|F=HKGT!n3m+|g?_`mqxSv!Z^J+P_5P2>AdL?Sf)&6+h z5fZ;ikr-{*HMh3gMR`TOOJwN+N8@dt?J9Xyma+fSogei^iZ94#xDh*+XDDG%WDenW z?__|e--X0BDZK4UyodjU+*DG8jwF8whE)(!%W@}0nzRdLcmz%#)paD^K$F>lVu~pcteICA{nq1-qdj(Q?KGbd8 zVShd_{iV2otq8=psmdDOP}w{CsSBsI%2}J^jM2N4pzOYQa!zh7H=~+$_SC-k7I!P4 zRF5n(K*P1GfA2q&k`Eu>iq+@S_kw}i!pJZIT?xPHRcAimJ1x#wo-JsixsKQ;hvf@* zN>#V>~N_D%HEq>(Rdl^V23XWeQ1 z7x|?xFiD@%IJE?ini5i;8~4#17iZbMe;%oez88g97I&t9hTy{zcoz=2{mN=wo%ru@ zWzS#x89sCI`Ik{fR^0hp1K8M_sERYi{XbmvbUy9g+xvZU@5y%%n#leI*QBdC*iQ#M zL+-7)r2+c^Gd&A8Dn5N&fE^EI4{jv3EuxSOMwxktZmm%PAqp^fg(`1?JClTcXA8~2Ef7Y)`=_$^dWGZ?0pB5h(xAV zIGx(JVMIOFY<%JfK&wXV<$-a}12EYu(dPFJS z0CyK7nn?s-bHhCAKGa+_Yt$dNqwgAoGSyX3#(%LTACA|?Z-CJR{_oXDrG7yXGS$VZ zG1pv6JQ22v4OVdRIbimF?|K=`>xAJ39c9x6RYrViJ-dZGgP{NF6EPo7eeU43!gqJl zY0-f2B#HQrNxX`eMR;FcrFs9dKmYydo@Qna+4XwG|A{YI6sJ46MPk*k{t^@ysyu=| z4Kc&D&DEFfPwVg%Q2gcW1C@){vpCA;SjhDsf%ltR^5ZI;JLY{eAHexGSSOvKH2zUT zszQ2=z`$2RVhru)`%fnuMDPBt7jWq*0aeiVA0XKv^rwLlZ|wOmJ2RN;MvzS9q9aRTyrO8#<^87V%_Uf4anJ@PR0ClTpr<^Xp6 zaTxAITVO1P{#G{Q@*hrS!uLiK2sawsb%~+d)1(4|ozgLJJjD$PCCB|Z`Br^Jm+mZj z^+2l>uvXWruB<))q&4SsyCTlyay{#2RS7Q@U+>9EeBUe)ULk8XY_~VWEpDS{LlD=9 z4*vLz5Zn={8Y9b+ZoV=Vwr2&fcVOta1*n<9@Hw4FNNmC~s+~W|5$~TrfZ1d;IHt6^ z%fh9FUOk;5wM~&Tidy57-s*2=*eT<}EHsmnw=Z{tgdj)7s06Yw4`!+AG>Of}gu6~R z7@kLz#AZD)4f4=%rg6qYa@+F1%7q&vHXVH*{&bs^tubNdbV z&iI5-WQq!{nuVD|7jk&_FNHY)9X7PkQ?{{a9R|aGaES!0m>Rx~@vGwovin`I$^Uzf zM@_Y?hMcD~U-rk%Gc4t34nO4k0E|7eqAYhVveYY%G2xfv9>E#cj9N;IiisY=E5FuQ zxN+7x2uj=%i;!vO$NukQ9u;1~R(oixTG#qii{*U*H22s4$cqTdH*N^tes6WDch}z8 zH!+&!E`P?J23~-HW@X(lQYcx1hxvF8GOd>XBMJpMTu^$D2P!5$uj!jMubp zFNZZa!qMq16fs>D@TQ9;e@`Nqc8DUNcrHb(cbG1?emWy)O(*HbA>EHCnmPha8z7a= zn%ix8GUO*qAc;1-KVk3cVa-pIaw%XW{7WytQ`Drp$-JtEV+M7g)Lg! z_)M$cUICKk@|01tw%$JJAlpSU_?4xjgEy7&2ebiuqdx;lnF|MFdv*AItlxVhK+1@*c)R>=4#k$SwECKV4=)!KOYdB*O~tSZtp9!9Li^4WwIC~N z8}vH|VK)aj?+^>RPY}ybI!$k&FOo0j6%%>NI^Djem;7>I3Ig~!%e&{rD zI^vpBtzEJoJn-QwU=uNKGhcm4F0^*XJJVJ_u^4~~*Y!>CEom&6!0`ZXF>$$az&WDom}!n#bn6^kwVwOcf8NbA;49&|S(pjSu(8~|5tn+}h1eemRM5}G z@E}s^^Yf;ld>8Kww1aBG zdFxX(jiuLYe(j$=hbp~$ z0}y2wG6n~@q*^48nx+!~P!oIQk{aXR@5APeyXrQjNKg9mt+0V05YxV9i(I65Yl|cT z{t~rE-p3TnP}%JTy43Dle{~{e(rXg!FSa>3q};u_zV`VT%#xHekyUs+PpGFAjf_(w z?dOZHfj2BBQH-(VU1idPzxxBYm3lQ~UUsH@w!B_(^+?CFT{z~`d>ev*kfNJPT+{X} zJliRvu*kpIy6(t!R||#^s(JGVxqI6kcHgbD!0=yYw`I-$hvWF$U1luGDe-yB~*$w*h7ZlU-v?9T_VVB%XSfMM< zeL4<@)5{`~QS#ZbXJ_wnIVm*!Vv=%fqMRmcD(T^>AA|OQGVVv)@4Q=N89*2m&&+_^ z{rlVahoyqI_rd28Wt<{@2cXB-*^8cYk{Ch?1`iZGGI>it78T#=YyNs2;~)0YZk#2S zz;rW%bT)C4YWQAw`7eRo4Sd7?tTpd#+h58v;+~AQ9LKhF!msEM#Zw!u2}%RUk90Pq z<37{%-M;#BsaT~>{OfLoUpDNV2JkVea=D zMOzUc;Q|Ys1^X5%mzPLg{R>O)6z~HMr$h8Um4DTEOM`fWY`qO{i9h}G5K$-9D`=ea z$VW|$wnv%8U}DM8J^r?|$n*1G$)ZXif=GGB9DaI6F?J%zP!}h|i_F)MtCLZ^O=#3`X`iPl?rPRClNWg|-s_k30 zU(K=M_VMrjJ5?#FuYrCGZc4n=3`x7X46#+<9Bb)t#TYopEGz?Y2(SUyqphQ|`SuQu zcS-cekX3RCPruJ*reCSn$L>Wb*<2E5d|+`P^zae*K!+IDK{a`8gA>#ej-)u@%SnablrQ96j1I z_jq3rE3B_QbxPt^-O^lbhhD||d|OH*vrcdZ{o zYP}LRASS_%Ske-IBn~A`cXJryYWDNVmE`@BH2MDCb+^ddUBBNb=T-X71nXsa5eGf= zYN8E94|>VLk6&AZsV%ezrM$rPOcB3cNG?aYr2Y`9P)hWrC$OGh@yyXXxn>9~ZD6FG zo-?z?*v#R|@z**ZpjX=XR+#OhcpTi{Z|qOw<@eyO9KtLq!9rP_Z7P8#e_2P-<;?!= z+76Ndt~`fO*4sFw;Z9OJ`zFVs;m+_;Qye3HLoGsni@~ca)V{xR3{ix0VIr(nltv>% za5|cQw%qP4yx$_f=#KYtlxv_qbQZ#`G#sE7|4Bnx5==?ss~c*f{&??0`eF4+F5{U! znXYUL&IvFcr2}$}A$EJJXJ7LGZxr?Wj{R7kZtJ$t;152==ZDHcHrv9ztbd<}ps~2m z)$13}u>>3s?f!uw9uW9zEkOGylorZF0yNC5*=8cQb`0j0^FN5;Q zpuLRbefu!RRXRtIti8(h@%$*J^Zh`|2C>LzxX2OK-?RtIya$?E6KgehCQsq*^q7QAT6*K>b42n)QqLqzNq0HW>ekL5;>A&s z2JxJw3})X}&(UMt$=_E>~>0YdaXMxhSI#PRxg z&zwEPI>3GO-RSpz6~*jP5kI(fK}fI#aZfzi52!hQz}>uZwM$nG*A^T@&7F?HgMlQ$ z7CHeTE5;_Wa5VMzE<{{_^|MxY)d^5IJ9YgW%#h36`(IB|f)1Pj&jMU3{JUDe?D;LeFJLd`f#C}vDqN%pDESz|z4x7e=4rdqdYeK6D@Hj6UT033gXk+&bbzRT)@Al?@{K2TCS=Zh2{&r!`)-+`H>C)oV z-NOac$NwreezmJ}7H0=+m|Gh?i;AnDNicH_@O7^ohRwIq2#O1x}XXg*$F0&CV#*k*J4L)YRAg$RU1 zGifbdov80$C1zji zX>)mAztQf<$i#ykFG;5aH0O|?|97GAn`E|msp3$Jspd$N!WDSH`_JIN+oN0 zsa4838K#%F#$0q&cDm3RxXCuWfy~3!=STZ<{iQyiWx-R_!S>s*$}0$${)k%h&dR8(@eV6Ih}qUYqk%L7=k=0j!4}=%Ck`Ic})kF zW7C*nO)S8zlckq_4+iE83P>d8%>>>wJbel*AehmNfko0Kd5>@QDNEjX1{P&T30z9* zERbL7yj<+vMq>7A!*l?@$Kfdw|5%Sv&LxOmfU)4^(yUteCC+=o}U)YfLsCF&h>-D@>aN;(a9bP17?bM}Yr ztNW~o7@x5WsH+>f?&%4kdwM5A6 zo;oILy0fWJ#+TyWKE>K9>@@8B*O4g%>y4Z~bdOQcG&gJCWv7brFFX3ZosJtd<{Syk zF)eDO&JWTUDROD-ji7@ru9g=8<&7mSbHRDe!|xQQo*+w6MK`O-vF8KzedBIvk&b^+ zjEzwMmQ`FHYY-tv+Q6F~cmh4uTlw1wl)0$SS-SMlUA8|{4$s^B`-e7_m!4aY(YwE7 zcP)F3eI0@B-cWo7^^;4Wa$L?l5N2dpSY{6S3D2L3uaca&vAovb`=dJUHTJ$}9C3L= zz`>EPhvQ8k&OctC?@lXj1I8u?d}H>Ps&0TO&483of-M8UCwYcXbKe zhrl@ooMTt_mp84uCGF>(c)X;o;$J9ZCvF}Zzzf>PsV`;kv}eq`>D}!y>OcWa)o$4B zl2Q|dUDMRwf-a{X`HS(+lg#*PU9VgLT00)B2IuU>2sdA(Wl#Lh#PQ?B0?>6<#9oGW^k8RG#$G zd*iFtbo=|mInuZe0`$_{7khzEfDR#Hor@{;6!s_a%6l{f-)@Ry_Hcqu*}IR@+W7BO zsEunxnn2{JhV>J@e1wGW>>ch2mYTcIS;>-VY_`f9k=hH*Q}8D~wl^B~a{954yz3NR zrf@tD!Y1Sxwkv)Oei$y*z1HQuFO?^=2m_s?>Hj&zZS`@sZ z$CO-8c#(yE^_|mxrBv-cU+OUhG}0F}&-g1!pqbI&b+u&uuS4-4ZT50Qfn_Q;W5^>K z!fRVxBu?iXXx8P!GutOj0-fu7Fksg=_v?1|j z_(SbqOOpC^(w_az71!REKFYc4r@hw%BZ-f}}g7 z1JNhs_jH-;o=-dguF5GxX>se8?De|2vSrU+I|)rqC*;VMK0QRatf^18Jeu**Og%|? z^W|;l+_yQzEu}Pf>)}84C(4~D(!aNr$bH!!_~2=C$ayM~DQD!aNTt3<^8!0&wnAlb zyV!kb9E2tRiQ{aSy)e7#x~y`b9AJM|3#7!gq?y+tnNqtXX@b0BkwF^;Y?tDIl<<-7~7Jj#VbG=K^mwatg=kp!#Eg-4a zdgDv4hKxV?EIVW_sJQW)+`sSk!Tg zLBQsw+yVGl=x&w!t`3rupOIRfJae-WHYFl54RkL|XjaxZyckI#)0(q8e`UC9dsGk= zP8cs}RuVo8ZWY$vqb`ligr!1ZS$ubPqGer@ac_znH|n4O7Fb)`(P;J|n#MLd4$Jt% zCO)t6{&IO25iQGzOrW2IGZ(AB-Bpbw%6js{^Ioh6z>dD#!w1KMm+{_JEG!%!u*B7E zzGH5jHlI!#U zl*diq7?ap@U`5pzI|om!yS8RQQpVPL)-dE4+L(<=`5?+NlZYP98 zPMusj-@S8C2PrS{uEpqKxz7<+2BzwO<4|zpE^}*QXW!;|s^^6UB!#iFSqdvkitJoU zHCsVa6!P*b{$NUsv+S|UC#MR0UwrJmOVHsk`k+7EW_uXQ_*Kowb($fk@;NRQ_ZCor zcMH9|#H67~@~=Os4BPTQ6#Dqx0;%?T@oz0_MW^hJF&f!@(=}r^_S&9@Q!YF|pOYkz z@8HzumzlcZt$y=y3!_VQ2dbp)_xtw)0G1`$E9!e{UPc?#9uRjs+?1{>TneGLvB($y zs&Aq$CFkI4G_$>bBF8*{l{ zoQH5igr)&%S-vyzbodC-o*3gm6STe_p1b!P`+`OX6)!9|B&f^;t|U(^hJ$x0$shSq?5=T^LY1fvvN*Q3ms{AdqaexGm9hIbPyN|+$;(Hwd4<6OSKV`GUbc0dAn zecyu)_|+h$TX!M@M$_P2t;I1qxrR1|C%Smdua%{XJl&+0cjsXLx_-i*_zl(6S>(8% zpT5eH#(T)0Ka|q(f_0hgG77z0g681cRfi#P^7X5*PEd5Vv7`6ZX+x$**`=YKEm_##iB5j{v3_Zgie8%vhLcpEftu>GCw-eKA#?t8lwd{2l2|% zI5BzBb+590J1F#a(iv&@%p7~er61P8%nmQM?a-A~WW0(8x%b$E^Wk>90OC&XmC|dl zPvEOuIWNmyus~Nr8|SGw9Ray|yA}MNKy+`)T8xW~1!P|#8WCsx#Cx4>^1{WqK2M$x zvEDwyT3UrWpziR@=x~z!(P28PiGN*p;VL!@-mmy#-!@UAh>tb?j>x9k;@K9~9BHt|c2GARo@#pK)i@Hx~Fi(R2@j|qxZfkmk#Aq^k;=g!o{eLCo>>$$ zXR7Fm&8iLR?F={_z1yN+3>w3jsC7(`ca5k*#QZg~G^_hbERjzXZLPgn&VrRyu2Xlo z|CSqsfYE&>ph##pjrIt>*5yk;d5y%29(y82131*_doxcb3zz5dB_ub2XpegtRS~AX z)3<@#*=$>a)`-k8o**7`<`4T#<#1To0Whz4Y1m%5hP^;1*WN<5Av8Bg_m}sCl=K0E z*j6V_2I2a!TWP1GcJ1z2wjI&w{Q2~axG!MG9_9ANT0h(1C9C{`TlKBLUCHt1!JdmA zll~0n`a<@VIXj&`Rj{Wqz1)6F#!6e6eh~jQlrdkYjcHQ6MLHf7@m5CQZTTI{Fl&G; z_N)Ux6&I`2QQF#yuJ}O)PueqN#J$DqZqY|WZBB2O8vL_^j2e(&6-sz%c{|~{h_9da z3uRzmve0jjr{-E`#VEQ2(;`&Ssd;^dFV~6rd4z?2yoUn zj+Pidoz;~q-;8a+66??BkIH?;BURHu3r7VI#Pb7nzrGUdY8oE;D(QI7PJvGn$GShI z-kw$zIKN*T_yBz!yKnf8I*R`YEvmwQErEtRJXF~{2eT+(+V+49Cw%^XmPa%pI?~6H z_8@*aK&;L$91=_q{O&jMY2oDjApg#6?oNtS8n6loYL(0S4ilxxTnRP{N^xS|`$G^W zr8qELW@>R5Uj6;?1lUGC$agnF*KX4iy^|v(p7Ioq<;mOlY^N+ft5y>pYN$rGK{kUW z<|M$nyC!$`2n?%?EB&V9#JOPLNivUj(d*mm>^)$St6dq15Fb%*c2DK3-S4RGX%_)zOc#$7j`}XOA4grS<_B-8 z>}G$huk!(+L+%(4t0-N)b$HMXxP745S_j=fk-FvIFC!&B3kH;W)u?9c?qThyRAi!aDqx}FLCQ%^*F9yxc9<>^d>|95E1Hc%wXn-J#!n}cry>_Lx^(Z{#|tZ zuK}{?dt4ffV{yqNcQ_vHQ?K*^QCoYIA`kX%|K+i62p;Gzqwct!Ox%yZD|S9LTBoOd z%skO*{Gxz}`;&iq@MWB zV%C%rXT-dTb8|s_!^ibYH<%{s1LvEV8mzqA<@+vrIL)TCps$#^?DqG1f3-L15@8fh zhQU+IZsAusTmJFA&uSq$HA&!pZcv3dOxpM)*)dC;(BASp- z*uJQEkRPbef2#HTT*cNS{~Fmkyb^52OD9^Hi#G$8*?LXVn6JLV(atZKs(vP>@lZkk zI&5%bb=ayk2EoA`$W>rGsIfl^OS>2o?s{pfSI>)}~pCLeXF$L`|sXapl~ zeM*!-l_V6U^mF(ar)}lF2+_OzsP5|t0aM|+TB$ZuZn!HW(HAUsb8x}wPhRd8TcGS1 zq@(%fD8C;>;EvNjm72~LO{*W$aP+}T^}WynYKNw9P2ou0o##FFGkrT_-RG}pbl7DbX~NapAn|+B z#$4GBs`0@y@4m#laA&;kJ_iMa zxt6tT*5Xw&4v9DTte^XnyXV65Q9$zKZk6`qpxUH8W|bbyOKHMi)Z zMfDdkdoq0;PiJ_GPsKPjJG6cV$Whd3G0BHGUS6Uy1kf(x!>Juljo3|&3s{ML+M$1X zd?5yLnlvQ!V3e`cN`4SWqja+D{Q|4$l$Nfw=|pOR?f8`W^SNF=-`=>l6NJpR!IEzT@-V{X2*O-;}M+$K&7Fx>$p=( zlb!>LeGK15@)!Y2Tro;?eV>u|xJS}-H6(j$yS<4Shr(D(3id~WzV8gz5YRFB(K$}) zYtIvIgpd6~ zlXinQ4!2PWA&*Cww_Sugg!0Twq?Rpvy)EbS*6;ebD}ikaWbNa-DRoCWvq@$#Ldlwj zW8o4Oue;3VdYa@Nvq6v@ZHI(W^E-WRBZS_W3;zy2U>or5gP*YVI$75nQw5hrj1um! zVBR{F9hembGxjXAZ>(T@rpJ&`HXo!*<|Egi-UMx(o`iTk1?dr8Z9e#@x@?vg;NFo% zFDa<%o73T_i9y_4Uh(=Bit5R6&Xpa=LD)KhzY(kh8Bg;~KMCIRrNpY+<=8Z3H|vo4 zfSDMxY`)4aEG~!Q0*Uv}GZ?`Bf48fldyD7awYhnFr`hq?#EfGgIbk*b(zrB7b zig1t;arjz~*d;z6dQXSMQu-WxGdlwv=2d;Zy5B0i(!4C1r+e>TensUUW@D-JK7s5? z7aibOrE$J@T7*8ThQz5MUY6`ST34Y02k_)Fn8Ax7RD?{Hllq?Ad3|PAPUr(_x~#+s9?0X(#Xd(y^Ym_vA3`lYe;e^Z8tWemtHQ2+GcXp`lqAWyf z9I{41eAs{*PjU0jIkt;%fu>zO9<)tzlkT~j&R9Ge`-eF^Zl<`!01&^(!%f@vXQP|S z(z`vb7)fwHT&m5ZMSm%MT%>b?6*$bn`Uz5RuL+9^RC z=}xz8f!Fc;F}W0Gm)DI+3U}?p4?d2Bb9j-jWBEero;j%?Q%9g#VbTG2gm?ws%+l#_ z!J6Rht7>qyBSD8!*Pup+Xzg_P&^S+lzufsksNxXpkbAYSmq1-oNWFg#Y7?>fe58ljj3Zny!WH;C%6+DkO zfb_iH>v^zzl*`GRr}3OG)6coQ0;{o$NO>iu5nh_)E(+wqV|ie+BZ{>q_x#PW@rlt^n$O_QZkfY; zvZn^wM^!kTFeCt5`e*b8_4nd=Ul0`ium zS^}9tiyd~uGhupPgSdSkJ3z~1OVNIM2Ww6G=J2VgZyl2zls};O;9`stO5qfVuK>+V zlSwzW|GJ%QuV!Sj`sLoAW1`?#<-yL`{r3o^06s~I)PxB!_fkmR+q%yCR!CI}$lS-X zZu8Fl5EyibO@X9-l;%QCHhUuewf6?T2r+{-dTiXb!jbfT6zub&5J?EyAh5!;6sdcs zvY&k9Gze5%eJLs}a7!U>3ZyR&?lnA|HJr%*1~dmnrv*Us zLF}G`jsc#BG%#($3P52Wp#w9;?HFliw&xga{&LiQME3WwN?HCtoll<65I2~;wT0pR zb?8qmB*Mx``z@V$o*KU+wz1V&wHVr;Iu7t;6g66%Wvk4dwkH2x@W5ftM1} zWP?D-ajUK&!3^eMn^>4UZLfSFT8EwIwKNL11R@c`mrs0BstJy|FhteLua!1>17Z%{ zN21Q%9T8daHmDO?W32gGlZ3_hApi@5Y6j-C5K?B>&xIGB)czV{3KRUqAisbPwEeW$ zF_OVf1iAm7AQy7cW#2uNor4$q3YewEGc$&dfs=P+ol(vsIM_9Ww-r+|V zUyf*P$TGPn+oj~lRYiM%aI$Nj)nk3DjGy?J9ag?<;?E1!>bi%#${gm`Mf1TMw13yq zrpp`&=VR@A4J)^PBfD~^2=Z~>4npEQcE9{t*pyjkyllyDx+WrFX>WgT z?&}H1v#VbUKAnFkdA%SRx*k2`iaszi{k@qZNwZ$6GtQ{#=Jj_kJttgem4e*30IGg) zS7`fdb`1elqpUC_$|ed>#f>%3{>4t5j`8Obhg7{hZFNs`x^rQYD@}nYpOD%D@XBWo zBl1RPnK?w}GxK@Dn<$L*3R1Z|eV8GZ?M)x|O2~S^@22JsIOEH2Xhw_(vscKXQ58y6 zRdUll#4S_cxXp0>O)K(y-dCyB7lJzxhej*NXLBN&GnZmbBk2Gj!S$u9mm2GUn`h z@N$0zd2V_GO*5YEI*QA(COeTtnuYs;6y&BNMhlzLO;)#Zfg$k2dw;(TJEaR2y`SQ( zkYr*YH|ZaNovOt8N^sk4$qsiLXrI^c+EYQTevfOV0LQHoUywK0&ALj_?6c*iWC&16 zw!u-HEa$CWzSp%-bxYv*ELhowV~;C5J)fAC*c*R(0lrdBTKCG@^h5|OR}l|uqsqPZ z9iU^fufn%PdP}TF0vCeHM(UN=N5eqv-@HGEqdX=o7MK=xhR6k^o4v9Eujk-lb^FBkI$z613LbK z^w2${$A)9@<3A_{_wo=OaY~SyTz!w{9Xp>DRy(bsOS};Nu5L!G;W)H9c04Cu5U>6; zDwNqw8oXNp6;y4z+0sAJWnGn(C*+i1(EK3u6W>|Z9%SJs_)074fU_}4_AR*t`h$jM z8~1e=Q|~OCuE+B^;$JSx(NX=}1WNbbqBrtY{(c?$Co6zu6TTb%ElP6+1K zGnqOueWCt+THgF0O<+wbyhBmj;6n_r9t{bLG<1AByhB7~sriIw4#Isgn zh%G*p$}m|^0)Ob*yoZE`Wxf*_*C2fkchDT~Rm3ga{w*%Dw4{=amG0bo%zbxtfb~=s z0>}y}+GEhf?nX@vnZC9zTVvNzI7?>jPrd^pd7#OO_!)#noVi!DmYhE>or zr^_-3&u}>H?c8G4-*D>(`0b^!s@mPOd^0_LGrnCWRC4nLenUoK#PV{&XneX5rhQOBZHr(^t639rI zP?s`kxr#=*UX{?H;en6nrv#PMXR7#>g4=ofjQ!zOWC^Abqj+Ve1oavcNsm@~%S>u) zNHKO@F?`zb`&aVh%#=yGka($y`WU$4DW?02m|;42XP+hglY^BYPskV8qQpC>*ebGP zt-**Mu0L+P>EzsBR1@EqbFdvfP~3*KXc&N{KfZc3e~UPxv^^GmQqqIYb?>;W*nCpj zi}c&dkF{mpA3>MW{l@@HSV_Pcmg|j8ZEyBKpu*z6yoOAdKJ67>yirc`i{W(!KizTR z;}H0(%H`oMVTW^cx8K`jCG7nvLFCgsCmi`(AxdZF8?R~!J##5D%XUL13v_uY8PmVt;<7Y}U5FFwHg@=$7p`r7>b*LnU1gAV5#v zMXjoi+{W{Dfg}4JQJ=$(y{=)80pPCdG0+Tlj6FFj#cHheg`oM3htnoA8(xd;=qI^h zjx`Vsq%M~H#F#wvRJ>)1E)0$C8LNt?ND>Qh3+;d6manL*tNV(urghBeu()34vv|x|9j_xa zTm2aVh5{I8xQDjW2lT9dOK1(bovL7^$IfbZ=%ar2v&hD4epVGITTxIvD!b$SLQlaA zdZ?oC7{8aWy@koU;9($*|Uii}sOm<5Y?sOTTN(!FOVUvo-0xNt*aM@FM zrhoBGkZk5BL8-T2ojjWO>1JCyU1rMro$k%~5FSGt5xXwpfDd7%Fezs3CnN*pD76&r z6re{5OzV-o8=5_N8yRX(O*wV)Io4zV`NUpwzSqm4NrY?j@#TvKmFDW|9Wc$WKqIKv ztH9NB)9Gs_&ZNoN+!Kcv=nkn&pJA<@_KP<#1E6-l#;fYnY0;phO2#NF!gw&|j@lL9 z&vCmX?2Dpj5qa(n6JHEpLS5SX5YRKhYZwomH4CDJYsNMijdDs>cd(LFM{U20w;vVi zM|U#px9kdbsf{SP8;k&0IBkBT?oabbndnc#TxdV0x4X>kM-<86qAX9sR+5$7liNzX95X7d+XS2*c@ta_9C{Sud%k>G z0}yFQ^8g_wnb^;Uhhmc6)GrmS#_ng@CIxnt_#BmRpp}QYWMG$;Nx=6bH9RHkMnXFZ z*E_3Cn8Us5PV#qTFXM#2r%;oK!_L}d3_}70;2TGc1A%dA@!&~`4xSNoPBCnv=o)RM zVw5)!7(N~FEjT$|=y;AouJYq*flLpT^JkhTiJK-r*|IPtMn(}Zi<-4ZZHS`a!vZbM zTRzhW+odW^z(*o6%MTrnSy^FCI_?YK!AzpPVrwY>Ej?SiC_i$TO*bz4%Kof8>>9-ao+jUQG}`;Xtj7lId(xBDI^Dl6I7mVRCxs$g_4 znQl{?opVuWq5*>G;081wT7ZJKIl=J{bJ3gX`Ax#MKxNKA~&RAdj#pz$U7vZZJ`i=9`hLYs$Rj zqrjIx{jDPuxf|Sm<`8>5Ozf>eted%peY9=4Pb&hTadm>n?Xk_CSxJsnPHu*v{o_6S zn5)T8<dn7t);+9#=l>2qT`lzQ2SG7+dQPs+aY7pp;0Ih*^uDXbf@r zMO>g@p|Op_!KivsdAW}_qC=w&Rj;_V%Zi*H?Z6^a?Mp3%eXOb_8%2N1yaj@|>{(0} z0Vk+r?soVh;@6(vHG~B^x+FD|bhUy?&c~Rab+&gu`Gc#k#tPJh=afL`S|z3Od+{#A-LU>;Mb3$YE#ywB>B< zmg_cbhC5E8_d{$b!rNpKpkB`&`Q-LZiWKpo5JGvfL~9tvk<>QigI_=1GRSYx;ZpYI zAH*HdjGmo|9vu*E?2(t*BfcDH z>8K@+<>JDzo1;uB*Tam|1yn*GK|D?iq#}K#&mV=I&(uVrR*Ve0!oO_iu5} zShq97Gvb>N&-a)aMHREla?oUbPrRdKvxn>~Pr5Z`U-!I=$2_ISVHXkU;Y~cV3oPny zd!ZBDVD|NBCc`MJ3^{(Zv3N)?G9)|`iJcr}o3N8Nt1k^52CBIWYV;tMYDi~8yjz5< z!rk;BP$_%q-5XHx4L$J)1ZaRu3)dvVPj?IhQznm6&F()#9?+Xd7ll1DbcfTg;K<5` zc6mqVYn7X+fWDVNldKJ%)a5J*jL$xj=rMrc?I(|>G*4V_h48u#aGu!Yt=>!o$p}0> z3R$=QmS7>zNIW^RO{Z>w!x`xD?Lf$vV0L)pzNM;d2wC8~Xf**?Bj1%KgJzOyE1 zui{qYu--^EZ*G`DbpkNsWr@GD_)Z(dXG#oBiEKsb^UzR&qFDl(eBjHv|Y_V z3v#$qP3lWkDd)R*RZ<(r(A)YGKXi}RRz|k+jPKg#HW^waCRLWP-#w>ycgB(*_FAfc z8@U4*shN!{3~%0l2tE@C3rOGuk>!S=PKQu*UX2r8URjUI7{aoBCnsi=p-9&7)T4^- zBi+4e@w^Jplw?())k#?;iIyeVl?0zqB*_;4*$~r6k`gnKWP~{>u9cF>SfnJAQ)QDi znz6Y&dw?`yr=D#;A~6uOVS}+(jD~JlpY~qN7u|f{?q9RnOg*ovf_=NEZ(h0xkEj31 z(WHs=jNq3328QXkvRpLv!)@T%48`JAAMTV3Cm%v`_i~c^jTNkiXYt%+Qx1X!&T2gS zE#)smbw|OXVJuEae#m7$zoHJoj6m3D6irqFSrz2kQ(N5ykkh`hw=}Y+(Zf4(KyQCD zn!Oz~FM@tS-KhSIn@IC+P!SDBLM*D>DK|I{iTBMgsi85UQ`Ez&@f{D)1*sE&F5wOg=YsRboBUeZmJC? z4hwSHs`vGfT;fG>lifz|=9T$w3r^Y_!FG-E=|CvT1FIZNwYSUmZEJDqgBSXy72mLQ z{>E}Kdu_=^iv)%NHS(32u%QW3hF2Y0&r4QHL4=JVaX%54rVx$b!SdILm!0SRC{otD zDK8?aoD^F+BR!Uc(00{$L|BogaaE4;16a2fknUZp?C$m#b3s@s>~I*oIusg8Me9Al z$+KsQpQAReRDDt1>yJU;@qbCb7ps1WHqxKnH6>^p$<^h&=@GLv4!pF2{Vp~KO4QNy zR$i#Ms3SCciEzoz=`v}(eTT@b)0xZM1>XTG8?Z}%#r@NHu`OuuE))I zwdP{ysnY&&GKAOHx$G_x8SYFk}pTcQ>V+Ut$4h|cB?ce^M-u!=O zZja0BkknCVXHLL(x<9mtod14C@KI`48&&G_{m~%zx)m;nP-M`~km}8>v{Y zXE#fvx7Whw=FE!DIo3@^VVIYa#C8vamyylS7usRf*geJhH)KIp!))VHMwox`tF@<@+!<}ggWF~mM)kg@Idz*;(%E`?e6py98EDl z6~qLeXx}O~Yb!gGy4c%qO$-bgFg5VC6tF7H=vqd%yQEdy(!+_ z0loBT56s9a0|rU~LGD^E$1$qoe9k^O8Fq64gf_3RD?I`P^SJ8*gG2U5II$ z$1vhel`CtFr**)~ptDEvOiJD_F=OSTK?VXEIl>j0Ao?4eDhRiM5<|iinBlYZ0xsbc zZ_*zc51*?$CK9ny?PC-|eA)Je+Tx+Y$?SL)D;5|TF1Fi|L(5*dKS?)C>I&YH^fV=S zJ_$Lu?sYlb3?gye1+V641M>IYl7weGIKw~B&SY&FGT*|LP%uYhm1;8{F9-K*nNIi& zh!>eISc<6*aX8(0*Rc3tqy1zMM|dnpPF|aBnNshVYaZmj*D2SR*_kw9Jd>X<2l;ht zRdIUQT6itCzwdbah6L^4!Tk3xN&7FksoVX>g3PY#er{A%&LjL{9;-(MoeAd?hrA3U z9Zo!Nc>0QHKDLzeDJt%8iVYpBNbUnDj!&+bI+FHzil@bW1iSy zs2}(75=5;oSlR7_$I$f}EnQm&B^BQg*J#-O?8M!(4XF|j5B8{Up?bJQAI+xcy<=Z) zhd$ZJ(f(Jz4F}+%=cn4D!ze{lx`hm(=|=UM^sqA|KnH)QiyXXVu7F5_S?}{u7hyj) zKDRyAfVQ#*>ysNGYr5(V2Wi*dmkuAXbS+LoWe&lsaJcwlpUa@Ef?MvbjKKh(anrT0 zj^YxOT*igDLo!4SVBBcVxq&lCF8#LwjU-dO(lex{a06@`bb zsIjLjznG2Dp@&=I=JKEwQV25Gq*R6(?>dO+FB}Q9baUbA$E%K-TOFc`VqJderVqqH zAUWX#qn3jtP%raU{OwticaC`2+!=ekc?TJ~yP}_}i>DUX_dCB9C?(_24URi;COZ)r zDk)kw_It7qYB;&E%jA{ytC554w3m!y2={q?Kl$*(y0({Q;-gi`H1zHn8L-|^obUy> zu+2N^=Y1tw4>Bs;jStt|-o_XByTXbM1`APK%#aC+`d=4M^#=;f;EBl3=;sAkEw0!CXn7rR5lxF8C)M@PfJMNHsB&ksWq22)-`h2n)0{ zs5g6a^_t4|$OLlWrQUer4QpHns3?@UlQ!qQ3i=i9QLB}I3bUK0nwmM!SLM9FG$ZG= z`gtUZ{cwpU_Q-he$eoEY%NSWPZ(aFm3-T=AUccLm$u|hQ8#o&ss2Fg#Z1lr&eO3oQsOv zZ6_-RXbG2`a6kd^=$?dnM>vuJ@m*6SELaU^i2&@4MBuQ!+oD_z_LNx94BdeG%4WH+ zXJafg3ztm5GpyXRamENU)NR41z%F9FczLA)h&E>ww|HX8B zk{^h+=+_$$&cpRM7u%G}&Egx5h-pSEI0(1hW*9*?>)$ca;{e{n%l`b{o)=KN`8woM z&W217*bB%7j~td-@K&Z9|8N=ycaNW5W~SbY`vWi)%FuV z$7H2R7v10a-G5T#kFJPuN~-5&r&*O(?v6tm>(#GMc?;}w^SKR#65dvGQyTGEqj8G! zo}&A)EcFs>Kgx%nVChS@FiOo>gK=pQGO7Uk!>@`k2CVlIi+5Z)ZE@kK%!_jqi|#+Z z&SXtdY>UEkUxfkE;}8WzKu`n(W-7gO0)p`LwW1y%2lv)@o65?_FyNfM*ZTj&-7sz@ z>kl^3n^T$kg}``-hXd@%z8*yR06w^^VFBp!_&}Q=zHh;|=aJ|Ivqh*5^Qz#+952jW z8eZLgHki7P6b`u*+BOh`hEy7TO> z$POXx?T9m?Y0o%ZKhT5jw=dhb?QA|b?}*=3Z^oR<@B001Os?q``LH-|l>u_o(o>6# zr`YI<)VKSeNKNMa)?@AJ241~8+Tm_sC_VV($B3w)errJ<`Q;qeS(&_nEVP#t>1qmt zufF`^LM%9e;YG>wOE##^IKRM*>@fAZ7y4A3ypShRQ6j;FjCLUT3zt*P+L;_4Mq z@pz&5{{k|6rBo{wqt4qdh=~>lmpOk3^srz&K} z>T6P7q!{ww|Sml)OSalu6J7J-1~&uZF{`jB5Vat!mc=7 zjbQq2;|n-hC-fZkXFbW)dkDRCF%P#S+}`zp5H75@?G76_+IoY1iC|js>?5+?nuqG$ zp)XPJWbPP(t(2oHYUN5=f@k_G^lwZ}m%;It7-@hzdVMwb(QTjFM|HDCTW$d&2o7Zr zB=8#jethHkT06gMDBqDd7HKA zhNXUo(a#sZc`etC>7Psf!eIGaFvC`_pTQGIjl=l8^!yno=h50KTjT?`ysl-ZpyZ=t7*pp@~Opqa{>buI4B3*M{Hr1Wq+ zx)QywQ0pTYSquHKST}UcqT}})qgML_N~GVbZplSamkzMM?yw^`Y;B(_+UJZT=__LK zx!V5;$3@HlZ7c#+87> ztiN(jX%wTw)9m(hO_`orO z{vhx2;lxy55<7Oh9Wo5s+rQjyQ=FGv_x$`iq@FoUO8`a!ObM?R`DO+HrKLMXUK}jP z{p+1V&ptGiZTff@wM%p)%`sjw_PiIZ1vGbZ=Jyc#ur(hhLt-S4<&hH`+=1nBCKwHi ztyUf1PWCn#5aD57M~Ih_w!2S00NH^DawBgqX1D$T>S-{E7d`)1Ub6U@Ka{Z-O|{=R z9au?6HT#BnJ2PO>Pb&UG3-2`Lt9HyY3@f*ZJwo9V>lmVUoVi!N4MzL>~$5S?UY^jv~I z{8zO>HCE4f9X?my?asv5nv{bL+k!xS!dd6DfAn`)Vl;4dLl*iK&P?)U*B|~|++xp7 z{UV@B_n5Vs!_Srm0MB~pn_EIJcq;1C%;0WJXTrh)0gtOrau*FGC{}LsNY%jJY5md- zs(X6VFlOhM{Wdy5Ay^&kn!y#d|3VUM&+n(UvIgvJ680;F34FKK1(WuRP*shd@OoX3Z0 zb&5ROo6Fz$YaA^6^9jDHfPcI*!7j32+3d{EMIAZ9ddY7k zIqnWWR8pQk#Mai9?U{J7e%FEjHg>&f*)7KN`#5nyCz|rQlAiC^Z@gvxZ>twqxd2o3 zaY5&ke*7xTOK+D66#3W9IpodupsePiUb1X{b?@366K4XFq)@bdk2@>-=fIJA;zp@9rRng->XYA|Elgh5W9D}5mtCQ563cFuNnd4}E^8;{; zeu|3{9V}2s3Z;;Q74&=I>V6IY-~lxypPlV3r(IBA&)W*l6DwoLIewJ8_nz6^B~WT? ze9rF2&D-gcZTNH#2odd`1h2GyzHCQtN^o~fQyChoFXnjMs}2Gz#S>HSw!J#+p;+WU zzi=(b)Zx@LE52C4U4bdN$ce7`dr1#eiYNG-_+SOZX1(ddimDn%50|O8&#lslevAzJ zYNp#@0GtohDR}~+|i38bCbPyPv?Grz6!BJB_y-2+h>i+1KS#r!5V>5?M{2o);sOA&? z&C-_LfSj;(Qel%=s$xDLs*mexZ-Ju_j` z-#R*J{HVTXs8zP-Z@k5KqY^o_6aeG=VK2QB_i}Ji=PKB9uN9i6#^!hX+)uA7c|2y+ z6s_m2a`OyKA@8tIJcLJf&Lo9SO)K*nWnzo%S&5kJ385WH!`OqE#}1CrFnogbh9%3s>(WES6d5BTm;1v1Zq?tDkI zIn3#AD;7$XpUNEJD4Hq@P~49cyPr0@cus$g4%QapjzuxB&jku2cahk6ocFNOB8luu zvXowQ*BD>-LO+(!;Z(~O^6B#tPcU!5S+z1jHQapOL!3Om&)f6e6h}B~7X+@Vj=f-W z?F3sp=U)3&DJlED4SxjEWT2p3F0{zRF6Aw`@l;LmvmTW3cdRxN!BYpWNc$XpD&h6n z&pYVnJy)$;?04uP0c`XOrtQ3w^z*Jqyrx7S>H_{Z3$FqSJ&|@Z^xYR#>3*Xuzd3X* zIK~M|x{@Ue{1`Z2iu+0J-7#_Ak++;oKG<#D<%81E2Ph&YknQG%It||@`{aGzdLa_H zp}3I~>r;EE!~a@jU83R?I)AT|`FUICqfUtvxqY8)MB{eP(fV1J+T-r&e0@pM;5Jk~ z33PtD#$UqvA?$GZ5g$cKwvvmNdtH9qW1#*HHB=Fea=gND9)6A>$}eo#_t*Wla|cCp zo*8>alX?qzF`ep^6)CSp-oG}lZx&z&2*;)2_n|&OnmQyucqRh?Ckr z^~3d2ly3Sk5MewXoX1V+51s}Z_iCs}j?@{dwPo;@HZm|`oi#M#;h+|0{)Z&Pj7|fY zUZsmr#h8fE;7^dw8r5h2{%ViM%L;9%q`g9<%dH2GSDWy3FmYqcyF&f&1P^jt4Uxr#dvKVb`w6qVwTFVE)<1zM!! znIA{^$P1HQKGycDUUZOPRO)eE|_gGO~mVg1%gJc|O0ZOK-;Rbblu-v;#9p)z9w zYkzy={r2nQcF+K-iLey<%7-_+;hbgKb}%Nw5+Id+FXQKHm`w?B@J+vcFH|4R{XBe> z=DpJ0Q{3{?^D0)mWOTjKy`R@pBEKA)`RU$IuyUkW4?93(mv<}DX#VD-LKjHQ>zng9 z)0jWB=b;1mYMTHAk2IPiiRA6m?R4>msr3Z`jJpfVo5*^XE)`yd)OC4AcQd*M55YX9 z{S_6&J(vVHowJ9>R4wy37+6$l@%Jbz2E;}l5!EqQ5W*r(PE-Z(eb z`%-6=DMnVIa1MOAIZgtPqmyg^r`*nUG}T#Yz4$Gcr9rtl`n1%zZ8`P6scVFlFl& z1b|D|Ezv2R7lfcG-T6B0fFu?5J#Am&adEx|F+^zt_7BMck_J!;x>7 zn(t0tdFk^D=}>iv+~0S-j}xzM8*eg(O0bqGqeQ<7enER(#?gCfLG}E&87}Ol+r8|K z^s}>GDhKk_n>0C|RzTvmQbfhfkXOOz@(HclT-Um?c`PUvU`%DU;@nJ6Wvf>y7ZF zr~K^L-z)9N^oNquH$NaO%E$wIBOcpE7(c?b#;nH)ch{A4-L`TN6_wlHgM z+Pr&3m>@P!CT77bZBp+wdhmAnArxM_F|AkC+K`6`6O3zvrVNbM4@!I7nTEg<}p@a2=Pxs zhcTtqctVO3EPKeR{jCgxD}js@gkl}Y@a7k4SZGkVp}lx_VXd7_AMB6RgLUZfq`i2P zLGfLb%)^K}4>~{7Wo1kulfHu|2?}mLpslM$8AfxP?rMH5 zzqDixjn-Gl##qif5QQ_USxS^l>3l!+rq^UiiIlbI=$sHZ-NCHTIE!}bH zrR_K7<6RL4+~k4r%lEt^R>PJUrjhH5Ie+lX@v;QeN^sAS7est0BIZ-<|CY5%@XkL- z3|$Y@^Se7^9v5x0?B>oP``G^UQ8Us|egOk;Iy?sX9buw!9vCi1K5@QZBJ~f{Obnl6%6tnP*ZORrT`e^F!xEBuK3O8D#idu5KeE$ z4N7c6otLxj<9(8*cFf^*Z-A?4ri@EE*sAP_D2cykVv0m*sIje^{1d|XGjo>PR73a7 z_4e@bk!TZ)bcW*fB2f zQ3Y`+azGy*c9}cAweR^0*h;+L(%nOPGbxq(MuQHl;6s{FJORBu?lz8hf0i>Go%TM0 z!&ar6yP-8^R@NokI$x#|8W#N1I6srr)2E%dfuBa^#on_IP~P2nzh=b-dQwzfHrxG8 z#WYi{yWlbbsl0uk$~TYB%HFb_q<+EJC+E=bOo=faMr^V?T$9TR1VnHamxoT=sRY|x{VtzV+aO2_^u*rz zmH~={k9&Nsp54^*w@t)uFJg5SSZky^@7_rd{c^Cwm(ahb(XCA~T!^FlIslbWh+%)q zt!QqLb@6XL>%T6@+B6r$b>CGf>^34pf)a~Qa&IG(9BahnQs|`+1UHZXLr#~8(MWQf zQu5oo`0ugNC5g$pkTdlKhi;b172N$bAdEELq~!7hhJPpE7yVKsB*mmi4hhoE_lX?R z6i&UrUr50J2YP4@F%e)n6Nw>5h7|2DNe}~>BDb4PcDa!+WZ{!!E-=WlaRh#gG{ca* z#_-S)k$jVKCxW~Mg!uQLJd)%j{9lSx>jY9XQ=th6B_)47IbXzh^VtK9Nj4;@57_sR zI~VF>(j@``U(=@}38dV}A4x>`a^r>)0wf1}Pue&<}$&K%^xf_?hncVvlj57V=zD^oUBzvI9UD40z5D+OPFoCBZDv0jfgt+C5tURp4 zKv9fJqr*a+{eEMMASWN$Z6t|KTHna=Y9(W10|(KkUotD3#XV{yHy6d>eIahLuGCWY z!iFV0TUnnq!<8=Olwq&#KyHvL`$$hgta>%MG|X-}>{#2+69|7X3C()^Ftm7|i>QwN zD(;d$l81=LuV;N;cVl{OEuXa5N8)@hwXu=u3nP-Y|9li=vv+_;+>T#TtW2{c#U=%j z;FXdjRQB)+Q{#_}zSDQd^K5&#zf2giKzHbBV)b{#f!ORVb}`m%_Jhcla`(PYVrT6W z!tRO`>oK5^E^77bOK023=m$!sWL#~CH~AFeL-P21sBQ`~P1c5tvNoOen4tD`hAku( zs%{@#qi?^5Q==vd5q$#wb8(V+PhEep!l1xKEK1U6!ih4{5^akBbp$87mi!Q=8nk-h z!A|tiM1KLi_edo9a=({k2*N;+&&)UC&_P%(R1MGK!(nB*#rbp6fxV5_3V0;xpN2A3 z8XiS_pmr}@77(M>212Kg?2+GJNu9^44%gLFHHN$5Vw`MUJgZBiVL5Yi%Jii&xeX5y zFd&D$BV2IE>KMK8kRC&l?@RsI?x$A@*o=O#i*L_;#Q5DRF7I>pJPovwi0tj)f7ZeF zdd|(=Vo>%pT&+N905Eps?_GYF&c=XlZ~WF;{$LT}wt4qk{ujQ)y;(-Hlo;2Ze|{gs zc^4s(zNREP3pk`8J&p#w)P>~SAPIIDYL2?~w>OVBxl^0xRZ73K8aCIVpMKcS+t(Ebp@efr5WiO_pRei7ubcPM?q4SL7hmkY(*jbKzZAEdBy^B_ z9=QHUFEaLkNVEvJ%Fl_m0C&=GpB?H#&^ z>q|Qz9?^_Mw~^*kFXhNZ+XCP>AlO{|kP18d6r4Ubsn?H~2!?ISm+cj2rIjJLgVz;M zdR8Z|1#!85YvTt=Q7?-8%?R(v^fZa>LBdoA-rm7G9Oy>6p9}$A7W0++=b+KHIrq&M z7(7N9+0ZquX=FE}&{$-u(uDxhAqV~Xyx%#*yYGYH`N95&(7)U8%~`sGIzua!>LLZV zqe**xxaQEYa53i2k{AZlgK;ACNW(uW#7=(ILtt(KU}|XT6-_`J+bSi50>ORV+vAwj zrmEUyn4NbII*{DKiR-hk3q=fMsG5Lr?4HVdd zqs<-D_g!w4h8DNi>%RS9>o`C5?_Y2@%EEyH=lv53b?XPYQQkg-c}69CIz6wO8Tm{e zZx<{(_3c^g{&I&&c5@m!HuSYy_utD?SG^$6$s8E3<#yCKPdZ1#+p@0U^c45dmqYD4 z{j$$ScFfp3vGXC|;$2(gD>dq2k7{%+RlgD>C!KI!(Ak#Z+f)5Jo4Tw!T`Z6E(}N7` zFFv+Heou~yr(-?N7U|MDM{&<3=nh$l)^o|T56dUvo!t}Skuqh%bJt4eI|<~?_eD9; zR?KqZVK5?!sxR`xK7(XK>CC6LU_8jK zE>xKTHq(x6JuR}fp^>?LOiA=Rwuw9cx4|kXWxyFE`Rd{Q<&|h>iV%#{O+Dt zR(YN-;voi8YEZ zsBU~OQSBPk^HVnZEWv2cFy*NFrbeBcm8IuH^zn*u{!ebrPxbx z%D|0!i|D{YM1d$AyPti&c5(+I9_Rjp2=tbsRfq3&eZ4Cg$|f;$QNAXS2`bt`R8%q`$E{T?_8u0{h)FF&>ij{pXs4{cTq zJgikp+vbg$&m)aC9^@w|nL6)*(r1CtuT^3n67Q!kC(FFIbG5_?2U+Vn4|XzU9imz! zc{Rdu$!y>XrLs7T2gQ2@$idL*>2qP6gDgP$a+G%6q;4XJ2TRA+7vebc>p= z5Yv9U%70jvCktFVS>U=_JGVg-w27Bp&tGj&IWu*aJPlxd=kaye1h;46UP3^PwSg5g zYFOQL-euXrLsXTsKpLXfF*IBE*WF~pGS2Z$sZTHceafiIR)oqA%+xA>8A4u!KR z&*kjK$Q{4S#yYqP$Kr&aQs7CAZl<%_=``;?<)R{@l*rwlVTRLw&y>toG)XfJ;aq#p zpY*ch_D!CW8pG9_jwzu&ArEtqFS^O?SS`oRAa4>aoYJWbRi**dwlqXU24Lx+FY-tn z4sLPj2GlQBs%h|{oovy=HFXmn(;ay^)`Ypp(G>OIT7;#)cN8GdGegU=T)kRol3ig zyFd&mSWL(=A^spaCgVIGVv!K$)1|iTFIGo#5mKm+fbS6jVg`NVsqMrYJMD3yCW6II z$KB?21DJvm6FxoNr((Ku9_FcnYu02zpej+~s!=I7(kY&7!xjF*k+Cv)SCQy=w&H{; zS#*5U<6S_^{pO~+sglw+fMf6v5}l|Q8=O6`;uc@hJlaAKEAw-)1okUC31&Pjk1ixR z+O(cC!;^7d7wB+)Dd3Ur=J^zH;f;u0LD)r7BX_R9_{fLF_ARD=X$zwjYE{H-ioBAU*RbaHRGRdXc8L-i z|bAp`yrMcEeN*G*GC&cpo<&AjWkKvrQ5=p?~X_H0o0A zcIcvf4D}e$Ea=%=1l+Gl&qj8GGpY@9ROyv-xpKpEHMN@mt<=u)b9&s$d*eA_>urV{ z%b7+ZO$KY}PyeZ&Q>b9rCOgd-{_GfdXf5LP^4+@w4892GH!X{uUvy`$tbPD_a`HQ| z@%O|+GOzr{a@gSF<^_!`=Eg$N#ush ztC07cDeLu_h_DeBKV?(v+;&>q?S_YweXc)jl`qayoWh#F@a8mJeyUbIK9Bcik>%v| zJ4e#&Lm$Itzx-l85zl+c`$)Wvpx-2YNUJx=dFh{8AxJe}zU88&b9kRU8$am6{$m-p zPO{34!8l_4YSr-0t*d}V7gsmUJ-h47X%gglht*U0++rOMkh`NE?DkG)15kP8`a|mF zN+RCxBUMTTQ{rs)EFzSFJ!LK=AyBbh%T5ICZjyV&Q%WbhM@$l3TAp%_3O5*z9MJn^ zOB={w=SOTvV`kbT^zZag4{u7M*xdmmrSOlT&0^d|rBCGhuZKLOAfZ@^d`VXUC#Ze$ zX1oO9L1!h`Kapl}tO&%X>jBtC^+E)d0$jx%#Y!q(R+GR#X1~IJZG19Mf<#5AB zPA>Sihpe5gmv?pFO{a;SbKYe{lS9Qou{WF#DYnjc8~X`=sB;!nJgl12bAU#?cbdeR zNvghO7B`6Z>Wm=Ux68#9NKPAlV!rx3_-#~ipExi^lOKwqOP2p7&z)|MCXYDVE)U-`&*_iLE`$ z*+KPvaZWu>OKCN&wkO-AM;?iys>jpNf@vP_hSy=spdcY&Z{5KRlWTH0@0EcTkUVIf9ju zwYRBfD0zVMW@m+vO3TroF?+t0z=n2Vdqzp+6=h&*bul&I;}D7HN1j`vv@XM<*~cY{ zd;IUic-rXSH+)6a%JgGC>pL0PRaF>?LB{e*)7+dtWnQ%g^ljf&386_}7@xc#OcvN2 zmnp2maxB%fS8i=QZ73U&13Z{|6V<2n(;FxxQgpPvwQQt17{M?E-x#MZz2s0}31sLV zl_Bf(FWv*5G~G|UhQutYE82M7aF!I0`(~*~R&tJ7{&kfmOaqRlzot7oh{M=)+{Vc!Z;fke`q9?TRT~22wFukX@Q6;_Y=kvjrUi`d`-6LK8 z;`l0)$7!8U_7Tdw=tM@x0z|sT78(mjGO^HpF?I$=*~oL{&=G4ZW0ulw%yZxVrW4lw zIf=2NERGNq$#;##;Qy`Gjf7X6m`|dE@r`j)(e3yKu;j3Dj4;RA(kW#-%2zWY)*Je5$X!pE%3%jEuHa zpv!~4AUJJMZmQCBp{oADNz?XW&fPq*38y_pKRls@A7f4i^P3@O;OJO()Dm8!Hs^n8O1T~^lfNh zI#4+>t_BLKk{*fSj~nm@e}z3MGHTP?oD33(4*2enY47LwS36asSj5O1QQd#IEAu1# z?9D-*r1;cJYwN48va|Hr3o~pXI+)E(9r8cld(zy-yPv-o3q|ms#Jn3&V~%NI-;1Tp z6Qc)@CI5{~V&_kZ9WOxe(}yGoK;(u0DA*=f5lJVKLGDXs3gx<4ZTpSTgqQ!0bT2&U z5TT09LqqTSqFP&uFZszdu3DyF@Wv`n@!e`d_Djm`6ZLJgq;G-`b)Bzq7G-W!-Zt6d zD$0+N0R_`w`*WbArVYiDU4d-8Y#DFn7h1<{Hy<=bO^3`j9mTpIUv*2-cf`%*4_)99 zjaGq40Vb}~YI?=QeF%P~^L@2$Fj7eIM?;@CQNba7a`t5xk)gyB`0Bo^pg6dn3pb(o zy{2ZzOeErB+W3Wn%rP-XJq4CEJLa))T)1H69DLDl#SY)t0?o?r(cm1nEblzLC&Rpo zNKEQ(FXEU$e=hN@-_z-PgXPM7e+~v%h}|@<&O7&YzkCmOj_y^`N973l_Wg0KqsO<6 za;;e6(WkEzI){&pjZFX7+od9Z@=u`38!9<2HTu3qlpM?qr@RwwhXm`RrmaTxHPPl7 z369%qr|d51j~vF-T#qf@>{;FB-Q4nR*+XX_djLGb5S&Y%u(oqz4fE@bYz_8T&UN;> zb8eQ!t2*Q)*0KouPIST|g;1A7pV#N$bVb|}1#zck;_Gpf7F?&({}OzrmJ zZk|EFV43gmri9r#2(gha7!BsHuH}FswJpzXdg{YG3-5l>#YMd4_K$wN?3=dfV%w*H z(y*<8mEczM<^EHif=p7r;u9a>N0 z`=)9i_sG>%Nro-_en06*mEv5W%{^M@O5M^n?P01x;}@CJZ{Q|iqXsyctfOwOVy}Tn ztqBHbQp1Pbh-;L5TYG}ew^@Y~!8AKPmE3;5V2L{QzCgl}g|%i8UFMvdr1pmp>|Q+X z&58u4WTlHIIS6>r#M)P;8h-d`Y1@@*(j$Y%{}gvaoPp<8`Bo+Z&E*}-v&T}A*8xo2wxB1i_prd z*sXlt@oOR7_iy{zSZ*|L%dInJwZTSs=6&nYla%WI{%Y^tVFY^Yy7SfGscdd{Q{N3Z zqnS5j{9tCy=1xuv-(^y@v3qD~yMm@Iy&uiK=qs_@E%EL^^SZ4CzdIqH(FA;;&1TwH zd^B3~zPSD!*`rwhB>d_5bOw6Z*W-GiCIX9kkbRmn;>fS${=VPk_iQ)vP1jNo1g`Nz z^v5K+rN%Em+35!JrXdUCD>}ok6P&7|RV~xOel01zEnGSDq{Y}>50>qQ)ZSFjuPEMmkBKZLIBo>#8>RN!{I2RgA1a zLAm#XV|aNQ&ZZlHQ&uNnM1wOlt{NhF(gi*XA6!fV5vh|AA(ix<)Au9(fM*Jdg5Uz? z-}`!X;alfLzT@|b?#~=FV0Gz11}6KVlBVyM(hvRJwNU^}%vVv~h0R&^!eDo~970H` zN~aH&=R%f&P@=!6gB$h+FIfzmr;si&_}h^5{c6geE0?*>DM z!*5GtlSX#%7ONM`zh2K0K7!qg^#QJX$wmOtSc1WvdrWPi#4rve&Q!in6T(E-`~7wJ z)LWP(%FQWr(}RjbHP=fZ8GSUr^m6i{(9ii=k-OIp5$C6TG`z>uQtB7RX3tfQ{#K{o z^fs9uO6*`bvosn0{5BH5uhqqn&+}IHoO9(p5<&@geng&_=L=`RYc#R`n(+Ih3V%w+ zAJFX%WO_n(GGiF=sUXP3F2o`k{Ko0;VngV)EQaOXR?z~iJVzpby9DYG0~pOyk_h0+ zlxq75PdMrLeAHnL_m-&Nr57mUaeaNMui5=1akHJGN>QpFxOc@p^lR-d=kT_DlI-!) zT&VpeC@)uW(Cf56Q+w~3(JOcC-`w|mG{vYw*zOiuRZ#Ad83SsR`tR2*ilxyOd zST+j_L{6rfuFq*j`4F#fcSRex>93RG?+%V&i1shxZ)bFCCn^`Tk4wAci2QTie#hkf ziK)|CZ~y4J;>LBtVSW%5=1y(8b(S|KY4sER$H$ir)oyVS-wKAw=QW^7BI+voZ>v~B zFTB2S3Ev_nU#x`m8b#*AZ`em+9e0DsyQgQfPfSn`5ZnsR)Kl>QcEriUG~4EEB7W>G zXXPed!K03|TTx2G`*aBVdA$5qHNFBvw2`lMpqh6ZroW%z2GR}1k$298p0)6A$EmOh zzRHvpgsuEZx*a)y+38;1c&e8-`d%cT+IaWwnNn{^=wzlB{kD&HdwzY87mD4Gb`UG9 z)oZ1mX~i`hpkB#s(RF&BxVLlhlAtJ=vwBGb@r`7? z{z4f*6R>gSs8`w|y2LD#_Cq!FB}gxtFgM9nj~4xP{HjzHdaswGy0M9+e;`%u*o8S@Vv@ z?z{SRP<6RX#qFVph3XY8pvOqnZqN^0OX@;$&>1X+4!=iqcdH-(uA)9j)pWppKBt>j zvfwH9Ofb&Nwbk0=9zyymayom^o8Esbs+F%xt0@(?s~ls)_4$Sbaj+c=ce z6fYij1FSO`_dryIxsu+r5pYQR$pF#`o*aFvzqYb-4es?x@MQ!GH@K=cl;i+ulBRQ}uQE zUt3tz^7HHmv0uh7ss$PHYOJgQ!Zj69%l)kztWM&;k9wCla*5XeyroN^*Yxo|Z;eRL z`@g$%|Es&(fkli7UITVfh$$~!)lzS-{OkSPnt?Ul5pJ7p=~{=SR}LoMQlVYqTXp=@FBi zetIO;7xD36PCmjB;Ty@))67Yk~j_KACZ=||B>gfrYV*Gq0R zNO9l!6Rd8!?@H~^gC(yeZwDmtP%IZ9P#Znin!Acr-jaTt_Vu*&^heGMXOHmsGLFlg z{|!>}TB>m(0Q#=6w~cPC{Swb>9vQNr8g>)AH-O8c+CuToxYW|g9iFpmrZAhuUmvXf zpW8A`h4tOnA(MH29&bih1^gjK6fZxQ;@(TzXZTP+U~Qv4jDf13o48v&66g@I$G%Gn z1(1Qju)HZLLdoWL=3L0968I-f*v+e%<52tENZ;jL9i>X+Px0Bm;r6^;aDBwbANre% zLr~sJNMDGr-_+zmr^}Lcm+Y};DzC*aT{km+Qut0=jYpJjMCvRxpWnGkCD3rAVf9Jz zdIRySW}5hX)<=o`BL2Bt5HTw63^=c!`!z3Z;<$zojdo`w+t%Ifcr7pnCPK5cpVakv z^GF_>+t2PdAMcNBNa`#VBP~TI_W?>~;5x8#{ZtQN?G_U#AP@&f5^gXh!M8hsZNfl>#jY5uqHtFTJX>{8*j%uhW*OlEZB&RP6$6xg&I;7kqux}T4juG7K1t}@b z>(48$t}Ob7*PI92oyhwT@?i4iR7Lq4^4t$sPND4TdhfcAK>>2qNt|YWQ@bcG*4RcR zOg7xUSKkLlI3>u3B@!Xu@)bLBCd}74+&TyCu#GO8_K4?b%#|LJ4NCJc&ihOl_ma~S z-qm}k)|}ub(dGD4K0fuxSnkIxDv5=<>PPy$=oq>7w=KTA)mT3_DCOSP+opb-n6P44dXK{}E7j@rdsPna)tXyA6Co`X?&KMwDif z*3PF5QR?2~FkgYK5Ii~UgQhWJIbQ_?Fop=D^9cW9>3quskSth{4T?4$e|>^&%%4Xe}nwz@LFxI ziWPLjQX)wTdqHs1TGOA1T5sG<;45$|g!ArQPDmHTA*MbLoMTr}^Ili~Xg*ok=t)pF z2>T)m>+E-0aOFyp@vF~dwe)GMv8VBX3QIQC$NE*i{{nlaRbNsN)6(h|;R3tFA-xyI zH~Q{w?=G_?=Mzi&H2EmgYkxgz?`_5LBN9-9;(AGZd?fA0-;YRp{Te!4Cp)`WUgT0R z$6K*w_V><=?aM5dQRRi(6{ZHu#b3MiwfkxHs2&(^2xqQ*+kq8);~J@Rn+<=OdriLX z(R*PD-iYGiI`gcZsi)%T5APR`fmt_}53blMUiOGWB{f|ARON`Oc>gw(sfVHZTTh*{ z;(X_8N>lcQnBWyYKhJOM+12mhfA%Z0+JB_?JvEbOIG-cRsP>;&$erO#H>W{F$r(j@eIayjG?rw%oP&onKzfhBw~tx!b0vA1ezR#YID&j7v-(SE zpUVx~gIEGB0iV08Z1Tx|q?xZ~!agDM#FhCVII+t3pzYhDs*@&dB~?jG=QzhK9!=&% zw{eM9Pv-(jqT0~W6}Xzg6H3u-o3(t7*$a&?$F|^yyLm!1uhVq+{PN&&KnZ@POi-j8 zHG~ua<9=`5W!SY@`=q_^e?|Hn)D5mD??Jo(yK|@CuUEd;9yg50QqYGCR>VPQ52o~D-J>sY=-om(l^2k0RfRtK$@?wlRr?? zTDdACBMf-&-gEYj2V&xk>&)%5EAMW-WxQuLVUG5+Q+l~LAfJ1C%zKk7`D!t)$83C7 z1HxJ3pOw{|__(6VyZr)Y!EWek;~`kSnphMsM~ag4?JbhI?`V&8=jSrwfr$m?**?$A zYHLm)h`|iNRV`b)#9O$9Q^>N4{%GpF6m-6q`Fj}c15hi3;O=K{1wBE>KE3K)J_K5v ztX%TUV&lo2FS&4rt(NjSz1h=oEjGyty4>sGUS>Zp%Xh_H8EH7t%d)@klMh-F*Nc@( zH^D&Qt)#8r(|2J)eRFj<0VY?uTCws zowy|LKSz@>Oqa@oh}G2}U2}CD9u>w&07w zU%|#9f83@*Hz;=8V(-UZC`OvrJvVN}-`lx&lptMj{5b6+;Tuk3xs!inuhQg6cnUoA zO+VDahUnD4T;wFoM`oZ2CRF8P0pVkKzC*rm_FA%)e{czbG)0sgUn8H*dDhJDcj83N z2y7|5F60*P@VD66xRaH~vwEbzXO%A==HQy2gK+&V+(8y0bsy<)cokYPN@hN7)Rx&C zIWzQi7gfgVb^pBEvcBJHPoRkBFqBwfk#mn)%(Pi77M8^*9%RcOHL+@*K=mH1qzyyG zNvCvHUcZwgzbrA?y=iX@9?l?&@Ah$dIS`A~`)hdE{{(x* zNBsHO`q2=VLE*AKIrEnbxMbG9(X?eAG79v(!xjxP1)j9a<3z2oc%ZInnrE{^h^N00 z#d4-6$CNwVP@O>ae>rjjb9^NA=o;4=13?N2OTCxfId zr8?7JZKFRo3ZLConI+0}UL>u474>TQ8yra}B__AY7tQdLHt(w;TgKf%p{48f$5q?i zNov)da7%vNMI3p6BDM<@GnjUgd=d!Vzz`VY^Cf_qD!EYpz@gk#Ea)~Y`A$5Vooh78mRLwi$VycAEx_jey{;j!QNDFri2%9ARvo?(mi$9*wI@cfGo0n5W z8rpA5WWL-{jM;QPTiUX(?blbNg4d89{EP84#2t;!1?pMRK3DwUqn{Xv(Ua2$RtN7M zG-37^XT{HAs#DhNb!r>V8N5gByY#dW?$l-ftn&R<@K43xk2^a#=iiYyu=VO*FYV7{ zTH@QM6Ifr)4dc2Fm%jWXiwD!#o07=&tYmoc!pD5YUD7kwvXXSBd1F@*TM>g$n^z|@ z@|q)kfD3Ba?OBw6Aqha!i7@V9Xj_!qWq;NqllJo}u2QMbO!IT+azClSb3CG>)hVgj zSROb{{P)&eSbKf{ncZ92ePnBaWWpKc-xS*B;mI2aRq^-oP0t;Wu`_80+Bdef`g6G7 zgS)p4LiOIC>F?JNPf=c3ZY+Ot^u8?X;IYbiA=UTOVK*EE#RIioHF1OJY*`unenai zCzy9-tJ+YX0fh&^Th*^Fc{H={>b9Q~wx=|0ljy|LE{8u{w1-`T6VIv*GkL+H>oE?> zzBK7;;l_s*VB6{T&p22H#uupMwyf;(vgKTPRt4VG<1f!ys?vA?NGPxEy6&Fd5*YjX zeb1wAD2okQy6=aJY~jN`=I%-_-r-<~_aWtAth@cBN^_^-1YoQ=+6FW)NZ-Ev1i%LK z{od_2=@5vCdSe}~9l(Cx)6j+)TSI-`GEi0o$PbHgA_*p$_*SVd6 zTt4B&?hkD6m-08kVUOoJn0IIIKpuhKFr0A>wd#4Xt-E#o+A)I$o!i%~mzTIXY&jj? ze@*b_0jYDoXX`uxpn_S`)SZ89hoHr!&UdP4IasqCbW0o6(?#fUIdPn&fy*yx&)uQI z95Z0;jtN?7w$8O450)*y6u9d_c7t0ZZw@KG5D}usowD2lpUm_9MUDr5;jF$Cjn?o< z1?jEFcw=768k8`*0>Q}U!nB=)&6-H1b1N+509hX?|M(Db-P!It#}M`dd=c$v{I0!{ zA#k@{(HH@UiO0ex26M|cD{Mp4qGWGAJ@uvuWv2)H(tyd<`arix@^8#BTb12UD}j4wyj*?DB7BwjZ=E@-R)u8|uu)Cu zR0|*q_Yr_Mbnh}BD(3dvQa+ovU>N71mmNCQ&3~bajfIu@4$@+cd$@6y^ZZ+n42u7< z36b4Eh9hBiB4$sfp)=9W!Xb{PSo}dRyA>N1^%y^tD2|(P{)9s3$f@L?{8Ub%MEMp9 z$*kb0n|r)4k7jcP9fZ6a$~AWNu-08D+=D}%q*?X%px(h{CmxA1@1&4xF@ouQ}LgWS)x;B}BqPxX|y`8|wkyQU4v(%nkmyVwa$$$FK-!?3w= zhbaTAYvtu--5U;^FP?t{%Ln21aU)i~#iZeK+ywt{aMn=TbmMAH>2*fT1=B_BkM4i$ z2OM|hM0d5kJN1TDTjm?;@ag`>SA01dVjU*asP!(w7)JlSBMsGyofWfs)@fB)CUT}7 z3#!>y0ya=$hBG!YqsYQIkt@#EwTtz6-7X9Uy2{E$Q!Sbz zM`4!xJ_VO#yn}qxujb%bh+-2|@m6|X)c0?%D{xCT$;pD!#D zb`=&Qt&JX72g!(K;qnFPB{=`x^fG~Zo@=74~JX%?5k_p>tbB< zZw1(s@WF~-yx7%AJsakxy?0(_a(brkRmnYVuQKeHRReFX*yJuDNw+Zo2b5lBn^yjYitBaY%sUBoVPdk0 zC}ns^P?6lu#q(@f7r0Nb-1$5>SDC6)IT6A)+Nu+_cWRDBMW28Fct1F6gv0T&y1(O^ zz-%+;zvZF^MFU+TON4*r;DXojbd4Wxk5T>w9UEj(5di3MQwUVQ{3ZvT+_n$pb3A8d zzJf`fVr^1DIg}vJca`&-a~6}1pK{<@em~YRD(N>ssari0A$ocC#FO@+R{efr_ z_b!s1^uakZ$3AeC9G3;>PY1hg`0%kHh34nD2zMe^M+DVSvy@A=o&EG<`*r6g7e$V* zvT)zgC-mtrN%+W*f;#UXg)Q6Ny{nGZ!@2aq5_})APU6OpAJsqQJ_n^-f`H30My4Sq zx+IY|sKQ?y55HyiGpMRaC_{P#gZOpN-*21Edfc9PrBr_5J+a`e_j3u{akT}7`Lq!E zM5o<+3dOaTp-P$NFB99#BHXFA4BEkqyKh-cbl*DdtonbP42IoLbzwF)~f$$thYc|Rovzg1FGlKxRI z>y=8J@5|1>-8wm8;(IIB!`hg)7c!<)aS#kA5W)u#hw2W^ob>85v-uZkYOLSNQ$11p zPbmD|6)#t_Na0M-)TDZaz=89Sh#<&?VKq30L`z~$exp51ghW75uXnV2p`k_t^(ROM z{dfA9MXn%|v@RJ?;+<_^YYusG}T^EYaBNBw@_d-KC@o?*g#L(JrCW zZ=f3c%?vKNgoM$PmFVZ!R;oXfF%!{|)n`srMA}VQVO8YvoE2N@jK9>DLhpGR(-bry zstfBl*jXPUGOX%J+6n_{`{NNcj;S7_vk=+oo56OZjBkpihF5Z(s|2n6vb{5-_j15m zuD-bI{cq-Wyb+RiCTHpc;@vQ}-sU)>`B_FO_%oXF>H8a^)otm)p*@`2_l5@9z z3xj`bd9$HTmG2Uw*utzcs71mp_ym6{LHC zR?w~x)*_NSwx@GCVm=T&UpXm<=8}7p^W7JBkrsC0g7b}rYj2VG&v7XqKd*1xk`S2g zh6nEnf6iX7B!ACIMZgsBK{aQ+%Bs@~NoO12VJUE>#i|LcoOd1fikFN_lV&vqhJ#Ox zW^D7PZ?(7-h5}A!3D`2frm)Lj#R{&dMYtkb!OL!gih04c_Qm{*>3w%Dc6R@Dr9h-G z0X_RMbJsV$VJU^hqjy>&i3o2-R>)4zUTS{xyIRG){9!+^m3l=K_x;U5kRn3z%&c#* zQ;zVzHH0jTub!ggr=`4L zC0@7TaWWJJD7F4m28uE9?Xu5>=Y7ZT5kh&e$89mz!Xzu97Gj6f+k7Q7gtNJEEUY*k ztFvP+G|}H|H@8?itaKj=Z&#K4MOCk0?MwX8+Y$P&zY4c^%C!+?;nt~eutfAwfnD{- zTPOKje_84XU-=Oe@{$N>aBJez6=zrLNi9p4-?)1KPeG2>C-e%XSrdcw@*q>u!jMP3 zM(>LRw`?R@4}79MFh*?q{i8YzZy|ejm^wFy7J=J%4OMGfl1q5rs@2MN_WS1j?HLSZ zc}7nf8IoO1c9}r1vY`{Ed-N3!!+yvnRlHQ6jx;1tSqaVUiFFtfkZx~P{kZ``uhRC; z*C>&&N%HB^f#LIIAj=)4)OpdEpuOM*ZXUl!o#xUG02SU}fmo>bi3L*shqF_k5!Sf9 z*j?<2M8E6J5GxW(Qv4#X``=6Xw*l1B7jfw_$IWg36cTFqe2krQs|mcd#J5Z2UP?Ih zxt}kEY}tYTV`Zj?pq6cU{~R;DdO2&X;h}x6En0jl7=q9CO7*F41=g4T7n-@mzLEqN z<;(roJqziAcqmBHsnaF#LX)2@#z^zi{Mho9do#ip$iQcpu} z(vlF!lW==nJ}UEhYa^fv{s>w* z`g1JK(Up7qd>~c(;lu=DT>GJFGdIzHKItSSl%-)TJn4K^qBs9OSJkwP-IKl(^Q%MD zB0V}ecuvI}p-rb2iI}ub2R{PlGfX7j!C+la3;z^h$_)q;@ttV@4c$MEt^B8TUk$U} zy+KJL;tHd4P}^YFmMctJglj+r!(siouj%)rJiJZJ9>ZeoQL5O}p`)rz=FyvQmvWJP zm5hv5Q^VbTDUlKva79h5DF~RgmG(PQ3xoV4c-rS@mx7d}*2JxhZajr;%TKw9c<U>?r*MD(E0hv9vokv=5t6`dp;VY^_4!TzTZ$u#bQ4wPZvzBrjl4rgq@c>fted zj5|lIvh8R?B9w>OR0u#IC8=^3d52@)ca7X6dAzePCW6w>RJ;d$zTLXK$~wSTWjFe` z9RY#)jVOmc;y!S7(3O>WWM$rE>~`*l=TA&qb_d=r7dQ{Vz?k=qYXH?qfr6;GkB_!- zc6FvF1(zJfqI(a^h0gJNa4t1vvyM;XaiAN@9LfPoEsU>`CAUQjU0uNT1kj|8|>h74&F`+`i31;@JP zSE4?Ito$L-azJ!7p>VaKC8Ro_Iul70Uf(u;-0mW>fG$vQ@A`WO=k1%nvF{<*xOoS| zQ`pwfj)1T%4=hU`4fP1A=vkwrl5NOy&YSZQEqeUI+T!li2l?s zf7`@5yzgZZV}Sc({hQBQYt4r{yb^A|=N-(LDhw9+6q~nMaPB9oxD)M--SUlj7q9s) z7u;zurhj}OZ(k11V<^{vgP6$C0=Z~N^l+}fsb|r;f@cWi1`b_3~Rw4x{cs@qT zQ*gtYdSb24^;(w0W%d&9LY8UncZ9T;YpcxRx?*3-RdV3=f704ef5icLtN70T6EJH= zLM(`g5fD2zkt{OWf>!XK4GagCZNX^@1&%?SL~5>j@0=7JykqA&B)^LXSYe!)b+Qw@ zd%f`DnEIs^)6eX*h<9JBV%I>ScYo9F<;wV?oyr~$Vq2((h#B-=O;E4Ld|6dn-_!;z z#~?j{r`+(Df6X~kYF+&gXHBs8Vh10uhhxilz#2C_G1G}t*9%S-xCxi>1J+2Un3i#y z#dFhFwV-ogsjl~Yhi25)cn*2O4KmD@D0YAG-_MTh{tNIjuWC;we zu}9QJU3}&qR_HZ|>Xwn;mtb#rIHs{VDUX)A>3y^e_3QiT z`8V&ol{644ze8y9h^X}8-{ETJcTO~J9O*4(6^2g(-@DXl1BYQeRNbSoqByK)Pc5imk zN8mB<4MXw|_51A3sUls30Zj#=%qY17W{w`3&i@4D;VR}~9w!(t-|Tv)92U`+x+y+E zHhBGeScl^8p)``C2i2HQR(|^S5QnMMdcLWBdo=M;<5mC;d-l&z9ILM_&#e9c@}2VC zYhtXc>fVIUK(?6e21r{Tg3Z?fse2fVWfZ6$JNvXyvEM1a=hZzWr|ozM>HD+97Ls+7 zx`^7xC=|(#{~;JFslg`d#WSKa@>B`(uRNIw`cXoZ4KDHfF&O~o)Y-3~<6ghRJL6Y@ zkUsAkDsGHYVusbtHT8B^>y7NHXKAh*yGnb^oE1~YE6Axe$^2%4s=e8-WG0>HsN{iK zcJ7BsSZ_Fd%Xa(qj#>55*45Qo?QaLl-;X{c!QfTgfw@Xz35u8QkbaKj`o?x8K<~cV zwQ~HjKvGbFu^M>is6rE#`Z9lca7DfZajHs1v%9y>je`CG!g{iQ>hhwm2kxYp@OS*V zH}4mGc+8&xltFFS)q06_4*fHD=}1yOUe=Vl)=~4Gx^CdF-dX(M`1_+_TM$=P)|xc> zz-zM-)=FvZ4K@I!jJ#&o-=uziI6^o8$4Sf3Gp>H30YV;ak4WeF{aw4q=gSv zMU>n0t)DZyUq(fZf!)CK*F+E@<@U{Z7@Cbg{5R~o8O0J<=&Vld@LWADmqWWf1Rgg~ zPrX3miixV(CmX}X*Hg3m2#oxBe)7nq>)$B&%Hbqq!2=YuJ@pG8S-)PZWuL@&iPIuI zK&^yT7F<&E`-%2W7k2-Wq|d?n3YxYnw-218S@}_fQci2SoURKVsc3Z&a(zCWboX46 zXUC$!3P^($w-F7~Lz>ta8akY@Mv!qOT~l92iKDdYg8h6kl`e;3yvarB zPpKZF$cZP}{qIpYpUO&W%z2(y&8a6zZiwo|f;ReX*mfOgvR1A77#99Rd_3pTjks)>N!4N<^ch%s`@Ir`i&FB z{*zKzr`9s@wvM%ay@+gZ=P$|6WjXK_AMZE)9XH=-+oxfIUkCz?6u-N8xt3S5=Buu9 z8`aC#=Yxuf-74w~W$WGP=2+34%svarpsc%)XzQO~rRd@ubUnPTsf7>RSKEIl_ZiYD zm^^l-w~^uU=6An+x9cO`fl&PSCdcv5pZx88DpT`GoKaFdV55Rl@ReO2FZNwi~%R~+^PsfvYpI8%REbjOTit1Op3NE@!7n6s!awHsq zQ2erylpngK{T&Ro`{JhAIJ%_MIk#OYQM73HHFEt2{hs8ioDwJ&uWa^Bs<%^WO8?4% zs&)LxV8T}OyE|hMnVE5a?X6D@a@tb$xVPFqINValCtgqW5L&grGg9Nlw<1I6%G;qy z8QBXt?kuvK>L1uC-hH5L5yn$?M6rSbhgJFrPx-HS@m^2~$5?){g-;(K6KI?7~W!*ns{uuH;9bzJY7ZKVlr>q>H$@TFud82Nl_{hDO0(qHVP=O z)Hiq59yeeDHv1=jozFv-18L*X<}1H0VK^cjCfFC^Guv1UU-o+6tvE8M3W++}Ih4Ue z@jk9UPU5s*eQkFWy-)hl?!-Gr*)~(PEcx8e9IEGO0=W22GX#*bw$s{7IIK!;f{Z? zD+r{TQ@w%t8izpb8XxuUFN||D0W0j$>^#a^NUm9{+o*73X>J3H5J?IO3eb>X0s$X7 z0gX^j7>NU1=cC8*piv)h`lFBB#Wi|y;hg^M|HA7RHZgcKFzN4Lv&cF6c|J3^*a2*wGyL^9B6E*C_(AdAz_uXlf zXhRwyaXYi15NqmFjpF@5PU2%U0NPPgl_-p)n=gCB5l<2yXw>6;nu)`H#EfDVCcIbP zQ-|~lfN#Vj3DjNEvLe;Km|fX}c3iTP z=6=*zhtXcm_p#X<0$wqWL_6YfnaYRQ_Syr<{o%@*r*u=A$LFQ1(yW)L8b_3y0Gbcy?uATd_`#`Ox~8!Wn-%rX<~j-H=nS1_MuX> zpW6F{DRInB^_vu)xA8nz?_gsy?S>9*m%nYi-QgFKO?j6p(JMu!*>~UOqolO&ri1la z!g`2*6GRv3zS78P7_cHIur&PzPEm#@W^3YM&mf8nvYmEX|FX=#@H>EUoaf7MsrnVs zp0r{Td4ISyg#gB<*O0b^={caB^Lu!=^Xu1M^3o803Uh!m_#I}|)pojE6~KtlvmJUg zl&s3V)Z3fM#J4-U*vGOVJaHfY8f_n+YR4)V|Avl!80fPr>@SzY!75jZ;1M!Gsn!B# zy4TCX*(C}_%x}xoE_P{(cNe`fSstX(na&tDM7m?GT@1^! zo!CKE_I+)7;emnZ?l~VZUw+HD?U~9xQS!&ryiwA^an6zHun?ltd`|YQ09cSy`}hzJ z*!Rp-IumbM|7^X~XlM(1Y!eqd1Qyo#q_pVBBQt5-iP-z`rnFeK|d) z%{w2PqjaRQCV$Xz^WAGB8dbjd5ePsNvg8$kwb~bHE=4P@)}mxsb}1#UL@)ffkw`S z-F24M)#pd=ey6M8KjIg^WvKOx#D3)nh>LqCgk`P4ymNLA*WzfsFrpe9p_%6|sxW`0 z*BxM#fjWqze|FhY7x0Y+H`AjriByCs)VX55d`R6R_Uuh>kT`B#rcd!S?^i`>4i%=D zt&se2m)#co!WX*|xG`t7|2Pr9k*Ta6RTc2ibWCGD%lmtenfGb(!gmE)LHCACAT4vNJzEbqEnBAm7r}j#gDEUrKv^R_8|YYd^bDWTD|` z{OH^$JYR#?Uj7q)_g8%4P!j9C%r*8&9j*q6hj>*#VT&0AcCX)2W)M6V+&P~C+B~p$r3H!&RYX&dVZg+og!u+zH zU3-5=6LFF;XCvclT$`yoo!0v|A%h`c#o^@S){O`_>yKbTeBJC(P#=TpFys~*f%S6J z=CjM;8uzRsEA|Zla42X^#(KnhF)MApB5P&*qy(|NrZeEZiE`|i1;wYnuhfe0n)S)SkZW8%=Uri1RW0wfXCGI}fL})nYRXrki6b;mNraQ() zNRR~EK#Bdp!c>&kUv3-m;--qR@~GkkkxsNF-R%)qs!heZw-0ao`I9RgZ;v$b;WC^r zo4E5V8|@azVS4ef-nEquZi@i|HV-?~2mciQ@6!p|c%Ox2)0DfK)bit^Tb z1s9h(yfGqdzSWL+s?B}#WHWb*9s%lv3NC=0dePLL=^vrZwUZ3EC%~Iok8amsdUkJUU$GP2 zUpd%%AH{F)=C?ocHu^{Z9fX%BxlegfRrFnX#rOVGj4+z*ohf-`fl+Y<4<&(KUtY)u zVhQ*WTJ#KlotWze-r(Jr{;37Of@gt*p-4Kk-5o>?acn$vT4#SCBfbaPNd>;(Xb-TG z<2fAkF>}rw+>^mKrGd>KuipAh%KdA2RwQ~*pR%|-bn7UcP9&vHe>;uVaeAD~T7Zfe z*csC)8;PvC>iolFa!3HQQd&b>r=b6R9jbVLAbfgFY+CSq$m<@@-I*3h z`D106H{ZqQRa{=weL%xO|JJ91>suTr)sA6_er7q_yKSs;TMEygGf`cFgDgCkYP`pv z*hlSZN2$m3&T!-Vf|C9NLYL5|e~%IoDo?;qy_8h{$i5C?&9TB!_h!*igKn_y0$Bag zLC1dOe(xVx$n3Y*j(zR9?Yj?G-N0;_rw0{8JVYv(sW0|;aW!cHMp)AzhgztSgdDNCzmP_^YUKk+4Nhj<5wa<23 zOB>vXzYD3a-1JR*&;puUVX(Oudcqu?%`n=G*@l5y`YAiDucDk-Fbl^SMYtWdVPEhO zmXC3oJs;+_$LTa&Rq)ZR7bE?I;Sc16#Csdbfw=q2z2=`!%041?Nqlw>XgBmcyS~j2 zgg@(=VXIm5$#1oaNqW_ad&y|x{Px|2{(L~zv>(jr1m?rS8`~rG^jY?vRIvT1@;&S% zJ8so}0r(7xU%hnpKxKMpLluao{<9C@<^Ii;F+0-0!1;t%q#+#hxEDlLO7k95oe$Z9 zM5=u`%sWg^kSY-RPmQpPb^Rq*%egN&6xZd-*Zq-tecnTz3+pM!r!&SYYj;`S$5wQ# zNf7m)PqW@!J+76vPj^bP_QB&%=j_MXK$+Cn%gJ}yiq**j;*_6E4cC$Y(fjxz%bwFd zReH9$V^7Tbry><8ii&Btt)o`5ubmBrP*?)}7aUx_ebVt$u}bMIFYZ-VszI21?V!v7 zmc7wlu=hOyB%@+?R4IZo@{y~BbT03n={Oei1Qr(HzxwQYE!2SJgIAX!eld|h1t;B6 zm?<(pC64`N>RyoFgBm*($VX#BT&-qtO*7v)TFYRsZL_WHJmrVyHCl|=q?fO`oz%B6 z-eGj>t5ou17TeLpyX&uoiGOFYzL{Jz+xq3_y%_okt6tFb@PuW^n2XNt?-`g^9x0Tl zjjXm?NIVdg*BG)%b&tbaeZUntMH4gydZ$( zclU+vEI_Slp1LS{?%B{wxuk}oeMu92vQX_b`VD!~*JpcP9vabYkeqpA8MY>~w%Ky7 zsVVrzFY4TdEAs-@dZBl9wp``Y0Wi?(ft_M9Q$@4N;CmXB_XbiO+8wIJ|DFy_u=gY$ zyVnT7A4wh=pBp0)?$}-s>%T{!IrEljddqYHN@fag7aIN~AYaZ|FK3?}# zC&>JqFao`|xBOBcn99V#f1~Kj70Oy#UzML+3?XK%L=TK^ByiCy0q>y8fw<;CAZU!Om`>%T95%lX=WV_!t+_4BgYxtxoTig@ldWS&H&z+yaCpX^n z?TTO~Z3Fzo@#Kq(&j#uZ{nGz^MD{XJ7`EOP=I-3~lVD3VHN-+!li01V16%yD(PF;w-G*&9 zO_7K+?>&%1{5ug%$fnjS=t3Rf)h8fYmh)7O+-+mN>DBnRalUmsj0@x}%Em5e>f;66 zm+`PHaz5pmi|XM(H}5mC^fm`IZ&LMu#*K&wUYo71^c(j+JacC5^VAun-?;1;OIpD< zP%LFLJv-R92OMDCbFdk5rQtdg5K!CyiX5+wHI}W{=zujt7O5Z0-k_T>Wx&3v?oUkY zh2SYCV2h7aosK9B1~Q`Afw6UIy%UV;OW~XUDy{!Ob%$MXy{}y-4EySV&o!5WXgs3I4vh8} zE3@m~qrm(lw&#I$AC=nR<(^+|80t2!2gC3XcqXIhjC+5d=v^wps^;IjtFS z40d-rGzju60Q~Mdukt|0Co?M7@9pJHic-*jgsyItKfM~=6h@^2flK6ldfbC@6{8-p z=hbh}pdz6njQUi0GxN5Q{{x~u4|vD}T09L*;_E(wXfZ_B-80W;UR-Eqh6qp@d~8@6 z`u;5kMEt1oZ+3HEFQmtP;@IV$7j3Jsowv{c+VyslS_D;^ydovp)K^fhf77r;{2-a=wa66$Uku02&hv89S;gW(ws?L890)W8&We$ zJ+thV+eIC&!t?Q=PT*IV3is^*ZRPv|q_x^Vy^opwcl(?QmtUgn+cYu1Uo|oc9kc$V z%sHxq5l-LsaBEOFflHt-fsH@vzeEwQ?lmBN@7{U`;sW?t_*UHf`+|VY5dL&oZ8@Ox z_{g1!E>>y^w8uDTKg4xkqrbgFr>@)@Le@OWKP_j+4vYAY0}Hr?@~<)|Ii+$QcjrMo z{GYQS_I082CRckkA*|j7Ou#L&rMk2T(=X+T{Y4Fj!87>>%ghGdi+wZ$jMnJgrI?xX zDx~k`9ml0<9DSYUKSc5jQk>#cJ?@TmhQ6x;cyeT4)9)A$N8^VFVEiid+vfLIe-w%Ay1Y;4=qzCP*Mx(st?F$%d9?$MZu zKjIt2vff~{{{i~!kUk%MzP>j@(Iy+aq|C}0m z6XBV(D^l;4WL>25&>fG({Jzosxc)v(Z5)lWg>?z@Bq{N)5|GTF060+H%sPg9{KfT~ z4Zi(Sc_4S9^lNnuYMG@+*+x~rrg3JEZs?}v-;@sq_FmmraN)nz&-p>jr#>}*;_haf zu?%Yte!SToRl_+Ju0+Meh@>N2Ok)vc|H$vCKfi`ySo<^_ZKfXUycVQdM(j$^iqwI? zwT#gGN2qOiy(5ns53Fu$0@7ozJaAq9yR`fJXA)mXf`K;oPEj?ht|a&b885Ksx^y?f zkre9wMkqa*Z;^T5rB*AgTr3Dv_k#TMyRvy=fAM=?8KU2x_U1``PF2Z@2f0XiW&hfb3FM4&+zR-|d3AINDg5JI=1WJ^?g zf5fOketw`sFtXSJ#Upi$xIQfMGdZa59(8-aj3?7{#`wAWc`eAQEAzYrU}gB^595nb zG*#Pfz@!OoqwaKbB8x0cdMkRr`t$Z=Cl>9thxVdNG~TL8u-|N25I=-b4|b^xIr@7f z6|emPKBESa$IJb4ZzIty{Udb?->NzaY2Md;CrxF9-xcxXsg_&gqMg*hjO!m45`*Z6SDfB7xY^8LVF?({2= zf|`4=V~lUEcZ4y>1T^>Qv&@-$g4MpR(bHpE-G#+Bt=qj4ToL#BB=&=IUVW+`{DWuf z=FNTblXBO7!PBPO`n(7=aX{|C#Udn8XzD^;HBUH!NOK03G`yMrNWh0Zn!7E<2pwY%KDoLYcpnYfHb`m8(w`PZE2q zC`+T$3=Z)p;_bI29g#nIy_FGZJG3TF67fNxY04_0qivyn@1%F#@7v3MpbTq`vDh_} znDgZ1@9C`oBOj~c4`FZb!g7$-E1utTe}!f~64yy{+Lj2A_9__c?(<(F?ZQ*nU65;Y z?^2e3%A+K3T#LNWE}hBBjbFaxWr!Mi_pCekJeGFWPga=#9_Y zE;)W2?k?uqy|ylJNTU4FyUy{kXNAh6==jo5_a(6|hYYIj062y#gU{5$I`!-Hu)k6% z96Yd3kHYi!08yO0%k;uhml~sG>A>0F^6@Iis{6$woS`EG37pna;33~-r-38&K|5M z116n#1{jUdjp4kKntj<+;`phb;~+myJ6vFD{gKCz`3AzAowgMT-i2@M>VE!B3C}+t z=ipZUfj}tTs=KS7-T`E}ROY_?Y(7+c9lSY-P7!i8cl7%(s1ycEmb%Av4%(PEOH_C1 ztm}WjbLT%y?2^3oWIU4Jtwkgo`m`BAK7nG%&d#&KSZ_^Clp8ZkI~Wpwi{2Oyv~>Y* zi-j7Hl@CW=foE0P^~F4DVP<}6z%_2nzviF6If7xQAAMG&7SbE`R{rB;{&^K%!t>v( z;A?fJuG$NqH9)p=`rAA`ST+3wunu_|%Z5&m^Mk1Bc-edDa3)gmILw*w?gwE&Uj4Z3sp;AY)v5 z+n%qUt=wohT0V)N4ljsAuRtzb7!9^k?@{mm@QJ)-$IY*yirs5(l~m(y&n&TjaNz@$;L+wx1=jDGA2Pu0GKe+;h9A*LGyt`h9X9?R@lu1@Q(#uUj7Qo8 z!pi~rzOX|F^JzlHxBdJxyrX_d^h0+R)9;)7eslWoRQ$>0PAPyZiBE?o@$zEWpL>WS zzvDfVhVn)c9d$8Y2zI;4ThuUp(i^b6EGzpvehTkDzRqLIQ7ej~bNvbfk;71cBt!;* z2s19=IXCeU6Q*rvxdaffhCU<^V8A)eTGgz+T(>8&uf* ze6eNcXGym{v6y$>rH3b1SPB;##SC9>DsXM^v7h4Gf}mdm)=iqQM=)y%+n2dBC^y-r z$iS~N66N8=7xSC%^c^-VU+^@%u-|I4qKB0?l)k;iqiZ~;g_?YqVIoM(49jP(iqZ&h zP1A9v>R&fp;DdyG1Y@NA$r~VmhpS*S zsIGvYz<}+afR?=?26w3Ng+Lm=(aJ-HTOFrH`w#m9h(Akj-(tEgMzkdecW@%S>9Gp!tq6QC>~JxBYX{5zjwRWJk!ZW%T}n3~nSb04?&vfqWOWckF_vk8195SKC1=v=rD);N#2t|H zYuK1!SnyqB(*=?|#Efo-5m&bxhk!j3IH>4gP+{;?FN8~?j2JI^1zHaY1X?M`>*c8C zalzLGkTU_;r8i=R>Cm4!eLhjJJ=_!&yt%Qx8cHHO6<(+(9~6dhfmb@j5(Lq55b%=3 z76MlXYXn!tGn5z;@~`ml;}glkaRVNlqE2VuSpTlcGZ=FSiiwW^6}xN~ zy{PPqmyZn!@5yvNtWQCIzSN^1+bI9Amc1iplt}HJL_@=)K}s1HSPzfN?=s)M^Sy+^ zIPo0cRT7kWH9_%((MaCRlVq?hdAyyuK8K-iZ5bgq2hwpn8{> zZ<=2VN+?BHPEQb!q8y^|P@T9);`eUD!POTq3j308l8K;jMz!AK!_qzCoaerL=$^Mw z1S%GJtPtzR7xX9t;BSSO)Hm}Nh`s^~5OXi!yx4P472=y8y>>U4+Fux|M@G%=wWB z+pO_u@;O=3u&aO^dcc{=of({{42-yC+ApnP;-H9ls$Paglplq!6u>NxksIYb-~kFj zGSNvN1QKvIjX+P?ux<4>%q8GC*QQ6W5bI}8gdT%W%D|8SpF*Gs+7}-i)#S!rd3~bu zb<#fe>XW#jMEiMf0j3GW>Ug0m-@D;b^86(a4$?%GgMPs?-PC)LmkuGjB}Zz^eA(-` z1j;_VaA4iDC|uTU$3~05zTq4I>BdAkwIMT;t{LzWDD>2TeL4lD{n+*F&@e{+CgTRX*In=e+}Bxr{0i|sine7WYK=CFYpUt%@X8WI@egAT|$Ak!S&cE946bp$?ArAJ(Jc|l$toA7E(g~r z1S8=eLk0ZK=Q#sWD;c{fk0f7-G46v!2^PKDJ51)8Im%Q3?7_Pb1x*h(kkaVh_Sv-!0ql)Q1Tc44YieW7pp@^knP#st2Ey`UGE9iQC} zL46Hauy&bxQF;J-0F&z)8ov|hN0zE9Gq2p%V>r;@^Gj(IVz3;zDS@bXc@ija5f}jK zpE#QhIn51c01*^`p%3$Xg6Jra2|GbF0S2JK>hCjvNlw*W z&PEWy@bdb|%Zt)o89-*B^8gPkXht_&S0Xqc@;m$4xuV2AIYd``+66c64UelrDqXc7 z_dp*cj}j;n+!p0P0p%Fd$&dFkqhOk*AeR4-Q2lZcX}h}p3Fl$YVB=q;;Y+}PGfA2SY-zh0x?iXmXM%+0wSm&+i;)3A? zl<^wP=;~cQ-&p^rHSv7sr&_5B*y|x#&xcYy+_6V%PrCcfJ|!KnY%wtoE{&NyZ^AVJ z$5;%XcM)oa2${89m=vRi2q_718PbK?V7TCX2uq=>L9AU%FH&q5$(g+G3`o+^hUS>& zLgL?*+~J-4E{Az&Mh@aK3}-`__Nz0%nJMusRX5`m!2)jtCFyOg*#{QE^uS@nqzv}Nd*nTh3^a-d$iw@5KW&L`ryuW4TP=3HnH%F@+iiJj(Na3|=j2sn$b zWCQ{qllrmD=O*P%1=YCd&Hui^N7dRp{6F-=_$J}9u%0lB8*lfET{oP%Jq*AyX^CP5 zAdtHUYUsG?xSSpBE!PT?G&lBJ>qzVJJZ6PvliY6P;}=Extc~u^PB3|)?(6U3#&61_ z!@B5ocN&T%hPV~%DHY>9ui_J1fU1G=_m>3N`8nWkd4=HXKoJB;(5nMV!_X^NRxXv) zB33WQn6dO?=RW`rAbYd$zwipttKX-}!7Fh44tO|*DBH&OLvL``#=>F7@}T=X>zS|L z1DuY7CwSjpb7Ms`HBzd41huFe5Y-`*ph)4ITsF;H*HW4pvC zvWFqe#jj9mraoU5lM=zaHWCj4i7*aglxS`y952mwdj5#du{;KG?Z7S8qVVwv0qxwb zXboaN+2iurpS5S9aA)sI(*i;yppVH!)t$kgU%&kvI)U5R>idQ8Ce=&}5JTRTZM+34 z>Hu*9NaSM!C$}Mdzr$tunsL!lH~~j|=ZCyS9&r&SF=wyaUQ}9|a)Ef>LxEUnr-_xK zyZYztG4~s|$J$U|UN%w>Fxsi06nY6?RWwG4?Q-coA7@FqhI)jHlj>EKw^ zLQz?0L~-zlC*(tX#e?m-&dC>uIlk5T{SoXf#vki*_dF-UF8k==0L=E1eNkkxx-k^) zMeqBsE>ex}`kr4Z>+#Cuw)r@&Fr3e?ZyU2=PE;84F91se0OXE}!l5kRi}6~K!e~Fe zTj6>?09l^8_brH{)w{&E6GYUJ^?*MmFP-<2@)dg%6qMGy$MhT3tvf%C1qVK$dUM{F z4wK%!3&Q)mKav9~6_i#95M}JI)4cE7Z|1Mfcr%^}! zD57pkp&d+wAzB}{p+?9XcttqzvoBcFF&U7IdzI##{YJ&p=`TJI-rgGL{pz z{8k8%XBY`;U}0%~e;5%cR|5UsOM2?z*2ijXO1<_H_jN8HkLqtZ6dx2wB})8N^KS>t zQR14R^h4BP`c?){9_Wxra`;4U`p3d!%L1L&Uxd}4Y5@z2b%yiGMchNV2U`Ayejx&P zCKp&QbOgCRj>O_{n{Lzeje9gJmEDZsHR7+o`a6CSbeF%1Mk4n2EB+2G3R{|(H0YvY z0PQjHEA@lHCkt20ZV#@P{mb3&6$zg~g!w&)sD_rqc6WGj79KSyETwzIe6h&dV7A~8 zbFHmPe+Cu;&OjXB#pHm9Ys&o&9Tr;`Xp_(6d%0yOu8`9lS>i8N^!-zS%VN}z2Q@6+ z>6V$sQh*Hr%2T(KICJet8FoCQqdV}dMd%)eb9e6oygU8g;4#qpM&r1yO9`buXf39h zT~puB(?$VNJwnMXU4!9!Yq?c+AB=o+9R1yj&2ne(Jb1q$6P z&Krit3F#tJVGsKS8jIadf{P06W1acO6=UxhOzCGGT-Hc5DMdJ|2%K2K-Q!nA^V;o?e+T3GKoQ$Z*qk)#+5ywl_8Y3Y-2`7XWm9Xy>43bkILYC+&F1`aNJ^9`SNI53yZ!#$t=AH+lrgddf{}vvlUUV;@cT| zO`8aCsRyhQrO^c=rt7v|WxYGEOZ(+IxO!n#Li{$&@INkGf3#sC?MY#MKnFm;`ANX) z#gBOWvsqzoQC6hKsebg?#;K&+pcDjw84m4*-zs;AoAm^Ub3F{c_8rT37y&zpdIg=A%m#V5*E`(kSEi1D|5PJBR}hz{`{7?7y9 zK2Y!!a22S76dp?2J~{dL2_P4O#iOeaHKGtHr0doKgm+I&K-2lP(8@MQ)?}{2S=V}RU(uQb_CuLUJuD(1?FeIZZ943Af42`UB?JvbY&TNC z#ysIP@jHRyJ&v1*(_#}ULLW%`%ciPCKl{Y*@u-7_@sk8zN#18=Kgu740D)YXe%d>j`|GXp}A-1UOWNoiqtQXAp-1GcoBYNHcE}KRf^{Q=e2P|MVnk zLX1YEXW->vO|{|20d|a<)B(uG4w#^_eSe|c(Cq~OP*fA$JW!5ccpwJVGG;*F1Sy6c zqHiyHx|MiUeCMnDW<7Za>$~)yPq;LDADQE`#6pCPMk;tfVD_#; zwu;^nRIh@Q_WG6;GZTQAph$*c7}>5fWEjX*Ep~+sy9b2g_h9r`dTD^3|H^^Q5QY`i z)*`!mal%&YVhOStpDmEC#P-=J=L>xTnIFy+Xn(1t+-=^(tn>DeL-Nc zF$9|{eP;F(un<6B-$i=mzXfO`F%Q58n_Nm3{W-V_?qk-0xo8YsrRG}^vvGGk5C2Bv zPpd&ndm(g%cM4$Y8gNX+U^PDG3XY53@2x{Y$W7&+2_d8xf3*ncmnh(Dn|4W1xy9B5 zSQ|fTRCP@TcqB%3T-q*5e;#WC0}fI?Q0?M@#^}y$DU`GPoPp@(-#Y(F#NBy|pr4PB z32r3^0#qL1vqnB;eJpH{XaE37m$VbL1Asu$5t0F@FUA0Tf?2E=J5w>9Kz(dG>H%=( z3OE7XXb|u`z}C|pkaXlfJ~`{dS55??ozsq@HE5sWpeTI)41N40jN1C0P5GkZw8r*j_2S+FhJBHtifK{ zVL9&qdA__(gGp54w+K*oK(MIrk&EM>;r3MSEb)5L!;rw5-1|M$&o_Esgu@8e&U7rO z+-;hpd{m$rPPsAkoHoK+Sb?zMaI>eFdTvfNKT{274Jv_d$Vf9bQwVYhp5Mv^3Q2Y$ zptk_WiR=~Ju?@0ffFlEB{QdX{5M+bXt*6v7jL&}iBQo8{FGfU=pi%o#cb4gbkY%7k zJ$NpX>7jc;$!@+X>G5P_B{1O7J%XnOh}vZ8H%7sLAoP2Do*~#3;zmX5DfX_wp6M-ud1vtV2(=Z=5)kvH9hueS&?6WDieYxBD?^Uq z20$1X*3P4tm?{OP=We0%0-*&=0kAw%Rg*s#+EK3K`GInp0Mh2<;`pIB@9@-me7pyk ztJ^n-z6kW5S?FvaR|Ck>I0j`jLkFqe(Sk=V>lR}qq8~;0C{yX^AO|;U;2rjUsjsGE z!-1K3&i4n_zfxb!N>xr_098h6@0I}Eb9*qGKAhTvtGc}3i=f%GtSMgm4(o_y*G%+n zSon3g92y5ZYfo^E6>O};C;mH^#ouQ`cne`okd)tU1a9457&D4n0;a0{rC+Nztvwyk z{FTng$mcgEwU@44Rt{>cQW1SHP%3Df(#-VCnE?qSkC`w)v>u+PAotoEwC34UdJz7X z{oG$_M>ZtnHJcZgxwC5a)S+V+addJy7z8Moa1=Z%vhN+LX^co#k*`VW6WWc$KO>$i^I+gB{B6r@F8^oIop zB2l7#J#IUFvT5TGJ0{M_oU<%vD}|`;9i_F|Lr6cG^vx~>2JP|#qx|=ayrVx^{ACWy z0xv=4p2u75YTCiWX?P63?MfLaol77s_sa2BdfVqZP&R>R5Ku_Q#Z)hztkrl7uUrA% z-|dEbuwJuwXhUn%7ExQC-U^h^ft4i@sXJz&qRjo3LopT0ALXF$#d*e20sSmh)GnaY z46w%}0Mz#tn!Fo4Uu}kXQMGd|b=$*tI4?TnmO{oS4S$dbm9$bN<=;evch{jhnQ7cW zcfmW)=yEu2OIE)BlJi%tOK-5+K`tAhie~c~8miNI+*1#=R8418O&JP7!QDHrf521R zHV-?sbOP%nkS{j%1r?ecDsAEbM+4$`sy+1{2XpcT!TW|IG)fN7N1wB(Kf$P~MT?zu zkfKTZl$B)l4Y@9Z;z0FNxLrVAh7=aoZ=5q^SHHWPy)QS$Ls^xLcW>)Ut?1qZNuut_ zcDeC>!OaNY4&}{%%-?V~Cp0|irhp40ociJO3TEdV|Mb-n`5vS`Dbx=Okw}J?^Dkk0 z2p_aJC=4k;xv5>r0^b#kbp(7oSRlA)kOsxU-W9z?+cTlVd%(y8o~$7iP3b+1hx{vY z6*q%bNeEfcA|Goj6<~Gwps+S}tjPrX62HjgjZph;iCKs|!|isr=x(^U$<-K`hx#sq zR||oLvAlM&=?$u3s}%oeo$?i=6Q~D{iTvHo4ZcvOKrmW!_3T?w5BF-;82b+4T|Zo4 zWzq#5C$+qmfvsMv`=WSDWx|BT46wx(KbgiAsrIfv+wq4Bdjp<8XEMjUsbgOTI~yFx z*}+M^-Fmrs1p2tasGniYgZK7(o40rh{ek-rUIp*|Zx>p32*8+D_Q&xF`MU*Aw%mTo z4MYJ%na21C58(IeDo^NdaeI=}H+*thQO7?vcMLgR34RK3WY;}Ek08BOGDs&>uluqA z)ZJFD3J3a=@soC>-O)HOa;%@L|GErkc6$@qPX`_tBvI<({>?M-dpl4zwUxMl6%(jd z%CM46W*6`;#k9Ishat`|hV0)le=mE3*K=8nDd z%cev1IAwmvtaT@$3<>{1^PYmn{)ehe`Hh!ne=BDYH3Clb*V?-H!!&ZrTR@*BPI`Mo zQ})c6=r!(ew>|CKc%H==R@Y!OupeJ84f#S)-R`|(lkdCYz0DEhtzPu*I;cP>ENP3? zy~xJ?ftR~r!!vAnFdk*(!In1O0A54sXO9D@Hj+2s>t#mI;KRPB`Hae-{%Vm83pr!{ z=g;BhE;Jk`E_R>gq((ym4<-8MS#-VXTCM1I5ufo-3v{i360PA%-WRUv+1j*qO=t`y z`AV7$nr&@MY$O%%!f$RblTJ|Tya3N2u52jvdDQ*$?lIZ9$%pJZ+r67_R%9?Az(DH+ zlyxQfR^-pq+2=p}taue8DM2!B0%pktmXqXF)jIqg(+D)T;po0Jpp1=fY>{&}nbbGe zc4J<{RtcFpz5Pm`vv^|u{gyE>uwsd>?DlNDx9{l!4!PlFtTU+#z;F5~;qOy!+^N-4 zmgrQ9tQD%m;;HVw@V$aNL?hy;Q1*7$w^i&5gm_BGk98}M>n@jIe@t9Y>}$pCe6NF_ zJd6NZH7yn)`7Ag(0T@dWef1f?$@l_av5Ok5<;arnDDQRrre6`mwpX{3PH;gBq%rY~ z0crc@$2`(s^#gfINg*J*f4|PYppoKq_)T>v6khee4)((h45im?B2x)!cxV8X64S|3 z&^OYFFVbC#eZIfrt>@<}UmNcAyXu9mv}=NZ#pO!?HYdv5Yr@<@iOq6tC}4PU7pEKO zDsQjP^0X^U2ru_ZK|O%OgoGv$0MUpI?2%>sO&5WI!!LmH8{+1+-K1BI>P>bEk_xI& zA=lujIWB>Uzd^#XSdaT&=9fM4e=ivqGb9;2+5pEIlExL_)Ewz${9xYJLHutK!~?tI zn0sc8tsUO$3Qgwi`feNCzd{`wqEo08ix+qyfi4zN8fb|y=51ZBL(i{Cqp_X@PbSsV zaqsBh7%J71b1TA0UB*#WNq~l+vB4vRPHtqA{>N6_f`Ph*#vW7qoxJvpTb^)c~g%}^O^TKW(k}v`g z@w-?329t-1`t4Rdsb|N%-}&GsR;u4&z5o~)$e8uj2Gda3Yg1Hxc(TvmMn zbvVjEqJufJD@?>1;9t_H!Aoe&O|08Ie`6STfN#My&c1K&sx6)bD9kW`0ATU$c}(}Z z1a(P>UuMg6dkuZ01a@N8aKQN%(kPaUSMAL8bXLXJD<_pBef7+Q`SaT%mbinxyUZRI zuuu|GjJv1uZFjG_%&-oc57~iU(^+89)}DfbXx*uF-oRgn5B&gwO5j+8=aa1JuvG+c zhcpB4;Q{Cno!9iV=5AT{VhhB%7{!dV7W~)eA?qGJe4goU{*d)D&+db-ew+JR_ccm; zwE^cKXm&sW4m_Jk#y_ly7Z10MiA{%t>;MO3420*=ul#YS8+n{Hur#bBHuR{3QI7Y3 z%+WC`;kB$=#V;0dgw)@n5KE!_P08(*hl!%VQntaHWAZNBv<{5aMsm_r@_GFk6}SB* zg}B^-DI}a56*?9^NmU8BApla1nYWokK>gQi;Zs_2$_HG4hX}BTItiFJ_a^{33w$E}~xj-W21`XS13g~S_`>n<3@O0*f)GELjK@h4>oz+e;R-zT2QtW|@9VF!NuqQy! zoK^}`q7Rn@NBuX_FBnJ>w9V!`QPb>Z^IOXMbb>&M6;;?Q8S>Kx@;bmGol}FoM|UGh z9W=VD3a|w*(Ppfc&PwP_)?5J|m=2X9dFo z5sV^Y&H2J*>?tUF^2Q*bqaHQzjiJjX;ZNaG(S@4nFrg5fIK{8V_rSKsNNh_I#H;U| z`F&5rvbL}$R*gG=yy3&4X6-*n1TlTN?t>$|ylKbpnma_NJu;A;dGK6b6dUjlDo=Ewpc6CsyimgSwoys<6oU!Chnl zGf_5d-kixw{TxGsSOEIcJn8 ztJE*^*~uo~!SjiKpv)hU*UZu7=NSjDL*}2X*Vi8vS@DR+obf&#BVM(tt`VW=jEmS8V{to z8}jUcEUfStfO8=w%DZj{t|R>^{=%m)BO>HPVRZG2AZx@7@G%UkX7sJ86XcHuc{1;I ztX%AFuZ$}YjOv$md%j&E&~`5js?8ofwxr$cXuCbE>LP=DD?7zjNK0o?6)aHG?&ODS z{D&tuQ{hU_@iK))%``Up2FdjC@CGz4x`NFb_tCy@`Asx^0VFCH7U5KG{;aSWA&HD6%VIx zWi!Q5I1z^ke>6{QpaHt@Fp2jQ)X$lD1DkWD@rh-^0ol-#yPak|9a~ot*`W9*o&@I&M6rRWoXl9@)aWlbw-i?KIcXf?X z$rYB)56EF92>py1{f_D?kHuxm9Ys-q%RI4`3d=Mo?QcOufu*$q)(IPvZ;HH3S08@z z1due&N^71U{4ShjBGL_W=Riqo7FN%nBUF*~6Y z@YaQXtV!2V;JFZWlp|$O=cv~NN8uF`k8Y>Ek)o?XnZ#=d|AHs}>>#hP$4$Je0$G%n zF@_3wpfhK|g1rPr*3oAf*UucAk2g(^dREB5Zt|O3jx~zkzjmnjU7=K!G(-)W%#@Zl ztpLQJv!5d18j5m>kJ~Ag=%q}p$NL5~5g>q0qx6<^-7#Np<$G2)iHw&4YBFJ96@ym% zlq$21$1R6Y2j);OZ8GlVO=|lmjxt3|UoZBl_)UaZiUA%^@69uZN%LkQf6S+RUQ+MISmsR_`ng#BmPjY!Oyd^*D-6alwut9ciG z2n8Vc|IOTPsDDd_ItYInL23d+MJZ{4wVg_v*bf?mgj&Fx!Ec~b9@1Y20RP7x+M$jx zZzmxuut@ZXhyq!V?t}~as`poAG*5frKOZku0`If=PuLc;jL^Vfxr7^R>hLZ=Z!zgp z9E`sA5Amn?863lr+8QJ$7HSjI5&8nk2H^|sWHHnP=`*Sl}+o;fZtI ztofoPl9x`xuNDk#F&cP65d+C{CPI+U13Fkv3@89|kMiqxzGzpQ9*~;;(borDm0o(} zE?h>Mazak^v z3z}c22=a}yjT?Kq)uTxC`F<60a@rdy%((QA5e?GWDcLg+iC-i1VfZR;hmQOLoeEQ3 zs98IB*q}YG$yNXhVEmyuYFtxVO!}w2NeMevb#$KJH#)w#_VwVi^!dyYPt72kS+x z5e6~(U&as^K>Cz>Gwy(+0ghbj>LR?hpSI4gkc)$bn#7?;KD{`=f@dm!z_1?$QtBH< zhoTq!h9#;k2v!;ve5J|uySa|HW2to-Ts*b4Fc}6HKt`Jhx1go(5JltQlmWV7X2Ofd zWWYrzk2*y-c}3JICN8!Kb3(ZoN(lOZ;F^SYt8*-9!Cr|80j}rI=YbH%y|$B^ACe1Q zrR*ZdS={XLPPT`^Z16p{s+zSJtujFBj#QM8L%+H$7|1Gt5BpicH!F!+-ZcVri~dq& zHK*`|1mmOab+MjBJ;I2RZ{_Ar!b2Cxe6$Z?(qrg99csYG-3IW6nxVq&8$m;lOL|d$ zdO5b8*yp)Y>4tb8m(kg+1fP8c<{Ph%S&to1wx3$ z?ES3YarDS4q<9s0{S$E5y^dfAidfJ;Tu#%18iixP3rwA28X%wz9I1|8_JNe`Adl%M zgs;FD&=R^l?N*a&*8|{Ha~$n{ASmTEi)Z^m4eiJJa^n~i9=AV1p*Y@6UxqE#hBDeC zBVh%y%5=a^^w3?UbJy=r=Nd4)4A|wjDc;+k)U&5^%J#Lm6Zq%6@Jiy+!Bt2pUgIO7 zXLX>CT7V5}J0UKo$E|1BO<&=SQYuCpMXreSuh%zswbHO=>mD=Z=r&mmZLlEpRb;2SJxJ2=LB?fIb(PNV0noA` z{tQqxygqM_)oYy#M3Q6EaCBV#8t#6TfHSnx-g%D+4zGoJU(+BK>rM;il^7I|sNIt+ zr*flarXVO23aE8f+ZKv+F2aQ*azmNp1vHxZq86~i+~PNF5ltS__Wj!{qo&91$H&UE zoS(7@Xzp5&=`X;xy^+P-c2R?wfkwVMHkZr-%%c7iV;;Iy)r`5FgJf3pflk&0B9q21 z9W_jMP=ob13CMJe4rHvSaXlsV3O!WkEN=^ZZ8di%ZWkc?v3dk)M?_bb2P#j3Xu=xV z2P^rbeD`vfStQQOX9peH(gq%Sh*J;<$UBNA=G1jnIvaqH8j5n(U+j(PnA+?l7($Co z>!T9t=T{3-nou@HJ@m&!^GWmj;Moa;PwfsvS5ob~XWqMACiTmv zMY2Z}nEX07d^J`pYk4zu&seEc88cP&3+LS{((G7L_j*mYuoYtrtow=~a7`Tg*ac`u z)^Pm0Roip+ush4&yExsix6wd{y@WPwZ?<9eczlbMCPI0(a^R`}S{W3Imv| z>tY8HryF=Uw9L^CaJ+zB#vGcN^Gt{e?|N}+C3B_(Jf#SU+!u#qM)+RbZ==NY{2i)% z&ckhi>r1R2enQ%vP11f3Ds^fXSi@Pwo4$j3+M$1s3YVudOsSB_3`L-uQ)1DB($T+FsV9%UGMJawVJ&H#I2f{xv)Pr($u{fZk zE_+Jp1#b`_RC`ub{kh9?oU~ZKh&epIUu$6I8il^>YsWpmNLI(C5f!A0t)VhQ`hd*P z2vaL|=U@q8JQYRTA71d-;L*AnOIl91R_d}#sh;R^eT)eWzn>2f44`_58V=IHdV$O_ z@_Y_v?dITOT{P{t6oBw#mE!l}94$U6fWke)awnff6P)a2DTfToRDgxLu32%ox0vXd z{cT^{r#2%jJlw(9P9!mS%{-Ab=eewIS6|Tsux)q>8a`|=Bmk{24uN%5&rNns!u7z~MYR0NEtjLClwp zg3D~}wI6GQGNsQvSI|~{VXpb+*3u$9kd!BMMnl_pYt(^BAeg%+pPW;`W({!!BN^fG zl%d^QQ~V1ZzWqf@3qA%mT(1Ye7feUMbf$4E zk!#p<45m;J@(0ZoQw1GkmU-VvB)^cZC_|aJik}}Vg#}@M%C8cuVCoyp93t(QiRw;Q zQ6d~fUwio32~>Vlvq;;Z<^2V$sp3PQ4_G&C@g+D(u}nJH?9D|M;duK&HdVY4+p>N) zx~WSrAYIcC=zo8kD*q0h5nO-3?eyv!Ul^b+#b25eBbLqDFK3UPq?983`g{VZ?!Lr( z`Y3k$bpq~j%*`c$F9kUXDAZrK$28LYGc2G}jMKu>=84C)2zBkXrf?uzGT4a1p1bIHf4FnlCnP~OB^!%E zFJSCb&~y2H(FY#oH0@fqemu-);xD&gxG^6x;pJi}mXo>(v9VG6pzYttq29@pMD+5x z*_gMM@A)X;qnHDILg$v3YlgwhW@`GFUwIm7N`i;d%Jz3IklDK+<}a0jP|%4c;rIcJ zII*5dR+F040o!U4%>;-bOnE;6cWYhh);t*(17f-FSO&&fPe@Ha8A6G1fPtFdhKz`u z^6wIbn^3k{)7<97c*tz9Ga>>5(N&##Oi1kOA^bE)zy|=Y5gID@A7>7vwwmDxgQjz+ z3?QEA0AJkur?1OO10;_(MmF?mM?smJr3C3UUfrl5tJ2f@=dl!kAtef0zz%e>^(bE7{Gri z@1ll2E^}btx z7krm%cq{k}1e%Xmu)avW`(6^MZl%YS4e%dEF=jE|^`Ow~vLqU1dCILD*;BW11gOS7 zAQ3P#c7na(QZ4nU+oQ-HzbUjI6J-3-_QLho&dKm=AbpYbdhExQ@~<0#aQpSDW+d># z#62U(z_NZxy_8oLhStl6`<{CIRAD>=-6m@#Ks1Qy)g^lHeU)d|qsH!6U>lxRLB4Lt zbr&|J21#6pv$~_bQ||dSIvV;`ihh=h)2_kGJYP`U{8HnI9jQ`v&85&E^tWwG>CW0s zemlH-Z`q=t;)Ky5o7le0N!&j5?;2z0M|!Lzl^|@!@B5qF&O)jU%l5r&AKl;t%#)G6 zGzUn52KqALRQ_=-$a2bh-|^6c-|uX`Cr|Af#{+D3UUoZAb^y4->?bpl%G2Pj6Plwn zW4(rXli@sek$|(@XQ#5N76CIGi@*g-a2aS3GIebTaYB3x(D-e3`OFFll0b0m zt$vtSSu^N{!P{bgx&F(n4Q(A4l2QAwcyN!>3^M)I!qm(MegWg$027r@#F-W2@|Fa1 z=U_0$w_FT9W6Qy;AUfM$oY!OYe47ADy~Bkca_SgVP7@U>pWZi}(_1&84agSHiQ`me zj7^aYiZZXssX1Jvflwfx*e?$#kCmQi(u=(og~VX8*ftmAL(49UpA-yxi~s?nptE@shG8;R!a%E61-#h6ckV7mFQAM+u5|6b+)IoQ z>J3D^hA##ZK#G3pn;VBQi-D!FlF98raI{ zqJU}#bwLz3J~dsME>jgflT2&|7D$+40;-A?mC7br9rEat!^);9-_#qJ zT}+a52-COWY;I;do#g28d1(g3j?NM`7v}(E;xSt-6u)ap%pzQV*4I~<&-!0-$jHbd zfpl~ZT<_)H`r~b5fh5Eejf6aYmYUYk@}T&OCt__%Aiu!K9$9N*kH;5G)SOOo388Gz z5|faiRe}4r=JDYEaG*`QZi+|+hNwV+B%}Y+5_FynY50|K;D@P&NN~l4PG%ElmPhDV z>-JX@Rs>^Dos`6!Z4%@S+lTrc&;LezQR*QDw>%S_;)$=z4iwMOi5S`xo@^BWP@9+)X^5ro$JdOMz290g)`Fuxn(KXaQ<6cNP?iUVl)Ez2ArOrQ&+1*ZIx;paDCw{mbB?aTF}D;(F4~ z^ImBBb-pz)gHRKd=d6o{dxD0+6(oNrt>@gZP&->QkpcGh+JP0GcoV1|K&mU$Daq(9 z`g*|}xs1umWDSAYr21^zwG*Q~S1-YW(IN&^N^wBzZDQGnLN+3Sy0;WtpG)%f-j*Fg zbgX=NFPTJyd-0bgAe86SiJaHT-hED)K_JY(t~f!HX+S~dBc;~xU23Te;j-x~idg@K zDEa2&@8inW&?I>S>sb;0Dl7zeZo<}7yb=h5JF4a@Hgbf*k{sm=8T^Fm00{kbQhjchLI_a+X-CCD8+0&5u@ zq=v<-8Sm8`^I&8vX|t|7b3Ro@BlBwM`2zq-r_!Nk_JP~f9yINd+=FLn5ItvjKBV(6 zL&sRyfr#{PB`dnoc(p}7#k;y2c>L#GPM}iDAJ;OfY0)+B5Veqv+XdqY} zFHw85q4y0YlYuB`ii;PhFu$8?^fr^bh7Cfp8`5KQtgL*StuuhNj9Y(3FjT!F?*PI8 zc3<*^j#y0Hs0efqKI)I!0^vuOrRYnNR&JSM`26jvVlS^B3zlp^1&AXrqp$KI zOTc>uyVPNU+Kf75$rF8`OCZ0cf(9~7@U@$5B^fJLHZ)WM3BuY<=7K}jg<&h-D2O1w z8qclDj5=F*HX9vtM|+ML+!oMRM0;Er*SKe2;&>p(y??ag36VChE-i@-alfF+7wW$= zfg55`)psm|MFiW zpzFE#doljH53cK>TQ^&Dp&D~%&1$%sz9P{bdos^09wuNEH(x|Q1%!3+l8#^3YAO*P!3|)bvZ*d&;^o!oUHmcJ zCOFE%l2Q!Uc=PFWP&D$a4WSK7;aKr3cD#=bmKj`w2JS^pusFEB4sjygSKcP1Up)Ox zWtj!gA%Wvlfz*aLyR`G02KhUs;|M6_vD2SlMW$};p6NFS2<;E(={lqZN_Q&S93cs6 zIHbr?;RPmNPG!sF9TLZP@51R?9a_ds7MAj2Ur_tsHhAw>bLQIXwv#hmru?1tBPo-8;1RU) zSx*tW5kexH+esIekcZc?#j^d!66C?+`zh@#2b5CU_ucIUlXW60u>BU`yii|)xulW#XL0b<76dDrG#-@n>^hoZUa-L@vQ zvIyew?gKG}<959s%uO*j?2lrnpp^g^qzixBQrek*V4sNtA(%xy_$bclbDpB_-PmRL zdHOG1AFpKy8&+jVer9R+Kz2wCDS#1QN7f&k?wVWnTFi{66TnHe%oFE4_u$YGJ$w(t zH>E$iD!-4~8=qcQp)%90`?4-aH=Wg%I+_u)q2B@pb;P&+jjFm9r>&TuOZRuuDD`@s z>Wi53(YbmnOgDKM8HSn>c0;wg(eP)Ob%gil8J79&k;M;xlk^mVYp=87F5Sd_lGjtJ z@9Qo+g;X*X1r{owc6*eTj(ZKSy>-|pE~BN~p*VF^D;z(5ZBA=!sM6`hBHPVxCpx5D zkj=6D(56~b;Z)1|$JqeRr@+bQROwfcCVMh*he6qjE(`;*CJOV zL+5S%m!b7%8YagJMwd@WeI6|HHf(WOG>=Y{%-Q|O#kqXmFFk3VcND5*py`h5lY3q9 zy*-aH@+M5TndHM8ue$0@tH)W~^Xm_S_Z_je4k(~w&_t?Tz4lnvxg&_in5>j1c{i%! zXgPi2Mxm~Ht2v%=r{1|6PsvKZr_}1`?C228P7-XfW9+QIYD(zqMX|h)u*n5OAO_T# z*PT;nBrbVkILjAzFWOf?QQ=sUARgOf*_H!W^Nl17CZV9x@3f1F9LxT|?mbpk5{S!# znTB&?APXcBoNy1+HdV|rm|)Lln?3mRGF|`Llwhos%37y)=)*vk(Qh}pX1?E(m%k0P z=T48NAM6wJg6^~VO0VBO-`^c9*IwrjoT*YW}mQ6t&It133*(s^24 zh8Gz~0*}<#kKRP=kk;v!KU+|jBq*|~PyK`}u;6#1H(L}?*KCjK32*;S`=P}wfFV9= zHf)0EcZbgEb$0PTRo(9oAd~5r8eS(fehvs{xd~PLU0zjiJ+1M0V_v@Tj8yfJq4v=U z&qTSKy9QA)RQuSD?6*82ipRMFs(?sd)Ytf~hisfx=+B;aCkGmCu;Grr5B~A@V}R7~ z!16J9W(wgZ8T1)L#ew=vo9wo=9(!b6lXEsw(LK3oNXCf;*EolJ77B z<{C!&cjTS+p(M(~k2Om^7#F5LzHUF++1xr?OhBLWu5qMM_q!#1H7Q|f<*je8EXe{f zvxSChe(#-SJG5`%p`*aDzK(Z@v#UvNrIzs3z|o=k+DxkG8>@|GW4dp2m5|kjUoHyI zzFJuohR1yVVEcr?18T}UPBbM(-XfSq$n$M|K69?Dlmy;Y0JwhXrX6ZexV{3d-XTU}nK>#`LpKercCYp%~KC8xyk-$I*A;z)rsAFGb`ljop%yfjq& zF4uK*DcuyGF73ZJyW1%a0cL7y5uU1M*MVDzY}l0+&>XTf+@^1`72J^;nsz?h`3XlK zDa+ocOEAh*dZ!F0C=nyR8hgy)cZ**=xa0Q-LOn6ZK9W9uLJxg7CNpRh@ zyh}>ogGh}PosIc_U_+Xu1NMo@2&ILPByFNyn__hm{}p&H`mqeFBgLU%DvN&XWY2x* zqzB^De4J|@fuDQ?xA7ziHbg(ky_#OIne@fF#6UXXx&!hYf&6=;8_gn3Nj4wfW4A}w zw2xK5AkNVIpd!FEPy5-QnY)MM42}eFj=G+`k~^3buNm^Cr%SlU8+|boHkxvXxFXh^ zANQOo&pS=OR=0>BMD*F5+q2%vaqQn@q8V)?1kB(tMJO|S;SMwyCV#q(TpPK$5qnk) zawdfpq{Q{b`GGRb!c`^pm_U9843dU*dvb>Ss*)-b-}Iii&(JKdwsju2!r=iv6nOhN zUkRvw`K0Q7Ave=fX8Igf2k!b|yF;4Gjj!M{u5-6m3UNUVR~eJnVa?lhIRm@(#Wy{b zyWeF>uQ6HFq&#ADzUX@#vah+LQ@8BK5b!WsmZGU|`Z|8kPu#fBX`YP?>96Y%L2%4f zG|V#&f^{Tc#9L*`h0d6JexEn!u}bZoVv*vJKSg(iE#>+Q=0rOZr*2CXt-Onqa^dQL z{B6~?y&KhfN)ufNE6=WkBl zSA;w79y(#BvWOn#{nVk_pLb7#@8OQ1)ERgoQqu3Yn4~uYbCqx1*d-jf4Zm^gyiTgL z-Y_s5`LzTlo#a(>xrg^+;POdzrZaW*K35IVTx?SACw!-sCtdWPqg8BTOAE=YF6?7O zUTu_OPbKUh4Jcp`EjL?{Ty0EmP_?UmXa2oEoq9r3@K}oY7JafMnt#iFUSsMb+WDq7 zs|wD^&v1S+gb`j{XF{0fU=_-ZI{Fvf>2BPxb1%*ZJc%Dd=eghMuONR=MFLBj`g?m0 z2I}v#+sm5=yy7DDx{r!u$lMuq>$ILj^)w6@`pkysH|=}f>`bgiyDXZpt?r&js69&j zf6}2QG`>X|c*I}uD>rXvUcRm7yulXM7vHre#!N_R48G|&eoc|^~AU-BA z(!;yp!y#&7dL4H1nP*8EJKy@!Z4^S$`f2;xE#f()?jz5B$=rbo>`$YQ_yI6K~U@B0eA$_e|_OrK!*U~>;_V*}%!`*I1t*lz! zje$&d#6xhh&+nxA9`yjZwy$rRmWG|nbd2nJPCuQE34dU}Hq>Nl>M3>A;(p|E^+CCS zcBpub+N^+(E)g6C1XO=2`*?YWV?w-he26>{-282{tj{PjU|Cl!QGS@hhB0CLvD5n+ zYMx*rV0#82$!gDxYb0nCeliq@ zr}5+U({E3I6T0c_%Xy=GFW^@jnX#?z+v{yDKc@hPtKE>{*zkPITJF{UI|*>Je=xrf z0U27)7{8LZt8XWei!zI8_&E6D8j665|t3`{7{`L;77E5O4~d2?OQ-)}AE zR4%QTiFyE6e?`au)6HyVCFWxfnn{Y~;Al@@eq*`leX%)r;{EN!4`e*^8@8H0H6Tt+ zJA)^~{N(E`K^InSPwXunDq#P7*sB~@kW;lJGfykuT#-)u@!hWkV^Gdhb)@MwUxI$eD;OFqS@AIUU<~$dwl9Qi3Zo)osR)K<*(&e@ z+W0CUJf~Aq{hkm{6gw?HR!L*Oj@v10KDdY-HT{7S7`9?U^j6Wx2|CH`2_gJkcJIV7 z6X@YaU8BY8vat&j7CEa%;X=gMAP|jTUgpw7PhB2MJi{C<@v-~um?x-Nr)wTphs9?} zYHl(FxCed8>dOtf1F)a94IEUtazIMLh#zFFj zaQbg$BW8OM3gyuMp#Sr|tCQRAq0J#;JOAi8$lf0P5Fm)0KT30S>*1#Cywh zU0CbqQ2VXFai%@BH+DvvoV`xrpLuML@&k?ZD~FZhW@%F6@MT-kyAeWcDDmeNo9D~4 z&p+!=?*A~f-B(}LZ~2O$rIs<%IJi22UD$0eo`2pGvCDPq==rf!H-VCavvN%PDxBE> zy>Pr~cyRKDF8v0j{iB!Wi1vxyCFGy~<+$%@lsz~Eu#REIU6nF1&6W!*{)cz`0qLD{ zeG7m=0}{-~G5UDzpep^Ode9^Q3>&Ao=00^YUfIj7b5n8Zlc#hBi?U72-|ahGf9WEp zb>;2=|5IiKPK~=4;6?qmd}e8Y>f-VCrLdl*8?|sE8%o8X5Ff<2({`_?o9Jma2Ca2% z9&b_lTK3crN_Ym}ivNW^s4wROo@QI7RkdKh2i_iGn9uN$KA}bmopWMeB?ADm`la{v znbOZ}ooc#gPsq2=uNXCp-gu)#%~qlDK1j=q@;_Uq&h;VQSSzTu^k>Wt#{dW$m(%t5 z5=C>huo{9H6E4$(9O}pI5X`HTe;dq}s>3F0=(8dEylA_hBm0RoWWkMh1vg9kNlRQW z>hYr=-ecSD>XeI*d8F;zhxA1P7E74jTqwYDc??$k2XSLJ=a0qLsXvgp7VgpENBA^p z*+xZ2==w8nCEg0RWkDsK*&PlGpv6D#{`uOFN3e|pHDUw%CKWn+mf4s^f*?zKKQ503 z0-jN`h3&jz9@@d|@_NP2*D@N-$q38TC1%c^ z7rMC&A1IZgPjdbfL&9q6i8 z8PWgWmTp?07?97!&#NHvUzpSCX7K`+^VPcqks`uEcnVRr(Mw=#&SJ5 z)V3H~Vx8=iysm8Lu8ud3A zOVeY4ixG@4tMGg-p10N0qDj0bcQf)`0sjRTr7mP~ADP)q9|B_YmobYAQ_0>NSDFQu z!|j>jyjTGF4}&Y+EEj``C~tKx>`zbgov|GI7ouABke^xqmI5k@&0KKsFkILa`7`Yv-;~K_?TLf;U^jeI^O+`J`v=BDn9u=z=-L2%ln%! z4Dks}`{!VE+Ns&Ap@n9o&6$0uK;u30A%{QuZog~1cYMP%v02~Qvzz;LMU;pNDPp`+ z{X>t-t+rvZP{SR>cn|sdxHZrC0Q_LZG&_R9>Ck5k2-f0NwU`*|{H6Sj1gS%MuH0$82CU`4AU`+N@Pc-OfLu z=896mMO%$9Mm~@Me2Dt@vHs;GHrQO?Sz({cC!#tmF){bc^EY?KuMQr&IUWlNstSD+ zqh7;H^K;Cs@_?Gr3;k5EDt^mYV4?@by-*-l_Lg@Q^*QexRPOiN?&F#Lk@C3gV9nHt z`#NPKEUyDyZ}r<&LgZplP>CP!xbt}qLG40P}ock7Fi-#zXy?JHHb)}aGUo$Je!eGFWI=)R|X1U7lw7KIDn zS?n)eBItZuHU_yBR3_UD0nZ<=zxpX$*QO#iw3ZbUW1f-n3u^&C@dZ=sq zx60IkD#)d+Z-RYV6BhSXGxz!Vk=X}ztbVv20+h|;)XrX?8*{ng4u+>LPRO(6?Vob^ z3Uf}|9~WfZi9KIO+57o=?`7wLk|i|=?&!Ou{G0@aHLy*}8+mVb?=U`@8|G^5*ySrS zBvbcH&V2dy6U;IMMgFRh>5qG4`3q{8>Yf8ykh?)Hum!_OxmxZpOF(as<4`s&jP=!Q zdO)B)K1F<+$FIQsMmEFa>9Bj}D?)sPcqr%mb&y7#1MR0>Z8?*jU2!=Po>T5Rb%DhI z31rRrd76pC-i)-AjC#)}!37J^zEehKrzIiI>P+;yT%;~q5>6YZr~V?qHp-C3361@W zEqCuPPT_zR{MjR3b9LTW>GoV3K=TYhm|dd}dS;JK%e?znBz8iI-|3^Kw7S^I_AeWB z^B}=&r5wLGsIV=AJO{l}xI~bmRF)gas6Gf{kh4LW1go4SX~^x#2+cH=Kcje?<=gY- zte5D6kc1-~3e95YeRRYAO8`xJL0=QQsAyu|&t|i~u!1y&)uTg^(4yScm9HAkb5>bH zhN58AM;rFa8%VCNjK{B+gf#G~C>}hYv#U!;W1~m(v#}NtK9hqY8cvy-wvU#m^lKok zz3BK$-RqZyhW0w!>3;hIoP<=MK--nk0myP~&uTln?5KY1Iu)JeeA1!1>9!8G#QUWo zf5PoN^7O&=?X)W&Y4qJ8Mz(!SLz0tpKI3lM#OK9B5l{BEu{laJ{kuKp-rV&+t;vRR zBV*<5AdBaRkEaW(K;ll;TMf9XfLV=d9Jggy=l;dy(wn3s%{Xp8{n+rxc-L$BdT&v_ zekn`#{9*mPQB@IaOzPE{b|ilKy#oZRFz`6m8H%iYag9x!FXBmK&UUFRu#_y3Hf^^?^Zj@2C8xLGl&rfyp?$w5-_X{PVj|ntEivK&~oG&ND}llphooz!Xm9iWKG|t|#5y8c6om1Z@$= z*P$nBY;-A$nDm)=-z}nj6UQ$O(EBY7_ANo*iS3I23={DfhtGy#7>k7G#ux|#SfDM2(ktc?ei*zQt-L+9N-@&w2239x#%7XB&Tj9*3x&WuN#2>kZ& zi+zx)OpC*7zs;K=Jro3*h|mT2vl#S)N3^UnKiS(%918r7b{Nv3iyJW5p%KS@K^$iq z|8rguxwYSI^z9 zR)-%KE;VEqO-)h(FI6uq0j&I3>KN!4f6b5Tc;<|C4QNZ)OHQ4b5hlnTwldzw*yCSo8*34koN@TxM50c$HVbot z^f}Bw{l-*{E6j#gLr_*hjDDk?892l3$M{bdTg_+4k(&_ z40jxTQ3@Kw-HTc|BX^{=-c+zE|PtOHE0l0P~TkjcWE@d)M*sP&j^LeUhDCb;yJ(`7Pw?@E|(!aqB0a;eZU^LitYp z!oK;|-I||3=Lh!90%MziXb3BM%ed|EW!~JcR_lB-IVRX%m)kcdTDjYEm?}K>B9G)A znh^xvJyEvJw%2*e@rr)m2izvF;obKJX~g^C8swJ(Pvu{Dq=tBtqV?JP9}f+K9}X8@ z1=U3dyb5DZ1aU;YeLE3Fy?=tcO^qC<7M>;Px#V`V#m(bt7)J|iMrk0u|QP%97W&-!*ZGH>pe=UNo;5ifD!a}LsoWv z-NxWt*2GLD8DLb zrAzz~3j0y(c&O9RX+My^9?F;{KUS*0+#@x)!ZL6AazTqNf8K%`fB|(r z9B2cd)u%ssw)+h40BdU*HQJQq#dTps+lkj*DyM7kZp_S~ESHmKM zfaQtoPgDZ~@aoR{Ku*>VoR<`c-^cc|`3%xd9DL#A?Nm)De|_iJ9eRhT=BMvtqK=-X z=KCG>-WxyeHM)COe&R585Ql?uM3&J7V`3$fi8!|1#Yp98fm$Z=T z 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%0D$q_E;>AZB)&KAhEPn`Q?$-&@F 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