diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index e343502043a..ea428210975 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -103,13 +103,9 @@ if(WITH_TBB) endif() if(WITH_OPENVDB) - add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) list(APPEND INC ../../openvdb ) - list(APPEND INC_SYS - ${OPENVDB_INCLUDE_DIRS} - ) list(APPEND LIB ${OPENVDB_LIBRARIES} ) diff --git a/intern/cycles/hydra/CMakeLists.txt b/intern/cycles/hydra/CMakeLists.txt index c4cfd09c6a9..4ed95eb57df 100644 --- a/intern/cycles/hydra/CMakeLists.txt +++ b/intern/cycles/hydra/CMakeLists.txt @@ -68,13 +68,6 @@ set(SRC_HD_CYCLES volume.cpp ) -if(WITH_OPENVDB) - add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) - list(APPEND INC_SYS - ${OPENVDB_INCLUDE_DIRS} - ) -endif() - # Blender libraries do not include hgiGL, so build without display driver then. if(EXISTS ${USD_INCLUDE_DIR}/pxr/imaging/hgiGL) add_definitions(-DWITH_HYDRA_DISPLAY_DRIVER) diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt index dd2776ce29d..66c9fb6794f 100644 --- a/intern/cycles/scene/CMakeLists.txt +++ b/intern/cycles/scene/CMakeLists.txt @@ -128,18 +128,9 @@ if(WITH_OPENCOLORIO) endif() if(WITH_OPENVDB) - add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) - list(APPEND INC_SYS - ${OPENVDB_INCLUDE_DIRS} - ) list(APPEND LIB ${OPENVDB_LIBRARIES} ) - - # This works around the issue described in #120317 and https://github.com/AcademySoftwareFoundation/openvdb/pull/1786 - if(MSVC_CLANG) - set_source_files_properties(image_vdb.cpp PROPERTIES COMPILE_FLAGS -fno-delayed-template-parsing) - endif() endif() if(WITH_ALEMBIC) diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp index 04f7912d9ab..bb1a4eb536c 100644 --- a/intern/cycles/scene/image_vdb.cpp +++ b/intern/cycles/scene/image_vdb.cpp @@ -5,129 +5,30 @@ #include "scene/image_vdb.h" #include "util/log.h" +#include "util/nanovdb.h" #include "util/openvdb.h" #ifdef WITH_OPENVDB # include #endif -#ifdef WITH_NANOVDB -# define NANOVDB_USE_OPENVDB -# include -# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ - (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7) -# include -# else -# include -# endif -#endif CCL_NAMESPACE_BEGIN #ifdef WITH_OPENVDB -struct NumChannelsOp { - int num_channels = 0; - - template - bool operator()(const openvdb::GridBase::ConstPtr & /*unused*/) - { - num_channels = channels; - return true; - } -}; - struct ToDenseOp { openvdb::CoordBBox bbox; void *pixels; - template - bool operator()(const openvdb::GridBase::ConstPtr &grid) + template + bool operator()(const typename GridType::ConstPtr &grid) { openvdb::tools::Dense dense(bbox, (FloatDataType *)pixels); - openvdb::tools::copyToDense(*openvdb::gridConstPtrCast(grid), dense); + openvdb::tools::copyToDense(*grid, dense); return true; } }; -# ifdef WITH_NANOVDB -struct ToNanoOp { - nanovdb::GridHandle<> nanogrid; - int precision; - - template - bool operator()(const openvdb::GridBase::ConstPtr &grid) - { - if constexpr (!std::is_same_v) { - try { -# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ - (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 6) -# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ - (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7) - /* OpenVDB 12. */ - using nanovdb::tools::createNanoGrid; - using nanovdb::tools::StatsMode; -# else - /* OpenVDB 11. */ - using nanovdb::createNanoGrid; - using nanovdb::StatsMode; -# endif - - if constexpr (std::is_same_v) { - const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast(grid)); - if (precision == 0) { - nanogrid = createNanoGrid(floatgrid); - } - else if (precision == 16) { - nanogrid = createNanoGrid(floatgrid); - } - else { - nanogrid = createNanoGrid(floatgrid); - } - } - else if constexpr (std::is_same_v) { - const openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast(grid)); - nanogrid = createNanoGrid(floatgrid, - StatsMode::Disable); - } -# else - /* OpenVDB 10. */ - if constexpr (std::is_same_v) { - openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast(grid)); - if (precision == 0) { - nanogrid = - nanovdb::openToNanoVDB( - floatgrid); - } - else if (precision == 16) { - nanogrid = - nanovdb::openToNanoVDB( - floatgrid); - } - else { - nanogrid = nanovdb::openToNanoVDB(floatgrid); - } - } - else if constexpr (std::is_same_v) { - openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast(grid)); - nanogrid = nanovdb::openToNanoVDB(floatgrid); - } -# endif - } - catch (const std::exception &e) { - LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: " << e.what(); - } - catch (...) { - LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: Unknown error"; - } - return true; - } - else { - return false; - } - } -}; -# endif - VDBImageLoader::VDBImageLoader(openvdb::GridBase::ConstPtr grid_, const string &grid_name) : grid_name(grid_name), grid(grid_) { @@ -145,29 +46,23 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet return false; } - /* Get number of channels from type. */ - NumChannelsOp op; - if (!openvdb::grid_type_operation(grid, op)) { + /* Convert to the few float types that we know. */ + grid = openvdb_convert_to_known_type(grid); + if (!grid) { return false; } - metadata.channels = op.num_channels; + /* Get number of channels from type. */ + metadata.channels = openvdb_num_channels(grid); /* Set data type. */ # ifdef WITH_NANOVDB if (features.has_nanovdb) { - /* NanoVDB expects no inactive leaf nodes. */ -# if 0 - openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast(grid); - openvdb::tools::pruneInactive(pruned_grid.tree()); - nanogrid = nanovdb::openToNanoVDB(pruned_grid); -# endif - ToNanoOp op; - op.precision = precision; - if (!openvdb::grid_type_operation(grid, op)) { + /* Convert OpenVDB to NanoVDB grid. */ + nanogrid = openvdb_to_nanovdb(grid, precision, 0.0f); + if (!nanogrid) { return false; } - nanogrid = std::move(op.nanogrid); } # endif @@ -263,7 +158,7 @@ bool VDBImageLoader::load_pixels(const ImageMetaData & /*metadata*/, ToDenseOp op; op.pixels = pixels; op.bbox = bbox; - openvdb::grid_type_operation(grid, op); + openvdb_grid_type_operation(grid, op); } return true; #else diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index fe28dfd66ce..8926376c305 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -18,6 +18,8 @@ set(SRC math_cdf.cpp md5.cpp murmurhash.cpp + nanovdb.cpp + openvdb.cpp path.cpp profiling.cpp string.cpp @@ -75,6 +77,7 @@ set(SRC_HEADERS math_int8.h md5.h murmurhash.h + nanovdb.h openimagedenoise.h openvdb.h optimization.h @@ -133,4 +136,15 @@ endif() include_directories(${INC}) include_directories(SYSTEM ${INC_SYS}) +if(WITH_OPENVDB) + list(APPEND LIB + ${OPENVDB_LIBRARIES} + ) + + # This works around the issue described in #120317 and https://github.com/AcademySoftwareFoundation/openvdb/pull/1786 + if(MSVC_CLANG) + set_source_files_properties(openvdb.cpp PROPERTIES COMPILE_FLAGS -fno-delayed-template-parsing) + endif() +endif() + cycles_add_library(cycles_util "${LIB}" ${SRC} ${SRC_HEADERS}) diff --git a/intern/cycles/util/nanovdb.cpp b/intern/cycles/util/nanovdb.cpp new file mode 100644 index 00000000000..4e9ec8a20f7 --- /dev/null +++ b/intern/cycles/util/nanovdb.cpp @@ -0,0 +1,310 @@ +/* SPDX-FileCopyrightText: Contributors to the OpenVDB Project + * SPDX-FileCopyrightText: 2025 Blender Foundation + * SPDX-License-Identifier: Apache-2.0 */ + +#ifdef WITH_NANOVDB + +# include "util/nanovdb.h" +# include "util/log.h" +# include "util/openvdb.h" + +# include + +# include + +# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ + (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7) +# include +# else +# include +# endif + +CCL_NAMESPACE_BEGIN + +/* Convert NanoVDB to OpenVDB mask grid. + * + * Implementation adapted from nanoToOpenVDB in nanovdb, this will create + * a MaskGrid from any type of grid using the active voxels. */ + +template class NanoToOpenVDBMask { + using NanoNode0 = nanovdb::LeafNode; + using NanoNode1 = nanovdb::InternalNode; + using NanoNode2 = nanovdb::InternalNode; + using NanoRootT = nanovdb::RootNode; + using NanoTreeT = nanovdb::Tree; + using NanoGridT = nanovdb::Grid; + using NanoValueT = typename NanoGridT::ValueType; + + using OpenBuildT = openvdb::ValueMask; + using OpenNode0 = openvdb::tree::LeafNode; + using OpenNode1 = openvdb::tree::InternalNode; + using OpenNode2 = openvdb::tree::InternalNode; + using OpenRootT = openvdb::tree::RootNode; + using OpenTreeT = openvdb::tree::Tree; + using OpenGridT = openvdb::Grid; + using OpenValueT = typename OpenGridT::ValueType; + + public: + NanoToOpenVDBMask() = default; + typename OpenGridT::Ptr operator()(const nanovdb::NanoGrid &grid = 0); + + private: + template + OpenNodeT *processNode(const NanoNodeT * /*node*/); + + OpenNode2 *process(const NanoNode2 *node) + { + return this->template processNode(node); + } + OpenNode1 *process(const NanoNode1 *node) + { + return this->template processNode(node); + } + + template OpenNode0 *process(const NanoLeafT *node); +}; + +template +typename NanoToOpenVDBMask::OpenGridT::Ptr NanoToOpenVDBMask::operator()( + const nanovdb::NanoGrid &grid) +{ + /* Since the input nanovdb grid might use nanovdb types (Coord, Mask, Vec3) + * we cast to use openvdb types. */ + const NanoGridT *srcGrid = reinterpret_cast(&grid); + auto dstGrid = openvdb::createGrid(OpenValueT()); + + /* Set transform. */ + const nanovdb::Map &nanoMap = reinterpret_cast(srcGrid)->mMap; + auto mat = openvdb::math::Mat4::identity(); + mat.setMat3(openvdb::math::Mat3(nanoMap.mMatD)); + mat.transpose(); /* The 3x3 in nanovdb is transposed relative to openvdb's 3x3. */ + mat.setTranslation(openvdb::math::Vec3(nanoMap.mVecD)); + dstGrid->setTransform(openvdb::math::Transform::createLinearTransform(mat)); + + /* Process root node. */ + auto &root = dstGrid->tree().root(); + auto *data = srcGrid->tree().root().data(); + for (uint32_t i = 0; i < data->mTableSize; ++i) { + auto *tile = data->tile(i); + if (tile->isChild()) { + root.addChild(this->process(data->getChild(tile))); + } + else { + root.addTile(tile->origin(), OpenValueT(), tile->state); + } + } + + return dstGrid; +} + +template +template +DstNodeT *NanoToOpenVDBMask::processNode(const SrcNodeT *srcNode) +{ + DstNodeT *dstNode = new DstNodeT(); /* Un-initialized for fast construction. */ + dstNode->setOrigin(srcNode->origin()); + const auto &childMask = srcNode->childMask(); + const_cast(dstNode->getValueMask()) = srcNode->valueMask(); + const_cast(dstNode->getChildMask()) = childMask; + auto *dstTable = const_cast(dstNode->getTable()); + auto *srcData = srcNode->data(); + std::vector> childNodes; + const auto childCount = childMask.countOn(); + childNodes.reserve(childCount); + for (uint32_t n = 0; n < DstNodeT::NUM_VALUES; ++n) { + if (childMask.isOn(n)) { + childNodes.emplace_back(n, srcData->getChild(n)); + } + } + auto kernel = [&](const auto &r) { + for (auto i = r.begin(); i != r.end(); ++i) { + auto &p = childNodes[i]; + dstTable[p.first].setChild(this->process(p.second)); + } + }; + +# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ + (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7) + nanovdb::util::forEach(0, childCount, 1, kernel); +# else + nanovdb::forEach(0, childCount, 1, kernel); +# endif + + return dstNode; +} + +template +template +inline typename NanoToOpenVDBMask::OpenNode0 *NanoToOpenVDBMask::process( + const NanoLeafT *srcNode) +{ + static_assert(std::is_same_v, "NanoToOpenVDBMask wrong leaf type"); + OpenNode0 *dstNode = new OpenNode0(); /* Un-initialized for fast construction. */ + dstNode->setOrigin(srcNode->origin()); + dstNode->setValueMask(srcNode->valueMask()); + + return dstNode; +} + +struct NanoToOpenVDBMaskOp { + openvdb::MaskGrid::Ptr mask_grid; + + template bool operator()(const nanovdb::NanoGrid &grid) + { + NanoToOpenVDBMask tmp; + mask_grid = tmp(grid); + return true; + } +}; + +template +bool nanovdb_grid_type_operation(const nanovdb::GridHandle<> &handle, OpType &&op) +{ + const int n = 0; + + if (const auto *grid = handle.template grid(n)) { + return op(*grid); + } + if (const auto *grid = handle.template grid(n)) { + return op(*grid); + } + if (const auto *grid = handle.template grid(n)) { + return op(*grid); + } + if (const auto *grid = handle.template grid(n)) { + return op(*grid); + } + if (const auto *grid = handle.template grid(n)) { + return op(*grid); + } + + assert(!"Unknown NanoVDB grid type"); + return true; +} + +openvdb::MaskGrid::Ptr nanovdb_to_openvdb_mask(const nanovdb::GridHandle<> &handle) +{ + NanoToOpenVDBMaskOp op; + nanovdb_grid_type_operation(handle, op); + return op.mask_grid; +} + +/* Convert OpenVDB to NanoVDB grid. */ + +struct ToNanoOp { + nanovdb::GridHandle<> nanogrid; + int precision = 16; + float clipping = 0.0f; + + template + bool operator()(const typename GridType::ConstPtr &grid) + { + if constexpr (std::is_same_v) { + return false; + } + + try { +# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ + (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 6) +# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ + (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7) + /* OpenVDB 12. */ + using nanovdb::tools::createNanoGrid; + using nanovdb::tools::StatsMode; +# else + /* OpenVDB 11. */ + using nanovdb::createNanoGrid; + using nanovdb::StatsMode; +# endif + + if constexpr (std::is_same_v) { + typename GridType::ConstPtr floatgrid = apply_clipping(grid); + if (precision == 0) { + nanogrid = createNanoGrid(*floatgrid, + StatsMode::Disable); + } + else if (precision == 16) { + nanogrid = createNanoGrid(*floatgrid, + StatsMode::Disable); + } + else { + nanogrid = createNanoGrid(*floatgrid, StatsMode::Disable); + } + } + else if constexpr (std::is_same_v) { + /* Enable stats for velocity grid. Weak, but there seems to be no simple iterator over all + * values in the grid? */ + typename GridType::ConstPtr floatgrid = apply_clipping(grid); + nanogrid = createNanoGrid(*floatgrid, + StatsMode::MinMax); + } + else if constexpr (std::is_same_v) { + typename GridType::ConstPtr floatgrid = apply_clipping(grid); + nanogrid = createNanoGrid(*floatgrid, + StatsMode::Disable); + } +# else + /* OpenVDB 10. */ + if constexpr (std::is_same_v) { + typename GridType::ConstPtr floatgrid = apply_clipping(grid); + if (precision == 0) { + nanogrid = nanovdb::openToNanoVDB( + *floatgrid); + } + else if (precision == 16) { + nanogrid = + nanovdb::openToNanoVDB( + *floatgrid); + } + else { + nanogrid = nanovdb::openToNanoVDB(*floatgrid); + } + } + else if constexpr (std::is_same_v) { + typename GridType::ConstPtr floatgrid = apply_clipping(grid); + nanogrid = nanovdb::openToNanoVDB(*floatgrid); + } + else if constexpr (std::is_same_v) { + typename GridType::ConstPtr floatgrid = apply_clipping(grid); + nanogrid = nanovdb::openToNanoVDB(*floatgrid); + } +# endif + } + catch (const std::exception &e) { + LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: " << e.what(); + } + catch (...) { + LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: Unknown error"; + } + return true; + } + + template + typename GridT::ConstPtr apply_clipping(const typename GridT::ConstPtr &grid) const + { + if (clipping == 0.0f) { + return grid; + } + + /* TODO: Ideally would apply clipping during createNanoGrid, this seems slow. */ + typename GridT::Ptr newgrid = grid->deepCopy(); + openvdb::tools::deactivate( + *newgrid, typename GridT::ValueType(0.0f), typename GridT::ValueType(clipping)); + return newgrid; + } +}; + +nanovdb::GridHandle<> openvdb_to_nanovdb(const openvdb::GridBase::ConstPtr &grid, + const int precision, + const float clipping) +{ + ToNanoOp op; + op.precision = precision; + op.clipping = clipping; + openvdb_grid_type_operation(grid, op); + return std::move(op.nanogrid); +} + +CCL_NAMESPACE_END + +#endif diff --git a/intern/cycles/util/nanovdb.h b/intern/cycles/util/nanovdb.h new file mode 100644 index 00000000000..6dec0c0e524 --- /dev/null +++ b/intern/cycles/util/nanovdb.h @@ -0,0 +1,35 @@ +/* SPDX-FileCopyrightText: Contributors to the OpenVDB Project + * SPDX-FileCopyrightText: 2025 Blender Foundation + * SPDX-License-Identifier: Apache-2.0 */ + +#pragma once + +#ifdef WITH_NANOVDB + +# include + +# define NANOVDB_USE_OPENVDB +# define NANOVDB_USE_TBB + +# include // manages and streams the raw memory buffer of a NanoVDB grid. + +# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \ + (NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7) +# include +# else +# include +# endif + +CCL_NAMESPACE_BEGIN + +/* Convert NanoVDB to OpenVDB mask grid that represents just the topology. */ +openvdb::MaskGrid::Ptr nanovdb_to_openvdb_mask(const nanovdb::GridHandle<> &handle); + +/* Convert OpenVDB to NanoVDB grid. */ +nanovdb::GridHandle<> openvdb_to_nanovdb(const openvdb::GridBase::ConstPtr &grid, + const int precision, + const float clipping); + +CCL_NAMESPACE_END + +#endif diff --git a/intern/cycles/util/openvdb.cpp b/intern/cycles/util/openvdb.cpp new file mode 100644 index 00000000000..2da3e4da095 --- /dev/null +++ b/intern/cycles/util/openvdb.cpp @@ -0,0 +1,80 @@ +/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation + * + * SPDX-License-Identifier: Apache-2.0 */ + +#ifdef WITH_OPENVDB + +# include "util/openvdb.h" + +# include +# include + +CCL_NAMESPACE_BEGIN + +/* Convert to the few data types we native can render. */ +openvdb::GridBase::ConstPtr openvdb_convert_to_known_type(const openvdb::GridBase::ConstPtr &grid) +{ + if (grid->isType()) { + return grid; + } + if (grid->isType()) { + return grid; + } + if (grid->isType()) { + return grid; + } + if (grid->isType()) { + const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast(grid)); + return std::make_shared(std::move(floatgrid)); + } + if (grid->isType()) { + const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast(grid)); + return std::make_shared(std::move(floatgrid)); + } + if (grid->isType()) { + const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast(grid)); + return std::make_shared(std::move(floatgrid)); + } + if (grid->isType()) { + const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast(grid)); + return std::make_shared(std::move(floatgrid)); + } + if (grid->isType()) { + const openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast(grid)); + return std::make_shared(std::move(floatgrid)); + } + if (grid->isType()) { + const openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast(grid)); + return std::make_shared(std::move(floatgrid)); + } + return nullptr; +} + +/* Counter number of channels. */ +struct NumChannelsOp { + int num_channels = 0; + + template + bool operator()(const typename GridType::ConstPtr & /*unused*/) + { + num_channels = channels; + return true; + } +}; + +int openvdb_num_channels(const openvdb::GridBase::ConstPtr &grid) +{ + NumChannelsOp op; + if (!openvdb_grid_type_operation(grid, op)) { + return 0; + } + return op.num_channels; +} + +/* Convert OpenVDB to NanoVDB. */ +# ifdef WITH_NANOVDB +# endif + +CCL_NAMESPACE_END + +#endif diff --git a/intern/cycles/util/openvdb.h b/intern/cycles/util/openvdb.h index a13833cdc68..7a94ac9db7e 100644 --- a/intern/cycles/util/openvdb.h +++ b/intern/cycles/util/openvdb.h @@ -5,6 +5,7 @@ #pragma once #ifdef WITH_OPENVDB +# include # include namespace openvdb { @@ -12,40 +13,36 @@ namespace openvdb { using Vec4fTree = tree::Tree4::Type; using Vec4fGrid = Grid; +} // namespace openvdb + +CCL_NAMESPACE_BEGIN + +/* Convert to the few grid types we can render natively. */ +openvdb::GridBase::ConstPtr openvdb_convert_to_known_type(const openvdb::GridBase::ConstPtr &grid); + /* Apply operation to known grid types. */ template -bool grid_type_operation(const openvdb::GridBase::ConstPtr &grid, OpType &&op) +bool openvdb_grid_type_operation(const openvdb::GridBase::ConstPtr &grid, OpType &&op) { if (grid->isType()) { - return op.template operator()(grid); + return op.template operator()( + openvdb::gridConstPtrCast(grid)); } if (grid->isType()) { - return op.template operator()(grid); + return op.template operator()( + openvdb::gridConstPtrCast(grid)); } - if (grid->isType()) { - return op.template operator()(grid); - } - if (grid->isType()) { - return op.template operator()(grid); - } - if (grid->isType()) { - return op.template operator()(grid); - } - if (grid->isType()) { - return op.template operator()(grid); - } - if (grid->isType()) { - return op.template operator()(grid); - } - if (grid->isType()) { - return op.template operator()(grid); - } - if (grid->isType()) { - return op.template operator()(grid); + if (grid->isType()) { + return op.template operator()( + openvdb::gridConstPtrCast(grid)); } + assert(0); return false; } -}; // namespace openvdb +/* Count number of channels in known types. */ +int openvdb_num_channels(const openvdb::GridBase::ConstPtr &grid); + +CCL_NAMESPACE_END #endif