Compare commits

..
Author SHA1 Message Date
Nick Avramoussis e7ec6329dc Auto sign off doc update commits
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-29 13:59:16 +01:00
Nick Avramoussis a28c227175 Testing documentation publishing
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 21:57:20 +01:00
Nick Avramoussis 30e59dc432 Testing documentation publishing
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 21:48:05 +01:00
Nick Avramoussis 3fff04fa64 Testing documentation publishing
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 21:13:42 +01:00
Nick Avramoussis a75b75617b Testing documentation publishing
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 20:54:45 +01:00
Nick Avramoussis 9abae44383 Temporarily remove other workflows for testing
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 20:32:48 +01:00
Nick Avramoussis 7fffe564ef Minor adjustments to auto doxygen deployment
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 20:30:37 +01:00
Nick Avramoussis 375c683456 Minor adjustments to auto doxygen deployment
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 20:09:08 +01:00
Nick Avramoussis 960336887b Merge branch 'master' into feature/docs
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2022-04-28 18:55:33 +01:00
Dan Bailey 6966d7453d Merge pull request #1252 from Idclip/deploy_docs_to_website
Changed the docs workflow to deploy to the website repo
2021-11-18 14:19:06 -08:00
Nick Avramoussis d0b0556a6c Changed the docs workflow to deploy to the website repo
Signed-off-by: Nick Avramoussis <4256455+Idclip@users.noreply.github.com>
2021-11-17 20:14:42 +00:00
1135 changed files with 417680 additions and 199 deletions
+28
View File
@@ -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.)
+20
View File
@@ -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.)
+85
View File
@@ -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>"
-3
View File
@@ -1,4 +1 @@
/build/*
**/src/benchmarks/build/*
nanovdb/nanovdb/build/*
.DS_Store
+3040
View File
File diff suppressed because it is too large Load Diff
+568
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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).
+347 -150
View File
@@ -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.
+16
View File
@@ -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
+129 -18
View File
@@ -1,28 +1,139 @@
# *ƒ*(VDB)
![OpenVDB](https://www.openvdb.org/images/openvdb_logo.png)
## 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://img.shields.io/github/license/AcademySoftwareFoundation/openvdb)](LICENSE)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2774/badge)](https://bestpractices.coreinfrastructure.org/projects/2774)
[![Slack](https://slack.aswf.io/badge.svg)](https://slack.aswf.io/)
### [fvdb-examples](https://github.com/openvdb/fvdb-examples)
| OpenVDB | AX | Nano | Houdini |
| :----: | :----: | :----: | :----: |
| [![core](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/build.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/build.yml) | [![ax](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/ax.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/ax.yml) | [![nano](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/nanovdb.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/nanovdb.yml) | [![hou](https://github.com/AcademySoftwareFoundation/openvdb/actions/workflows/houdini.yml/badge.svg)](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
View File
@@ -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
+22
View File
@@ -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
+170
View File
@@ -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!')
+59
View File
@@ -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
+106
View File
@@ -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
+92
View File
@@ -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
+36
View File
@@ -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
+15
View File
@@ -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
+18
View File
@@ -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
+18
View File
@@ -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
+32
View File
@@ -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
+37
View File
@@ -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
+26
View File
@@ -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
+7
View File
@@ -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
+170
View File
@@ -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
}
+21
View File
@@ -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
+33
View File
@@ -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
+384
View File
@@ -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()
+320
View File
@@ -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()
+447
View File
@@ -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()
+190
View File
@@ -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()
+344
View File
@@ -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()
+442
View File
@@ -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()
+839
View File
@@ -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)
+441
View File
@@ -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()
+147
View File
@@ -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()
+419
View File
@@ -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()
+253
View File
@@ -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()
+164
View File
@@ -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()
+41
View File
@@ -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)
+266
View 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()
+69
View File
@@ -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)
+30
View File
@@ -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
+274
View File
@@ -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>,&nbsp;<i>j</i>,&nbsp;<i>k</i>)"]]
[[xyz="(<i>x</i>,&nbsp;<i>y</i>,&nbsp;<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
View File
File diff suppressed because it is too large Load Diff
+496
View File
@@ -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>
*/
+267
View File
@@ -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>
*/
+886
View File
@@ -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>
*/
+47
View File
@@ -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&nbsp;(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>
*/
+72
View File
@@ -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
+103
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+309
View File
@@ -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&rsquo;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&rsquo;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&lt;int&gt;(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.
*/
+214
View File
@@ -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
View File
@@ -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">&ldquo;VDB:&nbsp;High-Resolution Sparse Volumes with Dynamic Topology&rdquo;</A>.
@b OpenVDB is maintained by the
<A HREF="https://www.aswf.io/">Academy Software Foundation&nbsp;(ASWF)</A>.
It was originally developed at
<A HREF="https://www.dreamworksanimation.com/">DreamWorks Animation</A>,
primarily by
- Ken Museth
- Peter Cucka
- Mihai Ald&eacute;n
- David Hill
See the @subpage changes "Release Notes" for what&rsquo;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)&nbsp;the @vdblink::tree::Tree Tree@endlink, a B-tree-like
three-dimensional data structure;
(2)&nbsp;the @vdblink::math::Transform Transform@endlink, which relates
voxel indices @ijk to physical locations @xyz in
@ref subsecWorSpace &ldquo;world&rdquo; space; and
(3)&nbsp;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&rsquo;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,&nbsp;4,&nbsp;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&times;8&times;8 voxel grid). Internally, the @b LeafNode is said
to be at &ldquo;level&nbsp;0&rdquo; of the tree.
At &ldquo;level&nbsp;1&rdquo; of this tree is the first @b InternalNode,
and it indexes a 2<SUP>4</SUP>&times;2<SUP>4</SUP>&times;2<SUP>4</SUP>
= 16&times;16&times;16 grid, each entry of which is either a @b LeafNode
or a constant value that represents an 8&times;8&times;8 block of
voxels. At &ldquo;level&nbsp;2&rdquo; is the second @b InternalNode in this
configuration; it in turn indexes a
2<SUP>5</SUP>&times;2<SUP>5</SUP>&times;2<SUP>5</SUP> = 32&times;32&times;32
grid of level-1 <B>InternalNode</B>s and/or values,
and so the @b InternalNode at level&nbsp;2 subsumes a three-dimensional
block of voxels of size 32&times;16&times;8 = 4096 on a side. Unlike
the <B>InternalNode</B>s and <B>LeafNode</B>s, the @b RootNode
(&ldquo;level&nbsp;3&rdquo; 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&rsquo;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 &ldquo;uninteresting&rdquo; 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&nbsp;1 is equivalent to a constant-value cube of
voxels of the same size, 8&times;8&times;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 &ldquo;interesting&rdquo; 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 (&ldquo;far&rdquo;) 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&nbsp;&Delta; between indices, so that
@xyz = (&Delta;<I>i</I>,&nbsp;&Delta;<I>j</I>,&nbsp;&Delta;<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&nbsp;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&rsquo;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 &ldquo;world-space&rdquo;, meaning that
if the grid is vector-valued, its voxel values should be transformed.
Alternatively, voxel values of grids identified as
&ldquo;local-space&rdquo;, via
@vdblink::Grid::setIsInWorldSpace() setIsInWorldSpace@endlink, do not
undergo transformation.
A world-space grid&rsquo;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&rsquo;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>&nbsp;[Wikipedia]).
The @vdblink::tools::transformVectors() transformVectors@endlink tool can be
used to apply a transform to a grid&rsquo;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&rsquo;s
file I/O routines recognize an ordinal suffix:
&ldquo;<TT>[0]</TT>&rdquo; refers to the first unnamed grid,
&ldquo;<TT>[1]</TT>&rdquo; refers to the second, and so on, and
&ldquo;<TT>density[0]</TT>&rdquo; and &ldquo;<TT>density[1]</TT>&rdquo;
refer to the first and second grids named &ldquo;density&rdquo;.
Also of interest for file I/O is a grid&rsquo;s
&ldquo;@vdblink::Grid::setSaveFloatAsHalf() save float as half@endlink&rdquo;
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&rsquo;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 &ldquo;begin&rdquo;
iterators closely mirrors that of the iterators themselves.
That is, @b Grid::cbeginValueOn returns a @c const iterator to the first
of a grid&rsquo;s active values, whereas @b LeafNode::beginValueAll returns
a non-<TT>const</TT> iterator to the first of a leaf node&rsquo;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&nbsp;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&mdash;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&nbsp;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&rsquo;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&rsquo;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&rsquo; 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&rsquo;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
View File
File diff suppressed because it is too large Load Diff
+235
View File
@@ -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&rsquo;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&nbsp;Transactions on Graphics</i>.
@section sLevelSet Is OpenVDB primarily for level set applications?
No! Don&rsquo;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&rsquo;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&rsquo;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&mdash;and therefore slower, but thread-safe&mdash;random access
is possible through a grid&rsquo;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&rsquo;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&rsquo;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&rsquo;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&nbsp;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&rsquo;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
View File
@@ -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&rsquo;s tooltip is used to describe the parameter
on the Help page for its operator.
More detailed documentation in Houdini&rsquo;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&rsquo; 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&rsquo;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&rsquo;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&rsquo;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&rsquo;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&rsquo;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&rsquo;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&rsquo;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&rsquo;s return value is ignored, so it&rsquo;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&rsquo;s
necessary to know the specific type, because @b prune takes an optional
tolerance argument whose type is the type of the grid&rsquo;s voxel values.
(Note that grids also have a @b pruneGrid method that doesn&rsquo;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
View File
@@ -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&nbsp;(1,&nbsp;2,&nbsp;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&times;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 &ldquo;first&rdquo; cell vertex often is aligned
with the origin.
In the cell-centered case, when the cells are cubes of length &Delta;
on a side, the transform @xyz = (&Delta;<I>i</I> + &Delta;/2,
&Delta;<I>j</I> + &Delta;/2, &Delta;<I>k</I> + &Delta; /2)
will place the center of the first cube (i.e., the image of (0,0,0))
at the world space location of (&Delta;/2,&nbsp;&Delta;/2,&nbsp;&Delta;/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 = (&Delta;<I>i</I>,&nbsp;&Delta;<I>j</I>,&nbsp;&Delta;<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&rsquo;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>&minus;1/2,&nbsp;<I>j</I>,&nbsp;<I>k</I>) face, the second element
with (<I>i</I>,&nbsp;<I>j</I>&minus;1/2,&nbsp;<I>k</I>), and
the third element with (<I>i</I>,&nbsp;<I>j</I>,&nbsp;<I>k</I>&minus;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 = (&Delta;<I>i</I>,&nbsp;&Delta;<I>j</I>,&nbsp;&Delta;<I>k</I>),
where &Delta; 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&times;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&rsquo;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&rsquo;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>&minus;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
*/
+37
View File
@@ -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).
+154
View File
@@ -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);
}
```
+55
View File
@@ -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`.
+44
View File
@@ -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
```
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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,&nbsp;value) pairs or, in the case of grids, through
a dictionary-like interface.
Add (name,&nbsp;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&rsquo;s metadata by supplying
a (name,&nbsp;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&rsquo;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&rsquo;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,&nbsp;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&rsquo;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&rsquo;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,&nbsp;0,&nbsp;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,&nbsp;0,&nbsp;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&nbsp;<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 &ldquo;inherit&rdquo; 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.
*/
-28
View File
@@ -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.
+273
View File
@@ -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()
+715
View File
@@ -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
+15
View File
@@ -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
[![CircleCI](https://circleci.com/gh/NVIDIA-Omniverse/NanoVDB.svg?style=svg&circle-token=6c3b9bb166841033a0e0c1a9ee5ac49f73d89152)](https://circleci.com/gh/NVIDIA-Omniverse/NanoVDB)
+48
View File
@@ -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;
}
+324
View File
@@ -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;
}
+33
View File
@@ -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)
+305
View File
@@ -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&rsquo;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&rsquo;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&lt;int&gt;(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
+115
View File
@@ -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
+159
View File
@@ -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