cmake_minimum_required(VERSION 3.20) project(UsdLayerManager VERSION 1.0.0 LANGUAGES C CXX) # Set C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # Add cmake modules path list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") # Find dependencies find_package(OpenGL REQUIRED) find_package(OpenUSD REQUIRED) find_package(Imgui REQUIRED) find_package(ImguiNodeEditor REQUIRED) find_package(Glad REQUIRED) find_package(FFmpeg REQUIRED) # OpenColorIO — provided by the OpenUSD distribution (USD built with OCIO support) set(OpenColorIO_DIR "${OpenUSD_ROOT_DIR}/lib/cmake/OpenColorIO" CACHE PATH "OpenColorIO CMake config dir" FORCE) find_package(OpenColorIO CONFIG REQUIRED) # USD build that includes hdEmbree (built with PXR_ENABLE_EMBREE_PLUGIN=ON). # Can be a separate install from OpenUSD_ROOT_DIR; leave empty to search there instead. set(HDEMBREE_USD_ROOT "" CACHE PATH "USD build containing hdEmbree plugin (separate from OpenUSD_ROOT_DIR)") # Only needed if embree*.dll are not inside HDEMBREE_USD_ROOT/bin. set(EMBREE_LOCATION "" CACHE PATH "Embree SDK bin/ directory (leave empty if bundled in HDEMBREE_USD_ROOT/bin)") # ── hdEmbree detection ─────────────────────────────────────────────────────── if(HDEMBREE_USD_ROOT AND EXISTS "${HDEMBREE_USD_ROOT}") set(_hdembree_root "${HDEMBREE_USD_ROOT}") else() set(_hdembree_root "${OpenUSD_ROOT_DIR}") endif() # hdEmbree.dll lives at plugin/usd/hdEmbree.dll; the subdir holds only plugin metadata. set(HDEMBREE_PLUGIN_DIR "${_hdembree_root}/plugin/usd/hdEmbree") set(HDEMBREE_DLL "${_hdembree_root}/plugin/usd/hdEmbree.dll") if(EXISTS "${HDEMBREE_PLUGIN_DIR}") set(OPENUSD_HAS_EMBREE TRUE) if(EMBREE_LOCATION AND EXISTS "${EMBREE_LOCATION}") set(_embree_dll_dir "${EMBREE_LOCATION}") else() set(_embree_dll_dir "${_hdembree_root}/bin") endif() # Skip tbb*.dll — already supplied by the main USD install to avoid conflicts. file(GLOB EMBREE_DLLS "${_embree_dll_dir}/embree*.dll") else() set(OPENUSD_HAS_EMBREE FALSE) message(STATUS "hdEmbree: NOT found — set HDEMBREE_USD_ROOT to a USD build with PXR_ENABLE_EMBREE_PLUGIN=ON") endif() # ── hdArnold detection ─────────────────────────────────────────────────────── # HDARNOLD_ROOT: CMAKE_INSTALL_PREFIX used when building arnold-usd set(HDARNOLD_ROOT "" CACHE PATH "arnold-usd install directory (the one containing plugin/hdArnold.dll)") # ARNOLD_LOCATION: Arnold SDK root (MtoA dir) — needed to deploy ai.dll set(ARNOLD_LOCATION "" CACHE PATH "Arnold SDK root (e.g. C:/Autodesk/mtoa/5.5.0/2026) for ai.dll deployment") if(HDARNOLD_ROOT AND EXISTS "${HDARNOLD_ROOT}/plugin/hdArnold.dll") set(OPENUSD_HAS_ARNOLD TRUE) set(HDARNOLD_DLL "${HDARNOLD_ROOT}/plugin/hdArnold.dll") set(NDRARNOLD_DLL "${HDARNOLD_ROOT}/plugin/ndrArnold.dll") set(HDARNOLD_PLUGIN_DIR "${HDARNOLD_ROOT}/plugin/hdArnold") set(NDRARNOLD_PLUGIN_DIR "${HDARNOLD_ROOT}/plugin/ndrArnold") if(ARNOLD_LOCATION AND EXISTS "${ARNOLD_LOCATION}/bin/ai.dll") set(ARNOLD_AI_DLL "${ARNOLD_LOCATION}/bin/ai.dll") # ai.dll also requires companion runtime DLLs (OIDN denoiser, Adsk licensing, cer) file(GLOB ARNOLD_RUNTIME_DLLS "${ARNOLD_LOCATION}/bin/ai*.dll" "${ARNOLD_LOCATION}/bin/AdClm*.dll" "${ARNOLD_LOCATION}/bin/AdskLicensing*.dll" "${ARNOLD_LOCATION}/bin/cer.dll" ) else() set(ARNOLD_AI_DLL "") set(ARNOLD_RUNTIME_DLLS "") endif() else() set(OPENUSD_HAS_ARNOLD FALSE) message(STATUS "hdArnold: NOT found — set HDARNOLD_ROOT to the arnold-usd install dir and ARNOLD_LOCATION to the MtoA root") endif() # ── Cycles hdCycles Hydra render delegate ──────────────────────────────────── # Build Blender Cycles from third_party/cycles using ExternalProject. # Set WITH_CYCLES=ON to enable; requires MSVC, and uses the precompiled libs # bundled in third_party/cycles/lib/windows_x64/. # hdCycles.dll is deployed to usd/ alongside hdEmbree and hdArnold. option(WITH_CYCLES "Build Cycles Hydra render delegate from third_party/cycles" OFF) set(CYCLES_BINARY_DIR "${CMAKE_BINARY_DIR}/cycles_build") set(CYCLES_INSTALL_DIR "${CMAKE_BINARY_DIR}/cycles_install") set(HDCYCLES_DLL "${CYCLES_INSTALL_DIR}/hydra/hdCycles.dll") set(HDCYCLES_PLUGIN_DIR "${CYCLES_INSTALL_DIR}/hydra/hdCycles") # tbb12.dll is required by openvdb/embree4 but lives in the precompiled lib tree, # not in the install output — deploy it explicitly. set(CYCLES_TBB12_DLL "${CMAKE_SOURCE_DIR}/third_party/cycles/lib/windows_x64/tbb/bin/tbb12.dll") if(WITH_CYCLES) include(ExternalProject) # Resolve absolute USD root so we can forward it to the sub-build. # FindOpenUSD.cmake stores the path in OpenUSD_ROOT_DIR. if(NOT OpenUSD_ROOT_DIR) message(FATAL_ERROR "WITH_CYCLES requires OpenUSD_ROOT_DIR to be set (run find_package(OpenUSD) first).") endif() ExternalProject_Add(CyclesBuild SOURCE_DIR "${CMAKE_SOURCE_DIR}/third_party/cycles" BINARY_DIR "${CYCLES_BINARY_DIR}" INSTALL_DIR "${CYCLES_INSTALL_DIR}" CMAKE_ARGS # Always Release — Cycles' Debug build is slow and rarely needed here. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX= # Point Cycles at our app's USD so hdCycles is ABI-compatible. -DPXR_ROOT=${OpenUSD_ROOT_DIR} # Hydra delegate is the only deliverable we need. -DWITH_CYCLES_HYDRA_RENDER_DELEGATE=ON -DWITH_CYCLES_USD=ON # Use bundled precompiled libs from lib/windows_x64/. -DWITH_LIBS_PRECOMPILED=ON # Turn off heavy optional features that aren't needed for the delegate. -DWITH_CYCLES_STANDALONE_GUI=OFF -DWITH_CYCLES_DEVICE_CUDA=OFF -DWITH_CYCLES_DEVICE_OPTIX=OFF -DWITH_CYCLES_DEVICE_HIP=OFF -DWITH_CYCLES_DEVICE_ONEAPI=OFF -DWITH_CYCLES_LOGGING=OFF # USD ships OpenVDB v9; Cycles prebuilt is v13 — ABI mismatch, both named # openvdb.dll. Disable openvdb in Cycles to avoid the version conflict. -DWITH_CYCLES_OPENVDB=OFF # Embree4 links tbb12.dll; USD already loads tbb.dll at process startup. # oneTBB detects the older tbb.dll and aborts initialization (DLL_INIT_FAILED). # Disable Embree so Cycles uses its own BVH traversal instead. -DWITH_CYCLES_EMBREE=OFF # ---- pxrConfig.cmake dependency overrides ---- # pxrConfig.cmake runs find_dependency() for these before Cycles' # precompiled lib paths are on CMAKE_PREFIX_PATH, so we must supply # them explicitly. The Python3 vars also override the hardcoded # CI build-machine path embedded in pxrConfig.cmake. -DPython3_EXECUTABLE=$ENV{LOCALAPPDATA}/Programs/Python/Python312/python.exe -DPython3_LIBRARY=$ENV{LOCALAPPDATA}/Programs/Python/Python312/libs/python312.lib -DPython3_INCLUDE_DIR=$ENV{LOCALAPPDATA}/Programs/Python/Python312/include -DTBB_DIR=${CMAKE_SOURCE_DIR}/third_party/cycles/lib/windows_x64/tbb/lib/cmake/TBB -DMaterialX_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/MaterialX # OpenSubdiv and Imath cmake configs are bundled in the USD install. # We must supply their dirs so pxrTargets.cmake can resolve the imported targets. -DOpenSubdiv_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/OpenSubdiv -DImath_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/Imath # Force Cycles to use its own prebuilt OCIO 2.5, not the OCIO 2.1 # bundled in the new USD include dir. Without this, the new USD's # include/OpenColorIO/ (OCIO 2.1) shadows Cycles' prebuilt OCIO 2.5 # headers and the colorspace.cpp API calls fail to compile. -DOpenColorIO_DIR=${CMAKE_SOURCE_DIR}/third_party/cycles/lib/windows_x64/opencolorio/lib/cmake/OpenColorIO BUILD_COMMAND ${CMAKE_COMMAND} --build --config Release INSTALL_COMMAND ${CMAKE_COMMAND} --install --config Release BUILD_BYPRODUCTS "${HDCYCLES_DLL}" ) set(OPENUSD_HAS_CYCLES TRUE) else() set(OPENUSD_HAS_CYCLES FALSE) message(STATUS "hdCycles: disabled — set WITH_CYCLES=ON to build from third_party/cycles") endif() # Collect source files file(GLOB_RECURSE CORE_SOURCES "src/core/*.cpp") file(GLOB_RECURSE UI_SOURCES "src/ui/*.cpp") # src/ui/NodeEditor is the in-tree vendored imgui-node-editor subset — already # compiled into the imgui_node_editor_impl target by FindImguiNodeEditor.cmake # (with its own required include dirs/defines); excluded here so it isn't # compiled a second time, incorrectly, as part of this target's own sources. list(FILTER UI_SOURCES EXCLUDE REGEX "/src/ui/NodeEditor/") file(GLOB_RECURSE UTILS_SOURCES "src/utils/*.cpp") set(MAIN_SOURCE "src/main.cpp") # Create executable add_executable(UsdLayerManager ${MAIN_SOURCE} ${CORE_SOURCES} ${UI_SOURCES} ${UTILS_SOURCES} ) # Include directories target_include_directories(UsdLayerManager PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/third_party/fontawesome ${CMAKE_SOURCE_DIR}/third_party/nanosvg ) # Link libraries target_link_libraries(UsdLayerManager PRIVATE OpenUSD::OpenUSD Imgui::Imgui ImguiNodeEditor::ImguiNodeEditor Glad::Glad FFmpeg::FFmpeg OpenColorIO::OpenColorIO ole32 shell32 ) target_include_directories(UsdLayerManager PRIVATE "${CMAKE_SOURCE_DIR}/third_party/ffmpeg/include" ) # Cycles is an ExternalProject; UsdLayerManager must wait for it to finish # before POST_BUILD copies hdCycles.dll to the output directory. if(WITH_CYCLES) add_dependencies(UsdLayerManager CyclesBuild) endif() # Platform-specific settings if(WIN32) # Windows-specific settings target_compile_definitions(UsdLayerManager PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS ) # OpenColorIO DLL — copy from USD bin/ (which already ships OpenColorIO_2_1.dll) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OpenUSD_ROOT_DIR}/bin/OpenColorIO_2_1.dll" "$" COMMENT "Copying OpenColorIO runtime DLL..." ) # FFmpeg DLLs — copy all .dll files from third_party/ffmpeg/bin file(GLOB FFMPEG_RUNTIME_DLLS "${CMAKE_SOURCE_DIR}/third_party/ffmpeg/bin/*.dll") if(FFMPEG_RUNTIME_DLLS) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FFMPEG_RUNTIME_DLLS} "$" COMMENT "Copying FFmpeg runtime DLLs..." ) endif() # cmake -P script to copy USD bin/ DLLs excluding CRT DLLs (msvcp, vcruntime, etc.). # The USD distribution bundles older CRT DLLs (14.34) that conflict with Cycles # binaries built against the newer system CRT (14.42+). The system CRT is # always present on Windows 10+ — no need to bundle our own copy. file(WRITE "${CMAKE_BINARY_DIR}/copy_usd_bin_dlls.cmake" "file(GLOB _all_dlls \"${OpenUSD_ROOT_DIR}/bin/*.dll\")\n" "set(_dlls)\n" "foreach(_dll \${_all_dlls})\n" " get_filename_component(_name \"\${_dll}\" NAME)\n" " string(TOLOWER \"\${_name}\" _lname)\n" " if(_lname MATCHES \"^(msvcp|vcruntime|ucrtbase|concrt|api-ms-win-)\")\n" " continue()\n" " endif()\n" " list(APPEND _dlls \"\${_dll}\")\n" "endforeach()\n" "if(_dlls)\n" " file(COPY \${_dlls} DESTINATION \"\${DEST_DIR}\")\n" "endif()\n" ) # Copy runtime DLLs to output directory for each configuration add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "$" # OpenUSD lib/ — usd_*.dll, boost_*.dll, Alembic.dll, etc. COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_BIN_DIR}" "$" # OpenUSD bin/ — tbb.dll, MaterialX, OpenEXR, OpenImageIO, etc. (CRT DLLs excluded) COMMAND ${CMAKE_COMMAND} "-DDEST_DIR=$" -P "${CMAKE_BINARY_DIR}/copy_usd_bin_dlls.cmake" COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_ROOT_DIR}/lib/usd" "$/usd" COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_ROOT_DIR}/plugin/usd" "$/usd" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python312.dll" "$" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python3.dll" "$" COMMENT "Copying runtime DLLs and USD plugins..." ) if(OPENUSD_HAS_EMBREE) add_custom_command(TARGET UsdLayerManager POST_BUILD # plugInfo.json has LibraryPath "../hdEmbree.dll" relative to usd/hdEmbree/, # which resolves to usd/hdEmbree.dll — so the DLL must live in usd/, not exe root. COMMAND ${CMAKE_COMMAND} -E copy_if_different "${HDEMBREE_DLL}" "$/usd/hdEmbree.dll" COMMAND ${CMAKE_COMMAND} -E copy_directory "${HDEMBREE_PLUGIN_DIR}" "$/usd/hdEmbree" COMMENT "Copying hdEmbree plugin..." ) if(EMBREE_DLLS) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${EMBREE_DLLS} "$" COMMENT "Copying Embree runtime DLLs..." ) endif() endif() if(OPENUSD_HAS_ARNOLD) add_custom_command(TARGET UsdLayerManager POST_BUILD # DLLs go in usd/ alongside their metadata dirs (LibraryPath "../hdArnold.dll") COMMAND ${CMAKE_COMMAND} -E copy_if_different "${HDARNOLD_DLL}" "$/usd/hdArnold.dll" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${NDRARNOLD_DLL}" "$/usd/ndrArnold.dll" COMMAND ${CMAKE_COMMAND} -E copy_directory "${HDARNOLD_PLUGIN_DIR}" "$/usd/hdArnold" COMMAND ${CMAKE_COMMAND} -E copy_directory "${NDRARNOLD_PLUGIN_DIR}" "$/usd/ndrArnold" COMMENT "Copying hdArnold plugin..." ) if(ARNOLD_RUNTIME_DLLS) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ARNOLD_RUNTIME_DLLS} "$" COMMENT "Copying Arnold runtime DLLs (ai, OIDN, licensing)..." ) endif() endif() if(OPENUSD_HAS_CYCLES) # hdCycles uses the same usd/ layout as hdEmbree: # usd/hdCycles.dll + usd/hdCycles/resources/plugInfo.json # The bundled plugInfo.json has Root=".." and LibraryPath="../hdCycles.dll" # which resolves correctly once the plugin dir lives in usd/. # # Runtime deps (embree4, epoxy, imath, openvdb, OIDN, sycl, vulkan, etc.) # live in CYCLES_INSTALL_DIR root and must be next to the exe. We can't # file(GLOB) them at configure time (ExternalProject hasn't run yet), so we # write a small cmake -P script that globs them at build time instead. # The script runs at build time (after ExternalProject finishes) so it can glob # the actual install output. CRT/Windows DLLs are excluded — they must come # from the system or the main exe's toolchain, not from Cycles' bundled copy. file(WRITE "${CMAKE_BINARY_DIR}/copy_cycles_runtime_dlls.cmake" "file(GLOB _all_dlls \"${CYCLES_INSTALL_DIR}/*.dll\")\n" "set(_dlls)\n" "foreach(_dll \${_all_dlls})\n" " get_filename_component(_name \"\${_dll}\" NAME)\n" " string(TOLOWER \"\${_name}\" _lname)\n" # Exclude CRT DLLs (system must supply these; Cycles bundles an older version). " if(_lname MATCHES \"^(msvcp|vcruntime|ucrtbase|concrt|api-ms-win-)\")\n" " continue()\n" " endif()\n" # Exclude debug-variant DLLs (not needed in release, just wasted space). # Pattern: OpenColorIO_d_2_5.dll → contains "_d_" # openjph.0.25d.dll → ends with "d.dll" " if(_lname MATCHES \"_d_\" OR _lname MATCHES \"d[.]dll$\")\n" " continue()\n" " endif()\n" " list(APPEND _dlls \"\${_dll}\")\n" "endforeach()\n" "if(_dlls)\n" " file(COPY \${_dlls} DESTINATION \"\${DEST_DIR}\")\n" "endif()\n" ) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${HDCYCLES_DLL}" "$/usd/hdCycles.dll" COMMAND ${CMAKE_COMMAND} -E copy_directory "${HDCYCLES_PLUGIN_DIR}" "$/usd/hdCycles" COMMAND ${CMAKE_COMMAND} "-DDEST_DIR=$" -P "${CMAKE_BINARY_DIR}/copy_cycles_runtime_dlls.cmake" # tbb12.dll is required by openvdb/embree4 but is not in the install output COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CYCLES_TBB12_DLL}" "$/tbb12.dll" COMMENT "Copying hdCycles plugin and runtime DLLs..." ) endif() endif() # Compiler warnings if(MSVC) target_compile_options(UsdLayerManager PRIVATE /W4) else() target_compile_options(UsdLayerManager PRIVATE -Wall -Wextra -Wpedantic) endif() # Install rules install(TARGETS UsdLayerManager RUNTIME DESTINATION bin ) # Install all OpenUSD runtime DLLs (same set that POST_BUILD copies to build/Release). # Without these the exe cannot start from install/bin. install(DIRECTORY ${OpenUSD_BIN_DIR}/ DESTINATION bin FILES_MATCHING PATTERN "*.dll" ) # Install OpenUSD bin/ DLLs — tbb.dll, tbbmalloc.dll, MaterialX, OpenEXR, # OpenImageIO, zlib, etc. Exclude CRT DLLs: the system VC++ Redistributable supplies # these at runtime; bundling an older copy (14.34) causes crashes on machines with # Cycles or other DLLs compiled against the newer CRT (14.42+). install(DIRECTORY ${OpenUSD_ROOT_DIR}/bin/ DESTINATION bin FILES_MATCHING PATTERN "*.dll" PATTERN "msvcp*" EXCLUDE PATTERN "vcruntime*" EXCLUDE PATTERN "ucrtbase*" EXCLUDE PATTERN "concrt*" EXCLUDE PATTERN "api-ms-win-*" EXCLUDE ) install(DIRECTORY ${OpenUSD_ROOT_DIR}/lib/usd DESTINATION bin ) install(DIRECTORY ${OpenUSD_ROOT_DIR}/plugin/usd/ DESTINATION bin/usd ) if(OPENUSD_HAS_EMBREE) # Install to bin/usd/ so plugInfo.json's LibraryPath "../hdEmbree.dll" resolves correctly. install(FILES "${HDEMBREE_DLL}" DESTINATION bin/usd OPTIONAL ) install(DIRECTORY "${HDEMBREE_PLUGIN_DIR}" DESTINATION bin/usd OPTIONAL ) if(EMBREE_DLLS) install(FILES ${EMBREE_DLLS} DESTINATION bin OPTIONAL ) endif() endif() if(OPENUSD_HAS_ARNOLD) install(FILES "${HDARNOLD_DLL}" "${NDRARNOLD_DLL}" DESTINATION bin/usd OPTIONAL ) install(DIRECTORY "${HDARNOLD_PLUGIN_DIR}" DESTINATION bin/usd OPTIONAL ) install(DIRECTORY "${NDRARNOLD_PLUGIN_DIR}" DESTINATION bin/usd OPTIONAL ) if(ARNOLD_RUNTIME_DLLS) install(FILES ${ARNOLD_RUNTIME_DLLS} DESTINATION bin OPTIONAL ) endif() endif() if(OPENUSD_HAS_CYCLES) install(FILES "${HDCYCLES_DLL}" DESTINATION bin/usd OPTIONAL ) install(DIRECTORY "${HDCYCLES_PLUGIN_DIR}" DESTINATION bin/usd OPTIONAL ) # Cycles runtime deps (embree4, epoxy, imath, openvdb, OIDN, sycl, etc.). # No OPTIONAL: install(DIRECTORY) disallows it with FILES_MATCHING, and the # dir always exists here since it is produced by the CyclesBuild step. # # EXCLUDE the MSVC CRT and api-ms-win DLLs that Cycles bundles: they are # older than what the system ships (v14.34 vs system v14.42+), and placing # an older MSVCP140.dll/VCRUNTIME140.dll ahead of System32 on the DLL # search path causes sycl8.dll (built with newer CRT) to fail DllMain with # ERROR_DLL_INIT_FAILED (1114) when hdCycles.dll is loaded. # The system VC++ Redistributable always satisfies these deps at runtime. install(DIRECTORY "${CYCLES_INSTALL_DIR}/" DESTINATION bin FILES_MATCHING PATTERN "*.dll" PATTERN "MSVCP140*.dll" EXCLUDE PATTERN "VCRUNTIME140*.dll" EXCLUDE PATTERN "ucrtbase*.dll" EXCLUDE PATTERN "api-ms-win-*.dll" EXCLUDE PATTERN "OpenColorIO_d_*.dll" EXCLUDE # debug OCIO build PATTERN "openjph.*d.dll" EXCLUDE # debug OpenJPH ) # tbb12.dll (used by openvdb/embree4) lives in the precompiled lib tree, not install output install(FILES "${CYCLES_TBB12_DLL}" DESTINATION bin OPTIONAL ) endif() # Install Python runtime DLLs required by OpenUSD and Cycles. # python312.dll : linked by Cycles (hdCycles.dll → python312.dll) # python311.dll : linked by usd_python.dll (the OpenUSD Python bindings were # built against Python 3.11, regardless of what we compile with) # Detect python311.dll from common install paths. foreach(_pyroot "$ENV{LOCALAPPDATA}/Programs/Python/Python311" "C:/Python311" "C:/Program Files/Python311" ) if(EXISTS "${_pyroot}/python311.dll") set(PYTHON311_DLL "${_pyroot}/python311.dll") message(STATUS "Found python311.dll (required by usd_python.dll): ${PYTHON311_DLL}") break() endif() endforeach() set(_python_runtime_dlls "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python312.dll" "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python3.dll" ) if(PYTHON311_DLL) list(APPEND _python_runtime_dlls "${PYTHON311_DLL}") endif() install(FILES ${_python_runtime_dlls} DESTINATION bin OPTIONAL # OPTIONAL so the install doesn't fail on machines with a # system-wide Python; in that case the DLL is on PATH already. ) # Also copy python311.dll to the build output directory so debug runs work # without requiring C:\Python311 to be on PATH. if(PYTHON311_DLL) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PYTHON311_DLL}" "$/python311.dll" COMMENT "Copying python311.dll (for usd_python.dll)..." ) endif() # --------------------------------------------------------------------------- # OCIO: download ACES 1.2 config at configure time if not present # --------------------------------------------------------------------------- set(_ocio_config_dir "${CMAKE_SOURCE_DIR}/resources/OpenColorIO-Configs/aces_1.2") if(NOT EXISTS "${_ocio_config_dir}/config.ocio") message(STATUS "Downloading ACES 1.2 OCIO config (~124 MB) ...") set(_ocio_zip "${CMAKE_BINARY_DIR}/aces_1.2.zip") file(DOWNLOAD "https://github.com/colour-science/OpenColorIO-Configs/releases/download/v1.2/OpenColorIO-Config-ACES-1.2.zip" "${_ocio_zip}" SHOW_PROGRESS STATUS _ocio_dl_status ) list(GET _ocio_dl_status 0 _ocio_dl_code) if(_ocio_dl_code EQUAL 0) execute_process( COMMAND ${CMAKE_COMMAND} -E tar xf "${_ocio_zip}" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" ) file(COPY "${CMAKE_BINARY_DIR}/OpenColorIO-Config-ACES-1.2/aces_1.2/" DESTINATION "${_ocio_config_dir}") file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/OpenColorIO-Config-ACES-1.2") file(REMOVE "${_ocio_zip}") message(STATUS "ACES 1.2 OCIO config installed to ${_ocio_config_dir}") else() message(WARNING "ACES 1.2 OCIO download failed (${_ocio_dl_status}) — OCIO will not be bundled.") endif() endif() # --------------------------------------------------------------------------- # HDRI: shader-ball lighting presets (Poly Haven, CC0) at configure time # --------------------------------------------------------------------------- set(_hdri_dir "${CMAKE_SOURCE_DIR}/resources/hdri") set(_hdri_files kloofendal_48d_partly_cloudy_puresky_1k.exr lebombo_1k.exr artist_workshop_1k.exr venice_sunset_1k.exr ) file(MAKE_DIRECTORY "${_hdri_dir}") foreach(_hdri ${_hdri_files}) if(NOT EXISTS "${_hdri_dir}/${_hdri}") message(STATUS "Downloading HDRI ${_hdri} ...") file(DOWNLOAD "https://dl.polyhaven.org/file/ph-assets/HDRIs/exr/1k/${_hdri}" "${_hdri_dir}/${_hdri}" STATUS _hdri_dl_status ) list(GET _hdri_dl_status 0 _hdri_dl_code) if(NOT _hdri_dl_code EQUAL 0) file(REMOVE "${_hdri_dir}/${_hdri}") message(WARNING "HDRI download failed for ${_hdri} (${_hdri_dl_status}) — the shader-ball lighting preset will fall back to a distant light.") endif() endif() endforeach() # --------------------------------------------------------------------------- # VDB: cloud volume for the shader-ball preview (OpenVDB sample model) at # configure time if not present # --------------------------------------------------------------------------- set(_vdb_dir "${CMAKE_SOURCE_DIR}/resources/vdb") file(MAKE_DIRECTORY "${_vdb_dir}") if(NOT EXISTS "${_vdb_dir}/bunny_cloud.vdb") message(STATUS "Downloading OpenVDB sample bunny_cloud.vdb ...") set(_vdb_zip "${CMAKE_BINARY_DIR}/bunny_cloud.zip") file(DOWNLOAD "https://artifacts.aswf.io/io/aswf/openvdb/models/bunny_cloud.vdb/1.0.0/bunny_cloud.vdb-1.0.0.zip" "${_vdb_zip}" STATUS _vdb_dl_status ) list(GET _vdb_dl_status 0 _vdb_dl_code) if(_vdb_dl_code EQUAL 0) execute_process( COMMAND ${CMAKE_COMMAND} -E tar xf "${_vdb_zip}" WORKING_DIRECTORY "${_vdb_dir}" ) file(REMOVE "${_vdb_zip}") message(STATUS "bunny_cloud.vdb installed to ${_vdb_dir}") else() message(WARNING "OpenVDB sample download failed (${_vdb_dl_status}) — the Cloud Volume preview shape will be unavailable.") endif() endif() # Copy resources to build directory file(COPY ${CMAKE_SOURCE_DIR}/resources DESTINATION ${CMAKE_BINARY_DIR} ) # Copy font and SVG icons to build directory add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "$/../resources/font" COMMAND ${CMAKE_COMMAND} -E make_directory "$/resources/icons" COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/third_party/Inter/Inter.ttc" "$/resources/font/Inter.ttc" COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/resources/icons" "$/resources/icons" COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/resources/hdri" "$/resources/hdri" COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/resources/preview" "$/resources/preview" COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/resources/vdb" "$/resources/vdb" COMMENT "Copying fonts, SVG icons, HDRI presets and preview shapes to build output" ) # Copy ACES OCIO config to build output — only on first build (skipped if already present). if(EXISTS "${_ocio_config_dir}/config.ocio") add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} "-DSRC=${_ocio_config_dir}" "-DDST=$/resources/OpenColorIO-Configs/aces_1.2" -P "${CMAKE_SOURCE_DIR}/cmake/CopyDirIfMissing.cmake" COMMENT "Copying ACES OCIO config to build output (first time only)" ) endif() # Install OpenColorIO DLL (from the OpenUSD distribution's bin/) install(FILES "${OpenUSD_ROOT_DIR}/bin/OpenColorIO_2_1.dll" DESTINATION bin OPTIONAL ) # Install resources (icons, fonts placeholder) next to the exe so the # exe-relative path "resources/..." resolves correctly from install/bin/. install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources DESTINATION bin ) # Install Inter font next to the exe under resources/font/ # ImGuiContext tries "resources/font/Inter.ttf" then "resources/font/Inter.ttc". install(FILES ${CMAKE_SOURCE_DIR}/third_party/Inter/Inter.ttc DESTINATION bin/resources/font ) # Print configuration summary message(STATUS "") message(STATUS "=== USD Layer Manager Configuration ===") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "C++ standard: ${CMAKE_CXX_STANDARD}") message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") message(STATUS "OpenUSD found: ${OpenUSD_FOUND}") message(STATUS "ImGui found: ${Imgui_FOUND}") message(STATUS "OpenGL found: ${OPENGL_FOUND}") message(STATUS "Glad found: ${Glad_FOUND}") message(STATUS "Build tests: ${BUILD_TESTS}") message(STATUS "hdEmbree support: ${OPENUSD_HAS_EMBREE}") if(OPENUSD_HAS_EMBREE AND EMBREE_DLLS) message(STATUS "Embree DLLs: ${EMBREE_DLLS}") elseif(OPENUSD_HAS_EMBREE) message(WARNING "hdEmbree found but no Embree DLLs detected — set EMBREE_LOCATION to the Embree SDK bin/ dir or check HDEMBREE_USD_ROOT/bin") endif() message(STATUS "hdArnold support: ${OPENUSD_HAS_ARNOLD}") if(OPENUSD_HAS_ARNOLD) message(STATUS "hdArnold DLL: ${HDARNOLD_DLL}") message(STATUS "Arnold runtime DLLs: ${ARNOLD_RUNTIME_DLLS}") if(NOT ARNOLD_AI_DLL) message(WARNING "hdArnold found but ai.dll not located — set ARNOLD_LOCATION to the MtoA root (e.g. C:/Autodesk/mtoa/5.5.0/2026)") endif() endif() message(STATUS "hdCycles support: ${OPENUSD_HAS_CYCLES}") if(OPENUSD_HAS_CYCLES) message(STATUS "Cycles source: ${CMAKE_SOURCE_DIR}/third_party/cycles") message(STATUS "Cycles build: ${CYCLES_BINARY_DIR}") message(STATUS "Cycles install: ${CYCLES_INSTALL_DIR}") endif() message(STATUS "=======================================") message(STATUS "") # === Test build option === option(BUILD_TESTS "Build test executables" OFF) if(BUILD_TESTS) # === Viewport Display Test === add_executable(ViewportDisplayTest tests/viewport_display_test.cpp ${CORE_SOURCES} ${UTILS_SOURCES} ) target_include_directories(ViewportDisplayTest PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include "${CMAKE_SOURCE_DIR}/third_party/ffmpeg/include" ) target_link_libraries(ViewportDisplayTest PRIVATE OpenUSD::OpenUSD Glad::Glad FFmpeg::FFmpeg ) if(WIN32) target_compile_definitions(ViewportDisplayTest PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS ) add_custom_command(TARGET ViewportDisplayTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_BIN_DIR}" "$" COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_ROOT_DIR}/lib/usd" "$/usd" COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_ROOT_DIR}/plugin/usd" "$/usd" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python312.dll" "$" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python3.dll" "$" COMMENT "Copying runtime DLLs and USD plugins for test..." ) endif() enable_testing() add_test(NAME ViewportDisplayTest COMMAND ViewportDisplayTest) add_executable(RendererDiagnosticTest tests/renderer_diagnostic_test.cpp ${CORE_SOURCES} ${UTILS_SOURCES} ) target_include_directories(RendererDiagnosticTest PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include "${CMAKE_SOURCE_DIR}/third_party/ffmpeg/include" ) target_link_libraries(RendererDiagnosticTest PRIVATE OpenUSD::OpenUSD Glad::Glad FFmpeg::FFmpeg ) if(WIN32) target_compile_definitions(RendererDiagnosticTest PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX _CRT_SECURE_NO_WARNINGS ) add_custom_command(TARGET RendererDiagnosticTest POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_BIN_DIR}" "$" COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_ROOT_DIR}/lib/usd" "$/usd" COMMAND ${CMAKE_COMMAND} -E copy_directory "${OpenUSD_ROOT_DIR}/plugin/usd" "$/usd" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python312.dll" "$" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python3.dll" "$" COMMENT "Copying runtime DLLs and USD plugins for diagnostic test..." ) endif() endif() # BUILD_TESTS