Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7ec6329dc | ||
|
|
a28c227175 | ||
|
|
30e59dc432 | ||
|
|
3fff04fa64 | ||
|
|
a75b75617b | ||
|
|
9abae44383 | ||
|
|
7fffe564ef | ||
|
|
375c683456 | ||
|
|
960336887b | ||
|
|
6966d7453d | ||
|
|
d0b0556a6c |
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Environment
|
||||
**Operating System:** (e.g. Windows 2019, macOS-10.15, Linux CentOS 7.4)
|
||||
**Version / Commit SHA:** (e.g VDB 7.2, SHA: 1a2b3c4d5e...)
|
||||
**Other:** (e.g compiler, C++ standard etc.)
|
||||
|
||||
### Describe the bug
|
||||
(A clear and concise description of what the bug is.)
|
||||
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
1. Build with '...'
|
||||
2. Run function '....'
|
||||
3. See error
|
||||
|
||||
### Expected behavior
|
||||
(A clear and concise description of what you expected to happen.)
|
||||
|
||||
### Additional context
|
||||
(Add any other context about the problem here.)
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Build / Installation
|
||||
about: Describe a problem with installation
|
||||
title: "[BUILD]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Environment
|
||||
**Operating System:** (e.g. Windows 2019, macOS-10.15, Linux CentOS 7.4)
|
||||
**Version / Commit SHA:** (e.g VDB 7.2, SHA: 1a2b3c4d5e...)
|
||||
**CMake Version:** (e.g. 3.18)
|
||||
**Compiler:** (e.g. gcc 10, msvc 2019)
|
||||
|
||||
### Describe the problem
|
||||
(A clear and concise description of the encountered issue.)
|
||||
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
1. Checkout repo '...'
|
||||
2. Run CMake '....'
|
||||
3. Build with '....'
|
||||
4. See error
|
||||
|
||||
### Additional context
|
||||
(Add any other context about the problem here.)
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[REQUEST]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Is your feature request related to a problem? Please describe.
|
||||
(A clear and concise description of what the problem is)
|
||||
|
||||
### Describe the solution you'd like
|
||||
(A clear and concise description of what you want to happen.)
|
||||
|
||||
### Describe alternatives you've considered
|
||||
(A clear and concise description of any alternative solutions or features you've considered.)
|
||||
|
||||
### Additional context
|
||||
(Add any other context or screenshots about the feature request here.)
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'feature/**'
|
||||
- 'pr/**'
|
||||
paths-ignore:
|
||||
- 'CHANGES'
|
||||
- 'openvdb_maya/**'
|
||||
- 'pendingchanges/**'
|
||||
- '**.md'
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
paths-ignore:
|
||||
- 'CHANGES'
|
||||
- 'openvdb_maya/**'
|
||||
- 'pendingchanges/**'
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
deploy:
|
||||
description: 'Deploy docs?'
|
||||
required: true
|
||||
default: 'false'
|
||||
|
||||
jobs:
|
||||
doxygen:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CXX: g++
|
||||
container:
|
||||
image: aswf/ci-openvdb:2019
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install_doxygen
|
||||
run: ./ci/install_doxygen.sh 1_8_11
|
||||
- name: install_epydoc
|
||||
run: pip install epydoc
|
||||
- name: install_latex
|
||||
run: yum -y install texlive-latex-bin texlive-dvips texlive-collection-fontsrecommended texlive-collection-latexrecommended
|
||||
- name: install_cmake
|
||||
run: ./ci/install_cmake.sh 3.15.0
|
||||
- name: build
|
||||
run: >
|
||||
./ci/build.sh -v
|
||||
--build-type=Release
|
||||
--components="core,python,doc"
|
||||
--cargs=\"
|
||||
-DUSE_BLOSC=OFF
|
||||
-DOPENVDB_CORE_STATIC=OFF
|
||||
-DOPENVDB_PYTHON_WRAP_ALL_GRID_TYPES=ON
|
||||
-DUSE_EXPLICIT_INSTANTIATION=OFF
|
||||
-DDISABLE_DEPENDENCY_VERSION_CHECKS=ON
|
||||
\"
|
||||
- name: epydoc
|
||||
run: |
|
||||
epydoc --html -o /usr/local/share/doc/OpenVDB/html/python pyopenvdb
|
||||
- name: pre_deploy
|
||||
# Overwrite global SSH configuration
|
||||
run: >
|
||||
echo "Host *
|
||||
StrictHostKeyChecking no
|
||||
UserKnownHostsFile=/dev/null
|
||||
" > /etc/ssh/ssh_config
|
||||
- name: deploy
|
||||
# only deploy documentation on a manual workflow dispatch
|
||||
if: |
|
||||
github.repository_owner == 'AcademySoftwareFoundation' &&
|
||||
github.event_name == 'workflow_dispatch' &&
|
||||
github.event.inputs.deploy == 'true'
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
|
||||
publish_dir: /usr/local/share/doc/OpenVDB/html
|
||||
destination_dir: documentation/doxygen
|
||||
external_repository: AcademySoftwareFoundation/openvdb-website
|
||||
publish_branch: doxygen
|
||||
full_commit_message: "Automatic doxygen documentation update
|
||||
- Deployed from: AcademySoftwareFoundation/openvdb ${{ github.sha }}
|
||||
|
||||
Signed-off-by: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>"
|
||||
@@ -1,4 +1 @@
|
||||
/build/*
|
||||
**/src/benchmarks/build/*
|
||||
nanovdb/nanovdb/build/*
|
||||
.DS_Store
|
||||
|
||||
+568
@@ -0,0 +1,568 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CMake Configuration for OpenVDB
|
||||
|
||||
The OpenVDB CMake build system generates targets depending on the
|
||||
enabled components. It is designed for out of source CMake generation
|
||||
(a build location for CMake to write to will be required). For example,
|
||||
from the root of the repository:
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../
|
||||
|
||||
Depending on the components you choose to build, a number of optional
|
||||
and required dependencies are expected. See the dependency documentation
|
||||
for more information:
|
||||
|
||||
https://academysoftwarefoundation.github.io/openvdb/dependencies.html
|
||||
|
||||
And the documentation on building OpenVDB for more in depth installation
|
||||
instructions:
|
||||
|
||||
https://academysoftwarefoundation.github.io/openvdb/build.html
|
||||
|
||||
This CMakeLists file provides most available options for configuring the
|
||||
build and installation of all OpenVDB components. By default the core
|
||||
library and the vdb_print binary are enabled.
|
||||
|
||||
Note that various packages have inbuilt CMake module support. See the
|
||||
CMake documentation for more ZLib, Doxygen, OpenGL, Boost and Python
|
||||
controls:
|
||||
|
||||
https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html
|
||||
|
||||
OpenVDB's CMake supports building the various components of against a
|
||||
prior installation of OpenVDB.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
# note: cmake_minimum_required must be called before project commands to
|
||||
# ensure policy scope is set up correctly
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# CMP0091 allows for MSVC ABI targetting via CMAKE_MSVC_RUNTIME_LIBRARY
|
||||
# from CMake 3.15 and above. Must come before project().
|
||||
if(POLICY CMP0091)
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
endif()
|
||||
|
||||
###### Version
|
||||
|
||||
set(OpenVDB_MAJOR_VERSION 9)
|
||||
set(OpenVDB_MINOR_VERSION 0)
|
||||
set(OpenVDB_PATCH_VERSION 1)
|
||||
set(OpenVDB_VERSION "${OpenVDB_MAJOR_VERSION}.${OpenVDB_MINOR_VERSION}.${OpenVDB_PATCH_VERSION}")
|
||||
|
||||
project(OpenVDB LANGUAGES CXX VERSION ${OpenVDB_VERSION})
|
||||
|
||||
###### OpenVDB Build/Component Options
|
||||
|
||||
include(CMakeDependentOption)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# todo epydoc and pdflatex
|
||||
option(OPENVDB_BUILD_CORE "Enable the core OpenVDB library. Both static and shared versions are enabled by default" ON)
|
||||
option(OPENVDB_BUILD_BINARIES "Enable the vdb binaries. Only vdb_print is enabled by default" ON)
|
||||
option(OPENVDB_BUILD_PYTHON_MODULE "Build the pyopenvdb Python module" OFF)
|
||||
option(OPENVDB_BUILD_UNITTESTS "Build the OpenVDB unit tests" OFF)
|
||||
option(OPENVDB_BUILD_DOCS "Build the OpenVDB documentation" OFF)
|
||||
option(OPENVDB_BUILD_HOUDINI_PLUGIN "Build the Houdini plugin" OFF)
|
||||
option(OPENVDB_BUILD_HOUDINI_ABITESTS "Build the Houdini ABI tests" OFF)
|
||||
|
||||
option(OPENVDB_BUILD_AX "Build the OpenVDB AX library. Turns ON if USE_AX is ON." ${USE_AX})
|
||||
option(OPENVDB_BUILD_AX_UNITTESTS "Build the OpenVDB AX unit tests" OFF)
|
||||
|
||||
option(OPENVDB_BUILD_NANOVDB "Build the NanoVDB library. Turns ON if USE_NANOVDB is ON." ${USE_NANOVDB})
|
||||
|
||||
option(OPENVDB_BUILD_MAYA_PLUGIN "Build the Maya plugin" OFF)
|
||||
option(OPENVDB_ENABLE_RPATH "Build with RPATH information" ON)
|
||||
option(OPENVDB_CXX_STRICT "Enable or disable pre-defined compiler warnings" OFF)
|
||||
|
||||
cmake_dependent_option(OPENVDB_INSTALL_CMAKE_MODULES
|
||||
"Install the provided OpenVDB CMake modules when building the core library"
|
||||
ON "OPENVDB_BUILD_CORE" OFF)
|
||||
|
||||
option(USE_HOUDINI [=[
|
||||
Build the library against a Houdini installation. Turns on automatically if OPENVDB_BUILD_HOUDINI_PLUGIN is enabled.
|
||||
When enabled, you do not need to provide dependency locations for TBB, Blosc, IlmBase and OpenEXR. Boost must be
|
||||
provided. IlmBase/OpenEXR can optionally be provided if Houdini Version >= 17.5.]=] OFF)
|
||||
option(USE_MAYA [=[
|
||||
Build the library against a Maya installation. Turns on automatically if OPENVDB_BUILD_MAYA_PLUGIN is enabled.
|
||||
When enabled, you do not need to provide dependency locations for TBB. All other dependencies must be provided.]=] OFF)
|
||||
option(USE_TBB [=[
|
||||
Use TBB in building the NanoVDB library.]=] ON)
|
||||
option(USE_BLOSC [=[
|
||||
Use blosc while building openvdb components. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located
|
||||
openvdb build configuration to decide on blosc support. You may set this to on to force blosc to be used if you
|
||||
know it to be required.]=] ON)
|
||||
option(USE_ZLIB [=[
|
||||
Use zlib while building openvdb components. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located
|
||||
openvdb build configuration to decide on zlib support. ZLib can only be disabled if Blosc is also disabled. ]=] ON)
|
||||
option(USE_LOG4CPLUS [=[
|
||||
Use log4cplus while building openvdb components. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the
|
||||
located openvdb build configuration to decide on log4cplus support. You may set this to on to force log4cplus
|
||||
to be used if you know it to be required.]=] OFF)
|
||||
option(USE_EXR [=[
|
||||
Use OpenEXR while building openvdb components. If enabled, this also switches USE_IMATH_HALF to ON unless
|
||||
it too was provided and set to OFF.]=] OFF)
|
||||
option(USE_IMATH_HALF [=[
|
||||
Use the definiton of half floating point types from the Imath library. If OFF, the embedded definition provided
|
||||
by OpenVDB is used. If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the located openvdb build configuration
|
||||
to select the correct half support. You may set this to on to force Imath half to be used if you know it to be
|
||||
required.]=] ${USE_EXR})
|
||||
option(USE_PNG "Use PNG while building openvdb components." OFF)
|
||||
option(USE_AX "Use OpenVDB AX while building openvdb components." ${OPENVDB_BUILD_AX})
|
||||
option(USE_NANOVDB "Use NanoVDB while building openvdb components." ${OPENVDB_BUILD_NANOVDB})
|
||||
|
||||
cmake_dependent_option(OPENVDB_DISABLE_BOOST_IMPLICIT_LINKING
|
||||
"Disable the implicit linking of Boost libraries on Windows" ON "WIN32" OFF)
|
||||
option(USE_CCACHE "Build using Ccache if found on the path" ON)
|
||||
option(USE_STATIC_DEPENDENCIES [=[
|
||||
Only search for and use static libraries. If OFF the shared versions of requried libraries are prioritised, falling
|
||||
back to static libraries. Forcing individual static dependencies can be enabled by setting XXX_USE_STATIC_LIBS
|
||||
to ON, where XXX is the package name. On Windows this behaviour is less strict, with any located libraries assumed
|
||||
to be static. This has no effect for any packages found with Xxx_DIR (i.e. CMake CONFIG mode).]=] OFF)
|
||||
option(DISABLE_DEPENDENCY_VERSION_CHECKS [=[
|
||||
Disable minimum version checks for OpenVDB dependencies. It is strongly recommended that this remains disabled.
|
||||
Consider updating your dependencies where possible if encountering minimum requirement CMake errors.]=] OFF)
|
||||
option(DISABLE_CMAKE_SEARCH_PATHS [=[
|
||||
Disable CMakes default system search paths when locating dependencies. When enabled, CMake will fall back to
|
||||
its default system search routine if it cannot find a dependency with the provided settings. When disabled, only
|
||||
paths provided through the Xxx_ROOT, supported XXX_INCLUDEDIR/XXX_LIBRARYDIR variables or the SYSTEM_LIBRARY_PATHS
|
||||
list will be searched.]=] OFF)
|
||||
option(OPENVDB_USE_DEPRECATED_ABI_7 "Bypass minimum ABI requirement checks" OFF)
|
||||
option(OPENVDB_USE_DEPRECATED_ABI_8 "Bypass minimum ABI requirement checks" OFF)
|
||||
option(OPENVDB_USE_FUTURE_ABI_10 "Bypass future ABI check" OFF)
|
||||
option(OPENVDB_FUTURE_DEPRECATION "Generate messages for upcoming deprecation" ON)
|
||||
option(OPENVDB_ENABLE_UNINSTALL "Adds a CMake uninstall target." ON)
|
||||
option(USE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." OFF)
|
||||
cmake_dependent_option(USE_PKGCONFIG "Use pkg-config to search for dependent libraries." ON "NOT WIN32" OFF)
|
||||
|
||||
option(USE_EXPLICIT_INSTANTIATION "Use explicit instantiation for all supported classes and methods against a
|
||||
pre-defined list of OpenVDB trees. This makes the core library larger and slower to compile, but speeds up
|
||||
the compilation of all dependent code by bypassing the expensive template instantation." ON)
|
||||
|
||||
set(SYSTEM_LIBRARY_PATHS "" CACHE STRING [=[
|
||||
A global list of library paths to additionally use into when searching for dependencies.]=])
|
||||
set(MSVC_MP_THREAD_COUNT "" CACHE STRING [=[
|
||||
The number of threads to use when invoking MSVC builds with cmake --build. CMake defaults to 1. Note that
|
||||
cmake --parallel and CMAKE_BUILD_PARALLEL_LEVEL only change the number of PROJECTS that are built in parallel,
|
||||
NOT the number of TU's ]=])
|
||||
|
||||
set(_CONCURRENT_MALLOC_OPTIONS None Auto Jemalloc Tbbmalloc)
|
||||
if(NOT CONCURRENT_MALLOC)
|
||||
set(CONCURRENT_MALLOC Auto CACHE STRING
|
||||
"Explicitly link the OpenVDB executables against a particular concurrent malloc library.
|
||||
Options are: None Auto Jemalloc Tbbmalloc. Although not required, it is strongly recommended
|
||||
to use a concurrent memory allocator. Has no effect if OPENVDB_BUILD_BINARIES and
|
||||
OPENVDB_BUILD_UNITTESTS are false. Auto is the default and implies Jemalloc, unless USE_MAYA
|
||||
is ON or Jemalloc is unavailable, in which case Tbbmalloc is used. Note that this is not
|
||||
linked into library builds and defers this choice to downstream applications via explicit
|
||||
CMake targets." FORCE
|
||||
)
|
||||
elseif(NOT ${CONCURRENT_MALLOC} IN_LIST _CONCURRENT_MALLOC_OPTIONS)
|
||||
message(WARNING "Unrecognized value for CONCURRENT_MALLOC, using Auto instead.")
|
||||
set(CONCURRENT_MALLOC Auto CACHE STRING FORCE)
|
||||
endif()
|
||||
|
||||
set(_OPENVDB_SIMD_OPTIONS None SSE42 AVX)
|
||||
if(NOT OPENVDB_SIMD)
|
||||
set(OPENVDB_SIMD None CACHE STRING
|
||||
"Choose whether to enable SIMD compiler flags or not, options are: None SSE42 AVX.
|
||||
Although not required, it is strongly recommended to enable SIMD. AVX implies SSE42.
|
||||
None is the default." FORCE
|
||||
)
|
||||
elseif(NOT ${OPENVDB_SIMD} IN_LIST _OPENVDB_SIMD_OPTIONS)
|
||||
message(WARNING "Unrecognized or unsupported value for OPENVDB_SIMD, "
|
||||
"using None instead.")
|
||||
set(OPENVDB_SIMD None CACHE STRING FORCE)
|
||||
endif()
|
||||
|
||||
if(USE_BLOSC AND NOT USE_ZLIB)
|
||||
message(WARNING "ZLib can only be disabled if Blosc is also disabled. Enabling ZLib.")
|
||||
endif()
|
||||
|
||||
if(USE_NANOVDB)
|
||||
if(OPENVDB_BUILD_CORE AND NOT OPENVDB_BUILD_NANOVDB)
|
||||
message(FATAL_ERROR "Invalid CMake build configuration:
|
||||
OPENVDB_BUILD_CORE: [ON]
|
||||
OPENVDB_BUILD_NANOVDB: [OFF]
|
||||
USE_NANOVDB: [ON]
|
||||
If you are rebuilding the core library and using sub components, building
|
||||
these sub components must also be enabled (i.e. -DOPENVDB_BUILD_NANOVDB=ON).")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_AX)
|
||||
if(OPENVDB_BUILD_CORE AND NOT OPENVDB_BUILD_AX)
|
||||
message(FATAL_ERROR "Invalid CMake build configuration:
|
||||
OPENVDB_BUILD_CORE: [ON]
|
||||
OPENVDB_BUILD_AX: [OFF]
|
||||
USE_AX: [ON]
|
||||
If you are rebuilding the core library and using sub components, building
|
||||
these sub components must also be enabled (i.e. -DOPENVDB_BUILD_AX=ON).")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_HOUDINI_PLUGIN OR OPENVDB_BUILD_HOUDINI_ABITESTS)
|
||||
set(USE_HOUDINI ON)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_MAYA_PLUGIN)
|
||||
set(USE_MAYA ON)
|
||||
endif()
|
||||
|
||||
if(USE_MAYA AND USE_HOUDINI)
|
||||
# @todo technically this is possible so long as library versions match
|
||||
# exactly but it's difficult to validate and dangerous
|
||||
message(FATAL_ERROR "Cannot build both Houdini and Maya plugins against "
|
||||
"the same core dependencies. Plugins must be compiled separately to "
|
||||
"ensure the required DCC dependencies are met.")
|
||||
endif()
|
||||
|
||||
###### Deprecated options
|
||||
|
||||
if(OPENVDB_CODE_COVERAGE)
|
||||
message(FATAL_ERROR "The OPENVDB_CODE_COVERAGE option has been removed. Choose instead the unique"
|
||||
"build type -DCMAKE_BUILD_TYPE=coverage")
|
||||
endif()
|
||||
if(OPENVDB_BUILD_HOUDINI_SOPS)
|
||||
message(FATAL_ERROR "The OPENVDB_BUILD_HOUDINI_SOPS option has been removed. Use OPENVDB_BUILD_HOUDINI_PLUGIN.")
|
||||
endif()
|
||||
if(DEFINED USE_SYSTEM_LIBRARY_PATHS)
|
||||
message(FATAL_ERROR "The USE_SYSTEM_LIBRARY_PATHS option has been removed. Use DISABLE_CMAKE_SEARCH_PATHS.")
|
||||
endif()
|
||||
|
||||
# Various root level CMake options which are marked as advanced
|
||||
|
||||
mark_as_advanced(
|
||||
CONCURRENT_MALLOC
|
||||
DISABLE_CMAKE_SEARCH_PATHS
|
||||
DISABLE_DEPENDENCY_VERSION_CHECKS
|
||||
OPENVDB_BUILD_HOUDINI_ABITESTS
|
||||
OPENVDB_CXX_STRICT
|
||||
OPENVDB_ENABLE_RPATH
|
||||
OPENVDB_FUTURE_DEPRECATION
|
||||
OPENVDB_SIMD
|
||||
OPENVDB_USE_DEPRECATED_ABI_7
|
||||
OPENVDB_USE_DEPRECATED_ABI_8
|
||||
OPENVDB_USE_FUTURE_ABI_10
|
||||
SYSTEM_LIBRARY_PATHS
|
||||
USE_CCACHE
|
||||
USE_COLORED_OUTPUT
|
||||
USE_HOUDINI
|
||||
USE_IMATH_HALF
|
||||
USE_LOG4CPLUS
|
||||
USE_MAYA
|
||||
)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# Configure MINIMUM and FUTURE_MINIMUM version variables
|
||||
|
||||
include(cmake/config/OpenVDBVersions.cmake)
|
||||
|
||||
#########################################################################
|
||||
|
||||
enable_testing()
|
||||
|
||||
# Add our cmake modules
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
|
||||
# Add cmake modules to installation command
|
||||
# @todo fix our glew cmake module
|
||||
|
||||
if(OPENVDB_INSTALL_CMAKE_MODULES)
|
||||
set(OPENVDB_CMAKE_MODULES
|
||||
cmake/FindBlosc.cmake
|
||||
cmake/FindJemalloc.cmake
|
||||
cmake/FindIlmBase.cmake
|
||||
cmake/FindLog4cplus.cmake
|
||||
cmake/FindOpenEXR.cmake
|
||||
cmake/FindOpenVDB.cmake
|
||||
cmake/FindTBB.cmake
|
||||
cmake/OpenVDBGLFW3Setup.cmake
|
||||
cmake/OpenVDBHoudiniSetup.cmake
|
||||
cmake/OpenVDBMayaSetup.cmake
|
||||
cmake/OpenVDBUtils.cmake
|
||||
)
|
||||
install(FILES ${OPENVDB_CMAKE_MODULES} DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenVDB)
|
||||
endif()
|
||||
|
||||
# Configure component dependencies by loading the Houdini/Maya setup
|
||||
# scripts. These also find the Houdini/Maya installations
|
||||
|
||||
if(USE_HOUDINI)
|
||||
include(OpenVDBHoudiniSetup)
|
||||
endif()
|
||||
|
||||
if(USE_MAYA)
|
||||
include(OpenVDBMayaSetup)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_DOCS)
|
||||
add_subdirectory(doc)
|
||||
endif()
|
||||
|
||||
if(NOT OPENVDB_BUILD_AX AND OPENVDB_BUILD_AX_GRAMMAR)
|
||||
# only re-generate the AX grammar
|
||||
set(OPENVDB_AX_SHARED OFF CACHE BOOL "" FORCE)
|
||||
set(OPENVDB_AX_STATIC OFF CACHE BOOL "" FORCE)
|
||||
add_subdirectory(openvdb_ax/openvdb_ax)
|
||||
endif()
|
||||
|
||||
# Early exit if there's nothing to build
|
||||
|
||||
if(NOT (
|
||||
OPENVDB_BUILD_CORE OR
|
||||
OPENVDB_BUILD_BINARIES OR
|
||||
OPENVDB_BUILD_AX OR
|
||||
OPENVDB_BUILD_AX_UNITTESTS OR
|
||||
OPENVDB_BUILD_PYTHON_MODULE OR
|
||||
OPENVDB_BUILD_UNITTESTS OR
|
||||
OPENVDB_BUILD_HOUDINI_PLUGIN OR
|
||||
OPENVDB_BUILD_HOUDINI_ABITESTS OR
|
||||
OPENVDB_BUILD_MAYA_PLUGIN OR
|
||||
OPENVDB_BUILD_NANOVDB)
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
#########################################################################
|
||||
|
||||
# ccache setup
|
||||
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_PATH ccache)
|
||||
if(CCACHE_PATH)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
message(STATUS "Using ccache: ${CCACHE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#########################################################################
|
||||
|
||||
# Configure general CMake and CXX settings
|
||||
|
||||
include(cmake/config/OpenVDBCXX.cmake)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# Configure malloc library. Use Jemalloc for Linux and non-Maya, otherwise Tbbmalloc.
|
||||
# * On Mac OSX, linking against Jemalloc < 4.3.0 seg-faults with this error:
|
||||
# malloc: *** malloc_zone_unregister() failed for 0xaddress
|
||||
# Houdini 17.5 and older ships with Jemalloc 3.6.0, so we make Tbbmalloc the default
|
||||
# on Mac OSX (https://github.com/jemalloc/jemalloc/issues/420). Later versions of
|
||||
# Jemalloc are thought to work, but haven't been tested.
|
||||
# * On Windows, we follow SideFX's example in using Tbbmalloc due to the challenges
|
||||
# of injecting into the Windows runtime to replace the system allocator.
|
||||
|
||||
if((OPENVDB_BUILD_BINARIES OR OPENVDB_BUILD_UNITTESTS) AND CONCURRENT_MALLOC STREQUAL "Auto")
|
||||
if(WIN32 OR APPLE OR USE_MAYA)
|
||||
set(CONCURRENT_MALLOC "Tbbmalloc")
|
||||
else()
|
||||
find_package(Jemalloc QUIET)
|
||||
if(NOT TARGET Jemalloc::jemalloc)
|
||||
message(WARNING "Unable to find Jemalloc, attempting to fall back to TBB malloc.
|
||||
It is recommended to use Jemalloc for optimum performance.")
|
||||
set(CONCURRENT_MALLOC "Tbbmalloc")
|
||||
else()
|
||||
set(CONCURRENT_MALLOC "Jemalloc")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Configure SIMD. AVX implies SSE 4.2.
|
||||
|
||||
if(OPENVDB_SIMD STREQUAL "AVX")
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:-mavx>")
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:-msse4.2>")
|
||||
add_compile_definitions("$<$<COMPILE_LANGUAGE:CXX>:OPENVDB_USE_AVX>")
|
||||
add_compile_definitions("$<$<COMPILE_LANGUAGE:CXX>:OPENVDB_USE_SSE42>")
|
||||
elseif(OPENVDB_SIMD STREQUAL "SSE42")
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:-msse4.2>")
|
||||
add_compile_definitions("$<$<COMPILE_LANGUAGE:CXX>:OPENVDB_USE_SSE42>")
|
||||
endif()
|
||||
|
||||
#########################################################################
|
||||
|
||||
# Configure our cmake modules to only search for static libraries
|
||||
|
||||
if(USE_STATIC_DEPENDENCIES)
|
||||
set(BLOSC_USE_STATIC_LIBS ON)
|
||||
set(OPENEXR_USE_STATIC_LIBS ON)
|
||||
set(ILMBASE_USE_STATIC_LIBS ON)
|
||||
set(TBB_USE_STATIC_LIBS ON)
|
||||
set(LOG4CPLUS_USE_STATIC_LIBS ON)
|
||||
set(JEMALLOC_USE_STATIC_LIBS ON)
|
||||
set(GTEST_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
# @todo glfw needs custom support.
|
||||
# set(GLFW_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
|
||||
# Configure OpenVDB Library and ABI versions
|
||||
|
||||
set(NEEDS_OPENVDB OFF)
|
||||
|
||||
if(OPENVDB_BUILD_AX OR
|
||||
OPENVDB_BUILD_BINARIES OR
|
||||
OPENVDB_BUILD_UNITTESTS OR
|
||||
OPENVDB_BUILD_HOUDINI_PLUGIN OR
|
||||
OPENVDB_BUILD_MAYA_PLUGIN OR
|
||||
OPENVDB_BUILD_PYTHON_MODULE OR
|
||||
OPENVDB_BUILD_HOUDINI_ABITESTS)
|
||||
set(NEEDS_OPENVDB ON)
|
||||
endif()
|
||||
|
||||
if(NOT OPENVDB_BUILD_CORE AND NEEDS_OPENVDB)
|
||||
# Find VDB installation and determine lib/abi versions. This resets the
|
||||
# version and ABI numbers
|
||||
find_package(OpenVDB REQUIRED)
|
||||
# Check ABI version was found and explicitly error if attempting to build against
|
||||
# an incompatible Houdini version
|
||||
if(OpenVDB_ABI AND OPENVDB_HOUDINI_ABI)
|
||||
if(NOT ${OpenVDB_ABI} EQUAL ${OPENVDB_HOUDINI_ABI})
|
||||
message(FATAL_ERROR "Located OpenVDB installation is not ABI compatible with "
|
||||
"Houdini Version ${Houdini_VERSION}. Requires ABI ${OPENVDB_HOUDINI_ABI}, found "
|
||||
"ABI ${OpenVDB_ABI}.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Configuring for OpenVDB Version ${OpenVDB_VERSION}")
|
||||
|
||||
# Locate openvdb_ax if necessary
|
||||
|
||||
if(NOT OPENVDB_BUILD_AX AND
|
||||
(OPENVDB_BUILD_AX_UNITTESTS OR
|
||||
USE_AX))
|
||||
find_package(OpenVDB REQUIRED COMPONENTS openvdb_ax)
|
||||
endif()
|
||||
|
||||
# Locate nanovdb if necessary
|
||||
|
||||
if(NOT OPENVDB_BUILD_NANOVDB AND
|
||||
USE_NANOVDB)
|
||||
find_package(OpenVDB REQUIRED COMPONENTS nanovdb)
|
||||
endif()
|
||||
|
||||
|
||||
# Validate the OpenVDB ABI Version. If OpenVDB_ABI is not set, we're either building
|
||||
# the core library OR the ABI hasn't been deduced from a VDB installation. Use the
|
||||
# value from OPENVDB_ABI_VERSION_NUMBER, falling back to the lib major version number
|
||||
|
||||
if(NOT OpenVDB_ABI)
|
||||
if(OPENVDB_ABI_VERSION_NUMBER)
|
||||
set(OpenVDB_ABI ${OPENVDB_ABI_VERSION_NUMBER})
|
||||
else()
|
||||
set(OpenVDB_ABI ${OpenVDB_MAJOR_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# From the deduced ABI, check against the required ABI for Houdini (if set).
|
||||
# Forcefully set the ABI to the required value if necessary - do this after to
|
||||
# explicitly warn the user if their chosen value is different.
|
||||
|
||||
if(OPENVDB_HOUDINI_ABI AND (NOT "${OpenVDB_ABI}" EQUAL "${OPENVDB_HOUDINI_ABI}"))
|
||||
message(WARNING "CMake will explicitly set the value of OPENVDB_ABI_VERSION_NUMBER to "
|
||||
"${OPENVDB_HOUDINI_ABI} to match the ABI of the target Houdini Version.")
|
||||
set(OpenVDB_ABI ${OPENVDB_HOUDINI_ABI})
|
||||
endif()
|
||||
|
||||
# Validate ABI value if outside supported range
|
||||
|
||||
if(OpenVDB_ABI LESS MINIMUM_OPENVDB_ABI_VERSION)
|
||||
message(FATAL_ERROR "OpenVDB ABI versions earlier than ${MINIMUM_OPENVDB_ABI_VERSION} are "
|
||||
"no longer supported.")
|
||||
endif()
|
||||
|
||||
if(FUTURE_MINIMUM_OPENVDB_ABI_VERSION AND OpenVDB_ABI LESS FUTURE_MINIMUM_OPENVDB_ABI_VERSION)
|
||||
if(NOT OPENVDB_USE_DEPRECATED_ABI_${OpenVDB_ABI})
|
||||
message(FATAL_ERROR "OpenVDB ABI versions earlier than ${FUTURE_MINIMUM_OPENVDB_ABI_VERSION} "
|
||||
"are deprecated. Set CMake option OPENVDB_USE_DEPRECATED_ABI_${OpenVDB_ABI} to ON to "
|
||||
"suppress this error.")
|
||||
endif()
|
||||
|
||||
message(DEPRECATION "OpenVDB ABI versions earlier than ${FUTURE_MINIMUM_OPENVDB_ABI_VERSION} "
|
||||
"are deprecated and will soon be removed.")
|
||||
# global target definition
|
||||
add_definitions(-DOPENVDB_USE_DEPRECATED_ABI_${OpenVDB_ABI})
|
||||
endif()
|
||||
|
||||
if(OpenVDB_ABI EQUAL FUTURE_OPENVDB_ABI_VERSION)
|
||||
if(NOT OPENVDB_USE_FUTURE_ABI_${OpenVDB_ABI})
|
||||
message(FATAL_ERROR "OpenVDB ABI version ${OpenVDB_ABI} contains changes to ABI that are still "
|
||||
"in active development and have not been finalized. Set CMake option "
|
||||
"OPENVDB_USE_FUTURE_ABI_${OpenVDB_ABI} to ON to suppress this error.")
|
||||
endif()
|
||||
|
||||
message(WARNING "OpenVDB ABI version ${OpenVDB_ABI} contains changes to ABI that are still "
|
||||
"in active development and have not been finalized.")
|
||||
# global target definition
|
||||
add_definitions(-DOPENVDB_USE_FUTURE_ABI_${OpenVDB_ABI})
|
||||
endif()
|
||||
|
||||
message(STATUS "Configuring for OpenVDB ABI Version ${OpenVDB_ABI}")
|
||||
|
||||
# Always force set as we may need to change it if it's incompatible with Houdini
|
||||
set(OPENVDB_ABI_VERSION_NUMBER ${OpenVDB_ABI} CACHE STRING [=[
|
||||
Build for compatibility with version N of the OpenVDB Grid ABI, where N is 6, 7, 8 etc. (some newer features
|
||||
will be disabled). If OPENVDB_BUILD_CORE is OFF, CMake attempts to query the installed vdb_print binary to
|
||||
determine the ABI number. You may set this to force a given ABI number.]=] FORCE)
|
||||
|
||||
##########################################################################
|
||||
|
||||
if(OPENVDB_BUILD_CORE)
|
||||
add_subdirectory(openvdb/openvdb)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_AX)
|
||||
add_subdirectory(openvdb_ax/openvdb_ax)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_AX_UNITTESTS)
|
||||
add_subdirectory(openvdb_ax/openvdb_ax/test)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_PYTHON_MODULE)
|
||||
add_subdirectory(openvdb/openvdb/python)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_BINARIES)
|
||||
add_subdirectory(openvdb_cmd)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_UNITTESTS)
|
||||
add_subdirectory(openvdb/openvdb/unittest)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_HOUDINI_PLUGIN)
|
||||
add_subdirectory(openvdb_houdini/openvdb_houdini)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_HOUDINI_ABITESTS)
|
||||
add_subdirectory(openvdb_houdini/openvdb_houdini/abitest)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_MAYA_PLUGIN)
|
||||
add_subdirectory(openvdb_maya/openvdb_maya)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_BUILD_NANOVDB)
|
||||
add_subdirectory(nanovdb/nanovdb)
|
||||
endif()
|
||||
|
||||
##########################################################################
|
||||
|
||||
if(OPENVDB_ENABLE_UNINSTALL)
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/Uninstall.cmake
|
||||
)
|
||||
endif()
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
# See https://help.github.com/articles/about-codeowners/
|
||||
# for more info about CODEOWNERS file
|
||||
|
||||
# It uses the same pattern rule for gitignore file
|
||||
# https://git-scm.com/docs/gitignore#_pattern_format
|
||||
|
||||
# Admin/General
|
||||
/.github/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
/ci/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
/cmake/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
/doc/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
/pendingchanges/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
/tsc/ @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
CODEOWNERS @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
LICENSE @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
CHANGES @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
*.md @kmuseth @apradhana @jmlait @idclip @danrbailey @richhones
|
||||
|
||||
# Core OpenVDB Library
|
||||
/openvdb/ @kmuseth
|
||||
/openvdb/openvdb/points/ @danrbailey @idclip
|
||||
|
||||
# OpenVDB AX
|
||||
/openvdb_ax/ @idclip @richhones
|
||||
|
||||
# NanoVDB
|
||||
/nanovdb/ @kmuseth
|
||||
|
||||
# OpenVDB Houdini - Default
|
||||
/openvdb_houdini/ @kmuseth
|
||||
|
||||
# OpenVDB Houdini - VDB Primitive and SideFX Utils
|
||||
/openvdb_houdini/openvdb_houdini/GEO_PrimVDB.* @jmlait
|
||||
/openvdb_houdini/openvdb_houdini/GU_PrimVDB.* @jmlait
|
||||
/openvdb_houdini/openvdb_houdini/GEO_VDBTranslator.* @jmlait
|
||||
/openvdb_houdini/openvdb_houdini/GT_GEOPrimCollectVDB.* @jmlait
|
||||
/openvdb_houdini/openvdb_houdini/SOP_VDBVerbUtils.* @jmlait
|
||||
/openvdb_houdini/openvdb_houdini/UT_VDBUtils.* @jmlait
|
||||
|
||||
# OpenVDB Houdini - VDB Points
|
||||
/openvdb_houdini/openvdb_houdini/PointUtils.* @danrbailey @idclip
|
||||
/openvdb_houdini/openvdb_houdini/*_OpenVDB_Points_* @danrbailey @idclip
|
||||
/openvdb_houdini/openvdb_houdini/GR_PrimVDBPoints.* @danrbailey @idclip
|
||||
@@ -0,0 +1 @@
|
||||
All participants agree to abide by LF Projects Code of Conduct (as defined in the [charter](tsc/charter.md)) available at https://lfprojects.org/policies/code-of-conduct/
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# Overview
|
||||
|
||||
This project aims to be governed in a transparent, accessible way for the benefit of the community. All participation in this project is open and not bound to corporate affiliation. Participants are all bound to the [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
# Project roles
|
||||
|
||||
## Contributor
|
||||
|
||||
The contributor role is the starting role for anyone participating in the project and wishing to contribute code.
|
||||
|
||||
### Process for becoming a contributor
|
||||
|
||||
* Review the [coding standards](https://academysoftwarefoundation.github.io/openvdb/codingStyle.html) to ensure your contribution is in line with the project's coding and styling guidelines.
|
||||
* Have a signed CLA on file ( see [below](#contributor-license-agreements) )
|
||||
* Submit your code as a PR with the appropriate [DCO sign-off](#commit-sign-off).
|
||||
* Have your submission approved by the [committer(s)](#committer) and merged into the codebase.
|
||||
|
||||
### Legal Requirements
|
||||
|
||||
OpenVDB is a project of the Academy Software Foundation and follows the
|
||||
open source software best practice policies of the Linux Foundation.
|
||||
|
||||
#### License
|
||||
|
||||
OpenVDB is licensed under the [Mozilla Public License, version 2.0](LICENSE.md)
|
||||
license. Contributions to OpenVDB should abide by that standard
|
||||
license.
|
||||
|
||||
#### Contributor License Agreements
|
||||
|
||||
Developers who wish to contribute code to be considered for inclusion
|
||||
in OpenVDB must first complete a **Contributor License Agreement**.
|
||||
|
||||
OpenVDB uses [EasyCLA](https://lfcla.com/) for managing CLAs, which automatically
|
||||
checks to ensure CLAs are signed by a contributor before a commit
|
||||
can be merged.
|
||||
|
||||
* If you are an individual writing the code on your own time and
|
||||
you're SURE you are the sole owner of any intellectual property you
|
||||
contribute, you can [sign the CLA as an individual contributor](https://docs.linuxfoundation.org/lfx/easycla/contributors/individual-contributor).
|
||||
|
||||
* If you are writing the code as part of your job, or if there is any
|
||||
possibility that your employers might think they own any
|
||||
intellectual property you create, then you should use the [Corporate
|
||||
Contributor Licence
|
||||
Agreement](https://docs.linuxfoundation.org/lfx/easycla/contributors/corporate-contributor).
|
||||
|
||||
The OpenVDB CLAs are the standard forms used by Linux Foundation
|
||||
projects and [recommended by the ASWF TAC](https://github.com/AcademySoftwareFoundation/tac/blob/master/process/contributing.md#contributor-license-agreement-cla). You can review the text of the CLAs in the [TSC directory](tsc/).
|
||||
|
||||
#### Commit Sign-Off
|
||||
|
||||
Every commit must be signed off. That is, every commit log message
|
||||
must include a “`Signed-off-by`” line (generated, for example, with
|
||||
“`git commit --signoff`”), indicating that the committer wrote the
|
||||
code and has the right to release it under the
|
||||
[Mozilla Public License, version 2.0](LICENSE.md)
|
||||
license. See the [TAC documentation on contribution sign off](https://github.com/AcademySoftwareFoundation/tac/blob/master/process/contributing.md#contribution-sign-off) for more information on this requirement.
|
||||
|
||||
## Committer
|
||||
|
||||
The committer role enables the participant to commit code directly to the repository, but also comes with the obligation to be a responsible leader in the community.
|
||||
|
||||
### Process for becoming a committer
|
||||
|
||||
* Show your experience with the codebase through contributions and engagement on the community channels.
|
||||
* Request to become a committer.
|
||||
* Have the majority of committers approve you becoming a committer.
|
||||
* Your name and email is added to the MAINTAINERS.md file for the project.
|
||||
|
||||
### Committer responsibilities
|
||||
|
||||
* Monitor email aliases.
|
||||
* Monitor Slack (delayed response is perfectly acceptable).
|
||||
* Triage GitHub issues and perform pull request reviews for other committers and the community.
|
||||
* Make sure that ongoing PRs are moving forward at the right pace or close them.
|
||||
* Remain an active contributor to the project in general and the code base in particular.
|
||||
|
||||
### When does a committer lose committer status?
|
||||
|
||||
If a committer is no longer interested or cannot perform the committer duties listed above, they
|
||||
should volunteer to be moved to emeritus status. In extreme cases this can also occur by a vote of
|
||||
the committers per the voting process below.
|
||||
|
||||
## Technical Steering Committee (TSC) member
|
||||
|
||||
The Technical Steering Committee (TSC) oversees the overall technical direction of OpenVDB, as defined in the [charter](charter.md).
|
||||
|
||||
TSC voting members consist of committers that have been nominated by the committers, with a supermajority of voting members required to have a committer elected to be a TSC voting member. TSC voting members term and succession is defined in the [charter](charter.md).
|
||||
|
||||
All meetings of the TSC are open to participation by any member of the OpenVDB community. Meeting times are listed in the [ASWF technical community calendar](https://lists.aswf.io/g/tac/calendar).
|
||||
|
||||
## Current TSC members
|
||||
|
||||
* Ken Museth, Chair / NVIDIA
|
||||
* Andre Pradhana, DreamWorks
|
||||
* Jeff Lait, SideFX
|
||||
* Nick Avramoussis, WETA
|
||||
* Dan Bailey, ILM
|
||||
* Richard Jones, DNEG
|
||||
|
||||
# Release Process
|
||||
|
||||
Project releases will occur on a scheduled basis as agreed to by the TSC.
|
||||
|
||||
# Conflict resolution and voting
|
||||
|
||||
In general, we prefer that technical issues and committer status/TSC membership are amicably worked out
|
||||
between the persons involved. If a dispute cannot be decided independently, the TSC can be
|
||||
called in to decide an issue. If the TSC themselves cannot decide an issue, the issue will
|
||||
be resolved by voting. The voting process is a simple majority in which each TSC receives one vote.
|
||||
|
||||
# Communication
|
||||
|
||||
This project, just like all of open source, is a global community. In addition to the [Code of Conduct](CODE_OF_CONDUCT.md), this project will:
|
||||
|
||||
* Keep all communication on open channels ( mailing list, forums, chat ).
|
||||
* Be respectful of time and language differences between community members ( such as scheduling meetings, email/issue responsiveness, etc ).
|
||||
* Ensure tools are able to be used by community members regardless of their region.
|
||||
|
||||
If you have concerns about communication challenges for this project, please contact the [TSC](mailto:openvdb-tsc-private@lists.aswf.io).
|
||||
@@ -1,176 +1,373 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1. Definitions.
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
2.1. Grants
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
2.2. Effective Date
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
<!-- Copyright Contributors to the OpenVDB project. -->
|
||||
|
||||
# OpenVDB Committers
|
||||
|
||||
The current OpenVDB maintainers are:
|
||||
|
||||
|
||||
| Name | Email |
|
||||
| ---------------- | -----------------
|
||||
| Jeff Lait | jlait@sidefx.com
|
||||
| Dan Bailey | danbailey@ilm.com
|
||||
| Nick Avramoussis | navramoussis@wetafx.co.nz
|
||||
| Ken Museth | ken.museth@gmail.com
|
||||
| Andre Pradhana | andre.pradhana@dreamworks.com
|
||||
| Richard Jones | rhj@dneg.com
|
||||
@@ -1,28 +1,139 @@
|
||||
# *ƒ*(VDB)
|
||||

|
||||
|
||||
## A New Home for ƒVDB
|
||||
|
||||
:warning: The public home for fVDB development is now located in the Academy Software Foundation OpenVDB Github Organization [https://github.com/openvdb](https://github.com/openvdb). :warning:
|
||||
|
||||
All of the code and history for fVDB on the OpenVDB `feature/fvdb` branch has been moved to repositories in the OpenVDB Github Organization. In order to encourage movement to fVDB's new home in the OpenVDB Github Organization, we have removed the code from the head of this branch but the history remains.
|
||||
|
||||
The components of fVDB have been split into the following repositories:
|
||||
|
||||
### [fvdb-core](https://github.com/openvdb/fvdb-core)
|
||||
|
||||
The fvdb-core repository houses the core library and PyTorch extension for ƒVDB. ƒVDB is a framework that provides differentiable, sparse volumetric operators built on top of NanoVDB and enables PyTorch users to utilize the NanoVDB data structure to build powerful and scalable spatial intelligence applications.
|
||||
[](LICENSE)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/2774)
|
||||
[](https://slack.aswf.io/)
|
||||
|
||||
|
||||
### [fvdb-examples](https://github.com/openvdb/fvdb-examples)
|
||||
| OpenVDB | AX | Nano | Houdini |
|
||||
| :----: | :----: | :----: | :----: |
|
||||
| [](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/build.yml) | [](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/ax.yml) | [](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/nanovdb.yml) | [](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/houdini.yml) |
|
||||
|
||||
The fvdb-examples repository contains examples of how to use the ƒVDB library to build spatial intelligence networks or pipelines. These are provided as reference for how to implement interesting or well-known methods and networks on top of ƒVDB including examples of pipelines that perform panoptic segmentation and depth reconstruction.
|
||||
[Website](https://www.openvdb.org) |
|
||||
[Discussion Forum](https://github.com/AcademySoftwareFoundation/openvdb/discussions) |
|
||||
[Documentation](https://academysoftwarefoundation.github.io/openvdb)
|
||||
|
||||
OpenVDB is an open source C++ library comprising a novel hierarchical data structure and a large suite of tools for the efficient storage and manipulation of sparse volumetric data discretized on three-dimensional grids. It was developed by DreamWorks Animation for use in volumetric applications typically encountered in feature film production.
|
||||
|
||||
|
||||
### [fvdb-reality-capture](https://github.com/openvdb/fvdb-reality-capture)
|
||||
### Development Repository
|
||||
|
||||
The fvdb-reality-capture repository contains examples of how to use the ƒVDB library to build reality capture pipelines centered on ƒVDB's 3D Gaussian splatting methods. This repository houses utilities and examples that illustrate how to train and render 3D Gaussian splatting models using ƒVDB as well as interesting methods that build upon the 3D Gaussian scene representation such as meshing.
|
||||
This GitHub repository hosts the trunk of the OpenVDB development. This implies that it is the newest public version with the latest features and bug fixes. However, it also means that it has not undergone a lot of testing and is generally less stable than the [production releases](https://github.com/AcademySoftwareFoundation/openvdb/releases).
|
||||
|
||||
|
||||
### [nanovdb-editor](https://github.com/openvdb/nanovdb-editor)
|
||||
### License
|
||||
|
||||
The nanovdb-editor repository contains a library, python bindings and a standalone GUI application that allows you to view and edit NanoVDB. nanovdb-editor also provides viewer functionality for fVDB.
|
||||
OpenVDB is released under the [Mozilla Public License Version 2.0](https://www.mozilla.org/MPL/2.0/), which is a free, open source software license developed and maintained by the Mozilla Foundation.
|
||||
|
||||
The trademarks of any contributor to this project may not be used in association with the project without the contributor's express permission.
|
||||
|
||||
### Contributing
|
||||
|
||||
OpenVDB welcomes contributions to the OpenVDB project. Please refer to the [contribution guidelines](CONTRIBUTING.md) for details on how to make a contribution.
|
||||
|
||||
### Developer Quick Start
|
||||
|
||||
The following provides basic installation examples for the core OpenVDB library. Other components, such as the python module, OpenVDB AX, NanoVDB and various executables, may require additional dependencies. See the [build documentation](https://academysoftwarefoundation.github.io/openvdb/build.html) for help with installations.
|
||||
|
||||
#### Linux
|
||||
##### Installing Dependencies (Boost, TBB, Blosc)
|
||||
|
||||
```bash
|
||||
apt-get install -y libboost-iostreams-dev
|
||||
apt-get install -y libtbb-dev
|
||||
apt-get install -y libblosc-dev
|
||||
```
|
||||
|
||||
##### Building OpenVDB
|
||||
```bash
|
||||
git clone git@github.com:AcademySoftwareFoundation/openvdb.git
|
||||
cd openvdb
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j4 && make install
|
||||
```
|
||||
#### macOS
|
||||
##### Installing Dependencies (Boost, TBB, Blosc)
|
||||
```bash
|
||||
brew install boost
|
||||
brew install tbb
|
||||
brew install c-blosc
|
||||
```
|
||||
##### Building OpenVDB
|
||||
```bash
|
||||
git clone git@github.com:AcademySoftwareFoundation/openvdb.git
|
||||
cd openvdb
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j4 && make install
|
||||
```
|
||||
#### Windows
|
||||
##### Installing Dependencies (Boost, TBB, Blosc)
|
||||
|
||||
Note that the following commands have only been tested for 64bit systems/libraries.
|
||||
It is recommended to set the `VCPKG_DEFAULT_TRIPLET` environment variable to
|
||||
`x64-windows` to use 64-bit libraries by default. You will also require
|
||||
[Git](https://git-scm.com/downloads), [vcpkg](https://github.com/microsoft/vcpkg)
|
||||
and [CMake](https://cmake.org/download/) to be installed.
|
||||
|
||||
```bash
|
||||
vcpkg install zlib:x64-windows
|
||||
vcpkg install blosc:x64-windows
|
||||
vcpkg install tbb:x64-windows
|
||||
vcpkg install boost-iostreams:x64-windows
|
||||
vcpkg install boost-any:x64-windows
|
||||
vcpkg install boost-algorithm:x64-windows
|
||||
vcpkg install boost-uuid:x64-windows
|
||||
vcpkg install boost-interprocess:x64-windows
|
||||
```
|
||||
##### Building OpenVDB
|
||||
```bash
|
||||
git clone git@github.com:AcademySoftwareFoundation/openvdb.git
|
||||
cd openvdb
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=<PATH_TO_VCPKG>\scripts\buildsystems\vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows -A x64 ..
|
||||
cmake --build . --parallel 4 --config Release --target install
|
||||
```
|
||||
|
||||
#### Building OpenVDB AX
|
||||
|
||||
OpenVDB AX depends on the core OpenVDB library. See the [build documentation](https://academysoftwarefoundation.github.io/openvdb/build.html) for all available AX component options:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:AcademySoftwareFoundation/openvdb.git
|
||||
cd openvdb
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DOPENVDB_BUILD_AX=ON ..
|
||||
make -j4 && make install
|
||||
```
|
||||
|
||||
#### Building NanoVDB
|
||||
|
||||
NanoVDB can be built with and without OpenVDB support. To see full build instructions
|
||||
see the [NanoVDB build documentation](https://academysoftwarefoundation.github.io/openvdb/NanoVDB_HowToBuild.html)
|
||||
|
||||
#### Building Without OpenVDB Support
|
||||
|
||||
```bash
|
||||
git clone git@github.com:AcademySoftwareFoundation/openvdb.git
|
||||
cd openvdb/nanovdb/nanovdb # Build from the subdirectory
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j4 && make install
|
||||
```
|
||||
|
||||
#### Building With OpenVDB Support
|
||||
|
||||
```bash
|
||||
git clone git@github.com:AcademySoftwareFoundation/openvdb.git
|
||||
cd openvdb
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DOPENVDB_BUILD_NANOVDB=ON ..
|
||||
make -j4 && make install
|
||||
```
|
||||
|
||||
Executable
+172
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
# print versions
|
||||
bash --version
|
||||
if [ ! -z "$CXX" ]; then $CXX -v; fi
|
||||
cmake --version
|
||||
CMAKE_VERSION=$(cmake --version | head -n1 | cut -d' ' -f3)
|
||||
|
||||
################################################
|
||||
|
||||
OPTS_ARGS+=("t:") ## See --target
|
||||
OPTS_ARGS+=("j:") ## Thread usage
|
||||
OPTS_ARGS+=("c:") ## See --cargs
|
||||
OPTS_ARGS+=("v") ## See --verbose
|
||||
OPTL_ARGS+=("components:") ## Specify cmake component(s) to enable
|
||||
OPTL_ARGS+=("config:") ## Specify cmake configuration during the build step
|
||||
OPTL_ARGS+=("target:") ## Specify target(s) to build
|
||||
OPTL_ARGS+=("build-dir:") ## Build directory
|
||||
OPTL_ARGS+=("cargs:") ## args to pass directly to cmake generation step
|
||||
OPTL_ARGS+=("build-type:") ## Release, Debug, etc.
|
||||
OPTL_ARGS+=("verbose") ## Verbose build output
|
||||
|
||||
# Defaults
|
||||
declare -A PARMS
|
||||
PARMS[--components]=core,bin
|
||||
PARMS[--target]=install
|
||||
PARMS[--build-dir]=build
|
||||
# github actions runners have 2 threads
|
||||
# https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners
|
||||
PARMS[-j]=2
|
||||
|
||||
# Available options for --components
|
||||
declare -A COMPONENTS
|
||||
COMPONENTS['core']='OPENVDB_BUILD_CORE'
|
||||
COMPONENTS['python']='OPENVDB_BUILD_PYTHON_MODULE'
|
||||
COMPONENTS['test']='OPENVDB_BUILD_UNITTESTS'
|
||||
COMPONENTS['bin']='OPENVDB_BUILD_BINARIES'
|
||||
COMPONENTS['view']='OPENVDB_BUILD_VDB_VIEW'
|
||||
COMPONENTS['render']='OPENVDB_BUILD_VDB_RENDER'
|
||||
COMPONENTS['hou']='OPENVDB_BUILD_HOUDINI_PLUGIN'
|
||||
COMPONENTS['doc']='OPENVDB_BUILD_DOCS'
|
||||
|
||||
COMPONENTS['axcore']='OPENVDB_BUILD_AX'
|
||||
COMPONENTS['axgr']='OPENVDB_BUILD_AX_GRAMMAR'
|
||||
COMPONENTS['axbin']='OPENVDB_BUILD_AX_BINARIES'
|
||||
COMPONENTS['axtest']='OPENVDB_BUILD_AX_UNITTESTS'
|
||||
|
||||
COMPONENTS['nano']='OPENVDB_BUILD_NANOVDB'
|
||||
COMPONENTS['nanotest']='NANOVDB_BUILD_UNITTESTS'
|
||||
COMPONENTS['nanoexam']='NANOVDB_BUILD_EXAMPLES'
|
||||
COMPONENTS['nanobench']='NANOVDB_BUILD_BENCHMARK'
|
||||
COMPONENTS['nanotool']='NANOVDB_BUILD_TOOLS'
|
||||
|
||||
################################################
|
||||
|
||||
HAS_PARM() {
|
||||
if [ -z "${PARMS[$1]}" ]; then return 1
|
||||
else return 0; fi
|
||||
}
|
||||
|
||||
# Format to string and replace spaces with commas
|
||||
LARGS_STR="${OPTL_ARGS[@]}"
|
||||
LARGS_STR=${LARGS_STR// /,}
|
||||
SARGS_STR="${OPTS_ARGS[@]}"
|
||||
SARGS_STR=${SARGS_STR// /,}
|
||||
|
||||
# Parse all arguments and store them in an array, split by whitespace. Error if unsupported
|
||||
ARGS="$(eval getopt --options=$SARGS_STR --longoptions=$LARGS_STR -- "$@")"
|
||||
eval set -- "$ARGS"
|
||||
|
||||
# split into associative array
|
||||
while true; do
|
||||
case "$1" in
|
||||
-v|--verbose) # options which dont take an argument
|
||||
PARMS["$1"]="ON"; shift
|
||||
;;
|
||||
-[a-z]*|--[a-z]*) # all other arguments (key/values)
|
||||
PARMS["$1"]="$2"; shift 2
|
||||
;;
|
||||
--)
|
||||
shift; break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
################################################
|
||||
|
||||
# extract arguments
|
||||
if HAS_PARM -t; then TARGET=${PARMS[-t]}; fi
|
||||
if HAS_PARM --target; then
|
||||
if [ -z $TARGET ]; then TARGET=${PARMS[--target]}
|
||||
else TARGET+=","${PARMS[--target]}; fi
|
||||
fi
|
||||
if HAS_PARM -c; then CMAKE_EXTRA=${PARMS[-c]}; fi
|
||||
if HAS_PARM --cargs; then
|
||||
if [ -z $CMAKE_EXTRA ]; then CMAKE_EXTRA=${PARMS[--cargs]}
|
||||
else CMAKE_EXTRA+=" "${PARMS[--cargs]}; fi
|
||||
fi
|
||||
BUILD_DIR=${PARMS[--build-dir]}
|
||||
|
||||
# handle whitespace
|
||||
eval "CMAKE_EXTRA=($CMAKE_EXTRA)"
|
||||
|
||||
if HAS_PARM -v || HAS_PARM --verbose; then
|
||||
# Using CMAKE_VERBOSE_MAKEFILE as well as `cmake --verbose` to
|
||||
# support older versions of CMake.
|
||||
CMAKE_EXTRA+=("-DCMAKE_VERBOSE_MAKEFILE=ON")
|
||||
fi
|
||||
if HAS_PARM --build-type; then CMAKE_EXTRA+=("-DCMAKE_BUILD_TYPE=${PARMS[--build-type]}"); fi
|
||||
|
||||
# Available components. If a component is not provided it is
|
||||
# explicitly set to OFF.
|
||||
IN_COMPONENTS=${PARMS[--components]}
|
||||
IFS=', ' read -r -a IN_COMPONENTS <<< "$IN_COMPONENTS"
|
||||
for comp in "${IN_COMPONENTS[@]}"; do
|
||||
if [ -z ${COMPONENTS[$comp]} ]; then
|
||||
echo "Invalid component passed to build \"$comp\""; exit -1
|
||||
fi
|
||||
done
|
||||
# Build Components command
|
||||
for comp in "${!COMPONENTS[@]}"; do
|
||||
setting="OFF"
|
||||
for in in "${IN_COMPONENTS[@]}"; do
|
||||
if [[ $comp == "$in" ]]; then
|
||||
setting="ON"; break
|
||||
fi
|
||||
done
|
||||
CMAKE_EXTRA+=("-D${COMPONENTS[$comp]}=$setting")
|
||||
done
|
||||
|
||||
################################################
|
||||
|
||||
# github actions runners have 2 threads
|
||||
# https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners
|
||||
export CMAKE_BUILD_PARALLEL_LEVEL=${PARMS[-j]}
|
||||
echo "Build using ${CMAKE_BUILD_PARALLEL_LEVEL} threads"
|
||||
|
||||
# NOTE: --parallel only effects the number of projects build, not t-units.
|
||||
# We support this with out own MSVC_MP_THREAD_COUNT option for MSVC.
|
||||
# Alternatively it is mentioned that the following should work:
|
||||
# cmake --build . -- /p:CL_MPcount=8
|
||||
# However it does not seem to for our project.
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/20564
|
||||
|
||||
CMAKE_BUILD_CMD="cmake --build . --parallel ${PARMS[-j]} --target $TARGET --verbose"
|
||||
|
||||
if HAS_PARM --config; then
|
||||
CMAKE_BUILD_CMD+=" --config ${PARMS[--config]}"
|
||||
fi
|
||||
|
||||
################################################
|
||||
|
||||
mkdir -p ${BUILD_DIR}
|
||||
cd ${BUILD_DIR}
|
||||
|
||||
# Report the cmake commands
|
||||
set -x
|
||||
|
||||
# Note:
|
||||
# - print and lod binary options are always on and can be toggles with: OPENVDB_BUILD_BINARIES=ON/OFF
|
||||
cmake \
|
||||
-DOPENVDB_USE_DEPRECATED_ABI_7=ON \
|
||||
-DOPENVDB_USE_DEPRECATED_ABI_8=ON \
|
||||
-DOPENVDB_BUILD_VDB_PRINT=ON \
|
||||
-DOPENVDB_BUILD_VDB_LOD=ON \
|
||||
-DMSVC_MP_THREAD_COUNT=${PARMS[-j]} \
|
||||
"${CMAKE_EXTRA[@]}" \
|
||||
..
|
||||
|
||||
$CMAKE_BUILD_CMD
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
wget -q https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip
|
||||
unzip build-wrapper-linux-x86.zip
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake \
|
||||
-DCMAKE_CXX_COMPILER=g++ \
|
||||
-DOPENVDB_ABI_VERSION_NUMBER=6 \
|
||||
-DUSE_BLOSC=ON \
|
||||
-DOPENVDB_CXX_STRICT=ON \
|
||||
-DOPENVDB_BUILD_UNITTESTS=ON \
|
||||
-DOPENVDB_BUILD_BINARIES=OFF \
|
||||
-DOPENVDB_CORE_STATIC=OFF \
|
||||
-DOPENVDB_BUILD_PYTHON_MODULE=OFF \
|
||||
-DOPENVDB_CODE_COVERAGE=ON \
|
||||
..
|
||||
|
||||
../build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw_output make -j2
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/usr/local/bin/python
|
||||
#
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# Python script to download the latest Houdini builds
|
||||
# using the SideFX download API:
|
||||
#
|
||||
# https://www.sidefx.com/docs/api/download/index.html
|
||||
#
|
||||
# Authors: Dan Bailey, SideFX
|
||||
|
||||
import time
|
||||
import sys
|
||||
import re
|
||||
import shutil
|
||||
import json
|
||||
import base64
|
||||
import requests
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
# this argument is for the major.minor version of Houdini to download (such as 15.0, 15.5, 16.0)
|
||||
version = sys.argv[1]
|
||||
only_production = True if sys.argv[2] == 'ON' else False
|
||||
user_client_id = os.getenv('HOUDINI_CLIENT_ID')
|
||||
user_client_secret_key = os.getenv('HOUDINI_SECRET_KEY')
|
||||
|
||||
if not re.match('[0-9][0-9]\.[0-9]$', version):
|
||||
raise IOError('Invalid Houdini Version "%s", expecting in the form "major.minor" such as "16.0"' % version)
|
||||
|
||||
|
||||
# Code that provides convenient Python wrappers to call into the API:
|
||||
|
||||
def service(
|
||||
access_token_url, client_id, client_secret_key, endpoint_url,
|
||||
access_token=None, access_token_expiry_time=None):
|
||||
if (access_token is None or
|
||||
access_token_expiry_time is None or
|
||||
access_token_expiry_time < time.time()):
|
||||
access_token, access_token_expiry_time = (
|
||||
get_access_token_and_expiry_time(
|
||||
access_token_url, client_id, client_secret_key))
|
||||
|
||||
return _Service(
|
||||
endpoint_url, access_token, access_token_expiry_time)
|
||||
|
||||
|
||||
class _Service(object):
|
||||
def __init__(
|
||||
self, endpoint_url, access_token, access_token_expiry_time):
|
||||
self.endpoint_url = endpoint_url
|
||||
self.access_token = access_token
|
||||
self.access_token_expiry_time = access_token_expiry_time
|
||||
|
||||
def __getattr__(self, attr_name):
|
||||
return _APIFunction(attr_name, self)
|
||||
|
||||
|
||||
class _APIFunction(object):
|
||||
def __init__(self, function_name, service):
|
||||
self.function_name = function_name
|
||||
self.service = service
|
||||
|
||||
def __getattr__(self, attr_name):
|
||||
# This isn't actually an API function, but a family of them. Append
|
||||
# the requested function name to our name.
|
||||
return _APIFunction(
|
||||
"{0}.{1}".format(self.function_name, attr_name), self.service)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return call_api_with_access_token(
|
||||
self.service.endpoint_url, self.service.access_token,
|
||||
self.function_name, args, kwargs)
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Code that implements authentication and raw calls into the API:
|
||||
|
||||
|
||||
def get_access_token_and_expiry_time(
|
||||
access_token_url, client_id, client_secret_key):
|
||||
"""Given an API client (id and secret key) that is allowed to make API
|
||||
calls, return an access token that can be used to make calls.
|
||||
"""
|
||||
response = requests.post(
|
||||
access_token_url,
|
||||
headers={
|
||||
"Authorization": u"Basic {0}".format(
|
||||
base64.b64encode(
|
||||
"{0}:{1}".format(
|
||||
client_id, client_secret_key
|
||||
).encode()
|
||||
).decode('utf-8')
|
||||
),
|
||||
})
|
||||
if response.status_code != 200:
|
||||
raise AuthorizationError(response.status_code, reponse.text)
|
||||
|
||||
response_json = response.json()
|
||||
access_token_expiry_time = time.time() - 2 + response_json["expires_in"]
|
||||
return response_json["access_token"], access_token_expiry_time
|
||||
|
||||
|
||||
class AuthorizationError(Exception):
|
||||
"""Raised from the client if the server generated an error while generating
|
||||
an access token.
|
||||
"""
|
||||
def __init__(self, http_code, message):
|
||||
super(AuthorizationError, self).__init__(message)
|
||||
self.http_code = http_code
|
||||
|
||||
|
||||
def call_api_with_access_token(
|
||||
endpoint_url, access_token, function_name, args, kwargs):
|
||||
"""Call into the API using an access token that was returned by
|
||||
get_access_token.
|
||||
"""
|
||||
response = requests.post(
|
||||
endpoint_url,
|
||||
headers={
|
||||
"Authorization": "Bearer " + access_token,
|
||||
},
|
||||
data=dict(
|
||||
json=json.dumps([function_name, args, kwargs]),
|
||||
))
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
|
||||
raise APIError(response.status_code, response.text)
|
||||
|
||||
|
||||
class APIError(Exception):
|
||||
"""Raised from the client if the server generated an error while calling
|
||||
into the API.
|
||||
"""
|
||||
def __init__(self, http_code, message):
|
||||
super(APIError, self).__init__(message)
|
||||
self.http_code = http_code
|
||||
|
||||
|
||||
service = service(
|
||||
access_token_url="https://www.sidefx.com/oauth2/application_token",
|
||||
client_id=user_client_id,
|
||||
client_secret_key=user_client_secret_key,
|
||||
endpoint_url="https://www.sidefx.com/api/",
|
||||
)
|
||||
|
||||
releases_list = service.download.get_daily_builds_list(
|
||||
product='houdini', version=version, platform='linux', only_production=only_production)
|
||||
|
||||
latest_release = service.download.get_daily_build_download(
|
||||
product='houdini', version=version, platform='linux', build=releases_list[0]['build'])
|
||||
|
||||
# Download the file as hou.tar.gz
|
||||
local_filename = 'hou.tar.gz'
|
||||
response = requests.get(latest_release['download_url'], stream=True)
|
||||
if response.status_code == 200:
|
||||
with open(local_filename, 'wb') as f:
|
||||
response.raw.decode_content = True
|
||||
shutil.copyfileobj(response.raw, f)
|
||||
else:
|
||||
raise Exception('Error downloading file!')
|
||||
|
||||
# Verify the file checksum is matching
|
||||
file_hash = hashlib.md5()
|
||||
with open(local_filename, 'rb') as f:
|
||||
for chunk in iter(lambda: f.read(4096), b''):
|
||||
file_hash.update(chunk)
|
||||
if file_hash.hexdigest() != latest_release['hash']:
|
||||
raise Exception('Checksum does not match!')
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
HOUDINI_MAJOR="$1"
|
||||
GOLD="$2"
|
||||
|
||||
pip install --user requests
|
||||
|
||||
python ci/download_houdini.py $HOUDINI_MAJOR $GOLD
|
||||
|
||||
# create dir hierarchy
|
||||
mkdir -p hou/bin
|
||||
mkdir -p hou/houdini
|
||||
mkdir -p hou/toolkit
|
||||
mkdir -p hou/dsolib
|
||||
|
||||
# unpack hou.tar.gz and cleanup
|
||||
tar -xzf hou.tar.gz
|
||||
rm -rf hou.tar.gz
|
||||
cd houdini*
|
||||
tar -xzf houdini.tar.gz
|
||||
|
||||
# copy required files into hou dir
|
||||
cp houdini_setup* ../hou/.
|
||||
cp -r toolkit/cmake ../hou/toolkit/.
|
||||
cp -r toolkit/include ../hou/toolkit/.
|
||||
cp -r dsolib/libHoudini* ../hou/dsolib/.
|
||||
cp -r dsolib/libopenvdb_sesi* ../hou/dsolib/.
|
||||
cp -r dsolib/libblosc* ../hou/dsolib/.
|
||||
cp -r dsolib/libhboost* ../hou/dsolib/.
|
||||
cp -r dsolib/libz* ../hou/dsolib/.
|
||||
cp -r dsolib/libbz2* ../hou/dsolib/.
|
||||
cp -r dsolib/libtbb* ../hou/dsolib/.
|
||||
cp -r dsolib/libHalf* ../hou/dsolib/.
|
||||
cp -r dsolib/libjemalloc* ../hou/dsolib/.
|
||||
cp -r dsolib/liblzma* ../hou/dsolib/.
|
||||
cp -r dsolib/libIex* ../hou/dsolib/.
|
||||
cp -r dsolib/libImath* ../hou/dsolib/.
|
||||
cp -r dsolib/libIlmThread* ../hou/dsolib/.
|
||||
cp -r dsolib/libIlmImf* ../hou/dsolib/.
|
||||
|
||||
# needed for < H18.0 (due to sesitag)
|
||||
if [ "$HOUDINI_MAJOR" == "17.0" ] || [ "$HOUDINI_MAJOR" == "17.5" ]; then
|
||||
cp -r bin/app_init* ../hou/bin/.
|
||||
cp -r bin/sesitag* ../hou/bin/.
|
||||
cp -r dsolib/lib* ../hou/dsolib/.
|
||||
fi
|
||||
|
||||
# write hou into hou.tar.gz and cleanup
|
||||
cd ..
|
||||
tar -czvf hou.tar.gz hou
|
||||
|
||||
# move hou.tar.gz into hou subdirectory
|
||||
rm -rf hou/*
|
||||
mv hou.tar.gz hou
|
||||
|
||||
# inspect size of tarball
|
||||
ls -lart hou/hou.tar.gz
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
import zipfile
|
||||
import argparse
|
||||
|
||||
try:
|
||||
from urllib.request import urlretrieve
|
||||
except ImportError:
|
||||
from urllib import urlretrieve
|
||||
|
||||
parser = argparse.ArgumentParser(description='VDB files to download')
|
||||
parser.add_argument('--files', '-f', type=str, nargs='+',
|
||||
help='files to download i.e. bunny.vdb fire.vdb')
|
||||
args = parser.parse_args()
|
||||
|
||||
vdbs = [
|
||||
'armadillo.vdb',
|
||||
'boat_points.vdb',
|
||||
'buddha.vdb',
|
||||
'bunny.vdb',
|
||||
'bunny_cloud.vdb',
|
||||
'bunny_points.vdb',
|
||||
'crawler.vdb',
|
||||
'cube.vdb',
|
||||
'dragon.vdb',
|
||||
'emu.vdb',
|
||||
'explosion.vdb',
|
||||
'fire.vdb',
|
||||
'icosahedron.vdb',
|
||||
'iss.vdb',
|
||||
'smoke1.vdb',
|
||||
'smoke2.vdb',
|
||||
'space.vdb',
|
||||
'sphere.vdb',
|
||||
'sphere_points.vdb',
|
||||
'torus.vdb',
|
||||
'torus_knot.vdb',
|
||||
'utahteapot.vdb',
|
||||
'venusstatue.vdb',
|
||||
'waterfall_points.vdb'
|
||||
]
|
||||
|
||||
if args.files:
|
||||
vdbs = list(set(vdbs) & set(args.files))
|
||||
if not vdbs:
|
||||
raise RuntimeError('No valid VDBs specified for download')
|
||||
|
||||
# forma urls in the form:
|
||||
# 'https://artifacts.aswf.io/io/aswf/openvdb/models/buddha.vdb/1.0.0/buddha.vdb-1.0.0.zip'
|
||||
|
||||
vdb_urls = []
|
||||
for vdb in vdbs:
|
||||
url = 'https://artifacts.aswf.io/io/aswf/openvdb/models/' + \
|
||||
vdb +'/1.0.0/' + vdb + '-1.0.0.zip'
|
||||
vdb_urls.append(url)
|
||||
|
||||
|
||||
def download(link, filelocation):
|
||||
urlretrieve(link, filelocation)
|
||||
|
||||
# Init downloads
|
||||
|
||||
downloads = dict()
|
||||
|
||||
for url in vdb_urls:
|
||||
zip_filename = os.path.basename(url)
|
||||
print('Initiating download "' + url + '"')
|
||||
download_thread = threading.Thread(target=download, args=(url,zip_filename))
|
||||
download_thread.start()
|
||||
downloads[zip_filename] = download_thread
|
||||
|
||||
sys.stdout.flush()
|
||||
|
||||
# Process files
|
||||
|
||||
while downloads:
|
||||
zip_file = None
|
||||
while not zip_file:
|
||||
time.sleep(1)
|
||||
for file, thread in downloads.items():
|
||||
if not thread.is_alive():
|
||||
thread.join()
|
||||
zip_file = file
|
||||
break
|
||||
# Remove the entry
|
||||
del downloads[zip_file]
|
||||
|
||||
try:
|
||||
# Extract the downloaded zip
|
||||
print('Extracting "' + zip_file + '"...')
|
||||
sys.stdout.flush()
|
||||
with zipfile.ZipFile(zip_file, 'r') as zip_ref:
|
||||
zip_ref.extractall()
|
||||
|
||||
print('Cleaning up "' + zip_file + '"...')
|
||||
sys.stdout.flush()
|
||||
if os.path.isfile(zip_file): os.remove(zip_file)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
#################################################################################
|
||||
# This script extracts all code blocks from AX documentation which are NOT #
|
||||
# marked as cpp/sh/unparsed and attempts to parse or compile them through the #
|
||||
# vdb_ax command line binary. Code blocks can be marked with a preceding #
|
||||
# notation to determine compilation mode: #
|
||||
# <!--- P ---> = points #
|
||||
# <!--- V ---> = volumes #
|
||||
# <!--- A ---> = all #
|
||||
# If not marked, code is only parsed (though ideally all code blocks should be #
|
||||
# compiled) #
|
||||
#################################################################################
|
||||
set -e
|
||||
|
||||
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/../"
|
||||
VDB_AX=$ROOT/build/openvdb_cmd/vdb_ax/vdb_ax
|
||||
|
||||
DOCS=()
|
||||
DOCS+=($ROOT/doc/ax/ax.txt)
|
||||
DOCS+=($ROOT/doc/ax/axcplusplus.txt)
|
||||
DOCS+=($ROOT/doc/ax/axexamples.txt)
|
||||
# DOCS+=($ROOT/doc/ax/axfunctionlist.txt) do not test this file
|
||||
DOCS+=($ROOT/doc/ax/doc.txt)
|
||||
|
||||
uncompiled=0
|
||||
|
||||
for DOC in "${DOCS[@]}"; do
|
||||
echo "Checking doxygen code in '$DOC...'"
|
||||
# Make sure the file exists
|
||||
if [ ! -f $DOC ]; then
|
||||
echo "Could not find '$DOC.'"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
# Extract all code segments from doxygen documentation in between @code and @endcode
|
||||
data=$(sed -n '/@code.* *$/,/^ *@endcode *$/p' $DOC)
|
||||
|
||||
str=""
|
||||
compile=""
|
||||
skip=false
|
||||
count=0
|
||||
# For each extracted line, rebuild each code segment from @code and @endcode and
|
||||
# run it through a vdb_ax binary if necessary
|
||||
while IFS= read -r line; do
|
||||
# If the code is marked as unparsed, c++ or shell, skip
|
||||
if [[ "$line" == "@code{.unparsed}" ]]; then
|
||||
skip=true
|
||||
elif [[ "$line" == "@code{.cpp}" ]]; then
|
||||
skip=true
|
||||
elif [[ "$line" == "@code{.sh}" ]]; then
|
||||
skip=true
|
||||
elif [[ $line == @code* ]]; then
|
||||
str=""
|
||||
compile="none"
|
||||
elif [[ $line == "<!-- V -->@code"* ]]; then
|
||||
str=""
|
||||
compile="volumes"
|
||||
elif [[ $line == "<!-- P -->@code"* ]]; then
|
||||
str=""
|
||||
compile="points"
|
||||
elif [[ $line == "<!-- A -->@code"* ]]; then
|
||||
str=""
|
||||
compile=""
|
||||
elif [[ $line == @endcode ]]; then
|
||||
echo -e "\nTesting [$count]:"
|
||||
if [ "$skip" = true ]; then
|
||||
echo "Skipping the following unparsed/c++/shell code:"
|
||||
echo -e "$str" | sed 's/^/ /'
|
||||
else
|
||||
# parse
|
||||
if [ "$compile" = "none" ]; then
|
||||
$VDB_AX analyze -s "$str" -v
|
||||
uncompiled=$((uncompiled+1))
|
||||
else
|
||||
$VDB_AX analyze -s "$str" --try-compile $compile -v
|
||||
fi
|
||||
fi
|
||||
skip=false
|
||||
count=$((count+1))
|
||||
str=""
|
||||
compile="none"
|
||||
else
|
||||
str+="$line"$'\n'
|
||||
fi
|
||||
done <<< "$data"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Extract test examples completed successfully"
|
||||
if [ $uncompiled -gt 0 ]; then
|
||||
echo " with $uncompiled uncompiled tests"
|
||||
fi
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
BLOSC_VERSION="$1"
|
||||
INSTALL_ROOT="$2"
|
||||
CMAKE_EXTRA=()
|
||||
if [ ! -z "${INSTALL_ROOT}" ]; then
|
||||
CMAKE_EXTRA+=("-DCMAKE_INSTALL_PREFIX=${INSTALL_ROOT}")
|
||||
fi
|
||||
|
||||
git clone https://github.com/Blosc/c-blosc.git
|
||||
cd c-blosc
|
||||
|
||||
if [ "$BLOSC_VERSION" != "latest" ]; then
|
||||
git checkout tags/v${BLOSC_VERSION} -b v${BLOSC_VERSION}
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
# On MacOS there's a bug between blosc 1.14-1.20 where unistd isn't included
|
||||
# in zlib-1.2.8/gzlib.c. Provide -DPREFER_EXTERNAL_ZLIB to use the installed
|
||||
# version of zlib.
|
||||
# https://github.com/Blosc/python-blosc/issues/229
|
||||
cmake \
|
||||
-DPREFER_EXTERNAL_ZLIB=ON \
|
||||
-DBUILD_STATIC=OFF \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_FUZZERS=OFF \
|
||||
-DBUILD_BENCHMARKS=OFF \
|
||||
"${CMAKE_EXTRA[@]}" \
|
||||
..
|
||||
|
||||
make -j4
|
||||
make install
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
CMAKE_VERSION="$1"
|
||||
CMAKE_PACKAGE=cmake-${CMAKE_VERSION}-Linux-x86_64
|
||||
|
||||
wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_PACKAGE}.tar.gz
|
||||
|
||||
tar -xf ${CMAKE_PACKAGE}.tar.gz
|
||||
cp ${CMAKE_PACKAGE}/bin/* /usr/local/bin/
|
||||
cp -r ${CMAKE_PACKAGE}/share/* /usr/local/share/
|
||||
|
||||
rm -rf ${CMAKE_PACKAGE}
|
||||
rm -rf ${CMAKE_PACKAGE}.tar.gz
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
DOXYGEN_VERSION="$1"
|
||||
|
||||
git clone https://github.com/doxygen/doxygen.git
|
||||
cd doxygen
|
||||
|
||||
if [ "$DOXYGEN_VERSION" != "latest" ]; then
|
||||
git checkout Release_${DOXYGEN_VERSION} -b v${DOXYGEN_VERSION}
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../.
|
||||
make -j4
|
||||
make install
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
GTEST_VERSION="$1"
|
||||
|
||||
git clone https://github.com/google/googletest.git
|
||||
cd googletest
|
||||
|
||||
if [ "$GTEST_VERSION" != "latest" ]; then
|
||||
git checkout release-${GTEST_VERSION} -b v${GTEST_VERSION}
|
||||
fi
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../.
|
||||
make -j4
|
||||
make install
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
LLVM_CRT="$1"
|
||||
|
||||
git clone -b llvmorg-12.0.0 --depth 1 https://github.com/llvm/llvm-project.git llvm
|
||||
cd llvm
|
||||
|
||||
mkdir .build
|
||||
cd .build
|
||||
|
||||
# @note currently only test static builds with MT
|
||||
cmake -S ../llvm -A x64 -G "Visual Studio 16 2019" -Thost=x64 \
|
||||
-DCMAKE_INSTALL_PREFIX="${HOME}/llvm_install" \
|
||||
-DLLVM_TARGETS_TO_BUILD="host" \
|
||||
-DLLVM_BUILD_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_BENCHMARKS=OFF \
|
||||
-DLLVM_INCLUDE_EXAMPLES=OFF \
|
||||
-DLLVM_INCLUDE_TESTS=OFF \
|
||||
-DLLVM_INCLUDE_TOOLS=OFF \
|
||||
-DLLVM_USE_CRT_RELEASE=${LLVM_CRT} \
|
||||
..
|
||||
|
||||
cmake --build . --config Release --target install
|
||||
|
||||
cd ..
|
||||
|
||||
du -h .build -d0
|
||||
du -h ${HOME}/llvm_install -d0
|
||||
|
||||
rm -rf .build
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -x
|
||||
|
||||
brew update
|
||||
brew install bash gnu-getopt # for CI scripts
|
||||
brew install cmake
|
||||
brew install ilmbase
|
||||
brew install openexr@2
|
||||
brew install boost
|
||||
brew install boost-python3 # also installs the dependent python version
|
||||
brew install tbb@2020
|
||||
brew install zlib
|
||||
brew install glfw
|
||||
brew install googletest
|
||||
brew install jq # for trivial parsing of brew json
|
||||
|
||||
# Alias python version installed by boost-python3 to path
|
||||
py_version=$(brew info boost-python3 --json | \
|
||||
jq -cr '.[].dependencies[] | select(. | startswith("python"))')
|
||||
echo "Using python $py_version"
|
||||
# export for subsequent action steps (note, not exported for this env)
|
||||
echo "Python_ROOT_DIR=/usr/local/opt/$py_version" >> $GITHUB_ENV
|
||||
echo "/usr/local/opt/$py_version/bin" >> $GITHUB_PATH
|
||||
|
||||
# Export OpenEXR paths which are no longer installed to /usr/local (as v2.x is deprecated)
|
||||
echo "IlmBase_ROOT=/usr/local/opt/ilmbase" >> $GITHUB_ENV
|
||||
echo "OpenEXR_ROOT=/usr/local/opt/openexr@2" >> $GITHUB_ENV
|
||||
echo "/usr/local/opt/openexr@2/bin" >> $GITHUB_PATH
|
||||
|
||||
# Export TBB paths which are no longer installed to /usr/local (as v2020 is deprecated)
|
||||
echo "TBB_ROOT=/usr/local/opt/tbb@2020" >> $GITHUB_ENV
|
||||
echo "/usr/local/opt/tbb@2020/bin" >> $GITHUB_PATH
|
||||
|
||||
# use gnu-getopt
|
||||
echo "/usr/local/opt/gnu-getopt/bin" >> $GITHUB_PATH
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Download and install deps from homebrew on macos
|
||||
|
||||
LLVM_VERSION=$1
|
||||
if [ -z $LLVM_VERSION ]; then
|
||||
echo "No LLVM version provided for LLVM installation"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
brew update
|
||||
brew install bash gnu-getopt # for CI scripts
|
||||
brew install cmake
|
||||
brew install boost
|
||||
brew install cppunit
|
||||
brew install c-blosc
|
||||
brew install tbb@2020
|
||||
brew install llvm@$LLVM_VERSION
|
||||
brew install zlib
|
||||
|
||||
# Export TBB paths which are no longer installed to /usr/local (as v2020 is deprecated)
|
||||
echo "TBB_ROOT=/usr/local/opt/tbb@2020" >> $GITHUB_ENV
|
||||
echo "/usr/local/opt/tbb@2020/bin" >> $GITHUB_PATH
|
||||
|
||||
# use gnu-getopt
|
||||
echo "/usr/local/opt/gnu-getopt/bin" >> $GITHUB_PATH
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
vcpkg update
|
||||
vcpkg install zlib libpng openexr tbb gtest blosc glfw3 glew \
|
||||
boost-iostreams boost-any boost-uuid boost-interprocess boost-algorithm
|
||||
@@ -0,0 +1,170 @@
|
||||
# Download and install CUDA on windows. Based off the scripts by:
|
||||
# https://github.com/ptheywood/cuda-cmake-github-actions
|
||||
|
||||
## -------------------
|
||||
## Constants
|
||||
## -------------------
|
||||
|
||||
# Dictionary of known cuda versions and thier download URLS, which do not follow a consistent pattern :(
|
||||
$CUDA_KNOWN_URLS = @{
|
||||
"8.0.44" = "http://developer.nvidia.com/compute/cuda/8.0/Prod/network_installers/cuda_8.0.44_win10_network-exe";
|
||||
"8.0.61" = "http://developer.nvidia.com/compute/cuda/8.0/Prod2/network_installers/cuda_8.0.61_win10_network-exe";
|
||||
"9.0.176" = "http://developer.nvidia.com/compute/cuda/9.0/Prod/network_installers/cuda_9.0.176_win10_network-exe";
|
||||
"9.1.85" = "http://developer.nvidia.com/compute/cuda/9.1/Prod/network_installers/cuda_9.1.85_win10_network";
|
||||
"9.2.148" = "http://developer.nvidia.com/compute/cuda/9.2/Prod2/network_installers2/cuda_9.2.148_win10_network";
|
||||
"10.0.130" = "http://developer.nvidia.com/compute/cuda/10.0/Prod/network_installers/cuda_10.0.130_win10_network";
|
||||
"10.1.105" = "http://developer.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.105_win10_network.exe";
|
||||
"10.1.168" = "http://developer.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.168_win10_network.exe";
|
||||
"10.1.243" = "http://developer.download.nvidia.com/compute/cuda/10.1/Prod/network_installers/cuda_10.1.243_win10_network.exe";
|
||||
"10.2.89" = "http://developer.download.nvidia.com/compute/cuda/10.2/Prod/network_installers/cuda_10.2.89_win10_network.exe";
|
||||
"11.0.1" = "http://developer.download.nvidia.com/compute/cuda/11.0.1/network_installers/cuda_11.0.1_win10_network.exe";
|
||||
"11.0.2" = "http://developer.download.nvidia.com/compute/cuda/11.0.2/network_installers/cuda_11.0.2_win10_network.exe";
|
||||
"11.0.3" = "http://developer.download.nvidia.com/compute/cuda/11.0.3/network_installers/cuda_11.0.3_win10_network.exe";
|
||||
"11.1.0" = "https://developer.download.nvidia.com/compute/cuda/11.1.0/network_installers/cuda_11.1.0_win10_network.exe";
|
||||
"11.1.1" = "https://developer.download.nvidia.com/compute/cuda/11.1.1/network_installers/cuda_11.1.1_win10_network.exe";
|
||||
"11.2.0" = "https://developer.download.nvidia.com/compute/cuda/11.2.0/network_installers/cuda_11.2.0_win10_network.exe";
|
||||
"11.2.1" = "https://developer.download.nvidia.com/compute/cuda/11.2.1/network_installers/cuda_11.2.1_win10_network.exe";
|
||||
"11.2.2" = "https://developer.download.nvidia.com/compute/cuda/11.2.2/network_installers/cuda_11.2.2_win10_network.exe";
|
||||
"11.3.0" = "https://developer.download.nvidia.com/compute/cuda/11.3.0/network_installers/cuda_11.3.0_win10_network.exe"
|
||||
}
|
||||
|
||||
# @todo - change this to be based on _MSC_VER intead, or invert it to be CUDA keyed instead?
|
||||
$VISUAL_STUDIO_MIN_CUDA = @{
|
||||
"2019" = "10.1";
|
||||
"2017" = "10.0"; # Depends on which version of 2017! 9.0 to 10.0 depending on version
|
||||
"2015" = "8.0"; # might support older, unsure.
|
||||
}
|
||||
|
||||
# cuda_runtime.h is in nvcc <= 10.2, but cudart >= 11.0
|
||||
# @todo - make this easier to vary per CUDA version.
|
||||
$CUDA_PACKAGES_IN = @(
|
||||
"nvcc";
|
||||
"visual_studio_integration";
|
||||
"curand_dev";
|
||||
"nvrtc_dev";
|
||||
"cudart";
|
||||
)
|
||||
|
||||
|
||||
## -------------------
|
||||
## Select CUDA version
|
||||
## -------------------
|
||||
|
||||
# Get the cuda version from the environment as env:cuda.
|
||||
$CUDA_VERSION_FULL = $env:cuda
|
||||
# Make sure CUDA_VERSION_FULL is set and valid, otherwise error.
|
||||
|
||||
# Validate CUDA version, extracting components via regex
|
||||
$cuda_ver_matched = $CUDA_VERSION_FULL -match "^(?<major>[1-9][0-9]*)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)$"
|
||||
if(-not $cuda_ver_matched){
|
||||
Write-Output "Invalid CUDA version specified, <major>.<minor>.<patch> required. '$CUDA_VERSION_FULL'."
|
||||
exit 1
|
||||
}
|
||||
$CUDA_MAJOR=$Matches.major
|
||||
$CUDA_MINOR=$Matches.minor
|
||||
$CUDA_PATCH=$Matches.patch
|
||||
|
||||
## ---------------------------
|
||||
## Visual studio support check
|
||||
## ---------------------------
|
||||
# Exit if visual studio is too new for the cuda version.
|
||||
$VISUAL_STUDIO = $env:visual_studio.trim()
|
||||
if ($VISUAL_STUDIO.length -ge 4) {
|
||||
$VISUAL_STUDIO_YEAR = $VISUAL_STUDIO.Substring($VISUAL_STUDIO.Length-4)
|
||||
if ($VISUAL_STUDIO_YEAR.length -eq 4 -and $VISUAL_STUDIO_MIN_CUDA.containsKey($VISUAL_STUDIO_YEAR)){
|
||||
$MINIMUM_CUDA_VERSION = $VISUAL_STUDIO_MIN_CUDA[$VISUAL_STUDIO_YEAR]
|
||||
if ([version]$CUDA_VERSION_FULL -lt [version]$MINIMUM_CUDA_VERSION) {
|
||||
Write-Output "Error: Visual Studio $($VISUAL_STUDIO_YEAR) requires CUDA >= $($MINIMUM_CUDA_VERSION)"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Output "Warning: Unknown Visual Studio Version. CUDA version may be insufficient."
|
||||
}
|
||||
|
||||
## ------------------------------------------------
|
||||
## Select CUDA packages to install from environment
|
||||
## ------------------------------------------------
|
||||
|
||||
$CUDA_PACKAGES = ""
|
||||
|
||||
# for CUDA >= 11 cudart is a required package.
|
||||
# if([version]$CUDA_VERSION_FULL -ge [version]"11.0") {
|
||||
# if(-not $CUDA_PACKAGES_IN -contains "cudart") {
|
||||
# $CUDA_PACKAGES_IN += 'cudart'
|
||||
# }
|
||||
# }
|
||||
|
||||
Foreach ($package in $CUDA_PACKAGES_IN) {
|
||||
# Make sure the correct package name is used for nvcc.
|
||||
if($package -eq "nvcc" -and [version]$CUDA_VERSION_FULL -lt [version]"9.1"){
|
||||
$package="compiler"
|
||||
} elseif($package -eq "compiler" -and [version]$CUDA_VERSION_FULL -ge [version]"9.1") {
|
||||
$package="nvcc"
|
||||
}
|
||||
$CUDA_PACKAGES += " $($package)_$($CUDA_MAJOR).$($CUDA_MINOR)"
|
||||
|
||||
}
|
||||
echo "$($CUDA_PACKAGES)"
|
||||
## -----------------
|
||||
## Prepare download
|
||||
## -----------------
|
||||
|
||||
# Select the download link if known, otherwise have a guess.
|
||||
$CUDA_REPO_PKG_REMOTE=""
|
||||
if($CUDA_KNOWN_URLS.containsKey($CUDA_VERSION_FULL)){
|
||||
$CUDA_REPO_PKG_REMOTE=$CUDA_KNOWN_URLS[$CUDA_VERSION_FULL]
|
||||
} else{
|
||||
# Guess what the url is given the most recent pattern (at the time of writing, 10.1)
|
||||
Write-Output "note: URL for CUDA ${$CUDA_VERSION_FULL} not known, estimating."
|
||||
$CUDA_REPO_PKG_REMOTE="http://developer.download.nvidia.com/compute/cuda/$($CUDA_MAJOR).$($CUDA_MINOR)/Prod/network_installers/cuda_$($CUDA_VERSION_FULL)_win10_network.exe"
|
||||
}
|
||||
$CUDA_REPO_PKG_LOCAL="cuda_$($CUDA_VERSION_FULL)_win10_network.exe"
|
||||
|
||||
|
||||
## ------------
|
||||
## Install CUDA
|
||||
## ------------
|
||||
|
||||
# Get CUDA network installer
|
||||
Write-Output "Downloading CUDA Network Installer for $($CUDA_VERSION_FULL) from: $($CUDA_REPO_PKG_REMOTE)"
|
||||
Invoke-WebRequest $CUDA_REPO_PKG_REMOTE -OutFile $CUDA_REPO_PKG_LOCAL | Out-Null
|
||||
if(Test-Path -Path $CUDA_REPO_PKG_LOCAL){
|
||||
Write-Output "Downloading Complete"
|
||||
} else {
|
||||
Write-Output "Error: Failed to download $($CUDA_REPO_PKG_LOCAL) from $($CUDA_REPO_PKG_REMOTE)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Invoke silent install of CUDA (via network installer)
|
||||
Write-Output "Installing CUDA $($CUDA_VERSION_FULL). Subpackages $($CUDA_PACKAGES)"
|
||||
Start-Process -Wait -FilePath .\"$($CUDA_REPO_PKG_LOCAL)" -ArgumentList "-s $($CUDA_PACKAGES)"
|
||||
|
||||
# Check the return status of the CUDA installer.
|
||||
if (!$?) {
|
||||
Write-Output "Error: CUDA installer reported error. $($LASTEXITCODE)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Store the CUDA_PATH in the environment for the current session, to be forwarded in the action.
|
||||
$CUDA_PATH = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$($CUDA_MAJOR).$($CUDA_MINOR)"
|
||||
$CUDA_PATH_VX_Y = "CUDA_PATH_V$($CUDA_MAJOR)_$($CUDA_MINOR)"
|
||||
# Set environmental variables in this session
|
||||
$env:CUDA_PATH = "$($CUDA_PATH)"
|
||||
$env:CUDA_PATH_VX_Y = "$($CUDA_PATH_VX_Y)"
|
||||
Write-Output "CUDA_PATH $($CUDA_PATH)"
|
||||
Write-Output "CUDA_PATH_VX_Y $($CUDA_PATH_VX_Y)"
|
||||
|
||||
# PATH needs updating elsewhere, anything in here won't persist.
|
||||
# Append $CUDA_PATH/bin to path.
|
||||
# Set CUDA_PATH as an environmental variable
|
||||
|
||||
|
||||
# If executing on github actions, emit the appropriate echo statements to update environment variables
|
||||
if (Test-Path "env:GITHUB_ACTIONS") {
|
||||
# Set paths for subsequent steps, using $env:CUDA_PATH
|
||||
echo "Adding CUDA to CUDA_PATH, CUDA_PATH_X_Y and PATH"
|
||||
echo "CUDA_PATH=$env:CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
echo "$env:CUDA_PATH_VX_Y=$env:CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
echo "$env:CUDA_PATH/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Various tests to test the FindOpenVDB CMake modules and
|
||||
# general VDB installation
|
||||
|
||||
# 1) Test basic CMakeLists is able to build vdb_print with
|
||||
# the expected VDB installation
|
||||
|
||||
cmakelists="
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(TestInstall LANGUAGES CXX)
|
||||
find_package(OpenVDB REQUIRED COMPONENTS openvdb)
|
||||
add_executable(test_vdb_print \"../openvdb_cmd/vdb_print/main.cc\")
|
||||
target_link_libraries(test_vdb_print OpenVDB::openvdb)
|
||||
"
|
||||
mkdir tmp
|
||||
cd tmp
|
||||
echo -e "$cmakelists" > CMakeLists.txt
|
||||
cmake -DCMAKE_MODULE_PATH=/usr/local/lib64/cmake/OpenVDB/ .
|
||||
cmake --build . --config Release --target test_vdb_print
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
SONAR_VERSION=3.3.0.1492
|
||||
|
||||
wget -q https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_VERSION}-linux.zip
|
||||
unzip sonar-scanner-cli-${SONAR_VERSION}-linux.zip
|
||||
|
||||
mkdir coverage
|
||||
cd coverage
|
||||
|
||||
for g in $(find ../build -name "*.gcno" -type f); do
|
||||
gcov -p -l -o $(dirname "$g") $(echo "$g" | sed -e 's/\/build\//\//' -e 's/\.gcno/\.cc/' -e 's/\/CMakeFiles.*\.dir\//\//')
|
||||
done
|
||||
|
||||
cd ..
|
||||
|
||||
sonar-scanner-${SONAR_VERSION}-linux/bin/sonar-scanner -X \
|
||||
-Dsonar.projectKey=openvdb \
|
||||
-Dsonar.links.homepage=https://www.openvdb.org/ \
|
||||
-Dsonar.links.scm=https://github.com/AcademySoftwareFoundation/openvdb \
|
||||
-Dsonar.links.issue=https://jira.aswf.io/projects/OVDB \
|
||||
-Dsonar.sources=openvdb \
|
||||
-Dsonar.exclusions=openvdb/cmd/**,openvdb/unittest/**,openvdb/viewer/**,openvdb/python/** \
|
||||
-Dsonar.binaries=build/openvdb/unittest/vdb_test \
|
||||
-Dsonar.tests=openvdb/unittest \
|
||||
-Dsonar.sourceEncoding=UTF-8 \
|
||||
-Dsonar.organization=danrbailey-github \
|
||||
-Dsonar.cfamily.build-wrapper-output=build/bw_output \
|
||||
-Dsonar.cfamily.gcov.reportsPath=coverage \
|
||||
-Dsonar.host.url=https://sonarcloud.io \
|
||||
-Dsonar.login=$SONAR_TOKEN
|
||||
@@ -0,0 +1,384 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindBlosc
|
||||
---------
|
||||
|
||||
Find Blosc include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(Blosc
|
||||
[version] [EXACT] # Minimum or EXACT version e.g. 1.5.0
|
||||
[REQUIRED] # Fail with error if Blosc is not found
|
||||
)
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``Blosc::blosc``
|
||||
This module defines IMPORTED target Blosc::Blosc, if Blosc has been found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``Blosc_FOUND``
|
||||
True if the system has the Blosc library.
|
||||
``Blosc_VERSION``
|
||||
The version of the Blosc library which was found.
|
||||
``Blosc_INCLUDE_DIRS``
|
||||
Include directories needed to use Blosc.
|
||||
``Blosc_RELEASE_LIBRARIES``
|
||||
Libraries needed to link to the release version of Blosc.
|
||||
``Blosc_RELEASE_LIBRARY_DIRS``
|
||||
Blosc release library directories.
|
||||
``Blosc_DEBUG_LIBRARIES``
|
||||
Libraries needed to link to the debug version of Blosc.
|
||||
``Blosc_DEBUG_LIBRARY_DIRS``
|
||||
Blosc debug library directories.
|
||||
|
||||
Deprecated - use [RELEASE|DEBUG] variants:
|
||||
|
||||
``Blosc_LIBRARIES``
|
||||
Libraries needed to link to Blosc.
|
||||
``Blosc_LIBRARY_DIRS``
|
||||
Blosc library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``Blosc_INCLUDE_DIR``
|
||||
The directory containing ``blosc.h``.
|
||||
``Blosc_LIBRARY``
|
||||
The path to the Blosc library. may include target_link_libraries() debug/optimized keywords
|
||||
``Blosc_LIBRARY_RELEASE``
|
||||
The path to the Blosc release library.
|
||||
``Blosc_LIBRARY_DEBUG``
|
||||
The path to the Blosc debug library.
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``Blosc_ROOT``
|
||||
Preferred installation prefix.
|
||||
``BLOSC_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``BLOSC_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``BLOSC_DEBUG_SUFFIX``
|
||||
Suffix of the debug version of blosc. Defaults to "_d", OR the empty string for VCPKG_TOOLCHAIN
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``BLOSC_USE_STATIC_LIBS``
|
||||
Only search for static blosc libraries
|
||||
``BLOSC_USE_EXTERNAL_SOURCES``
|
||||
Set to ON if Blosc has been built using external sources for LZ4, snappy,
|
||||
zlib and zstd. Default is OFF.
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
mark_as_advanced(
|
||||
Blosc_INCLUDE_DIR
|
||||
Blosc_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_BLOSC_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_BLOSC_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
# Set _BLOSC_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV BLOSC_ROOT from CMake 3.12
|
||||
if(Blosc_ROOT)
|
||||
set(_BLOSC_ROOT ${Blosc_ROOT})
|
||||
elseif(DEFINED ENV{Blosc_ROOT})
|
||||
set(_BLOSC_ROOT $ENV{Blosc_ROOT})
|
||||
elseif(BLOSC_ROOT)
|
||||
set(_BLOSC_ROOT ${BLOSC_ROOT})
|
||||
elseif(DEFINED ENV{BLOSC_ROOT})
|
||||
set(_BLOSC_ROOT $ENV{BLOSC_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find blosc
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_Blosc QUIET blosc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for blosc include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_BLOSC_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _BLOSC_INCLUDE_SEARCH_DIRS
|
||||
${BLOSC_INCLUDEDIR}
|
||||
${_BLOSC_ROOT}
|
||||
${PC_Blosc_INCLUDE_DIRS}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Look for a standard blosc header file.
|
||||
find_path(Blosc_INCLUDE_DIR blosc.h
|
||||
${_FIND_BLOSC_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_BLOSC_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include
|
||||
)
|
||||
|
||||
if(EXISTS "${Blosc_INCLUDE_DIR}/blosc.h")
|
||||
file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h"
|
||||
_blosc_version_major_string REGEX "#define BLOSC_VERSION_MAJOR +[0-9]+ "
|
||||
)
|
||||
string(REGEX REPLACE "#define BLOSC_VERSION_MAJOR +([0-9]+).*$" "\\1"
|
||||
_blosc_version_major_string "${_blosc_version_major_string}"
|
||||
)
|
||||
string(STRIP "${_blosc_version_major_string}" Blosc_VERSION_MAJOR)
|
||||
|
||||
file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h"
|
||||
_blosc_version_minor_string REGEX "#define BLOSC_VERSION_MINOR +[0-9]+ "
|
||||
)
|
||||
string(REGEX REPLACE "#define BLOSC_VERSION_MINOR +([0-9]+).*$" "\\1"
|
||||
_blosc_version_minor_string "${_blosc_version_minor_string}"
|
||||
)
|
||||
string(STRIP "${_blosc_version_minor_string}" Blosc_VERSION_MINOR)
|
||||
|
||||
file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h"
|
||||
_blosc_version_release_string REGEX "#define BLOSC_VERSION_RELEASE +[0-9]+ "
|
||||
)
|
||||
string(REGEX REPLACE "#define BLOSC_VERSION_RELEASE +([0-9]+).*$" "\\1"
|
||||
_blosc_version_release_string "${_blosc_version_release_string}"
|
||||
)
|
||||
string(STRIP "${_blosc_version_release_string}" Blosc_VERSION_RELEASE)
|
||||
|
||||
unset(_blosc_version_major_string)
|
||||
unset(_blosc_version_minor_string)
|
||||
unset(_blosc_version_release_string)
|
||||
|
||||
set(Blosc_VERSION ${Blosc_VERSION_MAJOR}.${Blosc_VERSION_MINOR}.${Blosc_VERSION_RELEASE})
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for blosc lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_BLOSC_LIBRARYDIR_SEARCH_DIRS "")
|
||||
list(APPEND _BLOSC_LIBRARYDIR_SEARCH_DIRS
|
||||
${BLOSC_LIBRARYDIR}
|
||||
${_BLOSC_ROOT}
|
||||
${PC_Blosc_LIBRARY_DIRS}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Library suffix handling
|
||||
|
||||
set(_BLOSC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(MSVC)
|
||||
if(BLOSC_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
|
||||
endif()
|
||||
else()
|
||||
if(BLOSC_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(Blosc_LIB_COMPONENTS "")
|
||||
# NOTE: Search for debug version first (see vcpkg hack)
|
||||
list(APPEND BLOSC_BUILD_TYPES DEBUG RELEASE)
|
||||
|
||||
foreach(BUILD_TYPE ${BLOSC_BUILD_TYPES})
|
||||
set(_BLOSC_LIB_NAME blosc)
|
||||
|
||||
set(_BLOSC_CMAKE_IGNORE_PATH ${CMAKE_IGNORE_PATH})
|
||||
if(VCPKG_TOOLCHAIN)
|
||||
# Blosc is installed very strangely in VCPKG (debug/release libs have the
|
||||
# same name, static build uses external deps, dll doesn't) and blosc itself
|
||||
# comes with almost zero downstream CMake support for us to detect settings.
|
||||
# We should not support external package managers in our own modules like
|
||||
# this, but there doesn't seem to be a work around
|
||||
if(NOT DEFINED BLOSC_DEBUG_SUFFIX)
|
||||
set(BLOSC_DEBUG_SUFFIX "")
|
||||
endif()
|
||||
if(BUILD_TYPE STREQUAL RELEASE)
|
||||
if(EXISTS ${Blosc_LIBRARY_DEBUG})
|
||||
get_filename_component(_BLOSC_DEBUG_DIR ${Blosc_LIBRARY_DEBUG} DIRECTORY)
|
||||
list(APPEND CMAKE_IGNORE_PATH ${_BLOSC_DEBUG_DIR})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_TYPE STREQUAL DEBUG)
|
||||
if(NOT DEFINED BLOSC_DEBUG_SUFFIX)
|
||||
set(BLOSC_DEBUG_SUFFIX _d)
|
||||
endif()
|
||||
set(_BLOSC_LIB_NAME "${_BLOSC_LIB_NAME}${BLOSC_DEBUG_SUFFIX}")
|
||||
endif()
|
||||
|
||||
find_library(Blosc_LIBRARY_${BUILD_TYPE} ${_BLOSC_LIB_NAME}
|
||||
${_FIND_BLOSC_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_BLOSC_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
|
||||
)
|
||||
|
||||
list(APPEND Blosc_LIB_COMPONENTS ${Blosc_LIBRARY_${BUILD_TYPE}})
|
||||
set(CMAKE_IGNORE_PATH ${_BLOSC_CMAKE_IGNORE_PATH})
|
||||
endforeach()
|
||||
|
||||
# Reset library suffix
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_BLOSC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_BLOSC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
|
||||
if(Blosc_LIBRARY_DEBUG AND Blosc_LIBRARY_RELEASE)
|
||||
# if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
|
||||
# single-config generators, set optimized and debug libraries
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(_isMultiConfig OR CMAKE_BUILD_TYPE)
|
||||
set(Blosc_LIBRARY optimized ${Blosc_LIBRARY_RELEASE} debug ${Blosc_LIBRARY_DEBUG})
|
||||
else()
|
||||
# For single-config generators where CMAKE_BUILD_TYPE has no value,
|
||||
# just use the release libraries
|
||||
set(Blosc_LIBRARY ${Blosc_LIBRARY_RELEASE})
|
||||
endif()
|
||||
# FIXME: This probably should be set for both cases
|
||||
set(Blosc_LIBRARIES optimized ${Blosc_LIBRARY_RELEASE} debug ${Blosc_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# if only the release version was found, set the debug variable also to the release version
|
||||
if(Blosc_LIBRARY_RELEASE AND NOT Blosc_LIBRARY_DEBUG)
|
||||
set(Blosc_LIBRARY_DEBUG ${Blosc_LIBRARY_RELEASE})
|
||||
set(Blosc_LIBRARY ${Blosc_LIBRARY_RELEASE})
|
||||
set(Blosc_LIBRARIES ${Blosc_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
||||
# if only the debug version was found, set the release variable also to the debug version
|
||||
if(Blosc_LIBRARY_DEBUG AND NOT Blosc_LIBRARY_RELEASE)
|
||||
set(Blosc_LIBRARY_RELEASE ${Blosc_LIBRARY_DEBUG})
|
||||
set(Blosc_LIBRARY ${Blosc_LIBRARY_DEBUG})
|
||||
set(Blosc_LIBRARIES ${Blosc_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# If the debug & release library ends up being the same, omit the keywords
|
||||
if("${Blosc_LIBRARY_RELEASE}" STREQUAL "${Blosc_LIBRARY_DEBUG}")
|
||||
set(Blosc_LIBRARY ${Blosc_LIBRARY_RELEASE} )
|
||||
set(Blosc_LIBRARIES ${Blosc_LIBRARY_RELEASE} )
|
||||
endif()
|
||||
|
||||
if(Blosc_LIBRARY)
|
||||
set(Blosc_FOUND TRUE)
|
||||
else()
|
||||
set(Blosc_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set Blosc_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Blosc
|
||||
FOUND_VAR Blosc_FOUND
|
||||
REQUIRED_VARS
|
||||
Blosc_LIBRARY
|
||||
Blosc_INCLUDE_DIR
|
||||
VERSION_VAR Blosc_VERSION
|
||||
)
|
||||
|
||||
if(NOT Blosc_FOUND)
|
||||
if(Blosc_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find Blosc")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Partition release/debug lib vars
|
||||
|
||||
set(Blosc_RELEASE_LIBRARIES ${Blosc_LIBRARY_RELEASE})
|
||||
get_filename_component(Blosc_RELEASE_LIBRARY_DIRS ${Blosc_RELEASE_LIBRARIES} DIRECTORY)
|
||||
set(Blosc_DEBUG_LIBRARIES ${Blosc_LIBRARY_DEBUG})
|
||||
get_filename_component(Blosc_DEBUG_LIBRARY_DIRS ${Blosc_DEBUG_LIBRARIES} DIRECTORY)
|
||||
set(Blosc_LIBRARIES ${Blosc_RELEASE_LIBRARIES})
|
||||
set(Blosc_LIBRARY_DIRS ${Blosc_RELEASE_LIBRARY_DIRS})
|
||||
set(Blosc_INCLUDE_DIRS ${Blosc_INCLUDE_DIR})
|
||||
set(Blosc_INCLUDE_DIRS ${Blosc_INCLUDE_DIR})
|
||||
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(BLOSC_LIB_TYPE UNKNOWN)
|
||||
if(BLOSC_USE_STATIC_LIBS)
|
||||
set(BLOSC_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_BLOSC_EXT ${Blosc_LIBRARY_RELEASE} EXT)
|
||||
if(_BLOSC_EXT STREQUAL ".a")
|
||||
set(BLOSC_LIB_TYPE STATIC)
|
||||
elseif(_BLOSC_EXT STREQUAL ".so" OR
|
||||
_BLOSC_EXT STREQUAL ".dylib")
|
||||
set(BLOSC_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_filename_component(Blosc_LIBRARY_DIRS ${Blosc_LIBRARY_RELEASE} DIRECTORY)
|
||||
|
||||
if(NOT TARGET Blosc::blosc)
|
||||
add_library(Blosc::blosc ${BLOSC_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(Blosc::blosc PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_Blosc_CFLAGS_OTHER}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Blosc_INCLUDE_DIRS}")
|
||||
|
||||
# Standard location
|
||||
set_target_properties(Blosc::blosc PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${Blosc_LIBRARY}")
|
||||
|
||||
# Release location
|
||||
if(EXISTS "${Blosc_LIBRARY_RELEASE}")
|
||||
set_property(TARGET Blosc::blosc APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(Blosc::blosc PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
|
||||
IMPORTED_LOCATION_RELEASE "${Blosc_LIBRARY_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Debug location
|
||||
if(EXISTS "${Blosc_LIBRARY_DEBUG}")
|
||||
set_property(TARGET Blosc::blosc APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(Blosc::blosc PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
|
||||
IMPORTED_LOCATION_DEBUG "${Blosc_LIBRARY_DEBUG}")
|
||||
endif()
|
||||
|
||||
# Blosc may optionally be compiled with external sources for
|
||||
# lz4, snappy and zlib . Add them as interface libs if requested
|
||||
# (there doesn't seem to be a way to figure this out automatically).
|
||||
# We assume they live along side blosc
|
||||
if(BLOSC_USE_EXTERNAL_SOURCES)
|
||||
set_target_properties(Blosc::blosc PROPERTIES
|
||||
INTERFACE_LINK_DIRECTORIES
|
||||
"\$<\$<CONFIG:Release>:${Blosc_RELEASE_LIBRARY_DIRS}>;\$<\$<CONFIG:Debug>:${Blosc_DEBUG_LIBRARY_DIRS}>")
|
||||
target_link_libraries(Blosc::blosc INTERFACE
|
||||
$<$<CONFIG:Release>:lz4;snappy;zlib;zstd>
|
||||
$<$<CONFIG:Debug>:lz4d;snappyd;zlibd;zstd>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindCppUnit
|
||||
-----------
|
||||
|
||||
Find CppUnit include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(CppUnit
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if CppUnit is not found
|
||||
)
|
||||
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``CppUnit::cppunit``
|
||||
This module defines IMPORTED target CppUnit::cppunit, if CppUnit has been
|
||||
found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``CppUnit_FOUND``
|
||||
True if the system has the CppUnit library.
|
||||
``CppUnit_VERSION``
|
||||
The version of the CppUnit library which was found.
|
||||
``CppUnit_INCLUDE_DIRS``
|
||||
Include directories needed to use CppUnit.
|
||||
``CppUnit_RELEASE_LIBRARIES``
|
||||
Libraries needed to link to the release version of CppUnit.
|
||||
``CppUnit_RELEASE_LIBRARY_DIRS``
|
||||
CppUnit release library directories.
|
||||
``CppUnit_DEBUG_LIBRARIES``
|
||||
Libraries needed to link to the debug version of CppUnit.
|
||||
``CppUnit_DEBUG_LIBRARY_DIRS``
|
||||
CppUnit debug library directories.
|
||||
|
||||
Deprecated - use [RELEASE|DEBUG] variants:
|
||||
|
||||
``CppUnit_LIBRARIES``
|
||||
Libraries needed to link to CppUnit.
|
||||
``CppUnit_LIBRARY_DIRS``
|
||||
CppUnit library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``CppUnit_INCLUDE_DIR``
|
||||
The directory containing ``cppunit/Portability.h``.
|
||||
``CppUnit_LIBRARY``
|
||||
The path to the CppUnit library.
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``CppUnit_ROOT``
|
||||
Preferred installation prefix.
|
||||
``CPPUNIT_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``CPPUNIT_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``CPPUNIT_DEBUG_SUFFIX``
|
||||
Suffix of the debug version of CppUnit libs. Defaults to "_d".
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``CPPUNIT_USE_STATIC_LIBS``
|
||||
Only search for static cppunit libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
mark_as_advanced(
|
||||
CppUnit_INCLUDE_DIR
|
||||
CppUnit_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_CPPUNIT_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_CPPUNIT_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
# Set _CPPUNIT_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV CPPUNIT_ROOT from CMake 3.12
|
||||
if(CppUnit_ROOT)
|
||||
set(_CPPUNIT_ROOT ${CppUnit_ROOT})
|
||||
elseif(DEFINED ENV{CppUnit_ROOT})
|
||||
set(_CPPUNIT_ROOT $ENV{CppUnit_ROOT})
|
||||
elseif(CPPUNIT_ROOT)
|
||||
set(_CPPUNIT_ROOT ${CPPUNIT_ROOT})
|
||||
elseif(DEFINED ENV{CPPUNIT_ROOT})
|
||||
set(_CPPUNIT_ROOT $ENV{CPPUNIT_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find cppunit
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
pkg_check_modules(PC_CppUnit QUIET cppunit)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for CppUnit include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_CPPUNIT_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _CPPUNIT_INCLUDE_SEARCH_DIRS
|
||||
${CPPUNIT_INCLUDEDIR}
|
||||
${_CPPUNIT_ROOT}
|
||||
${PC_CppUnit_INCLUDEDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Look for a standard cppunit header file.
|
||||
find_path(CppUnit_INCLUDE_DIR cppunit/Portability.h
|
||||
${_FIND_CPPUNIT_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_CPPUNIT_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include
|
||||
)
|
||||
|
||||
if(EXISTS "${CppUnit_INCLUDE_DIR}/cppunit/Portability.h")
|
||||
file(STRINGS "${CppUnit_INCLUDE_DIR}/cppunit/Portability.h"
|
||||
_cppunit_version_string REGEX "#define CPPUNIT_VERSION "
|
||||
)
|
||||
string(REGEX REPLACE "#define CPPUNIT_VERSION +\"(.+)\".*$" "\\1"
|
||||
_cppunit_version_string "${_cppunit_version_string}"
|
||||
)
|
||||
string(STRIP "${_cppunit_version_string}" CppUnit_VERSION)
|
||||
unset(_cppunit_version_string )
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for CppUnit lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(NOT DEFINED CPPUNIT_DEBUG_SUFFIX)
|
||||
set(CPPUNIT_DEBUG_SUFFIX "d")
|
||||
endif()
|
||||
|
||||
set(_CPPUNIT_LIBRARYDIR_SEARCH_DIRS "")
|
||||
list(APPEND _CPPUNIT_LIBRARYDIR_SEARCH_DIRS
|
||||
${CPPUNIT_LIBRARYDIR}
|
||||
${_CPPUNIT_ROOT}
|
||||
${PC_CppUnit_LIBDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Library suffix handling
|
||||
|
||||
set(_CPPUNIT_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(MSVC)
|
||||
if(CPPUNIT_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
|
||||
else()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_dll.lib")
|
||||
endif()
|
||||
else()
|
||||
if(CPPUNIT_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND CPPUNIT_BUILD_TYPES RELEASE DEBUG)
|
||||
|
||||
foreach(BUILD_TYPE ${CPPUNIT_BUILD_TYPES})
|
||||
set(_CPPUNIT_LIB_NAME cppunit)
|
||||
if(BUILD_TYPE STREQUAL DEBUG)
|
||||
set(_CPPUNIT_LIB_NAME "${_CPPUNIT_LIB_NAME}${CPPUNIT_DEBUG_SUFFIX}")
|
||||
endif()
|
||||
|
||||
# Find the lib
|
||||
find_library(CppUnit_LIBRARY_${BUILD_TYPE} ${_CPPUNIT_LIB_NAME}
|
||||
${_FIND_CPPUNIT_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_CPPUNIT_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# Reset library suffix
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_CPPUNIT_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_CPPUNIT_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
|
||||
if(CppUnit_LIBRARY_DEBUG AND CppUnit_LIBRARY_RELEASE)
|
||||
# if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
|
||||
# single-config generators, set optimized and debug libraries
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(_isMultiConfig OR CMAKE_BUILD_TYPE)
|
||||
set(CppUnit_LIBRARY optimized ${CppUnit_LIBRARY_RELEASE} debug ${CppUnit_LIBRARY_DEBUG})
|
||||
else()
|
||||
# For single-config generators where CMAKE_BUILD_TYPE has no value,
|
||||
# just use the release libraries
|
||||
set(CppUnit_LIBRARY ${CppUnit_LIBRARY_RELEASE})
|
||||
endif()
|
||||
# FIXME: This probably should be set for both cases
|
||||
set(CppUnit_LIBRARIES optimized ${CppUnit_LIBRARY_RELEASE} debug ${CppUnit_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# if only the release version was found, set the debug variable also to the release version
|
||||
if(CppUnit_LIBRARY_RELEASE AND NOT CppUnit_LIBRARY_DEBUG)
|
||||
set(CppUnit_LIBRARY_DEBUG ${CppUnit_LIBRARY_RELEASE})
|
||||
set(CppUnit_LIBRARY ${CppUnit_LIBRARY_RELEASE})
|
||||
set(CppUnit_LIBRARIES ${CppUnit_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
||||
# if only the debug version was found, set the release variable also to the debug version
|
||||
if(CppUnit_LIBRARY_DEBUG AND NOT CppUnit_LIBRARY_RELEASE)
|
||||
set(CppUnit_LIBRARY_RELEASE ${CppUnit_LIBRARY_DEBUG})
|
||||
set(CppUnit_LIBRARY ${CppUnit_LIBRARY_DEBUG})
|
||||
set(CppUnit_LIBRARIES ${CppUnit_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# If the debug & release library ends up being the same, omit the keywords
|
||||
if("${CppUnit_LIBRARY_RELEASE}" STREQUAL "${CppUnit_LIBRARY_DEBUG}")
|
||||
set(CppUnit_LIBRARY ${CppUnit_LIBRARY_RELEASE} )
|
||||
set(CppUnit_LIBRARIES ${CppUnit_LIBRARY_RELEASE} )
|
||||
endif()
|
||||
|
||||
if(CppUnit_LIBRARY)
|
||||
set(CppUnit_FOUND TRUE)
|
||||
else()
|
||||
set(CppUnit_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set CppUnit_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CppUnit
|
||||
FOUND_VAR CppUnit_FOUND
|
||||
REQUIRED_VARS
|
||||
CppUnit_LIBRARY
|
||||
CppUnit_INCLUDE_DIR
|
||||
VERSION_VAR CppUnit_VERSION
|
||||
)
|
||||
|
||||
if(NOT CppUnit_FOUND)
|
||||
if(CppUnit_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find CppUnit")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Partition release/debug lib vars
|
||||
|
||||
set(CppUnit_RELEASE_LIBRARIES ${CppUnit_LIBRARY_RELEASE})
|
||||
get_filename_component(CppUnit_RELEASE_LIBRARY_DIRS ${CppUnit_RELEASE_LIBRARIES} DIRECTORY)
|
||||
set(CppUnit_DEBUG_LIBRARIES ${CppUnit_LIBRARY_DEBUG})
|
||||
get_filename_component(CppUnit_DEBUG_LIBRARY_DIRS ${CppUnit_DEBUG_LIBRARIES} DIRECTORY)
|
||||
set(CppUnit_LIBRARIES ${CppUnit_RELEASE_LIBRARIES})
|
||||
set(CppUnit_LIBRARY_DIRS ${CppUnit_RELEASE_LIBRARY_DIRS})
|
||||
set(CppUnit_INCLUDE_DIRS ${CppUnit_INCLUDE_DIR})
|
||||
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(CPPUNIT_LIB_TYPE UNKNOWN)
|
||||
if(CPPUNIT_USE_STATIC_LIBS)
|
||||
set(CPPUNIT_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_CPPUNIT_EXT ${CppUnit_LIBRARY_RELEASE} EXT)
|
||||
if(_CPPUNIT_EXT STREQUAL ".a")
|
||||
set(CPPUNIT_LIB_TYPE STATIC)
|
||||
elseif(_CPPUNIT_EXT STREQUAL ".so" OR
|
||||
_CPPUNIT_EXT STREQUAL ".dylib")
|
||||
set(CPPUNIT_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET CppUnit::cppunit)
|
||||
add_library(CppUnit::cppunit ${CPPUNIT_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(CppUnit::cppunit PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_CppUnit_CFLAGS_OTHER}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CppUnit_INCLUDE_DIRS}")
|
||||
|
||||
# Standard location
|
||||
set_target_properties(CppUnit::cppunit PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${CppUnit_LIBRARY}")
|
||||
|
||||
# Release location
|
||||
if(EXISTS "${CppUnit_LIBRARY_RELEASE}")
|
||||
set_property(TARGET CppUnit::cppunit APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(CppUnit::cppunit PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
|
||||
IMPORTED_LOCATION_RELEASE "${CppUnit_LIBRARY_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Debug location
|
||||
if(EXISTS "${CppUnit_LIBRARY_DEBUG}")
|
||||
set_property(TARGET CppUnit::cppunit APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(CppUnit::cppunit PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
|
||||
IMPORTED_LOCATION_DEBUG "${CppUnit_LIBRARY_DEBUG}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,447 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindIlmBase
|
||||
-----------
|
||||
|
||||
Find IlmBase include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(IlmBase
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if IlmBase is not found
|
||||
[COMPONENTS <libs>...] # IlmBase libraries by their canonical name
|
||||
# e.g. "Half" for "libHalf"
|
||||
)
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``IlmBase::Half``
|
||||
The Half library target.
|
||||
``IlmBase::Iex``
|
||||
The Iex library target.
|
||||
``IlmBase::IexMath``
|
||||
The IexMath library target.
|
||||
``IlmBase::IlmThread``
|
||||
The IlmThread library target.
|
||||
``IlmBase::Imath``
|
||||
The Imath library target.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``IlmBase_FOUND``
|
||||
True if the system has the IlmBase library.
|
||||
``IlmBase_VERSION``
|
||||
The version of the IlmBase library which was found.
|
||||
``IlmBase_INCLUDE_DIRS``
|
||||
Include directories needed to use IlmBase.
|
||||
``IlmBase_RELEASE_LIBRARIES``
|
||||
Libraries needed to link to the release version of IlmBase.
|
||||
``IlmBase_RELEASE_LIBRARY_DIRS``
|
||||
IlmBase release library directories.
|
||||
``IlmBase_DEBUG_LIBRARIES``
|
||||
Libraries needed to link to the debug version of IlmBase.
|
||||
``IlmBase_DEBUG_LIBRARY_DIRS``
|
||||
IlmBase debug library directories.
|
||||
``IlmBase_{COMPONENT}_FOUND``
|
||||
True if the system has the named IlmBase component.
|
||||
|
||||
Deprecated - use [RELEASE|DEBUG] variants:
|
||||
|
||||
``IlmBase_LIBRARIES``
|
||||
Libraries needed to link to IlmBase.
|
||||
``IlmBase_LIBRARY_DIRS``
|
||||
IlmBase library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``IlmBase_INCLUDE_DIR``
|
||||
The directory containing ``IlmBase/config-auto.h``.
|
||||
``IlmBase_{COMPONENT}_LIBRARY``
|
||||
Individual component libraries for IlmBase. may include target_link_libraries() debug/optimized keywords.
|
||||
``IlmBase_{COMPONENT}_LIBRARY_RELEASE``
|
||||
Individual component libraries for IlmBase release
|
||||
``IlmBase_{COMPONENT}_LIBRARY_DEBUG``
|
||||
Individual component libraries for IlmBase debug
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``IlmBase_ROOT``
|
||||
Preferred installation prefix.
|
||||
``ILMBASE_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``ILMBASE_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``ILMBASE_DEBUG_SUFFIX``
|
||||
Suffix of the debug version of ilmbase libs. Defaults to "_d".
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``ILMBASE_USE_STATIC_LIBS``
|
||||
Only search for static ilmbase libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
mark_as_advanced(
|
||||
IlmBase_INCLUDE_DIR
|
||||
IlmBase_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_ILMBASE_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_ILMBASE_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
set(_ILMBASE_COMPONENT_LIST
|
||||
Half
|
||||
Iex
|
||||
IexMath
|
||||
IlmThread
|
||||
Imath
|
||||
)
|
||||
|
||||
if(IlmBase_FIND_COMPONENTS)
|
||||
set(ILMBASE_COMPONENTS_PROVIDED TRUE)
|
||||
set(_IGNORED_COMPONENTS "")
|
||||
foreach(COMPONENT ${IlmBase_FIND_COMPONENTS})
|
||||
if(NOT ${COMPONENT} IN_LIST _ILMBASE_COMPONENT_LIST)
|
||||
list(APPEND _IGNORED_COMPONENTS ${COMPONENT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_IGNORED_COMPONENTS)
|
||||
message(STATUS "Ignoring unknown components of IlmBase:")
|
||||
foreach(COMPONENT ${_IGNORED_COMPONENTS})
|
||||
message(STATUS " ${COMPONENT}")
|
||||
endforeach()
|
||||
list(REMOVE_ITEM IlmBase_FIND_COMPONENTS ${_IGNORED_COMPONENTS})
|
||||
endif()
|
||||
else()
|
||||
set(ILMBASE_COMPONENTS_PROVIDED FALSE)
|
||||
set(IlmBase_FIND_COMPONENTS ${_ILMBASE_COMPONENT_LIST})
|
||||
endif()
|
||||
|
||||
# Set _ILMBASE_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV ILMBASE_ROOT from CMake 3.12
|
||||
if(IlmBase_ROOT)
|
||||
set(_ILMBASE_ROOT ${IlmBase_ROOT})
|
||||
elseif(DEFINED ENV{IlmBase_ROOT})
|
||||
set(_ILMBASE_ROOT $ENV{IlmBase_ROOT})
|
||||
elseif(ILMBASE_ROOT)
|
||||
set(_ILMBASE_ROOT ${ILMBASE_ROOT})
|
||||
elseif(DEFINED ENV{ILMBASE_ROOT})
|
||||
set(_ILMBASE_ROOT $ENV{ILMBASE_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find IlmBase
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_IlmBase QUIET ilmbase)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for IlmBase include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_ILMBASE_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _ILMBASE_INCLUDE_SEARCH_DIRS
|
||||
${ILMBASE_INCLUDEDIR}
|
||||
${_ILMBASE_ROOT}
|
||||
${PC_IlmBase_INCLUDEDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Look for a standard IlmBase header file.
|
||||
find_path(IlmBase_INCLUDE_DIR IlmBaseConfig.h
|
||||
${_FIND_ILMBASE_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_ILMBASE_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/OpenEXR include/OpenEXR OpenEXR
|
||||
)
|
||||
|
||||
if(EXISTS "${IlmBase_INCLUDE_DIR}/IlmBaseConfig.h")
|
||||
# Get the ILMBASE version information from the config header
|
||||
file(STRINGS "${IlmBase_INCLUDE_DIR}/IlmBaseConfig.h"
|
||||
_ilmbase_version_major_string REGEX "#define ILMBASE_VERSION_MAJOR "
|
||||
)
|
||||
string(REGEX REPLACE "#define ILMBASE_VERSION_MAJOR" ""
|
||||
_ilmbase_version_major_string "${_ilmbase_version_major_string}"
|
||||
)
|
||||
string(STRIP "${_ilmbase_version_major_string}" IlmBase_VERSION_MAJOR)
|
||||
|
||||
file(STRINGS "${IlmBase_INCLUDE_DIR}/IlmBaseConfig.h"
|
||||
_ilmbase_version_minor_string REGEX "#define ILMBASE_VERSION_MINOR "
|
||||
)
|
||||
string(REGEX REPLACE "#define ILMBASE_VERSION_MINOR" ""
|
||||
_ilmbase_version_minor_string "${_ilmbase_version_minor_string}"
|
||||
)
|
||||
string(STRIP "${_ilmbase_version_minor_string}" IlmBase_VERSION_MINOR)
|
||||
|
||||
unset(_ilmbase_version_major_string)
|
||||
unset(_ilmbase_version_minor_string)
|
||||
|
||||
set(IlmBase_VERSION ${IlmBase_VERSION_MAJOR}.${IlmBase_VERSION_MINOR})
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for ILMBASE lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(NOT DEFINED ILMBASE_DEBUG_SUFFIX)
|
||||
set(ILMBASE_DEBUG_SUFFIX _d)
|
||||
endif()
|
||||
|
||||
set(_ILMBASE_LIBRARYDIR_SEARCH_DIRS "")
|
||||
|
||||
# Append to _ILMBASE_LIBRARYDIR_SEARCH_DIRS in priority order
|
||||
|
||||
list(APPEND _ILMBASE_LIBRARYDIR_SEARCH_DIRS
|
||||
${ILMBASE_LIBRARYDIR}
|
||||
${_ILMBASE_ROOT}
|
||||
${PC_IlmBase_LIBDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
set(IlmBase_LIB_COMPONENTS "")
|
||||
list(APPEND ILM_BUILD_TYPES RELEASE DEBUG)
|
||||
|
||||
foreach(COMPONENT ${IlmBase_FIND_COMPONENTS})
|
||||
foreach(BUILD_TYPE ${ILM_BUILD_TYPES})
|
||||
|
||||
set(_TMP_SUFFIX "")
|
||||
if(BUILD_TYPE STREQUAL DEBUG)
|
||||
set(_TMP_SUFFIX ${ILMBASE_DEBUG_SUFFIX})
|
||||
endif()
|
||||
|
||||
set(_IlmBase_Version_Suffix "-${IlmBase_VERSION_MAJOR}_${IlmBase_VERSION_MINOR}")
|
||||
set(_ILMBASE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(WIN32)
|
||||
if(ILMBASE_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.lib")
|
||||
endif()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_IlmBase_Version_Suffix}${_TMP_SUFFIX}.lib")
|
||||
else()
|
||||
if(ILMBASE_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.a")
|
||||
else()
|
||||
if(APPLE)
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_IlmBase_Version_Suffix}${_TMP_SUFFIX}.dylib")
|
||||
else()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_IlmBase_Version_Suffix}${_TMP_SUFFIX}.so")
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_IlmBase_Version_Suffix}${_TMP_SUFFIX}.a")
|
||||
endif()
|
||||
|
||||
# Find the lib
|
||||
find_library(IlmBase_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${COMPONENT}
|
||||
${_FIND_ILMBASE_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_ILMBASE_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
|
||||
)
|
||||
|
||||
if(EXISTS ${IlmBase_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
list(APPEND IlmBase_LIB_COMPONENTS ${IlmBase_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
list(APPEND IlmBase_LIB_COMPONENTS_${BUILD_TYPE} ${IlmBase_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
endif()
|
||||
|
||||
# Reset library suffix
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ILMBASE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_ILMBASE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
unset(_IlmBase_Version_Suffix)
|
||||
unset(_TMP_SUFFIX)
|
||||
endforeach()
|
||||
|
||||
if(IlmBase_${COMPONENT}_LIBRARY_DEBUG AND IlmBase_${COMPONENT}_LIBRARY_RELEASE)
|
||||
# if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
|
||||
# single-config generators, set optimized and debug libraries
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(_isMultiConfig OR CMAKE_BUILD_TYPE)
|
||||
set(IlmBase_${COMPONENT}_LIBRARY optimized ${IlmBase_${COMPONENT}_LIBRARY_RELEASE} debug ${IlmBase_${COMPONENT}_LIBRARY_DEBUG})
|
||||
else()
|
||||
# For single-config generators where CMAKE_BUILD_TYPE has no value,
|
||||
# just use the release libraries
|
||||
set(IlmBase_${COMPONENT}_LIBRARY ${IlmBase_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif()
|
||||
# FIXME: This probably should be set for both cases
|
||||
set(IlmBase_${COMPONENT}_LIBRARIES optimized ${IlmBase_${COMPONENT}_LIBRARY_RELEASE} debug ${IlmBase_${COMPONENT}_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# if only the release version was found, set the debug variable also to the release version
|
||||
if(IlmBase_${COMPONENT}_LIBRARY_RELEASE AND NOT IlmBase_${COMPONENT}_LIBRARY_DEBUG)
|
||||
set(IlmBase_${COMPONENT}_LIBRARY_DEBUG ${IlmBase_${COMPONENT}_LIBRARY_RELEASE})
|
||||
set(IlmBase_${COMPONENT}_LIBRARY ${IlmBase_${COMPONENT}_LIBRARY_RELEASE})
|
||||
set(IlmBase_${COMPONENT}_LIBRARIES ${IlmBase_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
||||
# if only the debug version was found, set the release variable also to the debug version
|
||||
if(IlmBase_${COMPONENT}_LIBRARY_DEBUG AND NOT IlmBase_${COMPONENT}_LIBRARY_RELEASE)
|
||||
set(IlmBase_${COMPONENT}_LIBRARY_RELEASE ${IlmBase_${COMPONENT}_LIBRARY_DEBUG})
|
||||
set(IlmBase_${COMPONENT}_LIBRARY ${IlmBase_${COMPONENT}_LIBRARY_DEBUG})
|
||||
set(IlmBase_${COMPONENT}_LIBRARIES ${IlmBase_${COMPONENT}_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# If the debug & release library ends up being the same, omit the keywords
|
||||
if("${IlmBase_${COMPONENT}_LIBRARY_RELEASE}" STREQUAL "${IlmBase_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
set(IlmBase_${COMPONENT}_LIBRARY ${IlmBase_${COMPONENT}_LIBRARY_RELEASE} )
|
||||
set(IlmBase_${COMPONENT}_LIBRARIES ${IlmBase_${COMPONENT}_LIBRARY_RELEASE} )
|
||||
endif()
|
||||
|
||||
if(IlmBase_${COMPONENT}_LIBRARY)
|
||||
set(IlmBase_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(IlmBase_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set ILMBASE_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(IlmBase
|
||||
FOUND_VAR IlmBase_FOUND
|
||||
REQUIRED_VARS
|
||||
IlmBase_INCLUDE_DIR
|
||||
IlmBase_LIB_COMPONENTS
|
||||
VERSION_VAR IlmBase_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
if(NOT IlmBase_FOUND)
|
||||
if(IlmBase_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find IlmBase")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Partition release/debug lib vars
|
||||
|
||||
set(IlmBase_RELEASE_LIBRARIES "")
|
||||
set(IlmBase_RELEASE_LIBRARY_DIRS "")
|
||||
set(IlmBase_DEBUG_LIBRARIES "")
|
||||
set(IlmBase_DEBUG_LIBRARY_DIRS "")
|
||||
foreach(LIB ${IlmBase_LIB_COMPONENTS_RELEASE})
|
||||
get_filename_component(_ILM_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND IlmBase_RELEASE_LIBRARIES ${LIB})
|
||||
list(APPEND IlmBase_RELEASE_LIBRARY_DIRS ${_ILM_LIBDIR})
|
||||
endforeach()
|
||||
|
||||
foreach(LIB ${IlmBase_LIB_COMPONENTS_DEBUG})
|
||||
get_filename_component(_ILM_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND IlmBase_DEBUG_LIBRARIES ${LIB})
|
||||
list(APPEND IlmBase_DEBUG_LIBRARY_DIRS ${_ILM_LIBDIR})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES IlmBase_RELEASE_LIBRARY_DIRS)
|
||||
list(REMOVE_DUPLICATES IlmBase_DEBUG_LIBRARY_DIRS)
|
||||
|
||||
set(IlmBase_LIBRARIES ${IlmBase_RELEASE_LIBRARIES})
|
||||
set(IlmBase_LIBRARY_DIRS ${IlmBase_RELEASE_LIBRARY_DIRS})
|
||||
|
||||
# We have to add both include and include/OpenEXR to the include
|
||||
# path in case OpenEXR and IlmBase are installed separately.
|
||||
#
|
||||
# Make sure we get the absolute path to avoid issues where
|
||||
# /usr/include/OpenEXR/../ is picked up and passed to gcc from cmake
|
||||
# which won't correctly compute /usr/include as an implicit system
|
||||
# dir if the path is relative:
|
||||
#
|
||||
# https://github.com/AcademySoftwareFoundation/openvdb/issues/632
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129
|
||||
|
||||
set(_IlmBase_Parent_Dir "")
|
||||
get_filename_component(_IlmBase_Parent_Dir
|
||||
${IlmBase_INCLUDE_DIR}/../ ABSOLUTE)
|
||||
|
||||
set(IlmBase_INCLUDE_DIRS)
|
||||
list(APPEND IlmBase_INCLUDE_DIRS
|
||||
${_IlmBase_Parent_Dir}
|
||||
${IlmBase_INCLUDE_DIR}
|
||||
)
|
||||
unset(_IlmBase_Parent_Dir)
|
||||
|
||||
# Configure imported targets
|
||||
|
||||
foreach(COMPONENT ${IlmBase_FIND_COMPONENTS})
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(ILMBASE_${COMPONENT}_LIB_TYPE UNKNOWN)
|
||||
if(ILMBASE_USE_STATIC_LIBS)
|
||||
set(ILMBASE_${COMPONENT}_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_ILMBASE_${COMPONENT}_EXT ${IlmBase_${COMPONENT}_LIBRARY_RELEASE} EXT)
|
||||
if(${_ILMBASE_${COMPONENT}_EXT} STREQUAL ".a")
|
||||
set(ILMBASE_${COMPONENT}_LIB_TYPE STATIC)
|
||||
elseif(${_ILMBASE_${COMPONENT}_EXT} STREQUAL ".so" OR
|
||||
${_ILMBASE_${COMPONENT}_EXT} STREQUAL ".dylib")
|
||||
set(ILMBASE_${COMPONENT}_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IlmBase_${COMPONENT}_DEFINITIONS)
|
||||
|
||||
# Add the OPENEXR_DLL define if the library is not static on WIN32
|
||||
if(WIN32)
|
||||
if(NOT ILMBASE_${COMPONENT}_LIB_TYPE STREQUAL STATIC)
|
||||
list(APPEND IlmBase_${COMPONENT}_DEFINITIONS OPENEXR_DLL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET IlmBase::${COMPONENT})
|
||||
add_library(IlmBase::${COMPONENT} ${ILMBASE_${COMPONENT}_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(IlmBase::${COMPONENT} PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_IlmBase_CFLAGS_OTHER}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "${IlmBase_${COMPONENT}_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${IlmBase_INCLUDE_DIRS}")
|
||||
|
||||
# Standard location
|
||||
set_target_properties(IlmBase::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${IlmBase_${COMPONENT}_LIBRARY}")
|
||||
|
||||
# Release location
|
||||
if(EXISTS "${IlmBase_${COMPONENT}_LIBRARY_RELEASE}")
|
||||
set_property(TARGET IlmBase::${COMPONENT} APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(IlmBase::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
|
||||
IMPORTED_LOCATION_RELEASE "${IlmBase_${COMPONENT}_LIBRARY_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Debug location
|
||||
if(EXISTS "${IlmBase_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
set_property(TARGET IlmBase::${COMPONENT} APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(IlmBase::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
|
||||
IMPORTED_LOCATION_DEBUG "${IlmBase_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -0,0 +1,190 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindJemalloc
|
||||
-----------
|
||||
|
||||
Find Jemalloc include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(Jemalloc
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if Jemalloc is not found
|
||||
)
|
||||
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``Jemalloc::jemalloc``
|
||||
This module defines IMPORTED target Jemalloc::jemalloc, if Jemalloc has been
|
||||
found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``Jemalloc_FOUND``
|
||||
True if the system has the Jemalloc library.
|
||||
``Jemalloc_VERSION``
|
||||
The version of the Jemalloc library which was found.
|
||||
``Jemalloc_LIBRARIES``
|
||||
Libraries needed to link to Jemalloc.
|
||||
``Jemalloc_LIBRARY_DIRS``
|
||||
Jemalloc library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``Jemalloc_LIBRARY``
|
||||
The path to the Jemalloc library.
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``Jemalloc_ROOT``
|
||||
Preferred installation prefix.
|
||||
``JEMALLOC_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``JEMALLOC_USE_STATIC_LIBS``
|
||||
Only search for static jemalloc libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
mark_as_advanced(
|
||||
Jemalloc_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_JEMALLOC_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_JEMALLOC_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
# Set _JEMALLOC_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV JEMALLOC_ROOT from CMake 3.12
|
||||
if(Jemalloc_ROOT)
|
||||
set(_JEMALLOC_ROOT ${Jemalloc_ROOT})
|
||||
elseif(DEFINED ENV{Jemalloc_ROOT})
|
||||
set(_JEMALLOC_ROOT $ENV{Jemalloc_ROOT})
|
||||
elseif(JEMALLOC_ROOT)
|
||||
set(_JEMALLOC_ROOT ${JEMALLOC_ROOT})
|
||||
elseif(DEFINED ENV{JEMALLOC_ROOT})
|
||||
set(_JEMALLOC_ROOT $ENV{JEMALLOC_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find jemalloc
|
||||
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
pkg_check_modules(PC_Jemalloc QUIET jemalloc)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for Jemalloc lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_JEMALLOC_LIBRARYDIR_SEARCH_DIRS "")
|
||||
list(APPEND _JEMALLOC_LIBRARYDIR_SEARCH_DIRS
|
||||
${JEMALLOC_LIBRARYDIR}
|
||||
${_JEMALLOC_ROOT}
|
||||
${PC_Jemalloc_LIBDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Library suffix handling
|
||||
|
||||
set(_JEMALLOC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(MSVC)
|
||||
if(JEMALLOC_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
|
||||
else()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_dll.lib")
|
||||
endif()
|
||||
else()
|
||||
if(JEMALLOC_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build suffix directories
|
||||
|
||||
set(JEMALLOC_PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
lib64
|
||||
lib
|
||||
)
|
||||
|
||||
find_library(Jemalloc_LIBRARY jemalloc
|
||||
${_FIND_JEMALLOC_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_JEMALLOC_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${JEMALLOC_PATH_SUFFIXES}
|
||||
)
|
||||
|
||||
# Reset library suffix
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_JEMALLOC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_JEMALLOC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set Jemalloc_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Jemalloc
|
||||
FOUND_VAR Jemalloc_FOUND
|
||||
REQUIRED_VARS
|
||||
Jemalloc_LIBRARY
|
||||
VERSION_VAR Jemalloc_VERSION
|
||||
)
|
||||
|
||||
if(Jemalloc_FOUND)
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(JEMALLOC_LIB_TYPE UNKNOWN)
|
||||
if(JEMALLOC_USE_STATIC_LIBS)
|
||||
set(JEMALLOC_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_JEMALLOC_EXT ${Jemalloc_LIBRARY} EXT)
|
||||
if(_JEMALLOC_EXT STREQUAL ".a")
|
||||
set(JEMALLOC_LIB_TYPE STATIC)
|
||||
elseif(_JEMALLOC_EXT STREQUAL ".so" OR
|
||||
_JEMALLOC_EXT STREQUAL ".dylib")
|
||||
set(JEMALLOC_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(Jemalloc_LIBRARIES ${Jemalloc_LIBRARY})
|
||||
|
||||
get_filename_component(Jemalloc_LIBRARY_DIRS ${Jemalloc_LIBRARY} DIRECTORY)
|
||||
|
||||
if(NOT TARGET Jemalloc::jemalloc)
|
||||
add_library(Jemalloc::jemalloc ${JEMALLOC_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(Jemalloc::jemalloc PROPERTIES
|
||||
IMPORTED_LOCATION "${Jemalloc_LIBRARIES}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_Jemalloc_CFLAGS_OTHER}"
|
||||
)
|
||||
endif()
|
||||
elseif(Jemalloc_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find Jemalloc")
|
||||
endif()
|
||||
@@ -0,0 +1,344 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindLog4cplus
|
||||
-------------
|
||||
|
||||
Find Log4cplus include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(Log4cplus
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if Log4cplus is not found
|
||||
)
|
||||
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``Log4cplus::Log4cplus``
|
||||
This module defines IMPORTED target Log4cplus::log4cplus, if Log4cplus has been
|
||||
found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``Log4cplus_FOUND``
|
||||
True if the system has the Log4cplus library.
|
||||
``Log4cplus_VERSION``
|
||||
The version of the Log4cplus library which was found.
|
||||
``Log4cplus_INCLUDE_DIRS``
|
||||
Include directories needed to use Log4cplus.
|
||||
``Log4cplus_RELEASE_LIBRARIES``
|
||||
Libraries needed to link to the release version of Log4cplus.
|
||||
``Log4cplus_RELEASE_LIBRARY_DIRS``
|
||||
Log4cplus release library directories.
|
||||
``Log4cplus_DEBUG_LIBRARIES``
|
||||
Libraries needed to link to the debug version of Log4cplus.
|
||||
``Log4cplus_DEBUG_LIBRARY_DIRS``
|
||||
Log4cplus debug library directories.
|
||||
|
||||
Deprecated - use [RELEASE|DEBUG] variants:
|
||||
|
||||
``Log4cplus_LIBRARIES``
|
||||
Libraries needed to link to Log4cplus.
|
||||
``Log4cplus_LIBRARY_DIRS``
|
||||
Log4cplus library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``Log4cplus_INCLUDE_DIR``
|
||||
The directory containing ``log4cplus/version.h``.
|
||||
``Log4cplus_LIBRARY``
|
||||
The path to the Log4cplus library. may include target_link_libraries() debug/optimized keywords.
|
||||
``Log4cplus_LIBRARY_RELEASE``
|
||||
The path to the Log4cplus release library.
|
||||
``Log4cplus_LIBRARY_DEBUG``
|
||||
The path to the Log4cplus debug library.
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``Log4cplus_ROOT``
|
||||
Preferred installation prefix.
|
||||
``LOG4CPLUS_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``LOG4CPLUS_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``LOG4CPLUS_DEBUG_SUFFIX``
|
||||
Suffix of the debug version of the log4cplus lib. Defaults to "D".
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``LOG4CPLUS_USE_STATIC_LIBS``
|
||||
Only search for static log4cplus libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
mark_as_advanced(
|
||||
Log4cplus_INCLUDE_DIR
|
||||
Log4cplus_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
# Set _LOG4CPLUS_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV LOG4CPLUS_ROOT from CMake 3.12
|
||||
if(Log4cplus_ROOT)
|
||||
set(_LOG4CPLUS_ROOT ${Log4cplus_ROOT})
|
||||
elseif(DEFINED ENV{Log4cplus_ROOT})
|
||||
set(_LOG4CPLUS_ROOT $ENV{Log4cplus_ROOT})
|
||||
elseif(LOG4CPLUS_ROOT)
|
||||
set(_LOG4CPLUS_ROOT ${LOG4CPLUS_ROOT})
|
||||
elseif(DEFINED ENV{LOG4CPLUS_ROOT})
|
||||
set(_LOG4CPLUS_ROOT $ENV{LOG4CPLUS_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find log4cplus
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_Log4cplus QUIET log4cplus)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for Log4cplus include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_LOG4CPLUS_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _LOG4CPLUS_INCLUDE_SEARCH_DIRS
|
||||
${LOG4CPLUS_INCLUDEDIR}
|
||||
${_LOG4CPLUS_ROOT}
|
||||
${PC_Log4cplus_INCLUDEDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Look for a standard log4cplus header file.
|
||||
find_path(Log4cplus_INCLUDE_DIR log4cplus/version.h
|
||||
${_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_LOG4CPLUS_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include
|
||||
)
|
||||
|
||||
if(EXISTS "${Log4cplus_INCLUDE_DIR}/log4cplus/version.h")
|
||||
file(STRINGS "${Log4cplus_INCLUDE_DIR}/log4cplus/version.h"
|
||||
_log4cplus_version_string REGEX "#define LOG4CPLUS_VERSION LOG4CPLUS_MAKE_VERSION"
|
||||
)
|
||||
string(REGEX REPLACE "#define LOG4CPLUS_VERSION LOG4CPLUS_MAKE_VERSION\((.*)\).*$" "\\1"
|
||||
_log4cplus_version_string "${_log4cplus_version_string}"
|
||||
)
|
||||
string(REGEX REPLACE "[(]([0-9]+),.*[)].*$" "\\1"
|
||||
Log4cplus_MAJOR_VERSION "${_log4cplus_version_string}"
|
||||
)
|
||||
string(REGEX REPLACE "[(].+, ([0-9]+),.+[)].*$" "\\1"
|
||||
Log4cplus_MINOR_VERSION "${_log4cplus_version_string}"
|
||||
)
|
||||
string(REGEX REPLACE "[(].*,.*, ([0-9]+)[)].*$" "\\1"
|
||||
Log4cplus_PATCH_VERSION "${_log4cplus_version_string}"
|
||||
)
|
||||
unset(_log4cplus_version_string)
|
||||
|
||||
set(Log4cplus_VERSION ${Log4cplus_MAJOR_VERSION}.${Log4cplus_MINOR_VERSION}.${Log4cplus_PATCH_VERSION})
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for Log4cplus lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(NOT DEFINED LOG4CPLUS_DEBUG_SUFFIX)
|
||||
set(LOG4CPLUS_DEBUG_SUFFIX D)
|
||||
endif()
|
||||
|
||||
set(_LOG4CPLUS_LIBRARYDIR_SEARCH_DIRS "")
|
||||
list(APPEND _LOG4CPLUS_LIBRARYDIR_SEARCH_DIRS
|
||||
${LOG4CPLUS_LIBRARYDIR}
|
||||
${_LOG4CPLUS_ROOT}
|
||||
${PC_Log4cplus_LIBDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Library suffix handling
|
||||
|
||||
set(_LOG4CPLUS_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(MSVC)
|
||||
if(LOG4CPLUS_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
|
||||
endif()
|
||||
else()
|
||||
if(LOG4CPLUS_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(Log4cplus_LIB_COMPONENTS "")
|
||||
list(APPEND LOG4CPLUS_BUILD_TYPES RELEASE DEBUG)
|
||||
|
||||
foreach(BUILD_TYPE ${LOG4CPLUS_BUILD_TYPES})
|
||||
set(_LOG4CPLUS_LIB_NAME log4cplus)
|
||||
if(BUILD_TYPE STREQUAL DEBUG)
|
||||
set(_LOG4CPLUS_LIB_NAME "${_LOG4CPLUS_LIB_NAME}${LOG4CPLUS_DEBUG_SUFFIX}")
|
||||
endif()
|
||||
|
||||
find_library(Log4cplus_LIBRARY_${BUILD_TYPE} ${_LOG4CPLUS_LIB_NAME}
|
||||
${_FIND_LOG4CPLUS_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_LOG4CPLUS_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
|
||||
)
|
||||
|
||||
list(APPEND Log4cplus_LIB_COMPONENTS ${Log4cplus_LIBRARY_${BUILD_TYPE}})
|
||||
endforeach()
|
||||
|
||||
# Reset library suffix
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_LOG4CPLUS_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_LOG4CPLUS_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
|
||||
if(Log4cplus_LIBRARY_DEBUG AND Log4cplus_LIBRARY_RELEASE)
|
||||
# if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
|
||||
# single-config generators, set optimized and debug libraries
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(_isMultiConfig OR CMAKE_BUILD_TYPE)
|
||||
set(Log4cplus_LIBRARY optimized ${Log4cplus_LIBRARY_RELEASE} debug ${Log4cplus_LIBRARY_DEBUG})
|
||||
else()
|
||||
# For single-config generators where CMAKE_BUILD_TYPE has no value,
|
||||
# just use the release libraries
|
||||
set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_RELEASE})
|
||||
endif()
|
||||
# FIXME: This probably should be set for both cases
|
||||
set(Log4cplus_LIBRARIES optimized ${Log4cplus_LIBRARY_RELEASE} debug ${Log4cplus_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# if only the release version was found, set the debug variable also to the release version
|
||||
if(Log4cplus_LIBRARY_RELEASE AND NOT Log4cplus_LIBRARY_DEBUG)
|
||||
set(Log4cplus_LIBRARY_DEBUG ${Log4cplus_LIBRARY_RELEASE})
|
||||
set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_RELEASE})
|
||||
set(Log4cplus_LIBRARIES ${Log4cplus_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
||||
# if only the debug version was found, set the release variable also to the debug version
|
||||
if(Log4cplus_LIBRARY_DEBUG AND NOT Log4cplus_LIBRARY_RELEASE)
|
||||
set(Log4cplus_LIBRARY_RELEASE ${Log4cplus_LIBRARY_DEBUG})
|
||||
set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_DEBUG})
|
||||
set(Log4cplus_LIBRARIES ${Log4cplus_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# If the debug & release library ends up being the same, omit the keywords
|
||||
if("${Log4cplus_LIBRARY_RELEASE}" STREQUAL "${Log4cplus_LIBRARY_DEBUG}")
|
||||
set(Log4cplus_LIBRARY ${Log4cplus_LIBRARY_RELEASE} )
|
||||
set(Log4cplus_LIBRARIES ${Log4cplus_LIBRARY_RELEASE} )
|
||||
endif()
|
||||
|
||||
if(Log4cplus_LIBRARY)
|
||||
set(Log4cplus_FOUND TRUE)
|
||||
else()
|
||||
set(Log4cplus_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set Log4cplus_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Log4cplus
|
||||
FOUND_VAR Log4cplus_FOUND
|
||||
REQUIRED_VARS
|
||||
Log4cplus_LIBRARY
|
||||
Log4cplus_INCLUDE_DIR
|
||||
VERSION_VAR Log4cplus_VERSION
|
||||
)
|
||||
|
||||
if(NOT Log4cplus_FOUND)
|
||||
if(Log4cplus_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find Log4cplus")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Partition release/debug lib vars
|
||||
|
||||
set(Log4cplus_RELEASE_LIBRARIES ${Log4cplus_LIBRARY_RELEASE})
|
||||
get_filename_component(Log4cplus_RELEASE_LIBRARY_DIRS ${Log4cplus_RELEASE_LIBRARIES} DIRECTORY)
|
||||
set(Log4cplus_DEBUG_LIBRARIES ${Log4cplus_LIBRARY_DEBUG})
|
||||
get_filename_component(Log4cplus_DEBUG_LIBRARY_DIRS ${Log4cplus_DEBUG_LIBRARIES} DIRECTORY)
|
||||
set(Log4cplus_LIBRARIES ${Log4cplus_RELEASE_LIBRARIES})
|
||||
set(Log4cplus_LIBRARY_DIRS ${Log4cplus_RELEASE_LIBRARY_DIRS})
|
||||
set(Log4cplus_INCLUDE_DIRS ${Log4cplus_INCLUDE_DIR})
|
||||
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(LOG4CPLUS_LIB_TYPE UNKNOWN)
|
||||
if(LOG4CPLUS_USE_STATIC_LIBS)
|
||||
set(LOG4CPLUS_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_LOG4CPLUS_EXT ${Log4cplus_LIBRARY} EXT)
|
||||
if(_LOG4CPLUS_EXT STREQUAL ".a")
|
||||
set(LOG4CPLUS_LIB_TYPE STATIC)
|
||||
elseif(_LOG4CPLUS_EXT STREQUAL ".so" OR
|
||||
_LOG4CPLUS_EXT STREQUAL ".dylib")
|
||||
set(LOG4CPLUS_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_filename_component(Log4cplus_LIBRARY_DIRS ${Log4cplus_LIBRARY_RELEASE} DIRECTORY)
|
||||
|
||||
if(NOT TARGET Log4cplus::log4cplus)
|
||||
add_library(Log4cplus::log4cplus ${LOG4CPLUS_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(Log4cplus::log4cplus PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_Log4cplus_CFLAGS_OTHER}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Log4cplus_INCLUDE_DIRS}")
|
||||
|
||||
# Standard location
|
||||
set_target_properties(Log4cplus::log4cplus PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX;RC"
|
||||
IMPORTED_LOCATION "${Log4cplus_LIBRARY}")
|
||||
|
||||
# WIN32 APIs
|
||||
if(WIN32)
|
||||
set_target_properties(Log4cplus::log4cplus PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LIBRARIES "ws2_32;advapi32")
|
||||
endif()
|
||||
|
||||
# Release location
|
||||
if(EXISTS "${Log4cplus_LIBRARY_RELEASE}")
|
||||
set_property(TARGET Log4cplus::log4cplus APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(Log4cplus::log4cplus PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX;RC"
|
||||
IMPORTED_LOCATION_RELEASE "${Log4cplus_LIBRARY_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Debug location
|
||||
if(EXISTS "${Log4cplus_LIBRARY_DEBUG}")
|
||||
set_property(TARGET Log4cplus::log4cplus APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(Log4cplus::log4cplus PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX;RC"
|
||||
IMPORTED_LOCATION_DEBUG "${Log4cplus_LIBRARY_DEBUG}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,442 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindOpenEXR
|
||||
-----------
|
||||
|
||||
Find OpenEXR include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(OpenEXR
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if OpenEXR is not found
|
||||
[COMPONENTS <libs>...] # OpenEXR libraries by their canonical name
|
||||
# e.g. "IlmImf" for "libIlmImf"
|
||||
)
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``OpenEXR::IlmImf``
|
||||
The IlmImf library target.
|
||||
``OpenEXR::IlmImfUtil``
|
||||
The IlmImfUtil library target.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``OpenEXR_FOUND``
|
||||
True if the system has the OpenEXR library.
|
||||
``OpenEXR_VERSION``
|
||||
The version of the OpenEXR library which was found.
|
||||
``OpenEXR_INCLUDE_DIRS``
|
||||
Include directories needed to use OpenEXR.
|
||||
``OpenEXR_RELEASE_LIBRARIES``
|
||||
Libraries needed to link to the release version of OpenEXR.
|
||||
``OpenEXR_RELEASE_LIBRARY_DIRS``
|
||||
OpenEXR release library directories.
|
||||
``OpenEXR_DEBUG_LIBRARIES``
|
||||
Libraries needed to link to the debug version of OpenEXR.
|
||||
``OpenEXR_DEBUG_LIBRARY_DIRS``
|
||||
OpenEXR debug library directories.
|
||||
``OpenEXR_DEFINITIONS``
|
||||
Definitions to use when compiling code that uses OpenEXR.
|
||||
``OpenEXR_{COMPONENT}_FOUND``
|
||||
True if the system has the named OpenEXR component.
|
||||
|
||||
Deprecated - use [RELEASE|DEBUG] variants:
|
||||
|
||||
``OpenEXR_LIBRARIES``
|
||||
Libraries needed to link to OpenEXR.
|
||||
``OpenEXR_LIBRARY_DIRS``
|
||||
OpenEXR library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``OpenEXR_INCLUDE_DIR``
|
||||
The directory containing ``OpenEXR/config-auto.h``.
|
||||
``OpenEXR_{COMPONENT}_LIBRARY``
|
||||
Individual component libraries for OpenEXR. may include target_link_libraries() debug/optimized keywords.
|
||||
``OpenEXR_{COMPONENT}_LIBRARY_RELEASE``
|
||||
Individual component libraries for OpenEXR release
|
||||
``OpenEXR_{COMPONENT}_LIBRARY_DEBUG``
|
||||
Individual component libraries for OpenEXR debug
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``OpenEXR_ROOT``
|
||||
Preferred installation prefix.
|
||||
``OPENEXR_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``OPENEXR_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``OPENEXR_DEBUG_SUFFIX``
|
||||
Suffix of the debug version of openexr libs. Defaults to "_d".
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``OPENEXR_USE_STATIC_LIBS``
|
||||
Only search for static openexr libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
mark_as_advanced(
|
||||
OpenEXR_INCLUDE_DIR
|
||||
OpenEXR_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_OPENEXR_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_OPENEXR_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
|
||||
# Set _OPENEXR_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV OPENEXR_ROOT from CMake 3.12
|
||||
if(OpenEXR_ROOT)
|
||||
set(_OPENEXR_ROOT ${OpenEXR_ROOT})
|
||||
elseif(DEFINED ENV{OpenEXR_ROOT})
|
||||
set(_OPENEXR_ROOT $ENV{OpenEXR_ROOT})
|
||||
elseif(OPENEXR_ROOT)
|
||||
set(_OPENEXR_ROOT ${OPENEXR_ROOT})
|
||||
elseif(DEFINED ENV{OPENEXR_ROOT})
|
||||
set(_OPENEXR_ROOT $ENV{OPENEXR_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find OpenEXR
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
pkg_check_modules(PC_OpenEXR QUIET OpenEXR)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for OpenEXR include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_OPENEXR_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _OPENEXR_INCLUDE_SEARCH_DIRS
|
||||
${OPENEXR_INCLUDEDIR}
|
||||
${_OPENEXR_ROOT}
|
||||
${PC_OpenEXR_INCLUDEDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Look for a standard OpenEXR header file.
|
||||
find_path(OpenEXR_INCLUDE_DIR OpenEXRConfig.h
|
||||
${_FIND_OPENEXR_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_OPENEXR_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR}/OpenEXR include/OpenEXR OpenEXR
|
||||
)
|
||||
|
||||
if(EXISTS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h")
|
||||
# Get the EXR version information from the config header
|
||||
file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h"
|
||||
_openexr_version_major_string REGEX "#define OPENEXR_VERSION_MAJOR "
|
||||
)
|
||||
string(REGEX REPLACE "#define OPENEXR_VERSION_MAJOR" ""
|
||||
_openexr_version_major_string "${_openexr_version_major_string}"
|
||||
)
|
||||
string(STRIP "${_openexr_version_major_string}" OpenEXR_VERSION_MAJOR)
|
||||
|
||||
file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h"
|
||||
_openexr_version_minor_string REGEX "#define OPENEXR_VERSION_MINOR "
|
||||
)
|
||||
string(REGEX REPLACE "#define OPENEXR_VERSION_MINOR" ""
|
||||
_openexr_version_minor_string "${_openexr_version_minor_string}"
|
||||
)
|
||||
string(STRIP "${_openexr_version_minor_string}" OpenEXR_VERSION_MINOR)
|
||||
|
||||
unset(_openexr_version_major_string)
|
||||
unset(_openexr_version_minor_string)
|
||||
|
||||
set(OpenEXR_VERSION ${OpenEXR_VERSION_MAJOR}.${OpenEXR_VERSION_MINOR})
|
||||
endif()
|
||||
|
||||
if(${OpenEXR_VERSION} VERSION_GREATER_EQUAL 3.0)
|
||||
set(_OPENEXR_COMPONENT_LIST OpenEXR OpenEXRUtil Iex IlmThread)
|
||||
else()
|
||||
set(_OPENEXR_COMPONENT_LIST IlmImf IlmImfUtil)
|
||||
endif()
|
||||
|
||||
if(OpenEXR_FIND_COMPONENTS)
|
||||
set(OPENEXR_COMPONENTS_PROVIDED TRUE)
|
||||
set(_IGNORED_COMPONENTS "")
|
||||
foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS})
|
||||
if(NOT ${COMPONENT} IN_LIST _OPENEXR_COMPONENT_LIST)
|
||||
list(APPEND _IGNORED_COMPONENTS ${COMPONENT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_IGNORED_COMPONENTS)
|
||||
message(STATUS "Ignoring unknown components of OpenEXR:")
|
||||
foreach(COMPONENT ${_IGNORED_COMPONENTS})
|
||||
message(STATUS " ${COMPONENT}")
|
||||
endforeach()
|
||||
list(REMOVE_ITEM OpenEXR_FIND_COMPONENTS ${_IGNORED_COMPONENTS})
|
||||
endif()
|
||||
else()
|
||||
set(OPENEXR_COMPONENTS_PROVIDED FALSE)
|
||||
set(OpenEXR_FIND_COMPONENTS ${_OPENEXR_COMPONENT_LIST})
|
||||
endif()
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for OPENEXR lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(NOT DEFINED OPENEXR_DEBUG_SUFFIX)
|
||||
set(OPENEXR_DEBUG_SUFFIX _d)
|
||||
endif()
|
||||
|
||||
set(_OPENEXR_LIBRARYDIR_SEARCH_DIRS "")
|
||||
|
||||
# Append to _OPENEXR_LIBRARYDIR_SEARCH_DIRS in priority order
|
||||
|
||||
list(APPEND _OPENEXR_LIBRARYDIR_SEARCH_DIRS
|
||||
${OPENEXR_LIBRARYDIR}
|
||||
${_OPENEXR_ROOT}
|
||||
${PC_OpenEXR_LIBDIR}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
set(OpenEXR_LIB_COMPONENTS "")
|
||||
list(APPEND OPENEXR_BUILD_TYPES RELEASE DEBUG)
|
||||
|
||||
foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS})
|
||||
foreach(BUILD_TYPE ${OPENEXR_BUILD_TYPES})
|
||||
|
||||
set(_TMP_SUFFIX "")
|
||||
if(BUILD_TYPE STREQUAL DEBUG)
|
||||
set(_TMP_SUFFIX ${OPENEXR_DEBUG_SUFFIX})
|
||||
endif()
|
||||
|
||||
set(_OpenEXR_Version_Suffix "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}")
|
||||
set(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(WIN32)
|
||||
if(OPENEXR_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.lib")
|
||||
endif()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.lib")
|
||||
else()
|
||||
if(OPENEXR_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES "${_TMP_SUFFIX}.a")
|
||||
else()
|
||||
if(APPLE)
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.dylib")
|
||||
else()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.so")
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "${_OpenEXR_Version_Suffix}${_TMP_SUFFIX}.a")
|
||||
endif()
|
||||
|
||||
# Find the lib
|
||||
find_library(OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${COMPONENT}
|
||||
${_FIND_OPENEXR_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_OPENEXR_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
|
||||
)
|
||||
|
||||
if(EXISTS ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
list(APPEND OpenEXR_LIB_COMPONENTS ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
list(APPEND OpenEXR_LIB_COMPONENTS_${BUILD_TYPE} ${OpenEXR_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
endif()
|
||||
|
||||
# Reset library suffix
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
unset(_OpenEXR_Version_Suffix)
|
||||
unset(_TMP_SUFFIX)
|
||||
endforeach()
|
||||
|
||||
if(OpenEXR_${COMPONENT}_LIBRARY_DEBUG AND OpenEXR_${COMPONENT}_LIBRARY_RELEASE)
|
||||
# if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
|
||||
# single-config generators, set optimized and debug libraries
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(_isMultiConfig OR CMAKE_BUILD_TYPE)
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY optimized ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} debug ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
|
||||
else()
|
||||
# For single-config generators where CMAKE_BUILD_TYPE has no value,
|
||||
# just use the release libraries
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif()
|
||||
# FIXME: This probably should be set for both cases
|
||||
set(OpenEXR_${COMPONENT}_LIBRARIES optimized ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} debug ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# if only the release version was found, set the debug variable also to the release version
|
||||
if(OpenEXR_${COMPONENT}_LIBRARY_RELEASE AND NOT OpenEXR_${COMPONENT}_LIBRARY_DEBUG)
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY_DEBUG ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
|
||||
set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
||||
# if only the debug version was found, set the release variable also to the debug version
|
||||
if(OpenEXR_${COMPONENT}_LIBRARY_DEBUG AND NOT OpenEXR_${COMPONENT}_LIBRARY_RELEASE)
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY_RELEASE ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
|
||||
set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# If the debug & release library ends up being the same, omit the keywords
|
||||
if("${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}" STREQUAL "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
set(OpenEXR_${COMPONENT}_LIBRARY ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} )
|
||||
set(OpenEXR_${COMPONENT}_LIBRARIES ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} )
|
||||
endif()
|
||||
|
||||
if(OpenEXR_${COMPONENT}_LIBRARY)
|
||||
set(OpenEXR_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(OpenEXR_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set OPENEXR_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(OpenEXR
|
||||
FOUND_VAR OpenEXR_FOUND
|
||||
REQUIRED_VARS
|
||||
OpenEXR_INCLUDE_DIR
|
||||
OpenEXR_LIB_COMPONENTS
|
||||
VERSION_VAR OpenEXR_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
if(NOT OpenEXR_FOUND)
|
||||
if(OpenEXR_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find OpenEXR")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Partition release/debug lib vars
|
||||
|
||||
set(OpenEXR_RELEASE_LIBRARIES "")
|
||||
set(OpenEXR_RELEASE_LIBRARY_DIRS "")
|
||||
set(OpenEXR_DEBUG_LIBRARIES "")
|
||||
set(OpenEXR_DEBUG_LIBRARY_DIRS "")
|
||||
foreach(LIB ${OpenEXR_LIB_COMPONENTS_RELEASE})
|
||||
get_filename_component(_EXR_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND OpenEXR_RELEASE_LIBRARIES ${LIB})
|
||||
list(APPEND OpenEXR_RELEASE_LIBRARY_DIRS ${_EXR_LIBDIR})
|
||||
endforeach()
|
||||
|
||||
foreach(LIB ${OpenEXR_LIB_COMPONENTS_DEBUG})
|
||||
get_filename_component(_EXR_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND OpenEXR_DEBUG_LIBRARIES ${LIB})
|
||||
list(APPEND OpenEXR_DEBUG_LIBRARY_DIRS ${_EXR_LIBDIR})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES OpenEXR_RELEASE_LIBRARY_DIRS)
|
||||
list(REMOVE_DUPLICATES OpenEXR_DEBUG_LIBRARY_DIRS)
|
||||
|
||||
set(OpenEXR_LIBRARIES ${OpenEXR_RELEASE_LIBRARIES})
|
||||
set(OpenEXR_LIBRARY_DIRS ${OpenEXR_RELEASE_LIBRARY_DIRS})
|
||||
|
||||
# We have to add both include and include/OpenEXR to the include
|
||||
# path in case OpenEXR and IlmBase are installed separately.
|
||||
#
|
||||
# Make sure we get the absolute path to avoid issues where
|
||||
# /usr/include/OpenEXR/../ is picked up and passed to gcc from cmake
|
||||
# which won't correctly compute /usr/include as an implicit system
|
||||
# dir if the path is relative:
|
||||
#
|
||||
# https://github.com/AcademySoftwareFoundation/openvdb/issues/632
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129
|
||||
|
||||
set(_OpenEXR_Parent_Dir "")
|
||||
get_filename_component(_OpenEXR_Parent_Dir
|
||||
${OpenEXR_INCLUDE_DIR}/../ ABSOLUTE)
|
||||
|
||||
set(OpenEXR_INCLUDE_DIRS)
|
||||
list(APPEND OpenEXR_INCLUDE_DIRS
|
||||
${_OpenEXR_Parent_Dir}
|
||||
${OpenEXR_INCLUDE_DIR}
|
||||
)
|
||||
unset(_OpenEXR_Parent_Dir)
|
||||
|
||||
# Configure imported target
|
||||
|
||||
foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS})
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(OpenEXR_${COMPONENT}_LIB_TYPE UNKNOWN)
|
||||
if(OPENEXR_USE_STATIC_LIBS)
|
||||
set(OpenEXR_${COMPONENT}_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_OpenEXR_${COMPONENT}_EXT ${OpenEXR_${COMPONENT}_LIBRARY_RELEASE} EXT)
|
||||
if(${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".a")
|
||||
set(OpenEXR_${COMPONENT}_LIB_TYPE STATIC)
|
||||
elseif(${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".so" OR
|
||||
${_OpenEXR_${COMPONENT}_EXT} STREQUAL ".dylib")
|
||||
set(OpenEXR_${COMPONENT}_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(OpenEXR_${COMPONENT}_DEFINITIONS)
|
||||
|
||||
# Add the OPENEXR_DLL define if the library is not static on WIN32
|
||||
if(WIN32)
|
||||
if(NOT OpenEXR_${COMPONENT}_LIB_TYPE STREQUAL STATIC)
|
||||
list(APPEND OpenEXR_${COMPONENT}_DEFINITIONS OPENEXR_DLL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET OpenEXR::${COMPONENT})
|
||||
add_library(OpenEXR::${COMPONENT} ${OpenEXR_${COMPONENT}_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_OpenEXR_CFLAGS_OTHER}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "${OpenEXR_${COMPONENT}_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIRS}")
|
||||
|
||||
# Standard location
|
||||
set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${OpenEXR_${COMPONENT}_LIBRARY}")
|
||||
|
||||
# Release location
|
||||
if(EXISTS "${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}")
|
||||
set_property(TARGET OpenEXR::${COMPONENT} APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
|
||||
IMPORTED_LOCATION_RELEASE "${OpenEXR_${COMPONENT}_LIBRARY_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Debug location
|
||||
if(EXISTS "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
set_property(TARGET OpenEXR::${COMPONENT} APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(OpenEXR::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
|
||||
IMPORTED_LOCATION_DEBUG "${OpenEXR_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
@@ -0,0 +1,839 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindOpenVDB
|
||||
-----------
|
||||
|
||||
Find OpenVDB include dirs, libraries and settings
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(OpenVDB
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if OpenVDB is not found
|
||||
[COMPONENTS <libs>...] # OpenVDB libraries by their canonical name
|
||||
# e.g. "openvdb" for "libopenvdb",
|
||||
# "pyopenvdb" for the python plugin
|
||||
# "openvdb_ax" for the OpenVDB AX extension
|
||||
# "openvdb_houdini" for the houdini plugin
|
||||
# "nanovdb" for the nanovdb extension
|
||||
)
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``OpenVDB::openvdb``
|
||||
The core openvdb library target.
|
||||
``OpenVDB::openvdb_je``
|
||||
The core openvdb library target with jemalloc.
|
||||
``OpenVDB::pyopenvdb``
|
||||
The openvdb python library target.
|
||||
``OpenVDB::openvdb_houdini``
|
||||
The openvdb houdini library target.
|
||||
``OpenVDB::openvdb_ax``
|
||||
The openvdb_ax library target.
|
||||
``OpenVDB::nanovdb``
|
||||
The nanovdb library target.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``OpenVDB_FOUND``
|
||||
True if the system has the OpenVDB library.
|
||||
``OpenVDB_VERSION``
|
||||
The version of the OpenVDB library which was found.
|
||||
``OpenVDB_INCLUDE_DIRS``
|
||||
Include directories needed to use OpenVDB.
|
||||
``OpenVDB_LIBRARIES``
|
||||
Libraries needed to link to OpenVDB.
|
||||
``OpenVDB_LIBRARY_DIRS``
|
||||
OpenVDB library directories.
|
||||
``OpenVDB_DEFINITIONS``
|
||||
Definitions to use when compiling code that uses OpenVDB.
|
||||
``OpenVDB_${COMPONENT}_FOUND``
|
||||
True if the system has the named OpenVDB component.
|
||||
``OpenVDB_USES_BLOSC``
|
||||
True if the OpenVDB Library has been built with blosc support
|
||||
``OpenVDB_USES_ZLIB``
|
||||
True if the OpenVDB Library has been built with zlib support
|
||||
``OpenVDB_USES_LOG4CPLUS``
|
||||
True if the OpenVDB Library has been built with log4cplus support
|
||||
``OpenVDB_USES_IMATH_HALF``
|
||||
True if the OpenVDB Library has been built with Imath half support
|
||||
``OpenVDB_ABI``
|
||||
Set if this module was able to determine the ABI number the located
|
||||
OpenVDB Library was built against. Unset otherwise.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``OpenVDB_INCLUDE_DIR``
|
||||
The directory containing ``openvdb/version.h``.
|
||||
``OpenVDB_${COMPONENT}_INCLUDE_DIR``
|
||||
Individual component include directories for OpenVDB
|
||||
``OpenVDB_${COMPONENT}_LIBRARY``
|
||||
Individual component libraries for OpenVDB
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``OpenVDB_ROOT``
|
||||
Preferred installation prefix.
|
||||
``OPENVDB_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``OPENVDB_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``OPENVDB_${COMPONENT}_ROOT``
|
||||
Preferred installation prefix of a specific component.
|
||||
``OPENVDB_${COMPONENT}_INCLUDEDIR``
|
||||
Preferred include directory of a specific component e.g. <prefix>/include
|
||||
``OPENVDB_${COMPONENT}_LIBRARYDIR``
|
||||
Preferred library directory of a specific component e.g. <prefix>/lib
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``OPENVDB_USE_STATIC_LIBS``
|
||||
Only search for static openvdb libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
# Include utility functions for version information
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/OpenVDBUtils.cmake)
|
||||
|
||||
mark_as_advanced(
|
||||
OpenVDB_INCLUDE_DIR
|
||||
OpenVDB_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_OPENVDB_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_OPENVDB_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
set(_OPENVDB_COMPONENT_LIST
|
||||
openvdb
|
||||
openvdb_je
|
||||
pyopenvdb
|
||||
openvdb_ax
|
||||
openvdb_houdini
|
||||
nanovdb
|
||||
)
|
||||
|
||||
if(OpenVDB_FIND_COMPONENTS)
|
||||
set(OPENVDB_COMPONENTS_PROVIDED TRUE)
|
||||
set(_IGNORED_COMPONENTS "")
|
||||
foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
|
||||
if(NOT ${COMPONENT} IN_LIST _OPENVDB_COMPONENT_LIST)
|
||||
list(APPEND _IGNORED_COMPONENTS ${COMPONENT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_IGNORED_COMPONENTS)
|
||||
message(STATUS "Ignoring unknown components of OpenVDB:")
|
||||
foreach(COMPONENT ${_IGNORED_COMPONENTS})
|
||||
message(STATUS " ${COMPONENT}")
|
||||
endforeach()
|
||||
list(REMOVE_ITEM OpenVDB_FIND_COMPONENTS ${_IGNORED_COMPONENTS})
|
||||
endif()
|
||||
else()
|
||||
set(OPENVDB_COMPONENTS_PROVIDED FALSE)
|
||||
set(OpenVDB_FIND_COMPONENTS openvdb)
|
||||
endif()
|
||||
|
||||
# always make sure openvdb is picked up as a component i.e.
|
||||
# find_package(OpenVDB COMPONENTS pyopenvdb) results in both
|
||||
# openvdb and pyopenvdb targets. Also make sure it appears
|
||||
# first in the component lists.
|
||||
list(INSERT OpenVDB_FIND_COMPONENTS 0 openvdb)
|
||||
list(REMOVE_DUPLICATES OpenVDB_FIND_COMPONENTS)
|
||||
|
||||
# Set _OPENVDB_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV OPENVDB_ROOT from CMake 3.12
|
||||
if(OpenVDB_ROOT)
|
||||
set(_OPENVDB_ROOT ${OpenVDB_ROOT})
|
||||
elseif(DEFINED ENV{OpenVDB_ROOT})
|
||||
set(_OPENVDB_ROOT $ENV{OpenVDB_ROOT})
|
||||
elseif(OPENVDB_ROOT)
|
||||
set(_OPENVDB_ROOT ${OPENVDB_ROOT})
|
||||
elseif(DEFINED ENV{OPENVDB_ROOT})
|
||||
set(_OPENVDB_ROOT $ENV{OPENVDB_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find OpenVDB
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
pkg_check_modules(PC_OpenVDB QUIET OpenVDB)
|
||||
endif()
|
||||
|
||||
# This CMake module supports being called from external packages AND from
|
||||
# within the OpenVDB repository for building openvdb components with the
|
||||
# core library build disabled. Determine where we are being called from:
|
||||
#
|
||||
# (repo structure = <root>/cmake/FindOpenVDB.cmake)
|
||||
# (inst structure = <root>/lib/cmake/OpenVDB/FindOpenVDB.cmake)
|
||||
|
||||
get_filename_component(_DIR_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
|
||||
if(${_DIR_NAME} STREQUAL "cmake")
|
||||
# Called from root repo for openvdb components
|
||||
elseif(${_DIR_NAME} STREQUAL "OpenVDB")
|
||||
# Set the install variable to track directories if this is being called from
|
||||
# an installed location and from another package. The expected installation
|
||||
# directory structure is:
|
||||
# <root>/lib/cmake/OpenVDB/FindOpenVDB.cmake
|
||||
# <root>/include
|
||||
# <root>/bin
|
||||
get_filename_component(_IMPORT_PREFIX ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
|
||||
get_filename_component(_IMPORT_PREFIX ${_IMPORT_PREFIX} DIRECTORY)
|
||||
get_filename_component(_IMPORT_PREFIX ${_IMPORT_PREFIX} DIRECTORY)
|
||||
set(_OPENVDB_INSTALL ${_IMPORT_PREFIX})
|
||||
list(APPEND _OPENVDB_ROOT ${_OPENVDB_INSTALL})
|
||||
endif()
|
||||
|
||||
unset(_DIR_NAME)
|
||||
unset(_IMPORT_PREFIX)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for OpenVDB include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_OPENVDB_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _OPENVDB_INCLUDE_SEARCH_DIRS
|
||||
${OPENVDB_INCLUDEDIR}
|
||||
${_OPENVDB_ROOT}
|
||||
${PC_OpenVDB_INCLUDE_DIRS}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
|
||||
# Add in extra component paths
|
||||
set(_VDB_COMPONENT_SEARCH_DIRS ${_OPENVDB_INCLUDE_SEARCH_DIRS})
|
||||
list(APPEND _VDB_COMPONENT_SEARCH_DIRS
|
||||
${OPENVDB_${COMPONENT}_ROOT}
|
||||
${OPENVDB_${COMPONENT}_INCLUDEDIR}
|
||||
)
|
||||
if(_VDB_COMPONENT_SEARCH_DIRS)
|
||||
list(REMOVE_DUPLICATES _VDB_COMPONENT_SEARCH_DIRS)
|
||||
endif()
|
||||
|
||||
# Look for a standard header files.
|
||||
if(${COMPONENT} STREQUAL "openvdb")
|
||||
# Look for a standard OpenVDB header file.
|
||||
find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR openvdb/version.h
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
include
|
||||
)
|
||||
elseif(${COMPONENT} STREQUAL "pyopenvdb")
|
||||
find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR pyopenvdb.h
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/openvdb/python
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/openvdb
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
include
|
||||
)
|
||||
elseif(${COMPONENT} STREQUAL "openvdb_ax")
|
||||
# Look for a standard OpenVDB header file.
|
||||
find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR compiler/Compiler.h
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/openvdb/openvdb_ax
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/openvdb_ax
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
include
|
||||
)
|
||||
elseif(${COMPONENT} STREQUAL "openvdb_houdini")
|
||||
# @note Expects both houdini_utils and openvdb_houdini folders
|
||||
# to be located in the same place
|
||||
find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR openvdb_houdini/SOP_NodeVDB.h
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/openvdb
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
include
|
||||
)
|
||||
elseif(${COMPONENT} STREQUAL "nanovdb")
|
||||
# Look for NanoVDB.h
|
||||
find_path(OpenVDB_${COMPONENT}_INCLUDE_DIR NanoVDB.h
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/nanovdb
|
||||
${CMAKE_INSTALL_INCLUDEDIR}
|
||||
include
|
||||
)
|
||||
endif()
|
||||
unset(_VDB_COMPONENT_SEARCH_DIRS)
|
||||
endforeach()
|
||||
|
||||
set(OpenVDB_INCLUDE_DIR ${OpenVDB_openvdb_INCLUDE_DIR}
|
||||
CACHE PATH "The OpenVDB core include directory")
|
||||
|
||||
set(_OPENVDB_VERSION_HEADER "${OpenVDB_INCLUDE_DIR}/openvdb/version.h")
|
||||
OPENVDB_VERSION_FROM_HEADER("${_OPENVDB_VERSION_HEADER}"
|
||||
VERSION OpenVDB_VERSION
|
||||
MAJOR OpenVDB_MAJOR_VERSION
|
||||
MINOR OpenVDB_MINOR_VERSION
|
||||
PATCH OpenVDB_PATCH_VERSION
|
||||
ABI OpenVDB_ABI_FROM_HEADER # will be OpenVDB_MAJOR_VERSION prior to 8.1.0
|
||||
)
|
||||
|
||||
if(OpenVDB_VERSION VERSION_LESS 8.1.0)
|
||||
set(_OPENVDB_HAS_NEW_VERSION_HEADER FALSE)
|
||||
# ABI gets computed later
|
||||
else()
|
||||
set(_OPENVDB_HAS_NEW_VERSION_HEADER TRUE)
|
||||
set(OpenVDB_ABI ${OpenVDB_ABI_FROM_HEADER})
|
||||
endif()
|
||||
unset(OpenVDB_ABI_FROM_HEADER)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for OPENVDB lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_OPENVDB_LIBRARYDIR_SEARCH_DIRS "")
|
||||
|
||||
# Append to _OPENVDB_LIBRARYDIR_SEARCH_DIRS in priority order
|
||||
|
||||
list(APPEND _OPENVDB_LIBRARYDIR_SEARCH_DIRS
|
||||
${OPENVDB_LIBRARYDIR}
|
||||
${_OPENVDB_ROOT}
|
||||
${PC_OpenVDB_LIBRARY_DIRS}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Library suffix handling
|
||||
|
||||
set(_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
set(OPENVDB_PYTHON_PATH_SUFFIXES
|
||||
lib64/python
|
||||
lib64/python2.7
|
||||
lib64/python3
|
||||
lib/python
|
||||
lib/python2.7
|
||||
lib/python3
|
||||
)
|
||||
|
||||
# Recurse through all the site-packages and dist-packages on the file system
|
||||
file(GLOB PYTHON_SITE_PACKAGES ${CMAKE_INSTALL_FULL_LIBDIR}/python**/*)
|
||||
foreach(_site_package_full_dir ${PYTHON_SITE_PACKAGES})
|
||||
string(REPLACE ${CMAKE_INSTALL_FULL_LIBDIR} "${CMAKE_INSTALL_LIBDIR}"
|
||||
_site_package_dir ${_site_package_full_dir})
|
||||
list(APPEND OPENVDB_PYTHON_PATH_SUFFIXES ${_site_package_dir})
|
||||
endforeach()
|
||||
|
||||
set(OPENVDB_LIB_PATH_SUFFIXES
|
||||
${CMAKE_INSTALL_LIBDIR}
|
||||
lib64
|
||||
lib
|
||||
)
|
||||
|
||||
list(REMOVE_DUPLICATES OPENVDB_PYTHON_PATH_SUFFIXES)
|
||||
list(REMOVE_DUPLICATES OPENVDB_LIB_PATH_SUFFIXES)
|
||||
|
||||
# Static library setup
|
||||
if(MSVC)
|
||||
if(OPENVDB_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
|
||||
endif()
|
||||
else()
|
||||
if(OPENVDB_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(OpenVDB_LIB_COMPONENTS "")
|
||||
|
||||
foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS})
|
||||
message("COMPONENT = " ${COMPONENT})
|
||||
set(LIB_NAME ${COMPONENT})
|
||||
|
||||
# Add in extra component paths
|
||||
set(_VDB_COMPONENT_SEARCH_DIRS ${_OPENVDB_LIBRARYDIR_SEARCH_DIRS})
|
||||
list(APPEND _VDB_COMPONENT_SEARCH_DIRS
|
||||
${OPENVDB_${COMPONENT}_ROOT}
|
||||
${OPENVDB_${COMPONENT}_LIBRARYDIR}
|
||||
)
|
||||
|
||||
if(${COMPONENT} STREQUAL "pyopenvdb")
|
||||
set(_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES ";lib") # find non-prefixed
|
||||
find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME}
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${OPENVDB_PYTHON_PATH_SUFFIXES}
|
||||
)
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES ${_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_PREFIXES})
|
||||
elseif(${COMPONENT} STREQUAL "openvdb_je")
|
||||
# alias to the result of openvdb which should be handled first
|
||||
set(OpenVDB_${COMPONENT}_LIBRARY ${OpenVDB_openvdb_LIBRARY})
|
||||
else()
|
||||
find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME}
|
||||
${_FIND_OPENVDB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_VDB_COMPONENT_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${OPENVDB_LIB_PATH_SUFFIXES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND OpenVDB_LIB_COMPONENTS ${OpenVDB_${COMPONENT}_LIBRARY})
|
||||
if(${COMPONENT} STREQUAL "nanovdb")
|
||||
# nanovdb is headers-only, no lib component
|
||||
if(OpenVDB_${COMPONENT}_INCLUDE_DIR)
|
||||
set(OpenVDB_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(OpenVDB_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
else()
|
||||
if(OpenVDB_${COMPONENT}_LIBRARY)
|
||||
set(OpenVDB_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(OpenVDB_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
endif()
|
||||
unset(_VDB_COMPONENT_SEARCH_DIRS)
|
||||
endforeach()
|
||||
|
||||
unset(OPENVDB_PYTHON_PATH_SUFFIXES)
|
||||
unset(OPENVDB_LIB_PATH_SUFFIXES)
|
||||
|
||||
# Reset library suffix
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_OPENVDB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set OPENVDB_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(OpenVDB
|
||||
FOUND_VAR OpenVDB_FOUND
|
||||
REQUIRED_VARS
|
||||
OpenVDB_INCLUDE_DIR
|
||||
OpenVDB_LIB_COMPONENTS
|
||||
VERSION_VAR OpenVDB_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Determine ABI number
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# Set the ABI number the library was built against. The old system,
|
||||
# which didn't define the ABI in the build config, uses vdb_print
|
||||
|
||||
if(NOT _OPENVDB_HAS_NEW_VERSION_HEADER)
|
||||
if(_OPENVDB_INSTALL)
|
||||
OPENVDB_ABI_VERSION_FROM_PRINT(
|
||||
"${_OPENVDB_INSTALL}/bin/vdb_print"
|
||||
ABI OpenVDB_ABI
|
||||
)
|
||||
else()
|
||||
# Try and find vdb_print from the include path
|
||||
OPENVDB_ABI_VERSION_FROM_PRINT(
|
||||
"${OpenVDB_INCLUDE_DIR}/../bin/vdb_print"
|
||||
ABI OpenVDB_ABI
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT OpenVDB_FIND_QUIETLY)
|
||||
if(NOT OpenVDB_ABI)
|
||||
message(WARNING "Unable to determine OpenVDB ABI version from OpenVDB "
|
||||
"installation. The library major version \"${OpenVDB_MAJOR_VERSION}\" "
|
||||
"will be inferred. If this is not correct, use "
|
||||
"add_definitions(-DOPENVDB_ABI_VERSION_NUMBER=N)"
|
||||
)
|
||||
else()
|
||||
message(STATUS "OpenVDB ABI Version: ${OpenVDB_ABI}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Handle OpenVDB dependencies and interface settings
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# Handle openvdb_houdini first to configure search paths
|
||||
|
||||
if(openvdb_houdini IN_LIST OpenVDB_FIND_COMPONENTS)
|
||||
include(OpenVDBHoudiniSetup)
|
||||
endif()
|
||||
|
||||
# Add standard dependencies
|
||||
|
||||
find_package(TBB REQUIRED COMPONENTS tbb)
|
||||
|
||||
if(NOT OPENVDB_USE_STATIC_LIBS AND NOT Boost_USE_STATIC_LIBS)
|
||||
# @note Both of these must be set for Boost 1.70 (VFX2020) to link against
|
||||
# boost shared libraries (more specifically libraries built with -fPIC).
|
||||
# http://boost.2283326.n4.nabble.com/CMake-config-scripts-broken-in-1-70-td4708957.html
|
||||
# https://github.com/boostorg/boost_install/commit/160c7cb2b2c720e74463865ef0454d4c4cd9ae7c
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
set(Boost_USE_STATIC_LIBS OFF)
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS iostreams)
|
||||
|
||||
# Add deps for pyopenvdb
|
||||
# @todo track for numpy
|
||||
|
||||
if(pyopenvdb IN_LIST OpenVDB_FIND_COMPONENTS)
|
||||
find_package(Python REQUIRED)
|
||||
|
||||
# Boost python handling - try and find both python and pythonXx (version suffixed).
|
||||
# Prioritize the version suffixed library, failing if neither exist.
|
||||
|
||||
find_package(Boost ${MINIMUM_BOOST_VERSION}
|
||||
QUIET COMPONENTS python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}
|
||||
)
|
||||
|
||||
if(TARGET Boost::python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR})
|
||||
set(BOOST_PYTHON_LIB "python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}")
|
||||
message(STATUS "Found boost_python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}")
|
||||
else()
|
||||
find_package(Boost ${MINIMUM_BOOST_VERSION} QUIET COMPONENTS python)
|
||||
if(TARGET Boost::python)
|
||||
set(BOOST_PYTHON_LIB "python")
|
||||
message(STATUS "Found non-suffixed boost_python, assuming to be python version "
|
||||
"\"${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}\" compatible"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to find boost_python or "
|
||||
"boost_python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add deps for openvdb_ax
|
||||
|
||||
if(openvdb_ax IN_LIST OpenVDB_FIND_COMPONENTS)
|
||||
find_package(LLVM REQUIRED)
|
||||
find_library(found_LLVM LLVM HINTS ${LLVM_LIBRARY_DIRS})
|
||||
|
||||
if(found_LLVM)
|
||||
set(LLVM_LIBS "LLVM")
|
||||
else()
|
||||
llvm_map_components_to_libnames(_llvm_libs
|
||||
native core executionengine support mcjit passes objcarcopts)
|
||||
set(LLVM_LIBS "${_llvm_libs}")
|
||||
endif()
|
||||
|
||||
if(NOT OpenVDB_FIND_QUIET)
|
||||
message(STATUS "Found LLVM: ${LLVM_DIR} (found version \"${LLVM_PACKAGE_VERSION}\")")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# As the way we resolve optional libraries relies on library file names, use
|
||||
# the configuration options from the main CMakeLists.txt to allow users
|
||||
# to manually identify the requirements of OpenVDB builds if they know them.
|
||||
set(OpenVDB_USES_BLOSC ${USE_BLOSC})
|
||||
set(OpenVDB_USES_ZLIB ${USE_ZLIB})
|
||||
set(OpenVDB_USES_LOG4CPLUS ${USE_LOG4CPLUS})
|
||||
set(OpenVDB_USES_IMATH_HALF ${USE_IMATH_HALF})
|
||||
set(OpenVDB_DEFINITIONS)
|
||||
|
||||
if(WIN32)
|
||||
if(OPENVDB_USE_STATIC_LIBS)
|
||||
list(APPEND OpenVDB_DEFINITIONS OPENVDB_STATICLIB)
|
||||
else()
|
||||
list(APPEND OpenVDB_DEFINITIONS OPENVDB_DLL)
|
||||
endif()
|
||||
# Newer version of OpenVDB define these in Platform.h, but they are also
|
||||
# provided here to maintain backwards compatibility with header include
|
||||
# others
|
||||
list(APPEND OpenVDB_DEFINITIONS _WIN32)
|
||||
list(APPEND OpenVDB_DEFINITIONS NOMINMAX)
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
list(APPEND OpenVDB_DEFINITIONS _USE_MATH_DEFINES)
|
||||
endif()
|
||||
|
||||
if(OpenVDB_ABI)
|
||||
# Newer version of OpenVDB defines this in version.h, but it is are also
|
||||
# provided here to maintain backwards compatibility with header include
|
||||
# others
|
||||
list(APPEND OpenVDB_DEFINITIONS OPENVDB_ABI_VERSION_NUMBER=${OpenVDB_ABI})
|
||||
endif()
|
||||
|
||||
# Configure deps
|
||||
|
||||
if(_OPENVDB_HAS_NEW_VERSION_HEADER)
|
||||
OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_IMATH_HALF" OpenVDB_USES_IMATH_HALF)
|
||||
OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_BLOSC" OpenVDB_USES_BLOSC)
|
||||
OPENVDB_GET_VERSION_DEFINE(${_OPENVDB_VERSION_HEADER} "OPENVDB_USE_ZLIB" OpenVDB_USES_ZLIB)
|
||||
elseif(NOT OPENVDB_USE_STATIC_LIBS)
|
||||
# Use GetPrerequisites to see which libraries this OpenVDB lib has linked to
|
||||
# which we can query for optional deps. This basically runs ldd/otoll/objdump
|
||||
# etc to track deps. We could use a vdb_config binary tools here to improve
|
||||
# this process
|
||||
include(GetPrerequisites)
|
||||
|
||||
set(_EXCLUDE_SYSTEM_PREREQUISITES 1)
|
||||
set(_RECURSE_PREREQUISITES 0)
|
||||
set(_OPENVDB_PREREQUISITE_LIST)
|
||||
|
||||
get_prerequisites(${OpenVDB_openvdb_LIBRARY}
|
||||
_OPENVDB_PREREQUISITE_LIST
|
||||
${_EXCLUDE_SYSTEM_PREREQUISITES}
|
||||
${_RECURSE_PREREQUISITES}
|
||||
""
|
||||
"${SYSTEM_LIBRARY_PATHS}"
|
||||
)
|
||||
|
||||
unset(_EXCLUDE_SYSTEM_PREREQUISITES)
|
||||
unset(_RECURSE_PREREQUISITES)
|
||||
|
||||
# Search for optional dependencies
|
||||
foreach(PREREQUISITE ${_OPENVDB_PREREQUISITE_LIST})
|
||||
set(_HAS_DEP)
|
||||
get_filename_component(PREREQUISITE ${PREREQUISITE} NAME)
|
||||
|
||||
string(FIND ${PREREQUISITE} "blosc" _HAS_DEP)
|
||||
if(NOT ${_HAS_DEP} EQUAL -1)
|
||||
set(OpenVDB_USES_BLOSC ON)
|
||||
endif()
|
||||
|
||||
string(FIND ${PREREQUISITE} "zlib" _HAS_DEP)
|
||||
if(NOT ${_HAS_DEP} EQUAL -1)
|
||||
set(OpenVDB_USES_ZLIB ON)
|
||||
endif()
|
||||
|
||||
string(FIND ${PREREQUISITE} "log4cplus" _HAS_DEP)
|
||||
if(NOT ${_HAS_DEP} EQUAL -1)
|
||||
set(OpenVDB_USES_LOG4CPLUS ON)
|
||||
endif()
|
||||
|
||||
string(FIND ${PREREQUISITE} "Half" _HAS_DEP)
|
||||
if(NOT ${_HAS_DEP} EQUAL -1)
|
||||
set(OpenVDB_USES_IMATH_HALF ON)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
unset(_OPENVDB_PREREQUISITE_LIST)
|
||||
endif()
|
||||
|
||||
if(OpenVDB_USES_BLOSC)
|
||||
find_package(Blosc REQUIRED)
|
||||
endif()
|
||||
|
||||
if(OpenVDB_USES_ZLIB)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
if(OpenVDB_USES_LOG4CPLUS)
|
||||
find_package(Log4cplus REQUIRED)
|
||||
endif()
|
||||
|
||||
if(OpenVDB_USES_IMATH_HALF)
|
||||
find_package(Imath CONFIG)
|
||||
if (NOT TARGET Imath::Imath)
|
||||
find_package(IlmBase REQUIRED COMPONENTS Half)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# @note OPENVDB_OPENEXR_STATICLIB is old functionality and should be removed
|
||||
if(OPENEXR_USE_STATIC_LIBS OR
|
||||
("${ILMBASE_LIB_TYPE}" STREQUAL "STATIC_LIBRARY") OR
|
||||
("${IMATH_LIB_TYPE}" STREQUAL "STATIC_LIBRARY"))
|
||||
list(APPEND OpenVDB_DEFINITIONS OPENVDB_OPENEXR_STATICLIB)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
# Set deps. Note that the order here is important. If we're building against
|
||||
# Houdini 17.5 we must include IlmBase deps first to ensure the users chosen
|
||||
# namespaced headers are correctly prioritized. Otherwise other include paths
|
||||
# from shared installs (including houdini) may pull in the wrong headers
|
||||
|
||||
set(_OPENVDB_VISIBLE_DEPENDENCIES Boost::iostreams)
|
||||
|
||||
if(OpenVDB_USES_IMATH_HALF)
|
||||
list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES $<TARGET_NAME_IF_EXISTS:IlmBase::Half> $<TARGET_NAME_IF_EXISTS:Imath::Imath>)
|
||||
endif()
|
||||
|
||||
if(OpenVDB_USES_LOG4CPLUS)
|
||||
list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES Log4cplus::log4cplus)
|
||||
list(APPEND OpenVDB_DEFINITIONS OPENVDB_USE_LOG4CPLUS)
|
||||
endif()
|
||||
|
||||
list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES
|
||||
TBB::tbb
|
||||
)
|
||||
if(UNIX)
|
||||
list(APPEND _OPENVDB_VISIBLE_DEPENDENCIES
|
||||
Threads::Threads
|
||||
)
|
||||
endif()
|
||||
|
||||
set(_OPENVDB_HIDDEN_DEPENDENCIES)
|
||||
|
||||
if(NOT OPENVDB_USE_STATIC_LIBS)
|
||||
if(OpenVDB_USES_BLOSC)
|
||||
list(APPEND _OPENVDB_HIDDEN_DEPENDENCIES Blosc::blosc)
|
||||
endif()
|
||||
if(OpenVDB_USES_ZLIB)
|
||||
list(APPEND _OPENVDB_HIDDEN_DEPENDENCIES ZLIB::ZLIB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(openvdb_je IN_LIST OpenVDB_FIND_COMPONENTS)
|
||||
find_package(Jemalloc REQUIRED)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure imported targets
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(OpenVDB_LIBRARIES ${OpenVDB_LIB_COMPONENTS})
|
||||
set(OpenVDB_INCLUDE_DIRS ${OpenVDB_INCLUDE_DIR})
|
||||
|
||||
set(OpenVDB_LIBRARY_DIRS "")
|
||||
foreach(LIB ${OpenVDB_LIB_COMPONENTS})
|
||||
get_filename_component(_OPENVDB_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND OpenVDB_LIBRARY_DIRS ${_OPENVDB_LIBDIR})
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES OpenVDB_LIBRARY_DIRS)
|
||||
|
||||
# OpenVDB::openvdb
|
||||
|
||||
if(NOT TARGET OpenVDB::openvdb)
|
||||
set(OPENVDB_openvdb_LIB_TYPE UNKNOWN)
|
||||
if(OPENVDB_USE_STATIC_LIBS)
|
||||
set(OPENVDB_openvdb_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_OPENVDB_openvdb_EXT
|
||||
${OpenVDB_openvdb_LIBRARY} EXT)
|
||||
if(_OPENVDB_openvdb_EXT STREQUAL ".a")
|
||||
set(OPENVDB_openvdb_LIB_TYPE STATIC)
|
||||
elseif(_OPENVDB_openvdb_EXT STREQUAL ".so" OR
|
||||
_OPENVDB_openvdb_EXT STREQUAL ".dylib")
|
||||
set(OPENVDB_openvdb_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(OpenVDB::openvdb ${OPENVDB_openvdb_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(OpenVDB::openvdb PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_openvdb_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_OpenVDB_CFLAGS_OTHER}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "${OpenVDB_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_INCLUDE_DIR}"
|
||||
IMPORTED_LINK_DEPENDENT_LIBRARIES "${_OPENVDB_HIDDEN_DEPENDENCIES}" # non visible deps
|
||||
INTERFACE_LINK_LIBRARIES "${_OPENVDB_VISIBLE_DEPENDENCIES}" # visible deps (headers)
|
||||
INTERFACE_COMPILE_FEATURES cxx_std_14
|
||||
)
|
||||
endif()
|
||||
|
||||
# OpenVDB::openvdb_je
|
||||
|
||||
if(OpenVDB_openvdb_je_LIBRARY)
|
||||
if(NOT TARGET OpenVDB::openvdb_je)
|
||||
add_library(OpenVDB::openvdb_je INTERFACE IMPORTED)
|
||||
target_link_libraries(OpenVDB::openvdb_je INTERFACE OpenVDB::openvdb)
|
||||
target_link_libraries(OpenVDB::openvdb_je INTERFACE Jemalloc::jemalloc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# OpenVDB::pyopenvdb
|
||||
|
||||
if(OpenVDB_pyopenvdb_LIBRARY)
|
||||
if(NOT TARGET OpenVDB::pyopenvdb)
|
||||
add_library(OpenVDB::pyopenvdb MODULE IMPORTED)
|
||||
set_target_properties(OpenVDB::pyopenvdb PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_pyopenvdb_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_pyopenvdb_INCLUDE_DIR};${PYTHON_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;Boost::${BOOST_PYTHON_LIB};${PYTHON_LIBRARIES}"
|
||||
INTERFACE_COMPILE_FEATURES cxx_std_14
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# OpenVDB::openvdb_houdini
|
||||
|
||||
if(OpenVDB_openvdb_houdini_LIBRARY)
|
||||
if(NOT TARGET OpenVDB::openvdb_houdini)
|
||||
add_library(OpenVDB::openvdb_houdini SHARED IMPORTED)
|
||||
set_target_properties(OpenVDB::openvdb_houdini PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_openvdb_houdini_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_openvdb_houdini_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;Houdini"
|
||||
INTERFACE_COMPILE_FEATURES cxx_std_14
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# OpenVDB::openvdb_ax
|
||||
|
||||
if(OpenVDB_openvdb_ax_LIBRARY)
|
||||
set(OPENVDB_openvdb_ax_LIB_TYPE UNKNOWN)
|
||||
if(OPENVDB_USE_STATIC_LIBS)
|
||||
set(OPENVDB_openvdb_ax_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_OPENVDB_openvdb_ax_EXT
|
||||
${OpenVDB_openvdb_ax_LIBRARY} EXT)
|
||||
if(_OPENVDB_openvdb_ax_EXT STREQUAL ".a")
|
||||
set(OPENVDB_openvdb_ax_LIB_TYPE STATIC)
|
||||
elseif(_OPENVDB_openvdb_ax_EXT STREQUAL ".so" OR
|
||||
_OPENVDB_openvdb_ax_EXT STREQUAL ".dylib")
|
||||
set(OPENVDB_openvdb_ax_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT TARGET OpenVDB::openvdb_ax)
|
||||
add_library(OpenVDB::openvdb_ax UNKNOWN IMPORTED)
|
||||
set_target_properties(OpenVDB::openvdb_ax PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_openvdb_ax_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_openvdb_ax_INCLUDE_DIR}"
|
||||
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${LLVM_INCLUDE_DIRS}"
|
||||
INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;${LLVM_LIBS}"
|
||||
INTERFACE_COMPILE_FEATURES cxx_std_14
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# OpenVDB::nanovdb
|
||||
|
||||
if(OpenVDB_nanovdb_LIBRARY)
|
||||
if(NOT TARGET OpenVDB::nanovdb)
|
||||
add_library(OpenVDB::nanovdb INTERFACE IMPORTED)
|
||||
set_target_properties(OpenVDB::nanovdb PROPERTIES
|
||||
IMPORTED_LOCATION "${OpenVDB_nanovdb_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${OpenVDB_nanovdb_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "OpenVDB::openvdb;"
|
||||
INTERFACE_COMPILE_FEATURES cxx_std_14
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(_OPENVDB_VISIBLE_DEPENDENCIES)
|
||||
unset(_OPENVDB_HIDDEN_DEPENDENCIES)
|
||||
@@ -0,0 +1,441 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
FindTBB
|
||||
-------
|
||||
|
||||
Find Tbb include dirs and libraries
|
||||
|
||||
Use this module by invoking find_package with the form::
|
||||
|
||||
find_package(TBB
|
||||
[version] [EXACT] # Minimum or EXACT version
|
||||
[REQUIRED] # Fail with error if Tbb is not found
|
||||
[COMPONENTS <libs>...] # Tbb libraries by their canonical name
|
||||
# e.g. "tbb" for "libtbb"
|
||||
)
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``TBB::tbb``
|
||||
The tbb library target.
|
||||
``TBB::tbbmalloc``
|
||||
The tbbmalloc library target.
|
||||
``TBB::tbbmalloc_proxy``
|
||||
The tbbmalloc_proxy library target.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``Tbb_FOUND``
|
||||
True if the system has the Tbb library.
|
||||
``Tbb_VERSION``
|
||||
The version of the Tbb library which was found.
|
||||
``Tbb_INCLUDE_DIRS``
|
||||
Include directories needed to use Tbb.
|
||||
``Tbb_RELEASE_LIBRARIES``
|
||||
Libraries needed to link to the release version of Tbb.
|
||||
``Tbb_RELEASE_LIBRARY_DIRS``
|
||||
Tbb release library directories.
|
||||
``Tbb_DEBUG_LIBRARIES``
|
||||
Libraries needed to link to the debug version of Tbb.
|
||||
``Tbb_DEBUG_LIBRARY_DIRS``
|
||||
Tbb debug library directories.
|
||||
``TBB_{COMPONENT}_FOUND``
|
||||
True if the system has the named TBB component.
|
||||
|
||||
Deprecated - use [RELEASE|DEBUG] variants:
|
||||
|
||||
``Tbb_LIBRARIES``
|
||||
Libraries needed to link to Tbb.
|
||||
``Tbb_LIBRARY_DIRS``
|
||||
Tbb library directories.
|
||||
|
||||
Cache Variables
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The following cache variables may also be set:
|
||||
|
||||
``Tbb_INCLUDE_DIR``
|
||||
The directory containing ``tbb/tbb_stddef.h``.
|
||||
``Tbb_{COMPONENT}_LIBRARY``
|
||||
Individual component libraries for Tbb. may include target_link_libraries() debug/optimized keywords.
|
||||
``Tbb_{COMPONENT}_LIBRARY_RELEASE``
|
||||
Individual component libraries for Tbb release
|
||||
``Tbb_{COMPONENT}_LIBRARY_DEBUG``
|
||||
Individual debug component libraries for Tbb debug
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``TBB_ROOT``
|
||||
Preferred installation prefix.
|
||||
``TBB_INCLUDEDIR``
|
||||
Preferred include directory e.g. <prefix>/include
|
||||
``TBB_LIBRARYDIR``
|
||||
Preferred library directory e.g. <prefix>/lib
|
||||
``TBB_DEBUG_SUFFIX``
|
||||
Suffix of the debug version of tbb. Defaults to "_debug".
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``TBB_USE_STATIC_LIBS``
|
||||
Only search for static tbb libraries
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
mark_as_advanced(
|
||||
Tbb_INCLUDE_DIR
|
||||
Tbb_LIBRARY
|
||||
)
|
||||
|
||||
set(_FIND_TBB_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_TBB_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
set(_TBB_COMPONENT_LIST
|
||||
tbb
|
||||
tbbmalloc
|
||||
tbbmalloc_proxy
|
||||
)
|
||||
|
||||
if(TBB_FIND_COMPONENTS)
|
||||
set(_TBB_COMPONENTS_PROVIDED TRUE)
|
||||
set(_IGNORED_COMPONENTS "")
|
||||
foreach(COMPONENT ${TBB_FIND_COMPONENTS})
|
||||
if(NOT ${COMPONENT} IN_LIST _TBB_COMPONENT_LIST)
|
||||
list(APPEND _IGNORED_COMPONENTS ${COMPONENT})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(_IGNORED_COMPONENTS)
|
||||
message(STATUS "Ignoring unknown components of TBB:")
|
||||
foreach(COMPONENT ${_IGNORED_COMPONENTS})
|
||||
message(STATUS " ${COMPONENT}")
|
||||
endforeach()
|
||||
list(REMOVE_ITEM TBB_FIND_COMPONENTS ${_IGNORED_COMPONENTS})
|
||||
endif()
|
||||
else()
|
||||
set(_TBB_COMPONENTS_PROVIDED FALSE)
|
||||
set(TBB_FIND_COMPONENTS ${_TBB_COMPONENT_LIST})
|
||||
endif()
|
||||
|
||||
if(TBB_ROOT)
|
||||
set(_TBB_ROOT ${TBB_ROOT})
|
||||
elseif(DEFINED ENV{TBB_ROOT})
|
||||
set(_TBB_ROOT $ENV{TBB_ROOT})
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find Tbb
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_Tbb QUIET tbb)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for tbb include DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_TBB_INCLUDE_SEARCH_DIRS "")
|
||||
list(APPEND _TBB_INCLUDE_SEARCH_DIRS
|
||||
${TBB_INCLUDEDIR}
|
||||
${_TBB_ROOT}
|
||||
${PC_Tbb_INCLUDE_DIRS}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Look for a standard tbb header file.
|
||||
find_path(Tbb_INCLUDE_DIR tbb/tbb_stddef.h
|
||||
${_FIND_TBB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_TBB_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include
|
||||
)
|
||||
|
||||
set(_tbb_version_file "${Tbb_INCLUDE_DIR}/tbb/tbb_stddef.h")
|
||||
|
||||
if(NOT EXISTS ${_tbb_version_file})
|
||||
# From TBB 2021, tbb_stddef is removed and the directory include/tbb is
|
||||
# simply an alias for include/oneapi/tbb. Try and find the version header
|
||||
# in oneapi/tbb
|
||||
find_path(Tbb_INCLUDE_DIR oneapi/tbb/version.h
|
||||
${_FIND_TBB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_TBB_INCLUDE_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_INCLUDEDIR} include
|
||||
)
|
||||
set(_tbb_version_file "${Tbb_INCLUDE_DIR}/oneapi/tbb/version.h")
|
||||
endif()
|
||||
|
||||
if(EXISTS ${_tbb_version_file})
|
||||
file(STRINGS ${_tbb_version_file}
|
||||
_tbb_version_major_string REGEX "#define TBB_VERSION_MAJOR "
|
||||
)
|
||||
string(REGEX REPLACE "#define TBB_VERSION_MAJOR" ""
|
||||
_tbb_version_major_string "${_tbb_version_major_string}"
|
||||
)
|
||||
string(STRIP "${_tbb_version_major_string}" Tbb_VERSION_MAJOR)
|
||||
|
||||
file(STRINGS ${_tbb_version_file}
|
||||
_tbb_version_minor_string REGEX "#define TBB_VERSION_MINOR "
|
||||
)
|
||||
string(REGEX REPLACE "#define TBB_VERSION_MINOR" ""
|
||||
_tbb_version_minor_string "${_tbb_version_minor_string}"
|
||||
)
|
||||
string(STRIP "${_tbb_version_minor_string}" Tbb_VERSION_MINOR)
|
||||
|
||||
unset(_tbb_version_major_string)
|
||||
unset(_tbb_version_minor_string)
|
||||
|
||||
set(Tbb_VERSION ${Tbb_VERSION_MAJOR}.${Tbb_VERSION_MINOR})
|
||||
endif()
|
||||
|
||||
unset(_tbb_version_file)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for TBB lib DIR
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_TBB_LIBRARYDIR_SEARCH_DIRS "")
|
||||
|
||||
# Append to _TBB_LIBRARYDIR_SEARCH_DIRS in priority order
|
||||
|
||||
set(_TBB_LIBRARYDIR_SEARCH_DIRS "")
|
||||
list(APPEND _TBB_LIBRARYDIR_SEARCH_DIRS
|
||||
${TBB_LIBRARYDIR}
|
||||
${_TBB_ROOT}
|
||||
${PC_Tbb_LIBRARY_DIRS}
|
||||
${SYSTEM_LIBRARY_PATHS}
|
||||
)
|
||||
|
||||
# Library suffix handling
|
||||
|
||||
if(NOT DEFINED TBB_DEBUG_SUFFIX)
|
||||
set(TBB_DEBUG_SUFFIX _debug)
|
||||
endif()
|
||||
set(_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
|
||||
if(MSVC)
|
||||
if(TBB_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
|
||||
endif()
|
||||
else()
|
||||
if(TBB_USE_STATIC_LIBS)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(Tbb_LIB_COMPONENTS "")
|
||||
list(APPEND TBB_BUILD_TYPES RELEASE DEBUG)
|
||||
|
||||
foreach(COMPONENT ${TBB_FIND_COMPONENTS})
|
||||
foreach(BUILD_TYPE ${TBB_BUILD_TYPES})
|
||||
|
||||
set(_TBB_LIB_NAME ${COMPONENT})
|
||||
if(BUILD_TYPE STREQUAL DEBUG)
|
||||
set(_TBB_LIB_NAME "${_TBB_LIB_NAME}${TBB_DEBUG_SUFFIX}")
|
||||
endif()
|
||||
|
||||
find_library(Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE} ${_TBB_LIB_NAME}
|
||||
${_FIND_TBB_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_TBB_LIBRARYDIR_SEARCH_DIRS}
|
||||
PATH_SUFFIXES ${CMAKE_INSTALL_LIBDIR} lib64 lib
|
||||
)
|
||||
|
||||
# On Unix, TBB sometimes uses linker scripts instead of symlinks, so parse the linker script
|
||||
# and correct the library name if so
|
||||
if(UNIX AND EXISTS ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
# Ignore files where the first four bytes equals the ELF magic number
|
||||
file(READ ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}} Tbb_${COMPONENT}_HEX OFFSET 0 LIMIT 4 HEX)
|
||||
if(NOT ${Tbb_${COMPONENT}_HEX} STREQUAL "7f454c46")
|
||||
# Read the first 1024 bytes of the library and match against an "INPUT (file)" regex
|
||||
file(READ ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}} Tbb_${COMPONENT}_ASCII OFFSET 0 LIMIT 1024)
|
||||
if("${Tbb_${COMPONENT}_ASCII}" MATCHES "INPUT \\(([^(]+)\\)")
|
||||
# Extract the directory and apply the matched text (in brackets)
|
||||
get_filename_component(Tbb_${COMPONENT}_DIR "${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}}" DIRECTORY)
|
||||
set(Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE} "${Tbb_${COMPONENT}_DIR}/${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(EXISTS ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
list(APPEND Tbb_LIB_COMPONENTS ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
list(APPEND Tbb_LIB_COMPONENTS_${BUILD_TYPE} ${Tbb_${COMPONENT}_LIBRARY_${BUILD_TYPE}})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(Tbb_${COMPONENT}_LIBRARY_DEBUG AND Tbb_${COMPONENT}_LIBRARY_RELEASE)
|
||||
# if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
|
||||
# single-config generators, set optimized and debug libraries
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(_isMultiConfig OR CMAKE_BUILD_TYPE)
|
||||
set(Tbb_${COMPONENT}_LIBRARY optimized ${Tbb_${COMPONENT}_LIBRARY_RELEASE} debug ${Tbb_${COMPONENT}_LIBRARY_DEBUG})
|
||||
else()
|
||||
# For single-config generators where CMAKE_BUILD_TYPE has no value,
|
||||
# just use the release libraries
|
||||
set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif()
|
||||
# FIXME: This probably should be set for both cases
|
||||
set(Tbb_${COMPONENT}_LIBRARIES optimized ${Tbb_${COMPONENT}_LIBRARY_RELEASE} debug ${Tbb_${COMPONENT}_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# if only the release version was found, set the debug variable also to the release version
|
||||
if(Tbb_${COMPONENT}_LIBRARY_RELEASE AND NOT Tbb_${COMPONENT}_LIBRARY_DEBUG)
|
||||
set(Tbb_${COMPONENT}_LIBRARY_DEBUG ${Tbb_${COMPONENT}_LIBRARY_RELEASE})
|
||||
set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_RELEASE})
|
||||
set(Tbb_${COMPONENT}_LIBRARIES ${Tbb_${COMPONENT}_LIBRARY_RELEASE})
|
||||
endif()
|
||||
|
||||
# if only the debug version was found, set the release variable also to the debug version
|
||||
if(Tbb_${COMPONENT}_LIBRARY_DEBUG AND NOT Tbb_${COMPONENT}_LIBRARY_RELEASE)
|
||||
set(Tbb_${COMPONENT}_LIBRARY_RELEASE ${Tbb_${COMPONENT}_LIBRARY_DEBUG})
|
||||
set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_DEBUG})
|
||||
set(Tbb_${COMPONENT}_LIBRARIES ${Tbb_${COMPONENT}_LIBRARY_DEBUG})
|
||||
endif()
|
||||
|
||||
# If the debug & release library ends up being the same, omit the keywords
|
||||
if("${Tbb_${COMPONENT}_LIBRARY_RELEASE}" STREQUAL "${Tbb_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
set(Tbb_${COMPONENT}_LIBRARY ${Tbb_${COMPONENT}_LIBRARY_RELEASE} )
|
||||
set(Tbb_${COMPONENT}_LIBRARIES ${Tbb_${COMPONENT}_LIBRARY_RELEASE} )
|
||||
endif()
|
||||
|
||||
if(Tbb_${COMPONENT}_LIBRARY)
|
||||
set(TBB_${COMPONENT}_FOUND TRUE)
|
||||
else()
|
||||
set(TBB_${COMPONENT}_FOUND FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Reset library suffix
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||
unset(_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set TBB_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(TBB
|
||||
FOUND_VAR TBB_FOUND
|
||||
REQUIRED_VARS
|
||||
Tbb_INCLUDE_DIR
|
||||
Tbb_LIB_COMPONENTS
|
||||
VERSION_VAR Tbb_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
if(NOT TBB_FOUND)
|
||||
if(TBB_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Unable to find TBB")
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Partition release/debug lib vars
|
||||
|
||||
set(Tbb_RELEASE_LIBRARIES "")
|
||||
set(Tbb_RELEASE_LIBRARY_DIRS "")
|
||||
set(Tbb_DEBUG_LIBRARIES "")
|
||||
set(Tbb_DEBUG_LIBRARY_DIRS "")
|
||||
foreach(LIB ${Tbb_LIB_COMPONENTS_RELEASE})
|
||||
get_filename_component(_TBB_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND Tbb_RELEASE_LIBRARIES ${LIB})
|
||||
list(APPEND Tbb_RELEASE_LIBRARY_DIRS ${_TBB_LIBDIR})
|
||||
endforeach()
|
||||
|
||||
foreach(LIB ${Tbb_LIB_COMPONENTS_DEBUG})
|
||||
get_filename_component(_TBB_LIBDIR ${LIB} DIRECTORY)
|
||||
list(APPEND Tbb_DEBUG_LIBRARIES ${LIB})
|
||||
list(APPEND Tbb_DEBUG_LIBRARY_DIRS ${_TBB_LIBDIR})
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES Tbb_RELEASE_LIBRARY_DIRS)
|
||||
list(REMOVE_DUPLICATES Tbb_DEBUG_LIBRARY_DIRS)
|
||||
|
||||
set(Tbb_LIBRARIES ${Tbb_RELEASE_LIBRARIES})
|
||||
set(Tbb_LIBRARY_DIRS ${Tbb_RELEASE_LIBRARY_DIRS})
|
||||
set(Tbb_INCLUDE_DIRS ${Tbb_INCLUDE_DIR})
|
||||
|
||||
# Configure imported targets
|
||||
|
||||
foreach(COMPONENT ${TBB_FIND_COMPONENTS})
|
||||
# Configure lib type. If XXX_USE_STATIC_LIBS, we always assume a static
|
||||
# lib is in use. If win32, we can't mark the import .libs as shared, so
|
||||
# these are always marked as UNKNOWN. Otherwise, infer from extension.
|
||||
set(TBB_${COMPONENT}_LIB_TYPE UNKNOWN)
|
||||
if(TBB_USE_STATIC_LIBS)
|
||||
set(TBB_${COMPONENT}_LIB_TYPE STATIC)
|
||||
elseif(UNIX)
|
||||
get_filename_component(_TBB_${COMPONENT}_EXT ${Tbb_${COMPONENT}_LIBRARY_RELEASE} EXT)
|
||||
if(_TBB_${COMPONENT}_EXT STREQUAL ".a")
|
||||
set(TBB_${COMPONENT}_LIB_TYPE STATIC)
|
||||
elseif(_TBB_${COMPONENT}_EXT STREQUAL ".so" OR
|
||||
_TBB_${COMPONENT}_EXT STREQUAL ".dylib")
|
||||
set(TBB_${COMPONENT}_LIB_TYPE SHARED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(Tbb_${COMPONENT}_DEFINITIONS)
|
||||
|
||||
# Add the TBB linking defines if the library is static on WIN32
|
||||
if(WIN32)
|
||||
if(${COMPONENT} STREQUAL tbb)
|
||||
if(Tbb_${COMPONENT}_LIB_TYPE STREQUAL STATIC)
|
||||
list(APPEND Tbb_${COMPONENT}_DEFINITIONS __TBB_NO_IMPLICIT_LINKAGE=1)
|
||||
endif()
|
||||
else() # tbbmalloc
|
||||
if(Tbb_${COMPONENT}_LIB_TYPE STREQUAL STATIC)
|
||||
list(APPEND Tbb_${COMPONENT}_DEFINITIONS __TBB_MALLOC_NO_IMPLICIT_LINKAGE=1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET TBB::${COMPONENT})
|
||||
add_library(TBB::${COMPONENT} ${TBB_${COMPONENT}_LIB_TYPE} IMPORTED)
|
||||
set_target_properties(TBB::${COMPONENT} PROPERTIES
|
||||
INTERFACE_COMPILE_OPTIONS "${PC_Tbb_CFLAGS_OTHER}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "${Tbb_${COMPONENT}_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Tbb_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_DIRECTORIES "${Tbb_LIBRARY_DIRS}")
|
||||
|
||||
# Standard location
|
||||
set_target_properties(TBB::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
|
||||
IMPORTED_LOCATION "${Tbb_${COMPONENT}_LIBRARY}")
|
||||
|
||||
# Release location
|
||||
if(EXISTS "${Tbb_${COMPONENT}_LIBRARY_RELEASE}")
|
||||
set_property(TARGET TBB::${COMPONENT} APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(TBB::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
|
||||
IMPORTED_LOCATION_RELEASE "${Tbb_${COMPONENT}_LIBRARY_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Debug location
|
||||
if(EXISTS "${Tbb_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
set_property(TARGET TBB::${COMPONENT} APPEND PROPERTY
|
||||
IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(TBB::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX"
|
||||
IMPORTED_LOCATION_DEBUG "${Tbb_${COMPONENT}_LIBRARY_DEBUG}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -0,0 +1,147 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
OpenVDBGLFW3Setup
|
||||
-----------------
|
||||
|
||||
Wraps the call the FindPackage ( glfw3 ) for OpenVDB builds. Provides
|
||||
some extra options for finding the glfw3 installation without polluting
|
||||
the OpenVDB Binaries cmake.
|
||||
|
||||
Use this module by invoking include with the form::
|
||||
|
||||
include ( OpenVDBGLFW3Setup )
|
||||
|
||||
IMPORTED Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``glfw``
|
||||
The glfw3 library target.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``glfw3_FOUND``
|
||||
True if the system has glfw3 installed.
|
||||
``glfw3_VERSION``
|
||||
The version of the glfw3 library which was found.
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
The following variables may be provided to tell this module where to look.
|
||||
|
||||
``GLFW3_ROOT``
|
||||
Preferred installation prefix.
|
||||
``SYSTEM_LIBRARY_PATHS``
|
||||
Global list of library paths intended to be searched by and find_xxx call
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
# Find the glfw3 installation and use glfw's CMake to initialize
|
||||
# the glfw lib
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(_FIND_GLFW3_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_GLFW3_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
set(_GLFW3_ROOT_SEARCH_DIR "")
|
||||
|
||||
if(GLFW3_ROOT)
|
||||
list(APPEND _GLFW3_ROOT_SEARCH_DIR ${GLFW3_ROOT})
|
||||
else()
|
||||
set(_ENV_GLFW_ROOT $ENV{GLFW3_ROOT})
|
||||
if(_ENV_GLFW_ROOT)
|
||||
list(APPEND _GLFW3_ROOT_SEARCH_DIR ${_ENV_GLFW_ROOT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Additionally try and use pkconfig to find glfw, though we only use
|
||||
# pkg-config to re-direct to the cmake. In other words, glfw's cmake is
|
||||
# expected to be installed
|
||||
if(USE_PKGCONFIG)
|
||||
if(NOT DEFINED PKG_CONFIG_FOUND)
|
||||
find_package(PkgConfig)
|
||||
endif()
|
||||
pkg_check_modules(PC_glfw3 QUIET glfw3)
|
||||
endif()
|
||||
|
||||
if(PC_glfw3_FOUND)
|
||||
foreach(DIR ${PC_glfw3_LIBRARY_DIRS})
|
||||
list(APPEND _GLFW3_ROOT_SEARCH_DIR ${DIR})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
list(APPEND _GLFW3_ROOT_SEARCH_DIR ${SYSTEM_LIBRARY_PATHS})
|
||||
|
||||
set(_GLFW3_PATH_SUFFIXES "lib/cmake/glfw3" "cmake/glfw3" "glfw3")
|
||||
|
||||
# GLFW 3.1 installs CMake modules into glfw instead of glfw3
|
||||
list(APPEND _GLFW3_PATH_SUFFIXES "lib/cmake/glfw" "cmake/glfw" "glfw")
|
||||
|
||||
find_path(GLFW3_CMAKE_LOCATION glfw3Config.cmake
|
||||
${_FIND_GLFW3_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_GLFW3_ROOT_SEARCH_DIR}
|
||||
PATH_SUFFIXES ${_GLFW3_PATH_SUFFIXES}
|
||||
)
|
||||
|
||||
if(GLFW3_CMAKE_LOCATION)
|
||||
if(EXISTS "${GLFW3_CMAKE_LOCATION}/glfw3Targets.cmake")
|
||||
include("${GLFW3_CMAKE_LOCATION}/glfw3Targets.cmake")
|
||||
elseif(EXISTS "${GLFW3_CMAKE_LOCATION}/glfwTargets.cmake")
|
||||
include("${GLFW3_CMAKE_LOCATION}/glfwTargets.cmake")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(GLFW3_CMAKE_LOCATION)
|
||||
list(APPEND CMAKE_PREFIX_PATH "${GLFW3_CMAKE_LOCATION}")
|
||||
endif()
|
||||
|
||||
set(glfw3_FIND_VERSION ${MINIMUM_GLFW_VERSION})
|
||||
find_package(glfw3 ${MINIMUM_GLFW_VERSION} REQUIRED)
|
||||
|
||||
# We only use find_package_handle_standard_args to verify and print
|
||||
# appropriate messages. This now explicitly errors in 3.19...
|
||||
# @todo Improve this entire GLFW3 search
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/21505
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.19)
|
||||
find_package(PackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(glfw3
|
||||
REQUIRED_VARS glfw3_DIR glfw3_FOUND
|
||||
VERSION_VAR glfw3_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
unset(glfw3_FIND_VERSION)
|
||||
|
||||
# GLFW 3.1 does not export INTERFACE_LINK_LIBRARIES so detect this
|
||||
# version and set the property ourselves
|
||||
# @todo investigate how this might apply for Mac OSX
|
||||
if(UNIX)
|
||||
if(glfw3_VERSION VERSION_LESS 3.2)
|
||||
message(WARNING "GLFW 3.1 does not set the INTERFACE_LINK_LIBRARIES property, "
|
||||
"hard-coding to expect a dependency on X11. To use a different "
|
||||
"library dependency, consider upgrading to GLFW 3.2+ where this "
|
||||
"property is set by the CMake find package module for GLFW.")
|
||||
find_package(X11 REQUIRED)
|
||||
set_property(TARGET glfw
|
||||
PROPERTY INTERFACE_LINK_LIBRARIES
|
||||
${X11_Xrandr_LIB}
|
||||
${X11_Xxf86vm_LIB}
|
||||
${X11_Xcursor_LIB}
|
||||
${X11_Xinerama_LIB}
|
||||
${X11_Xi_LIB}
|
||||
${X11_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,419 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
OpenVDBHoudiniSetup
|
||||
-------------------
|
||||
|
||||
Wraps the call the FindPackage ( Houdini ) for OpenVDB builds. This
|
||||
ensures that all dependencies that are included with a Houdini
|
||||
distribution are configured to load from that installation.
|
||||
|
||||
This CMake searches for the HoudiniConfig.cmake module provided by
|
||||
SideFX to configure the OpenVDB Houdini base and DSO libraries. Users
|
||||
can provide paths to the location of their Houdini Installation by
|
||||
setting HOUDINI_ROOT either as an environment variable or by passing it
|
||||
to CMake. This module also reads the value of $HFS, usually set by
|
||||
sourcing the Houdini Environment. Note that as long as you provide a
|
||||
path to your Houdini Installation you do not need to source the
|
||||
Houdini Environment.
|
||||
|
||||
Use this module by invoking include with the form::
|
||||
|
||||
include ( OpenVDBHoudiniSetup )
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``Houdini_FOUND``
|
||||
True if the system has Houdini installed.
|
||||
``Houdini_VERSION``
|
||||
The version of the Houdini which was found.
|
||||
``OPENVDB_HOUDINI_ABI``
|
||||
The ABI version that Houdini uses for it's own OpenVDB installation.
|
||||
``HOUDINI_INCLUDE_DIR``
|
||||
The Houdini include directory.
|
||||
``HOUDINI_LIB_DIR``
|
||||
The Houdini lib directory.
|
||||
|
||||
A variety of variables will also be set from HoudiniConfig.cmake.
|
||||
|
||||
Additionally, the following values are set for all dependent OpenVDB
|
||||
builds, ensuring they link against the correct libraries. This may
|
||||
overwrite user provided values.
|
||||
|
||||
``ZLIB_ROOT``
|
||||
``ZLIB_LIBRARY``
|
||||
``OPENEXR_INCLUDEDIR``
|
||||
``OPENEXR_LIBRARYDIR``
|
||||
``ILMBASE_INCLUDEDIR``
|
||||
``ILMBASE_LIBRARYDIR``
|
||||
``TBB_INCLUDEDIR``
|
||||
``TBB_LIBRARYDIR``
|
||||
``BLOSC_INCLUDEDIR``
|
||||
``BLOSC_LIBRARYDIR``
|
||||
``JEMALLOC_LIBRARYDIR``
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following variables
|
||||
may be provided to tell this module where to look.
|
||||
|
||||
``ENV{HFS}``
|
||||
Preferred installation prefix.
|
||||
``Houdini_ROOT``
|
||||
Preferred installation prefix.
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
# Find the Houdini installation and use Houdini's CMake to initialize
|
||||
# the Houdini lib
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# Include utility functions for version information
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/OpenVDBUtils.cmake)
|
||||
|
||||
set(_FIND_HOUDINI_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_HOUDINI_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
# Set _HOUDINI_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV HOUDINI_ROOT from CMake 3.12
|
||||
if(Houdini_ROOT)
|
||||
set(_HOUDINI_ROOT ${Houdini_ROOT})
|
||||
elseif(DEFINED ENV{Houdini_ROOT})
|
||||
set(_HOUDINI_ROOT $ENV{Houdini_ROOT})
|
||||
elseif(HOUDINI_ROOT)
|
||||
set(_HOUDINI_ROOT ${HOUDINI_ROOT})
|
||||
elseif(DEFINED ENV{HOUDINI_ROOT})
|
||||
set(_HOUDINI_ROOT $ENV{HOUDINI_ROOT})
|
||||
endif()
|
||||
|
||||
set(_HOUDINI_ROOT_SEARCH_DIR)
|
||||
|
||||
if(_HOUDINI_ROOT)
|
||||
list(APPEND _HOUDINI_ROOT_SEARCH_DIR ${_HOUDINI_ROOT})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{HFS})
|
||||
list(APPEND _HOUDINI_ROOT_SEARCH_DIR $ENV{HFS})
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for Houdini
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(_HOUDINI_CMAKE_PATH_SUFFIXES)
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND _HOUDINI_CMAKE_PATH_SUFFIXES
|
||||
Frameworks/Houdini.framework/Versions/Current/Resources/toolkit/cmake
|
||||
Houdini.framework/Versions/Current/Resources/toolkit/cmake
|
||||
Versions/Current/Resources/toolkit/cmake
|
||||
Current/Resources/toolkit/cmake
|
||||
Resources/toolkit/cmake
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND _HOUDINI_CMAKE_PATH_SUFFIXES
|
||||
toolkit/cmake
|
||||
cmake
|
||||
)
|
||||
|
||||
find_package(Houdini
|
||||
${_FIND_HOUDINI_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_HOUDINI_ROOT_SEARCH_DIR}
|
||||
PATH_SUFFIXES ${_HOUDINI_CMAKE_PATH_SUFFIXES}
|
||||
REQUIRED)
|
||||
|
||||
# Note that passing MINIMUM_HOUDINI_VERSION into find_package(Houdini) doesn't work
|
||||
if(NOT Houdini_FOUND)
|
||||
message(FATAL_ERROR "Unable to locate Houdini Installation.")
|
||||
elseif(MINIMUM_HOUDINI_VERSION)
|
||||
if(Houdini_VERSION VERSION_LESS MINIMUM_HOUDINI_VERSION)
|
||||
message(FATAL_ERROR "Unsupported Houdini Version ${Houdini_VERSION}. Minimum "
|
||||
"supported is ${MINIMUM_HOUDINI_VERSION}."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(Houdini_VERSION_MAJOR_MINOR "${Houdini_VERSION_MAJOR}.${Houdini_VERSION_MINOR}")
|
||||
|
||||
find_package(PackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Houdini
|
||||
REQUIRED_VARS _houdini_install_root Houdini_FOUND
|
||||
VERSION_VAR Houdini_VERSION
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Add support for older versions of Houdini
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_HOUDINI_VERSION)
|
||||
if(Houdini_VERSION VERSION_LESS ${FUTURE_MINIMUM_HOUDINI_VERSION})
|
||||
message(DEPRECATION "Support for Houdini versions < ${FUTURE_MINIMUM_HOUDINI_VERSION} "
|
||||
"is deprecated and will be removed.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure imported Houdini target
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# Set the relative directory containing Houdini libs and populate an extra list
|
||||
# of Houdini dependencies for _houdini_create_libraries.
|
||||
|
||||
if(NOT HOUDINI_DSOLIB_DIR)
|
||||
if(APPLE)
|
||||
set(HOUDINI_DSOLIB_DIR Frameworks/Houdini.framework/Versions/Current/Libraries)
|
||||
elseif(UNIX)
|
||||
set(HOUDINI_DSOLIB_DIR dsolib)
|
||||
elseif(WIN32)
|
||||
set(HOUDINI_DSOLIB_DIR custom/houdini/dsolib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(_HOUDINI_EXTRA_LIBRARIES)
|
||||
set(_HOUDINI_EXTRA_LIBRARY_NAMES)
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARIES
|
||||
${HOUDINI_DSOLIB_DIR}/libHoudiniRAY.dylib
|
||||
${HOUDINI_DSOLIB_DIR}/libhboost_regex.dylib
|
||||
${HOUDINI_DSOLIB_DIR}/libhboost_thread.dylib
|
||||
)
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARY_NAMES
|
||||
HoudiniRAY
|
||||
hboost_regex
|
||||
hboost_thread
|
||||
)
|
||||
elseif(UNIX)
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARIES
|
||||
${HOUDINI_DSOLIB_DIR}/libHoudiniRAY.so
|
||||
${HOUDINI_DSOLIB_DIR}/libhboost_regex.so
|
||||
${HOUDINI_DSOLIB_DIR}/libhboost_thread.so
|
||||
)
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARY_NAMES
|
||||
HoudiniRAY
|
||||
hboost_regex
|
||||
hboost_thread
|
||||
)
|
||||
elseif(WIN32)
|
||||
#libRAY is already included by houdini for windows builds
|
||||
if(Houdini_VERSION VERSION_LESS 18.5)
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARIES
|
||||
${HOUDINI_DSOLIB_DIR}/hboost_regex-mt.lib
|
||||
${HOUDINI_DSOLIB_DIR}/hboost_thread-mt.lib
|
||||
)
|
||||
else()
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARIES
|
||||
${HOUDINI_DSOLIB_DIR}/hboost_regex-mt-x64.lib
|
||||
${HOUDINI_DSOLIB_DIR}/hboost_thread-mt-x64.lib
|
||||
)
|
||||
endif()
|
||||
list(APPEND _HOUDINI_EXTRA_LIBRARY_NAMES
|
||||
hboost_regex
|
||||
hboost_thread
|
||||
)
|
||||
endif()
|
||||
|
||||
# Additionally link extra deps
|
||||
|
||||
_houdini_create_libraries(
|
||||
PATHS ${_HOUDINI_EXTRA_LIBRARIES}
|
||||
TARGET_NAMES ${_HOUDINI_EXTRA_LIBRARY_NAMES}
|
||||
TYPE SHARED
|
||||
)
|
||||
|
||||
unset(_HOUDINI_EXTRA_LIBRARIES)
|
||||
unset(_HOUDINI_EXTRA_LIBRARY_NAMES)
|
||||
|
||||
# Set Houdini lib and include directories
|
||||
|
||||
set(HOUDINI_INCLUDE_DIR ${_houdini_include_dir})
|
||||
set(HOUDINI_LIB_DIR ${_houdini_install_root}/${HOUDINI_DSOLIB_DIR})
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure dependencies
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# Congfigure dependency hints to point to Houdini. Allow for user overriding
|
||||
# if custom Houdini installations are in use
|
||||
|
||||
# ZLIB - FindPackage ( ZLIB) only supports a few path hints. We use
|
||||
# ZLIB_ROOT to find the zlib includes and explicitly set the path to
|
||||
# the zlib library
|
||||
|
||||
if(NOT ZLIB_ROOT)
|
||||
set(ZLIB_ROOT ${HOUDINI_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT ZLIB_LIBRARY)
|
||||
# Full path to zlib library - FindPackage ( ZLIB)
|
||||
find_library(ZLIB_LIBRARY z
|
||||
${_FIND_HOUDINI_ADDITIONAL_OPTIONS}
|
||||
PATHS ${HOUDINI_LIB_DIR}
|
||||
)
|
||||
if(NOT EXISTS ${ZLIB_LIBRARY})
|
||||
message(WARNING "The OpenVDB Houdini CMake setup is unable to locate libz within "
|
||||
"the Houdini installation at: ${HOUDINI_LIB_DIR}. OpenVDB may not build correctly."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TBB
|
||||
|
||||
if(NOT TBB_INCLUDEDIR)
|
||||
set(TBB_INCLUDEDIR ${HOUDINI_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT TBB_LIBRARYDIR)
|
||||
set(TBB_LIBRARYDIR ${HOUDINI_LIB_DIR})
|
||||
endif()
|
||||
|
||||
# Blosc
|
||||
|
||||
if(NOT BLOSC_INCLUDEDIR)
|
||||
set(BLOSC_INCLUDEDIR ${HOUDINI_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT BLOSC_LIBRARYDIR)
|
||||
set(BLOSC_LIBRARYDIR ${HOUDINI_LIB_DIR})
|
||||
endif()
|
||||
|
||||
# Jemalloc
|
||||
|
||||
if(NOT JEMALLOC_LIBRARYDIR)
|
||||
set(JEMALLOC_LIBRARYDIR ${HOUDINI_LIB_DIR})
|
||||
endif()
|
||||
|
||||
# OpenEXR
|
||||
|
||||
if(NOT OPENEXR_INCLUDEDIR)
|
||||
set(OPENEXR_INCLUDEDIR ${HOUDINI_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT OPENEXR_LIBRARYDIR)
|
||||
set(OPENEXR_LIBRARYDIR ${HOUDINI_LIB_DIR})
|
||||
endif()
|
||||
|
||||
# IlmBase
|
||||
|
||||
if(NOT ILMBASE_INCLUDEDIR)
|
||||
set(ILMBASE_INCLUDEDIR ${HOUDINI_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT ILMBASE_LIBRARYDIR)
|
||||
set(ILMBASE_LIBRARYDIR ${HOUDINI_LIB_DIR})
|
||||
endif()
|
||||
|
||||
# Boost - currently must be provided as VDB is not fully configured to
|
||||
# use Houdini's namespaced hboost
|
||||
|
||||
# Versions of Houdini >= 17.5 have some namespaced libraries (IlmBase/OpenEXR).
|
||||
# Add the required suffix as part of the cmake lib suffix searches
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_sidefx.dylib")
|
||||
elseif(UNIX)
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_sidefx.so")
|
||||
elseif(WIN32)
|
||||
list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES "_sidefx.lib")
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure OpenVDB ABI
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# Explicitly configure the OpenVDB ABI version depending on the Houdini
|
||||
# version.
|
||||
|
||||
if(Houdini_VERSION_MAJOR_MINOR VERSION_EQUAL 18.5)
|
||||
set(OPENVDB_HOUDINI_ABI 7)
|
||||
else()
|
||||
find_file(_houdini_openvdb_version_file "openvdb/version.h"
|
||||
PATHS ${HOUDINI_INCLUDE_DIR}
|
||||
NO_DEFAULT_PATH)
|
||||
if(_houdini_openvdb_version_file)
|
||||
OPENVDB_VERSION_FROM_HEADER("${_houdini_openvdb_version_file}"
|
||||
ABI OPENVDB_HOUDINI_ABI)
|
||||
endif()
|
||||
unset(_houdini_openvdb_version_file)
|
||||
if(NOT OPENVDB_HOUDINI_ABI)
|
||||
message(WARNING "Unknown version of Houdini, assuming OpenVDB ABI=${OpenVDB_MAJOR_VERSION}, "
|
||||
"but if this not correct, the CMake flag -DOPENVDB_HOUDINI_ABI=<N> can override this value.")
|
||||
set(OPENVDB_HOUDINI_ABI ${OpenVDB_MAJOR_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure GCC CXX11 ABI
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if((CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.1) OR
|
||||
(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.1))
|
||||
message(STATUS "GCC >= 5.1 detected. Configuring GCC CXX11 ABI for Houdini compatibility...")
|
||||
|
||||
execute_process(COMMAND echo "#include <string>"
|
||||
COMMAND ${CMAKE_CXX_COMPILER} "-x" "c++" "-E" "-dM" "-"
|
||||
COMMAND grep "-F" "_GLIBCXX_USE_CXX11_ABI"
|
||||
TIMEOUT 10
|
||||
RESULT_VARIABLE QUERIED_GCC_CXX11_ABI_SUCCESS
|
||||
OUTPUT_VARIABLE _GCC_CXX11_ABI)
|
||||
|
||||
set(GLIBCXX_USE_CXX11_ABI "UNKNOWN")
|
||||
|
||||
if(NOT QUERIED_GCC_CXX11_ABI_SUCCESS)
|
||||
string(FIND ${_GCC_CXX11_ABI} "_GLIBCXX_USE_CXX11_ABI 0" GCC_OLD_CXX11_ABI)
|
||||
string(FIND ${_GCC_CXX11_ABI} "_GLIBCXX_USE_CXX11_ABI 1" GCC_NEW_CXX11_ABI)
|
||||
if(NOT (${GCC_OLD_CXX11_ABI} EQUAL -1))
|
||||
set(GLIBCXX_USE_CXX11_ABI 0)
|
||||
endif()
|
||||
if(NOT (${GCC_NEW_CXX11_ABI} EQUAL -1))
|
||||
set(GLIBCXX_USE_CXX11_ABI 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Try and query the Houdini CXX11 ABI. Allow it to be provided by users to
|
||||
# override this logic should Houdini's CMake ever change
|
||||
|
||||
if(NOT DEFINED HOUDINI_CXX11_ABI)
|
||||
get_target_property(houdini_interface_compile_options
|
||||
Houdini INTERFACE_COMPILE_OPTIONS)
|
||||
set(HOUDINI_CXX11_ABI "UNKNOWN")
|
||||
if("-D_GLIBCXX_USE_CXX11_ABI=0" IN_LIST houdini_interface_compile_options)
|
||||
set(HOUDINI_CXX11_ABI 0)
|
||||
elseif("-D_GLIBCXX_USE_CXX11_ABI=1" IN_LIST houdini_interface_compile_options)
|
||||
set(HOUDINI_CXX11_ABI 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS " GCC CXX11 ABI : ${GLIBCXX_USE_CXX11_ABI}")
|
||||
message(STATUS " Houdini CXX11 ABI : ${HOUDINI_CXX11_ABI}")
|
||||
|
||||
if(${HOUDINI_CXX11_ABI} STREQUAL "UNKNOWN")
|
||||
message(WARNING "Unable to determine Houdini CXX11 ABI. Assuming newer ABI "
|
||||
"has been used.")
|
||||
set(HOUDINI_CXX11_ABI 1)
|
||||
endif()
|
||||
|
||||
if(${GLIBCXX_USE_CXX11_ABI} EQUAL ${HOUDINI_CXX11_ABI})
|
||||
message(STATUS " Current CXX11 ABI matches Houdini configuration "
|
||||
"(_GLIBCXX_USE_CXX11_ABI=${HOUDINI_CXX11_ABI}).")
|
||||
else()
|
||||
message(WARNING "A potential mismatch was detected between the CXX11 ABI "
|
||||
"of GCC and Houdini. The following ABI configuration will be used: "
|
||||
"-D_GLIBCXX_USE_CXX11_ABI=${HOUDINI_CXX11_ABI}. See: "
|
||||
"https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html and "
|
||||
"https://vfxplatform.com/#footnote-gcc6 for more information.")
|
||||
endif()
|
||||
|
||||
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=${HOUDINI_CXX11_ABI})
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,253 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
OpenVDBMayaSetup
|
||||
-------------------
|
||||
|
||||
Finds the Maya installation and sets up dependencies for OpenVDB builds.
|
||||
This ensures that all dependencies that are included with a Maya
|
||||
distribution are configured to load from that installation.
|
||||
|
||||
Use this module by invoking include with the form::
|
||||
|
||||
include ( OpenVDBMayaSetup )
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``Maya_FOUND``
|
||||
True if the system has Maya installed.
|
||||
``Maya_VERSION``
|
||||
The version of the Maya which was found.
|
||||
|
||||
Additionally, the following values are set for all dependent OpenVDB
|
||||
builds, ensuring they link against the correct libraries. This may
|
||||
overwrite user provided values.
|
||||
|
||||
``TBB_INCLUDEDIR``
|
||||
``TBB_LIBRARYDIR``
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
Instead of explicitly setting the cache variables, the following
|
||||
variables may be provided to tell this module where to look.
|
||||
|
||||
``Maya_ROOT``
|
||||
Preferred installation prefix.
|
||||
``ENV{Maya_ROOT}``
|
||||
Preferred installation prefix.
|
||||
``ENV{MAYA_LOCATION}``
|
||||
Preferred installation prefix.
|
||||
``DISABLE_CMAKE_SEARCH_PATHS``
|
||||
Disable CMakes default search paths for find_xxx calls in this module
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
# Find the Maya installation and use Maya's CMake to initialize
|
||||
# the Maya lib
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
|
||||
set(_FIND_MAYA_ADDITIONAL_OPTIONS "")
|
||||
if(DISABLE_CMAKE_SEARCH_PATHS)
|
||||
set(_FIND_MAYA_ADDITIONAL_OPTIONS NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
# Set _MAYA_ROOT based on a user provided root var. Xxx_ROOT and ENV{Xxx_ROOT}
|
||||
# are prioritised over the legacy capitalized XXX_ROOT variables for matching
|
||||
# CMake 3.12 behaviour
|
||||
# @todo deprecate -D and ENV MAYA_ROOT from CMake 3.12
|
||||
if(Maya_ROOT)
|
||||
set(_MAYA_ROOT ${Maya_ROOT})
|
||||
elseif(DEFINED ENV{Maya_ROOT})
|
||||
set(_MAYA_ROOT $ENV{Maya_ROOT})
|
||||
elseif(MAYA_ROOT)
|
||||
set(_MAYA_ROOT ${MAYA_ROOT})
|
||||
elseif(DEFINED ENV{MAYA_ROOT})
|
||||
set(_MAYA_ROOT $ENV{MAYA_ROOT})
|
||||
endif()
|
||||
|
||||
set(_MAYA_ROOT_SEARCH_DIR)
|
||||
if(_MAYA_ROOT)
|
||||
list(APPEND _MAYA_ROOT_SEARCH_DIR ${_MAYA_ROOT})
|
||||
endif()
|
||||
|
||||
# @todo deprecate MAYA_LOCATION? There may be workflows which set this variable
|
||||
if(DEFINED ENV{MAYA_LOCATION})
|
||||
list(APPEND _MAYA_ROOT_SEARCH_DIR $ENV{MAYA_LOCATION})
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Search for Maya
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
find_path(Maya_INCLUDE_DIR maya/MTypes.h
|
||||
${_FIND_MAYA_ADDITIONAL_OPTIONS}
|
||||
PATHS ${_MAYA_ROOT_SEARCH_DIR}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
if(NOT EXISTS "${Maya_INCLUDE_DIR}/maya/MTypes.h")
|
||||
message(FATAL_ERROR "Unable to locate Maya Installation.")
|
||||
endif()
|
||||
|
||||
# Determine Maya version, including point releases. Currently only works for
|
||||
# Maya 2016 and onwards so there is no -x64 and -x32 suffixes in the version
|
||||
file(STRINGS "${Maya_INCLUDE_DIR}/maya/MTypes.h"
|
||||
_maya_version_string REGEX "#define MAYA_API_VERSION "
|
||||
)
|
||||
string(REGEX REPLACE ".*#define[ \t]+MAYA_API_VERSION[ \t]+([0-9]+).*$" "\\1"
|
||||
_maya_version_string "${_maya_version_string}"
|
||||
)
|
||||
string(SUBSTRING ${_maya_version_string} 0 4 Maya_MAJOR_VERSION)
|
||||
string(SUBSTRING ${_maya_version_string} 4 2 Maya_MINOR_VERSION)
|
||||
|
||||
if(Maya_MINOR_VERSION LESS 50)
|
||||
set(Maya_VERSION ${Maya_MAJOR_VERSION})
|
||||
else()
|
||||
set(Maya_VERSION ${Maya_MAJOR_VERSION}.5)
|
||||
endif()
|
||||
unset(_maya_version_string)
|
||||
|
||||
# Find required maya libs
|
||||
|
||||
set(_MAYA_COMPONENT_LIST
|
||||
OpenMaya
|
||||
OpenMayaFX
|
||||
OpenMayaUI
|
||||
Foundation
|
||||
)
|
||||
|
||||
set(Maya_LIBRARY_DIR "")
|
||||
if(APPLE)
|
||||
set(Maya_LIBRARY_DIR ${Maya_INCLUDE_DIR}/../Maya.app/Contents/MacOS/)
|
||||
else()
|
||||
set(Maya_LIBRARY_DIR ${Maya_INCLUDE_DIR}/../lib/)
|
||||
endif()
|
||||
|
||||
set(Maya_LIB_COMPONENTS "")
|
||||
|
||||
foreach(COMPONENT ${_MAYA_COMPONENT_LIST})
|
||||
find_library(Maya_${COMPONENT}_LIBRARY ${COMPONENT}
|
||||
${_FIND_MAYA_ADDITIONAL_OPTIONS}
|
||||
PATHS ${Maya_LIBRARY_DIR}
|
||||
)
|
||||
list(APPEND Maya_LIB_COMPONENTS ${Maya_${COMPONENT}_LIBRARY})
|
||||
endforeach()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Cache and set Maya_FOUND
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Maya
|
||||
FOUND_VAR Maya_FOUND
|
||||
REQUIRED_VARS
|
||||
Maya_INCLUDE_DIR
|
||||
Maya_LIB_COMPONENTS
|
||||
VERSION_VAR Maya_VERSION
|
||||
)
|
||||
|
||||
if(NOT Maya_FOUND)
|
||||
message(FATAL_ERROR "Unable to locate Maya Installation.")
|
||||
elseif(Maya_VERSION VERSION_LESS MINIMUM_MAYA_VERSION)
|
||||
message(WARNING "Unsupported Maya Version ${Maya_VERSION}. Minimum "
|
||||
"supported is ${MINIMUM_MAYA_VERSION}."
|
||||
)
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure dependencies
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
if(NOT TBB_INCLUDEDIR)
|
||||
set(TBB_INCLUDEDIR ${Maya_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT TBB_LIBRARYDIR)
|
||||
set(TBB_LIBRARYDIR ${Maya_LIBRARY_DIR})
|
||||
endif()
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Configure Maya
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
set(Maya_LIBRARIES ${Maya_LIB_COMPONENTS})
|
||||
set(Maya_INCLUDE_DIRS ${Maya_INCLUDE_DIR})
|
||||
set(Maya_LIBRARY_DIRS ${Maya_LIBRARY_DIR})
|
||||
|
||||
if(APPLE)
|
||||
set(Maya_DEFINITIONS
|
||||
-DMAC_PLUGIN
|
||||
-DREQUIRE_IOSTREAM
|
||||
-DOSMac_
|
||||
-DOSMac_MachO_
|
||||
-D_BOOL
|
||||
)
|
||||
elseif(WIN32)
|
||||
set(Maya_DEFINITIONS
|
||||
-DNOMINMAX
|
||||
-DNT_PLUGIN
|
||||
-DREQUIRE_IOSTREAM
|
||||
-D_USE_MATH_DEFINES
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
else()
|
||||
set(Maya_DEFINITIONS
|
||||
-D_BOOL
|
||||
-DFUNCPROTO
|
||||
-DGL_GLEXT_PROTOTYPES=1
|
||||
-DREQUIRE_IOSTREAM
|
||||
-DUNIX
|
||||
-fno-gnu-keywords
|
||||
-fno-omit-frame-pointer
|
||||
-fno-strict-aliasing
|
||||
-funsigned-char
|
||||
-Wno-comment
|
||||
-Wno-multichar
|
||||
-Wno-strict-aliasing
|
||||
-m64
|
||||
-DBits64_
|
||||
-DLINUX
|
||||
-DLINUX_64
|
||||
)
|
||||
endif()
|
||||
|
||||
# Configure imported targets
|
||||
|
||||
if(NOT TARGET Maya)
|
||||
add_library(Maya INTERFACE)
|
||||
foreach(COMPONENT ${_MAYA_COMPONENT_LIST})
|
||||
add_library(Maya::${COMPONENT} UNKNOWN IMPORTED)
|
||||
set_target_properties(Maya::${COMPONENT} PROPERTIES
|
||||
IMPORTED_LOCATION "${Maya_${COMPONENT}_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${Maya_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Maya_INCLUDE_DIRS}"
|
||||
)
|
||||
target_link_libraries(Maya INTERFACE Maya::${COMPONENT})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
macro(MAYA_SET_LIBRARY_PROPERTIES NAME)
|
||||
if(WIN32)
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
SUFFIX ".mll"
|
||||
PREFIX ""
|
||||
LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin"
|
||||
)
|
||||
elseif(APPLE)
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
SUFFIX ".bundle"
|
||||
PREFIX ""
|
||||
)
|
||||
else()
|
||||
set_target_properties(${NAME} PROPERTIES
|
||||
PREFIX ""
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -0,0 +1,164 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
OpenVDBUtils.cmake
|
||||
------------------
|
||||
|
||||
A utility CMake file which provides helper functions for configuring an
|
||||
OpenVDB installation.
|
||||
|
||||
Use this module by invoking include with the form::
|
||||
|
||||
include ( OpenVDBUtils )
|
||||
|
||||
|
||||
The following functions are provided:
|
||||
|
||||
``OPENVDB_GET_VERSION_DEFINE``
|
||||
|
||||
OPENVDB_GET_VERSION_DEFINE ( <header_path> <key> <value> )
|
||||
|
||||
Parse the provided version file to retrieve the a given OpenVDB define
|
||||
specified by <key> and store the result in <value>. If the define has a
|
||||
value, the value is stored. If the define has no value but exists, ON is
|
||||
stored. Else, OFF is stored.
|
||||
|
||||
If the file does not exist, <value> is unmodified.
|
||||
|
||||
``OPENVDB_VERSION_FROM_HEADER``
|
||||
|
||||
OPENVDB_VERSION_FROM_HEADER ( <header_path>
|
||||
VERSION [<version>]
|
||||
MAJOR [<version>]
|
||||
MINOR [<version>]
|
||||
PATCH [<version>] )
|
||||
|
||||
Parse the provided version file to retrieve the current OpenVDB
|
||||
version information. The file is expected to be a version.h file
|
||||
as found in the following path of an OpenVDB repository:
|
||||
openvdb/version.h
|
||||
|
||||
If the file does not exist, variables are unmodified.
|
||||
|
||||
``OPENVDB_ABI_VERSION_FROM_PRINT``
|
||||
|
||||
OPENVDB_ABI_VERSION_FROM_PRINT ( <vdb_print>
|
||||
[QUIET]
|
||||
ABI [<version>] )
|
||||
|
||||
Retrieve the ABI version that an installation of OpenVDB was compiled
|
||||
for using the provided vdb_print binary. Parses the result of:
|
||||
vdb_print --version
|
||||
|
||||
If the binary does not exist or fails to launch, variables are
|
||||
unmodified.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
|
||||
function(OPENVDB_GET_VERSION_DEFINE HEADER KEY VALUE)
|
||||
if(NOT EXISTS ${HEADER})
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(STRINGS "${HEADER}" details REGEX "^#define[\t ]+${KEY}[\t ]+.*")
|
||||
if(details)
|
||||
# define has a value, extract it and return
|
||||
string(REGEX REPLACE "^.*${KEY}[\t ]+([0-9]*).*$" "\\1" details "${details}")
|
||||
set(${VALUE} ${details} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# try re-searching for single defines
|
||||
file(STRINGS "${HEADER}" details REGEX "^#define[\t ]+${KEY}.*")
|
||||
if(details)
|
||||
set(${VALUE} ON PARENT_SCOPE)
|
||||
else()
|
||||
set(${VALUE} OFF PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
########################################################################
|
||||
########################################################################
|
||||
|
||||
|
||||
function(OPENVDB_VERSION_FROM_HEADER OPENVDB_VERSION_FILE)
|
||||
cmake_parse_arguments(_VDB "" "VERSION;MAJOR;MINOR;PATCH;ABI" "" ${ARGN})
|
||||
|
||||
if(NOT EXISTS ${OPENVDB_VERSION_FILE})
|
||||
return()
|
||||
endif()
|
||||
|
||||
OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER" _OpenVDB_MAJOR_VERSION)
|
||||
OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_LIBRARY_MINOR_VERSION_NUMBER" _OpenVDB_MINOR_VERSION)
|
||||
OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_LIBRARY_PATCH_VERSION_NUMBER" _OpenVDB_PATCH_VERSION)
|
||||
OPENVDB_GET_VERSION_DEFINE(${OPENVDB_VERSION_FILE} "OPENVDB_ABI_VERSION_NUMBER" _OpenVDB_ABI_VERSION)
|
||||
|
||||
if(_VDB_VERSION)
|
||||
set(${_VDB_VERSION}
|
||||
${_OpenVDB_MAJOR_VERSION}.${_OpenVDB_MINOR_VERSION}.${_OpenVDB_PATCH_VERSION}
|
||||
PARENT_SCOPE
|
||||
)
|
||||
endif()
|
||||
if(_VDB_MAJOR)
|
||||
set(${_VDB_MAJOR} ${_OpenVDB_MAJOR_VERSION} PARENT_SCOPE)
|
||||
endif()
|
||||
if(_VDB_MINOR)
|
||||
set(${_VDB_MINOR} ${_OpenVDB_MINOR_VERSION} PARENT_SCOPE)
|
||||
endif()
|
||||
if(_VDB_PATCH)
|
||||
set(${_VDB_PATCH} ${_OpenVDB_PATCH_VERSION} PARENT_SCOPE)
|
||||
endif()
|
||||
if(_VDB_ABI)
|
||||
set(${_VDB_ABI} ${_OpenVDB_ABI_VERSION} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
########################################################################
|
||||
########################################################################
|
||||
|
||||
|
||||
function(OPENVDB_ABI_VERSION_FROM_PRINT OPENVDB_PRINT)
|
||||
cmake_parse_arguments(_VDB "QUIET" "ABI" "" ${ARGN})
|
||||
|
||||
if(NOT EXISTS ${OPENVDB_PRINT})
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_VDB_PRINT_VERSION_STRING "")
|
||||
set(_VDB_PRINT_RETURN_STATUS "")
|
||||
|
||||
if(${_VDB_QUIET})
|
||||
execute_process(COMMAND ${OPENVDB_PRINT} "--version"
|
||||
RESULT_VARIABLE _VDB_PRINT_RETURN_STATUS
|
||||
OUTPUT_VARIABLE _VDB_PRINT_VERSION_STRING
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
else()
|
||||
execute_process(COMMAND ${OPENVDB_PRINT} "--version"
|
||||
RESULT_VARIABLE _VDB_PRINT_RETURN_STATUS
|
||||
OUTPUT_VARIABLE _VDB_PRINT_VERSION_STRING
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${_VDB_PRINT_RETURN_STATUS})
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_OpenVDB_ABI)
|
||||
string(REGEX REPLACE ".*abi([0-9]*).*" "\\1" _OpenVDB_ABI ${_VDB_PRINT_VERSION_STRING})
|
||||
unset(_VDB_PRINT_RETURN_STATUS)
|
||||
unset(_VDB_PRINT_VERSION_STRING)
|
||||
|
||||
if(_VDB_ABI)
|
||||
set(${_VDB_ABI} ${_OpenVDB_ABI} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,41 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[.rst:
|
||||
|
||||
Uninstall
|
||||
---------
|
||||
|
||||
Adds a custom target to the CMake build generation which allows for
|
||||
calling::
|
||||
|
||||
make uninstall
|
||||
|
||||
to remove an installation of OpenVDB. Relies on the install_manifest
|
||||
existing from a previous run of cmake.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
|
||||
if(NOT EXISTS ${MANIFEST})
|
||||
message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'")
|
||||
endif()
|
||||
|
||||
file(STRINGS ${MANIFEST} INSTALLED_FILES)
|
||||
foreach(INSTALLED_FILE ${INSTALLED_FILES})
|
||||
if(EXISTS ${INSTALLED_FILE})
|
||||
message(STATUS "Uninstalling: ${INSTALLED_FILE}")
|
||||
exec_program(
|
||||
${CMAKE_COMMAND} ARGS "-E remove ${INSTALLED_FILE}"
|
||||
OUTPUT_VARIABLE stdout
|
||||
RETURN_VALUE RESULT
|
||||
)
|
||||
|
||||
if(NOT "${RESULT}" STREQUAL 0)
|
||||
message(FATAL_ERROR "Failed to remove file: '${INSTALLED_FILE}'.")
|
||||
endif()
|
||||
endif()
|
||||
endforeach(INSTALLED_FILE)
|
||||
@@ -0,0 +1,266 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CXX and CMAKE_CXX options and definitions for OpenVDB build types
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
###############################################################################
|
||||
|
||||
# General CMake and CXX settings
|
||||
|
||||
if(FUTURE_MINIMUM_CMAKE_VERSION)
|
||||
if(${CMAKE_VERSION} VERSION_LESS ${FUTURE_MINIMUM_CMAKE_VERSION})
|
||||
message(DEPRECATION "Support for CMake versions < ${FUTURE_MINIMUM_CMAKE_VERSION} "
|
||||
"is deprecated and will be removed.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD ${MINIMUM_CXX_STANDARD} CACHE STRING
|
||||
"The C++ standard whose features are requested to build OpenVDB components." FORCE)
|
||||
elseif(CMAKE_CXX_STANDARD LESS ${MINIMUM_CXX_STANDARD})
|
||||
message(FATAL_ERROR "Provided C++ Standard is less than the supported minimum."
|
||||
"Required is at least \"${MINIMUM_CXX_STANDARD}\" (found ${CMAKE_CXX_STANDARD})")
|
||||
endif()
|
||||
if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_CXX_STANDARD)
|
||||
if(CMAKE_CXX_STANDARD LESS ${FUTURE_MINIMUM_CXX_STANDARD})
|
||||
message(DEPRECATION "C++ < 17 is deprecated and will be removed.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Configure MS Runtime
|
||||
|
||||
if(WIN32 AND CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
message(STATUS "CMAKE_MSVC_RUNTIME_LIBRARY set to target ${CMAKE_MSVC_RUNTIME_LIBRARY}")
|
||||
|
||||
# Configure Boost library varient on Windows
|
||||
if(NOT Boost_USE_STATIC_RUNTIME)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreaded OR
|
||||
CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreadedDebug)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT Boost_USE_DEBUG_RUNTIME)
|
||||
set(Boost_USE_DEBUG_RUNTIME OFF)
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreadedDebugDLL OR
|
||||
CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL MultiThreadedDebug)
|
||||
set(Boost_USE_DEBUG_RUNTIME ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
|
||||
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
|
||||
|
||||
if(OPENVDB_ENABLE_RPATH)
|
||||
# Configure rpath for installation base on the following:
|
||||
# https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
# @todo make relocatable?
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
# For CMake's find Threads module which brings in pthread - This flag
|
||||
# forces the compiler -pthread flag vs -lpthread
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Compiler version checks
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_CLANG_VERSION)
|
||||
message(FATAL_ERROR "Insufficient clang++ version. Minimum required is "
|
||||
"\"${MINIMUM_CLANG_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\""
|
||||
)
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_GCC_VERSION)
|
||||
message(FATAL_ERROR "Insufficient g++ version. Minimum required is "
|
||||
"\"${MINIMUM_GCC_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\""
|
||||
)
|
||||
endif()
|
||||
if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_GCC_VERSION)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS FUTURE_MINIMUM_GCC_VERSION)
|
||||
message(DEPRECATION "Support for GCC versions < ${FUTURE_MINIMUM_GCC_VERSION} "
|
||||
"is deprecated and will be removed.")
|
||||
endif()
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_ICC_VERSION)
|
||||
message(FATAL_ERROR "Insufficient ICC version. Minimum required is "
|
||||
"\"${MINIMUM_ICC_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\""
|
||||
)
|
||||
endif()
|
||||
if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_ICC_VERSION)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS FUTURE_MINIMUM_ICC_VERSION)
|
||||
message(DEPRECATION "Support for ICC versions < ${FUTURE_MINIMUM_ICC_VERSION} "
|
||||
"is deprecated and will be removed.")
|
||||
endif()
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MINIMUM_MSVC_VERSION)
|
||||
message(FATAL_ERROR "Insufficient MSVC version. Minimum required is "
|
||||
"\"${MINIMUM_MSVC_VERSION}\". Found version \"${CMAKE_CXX_COMPILER_VERSION}\""
|
||||
)
|
||||
endif()
|
||||
if(OPENVDB_FUTURE_DEPRECATION AND FUTURE_MINIMUM_MSVC_VERSION)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS FUTURE_MINIMUM_MSVC_VERSION)
|
||||
message(DEPRECATION "Support for MSVC versions < ${FUTURE_MINIMUM_MSVC_VERSION} "
|
||||
"is deprecated and will be removed.")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Unsupported CXX compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Increase the number of sections that an object file can contain
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/bigobj>")
|
||||
# Excludes APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets
|
||||
add_compile_definitions("$<$<CXX_COMPILER_ID:MSVC>:WIN32_LEAN_AND_MEAN>")
|
||||
# Disable non-secure CRT library function warnings
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/
|
||||
# compiler-warning-level-3-c4996?view=vs-2019#unsafe-crt-library-functions
|
||||
add_compile_definitions("$<$<CXX_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>")
|
||||
# Disable POSIX function name warnings
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/
|
||||
# compiler-warning-level-3-c4996?view=vs-2019#posix-function-names
|
||||
add_compile_definitions("$<$<CXX_COMPILER_ID:MSVC>:_CRT_NONSTDC_NO_WARNINGS>")
|
||||
# If a user has explicitly requested a parallel build, configure this during CMake
|
||||
if(MSVC_MP_THREAD_COUNT AND MSVC_MP_THREAD_COUNT GREATER 1)
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/MP${MSVC_MP_THREAD_COUNT}>")
|
||||
endif()
|
||||
|
||||
if(OPENVDB_CXX_STRICT)
|
||||
message(STATUS "Configuring CXX warnings")
|
||||
# Clang/AppleClang
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Werror>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wall>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wextra>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wconversion>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-Wno-sign-conversion>")
|
||||
# GNU
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Werror>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wall>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wextra>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-pedantic>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wcast-align>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wcast-qual>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wconversion>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wdisabled-optimization>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Woverloaded-virtual>")
|
||||
else()
|
||||
# NO OPENVDB_CXX_STRICT, suppress some warnings
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
message(STATUS "Suppressing some noisy MSVC CXX warnings, "
|
||||
"set OPENVDB_CXX_STRICT=ON to re-enable them.")
|
||||
endif()
|
||||
# Conversion from int64_t to long
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/wd4244>")
|
||||
# It's not possible to use STL types in DLL interfaces in a portable and
|
||||
# reliable way so disable this warning
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/wd4251>")
|
||||
# Conversion from size_t to uLong
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/wd4267>")
|
||||
# Non dll-interface class used as base for dll-interface class
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/wd4275>")
|
||||
# Truncation from 'int' to 'bool'
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/wd4305>")
|
||||
endif()
|
||||
|
||||
if(USE_COLORED_OUTPUT)
|
||||
message(STATUS "Enabling colored compiler output")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>:-fcolor-diagnostics>")
|
||||
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-fdiagnostics-color=always>")
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Build Types
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
|
||||
CACHE STRING [=[Choose the type of build. CMake natively supports the following options: None Debug Release
|
||||
RelWithDebInfo MinSizeRel. OpenVDB additionally supports the following sanitizers and tools:
|
||||
coverage tsan asan lsan msan ubsan]=]
|
||||
FORCE)
|
||||
|
||||
if(CMAKE_BUILD_TYPE EQUAL coverage)
|
||||
# use .gcno extension instead of .cc.gcno
|
||||
# @note This is an undocumented internal cmake var and does not work
|
||||
# with multi config generators
|
||||
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
|
||||
endif()
|
||||
|
||||
# Note that the thread, address and memory sanitizers are incompatible with each other
|
||||
set(EXTRA_BUILD_TYPES coverage tsan asan lsan msan ubsan)
|
||||
|
||||
# Set all build flags to empty (unless they have been provided)
|
||||
|
||||
# DebugNoInfo - An internal build type only used by the OpenVDB CI. no optimizations, no symbols, asserts enabled
|
||||
set(CMAKE_CXX_FLAGS_DebugNoInfo "" CACHE STRING "Flags used by the C++ compiler during DebugNoInfo builds.")
|
||||
|
||||
foreach(TYPE ${EXTRA_BUILD_TYPES})
|
||||
set(CMAKE_CXX_FLAGS_${U_TYPE} "" CACHE STRING "Flags used by the C++ compiler during ${TYPE} builds.")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_${U_TYPE} "" CACHE STRING "Flags used by the linker during ${TYPE} builds.")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_${U_TYPE} "" CACHE STRING "Flags used by the linker during ${TYPE} builds.")
|
||||
endforeach()
|
||||
|
||||
# Init generator options - we use generator expressions to allow builds with both
|
||||
# clang and GCC. Sanitizers are currently only configured for clang and GCC.
|
||||
|
||||
# Coverage
|
||||
add_compile_options("$<$<AND:$<CONFIG:COVERAGE>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:--coverage>")
|
||||
add_link_options("$<$<AND:$<CONFIG:COVERAGE>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:--coverage>")
|
||||
|
||||
# ThreadSanitizer
|
||||
add_compile_options("$<$<AND:$<CONFIG:TSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=thread>")
|
||||
add_compile_options("$<$<AND:$<CONFIG:TSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-g;-O1>")
|
||||
add_link_options("$<$<AND:$<CONFIG:TSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=thread>")
|
||||
|
||||
# AddressSanitize
|
||||
add_compile_options("$<$<AND:$<CONFIG:ASAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=address>")
|
||||
add_compile_options("$<$<AND:$<CONFIG:ASAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fno-omit-frame-pointer;-g;-O1>")
|
||||
add_compile_options("$<$<AND:$<CONFIG:ASAN>,$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>>:-fsanitize-address-use-after-scope;-fno-optimize-sibling-calls>")
|
||||
# -fsanitize-address-use-after-scope added in GCC 7
|
||||
add_compile_options("$<$<AND:$<CONFIG:ASAN>,$<COMPILE_LANG_AND_ID:CXX,GNU>,$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,7.0.0>>:-fsanitize-address-use-after-scope>")
|
||||
add_link_options("$<$<AND:$<CONFIG:ASAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=address>")
|
||||
|
||||
# LeakSanitizer
|
||||
add_compile_options("$<$<AND:$<CONFIG:LSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=leak>")
|
||||
add_compile_options("$<$<AND:$<CONFIG:LSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fno-omit-frame-pointer;-g;-O1>")
|
||||
add_link_options("$<$<AND:$<CONFIG:LSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=leak>")
|
||||
|
||||
# MemorySanitizer
|
||||
add_compile_options("$<$<AND:$<CONFIG:MSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=memory>")
|
||||
add_compile_options("$<$<AND:$<CONFIG:MSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fno-omit-frame-pointer;-g;-O2>")
|
||||
add_compile_options("$<$<AND:$<CONFIG:MSAN>,$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>>:--fno-optimize-sibling-calls;-fsanitize-memory-track-origins=2>")
|
||||
add_link_options("$<$<AND:$<CONFIG:MSAN>,$<COMPILE_LANG_AND_ID:CXX,Clang,AppleClang>>:-fsanitize=memory>")
|
||||
|
||||
# UndefinedBehaviour
|
||||
add_compile_options("$<$<AND:$<CONFIG:UBSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=undefined>")
|
||||
add_link_options("$<$<AND:$<CONFIG:UBSAN>,$<COMPILE_LANG_AND_ID:CXX,GNU,Clang,AppleClang>>:-fsanitize=undefined>")
|
||||
|
||||
# CMAKE_BUILD_TYPE is ignored for multi config generators i.e. MSVS
|
||||
|
||||
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(NOT _isMultiConfig)
|
||||
message(STATUS "CMake Build Type: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
Current and future version requirements for all OpenVDB dependencies,
|
||||
including compilers, language features and OpenVDB's ABI.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Configure minimum version requirements - some are treated specially and fall
|
||||
# outside of the DISABLE_DEPENDENCY_VERSION_CHECKS catch
|
||||
set(MINIMUM_CXX_STANDARD 14)
|
||||
|
||||
# @note ABI always enforced so the correct deprecation messages are available.
|
||||
# OPENVDB_USE_DEPRECATED_ABI_<VERSION> should be used to circumvent this
|
||||
set(MINIMUM_OPENVDB_ABI_VERSION 7)
|
||||
set(FUTURE_MINIMUM_OPENVDB_ABI_VERSION 9)
|
||||
set(FUTURE_OPENVDB_ABI_VERSION 10)
|
||||
|
||||
if(NOT DISABLE_DEPENDENCY_VERSION_CHECKS)
|
||||
# @note Currently tracking CY2020 of the VFX platform where available
|
||||
set(MINIMUM_GCC_VERSION 6.3.1)
|
||||
set(MINIMUM_CLANG_VERSION 3.8)
|
||||
set(MINIMUM_ICC_VERSION 17)
|
||||
set(MINIMUM_MSVC_VERSION 19.10)
|
||||
|
||||
set(MINIMUM_BOOST_VERSION 1.70)
|
||||
set(MINIMUM_ILMBASE_VERSION 2.4)
|
||||
set(MINIMUM_OPENEXR_VERSION 2.4)
|
||||
set(MINIMUM_ZLIB_VERSION 1.2.7)
|
||||
set(MINIMUM_TBB_VERSION 2019.0)
|
||||
set(MINIMUM_LLVM_VERSION 7.0.0)
|
||||
set(MINIMUM_BLOSC_VERSION 1.5.0)
|
||||
|
||||
set(MINIMUM_PYTHON_VERSION 2.7) # @warning should be 3.7.x, but H18.5+ can still be used with 2.7.x
|
||||
set(MINIMUM_NUMPY_VERSION 1.17.0)
|
||||
|
||||
set(MINIMUM_GOOGLETEST_VERSION 1.10)
|
||||
set(MINIMUM_GLFW_VERSION 3.1)
|
||||
set(MINIMUM_LOG4CPLUS_VERSION 1.1.2)
|
||||
set(MINIMUM_HOUDINI_VERSION 18.5)
|
||||
|
||||
# These always promote warnings rather than errors
|
||||
set(MINIMUM_MAYA_VERSION 2017)
|
||||
set(MINIMUM_DOXYGEN_VERSION 1.8.8)
|
||||
endif()
|
||||
|
||||
# VFX 21 deprecations to transition to MINIMUM_* variables in OpenVDB 10.0.0
|
||||
|
||||
set(FUTURE_MINIMUM_GCC_VERSION 9.3.1)
|
||||
set(FUTURE_MINIMUM_ICC_VERSION 19)
|
||||
# set(FUTURE_MINIMUM_MSVC_VERSION 19.10)
|
||||
|
||||
set(FUTURE_MINIMUM_CXX_STANDARD 17)
|
||||
set(FUTURE_MINIMUM_CMAKE_VERSION 3.18)
|
||||
#set(FUTURE_MINIMUM_ILMBASE_VERSION 2.4) # Minimum is already 2.4
|
||||
#set(FUTURE_MINIMUM_OPENEXR_VERSION 2.4) # Minimum is already 2.4
|
||||
set(FUTURE_MINIMUM_BOOST_VERSION 1.73)
|
||||
set(FUTURE_MINIMUM_BLOSC_VERSION 1.17.0)
|
||||
set(FUTURE_MINIMUM_TBB_VERSION 2020.2)
|
||||
set(FUTURE_MINIMUM_PYTHON_VERSION 3.7)
|
||||
set(FUTURE_MINIMUM_NUMPY_VERSION 1.19.0)
|
||||
set(FUTURE_MINIMUM_HOUDINI_VERSION 19.0)
|
||||
set(FUTURE_MINIMUM_LLVM_VERSION 10.0.0)
|
||||
@@ -0,0 +1,30 @@
|
||||
#################################################################################
|
||||
## This file is loaded by the Undefined Behaviour Sanitizer build for the unit ##
|
||||
## tests. It can be used to ignore various errors reported by the sanitizer. ##
|
||||
## This is especially useful with upstream issues (e.g. boost/tbb). For help ##
|
||||
## defining suppression rules, see: ##
|
||||
## https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html ##
|
||||
## The build is configured with CMAKE_BUILD_TYPE=ubsan. ##
|
||||
#################################################################################
|
||||
|
||||
##### Upstream #####
|
||||
|
||||
# Lots of warnings from TBB, ignore them
|
||||
alignment:tbb/concurrent_hash_map.h
|
||||
vptr:tbb/parallel_reduce.h
|
||||
vptr:tbb/task.h
|
||||
|
||||
##### OpenVDB #####
|
||||
|
||||
# The sOn/sOff static bool data held on the LeaffBuff<bool> objects can be
|
||||
# initialised to arbitrary true/false values. See the note in LeafBuffer.h
|
||||
enum:openvdb/tools/Activate.h
|
||||
# Some 2s complement tests, ignore the negative shifts
|
||||
# @todo Should address these
|
||||
shift-base:TestMultiResGrid.cc
|
||||
shift-base:openvdb/math/Coord.h
|
||||
|
||||
##### OpenVDB AX #####
|
||||
|
||||
# Ignore overflows reported from old OpenSimplexNoise
|
||||
signed-integer-overflow:openvdb_ax/math/OpenSimplexNoise.cc
|
||||
@@ -0,0 +1,274 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CMake Configuration for OpenVDB Documentation
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(OpenVDBDocs LANGUAGES NONE)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# If OPENVDB_DOXYGEN_HOUDINI is set, the Houdini documentation is also
|
||||
# built. You can provide this module a value for Houdini_VERSION which will
|
||||
# take into account any conditional compiled blocks. Whilst this doesn't
|
||||
# require you to build the Houdini plugin, building from the root CMake
|
||||
# with OPENVDB_BUILD_DOCS=ON and either OPENVDB_BUILD_HOUDINI_PLUGIN=ON or
|
||||
# USE_HOUDINI=ON will define Houdini_VERSION. If Houdini_VERSION is not set,
|
||||
# all documentation is included.
|
||||
option(OPENVDB_DOXYGEN_AX "Build AX documentation" ON)
|
||||
option(OPENVDB_DOXYGEN_HOUDINI "Build Houdini documentation" ON)
|
||||
option(OPENVDB_DOXYGEN_NANOVDB "Build NanoVDB documentation" ON)
|
||||
option(OPENVDB_DOXYGEN_INTERNAL [=[
|
||||
Enable documentation of methods and classes which have been explicitly marked as internal
|
||||
]=] OFF)
|
||||
|
||||
find_package(Doxygen REQUIRED doxygen)
|
||||
if(MINIMUM_DOXYGEN_VERSION)
|
||||
if(DOXYGEN_VERSION VERSION_LESS MINIMUM_DOXYGEN_VERSION)
|
||||
message(WARNING "The doxygen-config doxyfile has been generated with version "
|
||||
"\"${MINIMUM_DOXYGEN_VERSION}\". Found Doxygen version \"${DOXYGEN_VERSION}\". "
|
||||
"Documentation may contain errors."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(DOXY_FILES
|
||||
openvdb/openvdb
|
||||
openvdb/openvdb/io
|
||||
openvdb/openvdb/math
|
||||
openvdb/openvdb/points
|
||||
openvdb/openvdb/python/pyopenvdb.h
|
||||
openvdb/openvdb/tools
|
||||
openvdb/openvdb/tree
|
||||
openvdb/openvdb/util
|
||||
doc/build.txt
|
||||
doc/changes.txt
|
||||
doc/codingstyle.txt
|
||||
doc/dependencies.txt
|
||||
doc/doc.txt
|
||||
doc/examplecode.txt
|
||||
doc/faq.txt
|
||||
doc/math.txt
|
||||
doc/points.txt
|
||||
doc/python.txt)
|
||||
|
||||
set(DOXYGEN_PROJECT_NAME "OpenVDB")
|
||||
set(DOXYGEN_PROJECT_NUMBER "${OpenVDB_VERSION}")
|
||||
set(DOXYGEN_PROJECT_BRIEF "")
|
||||
set(DOXYGEN_FILE_PATTERNS *.h *h.in) # headers only
|
||||
set(DOXYGEN_EXTENSION_MAPPING .in=C) # parse CMake config headers as C
|
||||
set(DOXYGEN_IMAGE_PATH "doc/img")
|
||||
set(DOXYGEN_RECURSIVE NO)
|
||||
set(DOXYGEN_QUIET YES)
|
||||
|
||||
set(DOXYGEN_GENERATE_HTML YES)
|
||||
set(DOXYGEN_GENERATE_MAN NO)
|
||||
set(DOXYGEN_GENERATE_LATEX NO)
|
||||
set(DOXYGEN_GENERATE_TODOLIST NO)
|
||||
|
||||
set(DOXYGEN_HTML_COLORSTYLE_HUE 4)
|
||||
set(DOXYGEN_HTML_COLORSTYLE_SAT 222)
|
||||
set(DOXYGEN_HTML_TIMESTAMP NO) # for simpler website diffs
|
||||
|
||||
set(DOXYGEN_EXTRACT_ALL YES)
|
||||
set(DOXYGEN_EXTRACT_STATIC YES)
|
||||
set(DOXYGEN_EXTRACT_LOCAL_CLASSES NO)
|
||||
|
||||
# Allow for root directory paths to be listed (e.g. openvdb/io/File.h)
|
||||
# Rather than just the file names (e.g. File.h). This makes it far
|
||||
# easier to navigate the docs
|
||||
set(DOXYGEN_FULL_PATH_NAMES YES)
|
||||
set(DOXYGEN_STRIP_FROM_PATH
|
||||
"${CMAKE_SOURCE_DIR}/openvdb"
|
||||
"${CMAKE_SOURCE_DIR}/openvdb_ax"
|
||||
"${CMAKE_SOURCE_DIR}/nanovdb"
|
||||
"${CMAKE_SOURCE_DIR}/openvdb_houdini"
|
||||
"${CMAKE_SOURCE_DIR}")
|
||||
set(DOXYGEN_STRIP_FROM_INC_PATH
|
||||
"${CMAKE_SOURCE_DIR}/openvdb"
|
||||
"${CMAKE_SOURCE_DIR}/openvdb_ax"
|
||||
"${CMAKE_SOURCE_DIR}/nanovdb"
|
||||
"${CMAKE_SOURCE_DIR}/openvdb_houdini")
|
||||
|
||||
# Shows which source files generated the respected doxygen docs
|
||||
# at the bottom of each html page. Don't bother listing these.
|
||||
set(DOXYGEN_SHOW_USED_FILES NO)
|
||||
# When doxygen adds the source code for each header (see VERBATIM_HEADERS)
|
||||
# don't remove the actual doxygen comments
|
||||
set(DOXYGEN_STRIP_CODE_COMMENTS NO)
|
||||
# Don't add an alpha index of all classes (it's not particularly useful)
|
||||
set(DOXYGEN_ALPHABETICAL_INDEX NO)
|
||||
set(DOXYGEN_DISTRIBUTE_GROUP_DOC YES)
|
||||
set(DOXYGEN_HIDE_IN_BODY_DOCS YES)
|
||||
set(DOXYGEN_HIDE_SCOPE_NAMES YES)
|
||||
set(DOXYGEN_INLINE_INHERITED_MEMB YES)
|
||||
set(DOXYGEN_MACRO_EXPANSION YES)
|
||||
# @todo use dot with class diagrams for relevant classes
|
||||
set(DOXYGEN_CLASS_DIAGRAMS NO)
|
||||
|
||||
|
||||
set(DOXYGEN_ALIASES
|
||||
[[ijk="(<i>i</i>, <i>j</i>, <i>k</i>)"]]
|
||||
[[xyz="(<i>x</i>, <i>y</i>, <i>z</i>)"]]
|
||||
[[const="<tt>const</tt>"]]
|
||||
"\"vdbnamespace=openvdb::v${OpenVDB_MAJOR_VERSION}_${OpenVDB_MINOR_VERSION}\""
|
||||
[["hunamespace=houdini_utils"]]
|
||||
[["hvdbnamespace=openvdb_houdini"]]
|
||||
# Use this command to create a link to an OpenVDB class, function, etc.
|
||||
# Usage is "@vdblink{<symbol>,<text>}", where <symbol> is a fully namespace-
|
||||
# qualified symbol minus the openvdb and version number namespace components
|
||||
# and <text> is the text of the link.
|
||||
# Example: @vdblink{tree::RootNode,root node}
|
||||
[[vdblink{2}="@link @vdbnamespace::\1 \2@endlink"]]
|
||||
# Deprecated; use the two-argument overload defined above.
|
||||
[[vdblink="@link @vdbnamespace"]]
|
||||
# Use these commands to create links to OpenVDB Houdini symbols.
|
||||
# Usage is "@hulink{<symbol>,<text>}", where <symbol> is the name of
|
||||
# a symbol in the houdini_utils namespace and <text> is the text of the link
|
||||
# (and likewise for @hvdblink).
|
||||
# Example: @hulink{ParmFactory::setDefault(),setDefault}
|
||||
# These stub implementations are used when Houdini support is disabled;
|
||||
# see doxygen-config-houdini for the full implementations.
|
||||
[[hulink{2}="<B>\2</B>"]]
|
||||
[[hvdblink{2}="<B>\2</B>"]]
|
||||
)
|
||||
|
||||
set(DOXYGEN_PREDEFINED
|
||||
"OPENVDB_VERSION_NAME=v${OpenVDB_MAJOR_VERSION}_${OpenVDB_MINOR_VERSION}"
|
||||
"OPENVDB_ABI_VERSION_NUMBER=${OpenVDB_MAJOR_VERSION}"
|
||||
[[__declspec(x):= __attribute__(x):=]]
|
||||
# Replace the deprecated macros with doxygen deprecated comments. This ensures
|
||||
# that every bit of deprecated C++ is listed in the doxygen deprecated list,
|
||||
# even if it was not properly tagged
|
||||
[["OPENVDB_DEPRECATED=/** \deprecated */"]]
|
||||
[["OPENVDB_DEPRECATED_MESSAGE(x)=/** \deprecated x */"]]
|
||||
"OPENVDB_USE_LOG4CPLUS=")
|
||||
|
||||
set(DOXYGEN_ENABLED_SECTIONS "")
|
||||
|
||||
if(OPENVDB_DOXYGEN_INTERNAL)
|
||||
list(APPEND DOXYGEN_ENABLED_SECTIONS "OPENVDB_DOCS_INTERNAL")
|
||||
endif()
|
||||
|
||||
if(OPENVDB_DOXYGEN_HOUDINI)
|
||||
# Append Houdini-specific settings to the Doxygen config file.
|
||||
if(Houdini_VERSION)
|
||||
# Extract the components of the Houdini version number into a list.
|
||||
string(REPLACE "." ";" HOUDINI_VERSION_COMPONENTS ${Houdini_VERSION})
|
||||
list(GET HOUDINI_VERSION_COMPONENTS 0 HVERS_MAJOR)
|
||||
list(GET HOUDINI_VERSION_COMPONENTS 1 HVERS_MINOR)
|
||||
list(GET HOUDINI_VERSION_COMPONENTS 2 HVERS_PATCH)
|
||||
else()
|
||||
set(HVERS_MAJOR 127) # CMake treats (255 << 24) as a negative number
|
||||
set(HVERS_MINOR 0)
|
||||
set(HVERS_PATCH 0)
|
||||
endif()
|
||||
math(EXPR HVERS_INT "(((${HVERS_MAJOR} << 8) + ${HVERS_MINOR}) << 16) + ${HVERS_PATCH}")
|
||||
# Append Houdini version number macros to the Doxygen config file so that
|
||||
# the generated documentation reflects the API for that version
|
||||
# (i.e, taking into account any conditionally compiled blocks).
|
||||
list(APPEND DOXYGEN_PREDEFINED "UT_MAJOR_VERSION_INT=${HVERS_MAJOR}")
|
||||
list(APPEND DOXYGEN_PREDEFINED "UT_MINOR_VERSION_INT=${HVERS_MINOR}")
|
||||
list(APPEND DOXYGEN_PREDEFINED "UT_VERSION_INT=${HVERS_INT}")
|
||||
|
||||
list(APPEND DOXYGEN_ALIASES
|
||||
[[hulink{2}="@link @hunamespace::\1 \2@endlink"]]
|
||||
[[hvdblink{2}="@link @hvdbnamespace::\1 \2@endlink"]]
|
||||
# Deprecated; use the two-argument overloads defined above.
|
||||
[[hulink="@link @hunamespace"]]
|
||||
[[hvdblink="@link @hvdbnamespace"]]
|
||||
)
|
||||
|
||||
list(APPEND DOXYGEN_ENABLED_SECTIONS "OPENVDB_HOUDINI")
|
||||
|
||||
list(APPEND DOXY_FILES
|
||||
doc/houdini.txt
|
||||
openvdb_houdini/openvdb_houdini/AttributeTransferUtil.h
|
||||
openvdb_houdini/openvdb_houdini/GEO_PrimVDB.h
|
||||
openvdb_houdini/openvdb_houdini/GT_GEOPrimCollectVDB.h
|
||||
openvdb_houdini/openvdb_houdini/GU_PrimVDB.h
|
||||
openvdb_houdini/openvdb_houdini/GU_VDBPointTools.h
|
||||
openvdb_houdini/openvdb_houdini/GeometryUtil.h
|
||||
openvdb_houdini/openvdb_houdini/ParmFactory.h
|
||||
openvdb_houdini/openvdb_houdini/PointUtils.h
|
||||
openvdb_houdini/openvdb_houdini/SOP_NodeVDB.h
|
||||
openvdb_houdini/openvdb_houdini/SOP_VDBVerbUtils.h
|
||||
openvdb_houdini/openvdb_houdini/UT_VDBTools.h
|
||||
openvdb_houdini/openvdb_houdini/UT_VDBUtils.h
|
||||
openvdb_houdini/openvdb_houdini/Utils.h)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_DOXYGEN_AX)
|
||||
set(DOXYGEN_EXTRA_PACKAGES amsmath) # for math formatting
|
||||
set(DOXYGEN_FORMULA_FONTSIZE 14)
|
||||
list(APPEND DOXYGEN_ENABLED_SECTIONS "OPENVDB_AX")
|
||||
|
||||
list(APPEND DOXY_FILES
|
||||
doc/ax/ax.txt
|
||||
doc/ax/axcplusplus.txt
|
||||
doc/ax/axexamples.txt
|
||||
doc/ax/axfunctionlist.txt
|
||||
doc/ax/doc.txt
|
||||
openvdb_ax/openvdb_ax
|
||||
openvdb_ax/openvdb_ax/ast
|
||||
openvdb_ax/openvdb_ax/cmd
|
||||
openvdb_ax/openvdb_ax/codegen
|
||||
openvdb_ax/openvdb_ax/compiler
|
||||
openvdb_ax/openvdb_ax/grammar
|
||||
openvdb_ax/openvdb_ax/grammar/generated
|
||||
openvdb_ax/openvdb_ax/math
|
||||
openvdb_ax/openvdb_ax/test)
|
||||
endif()
|
||||
|
||||
if(OPENVDB_DOXYGEN_NANOVDB)
|
||||
list(APPEND DOXYGEN_ENABLED_SECTIONS "NANOVDB")
|
||||
|
||||
list(APPEND DOXY_FILES
|
||||
doc/nanovdb/doc.md
|
||||
doc/nanovdb/FAQ.md
|
||||
doc/nanovdb/SourceTree.md
|
||||
doc/nanovdb/HowToBuild.md
|
||||
doc/nanovdb/HelloWorld.md
|
||||
nanovdb/nanovdb
|
||||
nanovdb/nanovdb/util
|
||||
nanovdb/nanovdb/cmd/convert
|
||||
nanovdb/nanovdb/cmd/print
|
||||
nanovdb/nanovdb/cmd/validate
|
||||
nanovdb/nanovdb/examples/benchmark
|
||||
nanovdb/nanovdb/examples/ex_bump_pool_buffer
|
||||
nanovdb/nanovdb/examples/ex_collide_level_set
|
||||
nanovdb/nanovdb/examples/ex_make_custom_nanovdb
|
||||
nanovdb/nanovdb/examples/ex_make_funny_nanovdb
|
||||
nanovdb/nanovdb/examples/ex_make_nanovdb_sphere
|
||||
nanovdb/nanovdb/examples/ex_make_typed_grids
|
||||
nanovdb/nanovdb/examples/ex_map_pool_buffer
|
||||
nanovdb/nanovdb/examples/ex_modify_nanovdb_thrust
|
||||
nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb
|
||||
nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb_accessor
|
||||
nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb_cuda
|
||||
nanovdb/nanovdb/examples/ex_raytrace_fog_volume
|
||||
nanovdb/nanovdb/examples/ex_raytrace_level_set
|
||||
nanovdb/nanovdb/examples/ex_read_nanovdb_sphere
|
||||
nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor
|
||||
nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor_cuda
|
||||
nanovdb/nanovdb/examples/ex_util
|
||||
nanovdb/nanovdb/examples/ex_vox_to_nanovdb
|
||||
nanovdb/nanovdb/examples/ex_write_nanovdb_grids
|
||||
nanovdb/nanovdb/unittest)
|
||||
endif()
|
||||
|
||||
set(DOXYGEN_VERBATIM_VARS DOXYGEN_ALIASES DOXYGEN_PREDEFINED)
|
||||
|
||||
# Always add to build target (can't use USE_STAMP_FILE as we include
|
||||
# complete directories in DOXY_FILES)
|
||||
doxygen_add_docs(doc ${DOXY_FILES}
|
||||
ALL WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen")
|
||||
|
||||
# Suppress "Installing..." messages for all but one of the hundreds of generated files.
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/html/index.html DESTINATION ${CMAKE_INSTALL_DOCDIR}/html)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION ${CMAKE_INSTALL_DOCDIR} MESSAGE_NEVER)
|
||||
+2109
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,496 @@
|
||||
/**
|
||||
<div style="width:800px;text-align:justify;">
|
||||
|
||||
@page axcplusplus OpenVDB AX
|
||||
|
||||
@section axcdocs AX C++ Documentation
|
||||
@par
|
||||
The following documentation focuses on the C++ design and API of OpenVDB AX,
|
||||
@b not the front end AX language. For the latter, see the
|
||||
@ref ax "AX Language documentation". For more specific function API information,
|
||||
search for the relevant function doxygen.
|
||||
@note
|
||||
These documents are actively being worked on and are subject to change. See the
|
||||
API doxygen comments or contact us for more information.
|
||||
|
||||
@section vdbaxcontents Contents
|
||||
- @ref vdbaxapiabi
|
||||
- @ref vdbaxrepo
|
||||
- @ref vdbaxgrammar
|
||||
- @ref vdbaxast
|
||||
- @ref vdbaxastscanners
|
||||
- @ref vdbaxcompilerpipe
|
||||
- @ref vdbaxcompilerlogging
|
||||
- @ref vdbaxcompilerexe
|
||||
- @ref vdbaxcompilercustomdata
|
||||
- @ref vdbaxcodegen
|
||||
- @ref vdbaxcompiler
|
||||
- @ref vdbaxbinary
|
||||
- @ref vdbaxtoaxtypes
|
||||
- @ref vdbaxextend
|
||||
|
||||
<hr>
|
||||
|
||||
@section vdbaxapiabi Versioning, API and ABI
|
||||
@par
|
||||
AX is a self contained library which currently has a one way dependency on
|
||||
OpenVDB; any downstream artifact that uses AX will need to build and link
|
||||
against both OpenVDB and OpenVDB AX. There are a few important factors to be
|
||||
aware of with this integration:
|
||||
@par
|
||||
- OpenVDB AX is tied to the OpenVDB library version. There is no explicit
|
||||
OpenVDB AX version. This includes the OpenVDB namespaced API, the shared
|
||||
library version suffix on relevant platforms and the OpenVDB ABI. It *may* be
|
||||
possible to build OpenVDB AX against a different version of OpenVDB however
|
||||
this is not explicitly supported.
|
||||
- There are no ABI compatibility guarantees for OpenVDB AX components i.e. AX
|
||||
components do not support the transfer of themselves as binary representations
|
||||
across dynamic library boundaries to applications where AX has been compiled at
|
||||
a different location in the OpenVDB repository. Support for this may change in
|
||||
the future.
|
||||
@par
|
||||
In general, anything in the public namespace (defined as anything not labelled
|
||||
"internal") comes with standard API guarantees; that is, classes and methods
|
||||
will not change visible behaviour or signatures and deprecations will occur with
|
||||
appropriate replacements (where necessary) prior to removal. However, due to the
|
||||
nature of the project and its infancy, it's encouraged to continue reading below
|
||||
into the relevant AX components. These provide a better description of their
|
||||
intended public consumption and completeness.
|
||||
|
||||
<hr>
|
||||
|
||||
@section vdbaxrepo OpenVDB AX Repository
|
||||
@par
|
||||
The AX repository has been laid out using a modular design. Each subdirectory
|
||||
encompasses a set of similar tools with a fairly consistent (one-way) dependency
|
||||
diagram to other tools in the repository. The following provides a short
|
||||
description of each directory, listed in this ad-hoc dependency order (from
|
||||
highest to lowest):
|
||||
@par
|
||||
- @b grammar: Provides the flex/bison lexer/grammar rules for generating the
|
||||
OpenVDB AX language, as well as the pre-generated `.c` files.
|
||||
- @b ast: The definition of an AX Abstract Syntax Tree, its node types and
|
||||
methods to work explicitly with them.
|
||||
- @b compiler: The frontend C++ user interface for building and using AX.
|
||||
- @b codegen: The backend LLVM IR code generation for AX.
|
||||
@par
|
||||
Additional tools include (in no particular order):
|
||||
@par
|
||||
- @b cmd: Command line binary tools for AX.
|
||||
- @b math: Various mathematical methods, typically used by the AX
|
||||
code generators when building native functions.
|
||||
- @b test: Unit testing framework for AX.
|
||||
|
||||
@subsection vdbaxgrammar The Grammar
|
||||
@par
|
||||
The subdirectory @b grammar contains the rules used to generate an AX abstract
|
||||
syntax tree, as defined by the @ref ax "AX Language specification." These files
|
||||
do not provide an API per-se and are primarily used internally by the @b ast
|
||||
module. The grammar syntax rules are specified in files with <b>.y</b> suffix
|
||||
and the tokenziers are specified by the <b>.l</b> suffix. These files are designed
|
||||
to work with two UNIX tools, GNU <A HREF="https://www.gnu.org/software/bison/manual/">
|
||||
Bison</A> and <A HREF="https://westes.github.io/flex/manual/">Flex</A>. Together
|
||||
these tools provide a workflow for developers to create develop a wide range of
|
||||
language parsers. It's encouraged to visit the corresponding manuals for more
|
||||
information on their use.
|
||||
@par
|
||||
The AX grammar is defined with a <A HREF="https://en.wikipedia.org/wiki/LR_parser">
|
||||
LR parser</A>. In simplest terms, this means that the syntactical rules define a
|
||||
grammar which is parsed bottom-up, left-to-right, deterministically and context
|
||||
free (for the most part). These are fairly typical traits of parsers used to
|
||||
define computer languages. The parser is @b not designed to be interactive, nor
|
||||
reentrant (is not thread safe, each string is parsed sequentially) however such
|
||||
limitations are not imposed by AX and may be removed in the future. Note that
|
||||
the internal function symbols are correctly prefixed (with @b ax), so AX should
|
||||
be compatible with other software that also uses Bison/Flex.
|
||||
@par
|
||||
The <b>.y</b> and <b>.l</b> files are typically not part of the normal build
|
||||
process. Bison and Flex use them to generate compatible C/C++ code, however this
|
||||
code is always pre-generated and provided with the AX repository within the
|
||||
<b>grammar/generated</b> subdirectory. This C/C++ code is compiled into the AX
|
||||
library. Thus, the grammar is provided for two reasons; to demonstrate how the
|
||||
syntactical rules are implemented and to provide expert users the ability to
|
||||
regenerate the C/C++ bindings (see @ref build "the build instructions").
|
||||
Importantly, AX does not install any of the files in the grammar folder; the
|
||||
parser is accessed through the @b ast module.
|
||||
|
||||
@subsection vdbaxast The AST
|
||||
@par
|
||||
The @b ast module provides:
|
||||
- The complete implemenation of an @ref AST.h "AX abstract syntax tree"
|
||||
- The openvdb::ax::ast::parse() method
|
||||
- The @vdblink::ax::ast::Visitor AST Visitor@endlink
|
||||
- AST scanners and tools
|
||||
@par
|
||||
All methods in this module are designed to work around an AX AST, which represents the
|
||||
syntactical constructs of the AX language as a hierarchy of C++ objects (nodes).
|
||||
The complete AST hierarchy is visualized by the @vdblink::ax::ast::Node doxygen
|
||||
class graph for an openvdb::ax::ast::Node@endlink, which represents the top most
|
||||
node in the AST. The AST API exists in a nested namespace (`openvdb::ax::ast`)
|
||||
and can be used by clients for more granular control and modifications to an AST.
|
||||
Importantly, the AST API contains the openvdb::ax::ast::parse() method, which
|
||||
invokes the C/C++ functions built by the grammar to iteratively construct an
|
||||
AST from a provided character string.
|
||||
@par
|
||||
A number of other tools are provided by the module to work with an AST such as
|
||||
tools to re-interpret the AST back to AX compatible code, printing of the AST's
|
||||
node hierarchy/layout and scanners which are able to query details from AST
|
||||
branches. All these methods use the @vdblink::ax::ast::Visitor AX visitor
|
||||
framework@endlink, a visitor pattern traversal class strongly influenced by
|
||||
<A HREF="https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html">
|
||||
Clang's RecursiveVisitor</A>. Clients can use the AX visitor to implement their
|
||||
own AST analysis or modifications (see @ref vdbaxextend).
|
||||
|
||||
@subsubsection vdbaxastscanners Scanners
|
||||
@par
|
||||
todo
|
||||
|
||||
@subsection vdbaxcompilerpipe The Compiler Pipeline
|
||||
@par
|
||||
The @b compiler subdirectory contains the bulk of the C++ API intended to be
|
||||
used directly by clients of OpenVDB AX. It links together the grammar, AST and
|
||||
code generation to produce AX executable objects, forming a pipeline from an
|
||||
initial string of AX code to final execution across some geometry. The following
|
||||
sections detail the core components to the Compiler pipeline.
|
||||
|
||||
@subsubsection vdbaxcompilerlogging Logging
|
||||
@par
|
||||
Anyone familiar with programming languages will undoubtedly be aware of the huge
|
||||
variety and quantity of feedback that's presented to clients during use. This
|
||||
information, when properly presented, can be invaluable and help to advise
|
||||
users during their usage of the language. AX provides @vdblink::ax::Logger a
|
||||
Logger class@endlink which can be used throughout the Compiler pipeline to
|
||||
store and report this information. By default, this class reports all errors to
|
||||
<A HREF="https://en.cppreference.com/w/cpp/io/cerr">std::cerr</A> and swallows
|
||||
warnings, but can be customised depending on your needs e.g:
|
||||
@par
|
||||
@code{.cpp}
|
||||
#include <openvdb_ax/compiler/Logger.h>
|
||||
|
||||
// Create a logger which sends errors and warnings to std::cerr
|
||||
openvdb::ax::Logger
|
||||
logs([](const std::string& msg) { std::cerr << msg << std::endl; },
|
||||
[](const std::string& msg) { std::cerr << msg << std::endl; });
|
||||
|
||||
logs.setMaxErrors(5); // stop reporting after 5 errors
|
||||
logs.setWarningsAsErrors(false); // don't count warnings as an error
|
||||
logs.setPrintLines(true); // print code lines
|
||||
logs.setNumberedOutput(true); // number each error/warning reported
|
||||
@endcode
|
||||
@par
|
||||
A @vdblink::ax::Logger Logger@endlink should be passed to the relevant pipeline
|
||||
methods as detailed in the following sections.
|
||||
|
||||
@subsubsection vdbaxcompilerexe Executables
|
||||
@par
|
||||
The "executable" terminology comes from the binary representation of the
|
||||
compiled function which is invoked. AX executables essentially wrap the
|
||||
generated function calls from the AX codegen with an efficient multi-threaded
|
||||
invoke for the type of geometry being processed. The executable classes are
|
||||
designed to be lightweight to store, modify and copy with a consolidated
|
||||
interface for running and customising execution.
|
||||
@par
|
||||
There are two main types of executables; the @vdblink::ax::VolumeExecutable
|
||||
VolumeExecutable@endlink, designed to work with all OpenVDB Volumes and the
|
||||
@vdblink::ax::PointExecutable PointExecutable@endlink which works with OpenVDB
|
||||
`PointDataGrids`. They are not expected to be created directly; instead these
|
||||
objects are returned by the @vdblink::ax::Compiler AX Compiler@endlink depending
|
||||
on the selected @vdblink::ax::Compiler::compile() Compiler::compile() @endlink
|
||||
function.
|
||||
@note
|
||||
There is no inherent limitation to the design of the `VolumeExecutable` which
|
||||
stops it working on `PointDataGrids` but it's not particular useful in it's
|
||||
current form and can be confusing so it is explicitly disallowed.
|
||||
@par
|
||||
The executables are distinctly detached from the @vdblink::ax::Compiler
|
||||
Compiler@endlink once they have been built and can be safely used no matter
|
||||
previous or subsequent compilations of AX code. There are a variety of settings
|
||||
on the executables to control runtime behaviour - below demonstrates an example
|
||||
of using this API:
|
||||
@par
|
||||
@code{.cpp}
|
||||
using namespace openvdb;
|
||||
|
||||
ax::Compiler compiler; // compiler
|
||||
|
||||
FloatGrid a;
|
||||
a.setName("a");
|
||||
a.tree().setValueOn({0,0,0}, 1.0f); // set single coordinate to active 1.0f
|
||||
|
||||
const ax::VolumeExecutable::Ptr exe1 =
|
||||
compiler.compile<ax::VolumeExecutable>("f@a += 1.0f;");
|
||||
exe1->execute(a); // run over active leaf voxels in parallel
|
||||
|
||||
ax::VolumeExecutable::Ptr exe2 =
|
||||
compiler.compile<ax::VolumeExecutable>("f@a += 2.0f;");
|
||||
|
||||
// set to process all voxels
|
||||
exe2->setValueIterator(ax::VolumeExecutable::IterType::ALL);
|
||||
exe2->execute(a); // run over active and inactive leaf voxels in parallel
|
||||
|
||||
std::cout << a.tree().getValue({0,0,0}) << std::endl; // prints 4.0f
|
||||
std::cout << a.tree().getValue({1,0,0}) << std::endl; // prints 2.0f
|
||||
@endcode
|
||||
|
||||
@par Executable Thread Safety
|
||||
The executables are responsible for launching the compiled AX kernels and may
|
||||
internally use multiple threads. Multiple executables of any type can co-exist
|
||||
and be executed concurrently with unique arguments. For example:
|
||||
@par
|
||||
@code{.cpp}
|
||||
|
||||
FloatGrid a1, a2; // assume both are named "a"
|
||||
auto exe1 = compiler.compile<ax::VolumeExecutable>("f@a += 1.0f;");
|
||||
auto exe2 = compiler.compile<ax::VolumeExecutable>("f@a += 2.0f;");
|
||||
|
||||
std::thread t1([&]() { exe1->execute(a1); } );
|
||||
std::thread t2([&]() {
|
||||
exe1->execute(a2); // safe even if exe1::execute is being used by another thread
|
||||
exe2->execute(a2); // safe, can be running alongside another executable
|
||||
});
|
||||
@endcode
|
||||
@par
|
||||
This is, however, only safe depending on the access pattern of the AX code, the
|
||||
iteration patterns of the executables and the grid data being fed to the
|
||||
`execute` methods. When we talk about the thread safety of these classes we are
|
||||
referring to the invocation of their execution method <b>with the same argument
|
||||
data</b> by multiple threads, @b not how many threads the executables themselves
|
||||
use (which can be configured by the `grainSize()` setting). Importantly, for a
|
||||
given VDB grid or VDB Points attribute <b>"foo"</b>:
|
||||
- For The @vdblink::ax::VolumeExecutable VolumeExecutable@endlink it is safe to
|
||||
call @vdblink::ax::VolumeExecutable VolumeExecutable::execute@endlink @b from
|
||||
multiple threads only if:
|
||||
- All relevant AX kernels <b>do not write</b> to grid @b foo.
|
||||
- For The @vdblink::ax::PointExecutable PointExecutable@endlink it is safe to
|
||||
call @vdblink::ax::PointExecutable PointExecutable::execute@endlink @b from
|
||||
multiple threads only if:
|
||||
- All relevant AX kernels <b>do not write</b> to attribute @b foo.
|
||||
- All relevant AX kernels <b>do not create</b> any attributes or groups.
|
||||
- All relevant AX kernels <b>do not modify</b> the @b position "P" attribute.
|
||||
@par
|
||||
For example:
|
||||
@par
|
||||
@code{.cpp}
|
||||
auto exe = compiler.compile<ax::VolumeExecutable>("@a = @b");
|
||||
|
||||
// Grid a1 and a2 called "a", b called "b". Grid b is given to both threads.
|
||||
// This is safe as we guarantee b is only read from
|
||||
std::thread t1([&]() { GridPtrVec v{a1,b}; exe1->execute(v); } );
|
||||
std::thread t2([&]() { GridPtrVec v{a2,b}; exe1->execute(v); } );
|
||||
@endcode
|
||||
@par
|
||||
You can use the tools provided in @ref Scanners.h to query data accesses on
|
||||
AX ASTs to verify access patterns of your data.
|
||||
|
||||
@subsubsection vdbaxcompilercustomdata Custom Data
|
||||
@par
|
||||
The AX language provides two main tokens to access memory which has not been
|
||||
allocated by AX itself. The first token, @b \@ (the "at" symbol), is designed to
|
||||
provide read/write access to geometry attributes. The second token is the dollar
|
||||
character @b $. This allows <b>read only</b> access to custom data that can be
|
||||
modified in C++ i.e. outside the scope of an AX program. In the same way as the
|
||||
@b \@attribute syntax, the value of this data can change without the need for AX
|
||||
to re-compile the program. It is, however, solely on the C++ clients of AX to
|
||||
make sure that this data is setup correctly when integrating AX into their
|
||||
applications.
|
||||
@par
|
||||
Consider this trivial example:
|
||||
@par
|
||||
<!-- A -->@code{.c}
|
||||
f@density = f$my_value;
|
||||
// f$my_value = f@density; NOTE: writing to $ values is disallowed
|
||||
@endcode
|
||||
@par
|
||||
When compiled, this program will attempt to read a single float type value with
|
||||
the storage name "my_value". If the value cannot be found, a zero intialized
|
||||
block of memory (with size of the desired type) is returned. So, with no further
|
||||
setup, this will assign each value of @b density to 0.0f.
|
||||
@par
|
||||
The @vdblink::ax::CustomData CustomData@endlink class provides the intermediary
|
||||
storage for this data between the code generation and the compiler. Clients
|
||||
should use this API to create and modify custom data which will become available
|
||||
to AX programs. Although the data is stored as abstract openvdb::Metadata
|
||||
objects, the values are embedded into AX programs as pointers to their location
|
||||
in memory. In practice this means that accessing data stored in this way is
|
||||
almost as fast as accessing an AX local variable, though certain optimizations,
|
||||
such as constant folding, will not apply. As previously mentioned, this also
|
||||
means that the AX program does not need to be recompiled should this value need
|
||||
to be changed.
|
||||
@par
|
||||
The @vdblink::ax::CustomData CustomData@endlink starts off detached from an
|
||||
executable and thus must be provided when invoking
|
||||
@vdblink::ax::Compiler::compile Compiler::compile()@endlink. It is then tied to
|
||||
the AX executable for its duration. The compiler will validate the types of
|
||||
all accessed data of an AX program and, if it does not exist, the data will be
|
||||
created. Note that multiple executables can access the same
|
||||
@vdblink::ax::CustomData CustomData@endlink instance.
|
||||
@par
|
||||
@code{.cpp}
|
||||
using namespace openvdb;
|
||||
|
||||
FloatGrid density;
|
||||
density.setName("density");
|
||||
|
||||
ax::Compiler compiler; // compiler
|
||||
ax::CustomData::Ptr data(new ax::CustomData); // empty custom data
|
||||
|
||||
// data provided to compile is now registered with this exe. "m_value" is created
|
||||
ax::VolumeExecutable::Ptr exe =
|
||||
compiler.compile<ax::VolumeExecutable>("f@density = f$my_value;", data);
|
||||
exe->execute(density); // my_value doesn't exist, density set to 0.0f
|
||||
|
||||
// Compiler::compile will have created this
|
||||
assert(data->hasValue<TypedMetadata<float>>("my_value"));
|
||||
|
||||
// get the data in its typed storage wrapper
|
||||
TypedMetadata<float>* meta = data->getValue<TypedMetadata<float>>("my_value");
|
||||
meta->set(1.0f); // set the value of "my_value" to 1.0f
|
||||
|
||||
// don't need to re-compile
|
||||
exe->execute(density); // density set to 1.0f
|
||||
@endcode
|
||||
@warning
|
||||
Care should be taken to ensure that modifications to custom data values are
|
||||
peformed outside of any calls to `execute()`. Any attempt to modify the data
|
||||
whilst executables attempt to access it will result in undefined behaviour.
|
||||
|
||||
@subsubsection vdbaxcodegen Codegen
|
||||
@par
|
||||
todo
|
||||
|
||||
@subsubsection vdbaxcompiler The Compiler
|
||||
@par
|
||||
The @vdblink::ax::Compiler Compiler@endlink brings together the above
|
||||
components. It is responsible setting up LLVM contexts and modules for a given
|
||||
AX program, invoking the compute generators, binding custom data, performing any
|
||||
necessary AX and LLVM optimisations and finally JIT compiling the program to a
|
||||
callable function. The @vdblink::ax::Compiler::compile() Compiler::compile()
|
||||
@endlink member functions execute the aforementioned steps and, if successful,
|
||||
return a pointer to an executable.
|
||||
@par
|
||||
There are two main ways to invoke compilation; one with an @vdblink::ax::Logger
|
||||
AX Logger@endlink and one without. The prior will either return a valid pointer
|
||||
to a generated executable on success or a `nullptr` on failure. It is guaranteed
|
||||
to never throw a code generation runtime error and expects the caller to either
|
||||
query or setup the state of the logger to handle warnings and errors. The latter
|
||||
internally creates a default logger which swallows warnings and prints all
|
||||
possible errors to `std::cerr`. Note that the latter will throw a runtime error
|
||||
on failure and is thus guaranteed to never return a `nullptr`.
|
||||
@par
|
||||
@code{.cpp}
|
||||
using namespace openvdb;
|
||||
|
||||
ax::Compiler compiler;
|
||||
std::vector<std::string> warn, err;
|
||||
// custom logger to collect warnings and errors
|
||||
ax::Logger logger(
|
||||
[&warn]() { warn.emplace_back(msg); },
|
||||
[&err]() { err.emplace_back(msg); }
|
||||
);
|
||||
|
||||
// logger provided, exe could be null if input is invalid
|
||||
auto exe = compiler.compile<ax::VolumeExecutable>("f@a = 1.0f;", logger);
|
||||
// print warnings
|
||||
for (cosnt auto& msg : warn) std::cout << msg << std::endl;
|
||||
if (!exe) {
|
||||
for (cosnt auto& msg : err) std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
// without logger, divison by zero warning won't be reported
|
||||
exe = compiler.compile<ax::VolumeExecutable>("f@a = 1.0f / 0.0f;");
|
||||
|
||||
// without logger, invalid AX will cause a runtime error but
|
||||
// also print errors to std::cerr
|
||||
try {
|
||||
exe = compiler.compile<ax::VolumeExecutable>("foo");
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "See above error logs..." << std::endl;
|
||||
}
|
||||
@endcode
|
||||
@warning
|
||||
A single instance of the @vdblink::ax::Compiler AX Compiler@endlink uses a
|
||||
uniquely constructed <A HREF="https://llvm.org/doxygen/classllvm_1_1LLVMContext.html">
|
||||
LLVMContext</A>. This context is @b shared between copies of the Compiler,
|
||||
however new Compilers create new LLVMContexts. It is therefor unsafe to invoke
|
||||
concurrent calls to @vdblink::ax::Compiler::compile() Compiler::compile()
|
||||
@endlink on Compilers which share the same underlying LLVMContext.
|
||||
@par
|
||||
@code{.cpp}
|
||||
ax::Compiler C1, C2;
|
||||
|
||||
// @warning Not safe!
|
||||
// std::thread t1([&]() { C1.compile<ax::VolumeExecutable>("@a;") } );
|
||||
// std::thread t2([&]() { C1.compile<ax::VolumeExecutable>("@b;") } );
|
||||
|
||||
// the following is safe as C1 and C2 are unique instances
|
||||
std::thread t1([&]() { C1.compile<ax::VolumeExecutable>("@a;") } );
|
||||
std::thread t2([&]() { C2.compile<ax::VolumeExecutable>("@a;") } );
|
||||
@endcode
|
||||
|
||||
|
||||
@subsection vdbaxbinary The Command Line Binary
|
||||
@par
|
||||
todo
|
||||
|
||||
<hr>
|
||||
|
||||
@section vdbaxtoaxtypes OpenVDB / OpenVDB AX Types
|
||||
@par
|
||||
Whilst OpenVDB AX is primarily designed for OpenVDB, it has its own notion of
|
||||
types. This is so that the actual AX language is able to support arithmetic that
|
||||
OpenVDB geometry would perhaps otherwise not support. For example, AX supports
|
||||
3x3 and 4x4 matrix types. These types are akin to the `openvdb::math::Mat` types
|
||||
that exist in OpenVDB library - however, historically, these types are not
|
||||
"registered Grid types" by default by OpenVDB. This means that, although you
|
||||
could theoretically create an `openvdb::Mat3dGrid` OpenVDB may not support the
|
||||
reading or writing of these grid types out the box. Whilst this may change in
|
||||
the future, there may exist other examples of types in AX which suffer from the
|
||||
same limitation of existing geometry types in OpenVDB.
|
||||
@par
|
||||
Native OpenVDB types are types which are @b a) registered for serialization and
|
||||
@b b) compilable by the default C++ installation of OpenVDB. This is a bit
|
||||
convoluted, so what does this actually mean in practice? Generally, accessing an
|
||||
@b attribute in AX requires that data to exist on the underlying geometry. As
|
||||
such, reading or writing to a given attribute (for example `bool@myattr`)
|
||||
requires both the AX compiler @b and the underlying geometry to support the
|
||||
given type. As mentioned above, there may be times where this isn't the case.
|
||||
Consider the following:
|
||||
@par
|
||||
<!-- A -->@code{.c}
|
||||
vec4i a = {1,2,3,4};
|
||||
vec4i@attr = a;
|
||||
@endcode
|
||||
@par
|
||||
Now lets assume that a notion of four `int32` values is not supported for
|
||||
serialization of OpenVDB points or volumes (we assume the type can at least be
|
||||
instantiated). Whilst this code may execute, serializing this data to disk may
|
||||
fail due to unregistered OpenVDB types. AX does @b not register any additional
|
||||
OpenVDB types. This choice is left to downstream software. In this example, to
|
||||
allow for serialization of `vec4` types, some variant of the following can be
|
||||
implemented in your application.
|
||||
@warning
|
||||
The choice to register Grid types in OpenVDB is left to the OpenVDB maintainers.
|
||||
There are important consequences to registering custom types - other default
|
||||
installations of OpenVDB <b>will not be able to read your files</b> unless
|
||||
compiled with similar instantiations.
|
||||
@par
|
||||
@code{.cpp}
|
||||
openvdb::initialize(); // standard init of vdb
|
||||
openvdb::ax::initialize(); // standard init of ax
|
||||
// Define a Vec4I grid type from the openvdb::math::Vec4<int32_t> class.
|
||||
// Use a ValueConverter to ensure the grid has the same configuration as
|
||||
// a standard OpenVDB grid type.
|
||||
using Vec4IGrid = openvdb::BoolGrid::ValueConverter<openvdb::Vec4I>::Type;
|
||||
// register this type
|
||||
Vec4IGrid::registerGrid();
|
||||
@endcode
|
||||
|
||||
<hr>
|
||||
@section vdbaxextend Extending OpenVDB AX
|
||||
<!--@subsection vdbaxcustomtraversal Custom AST Traversal-->
|
||||
<!--@subsection vdbaxcustomtraversal Designing an Executable-->
|
||||
<!--@subsection vdbaxcustomtraversal Geometry Callbacks-->
|
||||
<!--@subsection vdbaxcustomtraversal Custom Code Generation-->
|
||||
</div>
|
||||
*/
|
||||
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
<div style="width:800px;text-align:justify;">
|
||||
|
||||
@page axexamples AX Code Examples
|
||||
|
||||
@section axexamplesintro AX Code Examples
|
||||
@par
|
||||
This page demonstrates a range of examples which use AX to manipulate OpenVDB
|
||||
point and volume data and can be used as a quick start demonstration on the
|
||||
capabilities of the software. These examples are constantly being updated but
|
||||
do not cover all aspects of AX!
|
||||
|
||||
@section axexamplecontents Contents
|
||||
- @ref axexamplepoints
|
||||
- @ref axexamplepointbasic
|
||||
- @ref axexamplepointdelete
|
||||
- @ref axexamplepointdrag
|
||||
- @ref axexamplepointcurlnoise
|
||||
- @ref axexamplepointtransforms
|
||||
- @ref axexamplevolumes
|
||||
- @ref axexamplevolumeclamp
|
||||
- @ref axexamplevolumevel
|
||||
- @ref axexamplevolumeblend
|
||||
|
||||
|
||||
@section axexamplepoints Points Examples
|
||||
@par
|
||||
These examples demonstrate how to use AX on OpenVDB points grids.
|
||||
|
||||
@subsection axexamplepointbasic Basic point attributes
|
||||
@par
|
||||
Below is a small example which demonstrates working with a few point attributes.
|
||||
The @ symbol is the identifier for an AX attribute. The type of each attribute
|
||||
is specified before the @ symbol and the name is specified afterwards. For
|
||||
example: @b `int@count` would imply an @b integer attribute called @b count.
|
||||
@par
|
||||
In this example there are three point attributes: a @b float attribute @b speed,
|
||||
a @b vec3f float attribute @b velocity and a @b vec3f float attribute @b colour.
|
||||
@par
|
||||
This snippet uses the functions @ref axlength "length" and @ref axfit "fit" to
|
||||
give points a colour between black and white based on their speed.
|
||||
@par
|
||||
<!-- P -->@code{.c}
|
||||
// This statement writes to a new float attribute called speed and reads from a
|
||||
// vector float attribute called velocity. The length function is used here to
|
||||
// return the length of the point's velocity vector.
|
||||
float@speed = length(vec3f@velocity);
|
||||
|
||||
// Points that move faster than this threshold will all be mapped to the same
|
||||
// colour (white).
|
||||
float fast_threshold = 6.f;
|
||||
|
||||
// Writing a single value to a vector will mean that all components of the
|
||||
// vector are assigned the same value.
|
||||
vec3f@colour = fit(float@speed, 0, fast_threshold, 0, 1);
|
||||
@endcode
|
||||
@par
|
||||
The @b velocity attribute in this example is assumed to exist and have a range
|
||||
of values to produce some visual variance in colour. The attributes @b speed and
|
||||
@b colour do not need to exist before this snippet is run as the attributes are
|
||||
only written to and will be created on the fly.
|
||||
@par
|
||||
@note
|
||||
In Houdini (AX SOP) changing the name of the attribute from @b colour to @b Cd
|
||||
will result in the points being given a colour in the viewport as Cd is a
|
||||
special attribute.
|
||||
|
||||
@subsection axexamplepointdelete Deleting Points
|
||||
@par
|
||||
This example demonstrates a simple way of removing points from a VDB points grid.
|
||||
It uses a combination of @ref axrand and @ref axdeletepoint to randomly delete
|
||||
roughly half of the points in the input VDB points grid.
|
||||
@par
|
||||
<!-- P -->@code{.c}
|
||||
float threshold = 0.5f;
|
||||
|
||||
// The rand function takes a seed and produces a random value between 0 and 1.
|
||||
// The integer attribute id from the points is used to seed the rand function.
|
||||
// If the value from rand is greater than the threshold (0.5) then delete the point.
|
||||
if (rand(int64@id) > threshold) {
|
||||
deletepoint();
|
||||
}
|
||||
@endcode
|
||||
@par
|
||||
The @b id attribute in this example is assumed to be a unique @b integer for
|
||||
each point in the VDB points grid such that @ref axrand will receive a
|
||||
different seed value per point producing a good distribution of random values.
|
||||
|
||||
@subsection axexamplepointdrag Applying Drag
|
||||
@par
|
||||
This example shows something a bit more complex: modifying a point's velocity
|
||||
with a drag force and then moving the point with the modified velocity.
|
||||
@par
|
||||
<!-- P -->@code{.c}
|
||||
float dt = 1.0f / (4.0f * 24.0f); // timestep
|
||||
vec3f gravity = {0.0f, -9.81f, 0.0f}; // gravity
|
||||
vec3f dV = {2.0f, 0.0f, 0.0f} - v@v; // drag
|
||||
|
||||
float lengthV = length(dV);
|
||||
float Re = lengthV * @rad / 1.225f;
|
||||
float C = 0.0f;
|
||||
|
||||
if (Re > 1000.0f) C = 24.0f / Re;
|
||||
else C = 0.424f;
|
||||
|
||||
// calculate drag force
|
||||
vec3f drag = 0.5f * 1.2f * C * lengthV * dV * 4.0f * 3.14f * pow(@rad, 2.0f);
|
||||
|
||||
// update velocity
|
||||
v@v += (gravity - drag / ((4.0f / 3.0f) * 3.14f * pow(@rad, 3.0f))) * dt;
|
||||
|
||||
// update position
|
||||
v@P += v@v * dt;
|
||||
@endcode
|
||||
@par
|
||||
The final AX command, `v@P += v@v * dt;` writes to the position attribute of
|
||||
the points @b `v@P`. Whenever position is written to in this way, the AX
|
||||
`PointExecutable` will move (re-bucket) points in PointDataGrids.
|
||||
|
||||
@subsection axexamplepointcurlnoise Curl Noise
|
||||
@par
|
||||
The following example demonstrates using various native AX functions to
|
||||
calculate a position based curl noise on points in a particular group, and to
|
||||
use that calculation to update point velocities.
|
||||
@par
|
||||
<!-- P -->@code{.c}
|
||||
// Only calcualte noise and apply it to points if the current point is NOT in
|
||||
// a group called "escaped". Note that the PointExecutable also has native
|
||||
// support for group based execution.
|
||||
if (!ingroup("escaped")) {
|
||||
|
||||
// Read custom data
|
||||
float amplitude = $amplitude;
|
||||
float persistence = $persistence;
|
||||
float lacunarity = $lacunarity;
|
||||
vec3f freq = vec3f$frequency;
|
||||
vec3f offset = vec3f$offset;
|
||||
|
||||
vec3f noise = 0.0f;
|
||||
|
||||
// Position based curl simplex noise
|
||||
for (int octave = 0; octave < int($octaves); ++octave) {
|
||||
vec3f noisePos = vec3f@P * freq + offset;
|
||||
noise += curlsimplexnoise(noisePos) * amplitude;
|
||||
amplitude *= persistence;
|
||||
freq *= lacunarity;
|
||||
}
|
||||
|
||||
// Apply noise scaled by the current velocity length
|
||||
vec3f@v += length(vec3f@v) * noise;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@subsection axexamplepointtransforms Transformations
|
||||
@par
|
||||
AX supports 3x3 and 4x4 matrix types and various transformations. They can be
|
||||
accessed via row, column operators or as a flat array and have defined
|
||||
operators (such as matrix multiplication etc.). The following demonstrates
|
||||
some trivial matrix math on VDB Point positions.
|
||||
@par
|
||||
<!-- P -->@code{.c}
|
||||
// get the 4x4 identity matrix. note that scalar->matrix promotion handles
|
||||
// this, so writing 'mat4f transform = 1;' has the same effect.
|
||||
mat4f transform = identity4();
|
||||
|
||||
// set the X transform component
|
||||
transform[3,0] = 5;
|
||||
|
||||
// pre scale the matrix. this is equal to writing: 'transform = scale * transform;'
|
||||
vec3f scale = { 1,2,3 };
|
||||
prescale(transform, scale);
|
||||
|
||||
// double the value of the scale Y component
|
||||
transform[5] *= 2;
|
||||
|
||||
// construct a basic rotation matrix, representing 90 degree rotation around Y
|
||||
float degrees = 90.0f;
|
||||
float rad = radians(degrees);
|
||||
mat3f rotation = {
|
||||
cos(rad), 0.0f, -sin(rad),
|
||||
0.0f, 1.0f, 0.0f,
|
||||
sin(rad), 0.0f, cos(rad)
|
||||
};
|
||||
|
||||
// apply the rotation and transformation to the current points position
|
||||
vec3f@P *= rotation;
|
||||
vec3f@P *= transform;
|
||||
@endcode
|
||||
|
||||
|
||||
<br/><hr>
|
||||
|
||||
|
||||
@section axexamplevolumes Volume Examples
|
||||
@par
|
||||
These examples demonstrate how to use AX on VDB volume grids.
|
||||
|
||||
@subsection axexamplevolumeclamp Volume Clamping
|
||||
@par
|
||||
Below is a small example of reading adn writing to voxels within a VDB volume.
|
||||
As with points, the @ symbol specifies an access to a named volume, with the
|
||||
type of each volume preceding it and the name appearing as a suffix. For
|
||||
example: `float@density` would imply a @b float volume called @b density.
|
||||
@par
|
||||
This snippet uses @ref axclamp function to constrain the @b density attribute
|
||||
between zero and one.
|
||||
@par
|
||||
<!-- V -->@code{.c}
|
||||
float@density = clamp(float@density, 0.f, 1.f);
|
||||
@endcode
|
||||
|
||||
@subsection axexamplevolumevel Velocity Update
|
||||
@par
|
||||
AX can be used to read and write to multiple volumes. Here we have a typical
|
||||
example of a eulerian velocity update which takes into account an updated
|
||||
vector force and scalar mass.
|
||||
@par
|
||||
<!-- V -->@code{.c}
|
||||
// Access the current timestep - this could instead be provided by the AX
|
||||
// integration and made accessible with custom data (i/e: float$timestep)
|
||||
float dt = 1.0f / 24.0f;
|
||||
// read from the mass grid the corresponding (matching index space) value
|
||||
float mass = float@mass;
|
||||
// safe divide, in case mass is zero
|
||||
float massInverse = 0.0f;
|
||||
if (mass > 0.0f) massInverse = 1.0f / mass;
|
||||
|
||||
// update the current velocity value by scaling the corresponding force
|
||||
// by the timestep and inverse mass
|
||||
vec3f@vel += dt * massInverse * vec3f@force;
|
||||
@endcode
|
||||
|
||||
@subsection axexamplevolumeblend Linear Blending
|
||||
@par
|
||||
Here we demonstrate how AX can be used to blend two volumes together. Note that
|
||||
only the volumes which are written to are executed over. In the below code,
|
||||
only @b `@surface_a` is written to. This means that the final blended result,
|
||||
stored in `surface_a`, will only be updated in `surface_a`'s topology. Should
|
||||
we want a combined blend of @b non @b overlapping areas of both surface a and b,
|
||||
we would need to activate a's topology with respect to b first.
|
||||
@par
|
||||
<!-- V -->@code{.c}
|
||||
// time constants for each run.
|
||||
float time = float$time;
|
||||
float maxDuration = 100.0f;
|
||||
|
||||
// read both surface a and surface b values
|
||||
float a = @surface_a; // source value
|
||||
float b = @surface_b; // target value
|
||||
|
||||
// calculate the fractional mask value in respect to time
|
||||
float mask = time / maxDuration;
|
||||
|
||||
// optionally scale the mask by a per index space density. if
|
||||
// $enable_density_mask is true, a density grid is used to vary the blend per
|
||||
// voxel
|
||||
if ($enable_density_mask) mask *= @density;
|
||||
|
||||
// finally, clamp the mask value and update the level set value in surface a.
|
||||
// Note that this may produce a no longer valid level set and might need to be
|
||||
// rebuilt!
|
||||
mask = clamp(mask, 0.0f, 1.0f);
|
||||
@surface_a = a + (b-a) * mask;
|
||||
@endcode
|
||||
|
||||
</div>
|
||||
*/
|
||||
@@ -0,0 +1,886 @@
|
||||
/**
|
||||
<div style="width:800px;text-align:justify;">
|
||||
|
||||
@page axfunctionlist AX Supported Functions
|
||||
|
||||
This page holds the full list of functions currently supported by AX. It is
|
||||
usually automatically updated from the most recent output of the @ref vdbaxbinary
|
||||
"vdb_ax binary's" function option.
|
||||
|
||||
@section axfunccontents Functions
|
||||
<ul style="height: 500px; display:flex; flex-direction:column; flex-wrap:wrap;">
|
||||
<li> @ref axabs "abs"</li>
|
||||
<li> @ref axacos "acos"</li>
|
||||
<li> @ref axacosh "acosh"</li>
|
||||
<li> @ref axaddtogroup "addtogroup"</li>
|
||||
<li> @ref axadjoint "adjoint"</li>
|
||||
<li> @ref axargsort "argsort"</li>
|
||||
<li> @ref axasin "asin"</li>
|
||||
<li> @ref axasinh "asinh"</li>
|
||||
<li> @ref axatan "atan"</li>
|
||||
<li> @ref axatan2 "atan2"</li>
|
||||
<li> @ref axatanh "atanh"</li>
|
||||
<li> @ref axatof "atof"</li>
|
||||
<li> @ref axatoi "atoi"</li>
|
||||
<li> @ref axcbrt "cbrt"</li>
|
||||
<li> @ref axceil "ceil"</li>
|
||||
<li> @ref axclamp "clamp"</li>
|
||||
<li> @ref axcofactor "cofactor"</li>
|
||||
<li> @ref axcos "cos"</li>
|
||||
<li> @ref axcosh "cosh"</li>
|
||||
<li> @ref axcross "cross"</li>
|
||||
<li> @ref axcurlsimplexnoise "curlsimplexnoise"</li>
|
||||
<li> @ref axdegrees "degrees"</li>
|
||||
<li> @ref axdeletepoint "deletepoint"</li>
|
||||
<li> @ref axdeterminant "determinant"</li>
|
||||
<li> @ref axdiag "diag"</li>
|
||||
<li> @ref axdot "dot"</li>
|
||||
<li> @ref axeuclideanmod "euclideanmod"</li>
|
||||
<li> @ref axexp "exp"</li>
|
||||
<li> @ref axexp2 "exp2"</li>
|
||||
<li> @ref axexternal "external"</li>
|
||||
<li> @ref axexternalv "externalv"</li>
|
||||
<li> @ref axfabs "fabs"</li>
|
||||
<li> @ref axfit "fit"</li>
|
||||
<li> @ref axfloor "floor"</li>
|
||||
<li> @ref axfloormod "floormod"</li>
|
||||
<li> @ref axgetcoordx "getcoordx"</li>
|
||||
<li> @ref axgetcoordy "getcoordy"</li>
|
||||
<li> @ref axgetcoordz "getcoordz"</li>
|
||||
<li> @ref axgetvoxelpws "getvoxelpws"</li>
|
||||
<li> @ref axhash "hash"</li>
|
||||
<li> @ref axidentity3 "identity3"</li>
|
||||
<li> @ref axidentity4 "identity4"</li>
|
||||
<li> @ref axingroup "ingroup"</li>
|
||||
<li> @ref axinverse "inverse"</li>
|
||||
<li> @ref axisfinite "isfinite"</li>
|
||||
<li> @ref axisinf "isinf"</li>
|
||||
<li> @ref axisnan "isnan"</li>
|
||||
<li> @ref axlength "length"</li>
|
||||
<li> @ref axlengthsq "lengthsq"</li>
|
||||
<li> @ref axlerp "lerp"</li>
|
||||
<li> @ref axlog "log"</li>
|
||||
<li> @ref axlog10 "log10"</li>
|
||||
<li> @ref axlog2 "log2"</li>
|
||||
<li> @ref axmax "max"</li>
|
||||
<li> @ref axmin "min"</li>
|
||||
<li> @ref axnormalize "normalize"</li>
|
||||
<li> @ref axpolardecompose "polardecompose"</li>
|
||||
<li> @ref axpostscale "postscale"</li>
|
||||
<li> @ref axpow "pow"</li>
|
||||
<li> @ref axprescale "prescale"</li>
|
||||
<li> @ref axpretransform "pretransform"</li>
|
||||
<li> @ref axprint "print"</li>
|
||||
<li> @ref axradians "radians"</li>
|
||||
<li> @ref axrand "rand"</li>
|
||||
<li> @ref axrand32 "rand32"</li>
|
||||
<li> @ref axremovefromgroup "removefromgroup"</li>
|
||||
<li> @ref axround "round"</li>
|
||||
<li> @ref axsign "sign"</li>
|
||||
<li> @ref axsignbit "signbit"</li>
|
||||
<li> @ref axsimplexnoise "simplexnoise"</li>
|
||||
<li> @ref axsin "sin"</li>
|
||||
<li> @ref axsinh "sinh"</li>
|
||||
<li> @ref axsort "sort"</li>
|
||||
<li> @ref axsqrt "sqrt"</li>
|
||||
<li> @ref axtan "tan"</li>
|
||||
<li> @ref axtanh "tanh"</li>
|
||||
<li> @ref axtrace "trace"</li>
|
||||
<li> @ref axtransform "transform"</li>
|
||||
<li> @ref axtranspose "transpose"</li>
|
||||
<li> @ref axtruncatemod "truncatemod"</li>
|
||||
</ul><hr>
|
||||
|
||||
|
||||
@anchor axabs
|
||||
@par abs
|
||||
Computes the absolute value of an integer number.
|
||||
@code{.c}
|
||||
int64(int64 n);
|
||||
int32(int32 n);
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axacos
|
||||
@par acos
|
||||
Computes the principal value of the arc cosine of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axacosh
|
||||
@par acosh
|
||||
Computes the inverse hyperbolic cosine of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axaddtogroup
|
||||
@par addtogroup
|
||||
Add the current point to the given group name, effectively setting its membership to true. If the
|
||||
group does not exist, it is implicitly created. This function has no effect if the point
|
||||
already belongs to the given group.
|
||||
@code{.c}
|
||||
void(string);
|
||||
@endcode
|
||||
|
||||
@anchor axadjoint
|
||||
@par adjoint
|
||||
Returns the adjoint of a 3x3 matrix. That is, the transpose of its cofactor matrix.
|
||||
@code{.c}
|
||||
mat3d(mat3d input);
|
||||
mat3f(mat3f input);
|
||||
@endcode
|
||||
|
||||
@anchor axargsort
|
||||
@par argsort
|
||||
Returns a vector of the indexes that would sort the input vector.
|
||||
@code{.c}
|
||||
vec3i(vec3d v);
|
||||
vec3i(vec3f v);
|
||||
vec3i(vec3i v);
|
||||
vec4i(vec4d v);
|
||||
vec4i(vec4f v);
|
||||
vec4i(vec4i v);
|
||||
@endcode
|
||||
|
||||
@anchor axasin
|
||||
@par asin
|
||||
Computes the principal value of the arc sine of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axasinh
|
||||
@par asinh
|
||||
Computes the inverse hyperbolic sine of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axatan
|
||||
@par atan
|
||||
Computes the principal value of the arc tangent of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axatan2
|
||||
@par atan2
|
||||
Computes the arc tangent of y/x using the signs of arguments to determine the correct quadrant.
|
||||
@code{.c}
|
||||
double(double y; double x);
|
||||
float(float y; float x);
|
||||
@endcode
|
||||
|
||||
@anchor axatanh
|
||||
@par atanh
|
||||
Computes the inverse hyperbolic tangent of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axatof
|
||||
@par atof
|
||||
Parses the string input, interpreting its content as a floating point number and returns its value
|
||||
as a double.
|
||||
@code{.c}
|
||||
double(i8* str);
|
||||
@endcode
|
||||
|
||||
@anchor axatoi
|
||||
@par atoi
|
||||
Parses the string input interpreting its content as an integral number, which is returned as a value
|
||||
of type int.
|
||||
@code{.c}
|
||||
int32(i8* str);
|
||||
@endcode
|
||||
|
||||
@anchor axcbrt
|
||||
@par cbrt
|
||||
Computes the cubic root of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axceil
|
||||
@par ceil
|
||||
Computes the smallest integer value not less than arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axclamp
|
||||
@par clamp
|
||||
Clamps the first argument to the minimum second argument value and maximum third argument value
|
||||
@code{.c}
|
||||
double(double in; double min; double max);
|
||||
float(float in; float min; float max);
|
||||
int64(int64 in; int64 min; int64 max);
|
||||
int32(int32 in; int32 min; int32 max);
|
||||
@endcode
|
||||
|
||||
@anchor axcofactor
|
||||
@par cofactor
|
||||
Returns the cofactor matrix of a 3x3 matrix. That is, the matrix of its cofactors.
|
||||
@code{.c}
|
||||
mat3d(mat3d input);
|
||||
mat3f(mat3f input);
|
||||
@endcode
|
||||
|
||||
@anchor axcos
|
||||
@par cos
|
||||
Computes the cosine of arg (measured in radians).
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axcosh
|
||||
@par cosh
|
||||
Computes the hyperbolic cosine of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axcross
|
||||
@par cross
|
||||
Returns the length of the given vector
|
||||
@code{.c}
|
||||
vec3d(vec3d a; vec3d b);
|
||||
vec3f(vec3f a; vec3f b);
|
||||
vec3i(vec3i a; vec3i b);
|
||||
@endcode
|
||||
|
||||
@anchor axcurlsimplexnoise
|
||||
@par curlsimplexnoise
|
||||
Generates divergence-free 3D noise, computed using a curl function on Simplex Noise.
|
||||
@code{.c}
|
||||
vec3d(vec3d pos);
|
||||
vec3d(double pos; double; double);
|
||||
@endcode
|
||||
|
||||
@anchor axdegrees
|
||||
@par degrees
|
||||
Converts the number of radians to degrees.
|
||||
@code{.c}
|
||||
double(double radians);
|
||||
float(float radians);
|
||||
@endcode
|
||||
|
||||
@anchor axdeletepoint
|
||||
@par deletepoint
|
||||
Delete the current point from the point set. Note that this does not stop AX execution - any
|
||||
additional AX commands will be executed on the point and it will remain accessible until the
|
||||
end of execution.
|
||||
@code{.c}
|
||||
void();
|
||||
@endcode
|
||||
|
||||
@anchor axdeterminant
|
||||
@par determinant
|
||||
Returns the determinant of a matrix.
|
||||
@code{.c}
|
||||
double(mat3d mat);
|
||||
float(mat3f mat);
|
||||
double(mat4d mat);
|
||||
float(mat4f mat);
|
||||
@endcode
|
||||
|
||||
@anchor axdiag
|
||||
@par diag
|
||||
Create a diagonal matrix from a vector, or return the diagonal components of a matrix as a vector.
|
||||
@code{.c}
|
||||
vec3d(mat3d vec);
|
||||
vec3f(mat3f vec);
|
||||
vec4d(mat4d vec);
|
||||
vec4f(mat4f vec);
|
||||
mat3d(vec3d mat);
|
||||
mat3f(vec3f mat);
|
||||
mat4d(vec4d mat);
|
||||
mat4f(vec4f mat);
|
||||
@endcode
|
||||
|
||||
@anchor axdot
|
||||
@par dot
|
||||
Computes the dot product of two vectors.
|
||||
@code{.c}
|
||||
double(vec3d a; vec3d b);
|
||||
float(vec3f a; vec3f b);
|
||||
int32(vec3i a; vec3i b);
|
||||
@endcode
|
||||
|
||||
@anchor axeuclideanmod
|
||||
@par euclideanmod
|
||||
Euclidean modulo, where by the result of the division operator on (dividend / divisor) is floored or
|
||||
ceiled depending on its sign, guaranteeing that the return value is always positive. The
|
||||
remainder is thus calculated with D - d * (d < 0 ? ceil(D/d) : floor(D/d)). This is NOT equal
|
||||
to a%b in AX. See truncatemod(), floormod().
|
||||
@code{.c}
|
||||
double(double dividend; double divisor);
|
||||
float(float dividend; float divisor);
|
||||
int64(int64 dividend; int64 divisor);
|
||||
int32(int32 dividend; int32 divisor);
|
||||
@endcode
|
||||
|
||||
@anchor axexp
|
||||
@par exp
|
||||
Computes e (Euler's number, 2.7182818...) raised to the given power arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axexp2
|
||||
@par exp2
|
||||
Computes 2 raised to the given power arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axexternal
|
||||
@par external
|
||||
Find a custom user parameter with a given name of type 'float' in the Custom data provided to the AX
|
||||
compiler. If the data can not be found, or is not of the expected type 0.0f is returned.
|
||||
@code{.c}
|
||||
float(string str);
|
||||
@endcode
|
||||
|
||||
@anchor axexternalv
|
||||
@par externalv
|
||||
Find a custom user parameter with a given name of type 'vector float' in the Custom data provided to
|
||||
the AX compiler. If the data can not be found, or is not of the expected type { 0.0f, 0.0f,
|
||||
0.0f } is returned.
|
||||
@code{.c}
|
||||
vec3f(string str);
|
||||
@endcode
|
||||
|
||||
@anchor axfabs
|
||||
@par fabs
|
||||
Computes the absolute value of a floating point value arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axfit
|
||||
@par fit
|
||||
Fit the first argument to the output range by first clamping the value between the second and third
|
||||
input range arguments and then remapping the result to the output range fourth and fifth
|
||||
arguments
|
||||
@code{.c}
|
||||
double(double value; double omin; double omax; double nmin; double nmax);
|
||||
float(float value; float omin; float omax; float nmin; float nmax);
|
||||
double(int64 value; int64 omin; int64 omax; int64 nmin; int64 nmax);
|
||||
double(int32 value; int32 omin; int32 omax; int32 nmin; int32 nmax);
|
||||
@endcode
|
||||
|
||||
@anchor axfloor
|
||||
@par floor
|
||||
Computes the largest integer value not greater than arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axfloormod
|
||||
@par floormod
|
||||
Floored modulo, where the result of the division operator on (dividend / divisor) is floored. The
|
||||
remainder is thus calculated with D - d * floor(D/d). This is the implemented modulo % operator
|
||||
of AX. This is equal to the python % implementation. See trucnatemod(), euclideanmod().
|
||||
@code{.c}
|
||||
double(double dividend; double divisor);
|
||||
float(float dividend; float divisor);
|
||||
int64(int64 dividend; int64 divisor);
|
||||
int32(int32 dividend; int32 divisor);
|
||||
@endcode
|
||||
|
||||
@anchor axgetcoordx
|
||||
@par getcoordx
|
||||
Returns the current voxel's X index value in index space as an integer.
|
||||
@code{.c}
|
||||
int32();
|
||||
@endcode
|
||||
|
||||
@anchor axgetcoordy
|
||||
@par getcoordy
|
||||
Returns the current voxel's Y index value in index space as an integer.
|
||||
@code{.c}
|
||||
int32();
|
||||
@endcode
|
||||
|
||||
@anchor axgetcoordz
|
||||
@par getcoordz
|
||||
Returns the current voxel's Z index value in index space as an integer.
|
||||
@code{.c}
|
||||
int32();
|
||||
@endcode
|
||||
|
||||
@anchor axgetvoxelpws
|
||||
@par getvoxelpws
|
||||
Returns the current voxel's position in world space as a vector float.
|
||||
@code{.c}
|
||||
vec3f();
|
||||
@endcode
|
||||
|
||||
@anchor axhash
|
||||
@par hash
|
||||
Return a hash of the provided string.
|
||||
@code{.c}
|
||||
int64(string str);
|
||||
@endcode
|
||||
|
||||
@anchor axidentity3
|
||||
@par identity3
|
||||
Returns the 3x3 identity matrix
|
||||
@code{.c}
|
||||
mat3f();
|
||||
@endcode
|
||||
|
||||
@anchor axidentity4
|
||||
@par identity4
|
||||
Returns the 4x4 identity matrix
|
||||
@code{.c}
|
||||
mat4f();
|
||||
@endcode
|
||||
|
||||
@anchor axingroup
|
||||
@par ingroup
|
||||
Return whether or not the current point is a member of the given group name. This returns false if
|
||||
the group does not exist.
|
||||
@code{.c}
|
||||
bool(string);
|
||||
@endcode
|
||||
|
||||
@anchor axinverse
|
||||
@par inverse
|
||||
Return the inverse of a 3x3 matrix.If the matrix is singular, returns the input matrix.
|
||||
@code{.c}
|
||||
mat3d(mat3d input);
|
||||
mat3f(mat3f input);
|
||||
@endcode
|
||||
|
||||
@anchor axisfinite
|
||||
@par isfinite
|
||||
Returns whether the value is finite i.e. not infinite or NaN. For matrix and vector types will
|
||||
return false if any element is not finite.
|
||||
@code{.c}
|
||||
bool(vec2d);
|
||||
bool(vec2f);
|
||||
bool(vec3d);
|
||||
bool(vec3f);
|
||||
bool(vec4d);
|
||||
bool(vec4f);
|
||||
bool(mat3f);
|
||||
bool(mat3d);
|
||||
bool(mat4f);
|
||||
bool(mat4d);
|
||||
bool(double arg);
|
||||
bool(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axisinf
|
||||
@par isinf
|
||||
Returns whether the value is inf. For matrix and vector types will return true if any element is
|
||||
inf.
|
||||
@code{.c}
|
||||
bool(vec2d);
|
||||
bool(vec2f);
|
||||
bool(vec3d);
|
||||
bool(vec3f);
|
||||
bool(vec4d);
|
||||
bool(vec4f);
|
||||
bool(mat3f);
|
||||
bool(mat3d);
|
||||
bool(mat4f);
|
||||
bool(mat4d);
|
||||
bool(double arg);
|
||||
bool(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axisnan
|
||||
@par isnan
|
||||
Returns whether the value is NaN (not-a-number).
|
||||
@code{.c}
|
||||
bool(vec2d);
|
||||
bool(vec2f);
|
||||
bool(vec3d);
|
||||
bool(vec3f);
|
||||
bool(vec4d);
|
||||
bool(vec4f);
|
||||
bool(mat3f);
|
||||
bool(mat3d);
|
||||
bool(mat4f);
|
||||
bool(mat4d);
|
||||
bool(double arg);
|
||||
bool(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axlength
|
||||
@par length
|
||||
Returns the length of the given vector
|
||||
@code{.c}
|
||||
double(vec2d v);
|
||||
float(vec2f v);
|
||||
double(vec2i v);
|
||||
double(vec3d v);
|
||||
float(vec3f v);
|
||||
double(vec3i v);
|
||||
double(vec4d v);
|
||||
float(vec4f v);
|
||||
double(vec4i v);
|
||||
@endcode
|
||||
|
||||
@anchor axlengthsq
|
||||
@par lengthsq
|
||||
Returns the squared length of the given vector
|
||||
@code{.c}
|
||||
double(vec2d v);
|
||||
float(vec2f v);
|
||||
int32(vec2i v);
|
||||
double(vec3d v);
|
||||
float(vec3f v);
|
||||
int32(vec3i v);
|
||||
double(vec4d v);
|
||||
float(vec4f v);
|
||||
int32(vec4i v);
|
||||
@endcode
|
||||
|
||||
@anchor axlerp
|
||||
@par lerp
|
||||
Performs bilinear interpolation between the values. If the amount is outside the range 0 to 1, the
|
||||
values will be extrapolated linearly. If amount is 0, the first value is returned. If it is 1,
|
||||
the second value is returned. This implementation is guaranteed to be monotonic.
|
||||
@code{.c}
|
||||
double(double a; double b; double amount);
|
||||
float(float a; float b; float amount);
|
||||
@endcode
|
||||
|
||||
@anchor axlog
|
||||
@par log
|
||||
Computes the natural (base e) logarithm of arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axlog10
|
||||
@par log10
|
||||
Computes the common (base-10) logarithm of arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axlog2
|
||||
@par log2
|
||||
Computes the binary (base-2) logarithm of arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axmax
|
||||
@par max
|
||||
Returns the larger of the given values.
|
||||
@code{.c}
|
||||
double(double a; double b);
|
||||
float(float a; float b);
|
||||
int64(int64 a; int64 b);
|
||||
int32(int32 a; int32 b);
|
||||
@endcode
|
||||
|
||||
@anchor axmin
|
||||
@par min
|
||||
Returns the smaller of the given values.
|
||||
@code{.c}
|
||||
double(double a; double b);
|
||||
float(float a; float b);
|
||||
int64(int64 a; int64 b);
|
||||
int32(int32 a; int32 b);
|
||||
@endcode
|
||||
|
||||
@anchor axnormalize
|
||||
@par normalize
|
||||
Returns the normalized result of the given vector.
|
||||
@code{.c}
|
||||
vec3d(vec3d v);
|
||||
vec3f(vec3f v);
|
||||
vec3d(vec3i v);
|
||||
vec4d(vec4d v);
|
||||
vec4f(vec4f v);
|
||||
vec4d(vec4i v);
|
||||
@endcode
|
||||
|
||||
@anchor axpolardecompose
|
||||
@par polardecompose
|
||||
Decompose an invertible 3x3 matrix into its orthogonal (unitary) matrix and symmetric matrix
|
||||
components. If the determinant of the unitary matrix is 1 it is a rotation, otherwise if it is
|
||||
-1 there is some part reflection.
|
||||
@code{.c}
|
||||
bool(mat3d input; mat3d unitary; mat3d symmetric);
|
||||
bool(mat3f input; mat3f unitary; mat3f symmetric);
|
||||
@endcode
|
||||
|
||||
@anchor axpostscale
|
||||
@par postscale
|
||||
Post-scale a given matrix by the provided vector.
|
||||
@code{.c}
|
||||
void(mat4d transform; vec3d vec);
|
||||
void(mat4f transform; vec3f vec);
|
||||
@endcode
|
||||
|
||||
@anchor axpow
|
||||
@par pow
|
||||
Computes the value of the first argument raised to the power of the second argument.
|
||||
@code{.c}
|
||||
double(double base; double exp);
|
||||
float(float base; float exp);
|
||||
double(double base; int32 exp);
|
||||
@endcode
|
||||
|
||||
@anchor axprescale
|
||||
@par prescale
|
||||
Pre-scale a given matrix by the provided vector.
|
||||
@code{.c}
|
||||
void(mat4d transform; vec3d vec);
|
||||
void(mat4f transform; vec3f vec);
|
||||
@endcode
|
||||
|
||||
@anchor axpretransform
|
||||
@par pretransform
|
||||
Return the transformed vector by transpose of this matrix. This function is equivalent to
|
||||
pre-multiplying the matrix.
|
||||
@code{.c}
|
||||
vec3d(mat3d vec; vec3d mat);
|
||||
vec3f(mat3f vec; vec3f mat);
|
||||
vec3d(mat4d vec; vec3d mat);
|
||||
vec3f(mat4f vec; vec3f mat);
|
||||
vec4d(mat4d vec; vec4d mat);
|
||||
vec4f(mat4f vec; vec4f mat);
|
||||
@endcode
|
||||
|
||||
@anchor axprint
|
||||
@par print
|
||||
Prints the input to the standard output stream. Warning: This will be run for every element.
|
||||
@code{.c}
|
||||
void(double n);
|
||||
void(float n);
|
||||
void(int64 n);
|
||||
void(int32 n);
|
||||
void(string n);
|
||||
void(vec2i n);
|
||||
void(vec2f n);
|
||||
void(vec2d n);
|
||||
void(vec3i n);
|
||||
void(vec3f n);
|
||||
void(vec3d n);
|
||||
void(vec4i n);
|
||||
void(vec4f n);
|
||||
void(vec4d n);
|
||||
void(mat3f n);
|
||||
void(mat3d n);
|
||||
void(mat4f n);
|
||||
void(mat4d n);
|
||||
@endcode
|
||||
|
||||
@anchor axradians
|
||||
@par radians
|
||||
Converts the number of degrees to radians.
|
||||
@code{.c}
|
||||
double(double degrees);
|
||||
float(float degrees);
|
||||
@endcode
|
||||
|
||||
@anchor axrand
|
||||
@par rand
|
||||
Creates a random number based on the provided seed. The number will be in the range of 0 to 1. The
|
||||
same number is produced for the same seed. Note that if rand is called without a seed the
|
||||
previous state of the random number generator is advanced for the currently processing element.
|
||||
This state is determined by the last call to rand() with a given seed. If rand is not called
|
||||
with a seed, the generator advances continuously across different elements which can produce
|
||||
non-deterministic results. It is important that rand is always called with a seed at least once
|
||||
for deterministic results.
|
||||
@code{.c}
|
||||
double();
|
||||
double(double seed);
|
||||
double(int64 seed);
|
||||
@endcode
|
||||
|
||||
@anchor axrand32
|
||||
@par rand32
|
||||
Creates a random number based on the provided 32 bit seed. The number will be in the range of 0 to
|
||||
1. The same number is produced for the same seed. NOTE: This function does not share the same
|
||||
random number generator as rand(). rand32() may provide a higher throughput on some
|
||||
architectures, but will produce different results to rand(). NOTE: If rand32 is called without
|
||||
a seed the previous state of the random number generator is advanced for the currently
|
||||
processing element. This state is determined by the last call to rand32() with a given seed. If
|
||||
rand32 is not called with a seed, the generator advances continuously across different elements
|
||||
which can produce non-deterministic results. It is important that rand32 is always called with
|
||||
a seed at least once for deterministic results.
|
||||
@code{.c}
|
||||
double();
|
||||
double(double seed);
|
||||
double(int32 seed);
|
||||
@endcode
|
||||
|
||||
@anchor axremovefromgroup
|
||||
@par removefromgroup
|
||||
Remove the current point from the given group name, effectively setting its membership to false.
|
||||
This function has no effect if the group does not exist.
|
||||
@code{.c}
|
||||
void(string);
|
||||
@endcode
|
||||
|
||||
@anchor axround
|
||||
@par round
|
||||
Computes the nearest integer value to arg (in floating-point format), rounding halfway cases away
|
||||
from zero.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axsign
|
||||
@par sign
|
||||
Implements signum, determining if the input is negative, zero or positive. Returns -1 for a negative
|
||||
number, 0 for the number zero, and +1 for a positive number. Note that this function does not
|
||||
check the sign of floating point +/-0.0 values. See signbit().
|
||||
@code{.c}
|
||||
int32(double n);
|
||||
int32(float n);
|
||||
int32(int64 n);
|
||||
int32(int32 n);
|
||||
@endcode
|
||||
|
||||
@anchor axsignbit
|
||||
@par signbit
|
||||
Determines if the given floating point number input is negative. Returns true if arg is negative,
|
||||
false otherwise. Will return true for -0.0, false for +0.0
|
||||
@code{.c}
|
||||
bool(double n);
|
||||
bool(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axsimplexnoise
|
||||
@par simplexnoise
|
||||
Compute simplex noise at coordinates x, y and z. Coordinates which are not provided will be set to
|
||||
0.
|
||||
@code{.c}
|
||||
double(double x);
|
||||
double(double x; double y);
|
||||
double(double x; double y; double z);
|
||||
double(vec3d pos);
|
||||
@endcode
|
||||
|
||||
@anchor axsin
|
||||
@par sin
|
||||
Computes the sine of arg (measured in radians).
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axsinh
|
||||
@par sinh
|
||||
Computes the hyperbolic sine of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axsort
|
||||
@par sort
|
||||
Returns the sorted result of the given vector.
|
||||
@code{.c}
|
||||
vec3d(vec3d v);
|
||||
vec3f(vec3f v);
|
||||
vec3i(vec3i v);
|
||||
vec4d(vec4d v);
|
||||
vec4f(vec4f v);
|
||||
vec4i(vec4i v);
|
||||
@endcode
|
||||
|
||||
@anchor axsqrt
|
||||
@par sqrt
|
||||
Computes the square root of arg.
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axtan
|
||||
@par tan
|
||||
Computes the tangent of arg (measured in radians).
|
||||
@code{.c}
|
||||
double(double n);
|
||||
float(float n);
|
||||
@endcode
|
||||
|
||||
@anchor axtanh
|
||||
@par tanh
|
||||
Computes the hyperbolic tangent of the input.
|
||||
@code{.c}
|
||||
double(double arg);
|
||||
float(float arg);
|
||||
@endcode
|
||||
|
||||
@anchor axtrace
|
||||
@par trace
|
||||
Return the trace of a matrix, the sum of the diagonal elements.
|
||||
@code{.c}
|
||||
double(mat3d mat);
|
||||
float(mat3f mat);
|
||||
double(mat4d mat);
|
||||
float(mat4f mat);
|
||||
@endcode
|
||||
|
||||
@anchor axtransform
|
||||
@par transform
|
||||
Return the transformed vector by the provided matrix. This function is equivalent to
|
||||
post-multiplying the matrix, i.e. vec * mult.
|
||||
@code{.c}
|
||||
vec3d(vec3d vec; mat3d mat);
|
||||
vec3f(vec3f vec; mat3f mat);
|
||||
vec3d(vec3d vec; mat4d mat);
|
||||
vec3f(vec3f vec; mat4f mat);
|
||||
vec4d(vec4d vec; mat4d mat);
|
||||
vec4f(vec4f vec; mat4f mat);
|
||||
@endcode
|
||||
|
||||
@anchor axtranspose
|
||||
@par transpose
|
||||
Returns the transpose of a matrix
|
||||
@code{.c}
|
||||
mat3d(mat3d mat);
|
||||
mat3f(mat3f mat);
|
||||
mat4d(mat4d mat);
|
||||
mat4f(mat4f mat);
|
||||
@endcode
|
||||
|
||||
@anchor axtruncatemod
|
||||
@par truncatemod
|
||||
Truncated modulo, where the result of the division operator on (dividend / divisor) is truncated.
|
||||
The remainder is thus calculated with D - d * trunc(D/d). This is equal to the C/C++ %
|
||||
implementation. This is NOT equal to a%b in AX. See floormod(), euclideanmod().
|
||||
@code{.c}
|
||||
double(double dividend; double divisor);
|
||||
float(float dividend; float divisor);
|
||||
int64(int64 dividend; int64 divisor);
|
||||
int32(int32 dividend; int32 divisor);
|
||||
@endcode
|
||||
|
||||
|
||||
</div>
|
||||
*/
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
<div style="width:800px;text-align:justify;">
|
||||
|
||||
@page openvdbax OpenVDB AX
|
||||
|
||||
@section axoverview Overview
|
||||
@par
|
||||
<b>OpenVDB AX</b> is an open source C++ library that provides a powerful and
|
||||
easy way of interacting with OpenVDB volume and point data. The software strives
|
||||
to provide a concise, fast, highly parallalisable and portable solution to
|
||||
performing custom manipulation of OpenVDB data via an expression language: AX.
|
||||
AX expressions are JIT-compiled and used in combination with a multi-threaded
|
||||
execution framework, specifically designed for VDB, that in many cases rival
|
||||
custom C++ operators.
|
||||
|
||||
@b OpenVDB AX is maintained by the
|
||||
<A HREF="https://www.aswf.io/">Academy Software Foundation (ASWF)</A>.
|
||||
It was originally developed at <A HREF="https://www.dneg.com/">DNEG</A>
|
||||
primarily by:
|
||||
- Nick Avramoussis
|
||||
- Richard Jones
|
||||
|
||||
Other notable contributors include:
|
||||
- Francisco Gochez
|
||||
- Matthew Warner
|
||||
- Dan Bailey
|
||||
- Todd Keeler
|
||||
- James Bird
|
||||
- Harry Biddle
|
||||
|
||||
@subsection docs Documentation
|
||||
@par
|
||||
The doxygen documentation provide information on both AX as a language and the
|
||||
developer documentation for OpenVDB AX as a C++ API. There are two main sections:
|
||||
@par
|
||||
- The @subpage ax "AX Language Documentation" provides useful information for front-end users looking for documentation on the AX Language.
|
||||
- The @subpage axcplusplus "OpenVDB AX Documentation" provides API and other C++ specific software information for developers.
|
||||
@par
|
||||
Some additional quick links to useful subsections of the documentation are also
|
||||
provided:
|
||||
@par
|
||||
- @subpage axexamples "Code Examples" for examples of OpenVDB AX in action.
|
||||
- @subpage axfunctionlist "AX Functions" for a list of all available AX functions.
|
||||
- @subpage build "Building OpenVDB" and @subpage dependencies "OpenVDB Dependencies" for information on building OpenVDB and <b>OpenVDB AX</b>.
|
||||
|
||||
</div>
|
||||
*/
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
BINARY=$1
|
||||
if [ -z $BINARY ]; then
|
||||
BINARY=vdb_ax
|
||||
fi
|
||||
echo $BINARY
|
||||
|
||||
# Generates a doxygen function.txt file using the available vdb_ax binary
|
||||
|
||||
# Add the doxygen header for the functions file
|
||||
echo -n "/**
|
||||
<div style=\"width:800px;text-align:justify;\">
|
||||
|
||||
@page axfunctionlist AX Supported Functions
|
||||
|
||||
This page holds the full list of functions currently supported by AX. It is
|
||||
usually automatically updated from the most recent output of the @ref vdbaxbinary
|
||||
\"vdb_ax binary's\" function option.
|
||||
|
||||
@section axfunccontents Functions
|
||||
<ul style=\"height: 500px; display:flex; flex-direction:column; flex-wrap:wrap;\">
|
||||
" > functions.txt
|
||||
|
||||
# 1) Create the contents list (reference links to each function)
|
||||
# Get all the function names
|
||||
$BINARY functions --list-names > tmp.txt
|
||||
# Remove commans
|
||||
tr -d , < tmp.txt > tmp2.txt
|
||||
# Add new lines between names
|
||||
tr ' ' '\n' < tmp2.txt > tmp.txt
|
||||
# Remove empty lines (created by the vdb_ax binary wrapping output)
|
||||
sed '/^$/d' tmp.txt > tmp2.txt
|
||||
# Append doxygen references to each funciton
|
||||
sed -e 's/^\(.*\)/\t<li> @ref ax\1 \"\1\"<\/li>/' tmp2.txt >> functions.txt
|
||||
|
||||
# End the function list and add a line break
|
||||
echo -n "</ul><hr>
|
||||
|
||||
" >> functions.txt
|
||||
|
||||
# 2) Add all function descriptions and signatures from the binary
|
||||
# First add a new line - this is for the next sed call which looks for a new
|
||||
# line followed by the function name
|
||||
echo "" > tmp.txt
|
||||
$BINARY functions --list >> tmp.txt
|
||||
echo "" >> tmp.txt
|
||||
|
||||
# look for functions such:
|
||||
# \n
|
||||
# functionname
|
||||
# |
|
||||
# and wrap the name in anchors and paragraphs
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/\n\([a-z0-9]\+\)\n|/\n@anchor ax\1\n@par \1/g' tmp.txt
|
||||
# Remove all "| -" which exist before the function help
|
||||
sed -i 's/| - //g' tmp.txt
|
||||
# Replace |\n with @code{.c}
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/|\n/@code{.c}\n/g' tmp.txt
|
||||
# Append semicolons to functions
|
||||
sed -i 's/| - \(.*\)/\1;/g' tmp.txt
|
||||
# Replace ;\n\n with ;\n:@endcode\n\n
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/;\n\n/;\n@endcode\n\n/g' tmp.txt
|
||||
# Remove left over pipes
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/| //g' tmp.txt
|
||||
|
||||
# Combine
|
||||
cat tmp.txt >> functions.txt
|
||||
echo -n "</div>
|
||||
*/" >> functions.txt
|
||||
|
||||
# cleanup
|
||||
rm tmp.txt tmp2.txt
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
|
||||
BINARY=$1
|
||||
if [ -z $BINARY ]; then
|
||||
BINARY=vdb_ax
|
||||
fi
|
||||
|
||||
# Generates a houdini html function file using the available vdb_ax binary
|
||||
|
||||
# Add the header for the file
|
||||
echo -n "
|
||||
<style>
|
||||
|
||||
.axsignature {
|
||||
position: relative;
|
||||
color: #888; }
|
||||
.axname {
|
||||
color: black; }
|
||||
.axstring {
|
||||
color: #c39c79; }
|
||||
.axvec {
|
||||
color: #8d31ae; }
|
||||
.axmat {
|
||||
color: #60bc8f; }
|
||||
.axint {
|
||||
color: #91a835; }
|
||||
.axfloat {
|
||||
color: #06C; }
|
||||
.axdouble {
|
||||
color: #06C; }
|
||||
.axvoid {
|
||||
color: #ccc; }
|
||||
|
||||
</style>
|
||||
|
||||
Function ||
|
||||
Description ||
|
||||
Signatures ||
|
||||
" > functions.txt
|
||||
|
||||
# Echo out the full descriptions
|
||||
echo "" > tmp.txt
|
||||
$BINARY functions --list >> tmp.txt
|
||||
echo "" >> tmp.txt
|
||||
|
||||
# Get a list of names
|
||||
names=$($BINARY functions --list-names)
|
||||
names="${names//$'\n'/}"
|
||||
|
||||
# For each line in the full function file, see which function we're processing
|
||||
# and update each signature with the function name
|
||||
found=""
|
||||
new_data=""
|
||||
while IFS= read -r line; do
|
||||
# Scan for a function switch
|
||||
for name in $names; do
|
||||
name="${name//$','/}"
|
||||
if [[ "$name" == "$line" ]]; then
|
||||
found=$name
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If processing a function signature, add the function name
|
||||
if [[ $line == "| -"*"("* ]]; then
|
||||
line=$(sed 's/(/'" $found"'(/g' <<<"$line")
|
||||
fi
|
||||
new_data+=$line"\n"
|
||||
done < tmp.txt
|
||||
|
||||
echo -e "$new_data" > tmp.txt
|
||||
|
||||
# look for functions such:
|
||||
# \n
|
||||
# functionname
|
||||
# |
|
||||
# and wrap the name in code and format the end
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/\n\([a-z0-9]\+\)\n|/\n<p><code>\1<\/code><\/p> |/g' tmp.txt
|
||||
|
||||
# # Remove all "| -" which exist before the function help
|
||||
sed -i 's/| - /\t/g' tmp.txt
|
||||
# Replace pipes with tabs
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/| /\t/g' tmp.txt
|
||||
# # # Replace |\n with " |\n"
|
||||
sed -i -e ':a' -e 'N' -e '$!ba' -e 's/\n|\n/ |\n/g' tmp.txt
|
||||
# # add usage sig
|
||||
sed -i 's/| - \(.*\)/\t\t<div class="usage item"><code class="axsignature">\1<\/code><\/div>/g' tmp.txt
|
||||
# Format parms
|
||||
sed -i 's/\(void\)/<span class="axvoid">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(bool\)/<span class="axbool">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(int32\)/<span class="axint">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(int64\)/<span class="axint">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(float\)/<span class="axfloat">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(double\)/<span class="axdouble">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(string\)/<span class="axstring">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(vec[234][ifd]\)/<span class="axvec">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/\(mat[234][ifd]\)/<span class="axmat">\1<\/span>/g' tmp.txt
|
||||
sed -i 's/ \([a-z]\+\)(/ <span class="axname">\1<\/span>(/g' tmp.txt
|
||||
|
||||
# Combine
|
||||
cat tmp.txt >> functions.txt
|
||||
# cleanup
|
||||
rm tmp.txt
|
||||
+674
@@ -0,0 +1,674 @@
|
||||
/**
|
||||
|
||||
@page build Building OpenVDB
|
||||
|
||||
@section buildContents Contents
|
||||
- @ref buildIntroduction
|
||||
- @ref buildCmakeStructure
|
||||
- @ref buildDependencies
|
||||
- @ref buildMixingDepInstalls
|
||||
- @ref buildBloscSupport
|
||||
- @ref buildZLibSupport
|
||||
- @ref buildVCPKG
|
||||
- @ref buildComponents
|
||||
- @ref buildGuide
|
||||
- @ref buildBuildTypes
|
||||
- @ref buildBuildHouMaya
|
||||
- @ref buildBuildHou
|
||||
- @ref buildBuildMaya
|
||||
- @ref buildBuildStandalone
|
||||
- @ref buildUsingOpenVDB
|
||||
- @ref buildTroubleshooting
|
||||
<!-- - @ref buildContents -->
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
@section buildIntroduction Introduction
|
||||
|
||||
[CMake](https://cmake.org/) is a cross-platform family of tools designed to
|
||||
help build software.
|
||||
CMake doesn't *actually* build the project but instead generates the files
|
||||
required for your toolchain, for example makefiles that serve as input to
|
||||
[GNU Make](https://www.gnu.org/software/make/).
|
||||
CMake support ensures a high level of
|
||||
flexibility and pre-compile verification to the build process, making it much
|
||||
easier to control and customize the installation process for a wider range of
|
||||
platforms.
|
||||
|
||||
CMake also makes it easier to automatically find and handle dependencies.
|
||||
If you're completely new to CMake, you may find it useful to read over the
|
||||
brief [introduction to CMake](https://cmake.org/runningcmake/) and the CMake
|
||||
structure section below. However the [build guide](@ref buildGuide) runs
|
||||
through the build process step by step.
|
||||
|
||||
@section buildCmakeStructure CMake Structure
|
||||
|
||||
CMake will configure a set of build files which represent the commands and
|
||||
dependencies for the OpenVDB components you wish to install. Finding and
|
||||
handling these dependencies on different platforms comprises the majority
|
||||
of the complexity involved in writing CMake. In general, software which uses
|
||||
CMake is expected to provide their own configuration files which dependent
|
||||
software will locate and use. Not all of OpenVDB's dependencies provide CMake
|
||||
support and therefore do not deploy with CMake configurations that OpenVDB can
|
||||
use. OpenVDB provides a set of `FindModules` in the `cmake` folder for finding
|
||||
these various dependencies e.g. `FindBlosc.cmake`. These are designed such
|
||||
that they can theoretically be used by any project that needs to locate the
|
||||
given library and are invoked by the `find_package()` call. For more
|
||||
information on FindModules and locating packages with CMake, see the following
|
||||
CMake documentation:
|
||||
|
||||
- [Using Packages with CMake](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#using-packages)
|
||||
- [Calling find_package()](https://cmake.org/cmake/help/latest/command/find_package.html)
|
||||
|
||||
The other type of file provided by OpenVDB are `OpenVDBSetupX.cmake` includes.
|
||||
These are primarily designed to configure the building of OpenVDB components
|
||||
against supported DCC's (Houdini/Maya) by locating their installations and
|
||||
setting various CMake variables for subsequent `find_package()` dependency
|
||||
calls. They also represent packages which already provide their own CMake
|
||||
modules, but additionally provide the same input variable interface as OpenVDB's
|
||||
other `Find` Modules.
|
||||
|
||||
@subsection buildDependencies Locating Dependencies
|
||||
|
||||
Each CMake FindModule provides a description of the possible inputs which can
|
||||
be provided to help drive the search for OpenVDB dependencies (as well as the
|
||||
resulting outputs). They have been homogenized such that these variables
|
||||
follow a set convention, typically followed by most CMake projects. For a
|
||||
given FindModule e.g. `FindBlosc.cmake`:
|
||||
|
||||
- FindXxx.cmake provides the module interface where Xxx becomes the library
|
||||
name
|
||||
- Invoked with the called `find_package( Xxx )`
|
||||
.
|
||||
- @b Inputs - The following variables can be used to help drive the search
|
||||
path on first runs of CMake (i.e. these variables are not
|
||||
[cached](https://cmake.org/cmake/help/latest/command/set.html#set-cache-entry)).
|
||||
They are listed in priority order. Note that the prefix is always capitalized.
|
||||
- @b Xxx_ROOT - Preferred installation prefix. The given dependency is
|
||||
expected to follow a folder structure `Xxx_ROOT/include` and `Xxx_ROOT/lib`
|
||||
exist. Note that unlike the above, this is the case matching name of the
|
||||
find package .i.e. Blosc_ROOT, IlmBase_ROOT, TBB_ROOT etc.
|
||||
- @b XXX_INCLUDEDIR / @b XXX_LIBRARYDIR - Preferred include and library
|
||||
directories
|
||||
- @b SYSTEM_LIBRARY_PATHS - A list of paths appended to all include and lib
|
||||
searches.
|
||||
- @b XXX_USE_STATIC_LIBS - Only search for static libraries for the given
|
||||
dependency. If OFF, the shared library is prioritized, falling back
|
||||
to the static library. This is OFF by default.
|
||||
- @b DISABLE_CMAKE_SEARCH_PATHS - The above variables are custom to the
|
||||
OpenVDB project. CMake itself implements its own search system to try and
|
||||
find the given libraries and packages. When ON, this variable
|
||||
disables CMake's inbuilt search, guaranteeing that only the above user
|
||||
provided paths are searched. See [CMakes Search Procedure](https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure)
|
||||
for more information. This is OFF by default (and thus CMake's search
|
||||
is enabled).
|
||||
.
|
||||
- @b Outputs The following variables are always set if the project is found:
|
||||
- @b Xxx_FOUND - True if the headers and library was found and exists
|
||||
- @b Xxx_VERSION - The library version
|
||||
- @b Xxx_INCLUDE_DIRS - A list of paths to all required include directories
|
||||
- @b Xxx_RELEASSE_LIBRARY_DIRS - A list of paths to all required release library directories
|
||||
- @b Xxx_DEBUG_LIBRARY_DIRS - A list of paths to all required debug library directories
|
||||
- @b Xxx_RELEASE_LIBRARIES - A list of libraries needed to use the release version of Xxx
|
||||
- @b Xxx_DEBUG_LIBRARIES - A list of libraries needed to use the debug version of Xxx
|
||||
- Each module produces an [imported target](https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries)
|
||||
in the form @b Xxx::xxx, and may generate multiple imported targets if multiple
|
||||
components are found.
|
||||
|
||||
@subsection buildMixingDepInstalls Mixing Dependency Installations
|
||||
|
||||
There may be a situation where you use a package manager to install some
|
||||
dependencies, use a DCC such as Maya to provide others and manually build and
|
||||
install others from source. Care must be taken when providing CMake with these
|
||||
locations to ensure that the correct files are used. Incorrect use of the above
|
||||
variables can lead to difficult to diagnose build and runtime errors.
|
||||
|
||||
As an example, let's assume we have a manual installation of TBB (either through
|
||||
a Maya installation or a manual installation from source) and we want to use
|
||||
this with other dependencies installed through a package manager such as
|
||||
homebrew. As homebrew copies all headers and libraries it installs to a
|
||||
`<homebrew>/include` `<homebrew>/lib` directory structure, it can be tempting
|
||||
to set @b Xxx_ROOT variables to points to the `<homebrew>` folder. However you
|
||||
may already have an existing installation of TBB through your package manager,
|
||||
potentially installed by as a dependency of a completely unrelated piece of
|
||||
software. Whilst CMake may report to you the correct include/lib path, this can
|
||||
end up being hidden at compile time through these types of shared installations.
|
||||
You should not rely on the dependency order of the CMake build system - instead,
|
||||
it's important that you try to use the explicit directory paths where possible.
|
||||
For example homebrew will install each piece of software to
|
||||
`<homebrew>/Cellar/<dep_name>/<dep_version>`, where the subsequent include and
|
||||
library directories can be passed to @b XXX_INCLUDEDIR and @b XXX_LIBRARYDIR
|
||||
respectively.
|
||||
|
||||
In summary try to stick to a single installation workflow and, if in doubt,
|
||||
provide direct include/lib paths to isolated software locations.
|
||||
|
||||
@subsection buildBloscSupport Blosc Support
|
||||
|
||||
Blosc is an optional dependency of all OpenVDB components. The documented
|
||||
build steps below treat blosc as a required dependency. There are two reasons
|
||||
for this:
|
||||
|
||||
- Blosc produces significantly smaller `.vdb` files
|
||||
- If Blosc is disabled, you will not be able to read or use any `.vdb` files
|
||||
that were created using blosc compression. This includes OpenVDB files from
|
||||
Houdini.
|
||||
|
||||
See the note in the [known issues list](@ref depKnownIssues) regarding supported
|
||||
versions of blosc.
|
||||
|
||||
@subsection buildZLibSupport ZLIB Support
|
||||
|
||||
ZLIB is an optional dependency of all OpenVDB components. The documented build
|
||||
steps below treat ZLib as a required dependency.
|
||||
|
||||
You can disable ZLib using `-D USE_ZLIB=OFF` if Blosc is also disabled using `-D USE_BLOSC=OFF`.
|
||||
|
||||
@subsection buildVCPKG Building Dependencies using VCPKG
|
||||
|
||||
It is recommended to set the VCPKG_DEFAULT_TRIPLET=x64-windows environment
|
||||
variable to use 64-bit libraries by default as even on a 64-bit Windows OS,
|
||||
VCPKG builds and installs 32-bit libraries by default.
|
||||
|
||||
@section buildComponents OpenVDB Components
|
||||
|
||||
The following table lists all targets (mainly library and binary components)
|
||||
which can be built through the CMake build system. They can be set when using
|
||||
CMake from the command line with `-D VAR=ON/OFF` or with a CMake gui:
|
||||
|
||||
Component | Description | CMake Variable | Default |
|
||||
------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------- | ---------- |
|
||||
OpenVDB Core Library | The Core OpenVDB shared/static library | OPENVDB_BUILD_CORE | ON |
|
||||
OpenVDB Print | Command line binary for displaying information about OpenVDB files | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_PRINT | ON / ON |
|
||||
OpenVDB LOD | Command line binary for generating volume mipmaps from an OpenVDB grid | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_LOD | ON / OFF |
|
||||
OpenVDB Render | Command line binary for ray-tracing OpenVDB grids | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_RENDER | ON / OFF |
|
||||
OpenVDB View | Command line binary for displaying OpenVDB grids in a GL viewport | OPENVDB_BUILD_BINARIES / OPENVDB_BUILD_VDB_VIEW | ON / OFF |
|
||||
OpenVDB Python | Python module for OpenVDB C++ Python bindings | OPENVDB_BUILD_PYTHON_MODULE | OFF |
|
||||
OpenVDB UnitTests | OpenVDB's Unit Test suite | OPENVDB_BUILD_UNITTESTS | OFF |
|
||||
OpenVDB Houdini Plugin | The OpenVDB Houdini shared library and OpenVDB Nodes | OPENVDB_BUILD_HOUDINI_PLUGIN | OFF |
|
||||
OpenVDB Maya Plugin | The Maya OpenVDB Nodes | OPENVDB_BUILD_MAYA_PLUGIN | OFF |
|
||||
OpenVDB AX Library | The OpenVDB AX library | OPENVDB_BUILD_AX | OFF |
|
||||
OpenVDB AX Binary | Command line binary for running OpenVDB AX code | OPENVDB_BUILD_AX_BINARIES | OFF |
|
||||
OpenVDB AX Grammar | Allows for re-generation of AX grammar, typically not required | OPENVDB_BUILD_AX_GRAMMAR | OFF |
|
||||
OpenVDB AX Unit Tests | OpenVDB AX's Unit Test suite | OPENVDB_BUILD_AX_UNITTESTS | OFF |
|
||||
NanoVDB | NanoVDB headers | OPENVDB_BUILD_NANOVDB | OFF |
|
||||
NanoVDB Tools | NanoVDB command line tools | NANOVDB_BUILD_TOOLS | OFF |
|
||||
NanoVDB Examples | NanoVDB example binaries and benchmarks | NANOVDB_BUILD_EXAMPLES / NANOVDB_BUILD_BENCHMARK | OFF / OFF |
|
||||
NanoVDB Unit Tests | NanoVDB Unit Test suite | NANOVDB_BUILD_UNITTESTS | OFF |
|
||||
Documentation | The OpenVDB doxygen documentation | OPENVDB_BUILD_DOCS | OFF |
|
||||
|
||||
|
||||
|
||||
@section buildGuide Building With CMake
|
||||
|
||||
@subsection buildBuildTypes Build Types
|
||||
|
||||
The first step is to decide what type of OpenVDB build you're after. This
|
||||
primarily boils down to three main options:
|
||||
|
||||
- A standalone OpenVDB build (no Houdini/Maya plugins)
|
||||
- OpenVDB for [Houdini](https://www.sidefx.com/)
|
||||
- OpenVDB for [Maya](https://www.autodesk.co.uk/products/maya/overview)
|
||||
|
||||
Each option provides various benefits. Apart from the support for either the
|
||||
Houdini or Maya OpenVDB plugins, the latter two options can make it easier for
|
||||
new users to install the range of OpenVDB dependencies without having to worry
|
||||
about using a package manager or manually installing for source. You'll still
|
||||
be able to build and use all components of OpenVDB with these methods. However
|
||||
depending on the DCC (Digital Content Creation) software's version, you may
|
||||
find that some features of the Core library are restricted to ensure
|
||||
compatibility. For more information of building OpenVDB against a Houdini or
|
||||
Maya installation, see [here](@ref buildBuildHouMaya).
|
||||
|
||||
Developers may wish to build a standalone version of OpenVDB to take advantage
|
||||
of newer dependencies and newer library features. See
|
||||
[here](@ref buildBuildStandalone) for more information.
|
||||
|
||||
@b Note: Blosc and ZLib are treated as required dependencies in these install
|
||||
instructions. See the [blosc support](@ref buildBloscSupport) and
|
||||
[zlib support](@ref buildZLibSupport) sections for more information.
|
||||
|
||||
@subsection buildBuildHouMaya Building Against Houdini/Maya
|
||||
|
||||
Building against a DCC reduces the list of dependencies you need to provide.
|
||||
You should not mix between Houdini and Maya libraries and should not attempt
|
||||
to build the Maya plugin using Houdini libraries and vice-versa. Additionally,
|
||||
it's a good idea to read the above section on
|
||||
[mixing dependency installations](@ref buildMixingDepInstalls).
|
||||
|
||||
DCC | Supported Version | OpenVDB ABI |
|
||||
-------- | ----------------- | ----------- |
|
||||
Houdini | 18.0 | 6 |
|
||||
Houdini | 18.5 | 7 |
|
||||
Houdini | 19.0 | 8 |
|
||||
Maya | 2017 | Any |
|
||||
Maya | 2018 | Any |
|
||||
Maya | 2019 | Any |
|
||||
|
||||
@subsection buildBuildHou Building Against Houdini
|
||||
|
||||
Houdini ships with a number of libraries that OpenVDB requires. When downloading
|
||||
Houdini, take note of the file version information. The version you install will
|
||||
determine the compiler version you should try and use to build OpenVDB. For
|
||||
example, for @b Linux Houdini 17.5, with a file name of
|
||||
`houdini-17.5.219-linux_x86_64_gcc6.3.tar.gz`, GCC 6.3 should be used. You
|
||||
will need to install some of the following dependencies depending on which
|
||||
OpenVDB components you wish to build.
|
||||
|
||||
Package | Description | OpenVDB Components |
|
||||
-------------- | --------------------------------------------------------------- | ------------------ |
|
||||
CMake | Cross-platform family of tools designed to help build software | All |
|
||||
C++14 Compiler | Matching Houdini compiler and version | All |
|
||||
Boost | Components: iostreams, python, thread | All |
|
||||
GoogleTest | A unit testing framework module for C++ | Unit Tests |
|
||||
CppUnit | A unit testing framework module for C++ | Unit Tests (AX) |
|
||||
GLFW | Simple API for OpenGL development | OpenVDB View |
|
||||
Doxygen | Documentation generation from C++ | Documentation |
|
||||
Log4cplus | An optional dependency for improved OpenVDB Logging | Optional (All) |
|
||||
NumPy | Scientific computing with Python | Optional (Python) |
|
||||
LLVM | Target-independent code generation | OpenVDB AX |
|
||||
|
||||
At a minimum, boost, a matching C++14 compiler and CMake will be required. See
|
||||
the full [dependency list](@ref dependencies) for help with downloading and
|
||||
installing the above software. Note that as Blosc and ZLib are provided as part
|
||||
of the Houdini installation `USE_BLOSC` and `USE_ZLIB` should be left `ON`.
|
||||
|
||||
With the necessary dependencies installed, create and enter a directory for
|
||||
cmake to write to. It's generally useful to create this in the location you've
|
||||
extracted the OpenVDB repository. It will house CMake's generated build files.
|
||||
|
||||
@code{.sh}
|
||||
mkdir build
|
||||
cd build
|
||||
@endcode
|
||||
|
||||
Now you can call CMake by providing the absolute or relative path to the root
|
||||
of the OpenVDB source tree along with the following options:
|
||||
|
||||
Required:
|
||||
|
||||
- @b Houdini_ROOT =`/path/to/houdini/install` # Path to Houdini Install
|
||||
- @b USE_HOUDINI =`ON` # Force all components to build against Houdini
|
||||
- @b OPENVDB_BUILD_HOUDINI_PLUGIN =`ON` # Required for building the Houdini Plugin.
|
||||
|
||||
Optional:
|
||||
|
||||
- @b [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
|
||||
=`/path/to/install/dir` # The location you wish to install OpenVDB to. See
|
||||
the link for default values.
|
||||
- @b OPENVDB_HOUDINI_INSTALL_PREFIX =`/path/to/install/dir` # The location to
|
||||
install the Houdini plugin to. Defaults to directories defined by Houdini:
|
||||
- Linux: `$ENV{HOME}/houdiniX.X`
|
||||
- Mac: `$ENV{HOME}/Library/Preferences/houdini/X.X`
|
||||
- Windows: `$ENV{HOMEDRIVE}$ENV{HOMEPATH}\Documents\houdiniX.X`
|
||||
- @b USE_DEFAULT_HOUDINI_INSTALL =`ON` # Use the above default locations if
|
||||
@b OPENVDB_HOUDINI_INSTALL_PREFIX is not specified. If `OFF`, uses the value
|
||||
of @b CMAKE_INSTALL_PREFIX.
|
||||
- @b BOOST_ROOT =`/path/to/boost/install` # Path to boost. May not be required,
|
||||
CMake may find it automatically
|
||||
|
||||
For example on MacOS and where the build folder has been created inside the
|
||||
OpenVDB source root:
|
||||
|
||||
@code
|
||||
cmake -D BOOST_ROOT=/path/to/boost/install \
|
||||
-D Houdini_ROOT=/Applications/Houdini/Houdini17.0.506/ \
|
||||
-D USE_HOUDINI=ON \
|
||||
../
|
||||
@endcode
|
||||
|
||||
After the CMake build files have been successfully generated, run the build
|
||||
tool within the build directory to compile the project. On UNIX, you can
|
||||
typically incoke `make` directly:
|
||||
@code
|
||||
make -j4
|
||||
@endcode
|
||||
|
||||
Where the value of the `j` argument is the number of CPU threads to use for a
|
||||
multi-threaded build. On Windows, you can leverage CMake's build tool to invoke
|
||||
the selected builder (usually msbuild):
|
||||
@code
|
||||
cmake --build .
|
||||
@endcode
|
||||
|
||||
Finally, once a successful build has completed, you can install all files.
|
||||
@code
|
||||
cmake --build . --target install # or simply `make install`
|
||||
@endcode
|
||||
|
||||
See the [troubleshooting](@ref buildTroubleshooting) section for help with
|
||||
CMake and Make errors.
|
||||
|
||||
|
||||
@subsection buildBuildMaya Building Against Maya
|
||||
|
||||
Supported versions of maya only ship with TBB.
|
||||
|
||||
Package | Description | OpenVDB Components |
|
||||
-------------- | --------------------------------------------------------------- | -------------------------------- |
|
||||
CMake | Cross-platform family of tools designed to help build software | All |
|
||||
C++14 Compiler | Matching Houdini compiler and version | All |
|
||||
Boost | Components: iostreams, python, thread | All |
|
||||
ZLIB | Compression library for disk serialization compression | All |
|
||||
Blosc | Recommended dependency for improved disk compression | All* |
|
||||
GoogleTest | A unit testing framework module for C++ | Unit Tests |
|
||||
CppUnit | A unit testing framework module for C++ | Unit Tests (AX) |
|
||||
GLFW | Simple API for OpenGL development | OpenVDB View |
|
||||
Doxygen | Documentation generation from C++ | Documentation |
|
||||
OpenEXR | EXR serialization support | OpenVDB Render |
|
||||
IlmBase | Used half precision floating points and EXR serialization support | Optional (All) |
|
||||
Log4cplus | An optional dependency for improved OpenVDB Logging | Optional (All) |
|
||||
NumPy | Scientific computing with Python | Optional (Python) |
|
||||
LLVM | Target-independent code generation | OpenVDB AX |
|
||||
|
||||
|
||||
* See [blosc support](@ref buildBloscSupport)
|
||||
|
||||
At a minimum, boost, a matching C++14 compiler, ZLIB, blosc and CMake will be
|
||||
required. See the full [dependency list](@ref dependencies) for help with
|
||||
downloading and installing the above software.
|
||||
|
||||
With the necessary dependencies installed, create and enter a directory for
|
||||
cmake to write to. It's generally useful to create this in the location you've
|
||||
extracted the OpenVDB repository. It will house CMake's generated build files.
|
||||
|
||||
@code{.sh}
|
||||
mkdir build
|
||||
cd build
|
||||
@endcode
|
||||
|
||||
Now you can call CMake by providing the absolute or relative path to the root
|
||||
of the OpenVDB source tree along with the following options:
|
||||
|
||||
Required:
|
||||
|
||||
- @b Maya_ROOT =`/path/to/maya/install` # Path to Maya Install
|
||||
- @b USE_MAYA =`ON` # Force all components to build against Maya
|
||||
|
||||
Optional:
|
||||
|
||||
- @b [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
|
||||
=`/path/to/install/dir` # The location you wish to install OpenVDB to. See
|
||||
the link for default values.
|
||||
- @b OPENVDB_MAYA_INSTALL_PREFIX =`/path/to/install/dir` # The location to
|
||||
install the Maya plugin to. Defaults to the value of `${CMAKE_INSTALL_PREFIX}/maya${Maya_VERSION}`
|
||||
- @b BOOST_ROOT =`/path/to/boost/install` # Path to boost. May not be required,
|
||||
CMake may find it automatically
|
||||
- @b IlmBase_ROOT =`/path/to/ilmbase/install` # Path to ilmbase.
|
||||
|
||||
For example on MacOS and where the build folder has been created inside the
|
||||
OpenVDB source root:
|
||||
|
||||
@code
|
||||
cmake -D BOOST_ROOT=/path/to/boost/install \
|
||||
-D IlmBase_ROOT=/path/to/ilmbase/install \
|
||||
-D Maya_ROOT=/Applications/Autodesk/maya2019/ \
|
||||
-D USE_MAYA=ON \
|
||||
../
|
||||
@endcode
|
||||
|
||||
As the Maya plugin is disabled by default, you may also want to add
|
||||
`-D OPENVDB_BUILD_MAYA_PLUGIN=ON` to the command. The
|
||||
[components](@ref buildComponents) section shows which targets are enabled by
|
||||
default.
|
||||
|
||||
After the CMake build files have been successfully generated, run the build
|
||||
tool within the build directory to compile the project. On UNIX, you can
|
||||
typically incoke `make` directly:
|
||||
@code
|
||||
make -j4
|
||||
@endcode
|
||||
|
||||
Where the value of the `j` argument is the number of CPU threads to use for a
|
||||
multi-threaded build. On Windows, you can leverage CMake's build tool to invoke
|
||||
the selected builder (usually msbuild):
|
||||
@code
|
||||
cmake --build .
|
||||
@endcode
|
||||
|
||||
Finally, once a successful build has completed, you can install all files.
|
||||
@code
|
||||
cmake --build . --target install # or simply `make install`
|
||||
@endcode
|
||||
|
||||
@b Note: The Maya OpenVDB Visualize Node is @b only compatible with Legacy
|
||||
OpenGL support. You can enable this in Maya by navigating to
|
||||
`Windows->Settings/Preferences->Preferences->Display` and changing
|
||||
`Rendering Engine` to OpenGL - Legacy.
|
||||
|
||||
See the [troubleshooting](@ref buildTroubleshooting) section for help with
|
||||
CMake and Make errors.
|
||||
|
||||
|
||||
@subsection buildBuildStandalone Building Standalone
|
||||
|
||||
It's recommended you first visit the [dependency list page](@ref dependencies)
|
||||
before attempting to run CMake on a standalone build. With the necessary
|
||||
dependencies installed, create and enter a directory for cmake to write to.
|
||||
It's generally useful to create this in the location you've extracted the
|
||||
OpenVDB repository. It will house CMake's generated build files.
|
||||
|
||||
@code{.sh}
|
||||
mkdir build
|
||||
cd build
|
||||
@endcode
|
||||
|
||||
Now you can call CMake by providing the absolute or relative path to the root
|
||||
of the OpenVDB source tree. Below are some common options you may want to
|
||||
provide:
|
||||
|
||||
- @b [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
|
||||
=`/path/to/install/dir` # The location you wish to install OpenVDB to. See
|
||||
the link for default values.
|
||||
- @b Xxx_ROOT =`/path/to/Xxx/` # Give CMake a path to where a package has been
|
||||
installed or simply to where your prefered package is installed if it cannot
|
||||
locate it.
|
||||
|
||||
For example, a typical first attempt at generating the build files may look as
|
||||
follows:
|
||||
|
||||
@code{.sh}
|
||||
cmake -D CMAKE_INSTALL_PREFIX=$HOME/openvdb ../
|
||||
@endcode
|
||||
|
||||
See the [components](@ref buildComponents) section to find which targets are
|
||||
available, their corresponding CMake flags and their default values.
|
||||
|
||||
After the CMake build files have been successfully generated, run the build
|
||||
tool within the build directory to compile the project. On UNIX, you can
|
||||
typically incoke `make` directly:
|
||||
@code
|
||||
make -j4
|
||||
@endcode
|
||||
|
||||
Where the value of the `j` argument is the number of CPU threads to use for a
|
||||
multi-threaded build. On Windows, you can leverage CMake's build tool to invoke
|
||||
the selected builder (usually msbuild):
|
||||
@code
|
||||
cmake --build .
|
||||
@endcode
|
||||
|
||||
Finally, once a successful build has completed, you can install all files.
|
||||
@code
|
||||
cmake --build . --target install # or simply `make install`
|
||||
@endcode
|
||||
|
||||
See the [troubleshooting](@ref buildTroubleshooting) section for help with
|
||||
CMake and Make errors.
|
||||
|
||||
@section buildUsingOpenVDB Building With OpenVDB
|
||||
|
||||
This section is for users wishing to use a build of OpenVDB in their own
|
||||
applications with CMake.
|
||||
|
||||
The following assumes that OpenVDB was installed with `OPENVDB_BUILD_CORE=ON`
|
||||
and `OPENVDB_INSTALL_CMAKE_MODULES=ON`. Don't worry if you didn't specify
|
||||
these options directly, they both default to `ON`. This ensures that OpenVDB
|
||||
has installed the required CMake modules that your application will need to
|
||||
use.
|
||||
|
||||
@b Note: Typically, projects provide a @b Config-file rather than a
|
||||
@b Find-module for downstream use. OpenVDB currently provides a @b Find-module.
|
||||
This may change in the future. Further information
|
||||
[here](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#using-packages).
|
||||
|
||||
You can add the below CMake snippet to your main `CMakeLists.txt` to bring in
|
||||
OpenVDB as a dependency:
|
||||
|
||||
@code{.cmake}
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
list(APPEND CMAKE_MODULE_PATH "/location/of/openvdb/install/lib/cmake/OpenVDB")
|
||||
find_package(OpenVDB REQUIRED)
|
||||
target_link_libraries(myapp OpenVDB::openvdb)
|
||||
@endcode
|
||||
|
||||
`myapp` in the above is a CMake target, usually created with `add_library()`
|
||||
or `add_executable()`. You can optionally provide `CMAKE_MODULE_PATH` as a
|
||||
`-D` argument to the cmake command line instead of specifying it in your
|
||||
`CMakeLists.txt`.
|
||||
|
||||
Note that the `FindOpenVDB.cmake` module relies on the other `FindModules`
|
||||
provided in the OpenVDB installation to find it's own dependencies. This may
|
||||
require you to provide additional dependency locations for OpenVDB's
|
||||
dependencies. See [Locating Dependencies](@ref buildDependencies) or the below
|
||||
troubleshooting for more information.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
@section buildTroubleshooting Troubleshooting
|
||||
|
||||
If after reading this guide you're unable to find your specific issue below,
|
||||
please get in touch or [file an issue](https://github.com/AcademySoftwareFoundation/openvdb/issues)
|
||||
with the OpenVDB TSC.
|
||||
|
||||
@b Note: If running into issues when changing CMake settings/dependency paths,
|
||||
try clearing the designated CMake build directory and running your `cmake`
|
||||
command again.
|
||||
|
||||
@subsection troubleshoot1 CMake Error ... Could NOT find XXX (missing: ... )
|
||||
|
||||
It's fairly typical that CMake may fail to find some dependencies on first
|
||||
runs, especially if you've manually compiled from source your own
|
||||
dependencies. Analyzing any dependency errors will help with running further
|
||||
invocations of cmake. The [Locating Dependencies](@ref buildDependencies)
|
||||
section details the variable format required to point CMake to the correct
|
||||
locations. Alternatively, with interactive cmake systems such as `ccmake` or
|
||||
CMake GUI, variables which are not found will be shown, allowing you to
|
||||
provide them directly.
|
||||
|
||||
As an example, earlier versions of
|
||||
[Threading Building Blocks (TBB)](https://www.threadingbuildingblocks.org/)
|
||||
do not come with CMake modules or
|
||||
[pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) modules.
|
||||
For OpenVDB to locate TBB, you typically need to provide this location
|
||||
manually:
|
||||
|
||||
@code{.sh}
|
||||
cmake -D CMAKE_INSTALL_PREFIX=$HOME/openvdb -D TBB_ROOT=/path/to/tbb/install ../
|
||||
@endcode
|
||||
|
||||
Note that this is also equivalent to:
|
||||
|
||||
@code{.sh}
|
||||
cmake -D CMAKE_INSTALL_PREFIX=$HOME/openvdb \
|
||||
-D TBB_INCLUDEDIR=/path/to/tbb/install/include \
|
||||
-D TBB_LIBRARYDIR=/path/to/tbb/install/lib \
|
||||
../
|
||||
@endcode
|
||||
|
||||
@subsection troubleshoot2 CMake Error ... Could NOT find XXX (Found unsuitable version: ... )
|
||||
|
||||
By default, OpenVDB sets a number of minimum version requires for its
|
||||
dependencies. These can be found in the root CMakeList.txt or in the
|
||||
[dependency table](@ref dependencies). These minimum versions either track
|
||||
the oldest supported [VFX Reference Platform](https://www.vfxplatform.com/) or
|
||||
are otherwise required for compatibility. Although not recommended, you can
|
||||
bypass these checks with `-D DISABLE_DEPENDENCY_VERSION_CHECKS=ON` if necessary.
|
||||
Note that using older or untested dependencies may produce undesired behavior.
|
||||
Older versions in particular are not supported by OpenVDB.
|
||||
|
||||
@b Note: Boost will produce a version error in the format `Detected version of
|
||||
Boost is too old.`
|
||||
|
||||
@subsection troubleshoot3 CMake warnings/errors in FindBoost.cmake
|
||||
|
||||
There are a variety of potential warnings and errors that may arise from the
|
||||
version compatibility of Boost and CMake. These are related to how both Boost
|
||||
and CMake have historically been kept in sync. A common warning and error
|
||||
combination is:
|
||||
|
||||
@code{.sh}
|
||||
CMake Warning at ... Imported targets not available for Boost version XXXXXX
|
||||
...
|
||||
Target "..." links to target "Boost::XXX" but the target
|
||||
was not found. Perhaps a find_package() call is missing for an IMPORTED
|
||||
target, or an ALIAS target is missing?
|
||||
@endcode
|
||||
|
||||
OpenVDB uses [imported targets](https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries)
|
||||
for all its dependencies. For imported Boost compatibility, the following
|
||||
versions of CMake are required:
|
||||
|
||||
- Boost 1.68, 1.69 require CMake 3.13 or newer.
|
||||
- Boost 1.70 requires CMake 3.14 or newer.
|
||||
|
||||
Use the above list to identify the version of CMake you require for your version
|
||||
of Boost. Note that this may be implemented into the OpenVDB CMake in the future.
|
||||
|
||||
@subsection troubleshoot4 Detected VCPKG toolchain is using a mismatching triplet for OpenVDB build artifacts
|
||||
|
||||
If you are on Windows and using vcpkg, builds of OpenVDB should usually only
|
||||
build the static OR shared library depending on your vcpkg triplet. This is
|
||||
related to how libraries link against the Windows CRT. In vcpkg, static triplets,
|
||||
such as @b x64-windows-static, will use the @b MultiThreaded (/MT) flag and
|
||||
dynamic triplets, such as @b x64-windows, will use the @b MultiThreadedDLL (/MD)
|
||||
flag. These flags @b must match throughout all software artifacts in your
|
||||
toolchain (regardless if you are using vcpkg or not).
|
||||
|
||||
This warning is shown when OpenVDB detects you using either a dynamic or static
|
||||
VCPKG toolchain on Windows, but have the opposite core library variant enabled.
|
||||
By default, the static build of OpenVDB links against the @b MultiThreaded
|
||||
(/MT) CRT and the dynamic library links against the @b MultiThreadedDLL (/MD)
|
||||
CRT. As OpenVDB configures both by default, it is typical that you may want
|
||||
to disable one or the other depending on your needs.
|
||||
|
||||
Note that you can provide a value for `CMAKE_MSVC_RUNTIME_LIBRARY` which is a
|
||||
native CMake variable to override any CRT selection done by OpenVDB.
|
||||
|
||||
For more information, see the following articles:
|
||||
Description of CRT selection: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
|
||||
In depth descriptopn of the CRT on Windows: https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features
|
||||
Related errors: https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-error-lnk2038
|
||||
`CMAKE_MSVC_RUNTIME_LIBRARY` docs: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
|
||||
|
||||
@subsection troubleshoot5 Unexpected value for the Windows CRT with target build artifacts.
|
||||
|
||||
On Windows, it is typical for static builds to link to static libraries and
|
||||
dynamic builds to link to dynamic library variants. This is not related to the
|
||||
libraries themselves, rather it is due to the way that all libraries used within
|
||||
a specific toolchain must use the same version of the CRT. The rule of thumb is
|
||||
to configure static builds against the static CRT and dynamic builds against
|
||||
the dynamic CRT.
|
||||
|
||||
This warning is shown if you have provided a value for the CMake variable
|
||||
`CMAKE_MSVC_RUNTIME_LIBRARY`, but this value is the opposite of what's expected
|
||||
for a target library.
|
||||
|
||||
Note that there are some cases where it makes sense to link static builds of
|
||||
OpenVDB against the dynamic (/MD) CRT. However, unless you are confident in your
|
||||
usage, it is strongly encouraged to match the selection against your desired
|
||||
build type.
|
||||
|
||||
For more information, see the following articles:
|
||||
Description of CRT selection: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
|
||||
In depth descriptopn of the CRT on Windows: https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features
|
||||
Related errors: https://docs.microsoft.com/en-us/cpp/error-messages/tool-errors/linker-tools-error-lnk2038
|
||||
`CMAKE_MSVC_RUNTIME_LIBRARY` docs: https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
|
||||
|
||||
@subsection troubleshoot6 error LNK2038: mismatch detected for 'RuntimeLibrary'
|
||||
|
||||
A build artifact of OpenVDB has been linked against a dependency which uses a
|
||||
different version of the Window CRT. See the [above section](@ref troubleshoot5)
|
||||
on dealing with CRT selection for static and dynamic library builds on Windows.
|
||||
|
||||
*/
|
||||
+3882
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
|
||||
@page codingStyle Coding Style
|
||||
|
||||
@section Introduction
|
||||
|
||||
This document details the coding practices that are used in the OpenVDB
|
||||
codebase. Contributed code should conform to these guidelines to maintain
|
||||
consistency and maintainability. If there is a rule that you would like
|
||||
clarified, changed, or added, please send a note to openvdb@gmail.com.
|
||||
|
||||
|
||||
@section sStyleContents Contents
|
||||
- @ref sNamingConventions
|
||||
- @ref sNamespaceConventions
|
||||
- @ref sClassConventions
|
||||
- @ref sClassMethods
|
||||
- @ref sClassInstanceVariables
|
||||
- @ref sClassStaticVariables
|
||||
- @ref sLocalVariablesAndArguments
|
||||
- @ref sConstants
|
||||
- @ref sEnumerationNames
|
||||
- @ref sEnumerationValues
|
||||
- @ref sTypedefs
|
||||
- @ref sGlobalVariables
|
||||
- @ref sGlobalFunctions
|
||||
- @ref sBooleans
|
||||
- @ref sPractices
|
||||
- @ref sGeneral
|
||||
- @ref sFormatting
|
||||
- @ref sIncludeStatements
|
||||
- @ref sComments
|
||||
- @ref sPrimitiveTypes
|
||||
- @ref sMacros
|
||||
- @ref sClasses
|
||||
- @ref sConditionalStatements
|
||||
- @ref sNamespaces
|
||||
- @ref sExceptions
|
||||
- @ref sTemplates
|
||||
- @ref sMiscellaneous
|
||||
|
||||
@section sNamingConventions Naming Conventions
|
||||
|
||||
|
||||
@subsection sNamespaceConventions Namespaces
|
||||
-# Lowercase words, keep simple and short (e.g., @c tools, @c tree).
|
||||
-# Use @c internal (or @c detail) or <TT><I>module</I>_internal</TT>
|
||||
for symbols such as templates that must be defined in header files
|
||||
but that are implementation details not intended for public use.
|
||||
|
||||
|
||||
@subsection sClassConventions Classes and Structs
|
||||
-# Mixed case; first letter uppercase (e.g., @c AffineMap, @c TreeIterator)
|
||||
-# Do not use a prefix.
|
||||
|
||||
|
||||
@subsection sClassMethods Class Methods
|
||||
-# Mixed case; first letter lowercase (e.g., <TT>getAccessor()</TT>, <TT>gridType()</TT>)
|
||||
-# Accessor methods that return a member variable by reference or a primitive type
|
||||
by value are just the variable name (e.g., <TT>Grid::tree()</TT>).
|
||||
-# Accessor methods that involve construction of objects or other computations are
|
||||
@c get + the variable name (e.g., <TT>Grid::getAccessor()</TT>).
|
||||
-# Simple mutators are @c set + the variable name (e.g., <TT>Grid::setTree(tree);</TT>).
|
||||
|
||||
|
||||
@subsection sClassInstanceVariables Class Instance Variables
|
||||
-# Mixed case; always prefixed by @c m (e.g., @c mTree, @c mTransform)
|
||||
-# The @c m prefix may be omitted for members of <TT>struct</TT>s
|
||||
used in the public API (e.g., <TT>struct Color { float r, g, b; }</TT>).
|
||||
|
||||
|
||||
@subsection sClassStaticVariables Class Static Variables
|
||||
-# Mixed case; always prefixed by @c s (e.g., @c sInitialized)
|
||||
|
||||
|
||||
@subsection sLocalVariablesAndArguments Local Variables and Arguments
|
||||
-# Use mixed case with an initial lower case letter (e.g., @c ijk, @c offset,
|
||||
@c range, @c rhsValue).
|
||||
|
||||
|
||||
@subsection sConstants Constants
|
||||
-# All uppercase; words separated by underscores. If not in a namespace or
|
||||
local to a source file, then prefixed with the library name in all caps
|
||||
(e.g., @c HALF_FLOAT_TYPENAME_SUFFIX, @c ZIP_COMPRESSION_LEVEL)
|
||||
|
||||
|
||||
@subsection sEnumerationNames Enumeration Names
|
||||
-# Mixed case; first letter uppercase (e.g., @c GridClass, @c VecType)
|
||||
|
||||
|
||||
@subsection sEnumerationValues Enumeration Values
|
||||
-# With @c enum, all uppercase with words separated by underscores
|
||||
(e.g., @c GRID_LEVEL_SET, @c VEC_INVARIANT) and with a common prefix
|
||||
-# With <TT>enum class</TT>, mixed case with the first letter uppercase
|
||||
(e.g., @c GridClass::Unknown, @c GridClass::LevelSet)
|
||||
|
||||
|
||||
@subsection sTypedefs Typedefs
|
||||
-# Mixed case; first letter uppercase (e.g., @c ConstPtr, @c ValueType)
|
||||
-# Do not use a prefix.
|
||||
|
||||
|
||||
@subsection sGlobalVariables Global Variables
|
||||
-# Mixed case; always prefixed by @c g (e.g., @c gRegistry)
|
||||
-# In general, try to use class static data instead of globals.
|
||||
|
||||
|
||||
@subsection sGlobalFunctions Global Functions
|
||||
-# Mixed case; always prefixed by @c g (e.g., <TT>gFunc()</TT>).
|
||||
-# In general, try to use class static members instead of global functions.
|
||||
|
||||
|
||||
@subsection sBooleans Booleans
|
||||
-# When naming boolean functions and variables, use names that read as a
|
||||
condition (e.g., <TT>if (grid.empty())</TT>,
|
||||
<TT>if (matrix.isInvertible())</TT>).
|
||||
|
||||
|
||||
@section sPractices Practices
|
||||
|
||||
|
||||
@subsection sGeneral General
|
||||
-# Code must compile without any warning messages at the default warning level.
|
||||
-# Prefer the C++ Standard Library to the C Standard Library.
|
||||
-# Restrict variables to the smallest scopes possible, and avoid defining
|
||||
local variables before giving them values. Prefer declarations inside
|
||||
conditionals: <TT>if (Grid::Ptr grid = createGrid()) { ... }</TT> instead of
|
||||
<TT>Grid::Ptr grid = createGrid(); if (grid) { ... }</TT>
|
||||
-# For new files, be sure to use the right license boilerplate per our license
|
||||
policy.
|
||||
|
||||
|
||||
@subsection sFormatting Formatting
|
||||
-# Indentation is 4 spaces. Do not use tabs.
|
||||
-# Lines are no more than 100 characters long.
|
||||
-# Use Unix-style carriage returns ("\n") rather than Windows/DOS ones ("\r\n").
|
||||
-# Do not leave debug <TT>printf</TT>s or other debugging code lying around.
|
||||
-# Leave a blank line between a group of variable declarations and other code.
|
||||
-# Leave a space after the keywords @c if, @c switch, @c while, @c do, @c for,
|
||||
and @c return.
|
||||
-# Leave a space on each side of binary operators such as @c +, @c -, @c *, @c /, @c &&,
|
||||
and @c ||. For clarity in mathematical situations, you may omit the spaces on
|
||||
either side of @c * and @c / operators to emphasize their precedence over @c + and @c -.
|
||||
-# Do not leave a space between any dereferencing operator
|
||||
(such as @c *, @c &, @c [], @c ->, or @c .) and its operands.
|
||||
-# In parameter lists, leave a space after each comma.
|
||||
-# Do not leave a space after an opening parenthesis or before a closing
|
||||
parenthesis.
|
||||
-# Parentheses should be used to clarify operator precedence in expressions.
|
||||
-# Do not leave a space before an end-of-statement semicolon.
|
||||
-# Do not use literal tabs in strings or character constants. Rather, use
|
||||
spaces or "\t".
|
||||
-# If a parameter list is too long, break it between parameters. Group related
|
||||
parameters on lines if appropriate.
|
||||
-# Modified spacing is allowed to vertically align repetitive expressions.
|
||||
-# Always begin numeric constants with a digit (e.g., 0.001 not .001).
|
||||
-# Use K&R-style brace placement in public code.
|
||||
-# You may leave off braces for simple, single line flow control statements.
|
||||
-# The return type in a function definition should go on a line by itself.
|
||||
|
||||
|
||||
@subsection sIncludeStatements Include Statements
|
||||
-# Always use double quotes ("") to include header files that live in the same
|
||||
directory as your source code.
|
||||
-# Use angle brackets (<>) to include header files from outside a file’s
|
||||
directory.
|
||||
-# Do not use absolute paths in include directives.
|
||||
-# If there is a header corresponding to a given source file, list it first,
|
||||
followed by other local headers, library headers and then system headers.
|
||||
|
||||
|
||||
@subsection sHeaderFiles Header Files
|
||||
-# Header files have a <TT>.h</TT> extension.
|
||||
-# All header files should be bracketed by @c \#ifdef "guard" statements.
|
||||
-# In class definitions, list public, then protected, then private members.
|
||||
-# List methods before variables.
|
||||
-# Fully prototype all public functions and use descriptive naming for each
|
||||
argument.
|
||||
-# Declare every function defined in a header but outside a class definition
|
||||
explicitly as @c inline.
|
||||
-# Prefer forward declarations to @c \#include directives in headers.
|
||||
-# Do not take advantage of indirect inclusion of header files.
|
||||
-# Do not use anonymous namespaces in header files.
|
||||
|
||||
|
||||
@subsection sSourceFiles Source Files
|
||||
-# Source files have a <TT>.cc</TT> extension.
|
||||
-# Properly prototype all file static functions with usefully named arguments.
|
||||
-# Whenever possible, put variables and functions in an anonymous namespace.
|
||||
-# Avoid global variables.
|
||||
|
||||
|
||||
@subsection sComments Comments
|
||||
-# Use @c // style comments instead of / * * / style, even for multi-line
|
||||
comments.
|
||||
-# Use multi-line comments to describe following paragraphs of code.
|
||||
-# Use end-of-line comments to describe variable declarations or to clarify a
|
||||
single statement.
|
||||
-# Large blocks of code should be commented out with <TT>\#if 0</TT> and @c \#endif.
|
||||
-# Do not leave obsolete code fragments within comments as an historical trail.
|
||||
-# Document public code with Doxygen comments, formatted as follows:
|
||||
@verbatim
|
||||
/// @brief Create a new grid of type @c GridType classified as a "Level Set",
|
||||
/// i.e., a narrow-band level set.
|
||||
///
|
||||
/// @param voxelSize the size of a voxel in world units
|
||||
/// @param halfWidth the half width of the narrow band in voxel units
|
||||
///
|
||||
/// @details The voxel size and the narrow band half width define the grid's
|
||||
/// background value as halfWidth*voxelWidth. The transform is linear
|
||||
/// with a uniform scaling only corresponding to the specified voxel size.
|
||||
///
|
||||
/// @note It is generally advisable to specify a half-width of the narrow band
|
||||
/// that is larger than one voxel unit, otherwise zero crossings are not guaranteed.
|
||||
template<typename GridType>
|
||||
typename GridType::Ptr createLevelSet(
|
||||
Real voxelSize = 1.0, Real halfWidth = LEVEL_SET_HALF_WIDTH);
|
||||
@endverbatim
|
||||
|
||||
|
||||
@subsection sPrimitiveTypes Primitive Types
|
||||
-# Avoid writing code that is dependent on the bit size of primitive values,
|
||||
but when specific bit sizes are required, use explicitly-sized types such as
|
||||
@c int32_t or @c uint64_t.
|
||||
|
||||
|
||||
@subsection sMacros Macros
|
||||
-# Avoid macros for constants. Use global static constants instead. (Local
|
||||
static constants are not guaranteed to be initialized in a thread-safe manner.)
|
||||
-# Avoid macro functions. Use @c inline and templates instead.
|
||||
|
||||
|
||||
@subsection sClasses Classes
|
||||
-# Constructors that can be called with only one argument should be prefixed
|
||||
with the @c explicit keyword to avoid unintended type conversions.
|
||||
-# Never call virtual methods from destructors.
|
||||
-# If you have a copy constructor, make sure you have an assignment operator.
|
||||
-# If you have an assignment operator, you probably need a copy constructor.
|
||||
-# If you have data members that are pointers to dynamically allocated memory,
|
||||
make sure you have a copy constructor and an assignment operator, both of
|
||||
which do the right thing with that memory.
|
||||
-# Classes which are to be subclassed always have a virtual destructor, even if
|
||||
it is empty.
|
||||
-# Check against self assignment and return <TT>*this</TT> in assignment
|
||||
operators.
|
||||
-# Declare methods as @c const wherever possible.
|
||||
-# Declare object-valued input arguments as const references wherever
|
||||
possible. Primitives may be passed by value, however.
|
||||
-# Arithmetic, logical, bitwise, dereference, and address of operators should
|
||||
only be used when their semantics are clear, obvious, and unambiguous.
|
||||
-# The application operator [ () ] is allowed for functors.
|
||||
-# Conversion operators should be avoided.
|
||||
-# Never return const references to stack allocated or implicitly computed
|
||||
objects.
|
||||
-# If a class does not have a copy constructor and/or assignment operator,
|
||||
consider creating a private unimplemented copy constructor and/or assignment
|
||||
operator to prevent automatically generated versions from being used.
|
||||
|
||||
|
||||
@subsection sConditionalStatements Conditional Statements
|
||||
-# For test expressions, use a form that indicates as clearly as possible the
|
||||
types of operands by avoiding implicit casts.
|
||||
-# Assignments that occur within conditional statements must have no effect in
|
||||
the enclosing scope.
|
||||
-# Allow for arithmetic imprecision when comparing floating point values.
|
||||
-# In switch statements, always comment fallthroughs and empty cases.
|
||||
|
||||
|
||||
@section sNamespaces Namespaces
|
||||
-# Namespaces should be used whenever possible.
|
||||
-# Avoid pulling in entire namespaces with @c using directives
|
||||
(e.g., <TT>using namespace std;</TT>).
|
||||
-# @c using declarations are allowed for individual symbols (e.g.,
|
||||
<TT>using std::vector;</TT>), but they should never appear in a header file.
|
||||
-# Define global operators in the namespace of their arguments.
|
||||
-# Namespaces are not indented.
|
||||
|
||||
|
||||
@subsection sExceptions Exceptions
|
||||
-# Appropriate use of exceptions is encouraged.
|
||||
-# Methods should declare all exceptions they might throw using comments,
|
||||
but not exception specifications.
|
||||
-# Throw scope local exception instances, not pointers or references or globals.
|
||||
-# Catch exceptions by reference.
|
||||
-# Never allow an exception to escape from a destructor.
|
||||
|
||||
|
||||
@subsection sTemplates Templates
|
||||
-# Use @c typename rather than @c class when declaring template type parameters.
|
||||
|
||||
|
||||
@subsection sMiscellaneous Miscellaneous
|
||||
-# Don’t use pointers to run through arrays of non-primitive types. Use explicit array indexing, iterators or generic algorithms instead.
|
||||
-# Use C++ casts (<TT>static_cast<int>(x)</TT> or <TT>int(x)</TT>),
|
||||
not C casts (<TT>(int)x</TT>).
|
||||
-# Multiple variables of the same data type may be declared on the same line
|
||||
if closely related.
|
||||
-# Library code must never deliberately terminate the application in response
|
||||
to an error condition.
|
||||
-# Avoid using malloc/free when new/delete can be used instead.
|
||||
-# Avoid @c goto.
|
||||
-# Avoid \"magic numbers\". Use named constants when necessary.
|
||||
-# If you use typeid/typeinfo, be aware that although all runtimes support
|
||||
<TT>typeinfo::name()</TT>, the format of the string it returns varies
|
||||
between compilers and even for a given compiler the value is not guaranteed
|
||||
to be unique.
|
||||
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
|
||||
@page dependencies Dependencies
|
||||
|
||||
@section depContents Contents
|
||||
- @ref depComponents
|
||||
- @ref depDependencyTable
|
||||
- @ref depKnownIssues
|
||||
- @ref depInstallingDependencies
|
||||
- @ref depUsingAptGet
|
||||
- @ref depUsingHomebrew
|
||||
- @ref depManInstall
|
||||
<!-- - @ref depContents -->
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
@b Note: The dependency information on this page details a complete
|
||||
requirements list for building OpenVDB as a @b standalone package. If you wish
|
||||
to use OpenVDB with a supported 3rd party DCC (Houdini/Maya), make sure you've
|
||||
first read the [Building OpenVDB](@ref build) information.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
There are a number of optional and required dependencies necessary when
|
||||
building different components of OpenVDB. Below you'll find a full list of all
|
||||
dependencies, any minimum/recommended version requirements and some guides for
|
||||
getting these dependencies installed. You'll also find information on any
|
||||
known issues with particular software. Please report any issues not listed
|
||||
here to the OpenVDB TSC.
|
||||
|
||||
Note that OpenVDB is production tested against the [VFX Reference Platform]
|
||||
(https://www.vfxplatform.com/). Not all dependencies exist in the VFX
|
||||
Reference Platform, but for those that do, their specified versions are
|
||||
@b always recommended.
|
||||
|
||||
@section depComponents OpenVDB Components
|
||||
|
||||
Component | Requirements | Optional
|
||||
----------------------- | ------------------------------------------------- | --------
|
||||
OpenVDB Core Library | CMake, C++14 compiler, TBB::tbb, Boost::iostream | Blosc, ZLib, Log4cplus, IlmBase::Half
|
||||
OpenVDB Print | Core Library dependencies | -
|
||||
OpenVDB LOD | Core Library dependencies | -
|
||||
OpenVDB Render | Core Library dependencies | OpenEXR, IlmBase, libpng
|
||||
OpenVDB View | Core Library dependencies, OpenGL, GLFW3, GLEW* | -
|
||||
OpenVDB Python | Core Library dependencies, Python, Boost::python | Boost::numpy, NumPy
|
||||
OpenVDB AX | Core Library dependencies, LLVM | Bison, Flex
|
||||
NanoVDB | - | Core Library, CUDA, TBB, Blosc, ZLib
|
||||
OpenVDB UnitTests | Core Library dependencies, GoogleTest | CppUnit**
|
||||
OpenVDB Documentation | Doxygen | -
|
||||
|
||||
- @b * GLEW is only required for building the vdb_view binary on Windows.
|
||||
- @b ** CppUnit is only required for building the AX unit tests.
|
||||
- @b Note - Bison and Flex are only required for re-generation of the AX
|
||||
grammar which is not typically necessary for the majority of users.
|
||||
|
||||
@subsection depDependencyTable Dependency Table
|
||||
|
||||
Package | Minimum | Recommended | Description | apt-get | Homebrew | Source
|
||||
-------------- | ------- | ----------- | ----------------------------------------------------------------- | ------- | -------- | ------
|
||||
CMake | 3.12 | Latest | Cross-platform family of tools designed to help build software | Y | Y | https://cmake.org
|
||||
GCC | 6.3.1 | 6.3.1 | C++ 14 Compiler: The GNU Compiler Collection | Y | Y | https://www.gnu.org/software/gcc
|
||||
Clang | 3.8 | Latest | C++ 14 Compiler: A C language family frontend for LLVM | Y | Y | https://clang.llvm.org
|
||||
Intel ICC | 17 | Latest | C++ 14 Compiler: Intels C++ Compiler | Y | Y | https://software.intel.com/en-us/c-compilers
|
||||
MSVC | 19.10 | Latest | C++ 14 Compiler: Microsoft Visual C++ Compiler | Y | Y | https://visualstudio.microsoft.com/vs
|
||||
IlmBase | 2.2** | 2.3 | Used half precision floating points and EXR serialization support | Y | Y | http://www.openexr.com
|
||||
OpenEXR | 2.2** | 2.3 | EXR serialization support | Y | Y | http://www.openexr.com
|
||||
TBB | 2018 | 2018 | Threading Building Blocks - template library for task parallelism | Y | Y | https://www.threadingbuildingblocks.org
|
||||
ZLIB | 1.2.7 | Latest | Compression library for disk serialization compression | Y | Y | https://www.zlib.net
|
||||
Boost | 1.66 | 1.66 | Components: iostreams, python, numpy | Y | Y | https://www.boost.org
|
||||
LLVM | 6.0.0 | 8.0.0 | Target-independent code generation | Y | Y | https://llvm.org/
|
||||
Bison | 3.0.0 | 3.0.5 | General-purpose parser generator | Y | Y | https://www.gnu.org/software/gcc
|
||||
Flex | 2.6 | 2.6.4 | Fast lexical analyzer generator | Y | Y | https://github.com/westes/flex
|
||||
Python | 2.7 | 2.7 | The python interpreter and libraries for C++/python bindings | Y | Y | https://www.python.org
|
||||
NumPy | 1.14.0 | 1.14.0 | Scientific computing with Python | Y | Y | http://www.numpy.org
|
||||
GoogleTest | 1.10 | Latest | A unit testing framework module for C++ | Y | Y | https://github.com/google/googletest
|
||||
CppUnit | 1.10 | Latest | A unit testing framework module for C++ | N | Y | https://freedesktop.org/wiki/Software/cppunit
|
||||
Blosc | 1.17.0* | 1.17.0 | Recommended dependency for improved disk compression | Y | Y | https://github.com/Blosc/c-blosc/releases
|
||||
Log4cplus | 1.1.2 | Latest | An optional dependency for improved OpenVDB Logging | Y | Y | https://github.com/log4cplus/log4cplus
|
||||
libpng | - | Latest | Library for manipulating PNG images | Y | Y | http://www.libpng.org/pub/png/libpng.html
|
||||
GLFW | 3.1 | Latest | Simple API for OpenGL development | Y | Y | https://www.glfw.org
|
||||
OpenGL | 3.2 | Latest | Environment for developing portable graphics applications | Y | Y | https://www.opengl.org
|
||||
GLEW | 1.0.0 | Latest | A cross-platform OpenGL extension loading library. | Y | Y | http://glew.sourceforge.net
|
||||
CUDA | - | Latest | Parallel computing platform for graphical processing units. | Y | N | https://developer.nvidia.com/cuda-downloads
|
||||
Doxygen | 1.8.8 | 1.8.11 | Documentation generation from C++ | Y | Y | http://www.doxygen.nl
|
||||
|
||||
- @b * See the note in [known issues](@ref depKnownIssues) regarding supported blosc versions.
|
||||
|
||||
- @b ** IlmBase/OpenEXR 2.2 is supported as Houdini 18.0 is shipped with
|
||||
VFX Reference Platform 2019, except for using older versions of these
|
||||
libraries.
|
||||
|
||||
@subsection depKnownIssues Known Issues
|
||||
|
||||
- @b GLFW: Crash with GLFW 3.2.1 when used with EGL on Linux. OpenVDB View may
|
||||
segfault on closure. Fixed in GLFW 3.3
|
||||
|
||||
- @b Boost 1.66/1.67 + @b Python3 + @b NumPy: Known issue on UNIX systems
|
||||
which can cause the below python runtime error. Consider updating to Boost 1.68
|
||||
if you require both Python3 and NumPy support:
|
||||
|
||||
@code{.sh}
|
||||
RuntimeError: FATAL: module compiled as little endian, but detected different endianness at runtime.
|
||||
@endcode
|
||||
|
||||
- @b Blosc: OpenVDB has historically used an old version of blosc (1.5.0) to
|
||||
serialize .vdb files. OpenVDB is moving to a new blosc version minimum of 1.17.0.
|
||||
We have tested a range of blosc versions and found that the following versions
|
||||
are NOT compatible with OpenVDB caches written using blosc 1.5.0. Additionally
|
||||
these versions of blosc may generally not be compatible with OpenVDB itself.
|
||||
Avoid using these versions and upgrade to the new minimum of 1.17.0 where
|
||||
possible.
|
||||
|
||||
- All versions from 1.11.0 through to, but excluding, 1.14.0.
|
||||
- Versions 1.16.0 and 1.16.1.
|
||||
|
||||
For more information see:
|
||||
|
||||
- https://www.blosc.org/posts/new-forward-compat-policy/
|
||||
- https://github.com/Blosc/c-blosc/issues/260
|
||||
- https://github.com/Blosc/c-blosc/issues/261
|
||||
|
||||
@section depInstallingDependencies Installing Dependencies
|
||||
|
||||
This section details a number of ways to get you up and running with the
|
||||
required OpenVDB dependencies.
|
||||
|
||||
@subsection depUsingAptGet Using UNIX apt-get
|
||||
|
||||
@b Note:CppUnit is unavailable using apt-get. See the other package manager
|
||||
methods or the [manual installation](@ref depManInstall) options.
|
||||
|
||||
@code{.sh}
|
||||
#!/bin/bash
|
||||
# Core library
|
||||
apt-get install cmake # CMake
|
||||
apt-get install libtbb-dev # TBB
|
||||
apt-get install zlibc # zlib
|
||||
apt-get install libboost-iostreams-dev # Boost::iostream
|
||||
apt-get install libblosc-dev # Blosc
|
||||
# AX
|
||||
apt-get install llvm-8-dev # LLVM
|
||||
# Python
|
||||
apt-get install libboost-python-dev # Boost::python
|
||||
apt-get install libboost-numpy-dev # Boost::numpy
|
||||
apt-get install python-dev # Python
|
||||
apt-get install python-numpy # NumPy
|
||||
# Optional
|
||||
apt-get install libpng-dev # libpng
|
||||
apt-get install libilmbase-dev # IlmBase
|
||||
apt-get install libopenexr-dev # OpenEXR
|
||||
apt-get install liblog4cplus-dev # Log4cplus
|
||||
apt-get install googletest # GoogleTest
|
||||
# vdb_view
|
||||
apt-get install libglfw3-dev # GLFW
|
||||
# Documentation
|
||||
apt-get install doxygen # doxygen
|
||||
# CUDA for NanoVDB
|
||||
apt-get install nvidia-cuda-toolkit # CUDA
|
||||
@endcode
|
||||
|
||||
@subsection depUsingHomebrew Using Homebrew
|
||||
|
||||
[Homebrew](https://brew.sh/) is a package manager for UNIX systems and is
|
||||
an alternative to apt-get or manual installation from source.
|
||||
|
||||
@code{.sh}
|
||||
#!/bin/bash
|
||||
# Core library
|
||||
brew install cmake # CMake
|
||||
brew install tbb # TBB
|
||||
brew install zlib # zlib
|
||||
brew install boost # Boost
|
||||
brew install c-blosc # blosc
|
||||
# AX
|
||||
brew install llvm # LLVM
|
||||
# Python
|
||||
brew install boost-python # Boost-python
|
||||
brew install python # Python
|
||||
brew install numpy # NumPy
|
||||
# Unit Tests
|
||||
brew install gtest # GoogleTest
|
||||
brew install cppunit # CppUnit
|
||||
# vdb_view
|
||||
brew install glfw # GLFW
|
||||
# vdb_render
|
||||
brew install ilmbase # IlmBase
|
||||
brew install openexr # OpenEXR
|
||||
brew install libpng # libpng
|
||||
# Documentation
|
||||
brew install doxygen # Doxygen
|
||||
@endcode
|
||||
|
||||
@subsection depManInstall UNIX Manual Installations
|
||||
|
||||
Some dependencies may be unavailable using the above package manager methods.
|
||||
Below are manual installation methods for these packages. Note that you will
|
||||
have to provide your chosen installation locations to the OpenVDB CMake build
|
||||
system when building OpenVDB.
|
||||
|
||||
@b CppUnit (for AX Unit Tests)
|
||||
|
||||
@code{.sh}
|
||||
#!/bin/bash
|
||||
wget http://dev-www.libreoffice.org/src/cppunit-1.13.2.tar.gz
|
||||
tar -xvzf cppunit-1.13.2.tar.gz
|
||||
cd cppunit-1.13.2
|
||||
# Install to users home directory - you may customise this location
|
||||
mkdir -p $HOME/cppunit
|
||||
./configure --prefix=$HOME/cppunit
|
||||
make
|
||||
make install
|
||||
@endcode
|
||||
|
||||
*/
|
||||
+546
@@ -0,0 +1,546 @@
|
||||
/**
|
||||
@mainpage OpenVDB
|
||||
|
||||
The @b OpenVDB library comprises a hierarchical data structure and a suite
|
||||
of tools for the efficient manipulation of sparse, possibly time-varying,
|
||||
volumetric data discretized on a three-dimensional grid. It is based on
|
||||
VDB, which was developed by Ken Museth at DreamWorks Animation, and it
|
||||
offers an effectively infinite 3D index space, compact storage (both in
|
||||
memory and on disk), fast data access (both random and sequential), and
|
||||
a collection of algorithms specifically optimized for the data structure
|
||||
for common tasks such as filtering, CSG, compositing, sampling and
|
||||
voxelization from other geometric representations. The technical details
|
||||
of VDB are described in the paper <A href="http://www.museth.org/Ken/Publications.html">“VDB: High-Resolution Sparse Volumes with Dynamic Topology”</A>.
|
||||
|
||||
@b OpenVDB is maintained by the
|
||||
<A HREF="https://www.aswf.io/">Academy Software Foundation (ASWF)</A>.
|
||||
It was originally developed at
|
||||
<A HREF="https://www.dreamworksanimation.com/">DreamWorks Animation</A>,
|
||||
primarily by
|
||||
- Ken Museth
|
||||
- Peter Cucka
|
||||
- Mihai Aldén
|
||||
- David Hill
|
||||
|
||||
See the @subpage changes "Release Notes" for what’s new in this version
|
||||
of @b OpenVDB.
|
||||
|
||||
See the @subpage dependencies "Dependencies" page for @b OpenVDB requirements.
|
||||
|
||||
See @subpage build "Building OpenVDB" for information on building @b OpenVDB.
|
||||
|
||||
See the @subpage overview "Overview" for an introduction to the library.
|
||||
|
||||
See @subpage transformsAndMaps "Transforms and Maps" for more
|
||||
discussion of the transforms used in @b OpenVDB.
|
||||
|
||||
See the @subpage faq "FAQ" for frequently asked questions about @b OpenVDB.
|
||||
|
||||
See the @subpage codeExamples "Cookbook" to get started using @b OpenVDB.
|
||||
|
||||
See @subpage points "OpenVDB Points" to store point data using @b OpenVDB.
|
||||
|
||||
See @subpage python "Using OpenVDB in Python" to get started with the
|
||||
@b OpenVDB Python module.
|
||||
|
||||
@if OPENVDB_AX
|
||||
See @subpage openvdbax "OpenVDB AX" for the AX documentation.
|
||||
@endif
|
||||
|
||||
@if OPENVDB_HOUDINI
|
||||
See the @subpage houdini "Houdini Cookbook" for help on implementing Houdini nodes.
|
||||
@endif
|
||||
|
||||
@if NANOVDB
|
||||
See @subpage NanoVDB_MainPage "NanoVDB" for the NanoVDB documentation.
|
||||
@endif
|
||||
|
||||
Contributors, please familiarize yourselves with our
|
||||
@subpage codingStyle "coding standards".
|
||||
|
||||
|
||||
|
||||
@page overview OpenVDB Overview
|
||||
|
||||
@section Contents
|
||||
- @ref secOverview
|
||||
- @ref secTree
|
||||
- @ref subsecTreeConfig
|
||||
- @ref secSparsity
|
||||
- @ref subsecValues
|
||||
- @ref subsecInactive
|
||||
- @ref secSpaceAndTrans
|
||||
- @ref subsecVoxSpace
|
||||
- @ref subsecWorSpace
|
||||
- @ref subsecTrans
|
||||
- @ref secGrid
|
||||
- @ref secToolUtils
|
||||
- @ref secIterator
|
||||
- @ref subsecTreeIter
|
||||
- @ref subsecNodeIter
|
||||
- @ref subsecValueAccessor
|
||||
- @ref subsecTraversal
|
||||
<!-- - @ref secRegistry -->
|
||||
|
||||
|
||||
@section secOverview Introduction
|
||||
|
||||
This document is a high-level summary of the terminology and basic
|
||||
components of the OpenVDB library and is organized around two key
|
||||
motivating concepts. First, OpenVDB is designed specifically to
|
||||
work efficiently with sparse volumetric data locally sampled at a high
|
||||
spatial frequency, although it will function well for dense volumetric
|
||||
data. From this follows the need for a memory efficient representation of
|
||||
this sparsity and the need for fast iterators (and other tools) that
|
||||
respect sparsity. Second, data storage is separated from data
|
||||
interpretation. OpenVDB uses unit-less three-dimensional integer
|
||||
coordinates to address the sparse data, but introduces a unit-less
|
||||
continuous index space for interpolation, along with a transform to
|
||||
place the data in physical space.
|
||||
|
||||
When manipulating data in OpenVDB, the three essential objects are
|
||||
(1) the @vdblink::tree::Tree Tree@endlink, a B-tree-like
|
||||
three-dimensional data structure;
|
||||
(2) the @vdblink::math::Transform Transform@endlink, which relates
|
||||
voxel indices @ijk to physical locations @xyz in
|
||||
@ref subsecWorSpace “world” space; and
|
||||
(3) the @vdblink::Grid Grid@endlink, a container
|
||||
that associates a @b Tree with a @b Transform and additional metadata.
|
||||
For instancing purposes (i.e., placing copies
|
||||
of the same volume in multiple locations), the same tree may be referenced
|
||||
(via smart pointers) by several different <B>Grid</B>s, each having a
|
||||
unique transform.
|
||||
|
||||
We now proceed to discuss the @b Tree and ideas of sparsity in some
|
||||
detail, followed by a briefer description of the different spaces and
|
||||
transforms as well as some of the tools that act on the sparse data.
|
||||
|
||||
|
||||
@section secTree The Tree
|
||||
|
||||
In OpenVDB the @b Tree data structure exists to answer the question
|
||||
<I>What value is stored at location @ijk in three-dimensional index
|
||||
space?</I> Here <I>i</I>, <I>j</I> and <I>k</I> are arbitrary signed 32-bit
|
||||
integers, and the data type of the associated value (<TT>float</TT>,
|
||||
<TT>bool</TT>, vector, etc.) is the same for all @ijk. While the @b Tree
|
||||
serves the same purpose as a large three-dimensional array, it is a
|
||||
specially designed data structure that, given sparse unique values,
|
||||
minimizes the overall memory footprint while retaining fast access times.
|
||||
This is accomplished, as the name suggests, via a tree-based acceleration
|
||||
structure comprising a @vdblink::tree::RootNode RootNode@endlink,
|
||||
@vdblink::tree::LeafNode LeafNode@endlink<B></B>s and usually one or more
|
||||
levels of @vdblink::tree::InternalNode InternalNode@endlink<B></B>s
|
||||
with prescribed branching factors.
|
||||
|
||||
@subsection subsecTreeConfig Tree Configuration
|
||||
|
||||
The tree-based acceleration structure can be configured in various ways,
|
||||
but with the restriction that for a given tree all the <B>LeafNode</B>s
|
||||
are at the same depth. Conceptually, the @b RootNode and
|
||||
<B>InternalNode</B>s increasingly subdivide the three-dimensional index
|
||||
space, and the <B>LeafNode</B>s hold the actual unique voxels.
|
||||
|
||||
The type of a @b Tree encodes both the type of the data to be
|
||||
stored in the tree (<TT>float</TT>, <TT>bool</TT>, etc.) and the
|
||||
tree’s node configuration. In practice a four-level (root,
|
||||
internal, internal, leaf) configuration is standard, and several
|
||||
common tree types are defined in openvdb.h. For example,
|
||||
@code
|
||||
using FloatTree = tree::Tree4<float, 5, 4, 3>::Type;
|
||||
using BoolTree = tree::Tree4<bool, 5, 4, 3>::Type;
|
||||
@endcode
|
||||
These predefined tree types share the same branching factors, which dictate
|
||||
the number of children of a given node.
|
||||
The branching factors (5, 4, 3) are specified as base two
|
||||
logarithms and should be read backwards from the leaf nodes up the tree.
|
||||
|
||||
In the default tree configuration, each @b LeafNode holds a
|
||||
three-dimensional grid of 2<SUP>3</SUP> voxels on a side (i.e., an
|
||||
8×8×8 voxel grid). Internally, the @b LeafNode is said
|
||||
to be at “level 0” of the tree.
|
||||
At “level 1” of this tree is the first @b InternalNode,
|
||||
and it indexes a 2<SUP>4</SUP>×2<SUP>4</SUP>×2<SUP>4</SUP>
|
||||
= 16×16×16 grid, each entry of which is either a @b LeafNode
|
||||
or a constant value that represents an 8×8×8 block of
|
||||
voxels. At “level 2” is the second @b InternalNode in this
|
||||
configuration; it in turn indexes a
|
||||
2<SUP>5</SUP>×2<SUP>5</SUP>×2<SUP>5</SUP> = 32×32×32
|
||||
grid of level-1 <B>InternalNode</B>s and/or values,
|
||||
and so the @b InternalNode at level 2 subsumes a three-dimensional
|
||||
block of voxels of size 32×16×8 = 4096 on a side. Unlike
|
||||
the <B>InternalNode</B>s and <B>LeafNode</B>s, the @b RootNode
|
||||
(“level 3” for the default configuration) is not explicitly
|
||||
restricted in the number of children it may have, so the overall index space is
|
||||
limited only by the range of the integer indices, which are 32-bit by default.
|
||||
|
||||
|
||||
@section secSparsity Sparse Values and Voxels
|
||||
|
||||
Like a tree’s node configuration, the type of data held by a tree is
|
||||
determined at compile time. Conceptually the tree itself
|
||||
employs two different notions of data sparsity to reduce the memory footprint
|
||||
and at the same time accelerate access to its contents. The first is largely
|
||||
hidden from the user and concerns ways in which large regions of uniform values
|
||||
are compactly represented, and the second allows for fast sequential iteration,
|
||||
skipping user-specified “uninteresting” regions (that may
|
||||
or may not have uniform values).
|
||||
|
||||
@subsection subsecValues Tile, Voxel, and Background Values
|
||||
|
||||
Although the data in a tree is accessed and set on a per-voxel level
|
||||
(i.e., the value at @ijk) it need not be internally stored in that way.
|
||||
To reduce the memory footprint and accelerate data access, data values are
|
||||
stored in three distinct forms internal to the tree: <B>voxel values</B>,
|
||||
<B>tile values</B>, and a <B>background value</B>. A voxel value is a unique
|
||||
value indexed by the location of a voxel and is stored in the @b LeafNode
|
||||
responsible for that voxel. A tile value is a uniform value assigned to all
|
||||
voxels subsumed by a given node. (For example, a tile Value belonging to an
|
||||
@b InternalNode at level 1 is equivalent to a constant-value cube of
|
||||
voxels of the same size, 8×8×8, as a @b LeafNode.)
|
||||
The tile value is returned when a request is made for the data associated
|
||||
with any @ijk location within the uniform tile. The background value is
|
||||
a unique value (stored at the root level) that is returned when accessing
|
||||
any @ijk location that does not resolve to either a tile or a @b LeafNode.
|
||||
|
||||
|
||||
@subsection subsecInactive Active and Inactive Voxels
|
||||
|
||||
Any voxel or tile can be classified as either @b active or @b inactive.
|
||||
The interpretation of this state is application-specific, but generally
|
||||
active voxels are “interesting” and inactive somehow less so.
|
||||
The locations of active values may be sparse in the overall voxel topology, and
|
||||
OpenVDB provides @ref secIterator "iterators" that access active values only
|
||||
(as well as iterators over inactive values, all values, and general topology).
|
||||
An example of active vs. inactive: the voxels used to store the distance
|
||||
values of a narrow-band level set (i.e., close to a given surface) will be
|
||||
marked as active while the other (“far”) voxel locations will be
|
||||
marked as inactive and will generally represent regions of space with
|
||||
constant distance values (e.g., two constant distance values of opposite sign
|
||||
to distinguish the enclosed inside region from the infinite outside or
|
||||
background embedding).
|
||||
|
||||
The @vdblink::tree::Tree::prune() prune@endlink method replaces
|
||||
with tile values any nodes that subsume voxels with the same values
|
||||
and active states.
|
||||
The resulting tree represents the same volume, but more sparsely.
|
||||
|
||||
@section secSpaceAndTrans Coordinate Systems and Transforms
|
||||
|
||||
The sampled data in the tree is accessed using signed <B>index coordinates</B>
|
||||
@ijk, but associating each indicial coordinate with a specific physical
|
||||
location is the job of a @b Transform.
|
||||
A simple linear transform assumes a lattice-like structure with a fixed
|
||||
physical distance Δ between indices, so that
|
||||
@xyz = (Δ<I>i</I>, Δ<I>j</I>, Δ<I>k</I>).
|
||||
|
||||
@subsection subsecVoxSpace Index Space
|
||||
|
||||
To simplify transformations between physical space and lattice index
|
||||
coordinates, a continuous generalization of the index lattice points called
|
||||
<B>index space</B> is used.
|
||||
For example, index space coordinate (1.0, 1.0, 1.0) corresponds to the same
|
||||
point as (1,1,1) in the index lattice, but (1.5,1.0,1.0) also has meaning as
|
||||
halfway between the index coordinates (1,1,1) and (2,1,1). Index space can
|
||||
be used in constructing interpolated data values: given an arbitrary
|
||||
location in physical space, one can use a transform to compute the point in
|
||||
index space (which need not fall on an exact integer index) that maps to that
|
||||
location and locally interpolate from values with neighboring index
|
||||
coordinates.
|
||||
|
||||
@subsection subsecWorSpace World Space
|
||||
|
||||
The interpretation of the data in a tree takes place in <B>world
|
||||
space</B>. For example, the tree might hold data sampled at discrete
|
||||
physical locations in world space. @b Transform methods such as
|
||||
@vdblink::math::Transform::indexToWorld() indexToWorld@endlink
|
||||
and its inverse @vdblink::math::Transform::worldToIndex() worldToIndex@endlink
|
||||
may be used to relate coordinates in the two continuous spaces. In
|
||||
addition, methods such as @vdblink::math::Transform::worldToIndexCellCentered()
|
||||
worldToIndexCellCentered@endlink actually return lattice points.
|
||||
|
||||
@subsection subsecTrans Transforms and Maps
|
||||
A @vdblink::math::Transform Transform @endlink provides a context for
|
||||
interpreting the information held in a tree by associating a location
|
||||
in world space with each entry in the tree.
|
||||
The actual implementation of the @b Transform is managed by a
|
||||
@vdblink::math::MapBase Map@endlink object, which is an
|
||||
encapsulation of a continuous, mostly invertible function of three
|
||||
variables. A @b Map is required to provide
|
||||
@vdblink::math::MapBase::applyMap() applyMap@endlink and
|
||||
@vdblink::math::MapBase::applyInverseMap() applyInverseMap@endlink
|
||||
methods to relate locations in its domain to its range and vice versa.
|
||||
A @b Map is also required to provide information about its local derivatives.
|
||||
For more on these classes, see the
|
||||
@subpage transformsAndMaps "Transforms and Maps" page.
|
||||
|
||||
|
||||
@section secGrid The Grid
|
||||
|
||||
For many applications, it might not be necessary ever to operate directly on
|
||||
trees, though there are often significant performance improvements to be
|
||||
gained by exploiting the tree structure.
|
||||
The @vdblink::Grid Grid@endlink, however, is the preferred interface through
|
||||
which to manage voxel data, in part because a grid associates with a tree
|
||||
additional and often necessary information that is not accessible through
|
||||
the tree itself.
|
||||
|
||||
A @vdblink::Grid Grid@endlink contains smart pointers to a
|
||||
@vdblink::tree::Tree Tree@endlink object and a
|
||||
@vdblink::math::Transform Transform@endlink object, either or both of which
|
||||
might be shared with other grids.
|
||||
As mentioned above, the transform provides for the interpretation of voxel
|
||||
locations. Other grid metadata, notably the <B>grid class</B>, the
|
||||
<B>vector type</B> and the world space/local space toggle, affect
|
||||
the interpretation of voxel values.
|
||||
|
||||
OpenVDB is particularly well-suited (though by no means exclusively so)
|
||||
to the representation of <B>narrow-band level sets</B> and
|
||||
<B>fog volumes</B>.
|
||||
A narrow-band level set is represented by three distinct regions of voxels:
|
||||
an @b outside (or background) region of inactive voxels having a constant,
|
||||
positive distance from the level set surface; an @b inside region of inactive
|
||||
voxels having a constant, negative distance; and a thin band of active voxels
|
||||
(normally three voxels wide on either side of the surface) whose values are
|
||||
signed distances.
|
||||
Similarly, a fog volume is represented by an outside region of inactive
|
||||
voxels with value zero, an inside region of active voxels with value one,
|
||||
and a thin band of active voxels, with values typically varying linearly
|
||||
between zero and one, that separates the inside from the outside.
|
||||
Identifying a grid as a level set or a fog volume, by setting its
|
||||
@vdblink::GridClass grid class@endlink with
|
||||
@vdblink::Grid::setGridClass() setGridClass@endlink, allows tools to invoke
|
||||
alternative implementations that are better-suited or better-optimized
|
||||
for those classes.
|
||||
For example, resampling (in particular, scaling) a level set should normally
|
||||
not be done without updating its signed distance values.
|
||||
The @vdblink::tools::resampleToMatch() resampleToMatch@endlink tool
|
||||
automatically recomputes signed distances for grids that are identified
|
||||
as level sets.
|
||||
(The lower-level @vdblink::tools::GridResampler GridResampler@endlink does not,
|
||||
but it is optimized for level set grids in that it transforms only voxels
|
||||
in the narrow band and relies on
|
||||
@vdblink::Grid::signedFloodFill() signed flood fill@endlink to reconstruct
|
||||
the inside and outside regions.)
|
||||
Other tools whose behavior is affected by the grid class include the
|
||||
@vdblink::tools::divergence() divergence@endlink operator (which has an
|
||||
alternative implementation for @ref sStaggered "staggered velocity" grids),
|
||||
the @vdblink::tools::volumeToMesh() volume to mesh@endlink converter, and
|
||||
the @vdblink::tools::fillWithSpheres() sphere packing@endlink tool.
|
||||
In addition, a number of level-set-specific tools, such as the
|
||||
@vdblink::tools::LevelSetTracker level set tracker@endlink, throw
|
||||
exceptions when invoked on grids that are not identified as level sets.
|
||||
It is important, therefore, to set a grid’s class appropriately.
|
||||
|
||||
When a vector-valued grid is transformed or resampled, it is often necessary
|
||||
for the transform to be applied not just to voxel locations but also to
|
||||
voxel values.
|
||||
By default, grids are identified as “world-space”, meaning that
|
||||
if the grid is vector-valued, its voxel values should be transformed.
|
||||
Alternatively, voxel values of grids identified as
|
||||
“local-space”, via
|
||||
@vdblink::Grid::setIsInWorldSpace() setIsInWorldSpace@endlink, do not
|
||||
undergo transformation.
|
||||
A world-space grid’s @vdblink::VecType vector type@endlink, specified
|
||||
with @vdblink::Grid::setVectorType() setVectorType@endlink, may be invariant,
|
||||
covariant or contravariant, which determines how transforms are applied
|
||||
to the grid’s voxel values (for details see, for example,
|
||||
<A HREF="http://en.wikipedia.org/wiki/Covariance_and_contravariance_of_vectors">
|
||||
<I>Covariance and contravariance of vectors</I></A> [Wikipedia]).
|
||||
The @vdblink::tools::transformVectors() transformVectors@endlink tool can be
|
||||
used to apply a transform to a grid’s voxel values, and it handles all
|
||||
of the supported vector types.
|
||||
|
||||
A grid can optionally be assigned @vdblink::Grid::setName() name@endlink and
|
||||
@vdblink::Grid::setCreator() creator@endlink strings.
|
||||
These are purely informational, though it might be desirable to name grids
|
||||
so as to easily select which ones to read from files that contain multiple
|
||||
grids.
|
||||
In the absence of grid names, or at least of unique names, OpenVDB’s
|
||||
file I/O routines recognize an ordinal suffix:
|
||||
“<TT>[0]</TT>” refers to the first unnamed grid,
|
||||
“<TT>[1]</TT>” refers to the second, and so on, and
|
||||
“<TT>density[0]</TT>” and “<TT>density[1]</TT>”
|
||||
refer to the first and second grids named “density”.
|
||||
Also of interest for file I/O is a grid’s
|
||||
“@vdblink::Grid::setSaveFloatAsHalf() save float as half@endlink”
|
||||
setting, which allows it to be written more compactly using 16-bit
|
||||
floating point values rather than full-precision values.
|
||||
Finally, during file output certain statistics are computed and stored
|
||||
as per-grid metadata.
|
||||
These include the grid’s index-space active voxel bounding box,
|
||||
its active voxel count and its memory usage in bytes.
|
||||
This information can also be
|
||||
@vdblink::io::File::readAllGridMetadata() retrieved@endlink
|
||||
efficiently from a file.
|
||||
|
||||
|
||||
@section secToolUtils Utilities and Tools
|
||||
|
||||
OpenVDB provides utility functions and classes for the manipulation of grids
|
||||
and the data they hold.
|
||||
Tools such as those found in GridOperators.h compute vector quantities from
|
||||
scalar data or vice-versa.
|
||||
Other tools perform filtering (Filter.h and LevelSetFilter.h) and
|
||||
interpolation (Interpolation.h) as well as sampling (GridTransformer.h),
|
||||
compositing and constructive solid geometry (Composite.h), and other
|
||||
transformations (ValueTransformer.h).
|
||||
OpenVDB also supports advanced finite difference computations through
|
||||
a variety of local support stencils (Stencils.h).
|
||||
|
||||
|
||||
@section secIterator Iterators
|
||||
|
||||
OpenVDB provides efficient, often multithreaded, implementations of a large
|
||||
variety of morphological, filtering and other algorithms that address common
|
||||
data manipulation tasks on three-dimensional grids. For more specialized
|
||||
tasks, OpenVDB provides lower-level data accessors that enable fast
|
||||
iteration over all or selected voxels and over the elements of a @b Tree.
|
||||
These take several forms: iterator classes of various types, functor-based
|
||||
@b visitor methods, and the
|
||||
@vdblink::tree::ValueAccessor ValueAccessor@endlink,
|
||||
an accelerator for indexed @ijk voxel lookups.
|
||||
|
||||
Iterator classes follow a fairly consistent naming scheme. First, the
|
||||
@b CIter and @b Iter suffixes denote @const and non-@const iterators, i.e.,
|
||||
iterators that offer, respectively, read-only and read/write access to the
|
||||
underlying tree or node. Second, iterators over tile and voxel values are
|
||||
denoted either @b On, @b Off or @b All, indicating that they visit only
|
||||
active values, only inactive values, or both active and inactive values.
|
||||
So, for example, @b Tree::ValueOnCIter is a read-only iterator over all
|
||||
active values (both tile and voxel) of a tree, whereas
|
||||
@b LeafNode::ValueAllIter is a read/write iterator over all values, both
|
||||
active and inactive, of a single leaf node.
|
||||
|
||||
OpenVDB iterators are not STL-compatible in that one can always request
|
||||
an iterator that points to the beginning of a collection of elements (nodes,
|
||||
voxels, etc.), but one usually cannot request an iterator that points to the
|
||||
end of the collection. (This is because finding the end might require a
|
||||
full tree traversal.) Instead, all OpenVDB iterators implement a @b test
|
||||
method that returns @c true as long as the iterator is not exhausted and
|
||||
@c false as soon as it is. Typical usage is as follows:
|
||||
@code
|
||||
using GridType = openvdb::FloatGrid;
|
||||
GridType grid = ...;
|
||||
for (GridType::ValueOnCIter iter = grid.cbeginValueOn(); iter.test(); ++iter) ...
|
||||
@endcode
|
||||
or more compactly
|
||||
@code
|
||||
for (auto iter = grid.cbeginValueOn(); iter; ++iter) ...
|
||||
@endcode
|
||||
Note that the naming scheme for methods that return “begin”
|
||||
iterators closely mirrors that of the iterators themselves.
|
||||
That is, @b Grid::cbeginValueOn returns a @c const iterator to the first
|
||||
of a grid’s active values, whereas @b LeafNode::beginValueAll returns
|
||||
a non-<TT>const</TT> iterator to the first of a leaf node’s values,
|
||||
both active and inactive.
|
||||
(@c const overloads of <B>begin</B>* methods are usually provided, so that if
|
||||
the @b Grid is itself @c const, <B>Grid::begin</B>* will actually return a
|
||||
@c const iterator. This makes it more convenient to use these methods in
|
||||
templated code.)
|
||||
|
||||
Finally, note that modifying the tree or node over which one is iterating
|
||||
typically does not invalidate the iterator, though it might first need
|
||||
to be incremented to point to the next existing element (for example,
|
||||
if one deletes a child node to which the iterator is currently pointing).
|
||||
|
||||
@subsection subsecTreeIter Tree Iterators
|
||||
@anchor treeValueIterRef
|
||||
@par Tree::ValueIter
|
||||
Tree-level value iterators traverse an entire tree, visiting each value
|
||||
(tile or voxel) exactly once. (It is also possible to restrict the
|
||||
traversal to minimum and maximum levels of the tree.) In addition to the
|
||||
methods common to all OpenVDB iterators, such as @b test and @b next,
|
||||
a @b Tree::ValueIter provides methods that return the depth in the tree of
|
||||
the node within which the iterator is pointing (the root node has depth 0)
|
||||
and the @ijk axis-aligned bounding box of the tile or voxel to which it is
|
||||
pointing, and methods to get and set both the value and the active state of
|
||||
the tile or voxel. See the
|
||||
@vdblink::tree::TreeValueIteratorBase TreeValueIteratorBase @endlink
|
||||
class for the complete list.
|
||||
|
||||
@anchor treeLeafIterRef
|
||||
@par Tree::LeafIter
|
||||
By convention in OpenVDB, voxels in the narrow band of a narrow-band
|
||||
level set are stored only at the leaf level of a tree, so to facilitate the
|
||||
implementation of level set algorithms that operate on narrow-band voxels,
|
||||
OpenVDB provides an iterator that visits each @b LeafNode in a tree exactly
|
||||
once.
|
||||
See the @vdblink::tree::LeafIteratorBase LeafIteratorBase@endlink class
|
||||
for details, and also the related
|
||||
@vdblink::tree::LeafManager LeafManager@endlink acceleration structure.
|
||||
|
||||
@anchor treeNodeIterRef
|
||||
@par Tree::NodeIter
|
||||
A node iterator traverses a tree in depth-first order, starting from its
|
||||
root, and visits each node exactly once. (It is also possible to restrict
|
||||
the traversal to minimum and maximum node depths—see the
|
||||
@vdblink::tree::NodeIteratorBase NodeIteratorBase @endlink class for details.)
|
||||
Like the tree-level value iterator, the node iterator provides methods
|
||||
that return the depth in the tree of the node to which the iterator
|
||||
is pointing (the root node has depth 0) and the @ijk axis-aligned
|
||||
bounding box of the voxels subsumed by the node and all of its children.
|
||||
@par
|
||||
Naturally, a node iterator also provides access to the node to which it is
|
||||
pointing, but this is complicated somewhat by the fact that nodes of the
|
||||
various types (@b RootNode, @b InternalNode and @b LeafNode) do not inherit
|
||||
from a common base class. For efficiency, OpenVDB generally avoids class
|
||||
inheritance and virtual functions in favor of templates, allowing the
|
||||
compiler to optimize away function calls. In particular, each node type is
|
||||
templated on the type of its children, so even two <B>InternalNode</B>s at
|
||||
different levels of a tree have distinct types. As a result, it is
|
||||
necessary to know the type of the node to which a node iterator is pointing
|
||||
in order to request access to that node. See the
|
||||
@ref sNodeIterator "Cookbook" for an example of how to do this.
|
||||
|
||||
@subsection subsecNodeIter Node Iterators
|
||||
|
||||
Less commonly used than tree-level iterators (but found in the
|
||||
implementations of some of the narrow-band level set algorithms referred to
|
||||
@ref treeLeafIterRef "above") are node-level iterators. A node
|
||||
<B>value iterator</B> visits the values (active, inactive or both) stored in
|
||||
a single @b RootNode, @b InternalNode or @b LeafNode, whereas a node
|
||||
<B>child iterator</B> visits the children of a single root or internal node.
|
||||
(Recall that non-leaf nodes store either a tile value or a child node at
|
||||
each grid position.)
|
||||
|
||||
|
||||
@subsection subsecValueAccessor Value Accessor
|
||||
|
||||
When traversing a grid by @ijk index in a spatially coherent pattern,
|
||||
such as when iterating over neighboring voxels, request a
|
||||
@vdblink::tree::ValueAccessor ValueAccessor@endlink from the grid
|
||||
(with @vdblink::Grid::getAccessor() Grid::getAccessor@endlink)
|
||||
and use the accessor’s
|
||||
@vdblink::tree::ValueAccessor::getValue() getValue@endlink and
|
||||
@vdblink::tree::ValueAccessor::setValue() setValue@endlink methods, since
|
||||
these will usually be significantly faster (a factor of three is typical)
|
||||
than accessing voxels directly in the grid’s tree.
|
||||
The accessor records the sequence of nodes
|
||||
visited during the most recent access; on the next access, rather than
|
||||
traversing the tree from the root node down, it performs an inverted
|
||||
traversal from the deepest recorded node up. For neighboring voxels, the
|
||||
traversal need only proceed as far as the voxels’ common ancestor node,
|
||||
which more often than not is the first node in the sequence.
|
||||
|
||||
Multiple accessors may be associated with a single grid. In fact, for
|
||||
multithreaded, read-only access to a grid, it is recommended that each
|
||||
thread be assigned its own accessor. A thread-safe, mutex-locked accessor
|
||||
is provided (see @vdblink::tree::ValueAccessorRW ValueAccessorRW@endlink),
|
||||
but the locking negates much of the performance benefit of inverted traversal;
|
||||
and because it is the accessor object that is thread-safe, not the grid,
|
||||
concurrent reads and writes are not safe unless all threads share a single
|
||||
accessor.
|
||||
|
||||
All accessors associated with a grid must be cleared after any operation that
|
||||
removes nodes from the grid’s tree, such as pruning, CSG or compositing.
|
||||
For those and other built-in operations, this is done automatically via
|
||||
a callback mechanism, but developers must be careful to call
|
||||
@vdblink::tree::Tree::clearAllAccessors() Tree::clearAllAccessors@endlink
|
||||
whenever deleting nodes directly.
|
||||
|
||||
|
||||
@subsection subsecTraversal Tree Traversal
|
||||
|
||||
<I>To be written</I>
|
||||
|
||||
*/
|
||||
+2079
File diff suppressed because it is too large
Load Diff
+235
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
|
||||
@page faq Frequently Asked Questions
|
||||
|
||||
@section sFAQContents Contents
|
||||
- @ref sWhatIsVDB
|
||||
- @ref sWhatLicense
|
||||
- @ref sWhatCLA
|
||||
- @ref sWhyUseVDB
|
||||
- @ref sVersionNumbering
|
||||
- @ref sGeneralizedOctree
|
||||
- @ref sLevelSet
|
||||
- @ref sCustomizeVDB
|
||||
- @ref sAdaptiveGrid
|
||||
- @ref sMeaningOfVDB
|
||||
- @ref sAccessor
|
||||
- @ref sValue
|
||||
- @ref sState
|
||||
- @ref sVoxel
|
||||
- @ref sTile
|
||||
- @ref sBackground
|
||||
- @ref sThreadSafe
|
||||
- @ref sMaxRes
|
||||
- @ref sCompareVDB
|
||||
- @ref sReplaceDense
|
||||
- @ref sContribute
|
||||
|
||||
@section sWhatIsVDB What is OpenVDB?
|
||||
OpenVDB is a library comprising a compact hierarchical data structure and a
|
||||
suite of tools for the efficient manipulation of sparse, possibly time-varying,
|
||||
volumetric data discretized on a three-dimensional grid. It is based on
|
||||
VDB, which was developed by Ken Museth at DreamWorks Animation, and it
|
||||
offers an effectively infinite 3D index space, compact storage (both in
|
||||
memory and on disk), fast data access (both random and sequential), and
|
||||
a collection of algorithms specifically optimized for the data structure
|
||||
for common tasks such as filtering, constructive solid geometry (CSG),
|
||||
discretization of partial differential equations, voxelization of polygons,
|
||||
skinning of particles, volumetric compositing and sampling. The technical
|
||||
details of VDB are described in the paper
|
||||
<a href="http://www.museth.org/Ken/Publications.html" target="_blank">"VDB: High-Resolution Sparse Volumes with Dynamic Topology"</a>.
|
||||
|
||||
@section sWhatLicense What license is OpenVDB distributed under?
|
||||
OpenVDB is released under the Mozilla Public License Version 2.0, which is a
|
||||
free, open source software license developed and maintained by the Mozilla
|
||||
Foundation. For more information about this license, see the
|
||||
<a href="https://www.mozilla.org/en-US/MPL/" target="_blank">Mozilla FAQ</a>.
|
||||
|
||||
@section sWhatCLA Is there a Contributor License Agreement for OpenVDB?
|
||||
Yes, developers who wish to contribute code to be considered for inclusion
|
||||
in the OpenVDB distribution must first be authorized under a signed Contributor
|
||||
License Agreement. The signature and authorization process is managed via
|
||||
the Linux Foundation's EasyCLA system, to handle the different CLAs depending
|
||||
on whether you are contributing on your own behalf or on behalf of your
|
||||
employer. The EasyCLA process will begin the first time you submit a PR
|
||||
to the project.
|
||||
|
||||
@section sWhyUseVDB Why should I use OpenVDB?
|
||||
The typical reasons to adopt OpenVDB are if you are <b>storing sparse
|
||||
data</b> and/or if you are performing <b>sparse computations</b>. OpenVDB
|
||||
is also effectively unbounded, which makes it very convenient for
|
||||
applications where the topology of the data is dynamic or unknown. Unlike
|
||||
many existing sparse data structures, OpenVDB is also optimized for
|
||||
numerical simulations, multithreaded volume compositing, near real-time
|
||||
boolean CSG operations, fast random and sequential data access and
|
||||
voxelization of points and polygons.
|
||||
|
||||
@section sVersionNumbering What is the version numbering system for OpenVDB?
|
||||
We currently use a <I>major.minor.patch</I> version numbering system,
|
||||
and with every release of OpenVDB we change one or more of the three numbers.
|
||||
The patch number is incremented for new features and bug fixes that change
|
||||
neither the API nor the file format of the library nor the ABIs of the @b Grid
|
||||
class or its constituent classes (@b Tree, @b Transform, @b Metadata,
|
||||
@b io::StreamMetadata, etc.).
|
||||
The minor version is incremented for releases that change the API without
|
||||
changing the @b Grid ABI, and for releases that change the file format
|
||||
in such a way that older files can still be read.
|
||||
The major version is incremented when the @b Grid ABI changes, or when the
|
||||
file format changes in a non-backward-compatible way (which should be rare).
|
||||
No release of OpenVDB guarantees ABI compatibility across the entire library,
|
||||
but rather only for the @b Grid and its constituent classes, and primarily
|
||||
to allow third-party app plugins compiled against different versions of
|
||||
the library to coexist and exchange data.
|
||||
|
||||
@section sCustomizeVDB Can I customize the configuration of OpenVDB?
|
||||
Yes! OpenVDB is specifically developed to be highly customizable. That is,
|
||||
the user can define the sizes of all the nodes at each level of a tree as
|
||||
well as the number of tree levels and the data type of values stored in the
|
||||
tree. However, note that since OpenVDB makes extensive use of C++
|
||||
templating, configurations are fixed at compile time rather than at run
|
||||
time. This is a fundamental design characteristic of OpenVDB, and it leads
|
||||
to very high performance, thanks to techniques like inlining and template
|
||||
metaprogramming.
|
||||
|
||||
@section sGeneralizedOctree Is OpenVDB merely a generalized octree or N-tree?
|
||||
No! While OpenVDB can conceptually be configured as a (height-balanced)
|
||||
octree, it is much more than an octree or N-tree. Whereas octrees and
|
||||
N-trees have fixed branching factors of respectively two and N in each
|
||||
coordinate direction, OpenVDB’s branching factors typically vary between
|
||||
tree levels and are only limited to be powers of two. To understand why
|
||||
and also learn about other unique features of OpenVDB, refer to the
|
||||
paper in <i>ACM Transactions on Graphics</i>.
|
||||
|
||||
@section sLevelSet Is OpenVDB primarily for level set applications?
|
||||
No! Don’t let the fact that OpenVDB can represent and operate so well on
|
||||
level sets mislead you into thinking that it is limited to or even focusing
|
||||
on this special type of sparse volumetric application. OpenVDB was developed
|
||||
for general-purpose volumetric processing and numerical simulation, and we
|
||||
have even had success using it for volumetric applications that traditionally
|
||||
call for blocked or dense grids. However, the fact remains that narrow-band
|
||||
level sets play an essential role in many volumetric applications, and this
|
||||
explains why OpenVDB includes so many tools and algorithms specifically
|
||||
for level sets.
|
||||
|
||||
@section sAdaptiveGrid Is OpenVDB an adaptive grid?
|
||||
Let’s first stress that the term "adaptive grid" is somewhat ambiguous.
|
||||
Some use it to mean a grid that can store data sampled at adaptive voxel sizes
|
||||
typically derived from a so-called "refinement oracle", whereas others mean
|
||||
multiple grids with different fixed voxel sizes all sampling the same data.
|
||||
An example of the former is an octree and of the latter is a mipmap.
|
||||
Since OpenVDB stores both data values and child nodes at each level of
|
||||
the tree, it is adaptive only in the first sense, not the second.
|
||||
The level of adaptivity or refinement between the tree levels is defined
|
||||
by the branching factors of the nodes, which are fixed at compile time.
|
||||
|
||||
@section sMeaningOfVDB What does "VDB" stand for?
|
||||
Over the years VDB has been interpreted to mean different things, none of
|
||||
which are very descriptive: "Voxel Data Base", "Volumetric Data Blocks",
|
||||
"Volumetric Dynamic B+tree", etc. In early presentations of VDB we even used
|
||||
a different name, "DB+Grid", which was abandoned to emphasize its
|
||||
distinction from similarly named, but different, existing sparse data
|
||||
structures like DT-Grid or DB-Grid. The simple truth is that "VDB" is just a
|
||||
name. :-)
|
||||
|
||||
@section sAccessor Why are there no coordinate-based access methods on the grid?
|
||||
It might surprise you that the @b Grid class doesn’t directly provide
|
||||
access to voxels via their @ijk coordinates.
|
||||
Instead, the recommended procedure is to ask the grid for a "value accessor",
|
||||
which is an accelerator object that performs bottom-up tree traversal using
|
||||
cached information from previous traversals.
|
||||
Caching greatly improves performance, but it is inherently not thread-safe.
|
||||
However, a single grid may have multiple value accessors, so each thread
|
||||
can safely be assigned its own value accessor.
|
||||
Uncached—and therefore slower, but thread-safe—random access
|
||||
is possible through a grid’s tree, for example with a call like
|
||||
<tt>grid.tree().getValue(ijk)</tt>.
|
||||
|
||||
@section sValue How and where does OpenVDB store values?
|
||||
OpenVDB stores voxel data in a tree with a fixed maximum height (chosen
|
||||
at compile time), with a root node that has a dynamic branching factor,
|
||||
with internal nodes that have fixed branching factors, and with leaf nodes
|
||||
of fixed dimensions. Values can be stored in nodes at all levels of
|
||||
the tree. Values stored in leaf nodes correspond to individual voxels;
|
||||
all other values correspond to "tiles" (see below).
|
||||
|
||||
@section sState What are active and inactive values?
|
||||
Every value in a grid has a binary state that we refer to as its
|
||||
"active state".
|
||||
The interpretation of this binary state is application-specific, but
|
||||
typically an active (on) value is "interesting" in some sense, and an
|
||||
inactive (off) value is less interesting or uninteresting.
|
||||
For example, the values in a narrow-band level set are all active, and
|
||||
values outside the narrow band are all inactive.
|
||||
Active states of values are stored in very compact bit masks that
|
||||
support sparse iteration, so visiting all active (or inactive) values
|
||||
in a grid can be done very efficiently.
|
||||
|
||||
@section sVoxel How are voxels represented in OpenVDB?
|
||||
Values stored in nodes of type @b LeafNode (which, when they exist,
|
||||
have a fixed depth), correspond to individual voxels.
|
||||
These are the smallest addressable units of index space.
|
||||
|
||||
@section sTile What are tiles?
|
||||
Values stored in nodes of type @b RootNode or @b InternalNode correspond to
|
||||
regions of index space with a constant value and active state and with
|
||||
power of two dimensions. We refer to such regions as "tiles". By
|
||||
construction, tiles have no child nodes.
|
||||
|
||||
@section sBackground What is the background value?
|
||||
A tree’s background value is the value that is returned whenever
|
||||
one accesses a region of index space that is not explicitly represented by
|
||||
voxels or tiles in the tree. Thus, you can think of the background value
|
||||
as the default value associated with an empty tree.
|
||||
Note that the background value is always inactive!
|
||||
|
||||
@section sThreadSafe Is OpenVDB thread-safe?
|
||||
Yes and no. If you’re asking if OpenVDB can safely be used in a
|
||||
multithreaded application then the answer is a resounding yes.
|
||||
In fact, many of the tools included in OpenVDB are multithreaded (using
|
||||
Intel’s Threading Building Blocks library).
|
||||
However, like virtually all data structures that employ caching and
|
||||
allocate-on-insert, certain operations in OpenVDB are not thread-safe
|
||||
in the general sense.
|
||||
In particular, it is not safe to retrieve voxels from a grid while
|
||||
another thread is inserting voxels.
|
||||
For multithreaded insertion operations we typically assign a separate grid
|
||||
to each thread and then merge the grids as threads terminate.
|
||||
This technique works remarkably well: because OpenVDB
|
||||
is sparse and hierarchical, merging is very efficient.
|
||||
For more details, please consult the @subpage codeExamples and
|
||||
Appendix B in the <i>Transactions on Graphics</i> paper.
|
||||
|
||||
@section sMaxRes Is OpenVDB unbounded?
|
||||
Yes, to within available memory and the 32-bit precision of the coordinates
|
||||
used to index voxels. And OpenVDB supports signed coordinates, unlike most
|
||||
existing sparse data structures, so there are almost no restrictions on the
|
||||
available grid resolution or the index range of OpenVDB grids.
|
||||
|
||||
@section sCompareVDB How does OpenVDB compare to existing sparse data structures?
|
||||
OpenVDB is very different from existing sparse data structures that you are
|
||||
likely to have heard of. Foremost it is hierarchical (unlike DT-Grid and
|
||||
Field3D), supports simulations and dynamic topology (unlike GigaVoxels), is
|
||||
effectively unbounded (unlike Field3D), and offers fast random and sequential
|
||||
voxel access.
|
||||
|
||||
@section sReplaceDense Does OpenVDB replace dense grids?
|
||||
This depends a lot on your application of dense grids and your configuration
|
||||
of OpenVDB.
|
||||
Clearly, if you are storing or processing sparse data, OpenVDB
|
||||
will offer a smaller memory footprint and faster (sparse) data processing.
|
||||
However, even in some cases where both data and computation are dense, OpenVDB
|
||||
can offer benefits like improved CPU cache performance due to its underlying
|
||||
blocking and hierarchical tree structure.
|
||||
Exceptions are of course algorithms that expect dense data to be laid out
|
||||
linearly in memory, or applications that use very small grids.
|
||||
The simple truth is only a benchmark comparison can tell you the preferred
|
||||
data structure, but for what it’s worth it is our experience that
|
||||
for the volumetric applications we encounter in production, OpenVDB is
|
||||
almost always superior.
|
||||
|
||||
@section sContribute How can I contribute to OpenVDB?
|
||||
If you have bug reports or ideas for improvements or new features,
|
||||
please contact us! If you want to contribute code, please see our
|
||||
<a href="http://www.openvdb.org/license/index.html" target="_blank">License page</a>.
|
||||
|
||||
*/
|
||||
+577
@@ -0,0 +1,577 @@
|
||||
/**
|
||||
|
||||
@page houdini Houdini Cookbook
|
||||
|
||||
This cookbook provides code snippets that illustrate the use of some new
|
||||
tools that simplify the construction of operators in Houdini.
|
||||
It also shows how to write operators that use OpenVDB.
|
||||
|
||||
|
||||
@section sHoudiniContents Contents
|
||||
- @ref sUIConstruction
|
||||
- @ref sParmFactory
|
||||
- @ref sOpFactory
|
||||
- @ref sScopedInputLock
|
||||
- @ref sOpenVDBOperators
|
||||
- @ref sListOfIncomingGrids
|
||||
- @ref sIteratingOverGrids
|
||||
- @ref sProcessingTypedGrids
|
||||
|
||||
|
||||
@section sUIConstruction General operator construction
|
||||
This section gives usage examples for some general helper classes
|
||||
that aid in the construction of Houdini operators.
|
||||
These helper classes are independent of OpenVDB and can be used in the
|
||||
implementation of any type of operator.
|
||||
|
||||
|
||||
@subsection sParmFactory ParmFactory and ParmList
|
||||
The @hulink::ParmFactory ParmFactory@endlink provides a simplified
|
||||
interface to define the parameters of an operator.
|
||||
Invoking the @hulink::ParmFactory::get() get@endlink method on a
|
||||
@b ParmFactory produces a new @b PRM_Template describing a single parameter.
|
||||
For example,
|
||||
|
||||
@code
|
||||
#include <houdini_utils/ParmFactory.h>
|
||||
...
|
||||
|
||||
PRM_Template groupParm =
|
||||
houdini_utils::ParmFactory(PRM_STRING, "group", "Group")
|
||||
.setTooltip("Specify a subset of the input VDB grids to be processed.")
|
||||
.setDocumentation(
|
||||
"The subset of VDB grids to be processed"
|
||||
" (see [specifying volumes|/model/volumes#group] for details"
|
||||
" on selecting grids)")
|
||||
.setChoiceList(&houdini_utils::PrimGroupMenu)
|
||||
.get();
|
||||
|
||||
PRM_Template toleranceParm =
|
||||
houdini_utils::ParmFactory(PRM_FLT_J, "tolerance", "Pruning Tolerance")
|
||||
.setDefault(0.01)
|
||||
.setRange(PRM_RANGE_RESTRICTED, 0, PRM_RANGE_UI, 1)
|
||||
.get();
|
||||
@endcode
|
||||
|
||||
Note that, using a @b ParmFactory, one need only specify those
|
||||
attributes of a parameter (@b setDefaults, @b setTooltip, etc.)
|
||||
that have non-default values.
|
||||
|
||||
By default, a parameter’s tooltip is used to describe the parameter
|
||||
on the Help page for its operator.
|
||||
More detailed documentation in Houdini’s
|
||||
<A HREF="http://www.sidefx.com/docs/houdini/help/format">wiki markup</A>
|
||||
format can be added with @hulink::ParmFactory::setDocumentation()
|
||||
setDocumentation@endlink, as in the example above.
|
||||
Call @b setDocumentation with a null pointer or with an empty string
|
||||
to exclude a parameter from the Help page.
|
||||
|
||||
@b ParmFactory objects may be added directly to a
|
||||
@hulink::ParmList ParmList@endlink, which among other things ensures that
|
||||
the list of templates is properly null-terminated.
|
||||
Typically, the @b ParmList is populated at the time the operator is registered,
|
||||
as in the following example:
|
||||
@code
|
||||
#include <houdini_utils/ParmFactory.h>
|
||||
|
||||
void
|
||||
newSopOperator(OP_OperatorTable* table)
|
||||
{
|
||||
houdini_utils::ParmList parms;
|
||||
|
||||
// Define a string-valued group name pattern parameter and add it to the list.
|
||||
parms.add(houdini_utils::ParmFactory(PRM_STRING, "group", "Group")
|
||||
.setTooltip("Specify a subset of the input VDB grids to be processed.")
|
||||
.setChoiceList(&houdini_utils::PrimGroupMenu));
|
||||
|
||||
// Define a menu of verbosity levels.
|
||||
parms.add(houdini_utils::ParmFactory(PRM_ORD, "verbose", "Verbosity")
|
||||
.setDefault(PRMoneDefaults)
|
||||
.setChoiceListItems(PRM_CHOICELIST_SINGLE, {
|
||||
"quiet", "Quiet", // token, label
|
||||
"verbose", "Verbose",
|
||||
"verbose2", "More Verbose",
|
||||
}));
|
||||
|
||||
// Define a menu from a dynamically-constructed list of items.
|
||||
{
|
||||
std::vector<std::string> items;
|
||||
for (int i = 0; i < openvdb::NUM_GRID_CLASSES; ++i) {
|
||||
openvdb::GridClass cls = openvdb::GridClass(i);
|
||||
items.push_back(openvdb::GridBase::gridClassToString(cls)); // token
|
||||
items.push_back(openvdb::GridBase::gridClassToMenuName(cls)); // label
|
||||
}
|
||||
|
||||
parms.add(houdini_utils::ParmFactory(PRM_ORD, "gridclass", "Grid Class")
|
||||
.setDefault(PRMzeroDefaults)
|
||||
.setChoiceListItems(PRM_CHOICELIST_SINGLE, items));
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
@endcode
|
||||
|
||||
@subsection Switchers
|
||||
The @b ParmList provides a convenient way of defining switchers (tab menus):
|
||||
|
||||
@code
|
||||
parms.beginSwitcher("switcher");
|
||||
|
||||
parms.addFolder("Tree Topology");
|
||||
|
||||
parms.add(houdini_utils::ParmFactory(PRM_HEADING, "nodes", "Nodes"));
|
||||
parms.add(houdini_utils::ParmFactory(PRM_TOGGLE, "viewnodes", "View"));
|
||||
...
|
||||
|
||||
parms.addFolder("Isosurface");
|
||||
|
||||
parms.add(houdini_utils::ParmFactory(PRM_HEADING, "surfacing", "Surfacing"));
|
||||
parms.add(houdini_utils::ParmFactory(PRM_TOGGLE, "extractmesh", "Extract Mesh"));
|
||||
...
|
||||
|
||||
parms.endSwitcher();
|
||||
@endcode
|
||||
|
||||
The above generates the following UI:
|
||||
|
||||
@image html tabmenu.png
|
||||
|
||||
Switchers can also be nested:
|
||||
|
||||
@code
|
||||
parms.beginSwitcher("switcher");
|
||||
parms.addFolder("A");
|
||||
parms.beginSwitcher("nested_switcher");
|
||||
parms.addFolder("1");
|
||||
parms.addFolder("2");
|
||||
parms.addFolder("3");
|
||||
parms.endSwitcher();
|
||||
parms.addFolder("B");
|
||||
...
|
||||
parms.endSwitcher();
|
||||
@endcode
|
||||
|
||||
@subsection Multi-Parms
|
||||
Multi-parms are dynamically-sized parameters that consist of a variable
|
||||
number of child instances.
|
||||
Each child instance is defined by a second @b ParmList that itself consists
|
||||
of multiple parameters.
|
||||
These parameters’ tokens must include a @c # character, which is
|
||||
typically placed at the end of the token.
|
||||
|
||||
@code
|
||||
houdini_utils::ParmList parms;
|
||||
...
|
||||
|
||||
// Build the multi-parm's parameter list.
|
||||
houdini_utils::ParmList multiParms;
|
||||
multiParms.add(houdini_utils::ParmFactory(PRM_STRING, "gridname#", "Grid name")
|
||||
.setTooltip("Specify a name for this grid."));
|
||||
...
|
||||
|
||||
// Create the multi-parm itself.
|
||||
parms.add(houdini_utils::ParmFactory(PRM_MULTITYPE_LIST, "gridlist", "Grids")
|
||||
.setMultiparms(multiParms)
|
||||
.setDefault(PRMoneDefaults));
|
||||
...
|
||||
@endcode
|
||||
|
||||
The above generates the following UI:
|
||||
@image html multiparm.png
|
||||
|
||||
A multi-parm’s parameters are accessed by iterating through each
|
||||
child instance:
|
||||
|
||||
@code
|
||||
UT_String gridNameStr;
|
||||
|
||||
for (int i = 1, N = evalInt("gridlist", 0, 0); i <= N; ++i) {
|
||||
evalStringInst("gridname#", &i, gridNameStr, 0, time);
|
||||
...
|
||||
}
|
||||
@endcode
|
||||
|
||||
Note that evaluating the multi-parm gives the number of child instances,
|
||||
and that the instances are numbered starting from one.
|
||||
|
||||
|
||||
@subsection sOpFactory OpFactory
|
||||
The @hulink::OpFactory OpFactory@endlink is used in conjunction with a
|
||||
@hulink::ParmList ParmList@endlink to register a new operator by adding it
|
||||
to the @b OP_OperatorTable.
|
||||
Among other things, the @b OpFactory ensures that the operator’s
|
||||
type name follows a consistent naming scheme, that its Help URL is set
|
||||
correctly and that its inputs are labeled.
|
||||
Continuing with the earlier @b newSopOperator example,
|
||||
|
||||
@code
|
||||
#include <houdini_utils/ParmFactory.h>
|
||||
|
||||
void
|
||||
newSopOperator(OP_OperatorTable* table)
|
||||
{
|
||||
...
|
||||
|
||||
// Register this operator.
|
||||
houdini_utils::OpFactory(houdini_utils::OpPolicy(), "My SOP",
|
||||
MySOP::factory, parms, *table)
|
||||
.addInput("VDB grids to process") // input 0
|
||||
.addOptionalInput("Reference geometry"); // input 1
|
||||
}
|
||||
@endcode
|
||||
|
||||
The first argument to the @b OpFactory constructor is an instance of the
|
||||
@hulink::OpPolicy OpPolicy@endlink class (or a subclass thereof).
|
||||
@b OpPolicy objects allow for customization of certain behaviors of
|
||||
the @b OpFactory.
|
||||
The base class specifies a policy for converting an English
|
||||
operator name like <tt>"My SOP"</tt>, which appears in menus and other
|
||||
UI elements, into an operator type name.
|
||||
The default policy is simply to call @b UT_String::forceValidVariableName
|
||||
on the English name.
|
||||
|
||||
If the policy does not specify the URL of a Help page, or if the
|
||||
@b OpFactory is constructed without an @b OpPolicy, then documentation
|
||||
for the operator in Houdini’s
|
||||
<A HREF="http://www.sidefx.com/docs/houdini/help/format">wiki markup</A>
|
||||
format can be provided with @hulink::OpFactory::setDocumentation()
|
||||
setDocumentation@endlink.
|
||||
By default, documentation for the operator’s parameters is generated
|
||||
automatically and appended to the text provided with @b setDocumentation.
|
||||
|
||||
When a particular @b OpPolicy is to be used to register multiple operators,
|
||||
it might be convenient to subclass @b OpFactory itself and provide a
|
||||
constructor that automatically initializes the base class with the desired
|
||||
policy.
|
||||
|
||||
If an operator ever needs to be renamed, call
|
||||
@hulink::OpFactory::addAlias() OpFactory::addAlias@endlink
|
||||
with the old name. This will help to ensure that scene files in which
|
||||
the operator was saved with the old name can still be read:
|
||||
|
||||
@code
|
||||
houdini_utils::OpFactory("My Renamed SOP", MySOP::factory, parms, *table)
|
||||
.addInput("VDB grids to process")
|
||||
.addAlias("My SOP"); // old name
|
||||
@endcode
|
||||
|
||||
If the operator name changed as a result of an @b OpPolicy change, supply
|
||||
the old operator type name directly, with
|
||||
@hulink::OpFactory::addAliasVerbatim() addAliasVerbatim@endlink:
|
||||
|
||||
@code
|
||||
houdini_utils::OpFactory(houdini_utils::MyNewOpPolicy(), "My SOP",
|
||||
MySOP::factory, parms, *table)
|
||||
.addAliasVerbatim("My_Old_SOP_Type"); // old operator type name
|
||||
@endcode
|
||||
|
||||
Among other @b OpFactory features,
|
||||
@hulink::OpFactory::setObsoleteParms() OpFactory::setObsoleteParms@endlink
|
||||
accepts an additional @b ParmList of parameters that are no longer in use
|
||||
but that might still exist in older scene files:
|
||||
|
||||
@code
|
||||
#include <houdini_utils/ParmFactory.h>
|
||||
|
||||
void
|
||||
newSopOperator(OP_OperatorTable* table)
|
||||
{
|
||||
// This boolean "draw" parameter has been replaced with a multi-state
|
||||
// "drawmode" parameter.
|
||||
houdini_utils::ParmList obsoleteParms;
|
||||
obsoleteParms.add(houdini_utils::ParmFactory(PRM_TOGGLE, "draw", "Draw"));
|
||||
|
||||
houdini_utils::ParmList parms;
|
||||
|
||||
parms.add(houdini_utils::ParmFactory(PRM_ORD, "drawmode", "Draw")
|
||||
.setChoiceListItems(PRM_CHOICELIST_SINGLE, {
|
||||
"none", "Don't Draw",
|
||||
"wireframe", "Draw Wireframe",
|
||||
"shaded", "Draw Shaded",
|
||||
}));
|
||||
|
||||
// Register this operator.
|
||||
houdini_utils::OpFactory("My SOP", MySOP::factory, parms, *table)
|
||||
.addInput("Input geometry")
|
||||
.setObsoleteParms(obsoleteParms);
|
||||
}
|
||||
@endcode
|
||||
|
||||
Override @b OP_Node::resolveObsoleteParms to convert the values of
|
||||
obsolete parameters into values of current parameters where appropriate.
|
||||
|
||||
|
||||
@subsection sScopedInputLock ScopedInputLock
|
||||
A @hulink::ScopedInputLock ScopedInputLock@endlink locks the inputs to
|
||||
an operator and then automatically unlocks them when it (the lock
|
||||
object) goes out of scope, even if an exception is thrown.
|
||||
|
||||
@code
|
||||
#include <houdini_utils/ParmFactory.h>
|
||||
|
||||
OP_ERROR
|
||||
MySOP::cookMySop(OP_Context& context)
|
||||
{
|
||||
try {
|
||||
houdini_utils::ScopedInputLock lock(*this, context);
|
||||
//
|
||||
// do cook work
|
||||
//
|
||||
} catch (std::exception& e) {
|
||||
addError(SOP_MESSAGE, e.what());
|
||||
}
|
||||
return error();
|
||||
}
|
||||
@endcode
|
||||
|
||||
|
||||
@section sOpenVDBOperators OpenVDB SOP construction
|
||||
OpenVDB SOPs are derived from the @hvdblink::SOP_NodeVDB SOP_NodeVDB@endlink
|
||||
base class which, among other things, adds guide geometry and node-specific
|
||||
info text.
|
||||
|
||||
@code
|
||||
#include <houdini_utils/ParmFactory.h>
|
||||
#include <openvdb_houdini/Utils.h>
|
||||
#include <openvdb_houdini/SOP_NodeVDB.h>
|
||||
#include <UT/UT_Interrupt.h>
|
||||
|
||||
class SOP_DW_OpenVDBTemplate: public openvdb_houdini::SOP_NodeVDB
|
||||
{
|
||||
public:
|
||||
SOP_DW_OpenVDBTemplate(OP_Network*, const char* name, OP_Operator*);
|
||||
~SOP_DW_OpenVDBTemplate() override {};
|
||||
|
||||
static OP_Node* factory(OP_Network*, const char* name, OP_Operator*);
|
||||
|
||||
// Return true for a given input if the connector to the input
|
||||
// should be drawn dashed rather than solid.
|
||||
int isRefInput(unsigned idx) const override { return (idx == 1); }
|
||||
|
||||
protected:
|
||||
OP_ERROR cookVDBSop(OP_Context&) override;
|
||||
bool updateParmsFlags() override;
|
||||
};
|
||||
@endcode
|
||||
|
||||
|
||||
@subsection sListOfIncomingGrids Selecting grids
|
||||
A typical SOP will have at least one group name parameter for each of
|
||||
its inputs. These parameters should be defined as follows (note the
|
||||
use of spare data to specify the input):
|
||||
|
||||
@code
|
||||
houdini_utils::ParmList parms;
|
||||
|
||||
// Define a string-valued group name pattern parameter.
|
||||
parms.add(houdini_utils::ParmFactory(PRM_STRING, "group", "Group")
|
||||
.setTooltip("Specify a subset of the input VDB grids to be processed.")
|
||||
.setChoiceList(&houdini_utils::PrimGroupMenu));
|
||||
|
||||
// Define a group name parameter associated with this operator's second input.
|
||||
parms.add(houdini_utils::ParmFactory(PRM_STRING, "group", "Group")
|
||||
.setTooltip("Specify a subset of the input VDB grids to be processed.")
|
||||
.setChoiceList(&houdini_utils::PrimGroupMenu)
|
||||
.setSpareData(&SOP_Node::theSecondInput));
|
||||
@endcode
|
||||
|
||||
Associated with each parameter is a menu of primitive group names.
|
||||
Users can select one or more groups from the menu, or create new groups
|
||||
on the fly using Houdini’s <tt>\@<i>attr</i>=<i>value</i></tt> syntax.
|
||||
For example, entering <tt>\@name="density*"</tt> as the group name
|
||||
creates a new group comprising all input primitives whose name begins
|
||||
with <tt>density</tt>. Entering <tt>\@vdb_value_type=float</tt>
|
||||
creates a new group of input grid primitives whose data type is @c float.
|
||||
Users may enter multiple space-separated group names or grouping expressions.
|
||||
|
||||
|
||||
@subsection sIteratingOverGrids Iterating over grids
|
||||
In @b cookMySOP, the string value of a group parameter
|
||||
is used to construct a @b GA_PrimitiveGroup.
|
||||
(SOP_NodeVDB provides a convenience method,
|
||||
@hvdblink::SOP_NodeVDB::matchGroup() SOP_NodeVDB::matchGroup@endlink,
|
||||
to simplify this step and to handle errors in a standard way.)
|
||||
The @b GA_PrimitiveGroup so constructed may be iterated over using
|
||||
either a @hvdblink::VdbPrimCIterator VdbPrimCIterator@endlink, for
|
||||
read-only access, or a @hvdblink::VdbPrimIterator VdbPrimIterator@endlink,
|
||||
for read/write access:
|
||||
|
||||
@code
|
||||
OP_ERROR
|
||||
MySOP::cookVDBSOP(OP_Context& context)
|
||||
{
|
||||
try {
|
||||
houdini_utils::ScopedInputLock lock(*this, context);
|
||||
|
||||
const fpreal time = context.getTime();
|
||||
|
||||
// This does a deep copy of native Houdini primitives
|
||||
// but only a shallow copy of VDB grids.
|
||||
duplicateSource(0, context);
|
||||
|
||||
// Get the group of grids to process.
|
||||
UT_String groupStr;
|
||||
evalString(groupStr, "group", 0, time);
|
||||
const GA_PrimitiveGroup* group = matchGroup(*gdp, groupStr.toStdString());
|
||||
|
||||
// Get other UI parameters.
|
||||
int verbose = evalInt("verbose", 0, time);
|
||||
|
||||
UT_AutoInterrupt progress("Processing VDB grids");
|
||||
|
||||
// For each VDB primitive in the selected group...
|
||||
for (openvdb_houdini::VdbPrimIterator it(gdp, group); it; ++it) {
|
||||
|
||||
if (progress.wasInterrupted()) {
|
||||
throw std::runtime_error("processing was interrupted");
|
||||
}
|
||||
|
||||
GU_PrimVDB* vdbPrim = *it;
|
||||
|
||||
// Optionally get the primitive's name (or, if the name is empty,
|
||||
// the primitive's index).
|
||||
const UT_String gridName = it.getPrimitiveNameOrIndex();
|
||||
|
||||
// If this primitive's grid is shared with other primitives, make
|
||||
// a deep copy of it. If the grid is not going to be modified
|
||||
// in place (or when using GEOvdbProcessTypedGrid()--see below),
|
||||
// skip this step.
|
||||
vdbPrim->makeGridUnique();
|
||||
|
||||
openvdb_houdini::Grid& grid = vdbPrim->getGrid();
|
||||
|
||||
// Process the grid.
|
||||
// (Your code goes here.)
|
||||
|
||||
// In cases where it is not possible to process the primitive's
|
||||
// grid in place, replace the grid with a new grid:
|
||||
// openvdb_houdini::GridPtr outputGrid = ...;
|
||||
// vdbPrim->setGrid(*outputGrid);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
addError(SOP_MESSAGE, e.what());
|
||||
}
|
||||
return error();
|
||||
}
|
||||
@endcode
|
||||
|
||||
|
||||
@subsection sProcessingTypedGrids Processing grids of different types
|
||||
Recall that a @b Grid is a container for a transform, metadata and a
|
||||
@b Tree, and that the @b Tree holds voxel data of a specific type
|
||||
(@c bool, @c float, @c vec3s, etc.).
|
||||
Whenever possible, try to write generic grid processing code.
|
||||
That is, write code that can handle grids of more than one type
|
||||
(@c int, @c float and @c double, say, instead of just @c float)
|
||||
or, ideally, grids of arbitrary type.
|
||||
|
||||
Writing generic code can be tricky, but convenience functions
|
||||
exist to make the job easier.
|
||||
Use @b GEOvdbProcessTypedGrid to call a method or methods on
|
||||
a primitive’s grid, regardless of its type:
|
||||
|
||||
@code
|
||||
MyGridProcessor proc; // functor (see explanation below)
|
||||
// Call a method on the primitive's grid, regardless of the grid's type.
|
||||
// Note that by default, GEOvdbProcessTypedGrid() calls makeGridUnique()
|
||||
// on the primitive if it is non-const.
|
||||
GEOvdbProcessTypedGrid(*vdbPrim, proc);
|
||||
@endcode
|
||||
|
||||
@b GEOvdbProcessTypedGrid accepts a primitive and a functor
|
||||
(an object for which the call operator,
|
||||
<tt>operator()()</tt>, is defined).
|
||||
The functor’s call operator must be templated on a single type
|
||||
(the grid type) and must accept a single argument (a reference to a grid
|
||||
of the template type).
|
||||
The operator’s return value is ignored, so it’s best to
|
||||
declare it @c void.
|
||||
The following is a simple example of a functor that satisfies these conditions:
|
||||
|
||||
@code
|
||||
struct PruneOp
|
||||
{
|
||||
template<typename GridT>
|
||||
void operator()(GridT& grid) const { grid.prune(); }
|
||||
};
|
||||
@endcode
|
||||
|
||||
@b PruneOp can call the @b prune method on a grid of any type, but it’s
|
||||
necessary to know the specific type, because @b prune takes an optional
|
||||
tolerance argument whose type is the type of the grid’s voxel values.
|
||||
(Note that grids also have a @b pruneGrid method that doesn’t require
|
||||
knowledge of the voxel value type.)
|
||||
|
||||
Because a functor is an object, it can have member variables.
|
||||
This makes it possible for the functor to process more than one grid
|
||||
at a time, even though it gets called with only one grid.
|
||||
This example shows how one might compute the CSG union of two level set
|
||||
grids, <i>A</i> and <i>B</i>, of the same type:
|
||||
|
||||
@code
|
||||
#include <openvdb/tools/Composite.h> // for csgUnion()
|
||||
|
||||
struct CSGUnionOp
|
||||
{
|
||||
// Pointer to the B grid
|
||||
// (non-const, because CSG operations modify both the A and B grids)
|
||||
openvdb_houdini::Grid* bGridBase;
|
||||
|
||||
template<typename GridT>
|
||||
void operator()(GridT& aGrid) const
|
||||
{
|
||||
// Cast the generic B grid pointer to point to a grid of
|
||||
// the same type as the A grid.
|
||||
if (GridT* bGrid = UTvdbGridCast<GridT>(bGridBase)) {
|
||||
// Compute the union, storing the result in the A grid
|
||||
// and emptying the B grid.
|
||||
openvdb::tools::csgUnion(aGrid, *bGrid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
OP_ERROR
|
||||
MySOP::cookVDBSop(OP_Context& context)
|
||||
{
|
||||
...
|
||||
// Retrieve the A and B grids from primitives on the input detail(s)
|
||||
// (non-const, because CSG operations modify both the A and B grids).
|
||||
openvdb_houdini::Grid
|
||||
&aGrid = aPrim->getGrid(),
|
||||
&bGrid = bPrim->getGrid();
|
||||
|
||||
// CSG operations require the A and B grids to have the same type.
|
||||
if (aGrid.type() != bGrid.type()) {
|
||||
addError(SOP_MESSAGE, "grids have different types");
|
||||
} else {
|
||||
CSGUnionOp proc;
|
||||
|
||||
// Hand the functor a generic pointer to the B grid
|
||||
// (whose concrete type we don't know yet).
|
||||
proc.bGridBase = &bGrid;
|
||||
|
||||
// Apply the CSG operation, overwriting grid A (and emptying grid B).
|
||||
if (!GEOvdbProcessTypedGrid(*aPrim, proc)) {
|
||||
addError(SOP_MESSAGE, "failed to compute CSG union");
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
|
||||
Certain operations might make sense only for grids with scalar or with
|
||||
vector voxel values.
|
||||
Variants of @b GEOvdbProcessTypedGrid exist to handle those cases.
|
||||
For example, @b GEOvdbProcessTypedGridScalar and @b GEOvdbProcessTypedGridVec3
|
||||
invoke a functor only on grids of scalar or 3-vector types, respectively,
|
||||
and they return @c false for and ignore grids of all other types.
|
||||
|
||||
|
||||
<!--
|
||||
To do:
|
||||
- iterating over multiple inputs
|
||||
- VDB source nodes
|
||||
-->
|
||||
|
||||
*/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
+422
@@ -0,0 +1,422 @@
|
||||
/**
|
||||
|
||||
@page transformsAndMaps Transforms and Maps
|
||||
|
||||
@section sMathContents Contents
|
||||
- @ref sTransforms
|
||||
- @ref sLinearTransforms
|
||||
- @ref sFrustumTransforms
|
||||
- @ref sCellVsVertex
|
||||
- @ref sVoxels
|
||||
- @ref sStaggered
|
||||
- @ref sMaps
|
||||
- @ref sGettingMat4
|
||||
- @ref sCostOfMaps
|
||||
- @ref sGradientAndMaps
|
||||
|
||||
@section sTransforms Transforms in OpenVDB
|
||||
The OpenVDB @vdblink::tree::Tree Tree@endlink is a sparse representation
|
||||
of a three-dimensional array of voxels, each element of which is addressed via
|
||||
discrete, three-dimensional index space coordinates, typically in the form of
|
||||
a @vdblink::math::Coord Coord@endlink.
|
||||
For example, the following code retrieves the floating-point value of
|
||||
a voxel with index coordinates (1, 2, 3):
|
||||
@code
|
||||
openvdb::FloatGrid grid = ...;
|
||||
openvdb::FloatGrid::Accessor accessor = grid.getAccessor();
|
||||
openvdb::Coord ijk(1,2,3);
|
||||
float value = accessor.getValue(ijk);
|
||||
@endcode
|
||||
|
||||
A @vdblink::math::Transform Transform@endlink relates index space coordinates
|
||||
to world space coordinates that give a spatial context for the
|
||||
discretized data.
|
||||
Translation from index coordinates @ijk to world space coordinates @xyz is
|
||||
done with a call to the
|
||||
@vdblink::math::Transform::indexToWorld() indexToWorld@endlink
|
||||
method, and from world space coordinates to index space coordinates with
|
||||
a call to @vdblink::math::Transform::worldToIndex() worldToIndex@endlink:
|
||||
@code
|
||||
// Create a linear transform that scales i, j and k by 0.1
|
||||
openvdb::math::Transform::Ptr linearTransform =
|
||||
openvdb::math::Transform::createLinearTransform(0.1);
|
||||
|
||||
// Compute the location in world space that is the image of (1,2,3).
|
||||
// The result will be (0.1, 0.2, 0.3).
|
||||
openvdb::Coord ijk(1,2,3);
|
||||
openvdb::Vec3d worldSpacePoint = linearTransform->indexToWorld(ijk);
|
||||
|
||||
// Compute the location in index space that is the pre-image of (0.1, 0.2, 0.3).
|
||||
// The result will be (1.0, 2.0, 3.0).
|
||||
openvdb::Vec3d indexSpacePoint = linearTransform->worldToIndex(worldSpacePoint);
|
||||
@endcode
|
||||
In the above example, there are two things to notice.
|
||||
First, world space locations are specified as three-dimensional,
|
||||
double-precision, floating-point vectors, and second, @b worldToIndex
|
||||
does not return discrete coordinates, but rather a floating-point vector.
|
||||
This is a reflection of the fact that not every location in a continuous
|
||||
world space, i.e., not every @xyz, is the image of discrete integral
|
||||
coordinates @ijk.
|
||||
|
||||
@subsection sLinearTransforms Linear Transforms
|
||||
Currently two different types of transforms are supported: linear and
|
||||
frustum transforms.
|
||||
A linear transform can be composed of scale, translation, rotation, and shear;
|
||||
essentially those things that can be mathematically represented by an
|
||||
invertible, constant-coefficient, 3×3 matrix and a translation
|
||||
(mathematically, an affine map).
|
||||
An essential feature of a linear transformation is that it treats all regions
|
||||
of index space equally: a small box in index space about origin @ijk=(0,0,0)
|
||||
is mapped (sheared, scaled, rotated, etc.) in just the same way that
|
||||
a small box about any other index point is mapped.
|
||||
@code
|
||||
// Create a linear transform from a 4x4 matrix (identity in this example).
|
||||
openvdb::math::Mat4d mat = openvdb::math::Mat4d::identity();
|
||||
openvdb::math::Transform::Ptr linearTransform =
|
||||
openvdb::math::Transform::createLinearTransform(mat);
|
||||
|
||||
// Rotate the transform by 90 degrees about the X axis.
|
||||
// As a result the j-index will now map into the -z physical direction,
|
||||
// and the k-index will map to the +y physical direction.
|
||||
linearTransform->preRotate(M_PI/2, openvdb::math::X_AXIS);
|
||||
@endcode
|
||||
|
||||
@subsection sFrustumTransforms Frustum Transforms
|
||||
The frustum transform is a nonlinear transform that treats different
|
||||
index points differently.
|
||||
And while the linear transform can be applied to any point in index
|
||||
or world space, the frustum transform is designed to operate on a subset
|
||||
of space. Specifically, it transforms a given box in index space to
|
||||
a tapered box in world space that is a frustum of a rectangular pyramid.
|
||||
@code
|
||||
// Create the bounding box that will be mapped by the transform into
|
||||
// the shape of a frustum.
|
||||
// The points (0,0,0), (100,0,0), (0,50,0) and (100,50,0) will map to
|
||||
// the corners of the near plane of the frustum, while the corners
|
||||
// of the far plane will be the images of (0,0,120), (100,0,120),
|
||||
// (0,50,120) and (100,50,120).
|
||||
const openvdb::math::BBoxd bbox(/*min=*/openvdb::math::Vec3d(0,0,0),
|
||||
/*max=*/openvdb::math::Vec3d(100,50,120));
|
||||
|
||||
// The far plane of the frustum will be twice as big as the near plane.
|
||||
const double taper = 2;
|
||||
|
||||
// The depth of the frustum will be 10 times the x-width of the near plane.
|
||||
cosnt double depth = 10;
|
||||
|
||||
// The x-width of the frustum in world space units
|
||||
const double xWidth = 100;
|
||||
|
||||
// Construct a frustum transform that results in a frustum whose
|
||||
// near plane is centered on the origin in world space.
|
||||
openvdb::math::Transform::Ptr frustumTransform =
|
||||
openvdb::math:::Transform::createFrustumTransform(
|
||||
bbox, taper, depth, xWidth);
|
||||
|
||||
// The frustum shape can be rotated, scaled, translated and even
|
||||
// sheared if desired. For example, the following call translates
|
||||
// the frustum by 10,15,0 in world space:
|
||||
frustumTransform->postTranslate(openvdb::math::Vec3d(10,15,0));
|
||||
|
||||
// Compute the world space image of a given point within
|
||||
// the index space bounding box that defines the frustum.
|
||||
openvdb::Coord ijk(20,10,18);
|
||||
openvdb::Vec3d worldLocation = frustumTransform->indexToWorld(ijk);
|
||||
@endcode
|
||||
|
||||
@subsection sCellVsVertex Cell-Centered vs. Vertex-Centered Transforms
|
||||
When partitioning world space with a regular grid, two popular
|
||||
configurations are cell-centered and vertex-centered grids. This is really
|
||||
a question of interpretation and transforms.
|
||||
|
||||
The cell-centered interpretation imagines world space as divided
|
||||
into discrete cells (e.g., cubes) centered on the image of the
|
||||
index-space lattice points.
|
||||
So the physical location @xyz that is the image (result of @b indexToWorld)
|
||||
of a lattice point @ijk is the center of a cube.
|
||||
In the vertex-centered approach, the images of the lattice points form the
|
||||
vertices of cells, so the location @xyz would be a corner, not the
|
||||
center, of a cube.
|
||||
|
||||
The link between transforms and cell-centered or vertex-centered
|
||||
partitioning of world space is tenuous.
|
||||
It boils down to this: the “first” cell vertex often is aligned
|
||||
with the origin.
|
||||
In the cell-centered case, when the cells are cubes of length Δ
|
||||
on a side, the transform @xyz = (Δ<I>i</I> + Δ/2,
|
||||
Δ<I>j</I> + Δ/2, Δ<I>k</I> + Δ /2)
|
||||
will place the center of the first cube (i.e., the image of (0,0,0))
|
||||
at the world space location of (Δ/2, Δ/2, Δ/2),
|
||||
and the cube will have walls coincident with the <I>x</I>=0, <I>y</I>=0
|
||||
and <I>z</I>=0 planes.
|
||||
Using the OpenVDB transforms to create a so-called cell-centered transform
|
||||
could be done like this:
|
||||
@code
|
||||
// -- Constructing a uniform, cell-centered transform --
|
||||
|
||||
// The grid spacing
|
||||
const double delta = 0.1;
|
||||
|
||||
// The offset to cell-center points
|
||||
const openvdb::math::Vec3d offset(delta/2., delta/2., delta/2.);
|
||||
|
||||
// A linear transform with the correct spacing
|
||||
openvdb::math::Transform::Ptr transform =
|
||||
openvdb::math:::Transform::createLinearTransform(delta);
|
||||
|
||||
// Add the offset.
|
||||
transform->postTranslate(offset);
|
||||
@endcode
|
||||
In contrast, for the vertex-centered partitions of space the first
|
||||
vertex is just the image of the first lattice point @ijk = (0,0,0),
|
||||
and the transform would lack the offset used in the cell-centered case;
|
||||
so it would simply be
|
||||
@xyz = (Δ<I>i</I>, Δ<I>j</I>, Δ<I>k</I>).
|
||||
@code
|
||||
// -- Constructing a uniform, vertex-centered transform --
|
||||
|
||||
// The grid spacing
|
||||
const double delta = 0.1;
|
||||
|
||||
// A linear transform with the correct spacing
|
||||
openvdb::math::Transform::Ptr transform =
|
||||
openvdb::math:::Transform::createLinearTransform(delta);
|
||||
@endcode
|
||||
|
||||
@subsection sVoxels Voxel Interpretations
|
||||
A similar and often related concept to cell- and vertex-centered
|
||||
partitioning of world space is the idea of a voxel.
|
||||
A voxel historically refers to the volumetric equivalent of a pixel
|
||||
and as such implies a small region of world space.
|
||||
A voxel could, for instance, be the image under transform of a vertex-centered
|
||||
(or cell-centered) box in index space.
|
||||
In this way the voxel can be seen as a generalization of regular grid cells.
|
||||
The interpretation of data stored in a grid can be related to the concept
|
||||
of a voxel but need not be.
|
||||
An application might interpret the grid value indexed by @ijk as the
|
||||
spatial average of a quantity in a defined world-space voxel centered
|
||||
on the image of that lattice point.
|
||||
But in other situations the value stored at @ijk might be a discrete sample
|
||||
taken from a single point in world space.
|
||||
|
||||
The @vdblink::math::Transform Transform@endlink class does include
|
||||
methods such as @vdblink::math::Transform::voxelSize() voxelSize@endlink
|
||||
and @vdblink::math::Transform::voxelVolume() voxelVolume@endlink that suppose
|
||||
a particular interpretation of a voxel.
|
||||
They assume a voxel that is the image of a vertex-centered cube in index space,
|
||||
so the @b voxelSize methods return the lengths of line segments in world space
|
||||
that connect vertices:
|
||||
@code
|
||||
openvdb::Coord ijk(0,0,0);
|
||||
openvdb::Coord tmp0(1,0,0), tmp1(0,1,0), tmp2(0,0,1);
|
||||
|
||||
openvdb::math::Vec3d size;
|
||||
size.x() = (xform.indexToWorld(ijk + tmp0) - xform.indexToWorld(ijk)).length();
|
||||
size.y() = (xform.indexToWorld(ijk + tmp1) - xform.indexToWorld(ijk)).length();
|
||||
size.z() = (xform.indexToWorld(ijk + tmp2) - xform.indexToWorld(ijk)).length();
|
||||
|
||||
// The voxelSize() for the voxel at (0,0,0) is consistent with
|
||||
// the computation above.
|
||||
assert(xform.voxelSize(ijk) == size);
|
||||
@endcode
|
||||
In the case where the transform is linear, the result of @b voxelSize
|
||||
will be independent of the actual location @ijk, but the voxel size for a
|
||||
nonlinear transform such as a frustum will be spatially varying.
|
||||
The related @b voxelVolume can not in general be computed from the
|
||||
@b voxelSize, because there is no guarantee that a general transform
|
||||
will convert a cube-shaped voxel into another cube.
|
||||
As a result, @b voxelVolume actually returns the determinant of the
|
||||
transform, which will be a correct measure of volume even if the voxel
|
||||
is sheared into a general parallelepiped.
|
||||
|
||||
@subsection sStaggered Staggered Velocity Grids
|
||||
Staggered velocity data is often used in fluid simulations, and the
|
||||
relationship between data interpretation and transforms is
|
||||
somewhat peculiar when using a vector grid to hold
|
||||
staggered velocity data.
|
||||
In this case the lattice point @ijk identifies a cell in world space
|
||||
by mapping to the cell’s center, but each element of the velocity
|
||||
vector is identified with a different face of the cell.
|
||||
The first element of the vector is identified with the image of the
|
||||
(<I>i</I>−1/2, <I>j</I>, <I>k</I>) face, the second element
|
||||
with (<I>i</I>, <I>j</I>−1/2, <I>k</I>), and
|
||||
the third element with (<I>i</I>, <I>j</I>, <I>k</I>−1/2).
|
||||
|
||||
|
||||
@section sMaps Maps in OpenVDB Transforms
|
||||
The actual work of a @vdblink::math::Transform Transform@endlink is performed
|
||||
by an implementation object called a @vdblink::math::MapBase Map@endlink.
|
||||
The @b Map in turn is a polymorphic object whose derived types are designed to
|
||||
optimally represent the most common transformations.
|
||||
Specifically, the @vdblink::math::Transform Transform@endlink holds a
|
||||
@vdblink::math::MapBase MapBase@endlink pointer to a derived type that
|
||||
has been simplified to minimize calculations.
|
||||
When the transform is updated by prepending or appending a linear operation
|
||||
(e.g., with @vdblink::math::Transform::preRotate() preRotate@endlink),
|
||||
the implementation map is recomputed and simplified if possible.
|
||||
For example, in many level-set-oriented applications the transform between
|
||||
index space and world space is simply a uniform scaling of the index points,
|
||||
i.e., @xyz = (Δ<I>i</I>, Δ<I>j</I>, Δ<I>k</I>),
|
||||
where Δ has some world space units.
|
||||
For transforms such as this, the implementation is a
|
||||
@vdblink::math::UniformScaleMap UniformScaleMap@endlink.
|
||||
@code
|
||||
// Create a linear transform that scales i, j and k by 0.1
|
||||
openvdb::math::Transform::Ptr linearTransform =
|
||||
openvdb::math::Transform::createLinearTransform(0.1);
|
||||
|
||||
// Create an equivalent map.
|
||||
openvdb::math::UniformScaleMap uniformScale(0.1);
|
||||
|
||||
// At this time the map holds a openvdb::math::UniformScaleMap.
|
||||
assert(linearTransform->mapType() == openvdb::math::UniformScaleMap::type());
|
||||
|
||||
openvdb::Coord ijk(1,2,3);
|
||||
|
||||
// Applying the transform...
|
||||
openvdb::math::Vec3d transformResult = linearTransform->indexToWorld(ijk);
|
||||
|
||||
// ...is equivalent to applying the map.
|
||||
openvdb::math::Vec3d mapResult = uniformScale.applyMap(ijk);
|
||||
|
||||
assert(mapResult == transformResult);
|
||||
@endcode
|
||||
|
||||
There are specialized maps for a variety of common linear transforms:
|
||||
pure translation (@vdblink::math::TranslationMap TranslationMap@endlink),
|
||||
uniform scale (@vdblink::math::UniformScaleMap UniformScaleMap@endlink),
|
||||
uniform scale and translation
|
||||
(@vdblink::math::UniformScaleTranslateMap UniformScaleTranslateMap@endlink),
|
||||
non-uniform scale (@vdblink::math::ScaleMap ScaleMap@endlink), and
|
||||
non-uniform scale and translation
|
||||
(@vdblink::math::ScaleTranslateMap ScaleTranslateMap@endlink).
|
||||
A general affine map (@vdblink::math::AffineMap AffineMap@endlink) is used
|
||||
for all other cases (those that include non-degenerate rotation or shear).
|
||||
|
||||
@subsection sGettingMat4 An Equivalent Matrix Representation
|
||||
The matrix representation used within OpenVDB adheres to the minority
|
||||
convention of right-multiplication of the matrix against a vector:
|
||||
@code
|
||||
// Example matrix transform that scales, next translates,
|
||||
// and finally rotates an incoming vector
|
||||
openvdb::math::Mat4d transform = openvdb::math::Mat4d::identity();
|
||||
transform.preScale(openvdb::math::Vec3d(2,3,2));
|
||||
transform.postTranslate(openvdb::math::Vec3d(1,0,0));
|
||||
transform.postRotate(openvdb::math::X_AXIS, M_PI/3.0);
|
||||
|
||||
// Location of a point in index space
|
||||
openvdb::math::Vec3d indexSpace(1,2,3);
|
||||
|
||||
// Apply the transform by right-multiplying the matrix.
|
||||
openvdb::math::Vec3d worldSpace = indexSpace * transform;
|
||||
@endcode
|
||||
Any linear map can produce an equivalent
|
||||
@vdblink::math::AffineMap AffineMap@endlink, which in turn can produce
|
||||
an equivalent 4×4 matrix.
|
||||
Starting with a linear transform one can produce a consistent matrix as follows:
|
||||
@code
|
||||
openvdb::math::Mat4d matrix;
|
||||
if (transform->isLinear()) {
|
||||
// Get the equivalent 4x4 matrix.
|
||||
matrix = transform->getBaseMap()->getAffineMap()->getMat4();
|
||||
}
|
||||
@endcode
|
||||
|
||||
This could be used as an intermediate form when constructing new linear
|
||||
transforms by combining old ones.
|
||||
@code
|
||||
// Get the matrix equivalent to linearTransformA.
|
||||
openvdb::math::Mat4d matrixA =
|
||||
linearTransformA->getBaseMap()->getAffineMap()->getMat4();
|
||||
|
||||
// Invert the matrix equivalent to linearTransformB.
|
||||
openvdb::math::Mat4d matrixBinv =
|
||||
(linearTransformB->getBaseMap()->getAffineMap()->getMat4()).inverse();
|
||||
|
||||
// Create a new transform that maps the index space of linearTransformA
|
||||
// to the index space of linearTransformB.
|
||||
openvdb::math::Transform::Ptr linearTransformAtoB =
|
||||
openvdb::math::Trasform::createLinearTransform(matrixA * matrixBinv);
|
||||
@endcode
|
||||
Notice that in the above example, the internal representation used by
|
||||
the transform will be simplified if possible to use one of the various
|
||||
map types.
|
||||
|
||||
@subsection sCostOfMaps Working Directly with Maps
|
||||
Accessing a transform’s map through virtual function calls
|
||||
introduces some overhead and precludes compile-time optimizations
|
||||
such as inlining.
|
||||
For this reason, the more computationally intensive OpenVDB tools are
|
||||
templated to work directly with any underlying map.
|
||||
This allows the tools direct access to the map’s simplified
|
||||
representation and gives the compiler a free hand to inline.
|
||||
|
||||
Maps themselves know nothing of index space and world space, but are
|
||||
simply functions <I>x</I><SUB><I>range</I></SUB> =
|
||||
<I>f</I>(<I>x</I><SUB><I>domain</I></SUB>) that map 3-vectors from
|
||||
one space (the domain) to another (the range), or from the range back to
|
||||
the domain (<I>x</I><SUB><I>domain</I></SUB> =
|
||||
<I>f</I><SUP>−1</SUP>(<I>x</I><SUB><I>range</I></SUB>)), by means of
|
||||
the methods @vdblink::math::MapBase::applyMap() applyMap@endlink and
|
||||
@vdblink::math::MapBase::applyInverseMap() applyInverseMap@endlink.
|
||||
|
||||
@code
|
||||
// Create a simple uniform scale map that scales by 10.
|
||||
openvdb::math::UniformScaleMap usm(10.0);
|
||||
|
||||
// A point in the domain
|
||||
openvdb::math::Vec3d domainPoint(0,1,3);
|
||||
|
||||
// The resulting range point
|
||||
openvdb::math::Vec3d rangePoint = usm.applyMap(domainPoint);
|
||||
|
||||
// The map is inverted thus:
|
||||
assert(domainPoint == usm.applyInverseMap(rangePoint));
|
||||
@endcode
|
||||
|
||||
In many tools, the actual map type is not known a priori and
|
||||
must be deduced at runtime prior to calling the appropriate
|
||||
map-specific or map-templated code. The type of map currently being
|
||||
used by a transform can be determined using the
|
||||
@vdblink::math::Transform::mapType() mapType@endlink method:
|
||||
@code
|
||||
// Test for a uniform scale map.
|
||||
if (transform->mapType() == openvdb::math::UniformScaleMap::type()) {
|
||||
|
||||
// This call would return a null pointer in the case of a map type mismatch.
|
||||
openvdb::math::UniformScaleMap::ConstPtr usm =
|
||||
transform->map<openvdb::math::UniformScaleMap>();
|
||||
|
||||
// Call a function that accepts UniformScaleMaps.
|
||||
dofoo(*usm)
|
||||
}
|
||||
@endcode
|
||||
|
||||
To simplify this process, the function
|
||||
@vdblink::math::processTypedMap processTypedMap@endlink has been provided.
|
||||
It accepts a transform and a functor templated on the map type.
|
||||
|
||||
@subsection sGradientAndMaps Maps and Mathematical Operations
|
||||
In addition to supporting the mapping of a point from one space to another,
|
||||
maps also support mapping of local gradients.
|
||||
This results from use of the chain rule of calculus in computing the
|
||||
Jacobian of the map.
|
||||
Essentially, the gradient calculated in the domain of a map can be converted
|
||||
to the gradient in the range of the map, allowing one to compute a gradient
|
||||
in index space and then transform it to a gradient in world space.
|
||||
@code
|
||||
// Compute the gradient at a point in index space in a
|
||||
// floating-point grid using the second-order central difference.
|
||||
openvdb::FloatGrid grid = ...;
|
||||
openvdb::Coord ijk(2,3,5)
|
||||
openvdb::math::Vec3d isGrad =
|
||||
openvdb::math::ISGradient<CD_2D>::result(grid, ijk);
|
||||
|
||||
// Apply the inverse Jacobian transform to convert the result to the
|
||||
// gradient in the world space defined by a map that scales index space
|
||||
// to create voxels of size 0.1 x 0.2 x 0.1
|
||||
openvdb::math::ScaleMap scalemap(0.1, 0.2, 0.1);
|
||||
openvdb::math::Vec3d wsGrad = scalemap.applyIJT(isGrad);
|
||||
@endcode
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,37 @@
|
||||
# FAQ {#NanoVDB_FAQ}
|
||||
|
||||
* **What is NanoVDB?**
|
||||
|
||||
As the name indicates it's a mini-version of the much bigger OpenVDB library, both in terms of functionality and scope. In fact, a stand-alone C++11 implementation of NanoVDB is available in the file [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) and the C99 equivalent in the files [CNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/CNanoVDB.h), and [PNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/PNanoVDB.h). However, NanoVDB offers one major advantage over OpenVDB, namely support for GPUs. In short, NanoVDB is a standalone static-topology implementation of the well-known sparse volumetric VDB data structure. In other words, while values can be modified in a NanoVDB grid its tree topology cannot.
|
||||
|
||||
**What graphics API does NanoVDB support?**
|
||||
|
||||
We have tested NanoVDB with CUDA, OpenCL, OpenGL, DirectX 12, OptiX, Vulkan, HLSL, and GLSL. We are also working on adding support for WebGL.
|
||||
|
||||
* **What are the advantages of NanoVDB?**
|
||||
|
||||
Other then the fact that it runs on the GPU, NanoVDB offers several other advantages over OpenVDB. For its limited applications it's generally faster, uses slightly less memory, is implemented in few header files, and has virtually no dependencies on external libraries (other then C++11 or C99). While NanoVDB inherits most of the memory and data access advantages of OpenVDB (e.g. fast random-access by means of inverse tree-traversal), the improved memory layout of NanoVDB actually results in faster read access performance.
|
||||
|
||||
* **What are the limitations of NanoVDB?**
|
||||
|
||||
Other than the fact that NanoVDB obviously lacks many of the features and tools of OpenVDB, the most important limitation of NanoVDB is the fact that it *assumes the topology of the tree structure to be static*. Thus, it is possible to modify the values in a NanoVDB grid, but not its topology, e.g. see [modify_nanovdb_thrust.cu](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_modify_nanovdb_thrust/modify_nanovdb_thrust.cu).
|
||||
|
||||
* **Does NanoVDB work on the CPU as well as the GPU?**
|
||||
|
||||
Yes! In fact, it provides performance advantages on the CPU over OpenVDB, primarily due to the defragmented and more cache-friendly memory layout for spatially coherent voxel access.
|
||||
|
||||
* **What is NanoVDB intended for?**
|
||||
|
||||
Rendering (e.g. ray-tracing) on the GPU or CPU, and other applications that require fast random access into a sparse volumetric data structure (e.g. collision detection for cloth simulations or static boundary conditions in fluid simulations). Additionally, since NanoVDB is essentially a slimmed-down version of the core data structure in OpenVDB, NanoVDB also serves as a great tool to learn about the implementation details of VDB, and can even serve as a starting point for your own sparse data structure.
|
||||
|
||||
* **Does NanoVDB depend on and require CUDA?**
|
||||
|
||||
No, NanoVDB is by design agnostic and works with most graphics APIs, e.g. OpenGL, OpenCL, OptiX, CUDA, HLSL, GLSL, DirectX, and even the CPU! The data structure itself (defined in [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) and [PNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/PNanoVDB.h)) only depends on C++11 or C99. However, some of the auxiliary math classes are optionally optimized with intrinsic CUDA calls (e.g. fma in Vec3) and some of the [Allocator](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/CudaDeviceBuffer.h) uses CUDA for explicit memory management. It should be straightforward to replace (or remove) these CUDA dependencies if you so desire.
|
||||
|
||||
* **How does the data structure of NanoVDB compare to that of OpenVDB?**
|
||||
|
||||
Conceptually they are essentially identical (NanoVDB uses the exact same tree configuration), but there are some implementation differences to minimize dependencies on external libraries in NanoVDB (e.g. no boost and std containers), and more importantly, NanoVDB has additional meta-data encoded in tree nodes specifically to accelerate ray-tracing (e.g. min/max values and AABB of active values). Also, NanoVDB is pointer-less and occupies a contiguous block of memory, i.e. de-fragmentized relative to OpenVDB. Effectively, NanoVDB is a linearized version of the well-known OpenVDB data structure with a few additional information baked into the tree nodes!
|
||||
|
||||
* **Are there known issues with NanoVDB?**
|
||||
|
||||
While the are currently no known bugs, there are certainly lots of room for improvements and enhancements. If you have issues or ideas for new feature in NanoVDB please let us know, e.g by submitting a [Github issue](https://github.com/AcademySoftwareFoundation/openvdb/issues).
|
||||
@@ -0,0 +1,154 @@
|
||||
# NanoVDB Hello World Examples {#NanoVDB_HelloWorld}
|
||||
|
||||
[The first example](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_openvdb_to_nanovdb_accessor/openvdb_to_nanovdb_accessor.cc) shows how to convert an OpenVDB level set sphere into a NanoVDB level set, use accessors to print out multiple values from both grids, and save the NanoVDB grid to file. Note that **this example depends on both OpenVDB and NanoVDB**.
|
||||
|
||||
```cpp
|
||||
#include <openvdb/tools/LevelSetSphere.h> // replace with your own dependencies for generating the OpenVDB grid
|
||||
#include <nanovdb/util/OpenToNanoVDB.h> // converter from OpenVDB to NanoVDB (includes NanoVDB.h and GridManager.h)
|
||||
#include <nanovdb/util/IO.h>
|
||||
|
||||
// Convert an openvdb level set sphere into a nanovdb, use accessors to print out multiple values from both
|
||||
// grids and save the NanoVDB grid to file.
|
||||
// Note, main depends on BOTH OpenVDB and NanoVDB.
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
// Create an OpenVDB grid (here a level set surface but replace this with your own code)
|
||||
auto srcGrid = openvdb::tools::createLevelSetSphere<openvdb::FloatGrid>(100.0f, openvdb::Vec3f(0.0f), 1.0f);
|
||||
|
||||
// Convert the OpenVDB grid, srcGrid, into a NanoVDB grid handle.
|
||||
auto handle = nanovdb::openToNanoVDB(*srcGrid);
|
||||
|
||||
// Define a (raw) pointer to the NanoVDB grid on the host. Note we match the value type of the srcGrid!
|
||||
auto* dstGrid = handle.grid<float>();
|
||||
|
||||
if (!dstGrid)
|
||||
throw std::runtime_error("GridHandle does not contain a grid with value type float");
|
||||
|
||||
// Get accessors for the two grids. Note that accessors only accelerate repeated access!
|
||||
auto dstAcc = dstGrid->getAccessor();
|
||||
auto srcAcc = srcGrid->getAccessor();
|
||||
|
||||
// Access and print out a cross-section of the narrow-band level set from the two grids
|
||||
for (int i = 97; i < 104; ++i) {
|
||||
printf("(%3i,0,0) OpenVDB cpu: % -4.2f, NanoVDB cpu: % -4.2f\n", i, srcAcc.getValue(openvdb::Coord(i, 0, 0)), dstAcc.getValue(nanovdb::Coord(i, 0, 0)));
|
||||
}
|
||||
|
||||
nanovdb::io::writeGrid("data/sphere.nvdb", handle); // Write the NanoVDB grid to file and throw if writing fails
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
[The second example](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor/read_nanovdb_sphere_accessor.cc) reads a NanoVDB grid from a file (the one saved in the previous example) and prints out multiple values. Note that **this example does not depend on OpenVDB (nor CUDA), only NanoVDB**.
|
||||
|
||||
```cpp
|
||||
#include <nanovdb/util/IO.h> // this is required to read (and write) NanoVDB files on the host
|
||||
|
||||
/// @brief Read a NanoVDB grid from a file and print out multiple values.
|
||||
///
|
||||
/// @note Note This example does NOT depend on OpenVDB (nor CUDA), only NanoVDB.
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
auto handle = nanovdb::io::readGrid("data/sphere.nvdb"); // reads first grid from file
|
||||
|
||||
auto* grid = handle.grid<float>(); // get a (raw) pointer to a NanoVDB grid of value type float
|
||||
|
||||
if (!grid)
|
||||
throw std::runtime_error("File did not contain a grid with value type float");
|
||||
|
||||
auto acc = grid->getAccessor(); // create an accessor for fast access to multiple values
|
||||
for (int i = 97; i < 104; ++i) {
|
||||
printf("(%3i,0,0) NanoVDB cpu: % -4.2f\n", i, acc.getValue(nanovdb::Coord(i, 0, 0)));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
[The third example](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor_cuda/read_nanovdb_sphere_accessor_cuda.cc) reads a NanoVDB grid from a file (the one saved in the first example) and prints out multiple values on both the CPU and GPU. Note that **this example does NOT depend on OpenVDB, only NanoVDB and CUDA**.
|
||||
|
||||
```cpp
|
||||
#include <nanovdb/util/IO.h> // this is required to read (and write) NanoVDB files on the host
|
||||
#include <nanovdb/DefaultCudaAllocator.h> // required for CUDA memory management
|
||||
|
||||
extern "C" void launch_kernels(const nanovdb::NanoGrid<float>*,
|
||||
const nanovdb::NanoGrid<float>*,
|
||||
cudaStream_t stream);
|
||||
|
||||
/// @brief Read a NanoVDB grid from a file and print out multiple values on both the cpu and gpu.
|
||||
///
|
||||
/// @note Note This example does NOT depend on OpenVDB, only NanoVDB and CUDA.
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
// returns a GridHandle using CUDA for memory management.
|
||||
auto handle = nanovdb::io::readGrid<nanovdb::CudaDeviceBuffer>("data/sphere.nvdb");
|
||||
|
||||
cudaStream_t stream; // Create a CUDA stream to allow for asynchronous copy of pinned CUDA memory.
|
||||
cudaStreamCreate(&stream);
|
||||
|
||||
handle.deviceUpload(stream, false); // Copy the NanoVDB grid to the GPU asynchronously
|
||||
|
||||
auto* cpuGrid = handle.grid<float>(); // get a (raw) pointer to a NanoVDB grid of value type float on the CPU
|
||||
auto* deviceGrid = handle.deviceGrid<float>(); // get a (raw) pointer to a NanoVDB grid of value type float on the GPU
|
||||
|
||||
if (!deviceGrid || !cpuGrid)
|
||||
throw std::runtime_error("GridHandle did not contain a grid with value type float");
|
||||
|
||||
launch_kernels(deviceGrid, cpuGrid, stream); // Call a host method to print a grid values on both the CPU and GPU
|
||||
|
||||
cudaStreamDestroy(stream); // Destroy the CUDA stream
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
NVCC requires the CUDA kernel to be defined in [a separate .cu file](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/examples/ex_read_nanovdb_sphere_accessor_cuda/read_nanovdb_sphere_accessor_cuda.cu):
|
||||
|
||||
```cpp
|
||||
#include <nanovdb/NanoVDB.h> // this defined the core tree data structure of NanoVDB accessible on both the host and device
|
||||
#include <stdio.h> // for printf
|
||||
|
||||
// This is called by the host only
|
||||
void cpu_kernel(const nanovdb::NanoGrid<float>* cpuGrid)
|
||||
{
|
||||
auto cpuAcc = cpuGrid->getAccessor();
|
||||
for (int i = 97; i < 104; ++i) {
|
||||
printf("(%3i,0,0) NanoVDB cpu: % -4.2f\n", i, cpuAcc.getValue(nanovdb::Coord(i, 0, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
// This is called by the device only
|
||||
__global__ void gpu_kernel(const nanovdb::NanoGrid<float>* deviceGrid)
|
||||
{
|
||||
if (threadIdx.x > 6)
|
||||
return;
|
||||
int i = 97 + threadIdx.x;
|
||||
auto gpuAcc = deviceGrid->getAccessor();
|
||||
printf("(%3i,0,0) NanoVDB gpu: % -4.2f\n", i, gpuAcc.getValue(nanovdb::Coord(i, 0, 0)));
|
||||
}
|
||||
|
||||
// This is called by the client code on the host
|
||||
extern "C" void launch_kernels(const nanovdb::NanoGrid<float>* deviceGrid,
|
||||
const nanovdb::NanoGrid<float>* cpuGrid,
|
||||
cudaStream_t stream)
|
||||
{
|
||||
// Launch the device kernel asynchronously
|
||||
gpu_kernel<<<1, 64, 0, stream>>>(deviceGrid);
|
||||
|
||||
// Launch the host "kernel" (synchronously)
|
||||
cpu_kernel(cpuGrid);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
# Build instructions {#NanoVDB_HowToBuild}
|
||||
|
||||
Note that NanoVDB can be built in many different ways, in the sense that its many external dependencies are optional. This includes OpenVDB, TBB, graphics APIs like CUDA, OpenGL, and OpenCL, as well as compression like ZLIB and BLOSC.
|
||||
However, since the core data structure in [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) is self-contained, client code may only depend on this single header file.
|
||||
|
||||
Also, note that if the environment variable `VDB_DATA_PATH` is set to a directory containing the OpenVDB files from [the OpenVDB web site](http://www.openvdb.org/download), they will be used for the unit and the benchmark tests. Else a simple narrow-band level set sphere is used. Set the environment variable `VDB_SCRATCH_PATH` to define the path to where images generated in the benchmark tests are stored (defaults to the build directory).
|
||||
|
||||
[//]: # (TODO: add back OPTIX, OPENCL, and OPENGL when these options are added back)
|
||||
To explicitly remove a dependency, `X`, add the argument `-DNANOVDB_USE_X=OFF` where `X = {OPENVDB, TBB, BLOSC, ZLIB, CUDA}`. These options are set in the [NanoVDB root CMakeLists.txt](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/CMakeLists.txt). The same file also defines options to build NanoVDB examples, benchmarks, unit-tests, and command-line tools. The default values for these options are `OFF`. A user can override each of these options by passing, for example, `-DNANOVDB_BUILD_UNITTESTS=ON` flag while running cmake from the command line.
|
||||
|
||||
To see the compiler arguments add `-DCMAKE_VERBOSE_MAKEFILE=ON`.
|
||||
|
||||
## First example: building NanoVDB and OpenVDB core
|
||||
|
||||
NanoVDB is now a module of the larger OpenVDB project. A user can build both libraries together. This will build the OpenVDB core library, install the NanoVDB header files, and build the NanoVDB command-line tools in the `build/nanovdb/cmd` directory. From the 'root' OpenVDB project directory (change the dependency paths to match your environment):
|
||||
```console
|
||||
foo@bar:~$ mkdir build
|
||||
foo@bar:~$ cd build
|
||||
foo@bar:~$ cmake .. -DUSE_NANOVDB=ON -DTBB_ROOT=/path/to/tbb -DBOOST_ROOT=/path/to/boost -DBLOSC_ROOT=/path/to/blosc -DCMAKE_INSTALL_PREFIX=/install/path
|
||||
foo@bar:~$ make -j 4 && make install
|
||||
```
|
||||
Note that the default value of `NANOVDB_USE_OPENVDB` is linked to `OPENVDB_BUILD_CORE` option and can be overriden by passing on `-DNANOVDB_USE_OPENVDB=OFF`. The `Boost` library is included because it is a requirement for building OpenVDB.
|
||||
|
||||
In general, CMake will try to find every optional dependency when a user opts to add an additional dependency. Be sure to check the CMake log to see what dependencies were **not** found.
|
||||
|
||||
## Second example: NanoVDB with no dependencies
|
||||
|
||||
From the 'root' OpenVDB project directory:
|
||||
```console
|
||||
foo@bar:~$ mkdir build
|
||||
foo@bar:~$ cd build
|
||||
foo@bar:~$ cmake .. -DUSE_NANOVDB=ON -DOPENVDB_BUILD_CORE=OFF -DOPENVDB_BUILD_BINARIES=OFF -DNANOVDB_USE_TBB=OFF -DNANOVDB_USE_BLOSC=OFF -DNANOVDB_USE_ZLIB=OFF -DCMAKE_INSTALL_PREFIX=/install/path
|
||||
foo@bar:~$ make -j 4 && make install
|
||||
```
|
||||
|
||||
Another option is to build it from the NanoVDB directory itself, which is much simpler:
|
||||
```console
|
||||
foo@bar:~$ cd nanovdb/nanovdb
|
||||
foo@bar:~$ mkdir build
|
||||
foo@bar:~$ cd build
|
||||
foo@bar:~$ cmake .. -DCMAKE_INSTALL_PREFIX=/install/path
|
||||
foo@bar:~$ make -j 4 && make install
|
||||
```
|
||||
Both options will install the NanoVDB header files to the `/install/path` as well as building `nanovdb_print` and `nanovdb_validate` executable. The path where these executables are installed will be different: in the first option they will be under `build/nanovdb/cmd` directory; whilst in the second option they will be under the `build/cmd/` directory.
|
||||
|
||||
## Third example: build 'everything' in NanoVDB along with OpenVDB core
|
||||
|
||||
From the root OpenVDB directory:
|
||||
```console
|
||||
foo@bar:~$ mkdir build
|
||||
foo@bar:~$ cd build
|
||||
foo@bar:~$ cmake .. -DUSE_NANOVDB=ON -DNANOVDB_BUILD_UNITTESTS=ON -DNANOVDB_BUILD_EXAMPLES=ON -DNANOVDB_BUILD_BENCHMARK=ON -DNANOVDB_USE_INTRINSICS=ON -DNANOVDB_USE_CUDA=ON -DNANOVDB_CUDA_KEEP_PTX=ON -DTBB_ROOT=/path/to/tbb -DBOOST_ROOT=/path/to/boost -DBLOSC_ROOT=/path/to/blosc -DGTEST_ROOT=/path/to/gtest -DCMAKE_INSTALL_PREFIX=/install/path
|
||||
foo@bar:~$ make -j 4 && make install
|
||||
```
|
||||
Note that if you already have the correct version of OpenVDB pre-installed, you can configure CMake to link against that library by passing the arguments `-DOPENVDB_BUILD_CORE=OFF -DOPENVDB_BUILD_BINARIES=OFF -DOPENVDB_ROOT=/path/to/openvdb` when invoking `cmake`.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Source tree structure {#NanoVDB_SourceTree}
|
||||
|
||||
#### Overview of the directory tree of NanoVDB.
|
||||
|
||||
* [NanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/NanoVDB.h) C++11 implementation of the core data structure and its access methods.
|
||||
* [CNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/CNanoVDB.h) Incomplete but useable C99 implementation of the core data structure and its access methods. Designed in particular for use in OpenCL kernels. Note that this relies on zero-sized arrays for the _reserved padding, so will not work on all compilers (with MSVC being a particular example)
|
||||
* [PNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/PNanoVDB.h) C99 implementation of the core data structure and its access methods. More complete coverage than CNanoVDB. This version is pointer-less and supports virtually all graphics APIs.
|
||||
* [util/GridHandle.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/GridHandle.h) defines a handler for the memory allocated to a NanoVDB grid.
|
||||
* [util/IO.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/IO.h) implements I/O support.
|
||||
* [util/OpenToNanoVDB.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/OpenToNanoVDB.h) defines the converter from OpenVDB to NanoVDB and obviously depends on the OpenVDB library (as the only header file).
|
||||
* [Ray.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/Ray.h) Ray class.
|
||||
* [HDDA.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/HDDA.h) HDDA related.
|
||||
* [SampleFromVoxels.h](https://github.com/AcademySoftwareFoundation/openvdb/blob/master/nanovdb/nanovdb/util/SampleFromVoxels.h) interpolation.
|
||||
|
||||
```bash
|
||||
foo@bar:~$ tree
|
||||
.
|
||||
├── nanovdb
|
||||
│ ├── CNanoVDB.h
|
||||
│ ├── NanoVDB.h
|
||||
│ ├── PNanoVDB.h
|
||||
│ └── util
|
||||
│ ├── CSampleFromVoxels.h
|
||||
│ ├── CudaDeviceBuffer.h
|
||||
| ├── DitherLUT.h
|
||||
│ ├── ForEach.h
|
||||
│ ├── GridBuilder.h
|
||||
│ ├── GridChecksum.h
|
||||
│ ├── GridHandle.h
|
||||
│ ├── GridStats.h
|
||||
│ ├── GridValidator.h
|
||||
│ ├── HDDA.h
|
||||
│ ├── HostBuffer.h
|
||||
│ ├── Invoke.h
|
||||
│ ├── IO.h
|
||||
│ ├── NanoToOpenVDB.h
|
||||
│ ├── OpenToNanoVDB.h
|
||||
| ├── Primitives.h
|
||||
│ ├── Range.h
|
||||
│ ├── Ray.h
|
||||
| ├── Reduce.h
|
||||
| ├── SampleFromVoxels.h
|
||||
| └── Stencils.h
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
# NanoVDB {#NanoVDB_MainPage}
|
||||
|
||||
Welcome to the NanoVDB documentation page.
|
||||
|
||||
* @ref NanoVDB_HowToBuild
|
||||
* @ref NanoVDB_FAQ
|
||||
* @ref NanoVDB_SourceTree
|
||||
* @ref NanoVDB_HelloWorld
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
@page points OpenVDB Points
|
||||
|
||||
|
||||
@section secPtContents Contents
|
||||
- @ref secPtOverview
|
||||
- @ref secPtCompression
|
||||
- @ref secPtLocality
|
||||
- @ref secPtAttributes
|
||||
- @ref secPtTypedAttributeArray
|
||||
- @ref secPtAttributeHandle
|
||||
- @ref secPtAttributePerformance
|
||||
- @ref secPtAttributeSet
|
||||
- @ref secPtPointTree
|
||||
- @ref secPtPointIndexTree
|
||||
- @ref secPtPointDataTree
|
||||
- @ref secPtSparsity
|
||||
- @ref secPtBackground
|
||||
- @ref secPtActiveValues
|
||||
- @ref secPtIndexIterators
|
||||
- @ref secPtIndexFilters
|
||||
- @ref secPtSpaceAndTrans
|
||||
|
||||
|
||||
@section secPtOverview Introduction
|
||||
@anchor openvdbPointsOverview
|
||||
|
||||
The @b OpenVDB library can store point data within an OpenVDB hierarchy in two
|
||||
different ways. A @b PointIndexGrid stores index offsets that reference data
|
||||
stored in an external linear point array, a @b PointDataGrid stores the points
|
||||
with attributes directly in the VDB Grid. This document focuses mainly on the
|
||||
localised style of storage used by @b PointDataGrids. Using this storage
|
||||
mechanism, points are spatially-organised into VDB voxels to provide faster
|
||||
access and a greater opportunity for data compression compared with linear point
|
||||
arrays.
|
||||
|
||||
See the @ref openvdbPointsHelloWorld "Cookbook" for code examples to get started
|
||||
using @b OpenVDB @b Points.
|
||||
|
||||
@section secPtCompression Compression
|
||||
|
||||
A key motivation behind the library is to increase data compression and thus
|
||||
reduce the memory and disk space requirements of the point set.
|
||||
|
||||
There are three types of compression used in this library to store point
|
||||
attribute data - (1) @b value @b compression where the codec is selected
|
||||
specifically based on the intent of the data, (2) @b uniform @b compression
|
||||
where arrays of identical values can be collapsed down into a single value,
|
||||
(3) @b stream @b compression where the Blosc stream compressor can be used to
|
||||
pack and unpack streams of data using a fast, lossless compression codec.
|
||||
|
||||
Uniform and stream compression are offered in other applications, notably
|
||||
Houdini, but with the case of stream compression, used only for disk storage.
|
||||
|
||||
Value compression is provided based on the principal that a good general-purpose
|
||||
compression scheme will usually not be superior to one that is specifically
|
||||
tuned to the range and intention of how the data will be used. The most commonly
|
||||
used style of value compression in OpenVDB Points is quantization for point
|
||||
position data. Floating-point world-space positions will typically use a much
|
||||
higher accuracy than desired around the origin and a much lower accuracy than
|
||||
desired far from the origin, which is as a result of the dynamic range used in
|
||||
floating-point that makes it usable at different orders of magnitude. More
|
||||
tailored position compression is introduced by splitting positions into an
|
||||
integer offset provided by the VDB voxels and grid transform and a reduced
|
||||
precision fixed-point offset from the center of the voxel.
|
||||
|
||||
In addition, other attributes such as velocity can benefit from value
|
||||
compression. For example, a unit vector scheme can compress a 3 x float vector
|
||||
(12 bytes) into just 2 bytes.
|
||||
|
||||
@section secPtLocality Locality
|
||||
|
||||
Data compression isn't the only area to benefit from a spatially organised data
|
||||
set. Due to the effects of L1 and L2 caching in modern CPUs, improved cache
|
||||
locality through storing point data close in memory to their neighbors can bring
|
||||
about a big improvement in performance.
|
||||
|
||||
A number of point rasterization gather-style tests that compared spatially
|
||||
organised data with randomly organised linear data when dereferenced using a
|
||||
spatial acceleration structure consistently resulted in a performance
|
||||
improvement of between 2x and 3x.
|
||||
|
||||
@section secPtAttributes Attributes
|
||||
|
||||
Attribute storage is provided as an independent toolset within the library to
|
||||
allow for use outside of OpenVDB grids.
|
||||
|
||||
@subsection secPtTypedAttributeArray TypedAttributeArray
|
||||
|
||||
The TypedAttributeArray stores array data with a specified value type and
|
||||
compression codec, which form the template signature.
|
||||
|
||||
@code
|
||||
template<typename ValueType, typename Codec>
|
||||
class TypedAttributeArray: public AttributeArray
|
||||
@endcode
|
||||
|
||||
The base AttributeArray class from which the TypedAttributeArray derives is not
|
||||
templated and can be used for all non-typed operations such as serialization.
|
||||
|
||||
Here is an example of floating-point scalar attribute storage using a truncation
|
||||
codec to reduce the footprint from 32-bit to 16-bit:
|
||||
|
||||
@code
|
||||
openvdb::points::TypedAttributeArray<float, openvdb::points::TruncateCodec>
|
||||
@endcode
|
||||
|
||||
@subsection secPtAttributeHandle AttributeHandle
|
||||
|
||||
AttributeHandle and AttributeWriteHandle classes provide access to the array
|
||||
data without requiring knowledge of the codec. This is important as it can allow
|
||||
users to add their own attribute compression schemes without requiring any
|
||||
modification to existing code.
|
||||
|
||||
AttributeHandles provide benefits to memory usage in allowing data to be packed
|
||||
and unpacked efficiently when using stream compression. When compressed with a
|
||||
stream compression scheme, the AttributeHandle unpacks attribute data into a
|
||||
local (uncompressed) buffer on access and discards this temporary data once the
|
||||
AttributeHandle is destroyed. This has the benefit of retaining the stream
|
||||
compression during access which lowers the peak memory substantially.
|
||||
|
||||
This is how to create a float AttributeHandle bound to a specific attribute in
|
||||
a leaf:
|
||||
|
||||
@code
|
||||
auto handle = AttributeHandle<float>::create(leaf->constAttributeArray("attribute_name"));
|
||||
@endcode
|
||||
|
||||
Note that ensuring const access to the attribute array will prevent redundant
|
||||
copying when using a read-only handle.
|
||||
|
||||
@subsection secPtAttributePerformance TypedAttributeArray vs AttributeHandle
|
||||
|
||||
One key benefit of AttributeHandles is that they ensure the data being accessed
|
||||
has been uncompressed and is in-core on creation of the handle to avoid the need
|
||||
to perform these checks when the data is being accessed and modified for
|
||||
improved performance. An AttributeHandle may also be provided a specific codec
|
||||
if known to eliminate the indirection cost.
|
||||
|
||||
@subsection secPtAttributeSet AttributeSet and Descriptor
|
||||
|
||||
The AttributeSet stores a collection of attribute arrays along with a Descriptor
|
||||
that tracks the type of each of the attribute arrays.
|
||||
|
||||
In typical use cases, the Descriptor is shared amongst leaf nodes with many of
|
||||
the algorithms making this assumption for performance reasons. However, it is
|
||||
still possible to configure the data so that leaf nodes in the same grid can use
|
||||
different Descriptors with different numbers and types of attributes. A typical
|
||||
use-case for this might be to reduce precision of an attribute further from a
|
||||
camera where accuracy is deemed less important and can be traded for a reduced
|
||||
memory or disk footprint.
|
||||
|
||||
@section secPtPointTree The Point Tree
|
||||
|
||||
@subsection secPtPointIndexTree Point Index Tree
|
||||
|
||||
As mentioned in the introduction, the PointIndexTree is a structure in OpenVDB
|
||||
that stores an array of offset indices to a linear point array in the leaf
|
||||
nodes. In constrast, the PointDataTree stores the actual data localised in the
|
||||
leaf nodes.
|
||||
|
||||
The PointIndexTree has this tree configuration:
|
||||
|
||||
@code
|
||||
typedef tree::Tree4<PointIdx32, 5, 4, 3>::Type PointIndexTree;
|
||||
@endcode
|
||||
|
||||
@subsection secPtPointDataTree Point Data Tree
|
||||
|
||||
The PointDataTree has this tree configuration:
|
||||
|
||||
@code
|
||||
typedef tree::Tree4<PointDataIdx32, 5, 4, 3>::Type PointDataTree;
|
||||
@endcode
|
||||
|
||||
Note that with both the PointIndexTree and the PointDataTree, the data type is
|
||||
actually a 32-bit unsigned integer, but it is provided in this form to
|
||||
distinguish it from other LeafNodes that store the same data type. None of the
|
||||
other components within the Tree or Grid hierarchy change. It is for this reason
|
||||
that many of the existing features of OpenVDB such as serialization work without
|
||||
requiring additional functionality in OpenVDB.
|
||||
|
||||
@section secPtSparsity Voxel Values
|
||||
|
||||
For the PointDataTree, the voxel values represent the end position in the linear
|
||||
attribute arrays attached to each LeafNode. Using the value of the previous
|
||||
voxel (zero for the first voxel), the offset for the start position can be
|
||||
deduced.
|
||||
|
||||
@subsection secPtBackground Background and Tile Values
|
||||
|
||||
There are three distinct ways of storing data in an OpenVDB tree:
|
||||
<B>voxel values</B>, <B>tile values</B>, and a <B>background value</B>.
|
||||
Unfortunately the background value and tile values make little sense for point
|
||||
data. While technically it would be valid to use a non-zero background value and
|
||||
tile value, this would simply mean that only the first voxel in the LeafNode
|
||||
contains points which is neither an efficient storage mechanism nor particularly
|
||||
common. For this reason, the LeafNode constructor may take a background value
|
||||
but it is internally overriden to be zero on construction.
|
||||
|
||||
@subsection secPtActiveValues Active Values
|
||||
|
||||
Any voxel or tile can be classified as either @b active or @b inactive. The
|
||||
interpretation of this state is application-specific, however there are some
|
||||
conventions, such as using the active state to denote the narrow band in a
|
||||
levelset. For points, the most intuitive use of the active state is to mark a
|
||||
voxel as active if it contains points and inactive otherwise. This allows
|
||||
iteration over the points in a LeafNode to be accelerated to only iterate over
|
||||
voxels that contain points.
|
||||
|
||||
@subsection secPtIndexIterators Index Iterators
|
||||
@anchor openvdbPointsIterators
|
||||
|
||||
An index iterator contains a value iterator and an index filter, however the
|
||||
most common usage is provided by the convenience methods on the leaf node:
|
||||
|
||||
@code
|
||||
auto iterAll = leaf.beginIndexAll();
|
||||
auto iterOn = leaf.beginIndexOn();
|
||||
auto iterOff = leaf.beginIndexOff();
|
||||
|
||||
for (; iterOn; ++iterOn) {
|
||||
Index32 index = *iterOn;
|
||||
}
|
||||
@endcode
|
||||
|
||||
These are analagous to the value iterators in the LeafNode and are creating an
|
||||
index iterator that wraps the value iterator together with a null filter.
|
||||
|
||||
It is also possible to iterate over indices within a specific voxel by using the
|
||||
beginIndexVoxel convenience method on the leaf:
|
||||
|
||||
@code
|
||||
auto iterVoxel = leaf.beginIndexVoxel(ijk);
|
||||
@endcode
|
||||
|
||||
For performance and simplicity, it is recommended to use the all/on/off index
|
||||
iterators where possible, as these hide the explicit voxel iteration from the
|
||||
user meaning it is only necessary to iterate over the indices within the leaf.
|
||||
It is also possible to retrieve the voxel coordinate from the index iterator
|
||||
directly.
|
||||
|
||||
@subsection secPtIndexFilters Index Filters
|
||||
|
||||
Index filters provide an easy way of only iterating over indices that match a
|
||||
set criteria. One such index filter provided by the library is to iterate over
|
||||
the points within a group:
|
||||
|
||||
@code
|
||||
openvdb::points::GroupFilter filter("test_point_group");
|
||||
auto iter = leaf.beginIndexOn(filter);
|
||||
@endcode
|
||||
|
||||
As the index iterator is templated on the filter, it's possible to construct
|
||||
filters that do relatively complicated operations provided they meet the basic
|
||||
interface requirements of an IndexFilter.
|
||||
|
||||
@section secPtSpaceAndTrans Voxel Space, Index Space, World Space
|
||||
|
||||
Points are stored in @b voxel @b space, meaning all point positions lie between
|
||||
(-0.5, -0.5, -0.5) and (0.5, 0.5, 0.5) with the center of the voxel being
|
||||
(0.0, 0.0, 0.0). The position of the point can be extracted in @b index @b space
|
||||
by adding the voxel space position to the ijk value of the voxel. The position
|
||||
of the point can be extracted in @b world @b space by using the grid transform
|
||||
to do an indexToWorld conversion.
|
||||
|
||||
See the @ref openvdbPointsHelloWorld "Cookbook" for code examples to get started
|
||||
using @b OpenVDB @b Points.
|
||||
|
||||
*/
|
||||
+652
@@ -0,0 +1,652 @@
|
||||
/**
|
||||
|
||||
@page python Using OpenVDB in Python
|
||||
|
||||
This section describes the OpenVDB Python module and includes Python code
|
||||
snippets and some complete programs that illustrate how to perform common tasks.
|
||||
(An <a href="./python/index.html">API reference</a> is also available,
|
||||
if <a href="http://epydoc.sourceforge.net/">Epydoc</a> is installed.)
|
||||
As of OpenVDB 2.0, the Python module exposes most of the functionality
|
||||
of the C++ @vdblink::Grid Grid@endlink class, including I/O, metadata
|
||||
management, voxel access and iteration, but almost none of the many
|
||||
@ref secToolUtils "tools".
|
||||
We expect to add support for tools in forthcoming releases.
|
||||
|
||||
The Python module supports a fixed set of grid types.
|
||||
If the symbol @c PY_OPENVDB_WRAP_ALL_GRID_TYPES is defined at compile time,
|
||||
most of the grid types declared in openvdb.h are accessible in Python,
|
||||
otherwise only @b FloatGrid, @b BoolGrid and @b Vec3SGrid are accessible.
|
||||
To add support for grids with other value types or configurations,
|
||||
search for @c PY_OPENVDB_WRAP_ALL_GRID_TYPES in the module source code,
|
||||
update the code as appropriate and recompile the module.
|
||||
(It is possible that this process will be streamlined in the future
|
||||
with a plugin mechanism.)
|
||||
Note however that adding grid types can significantly increase the time
|
||||
and memory needed to compile the module and can significantly increase
|
||||
the size of the resulting executable.
|
||||
In addition, grids of custom types that are saved to <tt>.vdb</tt> files
|
||||
or pickled will not be readable by clients using the standard version
|
||||
of the module.
|
||||
|
||||
Also note that the @vdblink::tree::Tree Tree@endlink class is not exposed
|
||||
in Python.
|
||||
Much of its functionality is either available through the
|
||||
@vdblink::Grid Grid@endlink or is too low-level to be generally useful
|
||||
in Python.
|
||||
Although trees are not accessible in Python, they can of course be operated on
|
||||
indirectly.
|
||||
Of note are the grid methods @b copy, which returns a new grid that shares
|
||||
its tree with the original grid, @b deepCopy, which returns a new grid
|
||||
that owns its own tree, and @b sharesWith, which reports whether two grids
|
||||
share a tree.
|
||||
|
||||
|
||||
|
||||
@section sPyContents Contents
|
||||
- @ref sPyBasics
|
||||
- @ref sPyHandlingMetadata
|
||||
- @ref sPyAccessors
|
||||
- @ref sPyIteration
|
||||
- @ref sPyNumPy
|
||||
- @ref sPyMeshConversion
|
||||
- @ref sPyCppAPI
|
||||
|
||||
|
||||
|
||||
@section sPyBasics Getting started
|
||||
|
||||
The following example is a complete program that illustrates some of the
|
||||
basic steps to create grids and write them to disk:
|
||||
@code{.py}
|
||||
import pyopenvdb as vdb
|
||||
|
||||
# A grid comprises a sparse tree representation of voxel data,
|
||||
# user-supplied metadata and a voxel space to world space transform,
|
||||
# which defaults to the identity transform.
|
||||
# A FloatGrid stores one single-precision floating point value per voxel.
|
||||
# Other grid types include BoolGrid and Vec3SGrid. The module-level
|
||||
# attribute pyopenvdb.GridTypes gives the complete list.
|
||||
cube = vdb.FloatGrid()
|
||||
cube.fill(min=(100, 100, 100), max=(199, 199, 199), value=1.0)
|
||||
|
||||
# Name the grid "cube".
|
||||
cube.name = 'cube'
|
||||
|
||||
# Populate another FloatGrid with a sparse, narrow-band level set
|
||||
# representation of a sphere with radius 50 voxels, located at
|
||||
# (1.5, 2, 3) in index space.
|
||||
sphere = vdb.createLevelSetSphere(radius=50, center=(1.5, 2, 3))
|
||||
|
||||
# Associate some metadata with the grid.
|
||||
sphere['radius'] = 50.0
|
||||
|
||||
# Associate a scaling transform with the grid that sets the voxel size
|
||||
# to 0.5 units in world space.
|
||||
sphere.transform = vdb.createLinearTransform(voxelSize=0.5)
|
||||
|
||||
# Name the grid "sphere".
|
||||
sphere.name = 'sphere'
|
||||
|
||||
# Write both grids to a VDB file.
|
||||
vdb.write('mygrids.vdb', grids=[cube, sphere])
|
||||
@endcode
|
||||
|
||||
This example shows how to read grids from files, and some ways to modify
|
||||
grids:
|
||||
@code{.py}
|
||||
import pyopenvdb as vdb
|
||||
|
||||
# Read a .vdb file and return a list of grids populated with
|
||||
# their metadata and transforms, but not their trees.
|
||||
filename = 'mygrids.vdb'
|
||||
grids = vdb.readAllGridMetadata(filename)
|
||||
|
||||
# Look for and read in a level-set grid that has certain metadata.
|
||||
sphere = None
|
||||
for grid in grids:
|
||||
if (grid.gridClass == vdb.GridClass.LEVEL_SET and 'radius' in grid
|
||||
and grid['radius'] > 10.0):
|
||||
sphere = vdb.read(filename, grid.name)
|
||||
else:
|
||||
print 'skipping grid', grid.name
|
||||
|
||||
if sphere:
|
||||
# Convert the level set sphere to a narrow-band fog volume, in which
|
||||
# interior voxels have value 1, exterior voxels have value 0, and
|
||||
# narrow-band voxels have values varying linearly from 0 to 1.
|
||||
|
||||
outside = sphere.background
|
||||
width = 2.0 * outside
|
||||
|
||||
# Visit and update all of the grid's active values, which correspond to
|
||||
# voxels in the narrow band.
|
||||
for iter in sphere.iterOnValues():
|
||||
dist = iter.value
|
||||
iter.value = (outside - dist) / width
|
||||
|
||||
# Visit all of the grid's inactive tile and voxel values and update
|
||||
# the values that correspond to the interior region.
|
||||
for iter in sphere.iterOffValues():
|
||||
if iter.value < 0.0:
|
||||
iter.value = 1.0
|
||||
iter.active = False
|
||||
|
||||
# Set exterior voxels to 0.
|
||||
sphere.background = 0.0
|
||||
|
||||
sphere.gridClass = vdb.GridClass.FOG_VOLUME
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
@section sPyHandlingMetadata Handling metadata
|
||||
|
||||
Metadata of various types (string, bool, int, float, and 2- and 3-element
|
||||
sequences of ints or floats) can be attached both to individual grids
|
||||
and to files on disk, either by supplying a Python dictionary of
|
||||
(name, value) pairs or, in the case of grids, through
|
||||
a dictionary-like interface.
|
||||
|
||||
Add (name, value) metadata pairs to a grid as you would to a dictionary.
|
||||
A new value overwrites an existing value if the name matches an existing name.
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
|
||||
>>> grid = vdb.Vec3SGrid()
|
||||
|
||||
>>> grid['vector'] = 'gradient'
|
||||
>>> grid['radius'] = 50.0
|
||||
>>> grid['center'] = (10, 15, 10)
|
||||
|
||||
>>> grid.metadata
|
||||
{'vector': 'gradient', 'radius': 50.0, 'center': (10, 15, 10)}
|
||||
|
||||
>>> grid['radius']
|
||||
50.0
|
||||
|
||||
>>> 'radius' in grid, 'misc' in grid
|
||||
(True, False)
|
||||
|
||||
# OK to overwrite an existing value with a value of another type:
|
||||
>>> grid['center'] = 0.0
|
||||
|
||||
# A 4-element sequence is not a supported metadata value type:
|
||||
>>> grid['center'] = (0, 0, 0, 0)
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: metadata value "(0, 0, 0, 0)" of type tuple is not allowed
|
||||
|
||||
# Metadata names must be strings:
|
||||
>>> grid[0] = (10.5, 15, 30)
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: expected str, found int as argument 1 to __setitem__()
|
||||
@endcode
|
||||
Alternatively, replace all or some of a grid’s metadata by supplying
|
||||
a (name, value) dictionary:
|
||||
@code{.py}
|
||||
>>> metadata = {
|
||||
... 'vector': 'gradient',
|
||||
... 'radius': 50.0,
|
||||
... 'center': (10, 15, 10)
|
||||
... }
|
||||
|
||||
# Replace all of the grid's metadata.
|
||||
>>> grid.metadata = metadata
|
||||
|
||||
>>> metadata = {
|
||||
... 'center': [10.5, 15, 30],
|
||||
... 'scale': 3.14159
|
||||
... }
|
||||
|
||||
# Overwrite "center" and add "scale":
|
||||
>>> grid.updateMetadata(metadata)
|
||||
@endcode
|
||||
|
||||
Iterate over a grid’s metadata as you would over a dictionary:
|
||||
@code{.py}
|
||||
>>> for key in grid:
|
||||
... print '%s = %s' % (key, grid[key])
|
||||
...
|
||||
vector = gradient
|
||||
radius = 50.0
|
||||
scale = 3.14159
|
||||
center = (10.5, 15.0, 30.0)
|
||||
@endcode
|
||||
|
||||
Removing metadata is also straightforward:
|
||||
@code{.py}
|
||||
>>> del grid['vector']
|
||||
>>> del grid['center']
|
||||
>>> del grid['vector'] # error: already removed
|
||||
File "<stdin>", line 1, in <module>
|
||||
KeyError: 'vector'
|
||||
|
||||
>>> grid.metadata = {} # remove all metadata
|
||||
@endcode
|
||||
|
||||
Some grid metadata is exposed in the form of properties, either because
|
||||
it might be frequently accessed (a grid’s name, for example)
|
||||
or because its allowed values are somehow restricted:
|
||||
@code{.py}
|
||||
>>> grid = vdb.createLevelSetSphere(radius=10.0)
|
||||
>>> grid.metadata
|
||||
{'class': 'level set'}
|
||||
|
||||
>>> grid.gridClass = vdb.GridClass.FOG_VOLUME
|
||||
>>> grid.metadata
|
||||
{'class': 'fog volume'}
|
||||
|
||||
# The gridClass property requires a string value:
|
||||
>>> grid.gridClass = 123
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: expected str, found int as argument 1 to setGridClass()
|
||||
|
||||
# Only certain strings are recognized; see pyopenvdb.GridClass
|
||||
# for the complete list.
|
||||
>>> grid.gridClass = 'Hello, world.'
|
||||
>>> grid.metadata
|
||||
{'class': 'unknown'}
|
||||
|
||||
>>> grid.metadata = {}
|
||||
>>> grid.vectorType = vdb.VectorType.COVARIANT
|
||||
>>> grid.metadata
|
||||
{'vector_type': 'covariant'}
|
||||
|
||||
>>> grid.name = 'sphere'
|
||||
>>> grid.creator = 'Python'
|
||||
>>> grid.metadata
|
||||
{'vector_type': 'covariant', 'name': 'sphere', 'creator': 'Python'}
|
||||
@endcode
|
||||
Setting these properties to @c None removes the corresponding metadata,
|
||||
but the properties retain default values:
|
||||
@code{.py}
|
||||
>>> grid.creator = grid.vectorType = None
|
||||
>>> grid.metadata
|
||||
{'name': 'sphere'}
|
||||
|
||||
>>> grid.creator, grid.vectorType
|
||||
('', 'invariant')
|
||||
@endcode
|
||||
|
||||
Metadata can be associated with a <tt>.vdb</tt> file at the time the file
|
||||
is written, by supplying a (name, value) dictionary
|
||||
as the optional @c metadata argument to the @b write function:
|
||||
@code{.py}
|
||||
>>> metadata = {
|
||||
... 'creator': 'Python',
|
||||
... 'time': '11:05:00'
|
||||
... }
|
||||
>>> vdb.write('mygrids.vdb', grids=grid, metadata=metadata)
|
||||
@endcode
|
||||
File-level metadata can be retrieved with either the @b readMetadata
|
||||
function or the @b readAll function:
|
||||
@code{.py}
|
||||
>>> metadata = vdb.readMetadata('mygrids.vdb')
|
||||
>>> metadata
|
||||
{'creator': 'Python', 'time': '11:05:00'}
|
||||
|
||||
>>> grids, metadata = vdb.readAll('mygrids.vdb')
|
||||
>>> metadata
|
||||
{'creator': 'Python', 'time': '11:05:00'}
|
||||
>>> [grid.name for grid in grids]
|
||||
['sphere']
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
@section sPyAccessors Voxel access
|
||||
|
||||
Grids provide read-only and read/write accessors for voxel lookup via @ijk
|
||||
index coordinates.
|
||||
Accessors store references to their parent grids, so a grid will not
|
||||
be deleted while it has accessors in use.
|
||||
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
|
||||
# Read two grids from a file.
|
||||
>>> grids, metadata = vdb.readAll('smoke2.vdb')
|
||||
>>> [grid.name for grid in grids]
|
||||
['density', 'v']
|
||||
|
||||
# Get read/write accessors to the two grids.
|
||||
>>> dAccessor = grids[0].getAccessor()
|
||||
>>> vAccessor = grids[1].getAccessor()
|
||||
|
||||
>>> ijk = (100, 103, 101)
|
||||
|
||||
>>> dAccessor.probeValue(ijk)
|
||||
(0.17614534497261047, True)
|
||||
# Change the value of a voxel.
|
||||
>>> dAccessor.setValueOn(ijk, 0.125)
|
||||
>>> dAccessor.probeValue(ijk)
|
||||
(0.125, True)
|
||||
|
||||
>>> vAccessor.probeValue(ijk)
|
||||
((-2.90625, 9.84375, 0.84228515625), True)
|
||||
# Change the active state of a voxel.
|
||||
>>> vAccessor.setActiveState(ijk, False)
|
||||
>>> vAccessor.probeValue(ijk)
|
||||
((-2.90625, 9.84375, 0.84228515625), False)
|
||||
|
||||
# Get a read-only accessor to one of the grids.
|
||||
>>> dAccessor = grids[0].getConstAccessor()
|
||||
>>> dAccessor.setActiveState(ijk, False)
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: accessor is read-only
|
||||
|
||||
# Delete the accessors once they are no longer needed,
|
||||
# so that the grids can be garbage-collected.
|
||||
>>> del dAccessor, vAccessor
|
||||
@endcode
|
||||
|
||||
|
||||
|
||||
@section sPyIteration Iteration
|
||||
|
||||
Grids provide read-only and read/write iterators over their values.
|
||||
Iteration is over sequences of value objects (<b>BoolGrid.Value</b>s,
|
||||
<b>FloatGrid.Value</b>s, etc.) that expose properties such as the number
|
||||
of voxels spanned by a value (one, for a voxel value, more than one
|
||||
for a tile value), its coordinates and its active state.
|
||||
Value objects returned by read-only iterators are immutable; those
|
||||
returned by read/write iterators permit assignment to their active state
|
||||
and value properties, which modifies the underlying grid.
|
||||
Value objects store references to their parent grids, so a grid will not
|
||||
be deleted while one of its value objects is in use.
|
||||
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
|
||||
>>> grid = vdb.read('smoke2.vdb', gridname='v')
|
||||
>>> grid.__class__.__name__
|
||||
'Vec3SGrid'
|
||||
|
||||
# Iterate over inactive values and print the coordinates of the first
|
||||
# five voxel values and the bounding boxes of the first five tile values.
|
||||
>>> voxels = tiles = 0
|
||||
... N = 5
|
||||
... for item in grid.citerOffValues(): # read-only iterator
|
||||
... if voxels == N and tiles == N:
|
||||
... break
|
||||
... if item.count == 1:
|
||||
... if voxels < N:
|
||||
... voxels += 1
|
||||
... print 'voxel', item.min
|
||||
... else:
|
||||
... if tiles < N:
|
||||
... tiles += 1
|
||||
... print 'tile', item.min, item.max
|
||||
...
|
||||
tile (0, 0, 0) (7, 7, 7)
|
||||
tile (0, 0, 8) (7, 7, 15)
|
||||
tile (0, 0, 16) (7, 7, 23)
|
||||
tile (0, 0, 24) (7, 7, 31)
|
||||
tile (0, 0, 32) (7, 7, 39)
|
||||
voxel (40, 96, 88)
|
||||
voxel (40, 96, 89)
|
||||
voxel (40, 96, 90)
|
||||
voxel (40, 96, 91)
|
||||
voxel (40, 96, 92)
|
||||
|
||||
# Iterate over and normalize all active values.
|
||||
>>> from math import sqrt
|
||||
>>> for item in grid.iterOnValues(): # read/write iterator
|
||||
... vector = item.value
|
||||
... magnitude = sqrt(sum(x * x for x in vector))
|
||||
... item.value = [x / magnitude for x in vector]
|
||||
...
|
||||
@endcode
|
||||
|
||||
For some operations, it might be more convenient to use one of
|
||||
the grid methods @b mapOn, @b mapOff or @b mapAll.
|
||||
These methods iterate over a grid’s tiles and voxels
|
||||
(active, inactive or both, respectively) and replace each value <i>x</i>
|
||||
with <i>f</i>(<i>x</i>), where <i>f</i> is a callable object.
|
||||
These methods are not multithreaded.
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
>>> from math import sqrt
|
||||
|
||||
>>> grid = vdb.read('smoke2.vdb', gridname='v')
|
||||
|
||||
>>> def normalize(vector):
|
||||
... magnitude = sqrt(sum(x * x for x in vector))
|
||||
... return [x / magnitude for x in vector]
|
||||
...
|
||||
>>> grid.mapOn(normalize)
|
||||
@endcode
|
||||
|
||||
Similarly, the @b combine method iterates over corresponding pairs of values
|
||||
(tile and voxel) of two grids @e A and @e B of the same type
|
||||
(<b>FloatGrid</b>, <b>Vec3SGrid</b>, etc.), replacing values in @e A
|
||||
with <i>f</i>(<i>a</i>, <i>b</i>), where <i>f</i> is a callable object.
|
||||
This operation assumes that index coordinates @ijk in both grids correspond
|
||||
to the same physical, world space location.
|
||||
Also, the operation always leaves grid @e B empty.
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
|
||||
>>> density = vdb.read('smoke2.vdb', gridname='density')
|
||||
>>> density.__class__.__name__
|
||||
'FloatGrid'
|
||||
|
||||
>>> sphere = vdb.createLevelSetSphere(radius=50.0, center=(100, 300, 100))
|
||||
|
||||
>>> density.combine(sphere, lambda a, b: min(a, b))
|
||||
@endcode
|
||||
For now, @b combine operates only on tile and voxel values,
|
||||
not on their active states or other attributes.
|
||||
|
||||
|
||||
|
||||
@section sPyNumPy Working with NumPy arrays
|
||||
|
||||
Large data sets are often handled in Python using
|
||||
<a href="http://www.numpy.org/">NumPy</a>.
|
||||
The OpenVDB Python module can optionally be compiled with NumPy support.
|
||||
With NumPy enabled, the @b copyFromArray and @b copyToArray grid methods
|
||||
can be used to exchange data efficiently between scalar-valued grids
|
||||
and three-dimensional NumPy arrays and between vector-valued grids and
|
||||
four-dimensional NumPy arrays.
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
>>> import numpy
|
||||
|
||||
>>> array = numpy.random.rand(200, 200, 200)
|
||||
>>> array.dtype
|
||||
dtype('float64')
|
||||
|
||||
# Copy values from a three-dimensional array of doubles
|
||||
# into a grid of floats.
|
||||
>>> grid = vdb.FloatGrid()
|
||||
>>> grid.copyFromArray(array)
|
||||
>>> grid.activeVoxelCount() == array.size
|
||||
True
|
||||
>>> grid.evalActiveVoxelBoundingBox()
|
||||
((0, 0, 0), (199, 199, 199))
|
||||
|
||||
# Copy values from a four-dimensional array of ints
|
||||
# into a grid of float vectors.
|
||||
>>> vecarray = numpy.ndarray((60, 70, 80, 3), int)
|
||||
>>> vecarray.fill(42)
|
||||
>>> vecgrid = vdb.Vec3SGrid()
|
||||
>>> vecgrid.copyFromArray(vecarray)
|
||||
>>> vecgrid.activeVoxelCount() == 60 * 70 * 80
|
||||
True
|
||||
>>> vecgrid.evalActiveVoxelBoundingBox()
|
||||
((0, 0, 0), (59, 69, 79))
|
||||
@endcode
|
||||
|
||||
When copying from a NumPy array, values in the array that are equal to
|
||||
the destination grid’s background value (or close to it, if the
|
||||
@c tolerance argument to @b copyFromArray is nonzero) are set to the
|
||||
background value and are marked inactive.
|
||||
All other values are marked active.
|
||||
@code{.py}
|
||||
>>> grid.clear()
|
||||
>>> grid.copyFromArray(array, tolerance=0.2)
|
||||
>>> print '%d%% of copied voxels are active' % (
|
||||
... round(100.0 * grid.activeVoxelCount() / array.size))
|
||||
80% of copied voxels are active
|
||||
@endcode
|
||||
|
||||
The optional @c ijk argument specifies the index coordinates of the voxel
|
||||
in the destination grid into which to start copying values.
|
||||
That is, array index (0, 0, 0) maps to voxel @ijk.
|
||||
@code{.py}
|
||||
>>> grid.clear()
|
||||
>>> grid.copyFromArray(array, ijk=(-1, 2, 3))
|
||||
>>> grid.evalActiveVoxelBoundingBox()
|
||||
((-1, 2, 3), (198, 201, 202))
|
||||
@endcode
|
||||
|
||||
The @b copyToArray method also accepts an @c ijk argument.
|
||||
It specifies the index coordinates of the voxel to be copied to array
|
||||
index (0, 0, 0).
|
||||
@code{.py}
|
||||
>>> grid = vdb.createLevelSetSphere(radius=10.0)
|
||||
>>> array = numpy.ndarray((40, 40, 40), int)
|
||||
>>> array.fill(0)
|
||||
# Copy values from a grid of floats into
|
||||
# a three-dimensional array of ints.
|
||||
>>> grid.copyToArray(array, ijk=(-15, -20, -35))
|
||||
>>> array[15, 20]
|
||||
array([ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 2, 1, 0, -1, -2, -3, -3,
|
||||
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3])
|
||||
@endcode
|
||||
@b copyToArray has no @c tolerance argument, because there is no distinction
|
||||
between active and inactive values in the destination array.
|
||||
|
||||
|
||||
|
||||
@section sPyMeshConversion Mesh conversion
|
||||
|
||||
Also available if the OpenVDB Python module is compiled with NumPy support
|
||||
(see @ref sPyNumPy "above") are grid methods to convert polygonal meshes to
|
||||
level sets (see @vdblink::tools::meshToLevelSet() tools::meshToLevelSet@endlink
|
||||
for some restrictions) and to convert isosurfaces of scalar-valued grids
|
||||
to meshes.
|
||||
@code{.py}
|
||||
>>> import pyopenvdb as vdb
|
||||
>>> import numpy
|
||||
|
||||
>>> grid = vdb.read('bunny.vdb', 'ls_bunny')
|
||||
|
||||
# Convert a volume to a quadrilateral mesh.
|
||||
>>> points, quads = grid.convertToQuads()
|
||||
|
||||
# World-space vertices of the mesh:
|
||||
>>> points
|
||||
array([[-14.05082607, -0.10118673, -0.40250054],
|
||||
[-14.05230808, -0.05570767, -0.45693323],
|
||||
[-14.05613995, -0.0734246 , -0.42150033],
|
||||
...,
|
||||
[ 7.25201273, 13.25417805, 6.45283508],
|
||||
[ 7.25596714, 13.31225586, 6.40827513],
|
||||
[ 7.30518484, 13.21096039, 6.40724468]], dtype=float32)
|
||||
|
||||
# Quadrilateral faces of the mesh, given by
|
||||
# 4-tuples of indices into the vertex list:
|
||||
>>> quads
|
||||
array([[ 5, 2, 1, 4],
|
||||
[ 11, 7, 6, 10],
|
||||
[ 14, 9, 8, 13],
|
||||
...,
|
||||
[1327942, 1327766, 1339685, 1339733],
|
||||
[1339728, 1327921, 1327942, 1339733],
|
||||
[1339733, 1339685, 1339661, 1339728]], dtype=uint32)
|
||||
|
||||
# Convert the mesh back to a (single-precision) volume.
|
||||
# Give the resulting grid the original grid's transform.
|
||||
>>> gridFromQuads = vdb.FloatGrid.createLevelSetFromPolygons(
|
||||
... points, quads=quads, transform=grid.transform)
|
||||
|
||||
|
||||
# Alternatively, mesh a volume adaptively for a lower polygon count.
|
||||
# Adaptive meshing generates both triangular and quadrilateral faces.
|
||||
>>> points, triangles, quads = grid.convertToPolygons(adaptivity=0.5)
|
||||
|
||||
# World-space vertices of the mesh:
|
||||
>>> points
|
||||
array([[-14.02906322, -0.07213751, -0.49265194],
|
||||
[-14.11877823, -0.11127799, -0.17118289],
|
||||
[-13.85006142, -0.08145611, -0.86669081],
|
||||
...,
|
||||
[ 7.31098318, 12.97358608, 6.55133963],
|
||||
[ 7.20240211, 12.80632019, 6.80356836],
|
||||
[ 7.23679161, 13.28100395, 6.45595646]], dtype=float32)
|
||||
|
||||
# Triangular faces of the mesh, given by
|
||||
# triples of indices into the vertex list:
|
||||
>>> triangles
|
||||
array([[ 8, 7, 0],
|
||||
[ 14, 9, 8],
|
||||
[ 14, 11, 9],
|
||||
...,
|
||||
[22794, 22796, 22797],
|
||||
[22784, 22783, 22810],
|
||||
[22796, 22795, 22816]], dtype=uint32)
|
||||
|
||||
# Quadrilateral faces of the mesh, given by
|
||||
# 4-tuples of indices into the vertex list:
|
||||
>>> quads
|
||||
array([[ 4, 3, 6, 5],
|
||||
[ 8, 9, 10, 7],
|
||||
[ 11, 12, 10, 9],
|
||||
...,
|
||||
[23351, 23349, 23341, 23344],
|
||||
[23344, 23117, 23169, 23351],
|
||||
[23169, 23167, 23349, 23351]], dtype=uint32)
|
||||
|
||||
# Convert the mesh to a double-precision volume.
|
||||
>>> doubleGridFromPolys = vdb.DoubleGrid.createLevelSetFromPolygons(
|
||||
... points, triangles, quads, transform=grid.transform)
|
||||
@endcode
|
||||
|
||||
The mesh representation is similar to that of the commonly-used
|
||||
<a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file">
|
||||
Wavefront <tt>.obj</tt></a> file format,
|
||||
except that the vertex array is indexed starting from 0 rather than 1.
|
||||
To output mesh data to a file in <tt>.obj</tt> format, one might do
|
||||
the following:
|
||||
@code{.py}
|
||||
>>> def writeObjFile(filename, points, triangles=[], quads=[]):
|
||||
... f = open(filename, 'w')
|
||||
... # Output vertices.
|
||||
... for xyz in points:
|
||||
... f.write('v %g %g %g\n' % tuple(xyz))
|
||||
... f.write('\n')
|
||||
... # Output faces.
|
||||
... for ijk in triangles:
|
||||
... f.write('f %d %d %d\n' %
|
||||
... (ijk[0]+1, ijk[1]+1, ijk[2]+1)) # offset vertex indices by one
|
||||
... for ijkl in quads:
|
||||
... f.write('f %d %d %d %d\n' %
|
||||
... (ijkl[0]+1, ijkl[1]+1, ijkl[2]+1, ijkl[3]+1))
|
||||
... f.close()
|
||||
...
|
||||
>>> mesh = grid.convertToPolygons(adaptivity=0.8)
|
||||
>>> writeObjFile('bunny.obj', *mesh)
|
||||
@endcode
|
||||
|
||||
|
||||
@section sPyCppAPI C++ glue routines
|
||||
|
||||
Python objects of type @b FloatGrid, @b Vec3SGrid, etc. are backed by
|
||||
C structs that “inherit” from @c PyObject.
|
||||
The OpenVDB Python extension module includes public functions that you can
|
||||
call in your own extension modules to convert between
|
||||
@vdblink::Grid openvdb::Grids@endlink and <tt>PyObject</tt>s.
|
||||
See the pyopenvdb.h reference for a description of these functions
|
||||
and a usage example.
|
||||
|
||||
Your extension module might need to link against the OpenVDB extension module
|
||||
in order to access these functions.
|
||||
On UNIX systems, it might also be necessary to specify the @c RTLD_GLOBAL
|
||||
flag when importing the OpenVDB module, to allow its symbols to be shared
|
||||
across modules.
|
||||
See @b setdlopenflags in the Python @b sys module for one way to do this.
|
||||
|
||||
*/
|
||||
@@ -1,28 +0,0 @@
|
||||
# *ƒ*(VDB)
|
||||
|
||||
## A New Home for ƒVDB
|
||||
|
||||
:warning: The public home for fVDB development is now located in the Academy Software Foundation OpenVDB Github Organization [https://github.com/openvdb](https://github.com/openvdb). :warning:
|
||||
|
||||
All of the code and history for fVDB on the OpenVDB `feature/fvdb` branch has been moved to repositories in the OpenVDB Github Organization. In order to encourage movement to fVDB's new home in the OpenVDB Github Organization, we have removed the code from the head of this branch but the history remains.
|
||||
|
||||
The components of fVDB have been split into the following repositories:
|
||||
|
||||
### [fvdb-core](https://github.com/openvdb/fvdb-core)
|
||||
|
||||
The fvdb-core repository houses the core library and PyTorch extension for ƒVDB. ƒVDB is a framework that provides differentiable, sparse volumetric operators built on top of NanoVDB and enables PyTorch users to utilize the NanoVDB data structure to build powerful and scalable spatial intelligence applications.
|
||||
|
||||
|
||||
### [fvdb-examples](https://github.com/openvdb/fvdb-examples)
|
||||
|
||||
The fvdb-examples repository contains examples of how to use the ƒVDB library to build spatial intelligence networks or pipelines. These are provided as reference for how to implement interesting or well-known methods and networks on top of ƒVDB including examples of pipelines that perform panoptic segmentation and depth reconstruction.
|
||||
|
||||
|
||||
### [fvdb-reality-capture](https://github.com/openvdb/fvdb-reality-capture)
|
||||
|
||||
The fvdb-reality-capture repository contains examples of how to use the ƒVDB library to build reality capture pipelines centered on ƒVDB's 3D Gaussian splatting methods. This repository houses utilities and examples that illustrate how to train and render 3D Gaussian splatting models using ƒVDB as well as interesting methods that build upon the 3D Gaussian scene representation such as meshing.
|
||||
|
||||
|
||||
### [nanovdb-editor](https://github.com/openvdb/nanovdb-editor)
|
||||
|
||||
The nanovdb-editor repository contains a library, python bindings and a standalone GUI application that allows you to view and edit NanoVDB. nanovdb-editor also provides viewer functionality for fVDB.
|
||||
@@ -0,0 +1,273 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CMake Configuration for NanoVDB
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(NanoVDB LANGUAGES C CXX)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
###############################################################################
|
||||
|
||||
message(STATUS "----------------------------------------------------")
|
||||
message(STATUS "--------------- Configuring NanoVDB ----------------")
|
||||
message(STATUS "----------------------------------------------------")
|
||||
|
||||
###############################################################################
|
||||
# add options
|
||||
###############################################################################
|
||||
|
||||
option(NANOVDB_BUILD_TOOLS "Build command-line tools" ON)
|
||||
option(NANOVDB_BUILD_UNITTESTS "Build Unit tests" OFF)
|
||||
option(NANOVDB_BUILD_EXAMPLES "Build examples" OFF)
|
||||
option(NANOVDB_BUILD_BENCHMARK "Build benchmark in examples" OFF)
|
||||
|
||||
option(NANOVDB_USE_INTRINSICS "Build with hardware intrinsics support" OFF)
|
||||
option(NANOVDB_USE_CUDA "Build with CUDA support" OFF)
|
||||
option(NANOVDB_CUDA_KEEP_PTX "Keep CUDA PTX" OFF)
|
||||
|
||||
option(NANOVDB_USE_OPENVDB "Build with OpenVDB support" OFF)
|
||||
option(NANOVDB_USE_BLOSC "Build with BLOSC support" ${USE_BLOSC})
|
||||
option(NANOVDB_USE_ZLIB "Build with ZLIB support" ${USE_ZLIB})
|
||||
option(NANOVDB_USE_TBB "Build with TBB support" ${USE_TBB})
|
||||
option(NANOVDB_USE_MAGICAVOXEL "Build with MagicaVoxel support" OFF)
|
||||
|
||||
option(NANOVDB_ALLOW_FETCHCONTENT
|
||||
"Allow FetchContent to download missing dependencies" OFF)
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
||||
# sanitize user input
|
||||
|
||||
if(NANOVDB_USE_OPENVDB)
|
||||
if(NOT NANOVDB_USE_TBB)
|
||||
message(FATAL_ERROR "Invalid CMake build configuration:
|
||||
NANOVDB_USE_OPENVDB : [ON]
|
||||
NANOVDB_USE_TBB : [OFF]
|
||||
If you are linking NanoVDB against OpenVDB, then you
|
||||
need to use TBB, (i.e. -DNANOVDB_USE_TBB=ON).")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
||||
enable_testing()
|
||||
|
||||
# Add our cmake modules
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../cmake")
|
||||
|
||||
if(UNIX)
|
||||
# For CMake's find Threads module which brings in pthread - This flag
|
||||
# forces the compiler -pthread flag vs -lpthread
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_BUILD_UNITTESTS OR NANOVDB_BUILD_BENCHMARK)
|
||||
find_package(GTest REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
|
||||
# Allow the user to provide CMAKE_CUDA_ARCHITECTURES
|
||||
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
|
||||
set(CMAKE_CUDA_ARCHITECTURES 75)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
enable_language(CUDA)
|
||||
|
||||
set(NANOVDB_CUDA_EXTENDED_LAMBDA "--expt-extended-lambda")
|
||||
if(CUDA_VERSION_MAJOR GREATER_EQUAL 11)
|
||||
set(NANOVDB_CUDA_EXTENDED_LAMBDA "--extended-lambda")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CUDA_FLAGS "${NANOVDB_CUDA_EXTENDED_LAMBDA} -use_fast_math -lineinfo ${CMAKE_CUDA_FLAGS}")
|
||||
|
||||
# workaround for win32 bug when nvcc "--keep" is used.
|
||||
if(WIN32)
|
||||
if(NANOVDB_CUDA_KEEP_PTX)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/Release")
|
||||
set(CMAKE_CUDA_FLAGS_RELEASE
|
||||
" --source-in-ptx --keep ${CMAKE_CUDA_FLAGS_RELEASE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# If a CMAKE_MSVC_RUNTIME_LIBRARY has not been provided and we're building
|
||||
# against openvdb, match the CRT that openvdb has been built against. This
|
||||
# setting is automatically propagated to CXX files but not CUDA sources, so
|
||||
# the VDB_MSVC_RUNTIME_SELECTION variables is used on targets with .cu files
|
||||
if(NOT CMAKE_MSVC_RUNTIME_LIBRARY AND NANOVDB_USE_OPENVDB AND OPENVDB_BUILD_CORE)
|
||||
get_target_property(VDB_MSVC_RUNTIME_SELECTION openvdb MSVC_RUNTIME_LIBRARY)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_OPENVDB)
|
||||
if(NOT OPENVDB_BUILD_CORE AND NOT TARGET OpenVDB::openvdb)
|
||||
find_package(OpenVDB REQUIRED COMPONENTS openvdb)
|
||||
# disable the shared libs that OpenVDB's cmake switches ON.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_TBB AND NOT TARGET TBB::tbb)
|
||||
find_package(TBB REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_BLOSC AND NOT TARGET Blosc::blosc)
|
||||
find_package(Blosc REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_ZLIB AND NOT TARGET ZLIB::ZLIB)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_MAGICAVOXEL)
|
||||
if(NANOVDB_ALLOW_FETCHCONTENT)
|
||||
if(NOT ogt_POPULATED)
|
||||
message(STATUS "Downloading ogt...")
|
||||
|
||||
FetchContent_Declare(
|
||||
ogt
|
||||
GIT_REPOSITORY https://github.com/jpaver/opengametools.git
|
||||
GIT_TAG master)
|
||||
|
||||
FetchContent_GetProperties(ogt)
|
||||
if(NOT ogt_POPULATED)
|
||||
FetchContent_Populate(ogt)
|
||||
set(NANOVDB_OGT_INCLUDE_DIRECTORY ${ogt_SOURCE_DIR}/src)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
# Installation
|
||||
###############################################################################
|
||||
|
||||
# NanoVDB header files
|
||||
set(NANOVDB_INCLUDE_FILES
|
||||
CNanoVDB.h
|
||||
NanoVDB.h
|
||||
PNanoVDB.h
|
||||
)
|
||||
|
||||
# NanoVDB util header files
|
||||
set(NANOVDB_INCLUDE_UTILFILES
|
||||
util/CSampleFromVoxels.h
|
||||
util/CudaDeviceBuffer.h
|
||||
util/DitherLUT.h
|
||||
util/ForEach.h
|
||||
util/GridBuilder.h
|
||||
util/GridChecksum.h
|
||||
util/GridHandle.h
|
||||
util/GridStats.h
|
||||
util/GridValidator.h
|
||||
util/HDDA.h
|
||||
util/HostBuffer.h
|
||||
util/Invoke.h
|
||||
util/IO.h
|
||||
util/NanoToOpenVDB.h
|
||||
util/NodeManager.h
|
||||
util/OpenToNanoVDB.h
|
||||
util/Primitives.h
|
||||
util/Range.h
|
||||
util/Ray.h
|
||||
util/Reduce.h
|
||||
util/SampleFromVoxels.h
|
||||
util/Stencils.h
|
||||
)
|
||||
|
||||
add_library(nanovdb INTERFACE)
|
||||
target_include_directories(nanovdb INTERFACE ../)
|
||||
target_compile_options(nanovdb INTERFACE
|
||||
"$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wno-invalid-offsetof>"
|
||||
"$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/bigobj>")
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNOMINMAX -D_USE_MATH_DEFINES)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_INTRINSICS)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_INTRINSICS)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_OPENVDB)
|
||||
if(NOT OPENVDB_BUILD_CORE)
|
||||
target_link_libraries(nanovdb INTERFACE OpenVDB::openvdb)
|
||||
else()
|
||||
target_link_libraries(nanovdb INTERFACE openvdb)
|
||||
endif()
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_OPENVDB)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_TBB)
|
||||
target_link_libraries(nanovdb INTERFACE TBB::tbb)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_TBB)
|
||||
if(WIN32)
|
||||
# this prevents tbb_debug.lib issue on windows
|
||||
target_compile_definitions(nanovdb INTERFACE -DTBB_USE_PREVIEW_BINARY)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_BLOSC)
|
||||
target_link_libraries(nanovdb INTERFACE Blosc::blosc)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_BLOSC)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_ZLIB)
|
||||
target_link_libraries(nanovdb INTERFACE ZLIB::ZLIB)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_ZIP)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_CUDA)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_CUDA)
|
||||
if(NOT CMAKE_CUDA_ARCHITECTURES)
|
||||
target_compile_options(nanovdb INTERFACE
|
||||
"$<$<COMPILE_LANG_AND_ID:CUDA,NVIDIA>:-arch=sm_75>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NANOVDB_USE_MAGICAVOXEL)
|
||||
target_compile_definitions(nanovdb INTERFACE -DNANOVDB_USE_MAGICAVOXEL)
|
||||
target_include_directories(nanovdb INTERFACE ${NANOVDB_OGT_INCLUDE_DIRECTORY})
|
||||
endif()
|
||||
|
||||
if(TARGET Threads::Threads)
|
||||
target_link_libraries(nanovdb INTERFACE Threads::Threads)
|
||||
endif()
|
||||
|
||||
set(NANOVDB_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}/nanovdb)
|
||||
set(NANOVDB_INSTALL_UTILDIR ${NANOVDB_INSTALL_INCLUDEDIR}/util)
|
||||
|
||||
install(FILES ${NANOVDB_INCLUDE_FILES} DESTINATION ${NANOVDB_INSTALL_INCLUDEDIR})
|
||||
install(FILES ${NANOVDB_INCLUDE_UTILFILES} DESTINATION ${NANOVDB_INSTALL_UTILDIR})
|
||||
|
||||
###############################################################################
|
||||
# Options
|
||||
###############################################################################
|
||||
|
||||
if(NANOVDB_BUILD_TOOLS)
|
||||
add_subdirectory(cmd)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_BUILD_UNITTESTS)
|
||||
add_subdirectory(unittest)
|
||||
endif()
|
||||
|
||||
if(NANOVDB_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
@@ -0,0 +1,715 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//
|
||||
// Simple C-wrapper for the nanovdb structure
|
||||
// Meant for systems where you lack a C++ compiler.
|
||||
//
|
||||
#ifndef __CNANOVDB__
|
||||
#define __CNANOVDB__
|
||||
|
||||
#define CNANOVDB_DATA_ALIGNMENT 32
|
||||
#define CNANOVDB_ALIGNMENT_PADDING(x, n) (-(x) & ((n)-1))
|
||||
|
||||
#define USE_SINGLE_ROOT_KEY
|
||||
|
||||
#ifdef __OPENCL_VERSION__
|
||||
|
||||
#define CNANOVDB_GLOBAL __global
|
||||
#define RESTRICT restrict
|
||||
|
||||
// OpenCL doesn't define these basic types:
|
||||
typedef unsigned long uint64_t;
|
||||
typedef long int64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef int int32_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
#else
|
||||
|
||||
#define CNANOVDB_GLOBAL
|
||||
#define RESTRICT __restrict
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
enum cnanovdb_GridType
|
||||
{
|
||||
cnanovdb_GridType_Unknown = 0,
|
||||
cnanovdb_GridType_Float = 1,
|
||||
cnanovdb_GridType_Double = 2,
|
||||
cnanovdb_GridType_Int16 = 3,
|
||||
cnanovdb_GridType_Int32 = 4,
|
||||
cnanovdb_GridType_Int64 = 5,
|
||||
cnanovdb_GridType_Vec3f = 6,
|
||||
cnanovdb_GridType_Vec3d = 7,
|
||||
cnanovdb_GridType_Mask = 8,
|
||||
cnanovdb_GridType_FP16 = 9,
|
||||
cnanovdb_GridType_End = 10
|
||||
};
|
||||
|
||||
#define ROOT_LEVEL 3
|
||||
|
||||
#define DEFINEMASK_int(LOG2DIM, SIZE) \
|
||||
typedef struct \
|
||||
{ \
|
||||
uint64_t mWords[SIZE >> 6]; \
|
||||
} cnanovdb_mask##LOG2DIM; \
|
||||
\
|
||||
static void cnanovdb_mask##LOG2DIM##_clear(CNANOVDB_GLOBAL cnanovdb_mask##LOG2DIM *RESTRICT mask) \
|
||||
{ for (uint32_t i = 0; i < (SIZE >> 6); i++) mask->mWords[i] = 0; } \
|
||||
\
|
||||
static bool cnanovdb_mask##LOG2DIM##_isOn(const CNANOVDB_GLOBAL cnanovdb_mask##LOG2DIM *RESTRICT mask, uint32_t n) \
|
||||
{ return 0 != (mask->mWords[n >> 6] & (((uint64_t)(1)) << (n & 63))); } \
|
||||
/**/
|
||||
|
||||
#define DEFINEMASK(LOG2DIM) \
|
||||
DEFINEMASK_int(LOG2DIM, (1U << (3*LOG2DIM)))
|
||||
|
||||
#define INSTANTIATE(LOG2DIM) \
|
||||
DEFINEMASK(LOG2DIM)
|
||||
|
||||
INSTANTIATE(3)
|
||||
INSTANTIATE(4)
|
||||
INSTANTIATE(5)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mMatF[9]; // r,c = 3*r + c
|
||||
float mInvMatF[9]; // r,c = 3*r + c
|
||||
float mVecF[3];
|
||||
float mTaperF;
|
||||
double mMatD[9]; // r,c = 3*r + c
|
||||
double mInvMatD[9]; // r,c = 3*r + c
|
||||
double mVecD[3];
|
||||
double mTaperD;
|
||||
} cnanovdb_map;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mVec[3];
|
||||
} cnanovdb_Vec3F;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t mVec[3];
|
||||
} cnanovdb_coord;
|
||||
|
||||
static int
|
||||
cnanovdb_coord_compare(const CNANOVDB_GLOBAL cnanovdb_coord *a, const cnanovdb_coord *b)
|
||||
{
|
||||
if (a->mVec[0] < b->mVec[0])
|
||||
return -1;
|
||||
if (a->mVec[0] > b->mVec[0])
|
||||
return 1;
|
||||
if (a->mVec[1] < b->mVec[1])
|
||||
return -1;
|
||||
if (a->mVec[1] > b->mVec[1])
|
||||
return 1;
|
||||
if (a->mVec[2] < b->mVec[2])
|
||||
return -1;
|
||||
if (a->mVec[2] > b->mVec[2])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_SINGLE_ROOT_KEY
|
||||
static uint64_t
|
||||
cnanovdb_coord_to_key(const cnanovdb_coord *RESTRICT ijk)
|
||||
{
|
||||
// Define to workaround a bug with 64-bit shifts in the AMD OpenCL compiler.
|
||||
#if defined(AVOID_64BIT_SHIFT)
|
||||
uint2 key = (uint2)( ((uint32_t)ijk->mVec[2]) >> 12, 0) |
|
||||
(uint2)((((uint32_t)ijk->mVec[1]) >> 12) << 21,
|
||||
((uint32_t)ijk->mVec[1]) >> 23) |
|
||||
(uint2)(0, (((uint32_t)ijk->mVec[0]) >> 12) << 10);
|
||||
return *(uint64_t *)&key;
|
||||
#else
|
||||
return ((uint64_t) (((uint32_t)ijk->mVec[2]) >> 12)) |
|
||||
(((uint64_t) (((uint32_t)ijk->mVec[1]) >> 12)) << 21) |
|
||||
(((uint64_t) (((uint32_t)ijk->mVec[0]) >> 12)) << 42);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void
|
||||
cnanovdb_coord_to_key(cnanovdb_coord *RESTRICT key, const cnanovdb_coord *RESTRICT ijk)
|
||||
{
|
||||
key->mVec[0] = ijk->mVec[0] & ~((1u << 12) - 1u);
|
||||
key->mVec[1] = ijk->mVec[1] & ~((1u << 12) - 1u);
|
||||
key->mVec[2] = ijk->mVec[2] & ~((1u << 12) - 1u);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
cnanovdb_map_apply(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
float sx = src->mVec[0];
|
||||
float sy = src->mVec[1];
|
||||
float sz = src->mVec[2];
|
||||
dst->mVec[0] = sx * map->mMatF[0] + sy * map->mMatF[1] + sz * map->mMatF[2] + map->mVecF[0];
|
||||
dst->mVec[1] = sx * map->mMatF[3] + sy * map->mMatF[4] + sz * map->mMatF[5] + map->mVecF[1];
|
||||
dst->mVec[2] = sx * map->mMatF[6] + sy * map->mMatF[7] + sz * map->mMatF[8] + map->mVecF[2];
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_map_applyInverse(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
float sx = src->mVec[0] - map->mVecF[0];
|
||||
float sy = src->mVec[1] - map->mVecF[1];
|
||||
float sz = src->mVec[2] - map->mVecF[2];
|
||||
dst->mVec[0] = sx * map->mInvMatF[0] + sy * map->mInvMatF[1] + sz * map->mInvMatF[2];
|
||||
dst->mVec[1] = sx * map->mInvMatF[3] + sy * map->mInvMatF[4] + sz * map->mInvMatF[5];
|
||||
dst->mVec[2] = sx * map->mInvMatF[6] + sy * map->mInvMatF[7] + sz * map->mInvMatF[8];
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_map_applyJacobi(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
float sx = src->mVec[0];
|
||||
float sy = src->mVec[1];
|
||||
float sz = src->mVec[2];
|
||||
dst->mVec[0] = sx * map->mMatF[0] + sy * map->mMatF[1] + sz * map->mMatF[2];
|
||||
dst->mVec[1] = sx * map->mMatF[3] + sy * map->mMatF[4] + sz * map->mMatF[5];
|
||||
dst->mVec[2] = sx * map->mMatF[6] + sy * map->mMatF[7] + sz * map->mMatF[8];
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_map_applyInverseJacobi(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
float sx = src->mVec[0];
|
||||
float sy = src->mVec[1];
|
||||
float sz = src->mVec[2];
|
||||
dst->mVec[0] = sx * map->mInvMatF[0] + sy * map->mInvMatF[1] + sz * map->mInvMatF[2];
|
||||
dst->mVec[1] = sx * map->mInvMatF[3] + sy * map->mInvMatF[4] + sz * map->mInvMatF[5];
|
||||
dst->mVec[2] = sx * map->mInvMatF[6] + sy * map->mInvMatF[7] + sz * map->mInvMatF[8];
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_map_applyIJT(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_map *RESTRICT map, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
float sx = src->mVec[0];
|
||||
float sy = src->mVec[1];
|
||||
float sz = src->mVec[2];
|
||||
dst->mVec[0] = sx * map->mInvMatF[0] + sy * map->mInvMatF[3] + sz * map->mInvMatF[6];
|
||||
dst->mVec[1] = sx * map->mInvMatF[1] + sy * map->mInvMatF[4] + sz * map->mInvMatF[7];
|
||||
dst->mVec[2] = sx * map->mInvMatF[2] + sy * map->mInvMatF[5] + sz * map->mInvMatF[8];
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int64_t mByteOffset; // byte offset to the blind data, relative to the GridData.
|
||||
uint64_t mElementCount; // number of elements, e.g. point count
|
||||
uint32_t mFlags; // flags
|
||||
uint32_t mSemantic; // semantic meaning of the data.
|
||||
uint32_t mDataClass; // 4 bytes
|
||||
uint32_t mDataType; // 4 bytes
|
||||
char mName[256];
|
||||
uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(int64_t)+sizeof(uint64_t)+2*sizeof(uint32_t)+2*sizeof(uint32_t)+256*sizeof(char), CNANOVDB_DATA_ALIGNMENT)];
|
||||
} cnanovdb_gridblindmetadata;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t mMagic; // 8B magic to validate it is valid grid data.
|
||||
uint64_t mChecksum; // 8B. Checksum of grid buffer.
|
||||
uint32_t mVersion;// 4B. compacted major.minor.path version number.
|
||||
uint32_t mFlags; // 4B. flags for grid.
|
||||
uint32_t mGridIndex;// 4B. Index of this grid in the buffer
|
||||
uint32_t mGridCount; // 4B. Total number of grids in the buffer
|
||||
uint64_t mGridSize; // 8B. byte count of this entire grid occupied in the buffer.
|
||||
char mGridName[256]; // 256B
|
||||
cnanovdb_map mMap; // 264B. affine transformation between index and world space in both single and double precision
|
||||
double mBBox[6]; // 48B. floating-point bounds of active values in WORLD SPACE
|
||||
double mVoxelSize[3]; // 24B. size of a voxel in world units
|
||||
uint32_t mGridClass; // 4B.
|
||||
uint32_t mGridType; // 4B.
|
||||
uint64_t mBlindMetadataOffset; // 8B. offset of GridBlindMetaData structures.
|
||||
int32_t mBlindMetadataCount; // 4B. count of GridBlindMetaData structures.
|
||||
uint32_t _reserved[CNANOVDB_ALIGNMENT_PADDING(8 + 8 + 4 + 4 + 4 + 4 + 8 + 256 + 24 + 24 + sizeof(cnanovdb_map) + 24 + 4 + 4 + 8 + 4, CNANOVDB_DATA_ALIGNMENT) / 4];
|
||||
} cnanovdb_griddata;
|
||||
|
||||
static void
|
||||
cnanovdb_griddata_worldToIndex(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
cnanovdb_map_applyInverse(dst, &grid->mMap, src);
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_griddata_indexToWorld(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
cnanovdb_map_apply(dst, &grid->mMap, src);
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_griddata_worldToIndexDir(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
cnanovdb_map_applyInverseJacobi(dst, &grid->mMap, src);
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_griddata_indexToWorldDir(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
cnanovdb_map_applyJacobi(dst, &grid->mMap, src);
|
||||
}
|
||||
|
||||
static void
|
||||
cnanovdb_griddata_applyIJT(cnanovdb_Vec3F *dst, const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid, const cnanovdb_Vec3F *src)
|
||||
{
|
||||
cnanovdb_map_applyIJT(dst, &grid->mMap, src);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t mNodeOffset[ROOT_LEVEL + 1];
|
||||
uint32_t mNodeCount[ROOT_LEVEL];
|
||||
uint32_t mTileCount[ROOT_LEVEL];
|
||||
uint64_t mVoxelCount;
|
||||
uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(4*sizeof(uint64_t)+(3+3)*sizeof(uint32_t)+sizeof(uint64_t), CNANOVDB_DATA_ALIGNMENT)];
|
||||
} cnanovdb_treedata;
|
||||
|
||||
static const CNANOVDB_GLOBAL cnanovdb_treedata *
|
||||
cnanovdb_griddata_tree(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT griddata)
|
||||
{
|
||||
return (const CNANOVDB_GLOBAL cnanovdb_treedata *)(griddata + 1);
|
||||
}
|
||||
|
||||
#define CREATE_TILEENTRY(VALUETYPE, SUFFIX) \
|
||||
typedef union \
|
||||
{ \
|
||||
VALUETYPE value; \
|
||||
uint64_t child; \
|
||||
} cnanovdb_tileentry##SUFFIX; \
|
||||
/**/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cnanovdb_coord mKey;
|
||||
const CNANOVDB_GLOBAL void *mNode[4];
|
||||
} cnanovdb_readaccessor;
|
||||
|
||||
|
||||
static void
|
||||
cnanovdb_readaccessor_insert(cnanovdb_readaccessor *RESTRICT acc, int childlevel, const CNANOVDB_GLOBAL void *RESTRICT node, const cnanovdb_coord *RESTRICT ijk)
|
||||
{
|
||||
acc->mNode[childlevel] = node;
|
||||
acc->mKey.mVec[0] = ijk->mVec[0];
|
||||
acc->mKey.mVec[1] = ijk->mVec[1];
|
||||
acc->mKey.mVec[2] = ijk->mVec[2];
|
||||
}
|
||||
|
||||
#define CREATE_LEAF_NODE_int(LEVEL, LOG2DIM, CHILDTOTAL, TOTAL, MASK, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
typedef struct \
|
||||
{ \
|
||||
cnanovdb_coord mBBox_min; \
|
||||
uint8_t mBBoxDif[3]; \
|
||||
uint8_t mFlags; \
|
||||
cnanovdb_mask##LOG2DIM mValueMask; \
|
||||
VALUETYPE mMinimum; \
|
||||
VALUETYPE mMaximum; \
|
||||
STATSTYPE mAverage; \
|
||||
STATSTYPE mStdDevi; \
|
||||
uint32_t _reserved[ CNANOVDB_ALIGNMENT_PADDING(sizeof(cnanovdb_mask##LOG2DIM)+2*sizeof(VALUETYPE)+2*sizeof(STATSTYPE)+sizeof(cnanovdb_coord)+sizeof(uint8_t[3])+sizeof(uint8_t), CNANOVDB_DATA_ALIGNMENT)/4]; \
|
||||
VALUETYPE mVoxels[1u << (3*LOG2DIM)]; \
|
||||
} cnanovdb_node##LEVEL##SUFFIX; \
|
||||
\
|
||||
static uint32_t \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
return ( ( ( ijk->mVec[0] & MASK ) >> CHILDTOTAL ) << ( 2 * LOG2DIM ) ) + \
|
||||
( ( ( ijk->mVec[1] & MASK ) >> CHILDTOTAL ) << ( LOG2DIM ) ) + \
|
||||
( ( ijk->mVec[2] & MASK ) >> CHILDTOTAL ); \
|
||||
} \
|
||||
\
|
||||
static VALUETYPE \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_getValue(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
return node->mVoxels[n]; \
|
||||
} \
|
||||
\
|
||||
static VALUETYPE \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_getValueAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT /* DO NOT REMOVE: Required for C99 compliance */ acc) \
|
||||
{ \
|
||||
(void)(acc); \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
return node->mVoxels[n]; \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_isActive(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
if (cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n)) \
|
||||
return true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_isActiveAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT /* DO NOT REMOVE: Required for C99 compliance */ acc) \
|
||||
{ \
|
||||
(void)(acc); \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
if (cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n)) \
|
||||
return true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX * \
|
||||
cnanovdb_tree_getNode##LEVEL##SUFFIX(const CNANOVDB_GLOBAL cnanovdb_treedata *RESTRICT tree, uint64_t i) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *basenode = (const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *)((CNANOVDB_GLOBAL uint8_t *)(tree) + tree->mNodeOffset[LEVEL]); \
|
||||
return basenode + i; \
|
||||
} \
|
||||
\
|
||||
/**/
|
||||
|
||||
#define CREATE_LEAF_NODE(LEVEL, LOG2DIM, TOTAL, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_LEAF_NODE_int(LEVEL, LOG2DIM, (TOTAL-LOG2DIM), TOTAL, ((1u << TOTAL) - 1u), VALUETYPE, STATSTYPE, SUFFIX)
|
||||
|
||||
#define CREATE_INTERNAL_NODE_int(CHILDLEVEL, LEVEL, LOG2DIM, CHILDTOTAL, TOTAL, MASK, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
typedef struct \
|
||||
{ \
|
||||
cnanovdb_coord mBBox_min, mBBox_max; \
|
||||
int32_t mOffset; \
|
||||
uint32_t mFlags; \
|
||||
cnanovdb_mask##LOG2DIM mValueMask, mChildMask; \
|
||||
VALUETYPE mMinimum, mMaximum; \
|
||||
STATSTYPE mAverage, mStdDevi; \
|
||||
uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(cnanovdb_mask##LOG2DIM)+sizeof(VALUETYPE)*2+sizeof(STATSTYPE)*2+sizeof(cnanovdb_coord)*2+sizeof(int32_t)+sizeof(uint32_t), CNANOVDB_DATA_ALIGNMENT)]; \
|
||||
cnanovdb_tileentry##SUFFIX mTable[1u << (3*LOG2DIM)]; \
|
||||
} cnanovdb_node##LEVEL##SUFFIX; \
|
||||
\
|
||||
static uint32_t \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
return ( ( ( ijk->mVec[0] & MASK ) >> CHILDTOTAL ) << ( 2 * LOG2DIM ) ) + \
|
||||
( ( ( ijk->mVec[1] & MASK ) >> CHILDTOTAL ) << ( LOG2DIM ) ) + \
|
||||
( ( ijk->mVec[2] & MASK ) >> CHILDTOTAL ); \
|
||||
} \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX * \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_getChild(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, uint32_t n) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *childnode = (const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *)( ((CNANOVDB_GLOBAL uint8_t *)node) + node->mTable[n].child); \
|
||||
return childnode; \
|
||||
} \
|
||||
\
|
||||
static VALUETYPE \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_getValue(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \
|
||||
return cnanovdb_node##CHILDLEVEL##SUFFIX##_getValue(child, ijk); \
|
||||
} \
|
||||
return node->mTable[n].value; \
|
||||
} \
|
||||
\
|
||||
static VALUETYPE \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_getValueAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \
|
||||
{ \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \
|
||||
cnanovdb_readaccessor_insert(acc, CHILDLEVEL, child, ijk); \
|
||||
return cnanovdb_node##CHILDLEVEL##SUFFIX##_getValueAndCache(child, ijk, acc); \
|
||||
} \
|
||||
return node->mTable[n].value; \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_isActive(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \
|
||||
return cnanovdb_node##CHILDLEVEL##SUFFIX##_isActive(child, ijk); \
|
||||
} \
|
||||
return cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n) ? true : false; \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
cnanovdb_node##LEVEL##SUFFIX##_isActiveAndCache(const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *RESTRICT node, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \
|
||||
{ \
|
||||
uint32_t n = cnanovdb_node##LEVEL##SUFFIX##_CoordToOffset(ijk); \
|
||||
if (cnanovdb_mask##LOG2DIM##_isOn(&node->mChildMask, n)) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##CHILDLEVEL##SUFFIX *child = cnanovdb_node##LEVEL##SUFFIX##_getChild(node, n); \
|
||||
cnanovdb_readaccessor_insert(acc, CHILDLEVEL, child, ijk); \
|
||||
return cnanovdb_node##CHILDLEVEL##SUFFIX##_isActiveAndCache(child, ijk, acc); \
|
||||
} \
|
||||
return cnanovdb_mask##LOG2DIM##_isOn(&node->mValueMask, n) ? true : false; \
|
||||
} \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX * \
|
||||
cnanovdb_tree_getNode##LEVEL##SUFFIX(const CNANOVDB_GLOBAL cnanovdb_treedata *RESTRICT tree, uint64_t i) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *basenode = (const CNANOVDB_GLOBAL cnanovdb_node##LEVEL##SUFFIX *)((CNANOVDB_GLOBAL uint8_t *)(tree) + tree->mNodeOffset[LEVEL]); \
|
||||
return basenode + i; \
|
||||
} \
|
||||
\
|
||||
/**/
|
||||
|
||||
#define CREATE_INTERNAL_NODE(CHILDLEVEL, LEVEL, LOG2DIM, TOTAL, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_INTERNAL_NODE_int(CHILDLEVEL, LEVEL, LOG2DIM, (TOTAL-LOG2DIM), TOTAL, ((1u << TOTAL) - 1u), VALUETYPE, STATSTYPE, SUFFIX)
|
||||
|
||||
|
||||
#ifdef USE_SINGLE_ROOT_KEY
|
||||
#define DEFINE_KEY(KEY) \
|
||||
uint64_t KEY;
|
||||
#define KEYSIZE sizeof(uint64_t)
|
||||
|
||||
#define KEYSEARCH(SUFFIX) \
|
||||
uint64_t key; \
|
||||
key = cnanovdb_coord_to_key(ijk); \
|
||||
\
|
||||
for (int i = low; i < high; i++) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = tiles + i; \
|
||||
if (tile->key == key) \
|
||||
return tile; \
|
||||
} \
|
||||
/**/
|
||||
#else
|
||||
#define DEFINE_KEY(KEY) \
|
||||
cnanovdb_coord KEY;
|
||||
#define KEYSIZE sizeof(cnanovdb_coord)
|
||||
#define KEYSEARCH(SUFFIX) \
|
||||
cnanovdb_coord key; \
|
||||
cnanovdb_coord_to_key(&key, ijk); \
|
||||
\
|
||||
while (low != high) \
|
||||
{ \
|
||||
int32_t mid = low + (( high - low ) >> 1 ); \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = tiles + mid; \
|
||||
\
|
||||
int keycmp = cnanovdb_coord_compare(&tile->key, &key); \
|
||||
if (keycmp == 0) \
|
||||
{ \
|
||||
return tile; \
|
||||
} \
|
||||
\
|
||||
if (keycmp < 0) \
|
||||
low = mid + 1; \
|
||||
else \
|
||||
high = mid; \
|
||||
} \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
|
||||
#define CREATE_ROOTDATA(VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
typedef struct \
|
||||
{ \
|
||||
DEFINE_KEY(key); \
|
||||
int64_t child; \
|
||||
uint32_t state; \
|
||||
VALUETYPE value; \
|
||||
uint8_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(KEYSIZE)+sizeof(VALUETYPE)+sizeof(int64_t)+sizeof(uint32_t), CNANOVDB_DATA_ALIGNMENT)]; \
|
||||
} cnanovdb_rootdata_tile##SUFFIX; \
|
||||
\
|
||||
typedef struct \
|
||||
{ \
|
||||
cnanovdb_coord mBBox_min, mBBox_max; \
|
||||
uint32_t mTableSize; \
|
||||
VALUETYPE mBackground; \
|
||||
VALUETYPE mMinimum, mMaximum; \
|
||||
STATSTYPE mAverage, mStdDevi; \
|
||||
uint32_t _reserved[CNANOVDB_ALIGNMENT_PADDING(sizeof(cnanovdb_coord)*2+sizeof(uint32_t)+sizeof(VALUETYPE)*3+sizeof(STATSTYPE)*2, CNANOVDB_DATA_ALIGNMENT)/4]; \
|
||||
} cnanovdb_rootdata##SUFFIX; \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX * \
|
||||
cnanovdb_treedata_root##SUFFIX(const CNANOVDB_GLOBAL cnanovdb_treedata *RESTRICT treedata) \
|
||||
{ \
|
||||
return (const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *) ((const CNANOVDB_GLOBAL uint8_t *)(treedata) + treedata->mNodeOffset[ROOT_LEVEL]); \
|
||||
} \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX * \
|
||||
cnanovdb_rootdata##SUFFIX##_getTile(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, uint32_t n) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *basetile = (const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *) (rootdata + 1); \
|
||||
return basetile + n; \
|
||||
} \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX * \
|
||||
cnanovdb_rootdata##SUFFIX##_getChild(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *RESTRICT tile) \
|
||||
{ \
|
||||
CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *basenode = (CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *) (((CNANOVDB_GLOBAL uint8_t *) rootdata) + tile->child); \
|
||||
return basenode; \
|
||||
} \
|
||||
\
|
||||
static const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX * \
|
||||
cnanovdb_rootdata##SUFFIX##_findTile(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
int32_t low = 0, high = rootdata->mTableSize; \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tiles = cnanovdb_rootdata##SUFFIX##_getTile(rootdata, 0); \
|
||||
\
|
||||
KEYSEARCH(SUFFIX) \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
static VALUETYPE \
|
||||
cnanovdb_rootdata##SUFFIX##_getValue(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \
|
||||
if (!tile) \
|
||||
return rootdata->mBackground; \
|
||||
if (tile->child == 0) \
|
||||
return tile->value; \
|
||||
return cnanovdb_node2##SUFFIX##_getValue( cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile), ijk ); \
|
||||
} \
|
||||
\
|
||||
static VALUETYPE \
|
||||
cnanovdb_rootdata##SUFFIX##_getValueAndCache(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \
|
||||
if (!tile) \
|
||||
return rootdata->mBackground; \
|
||||
if (tile->child == 0) \
|
||||
return tile->value; \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *child = cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile); \
|
||||
cnanovdb_readaccessor_insert(acc, 2, child, ijk); \
|
||||
return cnanovdb_node2##SUFFIX##_getValueAndCache( child, ijk, acc ); \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
cnanovdb_rootdata##SUFFIX##_isActive(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \
|
||||
if (!tile) \
|
||||
return false; \
|
||||
if (tile->child == 0) \
|
||||
return tile->state; \
|
||||
return cnanovdb_node2##SUFFIX##_isActive( cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile), ijk ); \
|
||||
} \
|
||||
\
|
||||
static bool \
|
||||
cnanovdb_rootdata##SUFFIX##_isActiveAndCache(const CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *RESTRICT rootdata, const cnanovdb_coord *RESTRICT ijk, cnanovdb_readaccessor *RESTRICT acc) \
|
||||
{ \
|
||||
const CNANOVDB_GLOBAL cnanovdb_rootdata_tile##SUFFIX *tile = cnanovdb_rootdata##SUFFIX##_findTile(rootdata, ijk); \
|
||||
if (!tile) \
|
||||
return false; \
|
||||
if (tile->child == 0) \
|
||||
return tile->state; \
|
||||
const CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *child = cnanovdb_rootdata##SUFFIX##_getChild(rootdata, tile); \
|
||||
cnanovdb_readaccessor_insert(acc, 2, child, ijk); \
|
||||
return cnanovdb_node2##SUFFIX##_isActiveAndCache( child, ijk, acc ); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
||||
inline void
|
||||
cnanovdb_readaccessor_init(cnanovdb_readaccessor *RESTRICT acc,
|
||||
const CNANOVDB_GLOBAL void /*cnanovdb_rootdata* */ *RESTRICT rootdata)
|
||||
{
|
||||
acc->mNode[0] = acc->mNode[1] = acc->mNode[2] = 0;
|
||||
acc->mNode[3] = rootdata;
|
||||
}
|
||||
|
||||
#define DEFINE_ISCACHED(LEVEL, MASK) \
|
||||
inline bool \
|
||||
cnanovdb_readaccessor_isCached##LEVEL(cnanovdb_readaccessor *RESTRICT acc, int32_t dirty) \
|
||||
{ \
|
||||
if (!acc->mNode[LEVEL]) \
|
||||
return false; \
|
||||
if (dirty & ~MASK) \
|
||||
{ \
|
||||
acc->mNode[LEVEL] = 0; \
|
||||
return false; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
/**/
|
||||
|
||||
DEFINE_ISCACHED(0, ((1u << 3) - 1u) )
|
||||
DEFINE_ISCACHED(1, ((1u << 7) - 1u) )
|
||||
DEFINE_ISCACHED(2, ((1u << 12) - 1u) )
|
||||
|
||||
inline int32_t
|
||||
cnanovdb_readaccessor_computeDirty(const cnanovdb_readaccessor *RESTRICT acc, const cnanovdb_coord *RESTRICT ijk)
|
||||
{
|
||||
return (ijk->mVec[0] ^ acc->mKey.mVec[0]) |
|
||||
(ijk->mVec[1] ^ acc->mKey.mVec[1]) |
|
||||
(ijk->mVec[2] ^ acc->mKey.mVec[2]);
|
||||
}
|
||||
|
||||
#define CREATE_ACCESSOR(VALUETYPE, SUFFIX) \
|
||||
inline VALUETYPE \
|
||||
cnanovdb_readaccessor_getValue##SUFFIX(cnanovdb_readaccessor *RESTRICT acc, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
int32_t dirty = cnanovdb_readaccessor_computeDirty(acc, ijk); \
|
||||
\
|
||||
if (cnanovdb_readaccessor_isCached0(acc, dirty)) \
|
||||
return cnanovdb_node0##SUFFIX##_getValue( ((CNANOVDB_GLOBAL cnanovdb_node0##SUFFIX *) acc->mNode[0]), ijk); \
|
||||
if (cnanovdb_readaccessor_isCached1(acc, dirty)) \
|
||||
return cnanovdb_node1##SUFFIX##_getValueAndCache( ((CNANOVDB_GLOBAL cnanovdb_node1##SUFFIX *) acc->mNode[1]), ijk, acc); \
|
||||
if (cnanovdb_readaccessor_isCached2(acc, dirty)) \
|
||||
return cnanovdb_node2##SUFFIX##_getValueAndCache( ((CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *) acc->mNode[2]), ijk, acc); \
|
||||
\
|
||||
return cnanovdb_rootdata##SUFFIX##_getValueAndCache( ((CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *)acc->mNode[3]), ijk, acc); \
|
||||
} \
|
||||
\
|
||||
inline bool \
|
||||
cnanovdb_readaccessor_isActive##SUFFIX(cnanovdb_readaccessor *RESTRICT acc, const cnanovdb_coord *RESTRICT ijk) \
|
||||
{ \
|
||||
int32_t dirty = cnanovdb_readaccessor_computeDirty(acc, ijk); \
|
||||
\
|
||||
if (cnanovdb_readaccessor_isCached0(acc, dirty)) \
|
||||
return cnanovdb_node0##SUFFIX##_isActive( ((CNANOVDB_GLOBAL cnanovdb_node0##SUFFIX *) acc->mNode[0]), ijk); \
|
||||
if (cnanovdb_readaccessor_isCached1(acc, dirty)) \
|
||||
return cnanovdb_node1##SUFFIX##_isActiveAndCache( ((CNANOVDB_GLOBAL cnanovdb_node1##SUFFIX *) acc->mNode[1]), ijk, acc); \
|
||||
if (cnanovdb_readaccessor_isCached2(acc, dirty)) \
|
||||
return cnanovdb_node2##SUFFIX##_isActiveAndCache( ((CNANOVDB_GLOBAL cnanovdb_node2##SUFFIX *) acc->mNode[2]), ijk, acc); \
|
||||
\
|
||||
return cnanovdb_rootdata##SUFFIX##_isActiveAndCache( ((CNANOVDB_GLOBAL cnanovdb_rootdata##SUFFIX *)acc->mNode[3]), ijk, acc); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
||||
#define CREATE_GRIDTYPE(VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_TILEENTRY(VALUETYPE, SUFFIX) \
|
||||
CREATE_LEAF_NODE(0, 3, 3, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_INTERNAL_NODE(0, 1, 4, 7, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_INTERNAL_NODE(1, 2, 5, 12, VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_ROOTDATA(VALUETYPE, STATSTYPE, SUFFIX) \
|
||||
CREATE_ACCESSOR(VALUETYPE, SUFFIX) \
|
||||
/**/
|
||||
|
||||
CREATE_GRIDTYPE(float, float, F)
|
||||
CREATE_GRIDTYPE(cnanovdb_Vec3F, float, F3)
|
||||
|
||||
static int
|
||||
cnanovdb_griddata_valid(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid)
|
||||
{
|
||||
if (!grid)
|
||||
return 0;
|
||||
if (grid->mMagic != 0x304244566f6e614eUL)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cnanovdb_griddata_validF(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid)
|
||||
{
|
||||
if (!cnanovdb_griddata_valid(grid))
|
||||
return 0;
|
||||
if (grid->mGridType != cnanovdb_GridType_Float)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cnanovdb_griddata_validF3(const CNANOVDB_GLOBAL cnanovdb_griddata *RESTRICT grid)
|
||||
{
|
||||
if (!cnanovdb_griddata_valid(grid))
|
||||
return 0;
|
||||
if (grid->mGridType != cnanovdb_GridType_Vec3f)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
<img src="https://www.openvdb.org/images/nanovdb_logo.png" height="150">
|
||||
|
||||
# NanoVDB:
|
||||
A lightweight GPU friendly version of VDB initially targeting rendering applications.
|
||||
|
||||
* [Build instructions for make and cmake](docs/HowToBuild.md)
|
||||
* [Frequently asked questions](docs/FAQ.md)
|
||||
* [Grid cells vs grid nodes](docs/GridCells_vs_GridNodes/Main.pdf)
|
||||
* [Source tree](docs/SourceTree.md)
|
||||
* [Examples](docs/HelloWorld.md)
|
||||
|
||||
### Copyright Contributors to the OpenVDB Project
|
||||
### SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
[](https://circleci.com/gh/NVIDIA-Omniverse/NanoVDB)
|
||||
@@ -0,0 +1,48 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CMake Configuration for NanoVDB Command Line Tools
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(NanoVDBExamples LANGUAGES CXX)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
###############################################################################
|
||||
|
||||
message(STATUS "----------------------------------------------------")
|
||||
message(STATUS "--------- Configuring NanoVDB Cmd Tools ------------")
|
||||
message(STATUS "----------------------------------------------------")
|
||||
|
||||
###############################################################################
|
||||
# -----------------------------------------------------------------------------
|
||||
# workaround for win32 bug when nvcc "--keep" is used.
|
||||
if(WIN32 AND NANOVDB_CUDA_KEEP_PTX)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/Release")
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if(NOT NANOVDB_USE_OPENVDB)
|
||||
message(WARNING " - OpenVDB required to build nanovdb_convert. Skipping.")
|
||||
else()
|
||||
add_executable(nanovdb_convert convert/nanovdb_convert.cc)
|
||||
target_link_libraries(nanovdb_convert PRIVATE nanovdb)
|
||||
install(TARGETS nanovdb_convert RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# nanovdb_print
|
||||
add_executable(nanovdb_print print/nanovdb_print.cc)
|
||||
target_link_libraries(nanovdb_print PRIVATE nanovdb)
|
||||
install(TARGETS nanovdb_print RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# nanovdb_validate
|
||||
add_executable(nanovdb_validate validate/nanovdb_validate.cc)
|
||||
target_link_libraries(nanovdb_validate PRIVATE nanovdb)
|
||||
install(TARGETS nanovdb_validate RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
@@ -0,0 +1,311 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/*!
|
||||
\file nanovdb_convert.cc
|
||||
|
||||
\author Ken Museth
|
||||
|
||||
\date May 21, 2020
|
||||
|
||||
\brief Command-line tool that converts between openvdb and nanovdb files
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#include <nanovdb/util/IO.h> // this is required to read (and write) NanoVDB files on the host
|
||||
#include <nanovdb/util/OpenToNanoVDB.h>
|
||||
#include <nanovdb/util/NanoToOpenVDB.h>
|
||||
|
||||
void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE)
|
||||
{
|
||||
std::cerr << "\nUsage: " << progName << " [options] *.vdb output.nvdb\n"
|
||||
<< "Which: converts one or more OpenVDB files to a single NanoVDB file\n\n"
|
||||
<< "Usage: " << progName << " [options] *.nvdb output.vdb\n"
|
||||
<< "Which: converts one or more NanoVDB files to a single OpenVDB file\n\n"
|
||||
<< "Options:\n"
|
||||
<< "-a,--abs-error float\t Absolute error tolerance used for variable bit depth quantization\n"
|
||||
<< "-b,--blosc\tUse BLOSC compression on the output file\n"
|
||||
<< "-c,--checksum mode\t where mode={none, partial, full}\n"
|
||||
<< "-d,--dither\tApply dithering during blocked compression\n"
|
||||
<< "-f,--force\tOverwrite output file if it already exists\n"
|
||||
<< "--fp4\tQuantize float grids to 4 bits\n"
|
||||
<< "--fp8\tQuantize float grids to 8 bits\n"
|
||||
<< "--fp16\tQuantize float grids to 16 bits\n"
|
||||
<< "--fpN\tQuantize float grids to variable bit depth (use -a or -r to specify a tolerance)\n"
|
||||
<< "-g,--grid name\tConvert all grids matching the specified string name\n"
|
||||
<< "-h,--help\tPrints this message\n"
|
||||
<< "-r,--rel-error float\t Relative error tolerance used for variable bit depth quantization\n"
|
||||
<< "-s,--stats mode\t where mode={none, bbox, extrema, all}\n"
|
||||
<< "-v,--verbose\tPrint verbose information to the terminal\n"
|
||||
<< "--version\tPrint version information to the terminal\n"
|
||||
<< "-z,--zip\tUse ZIP compression on the output file\n";
|
||||
exit(exitStatus);
|
||||
}
|
||||
|
||||
void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS)
|
||||
{
|
||||
printf("\n%s was build against NanoVDB version %s\n", progName, nanovdb::Version().c_str());
|
||||
exit(exitStatus);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int exitStatus = EXIT_SUCCESS;
|
||||
|
||||
nanovdb::io::Codec codec = nanovdb::io::Codec::NONE;// compression codec for the file
|
||||
nanovdb::StatsMode sMode = nanovdb::StatsMode::Default;
|
||||
nanovdb::ChecksumMode cMode = nanovdb::ChecksumMode::Default;
|
||||
nanovdb::GridType qMode = nanovdb::GridType::Unknown;//specify the quantization mode
|
||||
bool verbose = false, overwrite = false, dither = false, absolute = true;
|
||||
float tolerance = -1.0f;
|
||||
std::string gridName;
|
||||
std::vector<std::string> fileNames;
|
||||
auto toLowerCase = [](std::string &str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),[](unsigned char c){return std::tolower(c);});
|
||||
};
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
if (arg[0] == '-') {
|
||||
if (arg == "-v" || arg == "--verbose") {
|
||||
verbose = true;
|
||||
} else if (arg == "--version") {
|
||||
version(argv[0]);
|
||||
} else if (arg == "-f" || arg == "--force") {
|
||||
overwrite = true;
|
||||
} else if (arg == "--fp4") {
|
||||
qMode = nanovdb::GridType::Fp4;
|
||||
} else if (arg == "--fp8") {
|
||||
qMode = nanovdb::GridType::Fp8;
|
||||
} else if (arg == "--fp16") {
|
||||
qMode = nanovdb::GridType::Fp16;
|
||||
} else if (arg == "--fpN") {
|
||||
qMode = nanovdb::GridType::FpN;
|
||||
} else if (arg == "-h" || arg == "--help") {
|
||||
usage(argv[0], EXIT_SUCCESS);
|
||||
} else if (arg == "-b" || arg == "--blosc") {
|
||||
codec = nanovdb::io::Codec::BLOSC;
|
||||
} else if (arg == "-d" || arg == "--dither") {
|
||||
dither = true;
|
||||
} else if (arg == "-z" || arg == "--zip") {
|
||||
codec = nanovdb::io::Codec::ZIP;
|
||||
} else if (arg == "-c" || arg == "--checksum") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "Expected a mode to follow the -c,--checksum option\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
std::string str(argv[++i]);
|
||||
toLowerCase(str);
|
||||
if (str == "none") {
|
||||
cMode = nanovdb::ChecksumMode::Disable;
|
||||
} else if (str == "partial") {
|
||||
cMode = nanovdb::ChecksumMode::Partial;
|
||||
} else if (str == "full") {
|
||||
cMode = nanovdb::ChecksumMode::Full;
|
||||
} else {
|
||||
std::cerr << "Expected one of the following checksum modes: {none, partial, full}\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
} else if (arg == "-s" || arg == "--stats") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "Expected a mode to follow the -s,--stats option\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
std::string str(argv[++i]);
|
||||
toLowerCase(str);
|
||||
if (str == "none") {
|
||||
sMode = nanovdb::StatsMode::Disable;
|
||||
} else if (str == "bbox") {
|
||||
sMode = nanovdb::StatsMode::BBox;
|
||||
} else if (str == "extrema") {
|
||||
sMode = nanovdb::StatsMode::MinMax;
|
||||
} else if (str == "all") {
|
||||
sMode = nanovdb::StatsMode::All;
|
||||
} else {
|
||||
std::cerr << "Expected one of the following stats modes: {none, bbox, extrema, all}\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
} else if (arg == "-a" || arg == "--abs-error") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "Expected a float to follow the -a,--abs-error option\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
qMode = nanovdb::GridType::FpN;
|
||||
absolute = true;
|
||||
tolerance = atof(argv[++i]);
|
||||
}
|
||||
} else if (arg == "-r" || arg == "--rel-error") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "Expected a float to follow the -r,--rel-error option\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
qMode = nanovdb::GridType::FpN;
|
||||
absolute = false;
|
||||
tolerance = atof(argv[++i]);
|
||||
}
|
||||
} else if (arg == "-g" || arg == "--grid") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "Expected a grid name to follow the -g,--grid option\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
gridName.assign(argv[++i]);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "\nIllegal option: \"" << arg << "\"\n";
|
||||
usage(argv[0]);
|
||||
}
|
||||
} else if (!arg.empty()) {
|
||||
fileNames.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (fileNames.size() < 2) {
|
||||
std::cerr << "Expected at least one input file followed by exactly one output file\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
const std::string outputFile = fileNames.back();
|
||||
const std::string ext = outputFile.substr(outputFile.find_last_of(".") + 1);
|
||||
bool toNanoVDB = false;
|
||||
if (ext == "nvdb") {
|
||||
toNanoVDB = true;
|
||||
} else if (ext != "vdb") {
|
||||
std::cerr << "Unrecognized file extension: \"" << ext << "\"\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
fileNames.pop_back();
|
||||
|
||||
if (!overwrite) {
|
||||
std::ifstream is(outputFile, std::ios::in | std::ios::binary);
|
||||
if (is.peek() != std::ifstream::traits_type::eof()) {
|
||||
std::cout << "Overwrite the existing output file named \"" << outputFile << "\"? [Y]/N: ";
|
||||
std::string answer;
|
||||
getline(std::cin, answer);
|
||||
toLowerCase(answer);
|
||||
if (!answer.empty() && answer != "y" && answer != "yes") {
|
||||
std::cout << "Please specify a different output file" << std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openvdb::initialize();
|
||||
|
||||
// Note, unlike OpenVDB, NanoVDB allows for multiple write operations into the same output file stream.
|
||||
// Hence, NanoVDB grids can be read, converted and written to file one at a time whereas all
|
||||
// the OpenVDB grids has to be written to file in a single operation.
|
||||
|
||||
auto openToNano = [&](const openvdb::GridBase::Ptr& base)
|
||||
{
|
||||
if (auto floatGrid = openvdb::GridBase::grid<openvdb::FloatGrid>(base)) {
|
||||
switch (qMode) {
|
||||
case nanovdb::GridType::Fp4: {
|
||||
nanovdb::OpenToNanoVDB<float, nanovdb::Fp4> s;
|
||||
s.enableDithering(dither);
|
||||
return s(*floatGrid, sMode, cMode, verbose ? 1 : 0);
|
||||
}
|
||||
case nanovdb::GridType::Fp8: {
|
||||
nanovdb::OpenToNanoVDB<float, nanovdb::Fp8> s;
|
||||
s.enableDithering(dither);
|
||||
return s(*floatGrid, sMode, cMode, verbose ? 1 : 0);
|
||||
}
|
||||
case nanovdb::GridType::Fp16: {
|
||||
nanovdb::OpenToNanoVDB<float, nanovdb::Fp16> s;
|
||||
s.enableDithering(dither);
|
||||
return s(*floatGrid, sMode, cMode, verbose ? 1 : 0);
|
||||
}
|
||||
case nanovdb::GridType::FpN: {
|
||||
if (absolute) {
|
||||
nanovdb::OpenToNanoVDB<float, nanovdb::FpN, nanovdb::AbsDiff> s;
|
||||
s.enableDithering(dither);
|
||||
s.oracle() = nanovdb::AbsDiff(tolerance);
|
||||
return s(*floatGrid, sMode, cMode, verbose ? 1 : 0);
|
||||
} else {
|
||||
nanovdb::OpenToNanoVDB<float, nanovdb::FpN, nanovdb::RelDiff> s;
|
||||
s.enableDithering(dither);
|
||||
s.oracle() = nanovdb::RelDiff(tolerance);
|
||||
return s(*floatGrid, sMode, cMode, verbose ? 1 : 0);
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}// end of switch
|
||||
}
|
||||
return nanovdb::openToNanoVDB(base, sMode, cMode, verbose ? 1 : 0);
|
||||
};
|
||||
try {
|
||||
if (toNanoVDB) { // OpenVDB -> NanoVDB
|
||||
std::ofstream os(outputFile, std::ios::out | std::ios::binary);
|
||||
for (auto& inputFile : fileNames) {
|
||||
if (inputFile.substr(inputFile.find_last_of(".") + 1) != "vdb") {
|
||||
std::cerr << "Since the last file has extension .nvdb the remaining input files were expected to have extensions .vdb\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
if (verbose)
|
||||
std::cout << "Opening OpenVDB file named \"" << inputFile << "\"" << std::endl;
|
||||
openvdb::io::File file(inputFile);
|
||||
file.open(false); //disable delayed loading
|
||||
if (gridName.empty()) {// convert all grid in the file
|
||||
auto grids = file.getGrids();
|
||||
for (auto& grid : *grids) {
|
||||
if (verbose) {
|
||||
std::cout << "Converting OpenVDB grid named \"" << grid->getName() << "\" to NanoVDB" << std::endl;
|
||||
}
|
||||
auto handle = openToNano(grid);
|
||||
nanovdb::io::writeGrid(os, handle, codec);
|
||||
} // loop over OpenVDB grids in file
|
||||
} else {// convert only grid with matching name
|
||||
auto grid = file.readGrid(gridName);
|
||||
if (verbose) {
|
||||
std::cout << "Converting OpenVDB grid named \"" << grid->getName() << "\" to NanoVDB" << std::endl;
|
||||
}
|
||||
auto handle = openToNano(grid);
|
||||
nanovdb::io::writeGrid(os, handle, codec);
|
||||
}
|
||||
} // loop over input files
|
||||
} else { // NanoVDB -> OpenVDB
|
||||
openvdb::io::File file(outputFile);
|
||||
openvdb::GridPtrVecPtr grids(new openvdb::GridPtrVec());
|
||||
for (auto& inputFile : fileNames) {
|
||||
if (inputFile.substr(inputFile.find_last_of(".") + 1) != "nvdb") {
|
||||
std::cerr << "Since the last file has extension .vdb the remaining input files were expected to have extensions .nvdb\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
if (verbose)
|
||||
std::cout << "Opening NanoVDB file named \"" << inputFile << "\"" << std::endl;
|
||||
if (gridName.empty()) {
|
||||
auto handles = nanovdb::io::readGrids(inputFile, verbose);
|
||||
for (auto &h : handles) {
|
||||
if (verbose)
|
||||
std::cout << "Converting NanoVDB grid named \"" << h.gridMetaData()->shortGridName() << "\" to OpenVDB" << std::endl;
|
||||
grids->push_back(nanoToOpenVDB(h));
|
||||
}
|
||||
} else {
|
||||
auto handle = nanovdb::io::readGrid(inputFile, gridName);
|
||||
if (!handle) {
|
||||
std::cerr << "File did not contain a NanoVDB grid named \"" << gridName << "\"\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
if (verbose)
|
||||
std::cout << "Converting NanoVDB grid named \"" << handle.gridMetaData()->shortGridName() << "\" to OpenVDB" << std::endl;
|
||||
grids->push_back(nanoToOpenVDB(handle));
|
||||
}
|
||||
} // loop over input files
|
||||
file.write(*grids);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "Exception oof unexpected type caught" << std::endl;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return exitStatus;
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/*!
|
||||
\file nanovdb_print.cc
|
||||
|
||||
\author Ken Museth
|
||||
|
||||
\date May 21, 2020
|
||||
|
||||
\brief Command-line tool that prints information about grids in a nanovdb file
|
||||
*/
|
||||
|
||||
#include <nanovdb/util/IO.h> // this is required to read (and write) NanoVDB files on the host
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE)
|
||||
{
|
||||
std::cerr << "\nUsage: " << progName << " [options] *.nvdb\n"
|
||||
<< "Which: Prints grid information from one or more NanoVDB files\n\n"
|
||||
<< "Options:\n"
|
||||
<< "-g,--grid name\tPrint all grids matching the specified string name\n"
|
||||
<< "-h,--help\tPrints this message\n"
|
||||
<< "-l,--long\tPrints out extra grid information\n"
|
||||
<< "-s,--short\tOnly prints out a minimum amount of grid information\n"
|
||||
<< "-v,--verbose\tPrint information about the meaning of the labels\n"
|
||||
<< "--version\tPrint version information to the terminal\n";
|
||||
exit(exitStatus);
|
||||
}
|
||||
|
||||
void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS)
|
||||
{
|
||||
printf("\n%s was build against NanoVDB version %s\n", progName, nanovdb::Version().c_str());
|
||||
exit(exitStatus);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int exitStatus = EXIT_SUCCESS;
|
||||
|
||||
enum Mode : int { Short = 0,
|
||||
Default = 1,
|
||||
Long = 2 } mode = Default;
|
||||
bool verbose = false;
|
||||
std::string gridName;
|
||||
std::vector<std::string> fileNames;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
if (arg[0] == '-') {
|
||||
if (arg == "-h" || arg == "--help") {
|
||||
usage(argv[0], EXIT_SUCCESS);
|
||||
} else if (arg == "--version") {
|
||||
version(argv[0]);
|
||||
} else if (arg == "-s" || arg == "--short") {
|
||||
mode = Short;
|
||||
} else if (arg == "-l" || arg == "--long") {
|
||||
mode = Long;
|
||||
} else if (arg == "-v" || arg == "--verbose") {
|
||||
verbose = true;
|
||||
} else if (arg == "-g" || arg == "--grid") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "\nExpected a grid name to follow the -g,--grid option\n";
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
gridName.assign(argv[++i]);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "\nIllegal option: \"" << arg << "\"\n";
|
||||
usage(argv[0]);
|
||||
}
|
||||
} else if (!arg.empty()) {
|
||||
fileNames.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (fileNames.size() == 0) {
|
||||
std::cerr << "\nExpected at least one input NanoVDB file\n";
|
||||
usage(argv[0]);
|
||||
}
|
||||
const auto nameKey = nanovdb::io::stringHash(gridName);
|
||||
|
||||
auto format = [](uint64_t b) {
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(4);
|
||||
if (b >> 40) {
|
||||
ss << double(b) / double(1ULL << 40) << " TB";
|
||||
} else if (b >> 30) {
|
||||
ss << double(b) / double(1ULL << 30) << " GB";
|
||||
} else if (b >> 20) {
|
||||
ss << double(b) / double(1ULL << 20) << " MB";
|
||||
} else if (b >> 10) {
|
||||
ss << double(b) / double(1ULL << 10) << " KB";
|
||||
} else {
|
||||
ss << b << " Bytes";
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
const int padding = 2;
|
||||
|
||||
auto width = [&](size_t& n, const std::string& str) {
|
||||
const auto size = str.length() + padding;
|
||||
if (size > n)
|
||||
n = size;
|
||||
};
|
||||
auto vec3RToStr = [](const nanovdb::Vec3R& v) {
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(3);
|
||||
ss << "(" << v[0] << "," << v[1] << "," << v[2] << ")";
|
||||
return ss.str();
|
||||
};
|
||||
auto wbboxToStr = [](const nanovdb::BBox<nanovdb::Vec3d>& bbox) {
|
||||
std::stringstream ss;
|
||||
if (bbox.empty()) {
|
||||
ss << "empty grid";
|
||||
} else {
|
||||
ss << std::setprecision(3);
|
||||
ss << "(" << bbox[0][0] << "," << bbox[0][1] << "," << bbox[0][2] << ")";
|
||||
ss << " -> ";
|
||||
ss << "(" << bbox[1][0] << "," << bbox[1][1] << "," << bbox[1][2] << ")";
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
auto ibboxToStr = [](const nanovdb::CoordBBox& bbox) {
|
||||
std::stringstream ss;
|
||||
if (bbox.empty()) {
|
||||
ss << "empty grid";
|
||||
} else {
|
||||
ss << "(" << bbox[0][0] << "," << bbox[0][1] << "," << bbox[0][2] << ")";
|
||||
ss << " -> ";
|
||||
ss << "(" << bbox[1][0] << "," << bbox[1][1] << "," << bbox[1][2] << ")";
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
auto resToStr = [](const nanovdb::CoordBBox& bbox) {
|
||||
std::stringstream ss;
|
||||
auto dim = bbox.dim();
|
||||
ss << dim[0] << " x " << dim[1] << " x " << dim[2];
|
||||
return ss.str();
|
||||
};
|
||||
auto nodesToStr = [](const uint32_t* nodes) {
|
||||
std::stringstream ss;
|
||||
ss << nodes[2] << "->" << nodes[1] << "->" << nodes[0];
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
try {
|
||||
for (auto& file : fileNames) {
|
||||
auto list = nanovdb::io::readGridMetaData(file);
|
||||
if (!gridName.empty()) {
|
||||
std::vector<nanovdb::io::GridMetaData> tmp;
|
||||
for (auto& m : list) {
|
||||
if (nameKey == m.nameKey && gridName == m.gridName)
|
||||
tmp.emplace_back(m);
|
||||
}
|
||||
list = tmp;
|
||||
}
|
||||
if (list.size() == 0)
|
||||
continue;
|
||||
const auto numberWidth = std::to_string(list.size()).length() + padding;
|
||||
auto nameWidth = std::string("Name").length() + padding;
|
||||
auto typeWidth = std::string("Type").length() + padding;
|
||||
auto classWidth = std::string("Class").length() + padding;
|
||||
auto codecWidth = std::string("Codec").length() + padding;
|
||||
auto ibboxWidth = std::string("Index Bounding Box").length() + padding;
|
||||
auto wbboxWidth = std::string("World BBox").length() + padding;
|
||||
auto sizeWidth = std::string("Size").length() + padding;
|
||||
auto fileWidth = std::string("File").length() + padding;
|
||||
auto voxelsWidth = std::string("# Voxels").length() + padding;
|
||||
auto voxelSizeWidth = std::string("Scale").length() + padding;
|
||||
auto versionWidth = std::string("Version").length() + padding;
|
||||
auto configWidth = std::string("32^3->16^3->8^3").length() + padding;
|
||||
auto tileWidth = std::string("# Active tiles").length() + padding;
|
||||
auto resWidth = std::string("Resolution").length() + padding;
|
||||
for (auto& m : list) {
|
||||
width(nameWidth, m.gridName);
|
||||
width(typeWidth, nanovdb::toStr(m.gridType));
|
||||
width(classWidth, nanovdb::toStr(m.gridClass));
|
||||
width(codecWidth, nanovdb::io::toStr(m.codec));
|
||||
width(wbboxWidth, wbboxToStr(m.worldBBox));
|
||||
width(ibboxWidth, ibboxToStr(m.indexBBox));
|
||||
width(resWidth, resToStr(m.indexBBox));
|
||||
width(sizeWidth, format(m.gridSize));
|
||||
width(fileWidth, format(m.fileSize));
|
||||
width(versionWidth, std::string(m.version.c_str()));
|
||||
width(configWidth, nodesToStr(m.nodeCount));
|
||||
width(tileWidth, nodesToStr(m.tileCount));
|
||||
width(voxelsWidth, std::to_string(m.voxelCount));
|
||||
width(voxelSizeWidth, vec3RToStr(m.voxelSize));
|
||||
}
|
||||
std::cout << "\nThe file \"" << file << "\" contains the following ";
|
||||
if (list.size()>1) {
|
||||
std::cout << list.size() << " grids:\n";
|
||||
} else {
|
||||
std::cout << "grid:\n";
|
||||
}
|
||||
std::cout << std::left << std::setw(numberWidth) << "#"
|
||||
<< std::left << std::setw(nameWidth) << "Name"
|
||||
<< std::left << std::setw(typeWidth) << "Type";
|
||||
if (mode != Short) {
|
||||
std::cout << std::left << std::setw(classWidth) << "Class"
|
||||
<< std::left << std::setw(versionWidth) << "Version"
|
||||
<< std::left << std::setw(codecWidth) << "Codec"
|
||||
<< std::left << std::setw(sizeWidth) << "Size"
|
||||
<< std::left << std::setw(fileWidth) << "File"
|
||||
<< std::left << std::setw(voxelSizeWidth) << "Scale";
|
||||
}
|
||||
std::cout << std::left << std::setw(voxelsWidth) << "# Voxels"
|
||||
<< std::left << std::setw(resWidth) << "Resolution";
|
||||
if (mode == Long) {
|
||||
std::cout << std::left << std::setw(configWidth) << "32^3->16^3->8^3"
|
||||
<< std::left << std::setw(tileWidth) << "# Active tiles"
|
||||
<< std::left << std::setw(ibboxWidth) << "Index Bounding Box"
|
||||
<< std::left << std::setw(wbboxWidth) << "World Bounding Box";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
int n = 0;
|
||||
for (auto& m : list) {
|
||||
if (!gridName.empty() && (nameKey != m.nameKey || gridName != m.gridName))
|
||||
continue;
|
||||
std::cout << std::left << std::setw(numberWidth) << ++n
|
||||
<< std::left << std::setw(nameWidth) << m.gridName
|
||||
<< std::left << std::setw(typeWidth) << nanovdb::toStr(m.gridType);
|
||||
if (mode != Short) {
|
||||
std::cout << std::left << std::setw(classWidth) << nanovdb::toStr(m.gridClass)
|
||||
<< std::left << std::setw(versionWidth) << std::string(m.version.c_str())
|
||||
<< std::left << std::setw(codecWidth) << nanovdb::io::toStr(m.codec)
|
||||
<< std::left << std::setw(sizeWidth) << format(m.gridSize)
|
||||
<< std::left << std::setw(fileWidth) << format(m.fileSize)
|
||||
<< std::left << std::setw(voxelSizeWidth) << vec3RToStr(m.voxelSize);
|
||||
}
|
||||
std::cout << std::left << std::setw(voxelsWidth) << m.voxelCount
|
||||
<< std::left << std::setw(resWidth) << resToStr(m.indexBBox);
|
||||
if (mode == Long) {
|
||||
std::cout << std::left << std::setw(configWidth) << nodesToStr(m.nodeCount)
|
||||
<< std::left << std::setw(tileWidth) << nodesToStr(m.tileCount)
|
||||
<< std::left << std::setw(ibboxWidth) << ibboxToStr(m.indexBBox)
|
||||
<< std::left << std::setw(wbboxWidth) << wbboxToStr(m.worldBBox);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
size_t w = 0;
|
||||
switch (mode) {
|
||||
case Mode::Short:
|
||||
width(w, "\"Name\":");
|
||||
width(w, "\"Type\":");
|
||||
width(w, "\"# Voxels\":");
|
||||
width(w, "\"Resolution\":");
|
||||
std::cout << std::left << std::setw(w) << "\n\"Name\":" << "name of a grid. Note that it is optional and hence might be empty."
|
||||
<< std::left << std::setw(w) << "\n\"Type\":" << "static type of the values in a grid, e.g. float, vec3f etc."
|
||||
<< std::left << std::setw(w) << "\n\"# Voxels\":" << "total number of active values in a grid."
|
||||
<< std::left << std::setw(w) << "\n\"Resolution\":" << "Efficient resolution of all the active values in a grid!\n";
|
||||
break;
|
||||
case Mode::Default:
|
||||
width(w, "\"Name\":");
|
||||
width(w, "\"Type\":");
|
||||
width(w, "\"Class\":");
|
||||
width(w, "\"Version\":");
|
||||
width(w, "\"Codec\":");
|
||||
width(w, "\"Size\":");
|
||||
width(w, "\"File\":");
|
||||
width(w, "\"Scale\":");
|
||||
width(w, "\"# Voxels\":");
|
||||
width(w, "\"Resolution\":");
|
||||
std::cout << std::left << std::setw(w) << "\n\"Name\":" << "name of a grid. Note that it is optional and hence might be empty."
|
||||
<< std::left << std::setw(w) << "\n\"Type\":" << "static type of the values in a grid, e.g. float, vec3f etc."
|
||||
<< std::left << std::setw(w) << "\n\"Class\":" << "class of the grid, e.g. FOG for Fog volume, LS for level set, etc."
|
||||
<< std::left << std::setw(w) << "\n\"Version\":" << "major.minor.patch version numbers of the grid."
|
||||
<< std::left << std::setw(w) << "\n\"Codec\":" << "codec of the optional compression applied to the out-of-core grid, i.e. on disk."
|
||||
<< std::left << std::setw(w) << "\n\"Size\":" << "In-core memory footprint of the grid, i.e. in ram."
|
||||
<< std::left << std::setw(w) << "\n\"File\":" << "Out-of-core memory footprint of the grid, i.e. on disk."
|
||||
<< std::left << std::setw(w) << "\n\"Scale\":" << "Scale of the grid, i.e. the size of a voxel in world units."
|
||||
<< std::left << std::setw(w) << "\n\"# Voxels\":" << "total number of active values in a grid."
|
||||
<< std::left << std::setw(w) << "\n\"Resolution\":" << "Efficient resolution of all the active values in a grid!\n";
|
||||
break;
|
||||
case Mode::Long:
|
||||
width(w, "\"Name\":");
|
||||
width(w, "\"Type\":");
|
||||
width(w, "\"Class\":");
|
||||
width(w, "\"Version\":");
|
||||
width(w, "\"Codec\":");
|
||||
width(w, "\"Size\":");
|
||||
width(w, "\"File\":");
|
||||
width(w, "\"Scale\":");
|
||||
width(w, "\"# Voxels\":");
|
||||
width(w, "\"Resolution\":");
|
||||
width(w, "\"32^3->16^3->8^3\":");
|
||||
width(w, "\"# Active tiles\":");
|
||||
width(w, "\"Index Bounding Box\":");
|
||||
width(w, "\"World Bounding Box\":");
|
||||
std::cout << std::left << std::setw(w) << "\n\"Name\":" << "name of a grid. Note that it is optional and hence might be empty."
|
||||
<< std::left << std::setw(w) << "\n\"Type\":" << "static type of the values in a grid, e.g. float, vec3f etc."
|
||||
<< std::left << std::setw(w) << "\n\"Class\":" << "class of the grid, e.g. FOG for Fog volume, LS for level set, etc."
|
||||
<< std::left << std::setw(w) << "\n\"Version\":" << "major.minor.patch version numbers of the grid."
|
||||
<< std::left << std::setw(w) << "\n\"Codec\":" << "codec of the optional compression applied to the out-of-core grid, i.e. on disk."
|
||||
<< std::left << std::setw(w) << "\n\"Size\":" << "In-core memory footprint of the grid, e.g. in RAM on the CPU."
|
||||
<< std::left << std::setw(w) << "\n\"File\":" << "Out-of-core memory footprint of the grid, i.e. compressed on disk."
|
||||
<< std::left << std::setw(w) << "\n\"Scale\":" << "Scale of the grid, i.e. the size of a voxel in world units."
|
||||
<< std::left << std::setw(w) << "\n\"# Voxels\":" << "total number of active values in a grid. Note this includes both active tiles and voxels."
|
||||
<< std::left << std::setw(w) << "\n\"Resolution\":" << "Efficient resolution of all the active values in a grid!"
|
||||
<< std::left << std::setw(w) << "\n\"32^3->16^3->8^3\":" << "Number of nodes at each level of the tree structure from the root to leaf level."
|
||||
<< std::left << std::setw(w) << "\n\"# Active tiles\":" << "Number of active tiles at each level of the tree structure from the root to leaf level."
|
||||
<< std::left << std::setw(w) << "\n\"Index Bounding Box\":" << "coordinate bounding box of all the active values in a grid. Note that both min and max coordinates are inclusive!"
|
||||
<< std::left << std::setw(w) << "\n\"World Bounding Box\":" << "world-space bounding box of all the active values in a grid. Note that min is inclusive and max is exclusive!\n";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Internal error in switch!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "Exception oof unexpected type caught" << std::endl;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return exitStatus;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/*!
|
||||
\file nanovdb_validate.cc
|
||||
|
||||
\author Ken Museth
|
||||
|
||||
\date October 13, 2020
|
||||
|
||||
\brief Command-line tool that validates Grids in nanovdb files
|
||||
*/
|
||||
|
||||
#include <nanovdb/util/IO.h> // this is required to read (and write) NanoVDB files on the host
|
||||
#include <nanovdb/util/GridValidator.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
void usage [[noreturn]] (const std::string& progName, int exitStatus = EXIT_FAILURE)
|
||||
{
|
||||
std::cerr << "\nUsage: " << progName << " [options] *.nvdb\n"
|
||||
<< "Which: Validates grids in one or more NanoVDB files\n\n"
|
||||
<< "Options:\n"
|
||||
<< "-g,--grid name\tOnly validate grids matching the specified string name\n"
|
||||
<< "-h,--help\tPrints this message\n"
|
||||
<< "-v,--verbose\tPrint verbose information information useful for debugging\n"
|
||||
<< "--version\tPrint version information to the terminal\n";
|
||||
exit(exitStatus);
|
||||
}
|
||||
|
||||
void version [[noreturn]] (const char* progName, int exitStatus = EXIT_SUCCESS)
|
||||
{
|
||||
printf("\n%s was build against NanoVDB version %s\n", progName, nanovdb::Version().c_str());
|
||||
exit(exitStatus);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int exitStatus = EXIT_SUCCESS;
|
||||
|
||||
bool verbose = false;
|
||||
bool detailed = true;
|
||||
std::string gridName;
|
||||
std::vector<std::string> fileNames;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
if (arg[0] == '-') {
|
||||
if (arg == "-h" || arg == "--help") {
|
||||
usage(argv[0], EXIT_SUCCESS);
|
||||
} else if (arg == "--version") {
|
||||
version(argv[0]);
|
||||
} else if (arg == "-v" || arg == "--verbose") {
|
||||
verbose = true;
|
||||
} else if (arg == "-g" || arg == "--grid") {
|
||||
if (i + 1 == argc) {
|
||||
std::cerr << "\nExpected a grid name to follow the -g,--grid option\n";
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
gridName.assign(argv[++i]);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "\nIllegal option: \"" << arg << "\"\n";
|
||||
usage(argv[0]);
|
||||
}
|
||||
} else if (!arg.empty()) {
|
||||
fileNames.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (fileNames.size() == 0) {
|
||||
std::cerr << "\nExpected at least one input NanoVDB file\n";
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
const auto nameKey = nanovdb::io::stringHash(gridName);
|
||||
|
||||
try {
|
||||
for (auto& file : fileNames) {
|
||||
auto list = nanovdb::io::readGridMetaData(file);
|
||||
if (!gridName.empty()) {
|
||||
std::vector<nanovdb::io::GridMetaData> tmp;
|
||||
for (auto& m : list) {
|
||||
if (nameKey == m.nameKey && gridName == m.gridName)
|
||||
tmp.emplace_back(m);
|
||||
}
|
||||
list = tmp;
|
||||
}
|
||||
if (list.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "\nThe file \"" << file << "\" contains the following matching " << list.size() << " grid(s):\n";
|
||||
}
|
||||
|
||||
for (auto& m : list) {
|
||||
auto handle = nanovdb::io::readGrid(file, m.gridName);
|
||||
auto gridType = handle.gridType();
|
||||
bool test = false;
|
||||
if (gridType == nanovdb::GridType::End) {
|
||||
std::cerr << "GridHandle was empty\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
} else if (auto* grid = handle.grid<float>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::Vec3f>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<uint32_t>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<int32_t>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<int16_t>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<int64_t>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<int16_t>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<double>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::Vec3d>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::ValueMask>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::Rgba8>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::Fp4>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::Fp8>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::Fp16>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<nanovdb::FpN>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else if (auto* grid = handle.grid<bool>()) {
|
||||
test = isValid(*grid, detailed, verbose);
|
||||
} else {
|
||||
std::cerr << "Unsupported GridType: \"" << nanovdb::toStr(gridType) << "\"\n" << std::endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
if (verbose) {
|
||||
std::cout << "Grid named \"" << m.gridName << "\": " << (test ? "passed" : "failed") << std::endl;
|
||||
} else if (!test) {
|
||||
std::cout << "Grid named \"" << m.gridName << "\": failed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "Exception oof unexpected type caught" << std::endl;
|
||||
exitStatus = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return exitStatus;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# find_package(doxygen REQUIRED dot )
|
||||
if(WIN32)
|
||||
set(DOXYGEN_EXECUTABLE "C:/Program Files/doxygen/bin/doxygen.exe")
|
||||
else()
|
||||
set(DOXYGEN_EXECUTABLE "doxygen")
|
||||
endif()
|
||||
|
||||
message(STATUS "DOXYGEN_EXECUTABLE = ${DOXYGEN_EXECUTABLE}")
|
||||
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/doxygen-config DOXYGEN_CONFIG_CONTENT)
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cmake-doxygen-config
|
||||
${DOXYGEN_CONFIG_CONTENT})
|
||||
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/cmake-doxygen-config
|
||||
"OUTPUT_DIRECTORY=\"${CMAKE_CURRENT_BINARY_DIR}/docs\"\n")
|
||||
|
||||
add_custom_target(
|
||||
nanovdb_docs
|
||||
SOURCES doxygen-config
|
||||
doc.md
|
||||
codingstyle.txt
|
||||
FAQ.md
|
||||
SourceTree.md
|
||||
HowToBuild.md
|
||||
HelloWorld.md
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/cmake-doxygen-config
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen"
|
||||
VERBATIM)
|
||||
|
||||
install(
|
||||
CODE "EXECUTE_PROCESS(COMMAND \"${CMAKE_COMMAND}\" --build \"${PROJECT_BINARY_DIR}\" --target nanovdb_docs)"
|
||||
)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs/html DESTINATION docs)
|
||||
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
|
||||
@page codingStyle Coding Style
|
||||
|
||||
@section Introduction
|
||||
|
||||
NanoVDB coding practices.
|
||||
|
||||
@section sStyleContents Contents
|
||||
- @ref sNamingConventions
|
||||
- @ref sNamespaceConventions
|
||||
- @ref sClassConventions
|
||||
- @ref sClassMethods
|
||||
- @ref sClassInstanceVariables
|
||||
- @ref sClassStaticVariables
|
||||
- @ref sLocalVariablesAndArguments
|
||||
- @ref sConstants
|
||||
- @ref sEnumerationNames
|
||||
- @ref sEnumerationValues
|
||||
- @ref sTypedefs
|
||||
- @ref sGlobalVariables
|
||||
- @ref sGlobalFunctions
|
||||
- @ref sBooleans
|
||||
- @ref sPractices
|
||||
- @ref sGeneral
|
||||
- @ref sFormatting
|
||||
- @ref sIncludeStatements
|
||||
- @ref sComments
|
||||
- @ref sPrimitiveTypes
|
||||
- @ref sMacros
|
||||
- @ref sClasses
|
||||
- @ref sConditionalStatements
|
||||
- @ref sNamespaces
|
||||
- @ref sExceptions
|
||||
- @ref sTemplates
|
||||
- @ref sMiscellaneous
|
||||
|
||||
@section sNamingConventions Naming Conventions
|
||||
|
||||
|
||||
@subsection sNamespaceConventions Namespaces
|
||||
-# Lowercase words, keep simple and short (e.g., @c tools, @c tree).
|
||||
-# Use @c internal (or @c detail) or <TT><I>module</I>_internal</TT>
|
||||
for symbols such as templates that must be defined in header files
|
||||
but that are implementation details not intended for public use.
|
||||
|
||||
|
||||
@subsection sClassConventions Classes and Structs
|
||||
-# Mixed case; first letter uppercase (e.g., @c AffineMap, @c TreeIterator)
|
||||
-# Do not use a prefix.
|
||||
|
||||
|
||||
@subsection sClassMethods Class Methods
|
||||
-# Mixed case; first letter lowercase (e.g., <TT>getAccessor()</TT>, <TT>gridType()</TT>)
|
||||
-# Accessor methods that return a member variable by reference or a primitive type
|
||||
by value are just the variable name (e.g., <TT>Grid::tree()</TT>).
|
||||
-# Accessor methods that involve construction of objects or other computations are
|
||||
@c get + the variable name (e.g., <TT>Grid::getAccessor()</TT>).
|
||||
-# Simple mutators are @c set + the variable name (e.g., <TT>Grid::setTree(tree);</TT>).
|
||||
|
||||
|
||||
@subsection sClassInstanceVariables Class Instance Variables
|
||||
-# Mixed case; always prefixed by @c m (e.g., @c mTree, @c mTransform)
|
||||
-# The @c m prefix may be omitted for members of <TT>struct</TT>s
|
||||
used in the public API (e.g., <TT>struct Color { float r, g, b; }</TT>).
|
||||
|
||||
|
||||
@subsection sClassStaticVariables Class Static Variables
|
||||
-# Mixed case; always prefixed by @c s (e.g., @c sInitialized)
|
||||
|
||||
|
||||
@subsection sLocalVariablesAndArguments Local Variables and Arguments
|
||||
-# Use mixed case with an initial lower case letter (e.g., @c ijk, @c offset,
|
||||
@c range, @c rhsValue).
|
||||
|
||||
|
||||
@subsection sConstants Constants
|
||||
-# All uppercase; words separated by underscores. If not in a namespace or
|
||||
local to a source file, then prefixed with the library name in all caps
|
||||
(e.g., @c HALF_FLOAT_TYPENAME_SUFFIX, @c ZIP_COMPRESSION_LEVEL)
|
||||
|
||||
|
||||
@subsection sEnumerationNames Enumeration Names
|
||||
-# Mixed case; first letter uppercase (e.g., @c GridClass, @c VecType)
|
||||
|
||||
|
||||
@subsection sEnumerationValues Enumeration Values
|
||||
-# With @c enum, all uppercase with words separated by underscores
|
||||
(e.g., @c GRID_LEVEL_SET, @c VEC_INVARIANT) and with a common prefix
|
||||
-# With <TT>enum class</TT>, mixed case with the first letter uppercase
|
||||
(e.g., @c GridClass::Unknown, @c GridClass::LevelSet)
|
||||
|
||||
|
||||
@subsection sTypedefs Typedefs
|
||||
-# Mixed case; first letter uppercase (e.g., @c ConstPtr, @c ValueType)
|
||||
-# Do not use a prefix.
|
||||
|
||||
|
||||
@subsection sGlobalVariables Global Variables
|
||||
-# Mixed case; always prefixed by @c g (e.g., @c gRegistry)
|
||||
-# In general, try to use class static data instead of globals.
|
||||
|
||||
|
||||
@subsection sGlobalFunctions Global Functions
|
||||
-# Mixed case; always prefixed by @c g (e.g., <TT>gFunc()</TT>).
|
||||
-# In general, try to use class static members instead of global functions.
|
||||
|
||||
|
||||
@subsection sBooleans Booleans
|
||||
-# When naming boolean functions and variables, use names that read as a
|
||||
condition (e.g., <TT>if (grid.empty())</TT>,
|
||||
<TT>if (matrix.isInvertible())</TT>).
|
||||
|
||||
|
||||
@section sPractices Practices
|
||||
|
||||
|
||||
@subsection sGeneral General
|
||||
-# Code must compile without any warning messages at the default warning level.
|
||||
-# Prefer the C++ Standard Library to the C Standard Library.
|
||||
-# Restrict variables to the smallest scopes possible, and avoid defining
|
||||
local variables before giving them values. Prefer declarations inside
|
||||
conditionals: <TT>if (Grid::Ptr grid = createGrid()) { ... }</TT> instead of
|
||||
<TT>Grid::Ptr grid = createGrid(); if (grid) { ... }</TT>
|
||||
-# For new files, be sure to use the right license boilerplate per our license
|
||||
policy.
|
||||
|
||||
|
||||
@subsection sFormatting Formatting
|
||||
-# Indentation is 4 spaces. Do not use tabs.
|
||||
-# Lines are no more than 100 characters long.
|
||||
-# Use Unix-style carriage returns ("\n") rather than Windows/DOS ones ("\r\n").
|
||||
-# Do not leave debug <TT>printf</TT>s or other debugging code lying around.
|
||||
-# Leave a blank line between a group of variable declarations and other code.
|
||||
-# Leave a space after the keywords @c if, @c switch, @c while, @c do, @c for,
|
||||
and @c return.
|
||||
-# Leave a space on each side of binary operators such as @c +, @c -, @c *, @c /, @c &&,
|
||||
and @c ||. For clarity in mathematical situations, you may omit the spaces on
|
||||
either side of @c * and @c / operators to emphasize their precedence over @c + and @c -.
|
||||
-# Do not leave a space between any dereferencing operator
|
||||
(such as @c *, @c &, @c [], @c ->, or @c .) and its operands.
|
||||
-# In parameter lists, leave a space after each comma.
|
||||
-# Do not leave a space after an opening parenthesis or before a closing
|
||||
parenthesis.
|
||||
-# Parentheses should be used to clarify operator precedence in expressions.
|
||||
-# Do not leave a space before an end-of-statement semicolon.
|
||||
-# Do not use literal tabs in strings or character constants. Rather, use
|
||||
spaces or "\t".
|
||||
-# If a parameter list is too long, break it between parameters. Group related
|
||||
parameters on lines if appropriate.
|
||||
-# Modified spacing is allowed to vertically align repetitive expressions.
|
||||
-# Always begin numeric constants with a digit (e.g., 0.001 not .001).
|
||||
-# Use K&R-style brace placement in public code.
|
||||
-# You may leave off braces for simple, single line flow control statements.
|
||||
-# The return type in a function definition should go on a line by itself.
|
||||
|
||||
|
||||
@subsection sIncludeStatements Include Statements
|
||||
-# Always use double quotes ("") to include header files that live in the same
|
||||
directory as your source code.
|
||||
-# Use angle brackets (<>) to include header files from outside a file’s
|
||||
directory.
|
||||
-# Do not use absolute paths in include directives.
|
||||
-# If there is a header corresponding to a given source file, list it first,
|
||||
followed by other local headers, library headers and then system headers.
|
||||
|
||||
|
||||
@subsection sHeaderFiles Header Files
|
||||
-# Header files have a <TT>.h</TT> extension.
|
||||
-# All header files should be bracketed by @c \#ifdef "guard" statements.
|
||||
-# In class definitions, list public, then protected, then private members.
|
||||
-# List methods before variables.
|
||||
-# Fully prototype all public functions and use descriptive naming for each
|
||||
argument.
|
||||
-# Declare every function defined in a header but outside a class definition
|
||||
explicitly as @c inline.
|
||||
-# Prefer forward declarations to @c \#include directives in headers.
|
||||
-# Do not take advantage of indirect inclusion of header files.
|
||||
-# Do not use anonymous namespaces in header files.
|
||||
|
||||
|
||||
@subsection sSourceFiles Source Files
|
||||
-# Source files have a <TT>.cc</TT> extension.
|
||||
-# Properly prototype all file static functions with usefully named arguments.
|
||||
-# Whenever possible, put variables and functions in an anonymous namespace.
|
||||
-# Avoid global variables.
|
||||
|
||||
|
||||
@subsection sComments Comments
|
||||
-# Use @c // style comments instead of / * * / style, even for multi-line
|
||||
comments.
|
||||
-# Use multi-line comments to describe following paragraphs of code.
|
||||
-# Use end-of-line comments to describe variable declarations or to clarify a
|
||||
single statement.
|
||||
-# Large blocks of code should be commented out with <TT>\#if 0</TT> and @c \#endif.
|
||||
-# Do not leave obsolete code fragments within comments as an historical trail.
|
||||
-# Document public code with Doxygen comments, formatted as follows:
|
||||
@verbatim
|
||||
/// @brief Create a new grid of type @c GridType classified as a "Level Set",
|
||||
/// i.e., a narrow-band level set.
|
||||
///
|
||||
/// @param voxelSize the size of a voxel in world units
|
||||
/// @param halfWidth the half width of the narrow band in voxel units
|
||||
///
|
||||
/// @details The voxel size and the narrow band half width define the grid's
|
||||
/// background value as halfWidth*voxelWidth. The transform is linear
|
||||
/// with a uniform scaling only corresponding to the specified voxel size.
|
||||
///
|
||||
/// @note It is generally advisable to specify a half-width of the narrow band
|
||||
/// that is larger than one voxel unit, otherwise zero crossings are not guaranteed.
|
||||
template<typename GridType>
|
||||
typename GridType::Ptr createLevelSet(
|
||||
Real voxelSize = 1.0, Real halfWidth = LEVEL_SET_HALF_WIDTH);
|
||||
@endverbatim
|
||||
|
||||
|
||||
@subsection sPrimitiveTypes Primitive Types
|
||||
-# Avoid writing code that is dependent on the bit size of primitive values,
|
||||
but when specific bit sizes are required, use explicitly-sized types such as
|
||||
@c int32_t or @c uint64_t.
|
||||
|
||||
|
||||
@subsection sMacros Macros
|
||||
-# Avoid macros for constants. Use global static constants instead. (Local
|
||||
static constants are not guaranteed to be initialized in a thread-safe manner.)
|
||||
-# Avoid macro functions. Use @c inline and templates instead.
|
||||
|
||||
|
||||
@subsection sClasses Classes
|
||||
-# Constructors that can be called with only one argument should be prefixed
|
||||
with the @c explicit keyword to avoid unintended type conversions.
|
||||
-# Never call virtual methods from destructors.
|
||||
-# If you have a copy constructor, make sure you have an assignment operator.
|
||||
-# If you have an assignment operator, you probably need a copy constructor.
|
||||
-# If you have data members that are pointers to dynamically allocated memory,
|
||||
make sure you have a copy constructor and an assignment operator, both of
|
||||
which do the right thing with that memory.
|
||||
-# Classes which are to be subclassed always have a virtual destructor, even if
|
||||
it is empty.
|
||||
-# Check against self assignment and return <TT>*this</TT> in assignment
|
||||
operators.
|
||||
-# Declare methods as @c const wherever possible.
|
||||
-# Declare object-valued input arguments as const references wherever
|
||||
possible. Primitives may be passed by value, however.
|
||||
-# Arithmetic, logical, bitwise, dereference, and address of operators should
|
||||
only be used when their semantics are clear, obvious, and unambiguous.
|
||||
-# The application operator [ () ] is allowed for functors.
|
||||
-# Conversion operators should be avoided.
|
||||
-# Never return const references to stack allocated or implicitly computed
|
||||
objects.
|
||||
-# If a class does not have a copy constructor and/or assignment operator,
|
||||
consider creating a private unimplemented copy constructor and/or assignment
|
||||
operator to prevent automatically generated versions from being used.
|
||||
|
||||
|
||||
@subsection sConditionalStatements Conditional Statements
|
||||
-# For test expressions, use a form that indicates as clearly as possible the
|
||||
types of operands by avoiding implicit casts.
|
||||
-# Assignments that occur within conditional statements must have no effect in
|
||||
the enclosing scope.
|
||||
-# Allow for arithmetic imprecision when comparing floating point values.
|
||||
-# In switch statements, always comment fallthroughs and empty cases.
|
||||
|
||||
|
||||
@section sNamespaces Namespaces
|
||||
-# Namespaces should be used whenever possible.
|
||||
-# Avoid pulling in entire namespaces with @c using directives
|
||||
(e.g., <TT>using namespace std;</TT>).
|
||||
-# @c using declarations are allowed for individual symbols (e.g.,
|
||||
<TT>using std::vector;</TT>), but they should never appear in a header file.
|
||||
-# Define global operators in the namespace of their arguments.
|
||||
-# Namespaces are not indented.
|
||||
|
||||
|
||||
@subsection sExceptions Exceptions
|
||||
-# Appropriate use of exceptions is encouraged.
|
||||
-# Methods should declare all exceptions they might throw using comments,
|
||||
but not exception specifications.
|
||||
-# Throw scope local exception instances, not pointers or references or globals.
|
||||
-# Catch exceptions by reference.
|
||||
-# Never allow an exception to escape from a destructor.
|
||||
|
||||
|
||||
@subsection sTemplates Templates
|
||||
-# Use @c typename rather than @c class when declaring template type parameters.
|
||||
|
||||
|
||||
@subsection sMiscellaneous Miscellaneous
|
||||
-# Don’t use pointers to run through arrays of non-primitive types. Use explicit array indexing, iterators or generic algorithms instead.
|
||||
-# Use C++ casts (<TT>static_cast<int>(x)</TT> or <TT>int(x)</TT>),
|
||||
not C casts (<TT>(int)x</TT>).
|
||||
-# Multiple variables of the same data type may be declared on the same line
|
||||
if closely related.
|
||||
-# Library code must never deliberately terminate the application in response
|
||||
to an error condition.
|
||||
-# Avoid using malloc/free when new/delete can be used instead.
|
||||
-# Avoid @c goto.
|
||||
-# Avoid \"magic numbers\". Use named constants when necessary.
|
||||
-# If you use typeid/typeinfo, be aware that although all runtimes support
|
||||
<TT>typeinfo::name()</TT>, the format of the string it returns varies
|
||||
between compilers and even for a given compiler the value is not guaranteed
|
||||
to be unique.
|
||||
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CMake Configuration for NanoVDB Examples
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(NanoVDBExamples LANGUAGES CXX)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
###############################################################################
|
||||
|
||||
message(STATUS "----------------------------------------------------")
|
||||
message(STATUS "---------- Configuring NanoVDB Examples ------------")
|
||||
message(STATUS "----------------------------------------------------")
|
||||
|
||||
###############################################################################
|
||||
|
||||
if(WIN32)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/Release")
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------`
|
||||
# helper function
|
||||
# -----------------------------------------------------------------------------`
|
||||
function(NANOVDB_EXAMPLE)
|
||||
set(options OPENVDB)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs)
|
||||
cmake_parse_arguments(NANOVDB_EXAMPLE
|
||||
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
set(EXAMPLE_NAME ${NANOVDB_EXAMPLE_NAME})
|
||||
set(EXAMPLE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/${EXAMPLE_NAME}")
|
||||
|
||||
file(GLOB EXAMPLE_HEADER_FILES
|
||||
${EXAMPLE_ROOT}/*.h
|
||||
${EXAMPLE_ROOT}/*.inl
|
||||
${EXAMPLE_ROOT}/*.hh
|
||||
${EXAMPLE_ROOT}/*.hpp
|
||||
${EXAMPLE_ROOT}/*.cuh)
|
||||
|
||||
file(GLOB EXAMPLE_SOURCE_FILES
|
||||
${EXAMPLE_ROOT}/*.c
|
||||
${EXAMPLE_ROOT}/*.cc
|
||||
${EXAMPLE_ROOT}/*.cpp)
|
||||
|
||||
file(GLOB EXAMPLE_SOURCE_CUDA_FILES ${EXAMPLE_ROOT}/*.cu)
|
||||
|
||||
# configure CUDA
|
||||
if(NOT NANOVDB_USE_CUDA AND EXAMPLE_SOURCE_CUDA_FILES)
|
||||
message(WARNING " - CUDA required to build ${EXAMPLE_NAME}. Skipping.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NANOVDB_EXAMPLE_OPENVDB AND NOT NANOVDB_USE_OPENVDB)
|
||||
message(WARNING " - OpenVDB required to build ${EXAMPLE_NAME}. Skipping.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(${EXAMPLE_NAME}
|
||||
${EXAMPLE_SOURCE_FILES}
|
||||
${EXAMPLE_SOURCE_CUDA_FILES}
|
||||
${EXAMPLE_HEADER_FILES})
|
||||
|
||||
# Propagate MSVC Runtime from the OpenVDB library (if VDB_MSVC_RUNTIME_SELECTION
|
||||
# has been set then we're building and linking against OpenVDB, see the root
|
||||
# NanoVDB CMakeLists.txt)
|
||||
if(VDB_MSVC_RUNTIME_SELECTION)
|
||||
set_target_properties(${EXAMPLE_NAME} PROPERTIES
|
||||
MSVC_RUNTIME_LIBRARY ${VDB_MSVC_RUNTIME_SELECTION})
|
||||
endif()
|
||||
|
||||
target_include_directories(${EXAMPLE_NAME} PUBLIC ex_util)
|
||||
target_link_libraries(${EXAMPLE_NAME} PRIVATE nanovdb)
|
||||
|
||||
install(TARGETS ${EXAMPLE_NAME} DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples)
|
||||
endfunction()
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
if(NANOVDB_BUILD_BENCHMARK)
|
||||
add_subdirectory(benchmark)
|
||||
endif()
|
||||
|
||||
nanovdb_example(NAME "ex_make_custom_nanovdb")
|
||||
nanovdb_example(NAME "ex_make_funny_nanovdb")
|
||||
nanovdb_example(NAME "ex_make_typed_grids")
|
||||
nanovdb_example(NAME "ex_make_nanovdb_sphere")
|
||||
nanovdb_example(NAME "ex_write_nanovdb_grids")
|
||||
nanovdb_example(NAME "ex_openvdb_to_nanovdb" OPENVDB)
|
||||
nanovdb_example(NAME "ex_openvdb_to_nanovdb_accessor" OPENVDB)
|
||||
nanovdb_example(NAME "ex_openvdb_to_nanovdb_cuda" OPENVDB)
|
||||
nanovdb_example(NAME "ex_read_nanovdb_sphere")
|
||||
nanovdb_example(NAME "ex_read_nanovdb_sphere_accessor")
|
||||
nanovdb_example(NAME "ex_read_nanovdb_sphere_accessor_cuda")
|
||||
nanovdb_example(NAME "ex_modify_nanovdb_thrust")
|
||||
nanovdb_example(NAME "ex_map_pool_buffer")
|
||||
nanovdb_example(NAME "ex_bump_pool_buffer")
|
||||
nanovdb_example(NAME "ex_collide_level_set")
|
||||
nanovdb_example(NAME "ex_raytrace_fog_volume")
|
||||
nanovdb_example(NAME "ex_raytrace_level_set")
|
||||
|
||||
if(NANOVDB_USE_MAGICAVOXEL)
|
||||
nanovdb_example(NAME "ex_vox_to_nanovdb")
|
||||
endif()
|
||||
# add_subdirectory(ex_sph_benchmark)
|
||||
|
||||
# many of the sample projects depend on a data directory. This allows Debug
|
||||
# launching from the cmake binary working directory.
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/data")
|
||||
@@ -0,0 +1,108 @@
|
||||
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file BenchKernels_dense.cu
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief CUDA kernel for a simple ray-tracing benchmark test.
|
||||
|
||||
#include "DenseGrid.h"
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h> // for CUDA memory management
|
||||
#include <nanovdb/util/Ray.h> // for nanovdb::Ray
|
||||
#include <nanovdb/util/HDDA.h> // for nanovdb::DDA
|
||||
|
||||
#include "Image.h"
|
||||
#include "Camera.h"
|
||||
|
||||
// Comment out to disable timing of the CUDA kernel
|
||||
#define CUDA_TIMING
|
||||
|
||||
// This is called by the device
|
||||
__global__ void render_kernel(const nanovdb::DenseGrid<float>& grid,
|
||||
const nanovdb::Camera<float>& camera,
|
||||
nanovdb::Image& img)
|
||||
{
|
||||
using RealT = float;
|
||||
using Vec3T = nanovdb::Vec3<RealT>;
|
||||
using CoordT = nanovdb::Coord;
|
||||
using RayT = nanovdb::Ray<RealT>;
|
||||
using ColorRGB = nanovdb::Image::ColorRGB;
|
||||
|
||||
const int w = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int h = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if (w >= img.width() || h >= img.height()) return;
|
||||
RayT ray = camera.getRay(img.u(w), img.v(h));// ray in world space
|
||||
ray = ray.worldToIndexF(grid);// ray in index space
|
||||
if (ray.clip(grid.indexBBox().expandBy(-1))) {// clip to the index bounding box
|
||||
nanovdb::DDA<RayT> dda(ray);
|
||||
const float v0 = grid.getValue(dda.voxel());
|
||||
while( dda.step() ) {
|
||||
CoordT ijk = dda.voxel();
|
||||
const float v1 = grid.getValue(ijk);
|
||||
if (v0*v1>0) continue;
|
||||
#if 1// second-order central difference
|
||||
Vec3T grad(grid.getValue(ijk.offsetBy(1,0,0)) - grid.getValue(ijk.offsetBy(-1,0,0)),
|
||||
grid.getValue(ijk.offsetBy(0,1,0)) - grid.getValue(ijk.offsetBy(0,-1,0)),
|
||||
grid.getValue(ijk.offsetBy(0,0,1)) - grid.getValue(ijk.offsetBy(0,0,-1)));
|
||||
#else// first order single-sided difference
|
||||
Vec3T grad(-v0);
|
||||
ijk[0] += 1;
|
||||
grad[0] += grid.getValue(ijk);
|
||||
ijk[0] -= 1;
|
||||
ijk[1] += 1;
|
||||
grad[1] += grid.getValue(ijk);
|
||||
ijk[1] -= 1;
|
||||
ijk[2] += 1;
|
||||
grad[2] += grid.getValue(ijk);
|
||||
#endif
|
||||
grad *= rnorm3df(grad[0], grad[1], grad[2]);
|
||||
img(w, h) = ColorRGB(abs(grad.dot(ray.dir())), 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const int checkerboard = 1 << 7;
|
||||
img(w, h) = ((h & checkerboard) ^ (w & checkerboard)) ? ColorRGB(1, 1, 1) : ColorRGB(0, 0, 0);
|
||||
}
|
||||
|
||||
// This is called by the host
|
||||
extern "C" float launch_kernels(const nanovdb::DenseGridHandle<nanovdb::CudaDeviceBuffer>& gridHandle,
|
||||
nanovdb::ImageHandle<nanovdb::CudaDeviceBuffer>& imgHandle,
|
||||
const nanovdb::Camera<float>* camera,
|
||||
cudaStream_t stream)
|
||||
{
|
||||
const auto* img = imgHandle.image(); // host image!
|
||||
auto round = [](int a, int b) { return (a + b - 1) / b; };
|
||||
const dim3 threadsPerBlock(8, 8), numBlocks(round(img->width(), threadsPerBlock.x), round(img->height(), threadsPerBlock.y));
|
||||
auto* deviceGrid = gridHandle.deviceGrid<float>(); // note this cannot be de-referenced since it points to a memory address on the GPU!
|
||||
auto* deviceImage = imgHandle.deviceImage(); // note this cannot be de-referenced since it points to a memory address on the GPU!
|
||||
assert(deviceGrid && deviceImage);
|
||||
|
||||
#ifdef CUDA_TIMING
|
||||
cudaEvent_t start, stop;
|
||||
cudaEventCreate(&start);
|
||||
cudaEventCreate(&stop);
|
||||
cudaEventRecord(start, stream);
|
||||
#endif
|
||||
|
||||
// kernal syntax: <<<blocks per grid, threads per block, dynamic shared memory per block, stream >>>
|
||||
render_kernel<<<numBlocks, threadsPerBlock, 0, stream>>>(*deviceGrid, *camera, *deviceImage);
|
||||
|
||||
float elapsedTime = 0.0f;
|
||||
#ifdef CUDA_TIMING
|
||||
cudaEventRecord(stop, stream);
|
||||
cudaEventSynchronize(stop);
|
||||
|
||||
cudaEventElapsedTime(&elapsedTime, start, stop);
|
||||
//printf("DenseGrid: GPU kernel with %i rays ... completed in %5.3f milliseconds\n", imgHandle.image()->size(), elapsedTime);
|
||||
cudaError_t errCode = cudaGetLastError();
|
||||
if (errCode != cudaSuccess) {
|
||||
fprintf(stderr, "CUDA Runtime Error: %s %s %d\n", cudaGetErrorString(errCode), __FILE__, __LINE__);
|
||||
exit(errCode);
|
||||
}
|
||||
cudaEventDestroy(start);
|
||||
cudaEventDestroy(stop);
|
||||
#endif
|
||||
return elapsedTime;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file BenchKernels.cu
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief CUDA kernel for a simple ray-tracing benchmark test.
|
||||
|
||||
#include <nanovdb/util/GridHandle.h> // for nanovdb::GridHandle
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h> // for CUDA memory management
|
||||
#include <nanovdb/util/Ray.h> // for nanovdb::Ray
|
||||
#include <nanovdb/util/HDDA.h> // for nanovdb::ZeroCrossing
|
||||
|
||||
#include "Image.h"
|
||||
#include "Camera.h"
|
||||
|
||||
// Comment out to disable timing of the CUDA kernel
|
||||
#define CUDA_TIMING
|
||||
|
||||
// This is called by the device
|
||||
template <typename T>
|
||||
__global__ void render_kernel(const nanovdb::NanoGrid<T>& grid,
|
||||
const nanovdb::Camera<float>& camera,
|
||||
nanovdb::Image& img)
|
||||
{
|
||||
using RealT = float;
|
||||
using Vec3T = nanovdb::Vec3<RealT>;
|
||||
using CoordT = nanovdb::Coord;
|
||||
using RayT = nanovdb::Ray<RealT>;
|
||||
using ColorRGB = nanovdb::Image::ColorRGB;
|
||||
|
||||
const int w = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int h = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
if (w >= img.width() || h >= img.height())
|
||||
return;
|
||||
|
||||
const auto& tree = grid.tree();
|
||||
const auto& bbox = tree.bbox();
|
||||
RayT ray = camera.getRay(img.u(w), img.v(h));
|
||||
ray = ray.worldToIndexF(grid);
|
||||
|
||||
auto acc = tree.getAccessor();
|
||||
CoordT ijk;
|
||||
float t;
|
||||
float v0;
|
||||
if (nanovdb::ZeroCrossing(ray, acc, ijk, v0, t)) {
|
||||
#if 1// second-order central difference
|
||||
Vec3T grad(acc.getValue(ijk.offsetBy(1,0,0)) - acc.getValue(ijk.offsetBy(-1,0,0)),
|
||||
acc.getValue(ijk.offsetBy(0,1,0)) - acc.getValue(ijk.offsetBy(0,-1,0)),
|
||||
acc.getValue(ijk.offsetBy(0,0,1)) - acc.getValue(ijk.offsetBy(0,0,-1)));
|
||||
#else// first order single-sided difference
|
||||
Vec3T grad(-v0);
|
||||
ijk[0] += 1;
|
||||
grad[0] += acc.getValue(ijk);
|
||||
ijk[0] -= 1;
|
||||
ijk[1] += 1;
|
||||
grad[1] += acc.getValue(ijk);
|
||||
ijk[1] -= 1;
|
||||
ijk[2] += 1;
|
||||
grad[2] += acc.getValue(ijk);
|
||||
#endif
|
||||
grad *= rnorm3df(grad[0], grad[1], grad[2]);
|
||||
img(w, h) = ColorRGB(abs(grad.dot(ray.dir())), 0, 0);
|
||||
} else {
|
||||
const int checkerboard = 1 << 7;
|
||||
img(w, h) = ((h & checkerboard) ^ (w & checkerboard)) ? ColorRGB(1, 1, 1) : ColorRGB(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// This is called by the host
|
||||
extern "C" float launch_kernels(const nanovdb::GridHandle<nanovdb::CudaDeviceBuffer>& gridHandle,
|
||||
nanovdb::ImageHandle<nanovdb::CudaDeviceBuffer>& imgHandle,
|
||||
const nanovdb::Camera<float>* camera,
|
||||
cudaStream_t stream)
|
||||
{
|
||||
using BuildT = nanovdb::FpN;
|
||||
const auto* img = imgHandle.image(); // host image!
|
||||
auto round = [](int a, int b) { return (a + b - 1) / b; };
|
||||
const dim3 threadsPerBlock(8, 8), numBlocks(round(img->width(), threadsPerBlock.x), round(img->height(), threadsPerBlock.y));
|
||||
auto* deviceGrid = gridHandle.deviceGrid<BuildT>(); // note this cannot be de-referenced since it points to a memory address on the GPU!
|
||||
auto* deviceImage = imgHandle.deviceImage(); // note this cannot be de-referenced since it points to a memory address on the GPU!
|
||||
assert(deviceGrid && deviceImage);
|
||||
|
||||
#ifdef CUDA_TIMING
|
||||
cudaEvent_t start, stop;
|
||||
cudaEventCreate(&start);
|
||||
cudaEventCreate(&stop);
|
||||
cudaEventRecord(start, stream);
|
||||
#endif
|
||||
|
||||
// kernal syntax: <<<blocks per grid, threads per block, dynamic shared memory per block, stream >>>
|
||||
render_kernel<<<numBlocks, threadsPerBlock, 0, stream>>>(*deviceGrid, *camera, *deviceImage);
|
||||
|
||||
float elapsedTime = 0.0f;
|
||||
#ifdef CUDA_TIMING
|
||||
cudaEventRecord(stop, stream);
|
||||
cudaEventSynchronize(stop);
|
||||
|
||||
cudaEventElapsedTime(&elapsedTime, start, stop);
|
||||
//printf("NanoVDB: GPU kernel with %i rays ... completed in %5.3f milliseconds\n", imgHandle.image()->size(), elapsedTime);
|
||||
cudaError_t errCode = cudaGetLastError();
|
||||
if (errCode != cudaSuccess) {
|
||||
fprintf(stderr, "CUDA Runtime Error: %s %s %d\n", cudaGetErrorString(errCode), __FILE__, __LINE__);
|
||||
exit(errCode);
|
||||
}
|
||||
cudaEventDestroy(start);
|
||||
cudaEventDestroy(stop);
|
||||
#endif
|
||||
return elapsedTime;
|
||||
}
|
||||
@@ -0,0 +1,721 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file Benchmark.cc
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief A simple ray-tracing benchmark test.
|
||||
|
||||
#include <nanovdb/util/IO.h>
|
||||
#include <nanovdb/util/Ray.h>
|
||||
#include <nanovdb/util/HDDA.h>
|
||||
#include <nanovdb/util/Primitives.h>
|
||||
#include <nanovdb/util/SampleFromVoxels.h>
|
||||
#include "Image.h"
|
||||
#include "Camera.h"
|
||||
#include "../ex_util/CpuTimer.h"
|
||||
|
||||
#include "DenseGrid.h"
|
||||
|
||||
#if defined(NANOVDB_USE_CUDA)
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h>
|
||||
#endif
|
||||
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
#include <nanovdb/util/OpenToNanoVDB.h>
|
||||
|
||||
#include <openvdb/openvdb.h>
|
||||
#include <openvdb/tools/LevelSetSphere.h>
|
||||
#include <openvdb/tools/LevelSetPlatonic.h>
|
||||
#include <openvdb/tools/RayIntersector.h>
|
||||
#include <openvdb/math/Ray.h>
|
||||
#include <openvdb/math/Transform.h>
|
||||
#endif
|
||||
|
||||
#if defined(NANOVDB_USE_TBB)
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range2d.h>
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nanovdb {
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const CoordBBox& b)
|
||||
{
|
||||
os << "(" << b[0][0] << "," << b[0][1] << "," << b[0][2] << ") ->"
|
||||
<< "(" << b[1][0] << "," << b[1][1] << "," << b[1][2] << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const Coord& ijk)
|
||||
{
|
||||
os << "(" << ijk[0] << "," << ijk[1] << "," << ijk[2] << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const Vec3<T>& v)
|
||||
{
|
||||
os << "(" << v[0] << "," << v[1] << "," << v[2] << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// define the environment variable VDB_DATA_PATH to use models from the web
|
||||
// e.g. setenv VDB_DATA_PATH /home/kmu/dev/data/vdb
|
||||
// or export VDB_DATA_PATH=/Users/ken/dev/data/vdb
|
||||
|
||||
// define the environment variable VDB_SCRATCH_PATH to specify the directory where image are saved
|
||||
|
||||
// The fixture for testing class.
|
||||
class Benchmark : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
Benchmark() {}
|
||||
|
||||
~Benchmark() override {}
|
||||
|
||||
// If the constructor and destructor are not enough for setting up
|
||||
// and cleaning up each test, you can define the following methods:
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
// Code here will be called immediately after the constructor (right
|
||||
// before each test).
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// Code here will be called immediately after each test (right
|
||||
// before the destructor).
|
||||
}
|
||||
std::string getEnvVar(const std::string& name, const std::string def = "") const
|
||||
{
|
||||
const char* str = std::getenv(name.c_str());
|
||||
return str == nullptr ? def : std::string(str);
|
||||
}
|
||||
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
openvdb::FloatGrid::Ptr getSrcGrid(int verbose = 1)
|
||||
{
|
||||
openvdb::FloatGrid::Ptr grid;
|
||||
const std::string path = this->getEnvVar("VDB_DATA_PATH");
|
||||
if (path.empty()) { // create a narrow-band level set sphere
|
||||
std::cout << "\tSet the environment variable \"VDB_DATA_PATH\" to a directory\n"
|
||||
<< "\tcontaining OpenVDB level sets files. They can be downloaded\n"
|
||||
<< "\there: https://www.openvdb.org/download/" << std::endl;
|
||||
const float radius = 50.0f;
|
||||
const openvdb::Vec3f center(0.0f, 0.0f, 0.0f);
|
||||
const float voxelSize = 0.1f, width = 3.0f;
|
||||
if (verbose > 0) {
|
||||
std::stringstream ss;
|
||||
ss << "Generating level set sphere with a radius of " << radius << " voxels";
|
||||
mTimer.start(ss.str());
|
||||
}
|
||||
#if 1 // choose between a sphere or one of five platonic solids
|
||||
grid = openvdb::tools::createLevelSetSphere<openvdb::FloatGrid>(radius, center, voxelSize, width);
|
||||
grid->setName("ls_sphere");
|
||||
#else
|
||||
const int faces[5] = {4, 6, 8, 12, 20};
|
||||
grid = openvdb::tools::createLevelSetPlatonic<openvdb::FloatGrid>(faces[4], radius, center, voxelSize, width);
|
||||
grid->setName("ls_platonic");
|
||||
#endif
|
||||
} else {
|
||||
openvdb::initialize();
|
||||
const std::vector<std::string> models = {"armadillo.vdb", "buddha.vdb", "bunny.vdb", "crawler.vdb", "dragon.vdb", "iss.vdb", "space.vdb", "torus_knot_helix.vdb", "utahteapot.vdb", "bunny_cloud.vdb", "wdas_cloud.vdb"};
|
||||
const std::string fileName = path + "/" + models[4]; //
|
||||
if (verbose > 0)
|
||||
mTimer.start("Reading grid from the file \"" + fileName + "\"");
|
||||
openvdb::io::File file(fileName);
|
||||
file.open(false); //disable delayed loading
|
||||
grid = openvdb::gridPtrCast<openvdb::FloatGrid>(file.readGrid(file.beginName().gridName()));
|
||||
}
|
||||
if (verbose > 0)
|
||||
mTimer.stop();
|
||||
if (verbose > 1)
|
||||
grid->print(std::cout, 3);
|
||||
return grid;
|
||||
}
|
||||
#endif
|
||||
nanovdb::CpuTimer<> mTimer;
|
||||
}; // Benchmark
|
||||
|
||||
TEST_F(Benchmark, Ray)
|
||||
{
|
||||
using RealT = float;
|
||||
using Vec3T = nanovdb::Vec3<RealT>;
|
||||
using CoordT = nanovdb::Coord;
|
||||
using CoordBBoxT = nanovdb::BBox<CoordT>;
|
||||
using BBoxT = nanovdb::BBox<Vec3T>;
|
||||
using RayT = nanovdb::Ray<RealT>;
|
||||
|
||||
{// clip ray against an index bbox
|
||||
// test bbox clip
|
||||
const Vec3T dir(-1.0, 2.0, 3.0);
|
||||
const Vec3T eye(2.0, 1.0, 1.0);
|
||||
RealT t0 = 0.1, t1 = 12589.0;
|
||||
RayT ray(eye, dir, t0, t1);
|
||||
|
||||
// intersects the two faces of the box perpendicular to the y-axis!
|
||||
EXPECT_TRUE(ray.clip(CoordBBoxT(CoordT(0, 2, 2), CoordT(2, 4, 6))));
|
||||
//std::cerr << "t0 = " << ray.t0() << ", ray.t1() = " << ray.t1() << std::endl;
|
||||
//std::cerr << "ray(0.5) = " << ray(0.5) << std::endl;
|
||||
//std::cerr << "ray(1.5) = " << ray(1.5) << std::endl;
|
||||
//std::cerr << "ray(2.0) = " << ray(2.0) << std::endl;
|
||||
EXPECT_EQ(0.5, ray.t0());
|
||||
EXPECT_EQ(2.0, ray.t1());
|
||||
EXPECT_EQ(ray(0.5)[1], 2); //lower y component of intersection
|
||||
EXPECT_EQ(ray(2.0)[1], 5); //higher y component of intersection
|
||||
|
||||
ray.reset(eye, dir, t0, t1);
|
||||
// intersects the lower edge anlong the z-axis of the box
|
||||
EXPECT_TRUE(ray.clip(BBoxT(Vec3T(1.5, 2.0, 2.0), Vec3T(4.5, 4.0, 6.0))));
|
||||
EXPECT_EQ(0.5, ray.t0());
|
||||
EXPECT_EQ(0.5, ray.t1());
|
||||
EXPECT_EQ(ray(0.5)[0], 1.5); //lower y component of intersection
|
||||
EXPECT_EQ(ray(0.5)[1], 2.0); //higher y component of intersection
|
||||
|
||||
ray.reset(eye, dir, t0, t1);
|
||||
// no intersections
|
||||
EXPECT_TRUE(!ray.clip(CoordBBoxT(CoordT(4, 2, 2), CoordT(6, 4, 6))));
|
||||
EXPECT_EQ(t0, ray.t0());
|
||||
EXPECT_EQ(t1, ray.t1());
|
||||
}
|
||||
{// clip ray against an real bbox
|
||||
// test bbox clip
|
||||
const Vec3T dir(-1.0, 2.0, 3.0);
|
||||
const Vec3T eye(2.0, 1.0, 1.0);
|
||||
RealT t0 = 0.1, t1 = 12589.0;
|
||||
RayT ray(eye, dir, t0, t1);
|
||||
|
||||
// intersects the two faces of the box perpendicular to the y-axis!
|
||||
EXPECT_TRUE( ray.clip(CoordBBoxT(CoordT(0, 2, 2), CoordT(2, 4, 6)).asReal<double>()) );
|
||||
//std::cerr << "t0 = " << ray.t0() << ", ray.t1() = " << ray.t1() << std::endl;
|
||||
//std::cerr << "ray(0.5) = " << ray(0.5) << std::endl;
|
||||
//std::cerr << "ray(1.5) = " << ray(1.5) << std::endl;
|
||||
//std::cerr << "ray(2.0) = " << ray(2.0) << std::endl;
|
||||
EXPECT_EQ(0.5, ray.t0());
|
||||
EXPECT_EQ(2.0, ray.t1());
|
||||
EXPECT_EQ(ray(0.5)[1], 2); //lower y component of intersection
|
||||
EXPECT_EQ(ray(1.5)[1], 4); //higher y component of intersection
|
||||
|
||||
ray.reset(eye, dir, t0, t1);
|
||||
// intersects the lower edge along the z-axis of the box
|
||||
EXPECT_TRUE( ray.clip(BBoxT(Vec3T(1.5, 2.0, 2.0), Vec3T(4.5, 4.0, 6.0))) );
|
||||
EXPECT_EQ(0.5, ray.t0());
|
||||
EXPECT_EQ(0.5, ray.t1());
|
||||
EXPECT_EQ(ray(0.5)[0], 1.5); //lower y component of intersection
|
||||
EXPECT_EQ(ray(0.5)[1], 2.0); //higher y component of intersection
|
||||
|
||||
ray.reset(eye, dir, t0, t1);
|
||||
// no intersections
|
||||
EXPECT_TRUE(!ray.clip(CoordBBoxT(CoordT(4, 2, 2), CoordT(6, 4, 6)).asReal<double>()) );
|
||||
EXPECT_EQ(t0, ray.t0());
|
||||
EXPECT_EQ(t1, ray.t1());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Benchmark, HDDA)
|
||||
{
|
||||
using RealT = float;
|
||||
using CoordT = nanovdb::Coord;
|
||||
using RayT = nanovdb::Ray<RealT>;
|
||||
using Vec3T = RayT::Vec3T;
|
||||
|
||||
{ // basic test
|
||||
using DDAT = nanovdb::HDDA<RayT, CoordT>;
|
||||
const RayT::Vec3T dir(1.0, 0.0, 0.0);
|
||||
const RayT::Vec3T eye(-1.0, 0.0, 0.0);
|
||||
const RayT ray(eye, dir);
|
||||
DDAT dda(ray, 1 << (3 + 4 + 5));
|
||||
EXPECT_EQ(nanovdb::Delta<RealT>::value(), dda.time());
|
||||
EXPECT_EQ(1.0, dda.next());
|
||||
dda.step();
|
||||
EXPECT_EQ(1.0, dda.time());
|
||||
EXPECT_EQ(4096 + 1.0, dda.next());
|
||||
}
|
||||
{ // Check for the notorious +-0 issue!
|
||||
using DDAT = nanovdb::HDDA<RayT, CoordT>;
|
||||
|
||||
const Vec3T dir1(1.0, 0.0, 0.0);
|
||||
const Vec3T eye1(2.0, 0.0, 0.0);
|
||||
const RayT ray1(eye1, dir1);
|
||||
DDAT dda1(ray1, 1 << 3);
|
||||
dda1.step();
|
||||
|
||||
const Vec3T dir2(1.0, -0.0, -0.0);
|
||||
const Vec3T eye2(2.0, 0.0, 0.0);
|
||||
const RayT ray2(eye2, dir2);
|
||||
DDAT dda2(ray2, 1 << 3);
|
||||
dda2.step();
|
||||
|
||||
const Vec3T dir3(1.0, -1e-9, -1e-9);
|
||||
const Vec3T eye3(2.0, 0.0, 0.0);
|
||||
const RayT ray3(eye3, dir3);
|
||||
DDAT dda3(ray3, 1 << 3);
|
||||
dda3.step();
|
||||
|
||||
const Vec3T dir4(1.0, -1e-9, -1e-9);
|
||||
const Vec3T eye4(2.0, 0.0, 0.0);
|
||||
const RayT ray4(eye3, dir4);
|
||||
DDAT dda4(ray4, 1 << 3);
|
||||
dda4.step();
|
||||
|
||||
EXPECT_EQ(dda1.time(), dda2.time());
|
||||
EXPECT_EQ(dda2.time(), dda3.time());
|
||||
EXPECT_EQ(dda3.time(), dda4.time());
|
||||
EXPECT_EQ(dda1.next(), dda2.next());
|
||||
EXPECT_EQ(dda2.next(), dda3.next());
|
||||
EXPECT_EQ(dda3.next(), dda4.next());
|
||||
}
|
||||
{ // test voxel traversal along both directions of each axis
|
||||
using DDAT = nanovdb::HDDA<RayT>;
|
||||
const Vec3T eye(0, 0, 0);
|
||||
for (int s = -1; s <= 1; s += 2) {
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
const int d[3] = {s * (a == 0), s * (a == 1), s * (a == 2)};
|
||||
const Vec3T dir(d[0], d[1], d[2]);
|
||||
RayT ray(eye, dir);
|
||||
DDAT dda(ray, 1 << 0);
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
EXPECT_TRUE(dda.step());
|
||||
EXPECT_EQ(i, dda.time());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ // test Node traversal along both directions of each axis
|
||||
using DDAT = nanovdb::HDDA<RayT, CoordT>;
|
||||
const Vec3T eye(0, 0, 0);
|
||||
|
||||
for (int s = -1; s <= 1; s += 2) {
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
const int d[3] = {s * (a == 0), s * (a == 1), s * (a == 2)};
|
||||
const Vec3T dir(d[0], d[1], d[2]);
|
||||
RayT ray(eye, dir);
|
||||
DDAT dda(ray, 1 << 3);
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
EXPECT_TRUE(dda.step());
|
||||
EXPECT_EQ(8 * i, dda.time());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ // test accelerated Node traversal along both directions of each axis
|
||||
using DDAT = nanovdb::HDDA<RayT, CoordT>;
|
||||
const Vec3T eye(0, 0, 0);
|
||||
|
||||
for (int s = -1; s <= 1; s += 2) {
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
const int d[3] = {s * (a == 0), s * (a == 1), s * (a == 2)};
|
||||
const Vec3T dir(2 * d[0], 2 * d[1], 2 * d[2]);
|
||||
RayT ray(eye, dir);
|
||||
DDAT dda(ray, 1 << 3);
|
||||
double next = 0;
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
EXPECT_TRUE(dda.step());
|
||||
EXPECT_EQ(4 * i, dda.time());
|
||||
if (i > 1) {
|
||||
EXPECT_EQ(dda.time(), next);
|
||||
}
|
||||
next = dda.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // HDDA
|
||||
|
||||
|
||||
TEST_F(Benchmark, DenseGrid)
|
||||
{
|
||||
{// CoordT = nanovdb::Coord
|
||||
using GridT = nanovdb::DenseGrid<float>;
|
||||
const nanovdb::Coord min(-10,0,10), max(10,20,30), pos(0,5,20);
|
||||
const nanovdb::CoordBBox bbox( min, max );
|
||||
auto handle = GridT::create(min, max);
|
||||
auto *grid = handle.grid<float>();
|
||||
EXPECT_TRUE(grid);
|
||||
EXPECT_TRUE(grid->test(min));
|
||||
EXPECT_TRUE(grid->test(max));
|
||||
EXPECT_TRUE(grid->test(pos));
|
||||
EXPECT_EQ( uint64_t(21*21*21), bbox.volume() );
|
||||
EXPECT_EQ( bbox.volume(), grid->size() );
|
||||
EXPECT_EQ( 0u, grid->coordToOffset(min) );
|
||||
float *p = grid->values();
|
||||
for (uint64_t i=0; i<grid->size(); ++i) {
|
||||
*p++ = 0.0f;
|
||||
}
|
||||
EXPECT_EQ( 0.0f, grid->getValue(min) );
|
||||
EXPECT_EQ( 0.0f, grid->getValue(pos) );
|
||||
EXPECT_EQ( 0.0f, grid->getValue(max) );
|
||||
grid->setValue(pos, 1.0f);
|
||||
EXPECT_EQ( 0.0f, grid->getValue(min) );
|
||||
EXPECT_EQ( 1.0f, grid->getValue(pos) );
|
||||
EXPECT_EQ( 0.0f, grid->getValue(max) );
|
||||
for (auto it = bbox.begin(); it; ++it) {
|
||||
auto &ijk = *it;
|
||||
EXPECT_TRUE(grid->test(ijk));
|
||||
if (ijk == pos) {
|
||||
EXPECT_EQ( 1.0f, grid->getValue(ijk) );
|
||||
} else {
|
||||
EXPECT_EQ( 0.0f, grid->getValue(ijk) );
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(nanovdb::GridType::Float, grid->gridType());
|
||||
EXPECT_EQ(nanovdb::GridClass::Unknown, grid->gridClass());
|
||||
EXPECT_EQ(bbox, grid->indexBBox());
|
||||
EXPECT_EQ(nanovdb::Vec3d(min[0], min[1], min[2]), grid->worldBBox()[0]);
|
||||
EXPECT_EQ(nanovdb::Vec3d(max[0]+1, max[1]+1, max[2]+1), grid->worldBBox()[1]);
|
||||
EXPECT_EQ(nanovdb::Vec3d(1.0), grid->voxelSize());
|
||||
nanovdb::io::writeDense(handle, "data/dense.vol");
|
||||
//nanovdb::io::writeDense(*grid, "data/dense.vol");
|
||||
}
|
||||
{// CoordT = nanovdb::Coord
|
||||
auto handle = nanovdb::io::readDense<>("data/dense.vol");
|
||||
const nanovdb::Coord min(-10,0,10), max(10,20,30), pos(0,5,20);
|
||||
const nanovdb::CoordBBox bbox( min, max );
|
||||
auto *grid = handle.grid<float>();
|
||||
EXPECT_TRUE(grid);
|
||||
EXPECT_TRUE(grid->test(min));
|
||||
EXPECT_TRUE(grid->test(max));
|
||||
EXPECT_TRUE(grid->test(pos));
|
||||
EXPECT_EQ( uint64_t(21*21*21), bbox.volume() );
|
||||
EXPECT_EQ( bbox.volume(), grid->size() );
|
||||
EXPECT_EQ( 0u, grid->coordToOffset(min) );
|
||||
EXPECT_EQ( 0.0f, grid->getValue(min) );
|
||||
EXPECT_EQ( 1.0f, grid->getValue(pos) );
|
||||
EXPECT_EQ( 0.0f, grid->getValue(max) );
|
||||
EXPECT_EQ(min, grid->min());
|
||||
EXPECT_EQ(max, grid->max());
|
||||
for (auto it = bbox.begin(); it; ++it) {
|
||||
auto &ijk = *it;
|
||||
EXPECT_TRUE(grid->test(ijk));
|
||||
if (ijk == pos) {
|
||||
EXPECT_EQ( 1.0f, grid->getValue(ijk) );
|
||||
} else {
|
||||
EXPECT_EQ( 0.0f, grid->getValue(ijk) );
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(nanovdb::GridType::Float, grid->gridType());
|
||||
EXPECT_EQ(nanovdb::GridClass::Unknown, grid->gridClass());
|
||||
EXPECT_EQ(bbox, grid->indexBBox());
|
||||
EXPECT_EQ(nanovdb::Vec3d(min[0], min[1], min[2]), grid->worldBBox()[0]);
|
||||
EXPECT_EQ(nanovdb::Vec3d(max[0]+1, max[1]+1, max[2]+1), grid->worldBBox()[1]);
|
||||
EXPECT_EQ(nanovdb::Vec3d(1.0), grid->voxelSize());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
TEST_F(Benchmark, OpenVDB_CPU)
|
||||
{
|
||||
using GridT = openvdb::FloatGrid;
|
||||
using CoordT = openvdb::Coord;
|
||||
using ColorRGB = nanovdb::Image::ColorRGB;
|
||||
using RealT = float;
|
||||
using Vec3T = openvdb::math::Vec3<RealT>;
|
||||
using RayT = openvdb::math::Ray<RealT>;
|
||||
|
||||
const std::string image_path = this->getEnvVar("VDB_SCRATCH_PATH", ".");
|
||||
|
||||
auto srcGrid = this->getSrcGrid();
|
||||
mTimer.start("Generating NanoVDB grid");
|
||||
auto handle = nanovdb::openToNanoVDB(*srcGrid, nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Disable, /*verbose=*/0);
|
||||
mTimer.restart("Writing NanoVDB grid");
|
||||
#if defined(NANOVDB_USE_BLOSC)
|
||||
nanovdb::io::writeGrid("data/test.nvdb", handle, nanovdb::io::Codec::BLOSC);
|
||||
#elif defined(NANOVDB_USE_ZIP)
|
||||
nanovdb::io::writeGrid("data/test.nvdb", handle, nanovdb::io::Codec::ZIP);
|
||||
#else
|
||||
nanovdb::io::writeGrid("data/test.nvdb", handle, nanovdb::io::Codec::NONE);
|
||||
#endif
|
||||
mTimer.stop();
|
||||
|
||||
{// convert and write DenseGRid
|
||||
mTimer.start("Generating DenseGrid");
|
||||
auto dHandle = nanovdb::convertToDense(*handle.grid<float>());
|
||||
mTimer.restart("Writing DenseGrid");
|
||||
nanovdb::io::writeDense(dHandle, "data/test.vol");
|
||||
mTimer.stop();
|
||||
}
|
||||
|
||||
const int width = 1280, height = 720;
|
||||
const RealT vfov = 25.0f, aspect = RealT(width) / height, radius = 300.0f;
|
||||
const auto bbox = srcGrid->evalActiveVoxelBoundingBox();
|
||||
const openvdb::Vec3d center(0.5 * (bbox.max()[0] + bbox.min()[0]),
|
||||
0.5 * (bbox.max()[1] + bbox.min()[1]),
|
||||
0.5 * (bbox.max()[2] + bbox.min()[2]));
|
||||
const Vec3T lookat = srcGrid->indexToWorld(center), up(0, -1, 0);
|
||||
auto eye = [&lookat, &radius](int angle) {
|
||||
const RealT theta = angle * M_PI / 180.0f;
|
||||
return lookat + radius * Vec3T(sin(theta), 0, cos(theta));
|
||||
};
|
||||
|
||||
nanovdb::Camera<RealT, Vec3T, RayT> camera(eye(0), lookat, up, vfov, aspect);
|
||||
|
||||
nanovdb::ImageHandle<> imgHandle(width, height);
|
||||
auto* img = imgHandle.image();
|
||||
|
||||
auto kernel2D = [&](const tbb::blocked_range2d<int>& r) {
|
||||
openvdb::tools::LevelSetRayIntersector<GridT, openvdb::tools::LinearSearchImpl<GridT, 0, RealT>, GridT::TreeType::RootNodeType::ChildNodeType::LEVEL, RayT> tester(*srcGrid);
|
||||
const RealT wScale = 1.0f / width, hScale = 1.0f / height;
|
||||
auto acc = srcGrid->getAccessor();
|
||||
CoordT ijk;
|
||||
Vec3T xyz;
|
||||
float v;
|
||||
for (int w = r.rows().begin(); w != r.rows().end(); ++w) {
|
||||
for (int h = r.cols().begin(); h != r.cols().end(); ++h) {
|
||||
const RayT wRay = camera.getRay(w * wScale, h * hScale);
|
||||
RayT iRay = wRay.applyInverseMap(*srcGrid->transform().baseMap());
|
||||
if (tester.intersectsIS(iRay, xyz)) {
|
||||
ijk = openvdb::Coord::floor(xyz);
|
||||
v = acc.getValue(ijk);
|
||||
Vec3T grad(-v);
|
||||
ijk[0] += 1;
|
||||
grad[0] += acc.getValue(ijk);
|
||||
ijk[0] -= 1;
|
||||
ijk[1] += 1;
|
||||
grad[1] += acc.getValue(ijk);
|
||||
ijk[1] -= 1;
|
||||
ijk[2] += 1;
|
||||
grad[2] += acc.getValue(ijk);
|
||||
grad.normalize();
|
||||
(*img)(w, h) = ColorRGB(std::abs(grad.dot(iRay.dir())), 0, 0);
|
||||
} else {
|
||||
const int checkerboard = 1 << 7;
|
||||
(*img)(w, h) = ((h & checkerboard) ^ (w & checkerboard)) ? ColorRGB(1, 1, 1) : ColorRGB(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}; // kernel
|
||||
|
||||
for (int angle = 0; angle < 6; ++angle) {
|
||||
camera.update(eye(angle), lookat, up, vfov, aspect);
|
||||
std::stringstream ss;
|
||||
ss << "OpenVDB: CPU kernel with " << img->size() << " rays";
|
||||
tbb::blocked_range2d<int> range2D(0, img->width(), 0, img->height());
|
||||
mTimer.start(ss.str());
|
||||
#if 1
|
||||
tbb::parallel_for(range2D, kernel2D);
|
||||
#else
|
||||
kernel2D(range2D);
|
||||
#endif
|
||||
mTimer.stop();
|
||||
//mTimer.start("Write image to file");
|
||||
ss.str("");
|
||||
ss.clear();
|
||||
ss << image_path << "/openvdb_cpu_" << std::setfill('0') << std::setw(3) << angle << ".ppm";
|
||||
img->writePPM(ss.str(), "Benchmark test");
|
||||
//mTimer.stop();
|
||||
} // loop over angle
|
||||
} // OpenVDB_CPU
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
TEST_F(Benchmark, DenseGrid_CPU)
|
||||
{
|
||||
using CoordT = nanovdb::Coord;
|
||||
using ColorRGB = nanovdb::Image::ColorRGB;
|
||||
using RealT = float;
|
||||
using Vec3T = nanovdb::Vec3<RealT>;
|
||||
using RayT = nanovdb::Ray<RealT>;
|
||||
|
||||
auto handle = nanovdb::io::readDense("data/test.vol");
|
||||
auto* grid = handle.grid<float>();
|
||||
EXPECT_TRUE(grid);
|
||||
EXPECT_TRUE(grid->isLevelSet());
|
||||
|
||||
const int width = 1280, height = 720;
|
||||
const RealT vfov = 25.0f, aspect = RealT(width) / height, radius = 300.0f;
|
||||
const auto bbox = grid->worldBBox();
|
||||
const Vec3T lookat(0.5 * (bbox.min() + bbox.max())), up(0, -1, 0);
|
||||
auto eye = [&lookat, &radius](int angle) {
|
||||
const RealT theta = angle * M_PI / 180.0f;
|
||||
return lookat + radius * Vec3T(sin(theta), 0, cos(theta));
|
||||
};
|
||||
|
||||
nanovdb::Camera<RealT> camera(eye(0), lookat, up, vfov, aspect);
|
||||
|
||||
nanovdb::ImageHandle<> imgHandle(width, height);
|
||||
auto* img = imgHandle.image();
|
||||
|
||||
auto kernel2D = [&](int x0, int y0, int x1, int y1) {
|
||||
const RealT wScale = 1.0f / width, hScale = 1.0f / height;
|
||||
for (int w = x0; w != x1; ++w) {
|
||||
for (int h = y0; h != y1; ++h) {
|
||||
RayT ray = camera.getRay(w * wScale, h * hScale);
|
||||
ray = ray.worldToIndexF(*grid);
|
||||
if (!ray.clip(grid->indexBBox().expandBy(-1))) continue;
|
||||
nanovdb::DDA<RayT> dda(ray);
|
||||
CoordT ijk = dda.voxel();
|
||||
EXPECT_TRUE(grid->test(ijk));
|
||||
const float v0 = grid->getValue(ijk);
|
||||
bool hit = false;
|
||||
while( !hit && dda.step() ) {
|
||||
ijk = dda.voxel();
|
||||
EXPECT_TRUE(grid->test(ijk));
|
||||
const float v1 = grid->getValue(ijk);
|
||||
if (v0*v1>0) continue;
|
||||
Vec3T grad(-v1);
|
||||
ijk[0] += 1;
|
||||
grad[0] += grid->getValue(ijk);
|
||||
ijk[0] -= 1;
|
||||
ijk[1] += 1;
|
||||
grad[1] += grid->getValue(ijk);
|
||||
ijk[1] -= 1;
|
||||
ijk[2] += 1;
|
||||
grad[2] += grid->getValue(ijk);
|
||||
grad.normalize();
|
||||
(*img)(w, h) = ColorRGB(std::abs(grad.dot(ray.dir())), 0, 0);
|
||||
hit = true;
|
||||
}
|
||||
if (!hit) {
|
||||
const int checkerboard = 1 << 7;
|
||||
(*img)(w, h) = ((h & checkerboard) ^ (w & checkerboard)) ? ColorRGB(1, 1, 1) : ColorRGB(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}; // kernel
|
||||
|
||||
for (int angle = 0; angle < 6; ++angle) {
|
||||
camera.update(eye(angle), lookat, up, vfov, aspect);
|
||||
std::stringstream ss;
|
||||
ss << "DenseGrid: CPU kernel with " << img->size() << " rays";
|
||||
mTimer.start(ss.str());
|
||||
#if defined(NANOVDB_USE_TBB)
|
||||
tbb::blocked_range2d<int> range(0, img->width(), 0, img->height());
|
||||
tbb::parallel_for(range, [&](const tbb::blocked_range2d<int>& r) {
|
||||
kernel2D(r.rows().begin(), r.cols().begin(), r.rows().end(), r.cols().end());
|
||||
});
|
||||
#else
|
||||
kernel2D(0, 0, img->width(), img->height());
|
||||
#endif
|
||||
mTimer.stop();
|
||||
//mTimer.start("Write image to file");
|
||||
ss.str("");
|
||||
ss.clear();
|
||||
ss << "./dense_cpu_" << std::setfill('0') << std::setw(3) << angle << ".ppm";
|
||||
img->writePPM(ss.str(), "Benchmark test");
|
||||
//mTimer.stop();
|
||||
} // loop over angle
|
||||
} // DenseGrid_CPU
|
||||
|
||||
#if defined(NANOVDB_USE_CUDA)
|
||||
|
||||
// Convenience function for checking CUDA runtime API results
|
||||
// can be wrapped around any runtime API call. No-op in release builds.
|
||||
#define cudaCheck(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
|
||||
static inline bool gpuAssert(cudaError_t code, const char* file, int line, bool abort = true)
|
||||
{
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
if (code != cudaSuccess) {
|
||||
fprintf(stderr, "CUDA Runtime Error: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void launch_kernels(const nanovdb::GridHandle<nanovdb::CudaDeviceBuffer>&,
|
||||
nanovdb::ImageHandle<nanovdb::CudaDeviceBuffer>&,
|
||||
const nanovdb::Camera<float>*,
|
||||
cudaStream_t stream);
|
||||
|
||||
TEST_F(Benchmark, NanoVDB_GPU)
|
||||
{
|
||||
using BufferT = nanovdb::CudaDeviceBuffer;
|
||||
using RealT = float;
|
||||
using Vec3T = nanovdb::Vec3<RealT>;
|
||||
using CameraT = nanovdb::Camera<RealT>;
|
||||
|
||||
const std::string image_path = this->getEnvVar("VDB_SCRATCH_PATH", ".");
|
||||
|
||||
// The first CUDA run time call initializes the CUDA sub-system (loads the runtime API) which takes time!
|
||||
int deviceCount;
|
||||
cudaGetDeviceCount(&deviceCount);
|
||||
for (int device = 0; device < deviceCount; ++device) {
|
||||
cudaDeviceProp deviceProp;
|
||||
cudaGetDeviceProperties(&deviceProp, device);
|
||||
printf("Device %d has compute capability %d.%d.\n",
|
||||
device,
|
||||
deviceProp.major,
|
||||
deviceProp.minor);
|
||||
}
|
||||
cudaSetDevice(0);
|
||||
|
||||
cudaStream_t stream;
|
||||
cudaCheck(cudaStreamCreate(&stream));
|
||||
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
auto handle = nanovdb::io::readGrid<BufferT>("data/test.nvdb");
|
||||
#else
|
||||
auto handle = nanovdb::createLevelSetTorus<float, float, BufferT>(100.0f, 50.0f);
|
||||
#endif
|
||||
//auto handle = nanovdb::io::readGrid<BufferT>("data/test.nvdb");
|
||||
const auto* grid = handle.grid<float>();
|
||||
EXPECT_TRUE(grid);
|
||||
EXPECT_TRUE(grid->isLevelSet());
|
||||
EXPECT_FALSE(grid->isFogVolume());
|
||||
handle.deviceUpload(stream, false);
|
||||
|
||||
std::cout << "\nRay-tracing NanoVDB grid named \"" << grid->gridName() << "\"" << std::endl;
|
||||
|
||||
const int width = 1280, height = 720;
|
||||
const RealT vfov = 25.0f, aspect = RealT(width) / height, radius = 300.0f;
|
||||
const auto bbox = grid->worldBBox();
|
||||
const Vec3T lookat(0.5 * (bbox.min() + bbox.max())), up(0, -1, 0);
|
||||
auto eye = [&lookat, &radius](int angle) {
|
||||
const RealT theta = angle * M_PI / 180.0f;
|
||||
return lookat + radius * Vec3T(sin(theta), 0, cos(theta));
|
||||
};
|
||||
CameraT *host_camera, *dev_camera;
|
||||
cudaCheck(cudaMalloc((void**)&dev_camera, sizeof(CameraT))); // un-managed memory on the device
|
||||
cudaCheck(cudaMallocHost((void**)&host_camera, sizeof(CameraT)));
|
||||
|
||||
nanovdb::ImageHandle<BufferT> imgHandle(width, height);
|
||||
auto* img = imgHandle.image();
|
||||
imgHandle.deviceUpload(stream, false);
|
||||
|
||||
for (int angle = 0; angle < 6; ++angle) {
|
||||
std::stringstream ss;
|
||||
ss << "NanoVDB: GPU kernel with " << img->size() << " rays";
|
||||
host_camera->update(eye(angle), lookat, up, vfov, aspect);
|
||||
cudaCheck(cudaMemcpyAsync(dev_camera, host_camera, sizeof(CameraT), cudaMemcpyHostToDevice, stream));
|
||||
mTimer.start(ss.str());
|
||||
launch_kernels(handle, imgHandle, dev_camera, stream);
|
||||
mTimer.stop();
|
||||
|
||||
//mTimer.start("Write image to file");
|
||||
imgHandle.deviceDownload(stream);
|
||||
ss.str("");
|
||||
ss.clear();
|
||||
ss << image_path << "/nanovdb_gpu_" << std::setfill('0') << std::setw(3) << angle << ".ppm";
|
||||
img->writePPM(ss.str(), "Benchmark test");
|
||||
//mTimer.stop();
|
||||
|
||||
} //frame number angle
|
||||
|
||||
cudaCheck(cudaStreamDestroy(stream));
|
||||
cudaCheck(cudaFree(host_camera));
|
||||
cudaCheck(cudaFree(dev_camera));
|
||||
} // NanoVDB_GPU
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file Benchmark_nano.cc
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief A super lightweight and portable ray-tracing benchmark
|
||||
/// that only depends on NanoVDB (not OpenVDB) and CUDA.
|
||||
|
||||
#include <nanovdb/util/IO.h>
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h>
|
||||
#include "Image.h"
|
||||
#include "Camera.h"
|
||||
#include "DenseGrid.h"
|
||||
#include "../ex_util/CpuTimer.h"
|
||||
|
||||
#include <iomanip>// for std::setfill and std::setw
|
||||
|
||||
|
||||
// Convenience function for checking CUDA runtime API results
|
||||
// can be wrapped around any runtime API call. No-op in release builds.
|
||||
#define cudaCheck(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
|
||||
static inline bool gpuAssert(cudaError_t code, const char* file, int line, bool abort = true)
|
||||
{
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
if (code != cudaSuccess) {
|
||||
fprintf(stderr, "CUDA Runtime Error: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" float launch_kernels(const nanovdb::DenseGridHandle<nanovdb::CudaDeviceBuffer>&,
|
||||
nanovdb::ImageHandle<nanovdb::CudaDeviceBuffer>&,
|
||||
const nanovdb::Camera<float>*,
|
||||
cudaStream_t stream);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using BufferT = nanovdb::CudaDeviceBuffer;
|
||||
using RealT = float;
|
||||
using Vec3T = nanovdb::Vec3<RealT>;
|
||||
using CameraT = nanovdb::Camera<RealT>;
|
||||
nanovdb::CpuTimer<> timer;
|
||||
|
||||
if (argc!=2) {
|
||||
std::cerr << "Usage: " << argv[0] << " path/level_set.vol" << std::endl;
|
||||
//std::cerr << "To generate an input file: nanovdb_convert dragon.vdb dragon.nvdb\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The first CUDA run time call initializes the CUDA sub-system (loads the runtime API) which takes time!
|
||||
int deviceCount;
|
||||
cudaGetDeviceCount(&deviceCount);
|
||||
for (int device = 0; device < deviceCount; ++device) {
|
||||
cudaDeviceProp deviceProp;
|
||||
cudaGetDeviceProperties(&deviceProp, device);
|
||||
printf("Device %d has compute capability %d.%d.\n",
|
||||
device,
|
||||
deviceProp.major,
|
||||
deviceProp.minor);
|
||||
}
|
||||
cudaSetDevice(0);
|
||||
|
||||
cudaStream_t stream;
|
||||
cudaCheck(cudaStreamCreate(&stream));
|
||||
|
||||
auto handle = nanovdb::io::readDense<BufferT>(argv[1]);
|
||||
|
||||
const auto* grid = handle.grid<float>();
|
||||
if (!grid || !grid->isLevelSet()) {
|
||||
std::cerr << "Error loading NanoVDB level set from file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
handle.deviceUpload(stream, false);
|
||||
std::cout << "\nRay-tracing DenseGrid of size "
|
||||
<< (grid->gridSize() >> 20) << " MB" << std::endl;
|
||||
|
||||
const int width = 1280, height = 720;
|
||||
const RealT vfov = 25.0f, aspect = RealT(width) / height, radius = 300.0f;
|
||||
const auto bbox = grid->worldBBox();
|
||||
const Vec3T lookat(0.5 * (bbox.min() + bbox.max())), up(0, -1, 0);
|
||||
auto eye = [&lookat, &radius](int angle) {
|
||||
const RealT theta = angle * M_PI / 180.0f;
|
||||
return lookat + radius * Vec3T(sin(theta), 0, cos(theta));
|
||||
};
|
||||
CameraT *host_camera, *dev_camera;
|
||||
cudaCheck(cudaMalloc((void**)&dev_camera, sizeof(CameraT))); // un-managed memory on the device
|
||||
cudaCheck(cudaMallocHost((void**)&host_camera, sizeof(CameraT)));
|
||||
|
||||
nanovdb::ImageHandle<BufferT> imgHandle(width, height);
|
||||
auto* img = imgHandle.image();
|
||||
imgHandle.deviceUpload(stream, false);
|
||||
|
||||
float elapsedTime = 0.0f;
|
||||
const int maxAngle = 360;
|
||||
for (int angle = 0; angle < maxAngle; ++angle) {
|
||||
host_camera->update(eye(angle), lookat, up, vfov, aspect);
|
||||
cudaCheck(cudaMemcpyAsync(dev_camera, host_camera, sizeof(CameraT), cudaMemcpyHostToDevice, stream));
|
||||
elapsedTime += launch_kernels(handle, imgHandle, dev_camera, stream);
|
||||
|
||||
//timer.start("Write image to file");
|
||||
imgHandle.deviceDownload(stream);
|
||||
std::stringstream ss;
|
||||
ss << "./dense_gpu_" << std::setfill('0') << std::setw(3) << angle << ".ppm";
|
||||
img->writePPM(ss.str(), "Benchmark test");
|
||||
//timer.stop();
|
||||
|
||||
} //frame number angle
|
||||
|
||||
cudaCheck(cudaStreamDestroy(stream));
|
||||
cudaCheck(cudaFree(host_camera));
|
||||
cudaCheck(cudaFree(dev_camera));
|
||||
|
||||
printf("\nRay-traced %i different frames, each with %i rays, in %5.3f ms.\nThis corresponds to an average of %5.3f ms per frame or %5.3f FPS!\n",
|
||||
maxAngle, imgHandle.image()->size(), elapsedTime, elapsedTime/maxAngle, 1000.0f*maxAngle/elapsedTime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file Benchmark_nano.cc
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief A super lightweight and portable ray-tracing benchmark
|
||||
/// that only depends on NanoVDB (not OpenVDB) and CUDA.
|
||||
|
||||
#include <nanovdb/util/IO.h>
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h>
|
||||
#include "Image.h"
|
||||
#include "Camera.h"
|
||||
#include "../ex_util/CpuTimer.h"
|
||||
|
||||
#include <iomanip>// for std::setfill and std::setw
|
||||
|
||||
|
||||
// Convenience function for checking CUDA runtime API results
|
||||
// can be wrapped around any runtime API call. No-op in release builds.
|
||||
#define cudaCheck(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
|
||||
static inline bool gpuAssert(cudaError_t code, const char* file, int line, bool abort = true)
|
||||
{
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
if (code != cudaSuccess) {
|
||||
fprintf(stderr, "CUDA Runtime Error: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" float launch_kernels(const nanovdb::GridHandle<nanovdb::CudaDeviceBuffer>&,
|
||||
nanovdb::ImageHandle<nanovdb::CudaDeviceBuffer>&,
|
||||
const nanovdb::Camera<float>*,
|
||||
cudaStream_t stream);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using BufferT = nanovdb::CudaDeviceBuffer;
|
||||
using ValueT = float;
|
||||
using BuildT = nanovdb::FpN;
|
||||
using Vec3T = nanovdb::Vec3<ValueT>;
|
||||
using CameraT = nanovdb::Camera<ValueT>;
|
||||
nanovdb::CpuTimer<> timer;
|
||||
|
||||
if (argc!=2) {
|
||||
std::cerr << "Usage: " << argv[0] << " path/level_set.nvdb" << std::endl;
|
||||
std::cerr << "To generate an input file: nanovdb_convert dragon.vdb dragon.nvdb\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The first CUDA run time call initializes the CUDA sub-system (loads the runtime API) which takes time!
|
||||
int deviceCount;
|
||||
cudaGetDeviceCount(&deviceCount);
|
||||
for (int device = 0; device < deviceCount; ++device) {
|
||||
cudaDeviceProp deviceProp;
|
||||
cudaGetDeviceProperties(&deviceProp, device);
|
||||
printf("Device %d has compute capability %d.%d.\n",
|
||||
device,
|
||||
deviceProp.major,
|
||||
deviceProp.minor);
|
||||
}
|
||||
cudaSetDevice(0);
|
||||
int driverVersion, runtimeVersion;
|
||||
cudaDriverGetVersion(&driverVersion);
|
||||
cudaRuntimeGetVersion(&runtimeVersion);
|
||||
printf("CUDA driver version:\t%i.%i\n", driverVersion/1000, (driverVersion%1000)/10);
|
||||
printf("CUDA runtime version:\t%i.%i\n", runtimeVersion/1000, (runtimeVersion%1000)/10);
|
||||
|
||||
cudaStream_t stream;
|
||||
cudaCheck(cudaStreamCreate(&stream));
|
||||
|
||||
auto handle = nanovdb::io::readGrid<BufferT>(argv[1]);
|
||||
|
||||
const auto* grid = handle.grid<BuildT>();
|
||||
if (!grid || !grid->isLevelSet()) {
|
||||
std::cerr << "Error loading NanoVDB level set from file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
handle.deviceUpload(stream, false);
|
||||
std::cout << "\nRay-tracing NanoVDB grid named \"" << grid->gridName() << "\" of size "
|
||||
<< (grid->gridSize() >> 20) << " MB" << std::endl;
|
||||
|
||||
const int width = 1280, height = 720;
|
||||
const ValueT vfov = 25.0f, aspect = ValueT(width) / height, radius = 300.0f;
|
||||
const auto bbox = grid->worldBBox();
|
||||
const Vec3T lookat(0.5 * (bbox.min() + bbox.max())), up(0, -1, 0);
|
||||
auto eye = [&lookat, &radius](int angle) {
|
||||
const ValueT theta = angle * M_PI / 180.0f;
|
||||
return lookat + radius * Vec3T(sin(theta), 0, cos(theta));
|
||||
};
|
||||
CameraT *host_camera, *dev_camera;
|
||||
cudaCheck(cudaMalloc((void**)&dev_camera, sizeof(CameraT))); // un-managed memory on the device
|
||||
cudaCheck(cudaMallocHost((void**)&host_camera, sizeof(CameraT)));
|
||||
|
||||
nanovdb::ImageHandle<BufferT> imgHandle(width, height);
|
||||
auto* img = imgHandle.image();
|
||||
imgHandle.deviceUpload(stream, false);
|
||||
|
||||
float elapsedTime = 0.0f;
|
||||
const int maxAngle = 360;
|
||||
for (int angle = 0; angle < maxAngle; ++angle) {
|
||||
host_camera->update(eye(angle), lookat, up, vfov, aspect);
|
||||
cudaCheck(cudaMemcpyAsync(dev_camera, host_camera, sizeof(CameraT), cudaMemcpyHostToDevice, stream));
|
||||
elapsedTime += launch_kernels(handle, imgHandle, dev_camera, stream);
|
||||
|
||||
//timer.start("Write image to file");
|
||||
imgHandle.deviceDownload(stream);
|
||||
#if 1
|
||||
std::stringstream ss;
|
||||
ss << "./nanovdb_gpu_" << std::setfill('0') << std::setw(3) << angle << ".ppm";
|
||||
img->writePPM(ss.str(), "Benchmark test");
|
||||
#endif
|
||||
//timer.stop();
|
||||
|
||||
} //frame number angle
|
||||
|
||||
cudaCheck(cudaStreamDestroy(stream));
|
||||
cudaCheck(cudaFree(host_camera));
|
||||
cudaCheck(cudaFree(dev_camera));
|
||||
|
||||
printf("\nRay-traced %i different frames, each with %i rays, in %5.3f ms.\nThis corresponds to an average of %5.3f ms per frame or %5.3f FPS!\n",
|
||||
maxAngle, imgHandle.image()->size(), elapsedTime, elapsedTime/maxAngle, 1000.0f*maxAngle/elapsedTime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
# Copyright Contributors to the OpenVDB Project
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
#[=======================================================================[
|
||||
|
||||
CMake Configuration for NanoVDB Benchmark
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(NanoVDBBenchmark LANGUAGES CXX)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
###############################################################################
|
||||
|
||||
message(STATUS "----------------------------------------------------")
|
||||
message(STATUS "---------- Configuring NanoVDB Benchmark -----------")
|
||||
message(STATUS "----------------------------------------------------")
|
||||
|
||||
###############################################################################
|
||||
|
||||
if(WIN32 AND NANOVDB_CUDA_KEEP_PTX)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/x64/Release")
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# TODO: Benchmark should probably not require gtest.
|
||||
if(NOT TARGET GTest::GTest)
|
||||
message(WARNING " - GTest required to build benchmark. Skipping.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# many of the sample projects depend on a data directory. This allows Debug
|
||||
# launching from the cmake binary working directory.
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/data")
|
||||
|
||||
set(BENCHMARK_SOURCES Benchmark.cc Camera.h Image.h)
|
||||
|
||||
if(NANOVDB_USE_CUDA)
|
||||
list(APPEND BENCHMARK_SOURCES BenchKernels_nano.cu)
|
||||
|
||||
add_executable(benchmark_nano Benchmark_nano.cc BenchKernels_nano.cu)
|
||||
add_executable(benchmark_dense Benchmark_dense.cc BenchKernels_dense.cu)
|
||||
|
||||
target_link_libraries(benchmark_nano PRIVATE nanovdb)
|
||||
target_link_libraries(benchmark_dense PRIVATE nanovdb)
|
||||
|
||||
# Propagate MSVC Runtime from the OpenVDB library (if VDB_MSVC_RUNTIME_SELECTION
|
||||
# has been set then we're building and linking against OpenVDB, see the root
|
||||
# NanoVDB CMakeLists.txt)
|
||||
if(VDB_MSVC_RUNTIME_SELECTION)
|
||||
set_target_properties(benchmark_nano PROPERTIES
|
||||
MSVC_RUNTIME_LIBRARY ${VDB_MSVC_RUNTIME_SELECTION})
|
||||
set_target_properties(benchmark_dense PROPERTIES
|
||||
MSVC_RUNTIME_LIBRARY ${VDB_MSVC_RUNTIME_SELECTION})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
add_executable(benchmark ${BENCHMARK_SOURCES})
|
||||
target_link_libraries(benchmark PRIVATE nanovdb GTest::GTest GTest::Main)
|
||||
|
||||
# Propagate MSVC Runtime from the OpenVDB library (if VDB_MSVC_RUNTIME_SELECTION
|
||||
# has been set then we're building and linking against OpenVDB, see the root
|
||||
# NanoVDB CMakeLists.txt)
|
||||
if(VDB_MSVC_RUNTIME_SELECTION)
|
||||
set_target_properties(benchmark PROPERTIES
|
||||
MSVC_RUNTIME_LIBRARY ${VDB_MSVC_RUNTIME_SELECTION})
|
||||
endif()
|
||||
|
||||
install(TARGETS benchmark DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples)
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file Camera.h
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief A simple camera class.
|
||||
|
||||
#ifndef NANOVDB_CAMERA_H_HAS_BEEN_INCLUDED
|
||||
#define NANOVDB_CAMERA_H_HAS_BEEN_INCLUDED
|
||||
|
||||
#include <nanovdb/NanoVDB.h> // for Vec3
|
||||
#include <nanovdb/util/Ray.h>
|
||||
|
||||
namespace nanovdb {
|
||||
|
||||
/// @brief A minimal perspective camera for ray generation
|
||||
template<typename RealT = float, typename Vec3T = Vec3<RealT>, typename RayT = Ray<RealT>>
|
||||
class Camera
|
||||
{
|
||||
Vec3T mEye, mW, mU, mV;
|
||||
|
||||
__hostdev__ void init(RealT vfov, RealT aspect)
|
||||
{
|
||||
const RealT halfHeight = RealT(tan(vfov * 3.14159265358979323846 / 360));
|
||||
const RealT halfWidth = aspect * halfHeight;
|
||||
mW = halfWidth * mU + halfHeight * mV + mW; // remove eye here and in getRay
|
||||
mU *= 2 * halfWidth;
|
||||
mV *= 2 * halfHeight;
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief default Ctor.
|
||||
Camera() = default;
|
||||
|
||||
/// @brief Ctor. // vfov is top to bottom in degrees
|
||||
/// @note up is assumed to be a unit-vector
|
||||
__hostdev__ Camera(const Vec3T& eye, const Vec3T& lookat, const Vec3T& up, RealT vfov, RealT aspect)
|
||||
: mEye(eye)
|
||||
, mW((eye - lookat).normalize())
|
||||
, mU(up.cross(mW))
|
||||
, mV(up)
|
||||
{
|
||||
this->init(vfov, aspect);
|
||||
}
|
||||
__hostdev__ void update(const Vec3T& eye, const Vec3T& lookat, const Vec3T& up, RealT vfov, RealT aspect)
|
||||
{
|
||||
mEye = eye;
|
||||
mV = up;
|
||||
mW = mEye - lookat;
|
||||
mW.normalize();
|
||||
mU = mV.cross(mW);
|
||||
this->init(vfov, aspect);
|
||||
}
|
||||
/// @brief {u,v} are are assumed to be [0,1]
|
||||
__hostdev__ RayT getRay(RealT u, RealT v) const {
|
||||
auto dir = u * mU + v * mV - mW;
|
||||
dir.normalize();
|
||||
return RayT(mEye, dir);
|
||||
}
|
||||
|
||||
__hostdev__ const Vec3T& P() const { return mEye; }
|
||||
__hostdev__ const Vec3T& U() const { return mU; }
|
||||
__hostdev__ const Vec3T& V() const { return mV; }
|
||||
__hostdev__ const Vec3T& W() const { return mW; }
|
||||
|
||||
}; // Camera
|
||||
|
||||
} // namespace nanovdb
|
||||
|
||||
#endif // NANOVDB_CAMERA_HAS_BEEN_INCLUDED
|
||||
@@ -0,0 +1,487 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/// @file DenseGrid.h
|
||||
///
|
||||
/// @author Ken Museth
|
||||
///
|
||||
/// @brief Simple dense grid class.
|
||||
|
||||
#ifndef NANOVDB_DENSEGRID_H_HAS_BEEN_INCLUDED
|
||||
#define NANOVDB_DENSEGRID_H_HAS_BEEN_INCLUDED
|
||||
|
||||
#include <stdint.h>// for uint64_t
|
||||
#include <fstream> // for std::ifstream
|
||||
#include <nanovdb/util/HostBuffer.h>// for default Buffer
|
||||
#include <nanovdb/util/ForEach.h>
|
||||
#include <nanovdb/NanoVDB.h>// for Map, GridClass, GridType and and Coord
|
||||
|
||||
|
||||
// use 4x4x4 tiles for better cache coherence
|
||||
// else it uses dense indexing which is slow!
|
||||
// 0 means disable, 1 is 2x2x2, 2 is 4x4x4 and 3 is 8x8x8
|
||||
#define LOG2_TILE_SIZE 2
|
||||
|
||||
namespace nanovdb {
|
||||
|
||||
// forward decleration
|
||||
template<typename BufferT = HostBuffer>
|
||||
class DenseGridHandle;
|
||||
|
||||
#define DENSE_MAGIC_NUMBER 0x42445665736e6544UL // "DenseVDB" in hex - little endian (uint64_t)
|
||||
|
||||
|
||||
struct DenseData
|
||||
{
|
||||
Map mMap;// defined in NanoVDB.h
|
||||
CoordBBox mIndexBBox;// min/max of bbox
|
||||
BBox<Vec3R> mWorldBBox;// 48B. floating-point AABB of active values in WORLD SPACE (2 x 3 doubles)
|
||||
Vec3R mVoxelSize;
|
||||
GridClass mGridClass;// defined in NanoVDB.h
|
||||
GridType mGridType; // defined in NanoVDB.h
|
||||
uint64_t mY, mX;//strides in the y and x direction
|
||||
uint64_t mSize;
|
||||
|
||||
__hostdev__ Coord dim() const { return mIndexBBox.dim(); }
|
||||
|
||||
// Affine transformations based on double precision
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); }
|
||||
// Affine transformations based on single precision
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); }
|
||||
};
|
||||
/// @brief Simple dense grid class
|
||||
/// @note ZYX is the memory-layout in VDB. It leads to nested
|
||||
/// for-loops of the order x, y, z.
|
||||
template<typename ValueT>
|
||||
class DenseGrid : private DenseData
|
||||
{
|
||||
#if LOG2_TILE_SIZE > 0
|
||||
static constexpr uint32_t TileLog2 = LOG2_TILE_SIZE, TileMask = (1 << TileLog2) - 1, TileDim = 1 << (3*TileLog2);
|
||||
#endif
|
||||
using DenseData = DenseData;
|
||||
|
||||
public:
|
||||
using ValueType = ValueT;
|
||||
|
||||
template<typename BufferT = HostBuffer>
|
||||
inline static DenseGridHandle<BufferT> create(Coord min, // min inclusive index coordinate
|
||||
Coord max, // max inclusive index coordinate
|
||||
double dx = 1.0, //voxel size
|
||||
const Vec3d& p0 = Vec3d(0.0), // origin
|
||||
GridClass gridClass = GridClass::Unknown,
|
||||
const BufferT& allocator = BufferT());
|
||||
|
||||
__hostdev__ DenseGrid(const DenseGrid&) = delete;
|
||||
__hostdev__ ~DenseGrid() = delete;
|
||||
__hostdev__ DenseGrid& operator=(const DenseGrid&) = delete;
|
||||
|
||||
__hostdev__ uint64_t size() const { return mIndexBBox.volume(); }
|
||||
__hostdev__ inline uint64_t coordToOffset(const Coord &ijk) const;
|
||||
__hostdev__ inline bool test(const Coord &ijk) const;
|
||||
__hostdev__ uint64_t memUsage() const {return mSize;}
|
||||
__hostdev__ uint64_t gridSize() const {return this->memUsage();}
|
||||
__hostdev__ const Coord& min() const { return mIndexBBox[0]; }
|
||||
__hostdev__ const Coord& max() const { return mIndexBBox[1]; }
|
||||
__hostdev__ inline bool isValidType() const;
|
||||
|
||||
/// @brief Return a const reference to the Map for this grid
|
||||
__hostdev__ const Map& map() const { return DenseData::mMap; }
|
||||
|
||||
// @brief Return a const reference to the size of a voxel in world units
|
||||
__hostdev__ const Vec3R& voxelSize() const { return DenseData::mVoxelSize; }
|
||||
|
||||
/// @brief world to index space transformation
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); }
|
||||
|
||||
/// @brief world to index space transformation
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); }
|
||||
|
||||
/// @brief transformation from index space direction to world space direction
|
||||
/// @warning assumes dir to be normalized
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); }
|
||||
|
||||
/// @brief transformation from world space direction to index space direction
|
||||
/// @warning assumes dir to be normalized
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); }
|
||||
|
||||
/// @brief transform the gradient from index space to world space.
|
||||
/// @details Applies the inverse jacobian transform map.
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); }
|
||||
|
||||
/// @brief world to index space transformation
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); }
|
||||
|
||||
/// @brief index to world space transformation
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); }
|
||||
|
||||
/// @brief transformation from index space direction to world space direction
|
||||
/// @warning assumes dir to be normalized
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); }
|
||||
|
||||
/// @brief transformation from world space direction to index space direction
|
||||
/// @warning assumes dir to be normalized
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); }
|
||||
|
||||
/// @brief Transforms the gradient from index space to world space.
|
||||
/// @details Applies the inverse jacobian transform map.
|
||||
template<typename Vec3T>
|
||||
__hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DenseData::applyIJTF(grad); }
|
||||
|
||||
/// @brief Computes a AABB of active values in world space
|
||||
__hostdev__ const BBox<Vec3R>& worldBBox() const { return DenseData::mWorldBBox; }
|
||||
|
||||
__hostdev__ bool isLevelSet() const { return DenseData::mGridClass == GridClass::LevelSet; }
|
||||
__hostdev__ bool isFogVolume() const { return DenseData::mGridClass == GridClass::FogVolume; }
|
||||
|
||||
/// @brief Computes a AABB of active values in index space
|
||||
///
|
||||
/// @note This method is returning a floating point bounding box and not a CoordBBox. This makes
|
||||
/// it more useful for clipping rays.
|
||||
__hostdev__ const CoordBBox& indexBBox() const { return mIndexBBox; }
|
||||
|
||||
__hostdev__ const GridType& gridType() const { return DenseData::mGridType; }
|
||||
__hostdev__ const GridClass& gridClass() const { return DenseData::mGridClass; }
|
||||
|
||||
__hostdev__ DenseData* data() { return reinterpret_cast<DenseData*>(this); }
|
||||
__hostdev__ const DenseData* data() const { return reinterpret_cast<const DenseData*>(this); }
|
||||
|
||||
__hostdev__ ValueT* values() { return reinterpret_cast<ValueT*>(this+1);}
|
||||
__hostdev__ const ValueT* values() const { return reinterpret_cast<const ValueT*>(this+1); }
|
||||
|
||||
__hostdev__ inline const ValueT& getValue(const Coord &ijk) const;
|
||||
__hostdev__ inline void setValue(const Coord &ijk, const ValueT &v);
|
||||
}; // Grid
|
||||
|
||||
template<typename ValueT>
|
||||
template<typename BufferT>
|
||||
DenseGridHandle<BufferT>
|
||||
DenseGrid<ValueT>::create(Coord min,
|
||||
Coord max,
|
||||
double dx, //voxel size
|
||||
const Vec3d& p0, // origin
|
||||
GridClass gridClass,
|
||||
const BufferT& allocator)
|
||||
{
|
||||
if (dx <= 0) {
|
||||
throw std::runtime_error("GridBuilder: voxel size is zero or negative");
|
||||
}
|
||||
max += Coord(1,1,1);// now max is exclusive
|
||||
|
||||
#if LOG2_TILE_SIZE > 0
|
||||
const uint64_t dim[3] = {(uint64_t(max[0] - min[0]) + TileMask) >> TileLog2,
|
||||
(uint64_t(max[1] - min[1]) + TileMask) >> TileLog2,
|
||||
(uint64_t(max[2] - min[2]) + TileMask) >> TileLog2};
|
||||
const uint64_t size = sizeof(DenseGrid) + sizeof(ValueT)*TileDim*dim[0]*dim[1]*dim[2];
|
||||
#else
|
||||
const uint64_t dim[3] = {uint64_t(max[0] - min[0]),
|
||||
uint64_t(max[1] - min[1]),
|
||||
uint64_t(max[2] - min[2])};
|
||||
const uint64_t size = sizeof(DenseGrid) + sizeof(ValueT)*dim[0]*dim[1]*dim[2];
|
||||
#endif
|
||||
|
||||
DenseGridHandle<BufferT> handle(allocator.create(size));
|
||||
DenseGrid* grid = reinterpret_cast<DenseGrid*>(handle.data());
|
||||
grid->mSize = size;
|
||||
const double Tx = p0[0], Ty = p0[1], Tz = p0[2];
|
||||
const double mat[4][4] = {
|
||||
{dx, 0.0, 0.0, 0.0}, // row 0
|
||||
{0.0, dx, 0.0, 0.0}, // row 1
|
||||
{0.0, 0.0, dx, 0.0}, // row 2
|
||||
{Tx, Ty, Tz, 1.0}, // row 3
|
||||
};
|
||||
const double invMat[4][4] = {
|
||||
{1 / dx, 0.0, 0.0, 0.0}, // row 0
|
||||
{0.0, 1 / dx, 0.0, 0.0}, // row 1
|
||||
{0.0, 0.0, 1 / dx, 0.0}, // row 2
|
||||
{-Tx, -Ty, -Tz, 1.0}, // row 3
|
||||
};
|
||||
|
||||
grid->mMap.set(mat, invMat, 1.0);
|
||||
for (int i=0; i<3; ++i) {
|
||||
grid->mIndexBBox[0][i] = min[i];
|
||||
grid->mIndexBBox[1][i] = max[i] - 1;
|
||||
}
|
||||
grid->mWorldBBox[0] = grid->mWorldBBox[1] = grid->mMap.applyMap(Vec3d(min[0], min[1], min[2]));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(min[0], min[1], max[2])));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(min[0], max[1], min[2])));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(max[0], min[1], min[2])));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(max[0], max[1], min[2])));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(max[0], min[1], max[2])));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(min[0], max[1], max[2])));
|
||||
grid->mWorldBBox.expand(grid->mMap.applyMap(Vec3d(max[0], max[1], max[2])));
|
||||
grid->mVoxelSize = grid->mMap.applyMap(Vec3d(1)) - grid->mMap.applyMap(Vec3d(0));
|
||||
if (gridClass == GridClass::LevelSet && !is_floating_point<ValueT>::value)
|
||||
throw std::runtime_error("Level sets are expected to be floating point types");
|
||||
if (gridClass == GridClass::FogVolume && !is_floating_point<ValueT>::value)
|
||||
throw std::runtime_error("Fog volumes are expected to be floating point types");
|
||||
grid->mGridClass = gridClass;
|
||||
grid->mGridType = mapToGridType<ValueT>();
|
||||
grid->mY = dim[2];
|
||||
grid->mX = dim[2] * dim[1];
|
||||
return handle;
|
||||
}
|
||||
|
||||
template<typename ValueT>
|
||||
bool DenseGrid<ValueT>::test(const Coord &ijk) const
|
||||
{
|
||||
return (ijk[0]>=mIndexBBox[0][0]) && (ijk[0]<=mIndexBBox[1][0]) &&
|
||||
(ijk[1]>=mIndexBBox[0][1]) && (ijk[1]<=mIndexBBox[1][1]) &&
|
||||
(ijk[2]>=mIndexBBox[0][2]) && (ijk[2]<=mIndexBBox[1][2]);
|
||||
}
|
||||
|
||||
template<typename ValueT>
|
||||
uint64_t DenseGrid<ValueT>::coordToOffset(const Coord &ijk) const
|
||||
{
|
||||
assert(this->test(ijk));
|
||||
#if LOG2_TILE_SIZE > 0
|
||||
const uint32_t x = ijk[0] - mIndexBBox[0][0];
|
||||
const uint32_t y = ijk[1] - mIndexBBox[0][1];
|
||||
const uint32_t z = ijk[2] - mIndexBBox[0][2];
|
||||
return ((mX*(x>>TileLog2) + mY*(y>>TileLog2) + (z>>TileLog2))<<(3*TileLog2)) +
|
||||
((x&TileMask)<<(2*TileLog2)) + ((y&TileMask)<<TileLog2) + (z&TileMask);
|
||||
#else
|
||||
return uint64_t(ijk[0]-mIndexBBox[0][0])*mX +
|
||||
uint64_t(ijk[1]-mIndexBBox[0][1])*mY +
|
||||
uint64_t(ijk[2]-mIndexBBox[0][2]);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename ValueT>
|
||||
const ValueT& DenseGrid<ValueT>::getValue(const Coord &ijk) const
|
||||
{
|
||||
return this->values()[this->coordToOffset(ijk)];
|
||||
}
|
||||
|
||||
template<typename ValueT>
|
||||
void DenseGrid<ValueT>::setValue(const Coord &ijk, const ValueT &value)
|
||||
{
|
||||
this->values()[this->coordToOffset(ijk)] = value;
|
||||
}
|
||||
|
||||
template<typename ValueT>
|
||||
bool DenseGrid<ValueT>::isValidType() const
|
||||
{
|
||||
return std::is_same<float, ValueT>::value ? mGridType == GridType::Float : false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
||||
namespace io{
|
||||
|
||||
template<typename ValueT>
|
||||
void writeDense(const DenseGrid<ValueT> &grid, const char* fileName)
|
||||
{
|
||||
std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
if (!os.is_open()) {
|
||||
throw std::runtime_error("Unable to open file for output");
|
||||
}
|
||||
const uint64_t tmp[2] = {DENSE_MAGIC_NUMBER, grid.memUsage()};
|
||||
os.write(reinterpret_cast<const char*>(tmp), 2*sizeof(uint64_t));
|
||||
os.write(reinterpret_cast<const char*>(&grid), tmp[1]);
|
||||
}
|
||||
|
||||
template<typename BufferT>
|
||||
void writeDense(const DenseGridHandle<BufferT> &handle, const char* fileName)
|
||||
{
|
||||
std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
if (!os.is_open()) {
|
||||
throw std::runtime_error("Unable to open file for output");
|
||||
}
|
||||
const uint64_t tmp[2] = {DENSE_MAGIC_NUMBER, handle.size()};
|
||||
os.write(reinterpret_cast<const char*>(tmp), 2*sizeof(uint64_t));
|
||||
os.write(reinterpret_cast<const char*>(handle.data()), tmp[1]);
|
||||
}
|
||||
|
||||
template<typename BufferT = HostBuffer>
|
||||
DenseGridHandle<BufferT>
|
||||
readDense(const char* fileName, const BufferT& allocator = BufferT())
|
||||
{
|
||||
std::ifstream is(fileName, std::ios::in | std::ios::binary);
|
||||
if (!is.is_open()) {
|
||||
throw std::runtime_error("Unable to open file for input");
|
||||
}
|
||||
uint64_t tmp[2];
|
||||
is.read(reinterpret_cast<char*>(tmp), 2*sizeof(uint64_t));
|
||||
if (tmp[0] != DENSE_MAGIC_NUMBER) {
|
||||
throw std::runtime_error("This is not a dense NanoVDB file!");
|
||||
}
|
||||
DenseGridHandle<BufferT> handle(allocator.create(tmp[1]));
|
||||
is.read(reinterpret_cast<char*>(handle.data()), tmp[1]);
|
||||
return handle;
|
||||
}
|
||||
}// namespace io
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/// @brief Converts a NanoVDB grid to a DenseGrid
|
||||
template<typename GridT, typename BufferT = HostBuffer>
|
||||
DenseGridHandle<BufferT> convertToDense(const GridT &grid, const BufferT& allocator = BufferT())
|
||||
{
|
||||
using ValueT = typename GridT::ValueType;
|
||||
using DenseT = DenseGrid<ValueT>;
|
||||
const Coord min = grid.indexBBox().min(), max = grid.indexBBox().max() + Coord(1,1,1);// max is exclusive!
|
||||
#if LOG2_TILE_SIZE > 0
|
||||
static constexpr uint32_t TileLog2 = LOG2_TILE_SIZE, TileMask = (1 << TileLog2) - 1, TileDim = 1 << (3*TileLog2);
|
||||
const uint64_t dim[3] = {(uint64_t(max[0] - min[0]) + TileMask) >> TileLog2,
|
||||
(uint64_t(max[1] - min[1]) + TileMask) >> TileLog2,
|
||||
(uint64_t(max[2] - min[2]) + TileMask) >> TileLog2};
|
||||
const uint64_t size = sizeof(DenseT) + sizeof(ValueT)*TileDim*dim[0]*dim[1]*dim[2];
|
||||
#else
|
||||
const uint64_t dim[3] = {uint64_t(max[0] - min[0]),
|
||||
uint64_t(max[1] - min[1]),
|
||||
uint64_t(max[2] - min[2])};
|
||||
const uint64_t size = sizeof(DenseT) + sizeof(ValueT)*dim[0]*dim[1]*dim[2];
|
||||
#endif
|
||||
|
||||
DenseGridHandle<BufferT> handle( allocator.create(size) );
|
||||
auto *dense = reinterpret_cast<DenseT*>(handle.data());
|
||||
auto *data = dense->data();
|
||||
|
||||
// copy DenseData
|
||||
data->mMap = grid.map();
|
||||
data->mIndexBBox = grid.indexBBox();
|
||||
data->mWorldBBox = grid.worldBBox();
|
||||
data->mVoxelSize = grid.voxelSize();
|
||||
data->mGridClass = grid.gridClass();
|
||||
data->mGridType = grid.gridType();
|
||||
data->mY = dim[2];
|
||||
data->mX = dim[2] * dim[1];
|
||||
data->mSize = size;
|
||||
|
||||
// copy values
|
||||
auto kernel = [&](const Range<1,int> &r) {
|
||||
auto acc = grid.getAccessor();
|
||||
Coord ijk;
|
||||
for (ijk[0] = r.begin(); ijk[0] < r.end(); ++ijk[0]) {
|
||||
for (ijk[1] = min[1]; ijk[1] < max[1]; ++ijk[1]) {
|
||||
for (ijk[2] = min[2]; ijk[2] < max[2]; ++ijk[2]) {
|
||||
dense->setValue(ijk, acc.getValue(ijk));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Range<1,int> range(min[0], max[0]);
|
||||
#if 1
|
||||
forEach(range, kernel);
|
||||
#else
|
||||
kernel(range);
|
||||
#endif
|
||||
|
||||
return handle;
|
||||
}
|
||||
/////////////////////////////////////////////
|
||||
|
||||
template<typename BufferT>
|
||||
class DenseGridHandle
|
||||
{
|
||||
BufferT mBuffer;
|
||||
|
||||
public:
|
||||
DenseGridHandle(BufferT&& resources) { mBuffer = std::move(resources); }
|
||||
|
||||
DenseGridHandle() = default;
|
||||
/// @brief Disallow copy-construction
|
||||
DenseGridHandle(const DenseGridHandle&) = delete;
|
||||
/// @brief Disallow copy assignment operation
|
||||
DenseGridHandle& operator=(const DenseGridHandle&) = delete;
|
||||
/// @brief Move copy assignment operation
|
||||
DenseGridHandle& operator=(DenseGridHandle&& other) noexcept
|
||||
{
|
||||
mBuffer = std::move(other.mBuffer);
|
||||
return *this;
|
||||
}
|
||||
/// @brief Move copy-constructor
|
||||
DenseGridHandle(DenseGridHandle&& other) noexcept { mBuffer = std::move(other.mBuffer); }
|
||||
/// @brief Default destructor
|
||||
~DenseGridHandle() { this->reset(); }
|
||||
|
||||
void reset() { mBuffer.clear(); }
|
||||
|
||||
BufferT& buffer() { return mBuffer; }
|
||||
const BufferT& buffer() const { return mBuffer; }
|
||||
|
||||
/// @brief Returns a non-const pointer to the data.
|
||||
///
|
||||
/// @warning Note that the return pointer can be NULL if the DenseGridHandle was not initialized
|
||||
uint8_t* data() {return mBuffer.data();}
|
||||
|
||||
/// @brief Returns a const pointer to the data.
|
||||
///
|
||||
/// @warning Note that the return pointer can be NULL if the DenseGridHandle was not initialized
|
||||
const uint8_t* data() const {return mBuffer.data();}
|
||||
|
||||
/// @brief Returns the size in bytes of the raw memory buffer managed by this DenseGridHandle's allocator.
|
||||
uint64_t size() const { return mBuffer.size();}
|
||||
|
||||
/// @brief Returns a const pointer to the NanoVDB grid encoded in the DenseGridHandle.
|
||||
///
|
||||
/// @warning Note that the return pointer can be NULL if the DenseGridHandle was not initialized or the template
|
||||
/// parameter does not match!
|
||||
template<typename ValueT>
|
||||
const DenseGrid<ValueT>* grid() const
|
||||
{
|
||||
using GridT = const DenseGrid<ValueT>;
|
||||
GridT* grid = reinterpret_cast<GridT*>(mBuffer.data());
|
||||
return (grid && grid->isValidType()) ? grid : nullptr;
|
||||
}
|
||||
|
||||
template<typename ValueT>
|
||||
DenseGrid<ValueT>* grid()
|
||||
{
|
||||
using GridT = DenseGrid<ValueT>;
|
||||
GridT* grid = reinterpret_cast<GridT*>(mBuffer.data());
|
||||
return (grid && grid->isValidType()) ? grid : nullptr;
|
||||
}
|
||||
|
||||
template<typename ValueT, typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, const DenseGrid<ValueT>*>::type
|
||||
deviceGrid() const
|
||||
{
|
||||
using GridT = const DenseGrid<ValueT>;
|
||||
bool isValidType = reinterpret_cast<GridT*>(mBuffer.data())->isValidType();
|
||||
GridT* grid = reinterpret_cast<GridT*>(mBuffer.deviceData());
|
||||
return (grid && isValidType) ? grid : nullptr;
|
||||
}
|
||||
|
||||
template<typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
|
||||
deviceUpload(void* stream = nullptr, bool sync = true) {
|
||||
mBuffer.deviceUpload(stream, sync);
|
||||
}
|
||||
|
||||
template<typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
|
||||
deviceDownload(void* stream = nullptr, bool sync = true) {
|
||||
mBuffer.deviceDownload(stream, sync);
|
||||
}
|
||||
}; // DenseGridHandle
|
||||
|
||||
} // namespace nanovdb
|
||||
|
||||
#endif // NANOVDB_DENSEGRID_HAS_BEEN_INCLUDED
|
||||
@@ -0,0 +1,159 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/*!
|
||||
\file Image.h
|
||||
|
||||
\author Ken Museth
|
||||
|
||||
\date January 8, 2020
|
||||
|
||||
\brief A simple image class that uses pinned memory for fast GPU transfer
|
||||
|
||||
\warning This class is only included to support benchmark-tests.
|
||||
*/
|
||||
|
||||
#ifndef NANOVDB_IMAGE_H_HAS_BEEN_INCLUDED
|
||||
#define NANOVDB_IMAGE_H_HAS_BEEN_INCLUDED
|
||||
|
||||
#include <stdint.h> // for uint8_t
|
||||
#include <string> // for std::string
|
||||
#include <fstream> // for std::ofstream
|
||||
#include <cassert>
|
||||
|
||||
#include <nanovdb/util/HostBuffer.h>
|
||||
|
||||
#if defined(NANOVDB_USE_TBB)
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range2d.h>
|
||||
#endif
|
||||
|
||||
namespace nanovdb {
|
||||
|
||||
struct ImageData
|
||||
{
|
||||
int mWidth, mHeight, mSize;
|
||||
float mScale[2];
|
||||
ImageData(int w, int h)
|
||||
: mWidth(w)
|
||||
, mHeight(h)
|
||||
, mSize(w * h)
|
||||
, mScale{1.0f / w, 1.0f / h}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// @note Can only be constructed by an ImageHandle
|
||||
class Image : private ImageData
|
||||
{
|
||||
using DataT = ImageData;
|
||||
|
||||
public:
|
||||
struct ColorRGB
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
__hostdev__ ColorRGB(float _r, float _g, float _b)
|
||||
: r(uint8_t(_r * 255.0f))
|
||||
, g(uint8_t(_g * 255.0f))
|
||||
, b(uint8_t(_b * 255.0f))
|
||||
{
|
||||
}
|
||||
};
|
||||
void clear(int log2 = 7);
|
||||
__hostdev__ int width() const { return DataT::mWidth; }
|
||||
__hostdev__ int height() const { return DataT::mHeight; }
|
||||
__hostdev__ int size() const { return DataT::mSize; }
|
||||
__hostdev__ float u(int w) const { return w * mScale[0]; }
|
||||
__hostdev__ float v(int h) const { return h * mScale[1]; }
|
||||
__hostdev__ inline ColorRGB& operator()(int w, int h);
|
||||
void writePPM(const std::string& fileName, const std::string& comment = "width height 255");
|
||||
}; // Image
|
||||
|
||||
template<typename BufferT = HostBuffer>
|
||||
class ImageHandle
|
||||
{
|
||||
BufferT mBuffer;
|
||||
|
||||
public:
|
||||
ImageHandle(int width, int height, int log2 = 7);
|
||||
|
||||
const Image* image() const { return reinterpret_cast<const Image*>(mBuffer.data()); }
|
||||
|
||||
Image* image() { return reinterpret_cast<Image*>(mBuffer.data()); }
|
||||
|
||||
template<typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, const Image*>::type
|
||||
deviceImage() const { return reinterpret_cast<const Image*>(mBuffer.deviceData()); }
|
||||
|
||||
template<typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, Image*>::type
|
||||
deviceImage() { return reinterpret_cast<Image*>(mBuffer.deviceData()); }
|
||||
|
||||
template<typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
|
||||
deviceUpload(void* stream = nullptr, bool sync = true) { mBuffer.deviceUpload(stream, sync); }
|
||||
|
||||
template<typename U = BufferT>
|
||||
typename std::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
|
||||
deviceDownload(void* stream = nullptr, bool sync = true) { mBuffer.deviceDownload(stream, sync); }
|
||||
};
|
||||
|
||||
template<typename BufferT>
|
||||
ImageHandle<BufferT>::ImageHandle(int width, int height, int log2)
|
||||
: mBuffer(sizeof(ImageData) + width * height * sizeof(Image::ColorRGB))
|
||||
{
|
||||
ImageData data(width, height);
|
||||
*reinterpret_cast<ImageData*>(mBuffer.data()) = data;
|
||||
this->image()->clear(log2); // clear pixels or set background
|
||||
}
|
||||
|
||||
inline void Image::clear(int log2)
|
||||
{
|
||||
ColorRGB* ptr = &(*this)(0, 0);
|
||||
if (log2 < 0) {
|
||||
for (auto* end = ptr + ImageData::mSize; ptr != end;)
|
||||
*ptr++ = ColorRGB(0, 0, 0);
|
||||
} else {
|
||||
const int checkerboard = 1 << log2;
|
||||
|
||||
auto kernel2D = [&](int x0, int y0, int x1, int y1) {
|
||||
for (int h = y0; h != y1; ++h) {
|
||||
const int n = h & checkerboard;
|
||||
ColorRGB* p = ptr + h * ImageData::mWidth;
|
||||
for (int w = x0; w != x1; ++w) {
|
||||
*(p + w) = (n ^ (w & checkerboard)) ? ColorRGB(1, 1, 1) : ColorRGB(0, 0, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(NANOVDB_USE_TBB)
|
||||
tbb::blocked_range2d<int> range(0, ImageData::mWidth, 0, ImageData::mHeight);
|
||||
tbb::parallel_for(range, [&](const tbb::blocked_range2d<int>& r) {
|
||||
kernel2D(r.rows().begin(), r.cols().begin(), r.rows().end(), r.cols().end());
|
||||
});
|
||||
#else
|
||||
kernel2D(0, 0, ImageData::mWidth, ImageData::mHeight);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline Image::ColorRGB& Image::operator()(int w, int h)
|
||||
{
|
||||
assert(w < ImageData::mWidth);
|
||||
assert(h < ImageData::mHeight);
|
||||
return *(reinterpret_cast<ColorRGB*>((uint8_t*)this + sizeof(ImageData)) + w + h * ImageData::mWidth);
|
||||
}
|
||||
|
||||
inline void Image::writePPM(const std::string& fileName, const std::string& comment)
|
||||
{
|
||||
std::ofstream os(fileName, std::ios::out | std::ios::binary);
|
||||
if (os.fail())
|
||||
throw std::runtime_error("Unable to open file named \"" + fileName + "\" for output");
|
||||
os << "P6\n#" << comment << "\n"
|
||||
<< this->width() << " " << this->height() << "\n255\n";
|
||||
os.write((const char*)&(*this)(0, 0), this->size() * sizeof(ColorRGB));
|
||||
}
|
||||
|
||||
} // namespace nanovdb
|
||||
|
||||
#endif // end of NANOVDB_IMAGE_H_HAS_BEEN_INCLUDED
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <nanovdb/util/Primitives.h>
|
||||
#include <nanovdb/util/IO.h>
|
||||
#include <nanovdb/util/HostBuffer.h>
|
||||
#include <algorithm>
|
||||
|
||||
//////////////////////////////////////////////
|
||||
class BumpPoolAllocatorContext
|
||||
{
|
||||
public:
|
||||
uint64_t mNextFreeOffset;
|
||||
nanovdb::HostBuffer mPoolSlab;
|
||||
|
||||
BumpPoolAllocatorContext(uint64_t size)
|
||||
: mNextFreeOffset(0)
|
||||
{
|
||||
mPoolSlab.init(size);
|
||||
std::cout << "Created BumpPoolAllocatorContext" << std::endl;
|
||||
}
|
||||
|
||||
~BumpPoolAllocatorContext()
|
||||
{
|
||||
mPoolSlab.clear();
|
||||
std::cout << "Destroyed BumpPoolAllocatorContext" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
// This is an example of a custom Buffer with has a persistent state allocator ("mState") within it.
|
||||
// It must have methods for "clear", "data" (both const and non-const variants), and "size".
|
||||
// It must also include a static "create" method.
|
||||
class PoolBuffer
|
||||
{
|
||||
uint64_t mOffset = -1;
|
||||
uint64_t mSize = 0;
|
||||
std::shared_ptr<BumpPoolAllocatorContext> mState;
|
||||
|
||||
public:
|
||||
PoolBuffer() = default;
|
||||
PoolBuffer(const PoolBuffer&) = delete;
|
||||
PoolBuffer& operator=(const PoolBuffer&) = delete;
|
||||
PoolBuffer(PoolBuffer&&) = default;
|
||||
PoolBuffer& operator=(PoolBuffer&&) = default;
|
||||
|
||||
// Initialize the stateful allocator.
|
||||
void initialize(uint64_t size)
|
||||
{
|
||||
if (!mState) {
|
||||
mState = std::make_shared<BumpPoolAllocatorContext>(size);
|
||||
}
|
||||
}
|
||||
|
||||
// Mandatory.
|
||||
// Create a buffer instance (optionally using the context as a hint)
|
||||
static PoolBuffer create(uint64_t size, const PoolBuffer* context)
|
||||
{
|
||||
if (!context || !context->mState) {
|
||||
throw std::runtime_error("context has not been created.");
|
||||
}
|
||||
|
||||
PoolBuffer buffer;
|
||||
buffer.mState = context->mState;
|
||||
buffer.mOffset = context->mState->mNextFreeOffset;
|
||||
buffer.mSize = size;
|
||||
context->mState->mNextFreeOffset += size;
|
||||
|
||||
printf("Creating resources offset(%d) size(%d)\n", (int)buffer.mOffset, (int)buffer.mSize);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Mandatory.
|
||||
// Clear the buffer data.
|
||||
void clear()
|
||||
{
|
||||
// nothing to do, as this is a simple "bump" allocator.
|
||||
}
|
||||
|
||||
// Mandatory.
|
||||
// Return the size of the buffer data.
|
||||
uint64_t size() const { return mSize; }
|
||||
|
||||
// Mandatory.
|
||||
// Return non-const pointer to the buffer data.
|
||||
uint8_t* data() { return mState->mPoolSlab.data() + mOffset; }
|
||||
|
||||
// Mandatory.
|
||||
// Return const pointer to the buffer data.
|
||||
const uint8_t* data() const { return mState->mPoolSlab.data() + mOffset; }
|
||||
};
|
||||
|
||||
// we specify this trait to avoid declaring the "device...(...)" convenience methods.
|
||||
// By default, "hasDeviceDual" is false for a Buffer, but we are just being overly explicit here.
|
||||
namespace nanovdb {
|
||||
template<>
|
||||
struct BufferTraits<PoolBuffer>
|
||||
{
|
||||
static const bool hasDeviceDual = false;
|
||||
};
|
||||
} // namespace nanovdb
|
||||
|
||||
int main()
|
||||
{
|
||||
PoolBuffer bufferContext;
|
||||
// We must initialize the stateful allocator.
|
||||
bufferContext.initialize(1 << 26);
|
||||
|
||||
try {
|
||||
std::vector<nanovdb::GridHandle<PoolBuffer>> gridHdls;
|
||||
|
||||
// create two grids...
|
||||
gridHdls.push_back(nanovdb::createLevelSetSphere(100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "spheref", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, bufferContext));
|
||||
gridHdls.push_back(nanovdb::createLevelSetSphere(100.0, nanovdb::Vec3d( 20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "sphered", nanovdb::StatsMode::BBox, nanovdb::ChecksumMode::Partial, -1.0f, false, bufferContext));
|
||||
|
||||
// Get a (raw) pointer to the NanoVDB grid form the GridManager.
|
||||
auto* dstGrid = gridHdls[0].grid<float>();
|
||||
if (!dstGrid)
|
||||
throw std::runtime_error("GridHandle does not contain a grid with value type float");
|
||||
|
||||
// Access and print out a single value (inside the level set) from both grids
|
||||
printf("NanoVDB cpu: %4.2f\n", dstGrid->tree().getValue(nanovdb::Coord(99, 0, 0)));
|
||||
|
||||
// Write the NanoVDB grids to file and throw if writing fails
|
||||
nanovdb::io::writeGrids<PoolBuffer, std::vector>("data/spheres.nvdb", gridHdls, nanovdb::io::Codec::NONE, 2);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <nanovdb/NanoVDB.h>
|
||||
#include "ComputePrimitives.h"
|
||||
|
||||
// http://www.burtleburtle.net/bob/hash/doobs.html
|
||||
inline __hostdev__ uint32_t hash(uint32_t x)
|
||||
{
|
||||
x += (x << 10u);
|
||||
x ^= (x >> 6u);
|
||||
x += (x << 3u);
|
||||
x ^= (x >> 11u);
|
||||
x += (x << 15u);
|
||||
return x;
|
||||
}
|
||||
|
||||
inline __hostdev__ float randomf(uint32_t s)
|
||||
{
|
||||
return hash(s) / float(0xffffffffu);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <nanovdb/util/IO.h>
|
||||
#include <nanovdb/util/Primitives.h>
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h>
|
||||
|
||||
#if defined(NANOVDB_USE_CUDA)
|
||||
using BufferT = nanovdb::CudaDeviceBuffer;
|
||||
#else
|
||||
using BufferT = nanovdb::HostBuffer;
|
||||
#endif
|
||||
|
||||
extern void runNanoVDB(nanovdb::GridHandle<BufferT>& handle, int numIterations, int numPoints, BufferT& positionBuffer, BufferT& velocityBuffer);
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
extern void runOpenVDB(nanovdb::GridHandle<BufferT>& handle, int numIterations, int numPoints, BufferT& positionBuffer, BufferT& velocityBuffer);
|
||||
#endif
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
try {
|
||||
nanovdb::GridHandle<BufferT> handle;
|
||||
if (ac > 1) {
|
||||
handle = nanovdb::io::readGrid<BufferT>(av[1]);
|
||||
std::cout << "Loaded NanoVDB grid[" << handle.gridMetaData()->shortGridName() << "]...\n";
|
||||
} else {
|
||||
handle = nanovdb::createLevelSetSphere<float, float, BufferT>(100.0f, nanovdb::Vec3f(-20, 0, 0), 1.0, 3.0, nanovdb::Vec3R(0), "sphere");
|
||||
}
|
||||
|
||||
if (handle.gridMetaData()->isLevelSet() == false) {
|
||||
throw std::runtime_error("Grid must be a level set");
|
||||
}
|
||||
|
||||
const int numIterations = 100;
|
||||
|
||||
const int numPoints = 10000000;
|
||||
|
||||
BufferT positionBuffer;
|
||||
positionBuffer.init(numPoints * sizeof(float) * 3);
|
||||
BufferT velocityBuffer;
|
||||
velocityBuffer.init(numPoints * sizeof(float) * 3);
|
||||
|
||||
runNanoVDB(handle, numIterations, numPoints, positionBuffer, velocityBuffer);
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
runOpenVDB(handle, numIterations, numPoints, positionBuffer, velocityBuffer);
|
||||
#endif
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "An exception occurred: \"" << e.what() << "\"" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
|
||||
#include <nanovdb/util/IO.h>
|
||||
#include <nanovdb/util/GridBuilder.h>
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h>
|
||||
#include <nanovdb/util/Ray.h>
|
||||
#include <nanovdb/util/HDDA.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(NANOVDB_USE_CUDA)
|
||||
using BufferT = nanovdb::CudaDeviceBuffer;
|
||||
#else
|
||||
using BufferT = nanovdb::HostBuffer;
|
||||
#endif
|
||||
|
||||
using namespace nanovdb;
|
||||
|
||||
template<typename UpdateOp>
|
||||
float updateParticles(bool useCuda, const UpdateOp op, int numPoints, Vec3f* positions, Vec3f* velocities, const Grid<FloatTree>* grid)
|
||||
{
|
||||
using ClockT = std::chrono::high_resolution_clock;
|
||||
auto t0 = ClockT::now();
|
||||
|
||||
computeForEach(
|
||||
useCuda, numPoints, 512, __FILE__, __LINE__, [op, positions, velocities, grid] __hostdev__(int start, int end) {
|
||||
for (int i = start; i < end; ++i) {
|
||||
op(i, positions, velocities, grid);
|
||||
}
|
||||
});
|
||||
computeSync(useCuda, __FILE__, __LINE__);
|
||||
|
||||
auto t1 = ClockT::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count() / 1000.f;
|
||||
return duration;
|
||||
}
|
||||
|
||||
void runNanoVDB(nanovdb::GridHandle<BufferT>& handle, int numIterations, int numPoints, BufferT& positionBuffer, BufferT& velocityBuffer)
|
||||
{
|
||||
using namespace nanovdb;
|
||||
|
||||
auto* h_grid = handle.grid<float>();
|
||||
if (!h_grid)
|
||||
throw std::runtime_error("GridHandle does not contain a FloatGrid");
|
||||
|
||||
Vec3f* h_positions = reinterpret_cast<Vec3f*>(positionBuffer.data());
|
||||
computeFill(false, h_positions, 0, sizeof(Vec3f) * numPoints);
|
||||
|
||||
Vec3f* h_velocities = reinterpret_cast<Vec3f*>(velocityBuffer.data());
|
||||
computeFill(false, h_velocities, 0, sizeof(Vec3f) * numPoints);
|
||||
|
||||
Vec3f wBBoxDim = Vec3f(h_grid->worldBBox().dim());
|
||||
Vec3f wBBoxBottomCenter = Vec3f(h_grid->worldBBox().min()) + wBBoxDim * Vec3f(0.5f, 0, 0.5f);
|
||||
|
||||
const float dt = 0.01f;
|
||||
|
||||
auto collisionResponse = [] __hostdev__(Vec3f pos, Vec3f nextPos, Vec3f normal, float d, Vec3f& outP, Vec3f& outV) {
|
||||
Vec3f delta = (nextPos - pos).normalize() * d;
|
||||
outP = nextPos + delta;
|
||||
outV = outV - 2.0f * (outV.dot(normal) * normal);
|
||||
};
|
||||
|
||||
auto collideOp = [collisionResponse, dt] __hostdev__(const Grid<FloatTree>* grid, Vec3f wPos, Vec3f& wNextPos, Vec3f wVel, Vec3f& wNextVel) {
|
||||
// transform the position to grid index-space...
|
||||
Vec3f iNextPos = grid->worldToIndexF(wNextPos);
|
||||
// the grid index coordinate.
|
||||
auto ijk = Coord::Floor(iNextPos);
|
||||
// get an accessor.
|
||||
auto& tree = grid->tree();
|
||||
auto acc = tree.getAccessor();
|
||||
if (tree.isActive(ijk)) { // are we inside the narrow band?
|
||||
auto wDistance = acc.getValue(ijk);
|
||||
if (wDistance <= 0) { // are we inside the levelset?
|
||||
// get the normal for collision resolution.
|
||||
Vec3f normal(-wDistance);
|
||||
ijk[0] += 1;
|
||||
normal[0] += acc.getValue(ijk);
|
||||
ijk[0] -= 1;
|
||||
ijk[1] += 1;
|
||||
normal[1] += acc.getValue(ijk);
|
||||
ijk[1] -= 1;
|
||||
ijk[2] += 1;
|
||||
normal[2] += acc.getValue(ijk);
|
||||
normal.normalize();
|
||||
|
||||
// handle collision response with the surface.
|
||||
collisionResponse(wPos, wNextPos, normal, wDistance, wNextPos, wNextVel);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto updateOp = [wBBoxBottomCenter, wBBoxDim, collideOp, dt] __hostdev__(int i, Vec3f* positions, Vec3f* velocities, const Grid<FloatTree>* grid) {
|
||||
Vec3f v = velocities[i];
|
||||
Vec3f p = positions[i];
|
||||
// gravity.
|
||||
Vec3f a = Vec3f(0, -9.8f, 0);
|
||||
// integrate.
|
||||
Vec3f nextP = p + v * dt + a * dt * dt;
|
||||
Vec3f nextV = v + a * dt;
|
||||
|
||||
//printf("%f %f %f\n", p[0], p[1], p[2]);
|
||||
|
||||
if (nextP[1] < 0) {
|
||||
// emit at top.
|
||||
nextP = Vec3f(randomf(i * 2 + 0), wBBoxDim[1], randomf(i * 2 + 1));
|
||||
nextV = Vec3f(0, 0, 0);
|
||||
} else {
|
||||
// collision response...
|
||||
collideOp(grid, p, nextP, v, nextV);
|
||||
}
|
||||
|
||||
positions[i] = nextP;
|
||||
velocities[i] = nextV;
|
||||
};
|
||||
|
||||
{
|
||||
float durationAvg = 0;
|
||||
for (int i = 0; i < numIterations; ++i) {
|
||||
float duration = updateParticles(false, updateOp, numPoints, h_positions, h_velocities, h_grid);
|
||||
//std::cout << "Duration(NanoVDB-Host) = " << duration << " ms" << std::endl;
|
||||
durationAvg += duration;
|
||||
}
|
||||
durationAvg /= numIterations;
|
||||
std::cout << "Average Duration(NanoVDB-Host) = " << durationAvg << " ms" << std::endl;
|
||||
}
|
||||
|
||||
#if defined(NANOVDB_USE_CUDA)
|
||||
|
||||
handle.deviceUpload();
|
||||
|
||||
auto* d_grid = handle.deviceGrid<float>();
|
||||
if (!d_grid)
|
||||
throw std::runtime_error("GridHandle does not contain a valid device grid");
|
||||
|
||||
positionBuffer.deviceUpload();
|
||||
Vec3f* d_positions = reinterpret_cast<Vec3f*>(positionBuffer.deviceData());
|
||||
|
||||
velocityBuffer.deviceUpload();
|
||||
Vec3f* d_velocities = reinterpret_cast<Vec3f*>(velocityBuffer.deviceData());
|
||||
|
||||
{
|
||||
float durationAvg = 0;
|
||||
for (int i = 0; i < numIterations; ++i) {
|
||||
float duration = updateParticles(true, updateOp, numPoints, d_positions, d_velocities, d_grid);
|
||||
//std::cout << "Duration(NanoVDB-Cuda) = " << duration << " ms" << std::endl;
|
||||
durationAvg += duration;
|
||||
}
|
||||
durationAvg /= numIterations;
|
||||
std::cout << "Average Duration(NanoVDB-Cuda) = " << durationAvg << " ms" << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#if defined(NANOVDB_USE_OPENVDB)
|
||||
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
|
||||
#include <openvdb/openvdb.h>
|
||||
#include <openvdb/math/Ray.h>
|
||||
|
||||
#include <nanovdb/util/CudaDeviceBuffer.h>
|
||||
#include <nanovdb/util/NanoToOpenVDB.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(NANOVDB_USE_CUDA)
|
||||
using BufferT = nanovdb::CudaDeviceBuffer;
|
||||
#else
|
||||
using BufferT = nanovdb::HostBuffer;
|
||||
#endif
|
||||
|
||||
void runOpenVDB(nanovdb::GridHandle<BufferT>& handle, int numIterations, int numPoints, BufferT& positionBuffer, BufferT& velocityBuffer)
|
||||
{
|
||||
using GridT = openvdb::FloatGrid;
|
||||
using CoordT = openvdb::Coord;
|
||||
using RealT = float;
|
||||
using Vec3T = openvdb::math::Vec3<RealT>;
|
||||
using RayT = openvdb::math::Ray<RealT>;
|
||||
|
||||
auto srcGrid = nanovdb::nanoToOpenVDB(handle);
|
||||
std::cout << "Exporting to OpenVDB grid[" << srcGrid->getName() << "]...\n";
|
||||
|
||||
auto h_grid = (GridT*)srcGrid.get();
|
||||
|
||||
// Not yet implemented...
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user