diff options
33 files changed, 2077 insertions, 51 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e0326f1d75e..4ec5053eb58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,6 +242,9 @@ option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" _init_OPEN option(WITH_SUBSURF_WERROR "Treat warnings as errors in subsurf code" OFF) mark_as_advanced(WITH_COMPOSITOR_WERROR) +option(WITH_OPENVDB "Enable features relying on OpenVDB" OFF) +option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" OFF) + # GHOST Windowing Library Options option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF) mark_as_advanced(WITH_GHOST_DEBUG) @@ -677,10 +680,11 @@ if(NOT WITH_BOOST) set_and_warn(WITH_CYCLES OFF) set_and_warn(WITH_AUDASPACE OFF) set_and_warn(WITH_INTERNATIONAL OFF) + set_and_warn(WITH_OPENVDB OFF) set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE -elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL) +elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL OR WITH_OPENVDB) # Keep enabled else() # Enabled but we don't need it @@ -1056,6 +1060,24 @@ if(UNIX AND NOT APPLE) endif() endif() + if(WITH_OPENVDB) + find_package_wrapper(OpenVDB) + + set(TBB ${LIBDIR}/tbb) + set(TBB_LIBRARIES tbb) + set(TBB_LIBPATH ${TBB}/lib) + + set(OPENVDB_LIBRARIES ${OPENVDB_LIBRARIES} ${BOOST_LIBRARIES} ${ZLIB_LIBRARIES} ${TBB_LIBRARIES}) + set(OPENVDB_LIBPATH) # TODO, remove and reference the absolute path everywhere + set(OPENVDB_DEFINITIONS) + + if(NOT OPENVDB_FOUND) + set(WITH_OPENVDB OFF) + set(WITH_OPENVDB_BLOSC OFF) + message(STATUS "OpenVDB not found") + endif() + endif() + if(WITH_BOOST) # uses in build instructions to override include and library variables if(NOT BOOST_CUSTOM) @@ -1076,6 +1098,9 @@ if(UNIX AND NOT APPLE) if(WITH_CYCLES_NETWORK) list(APPEND __boost_packages serialization) endif() + if(WITH_OPENVDB) + list(APPEND __boost_packages iostreams) + endif() find_package(Boost 1.48 COMPONENTS ${__boost_packages}) if(NOT Boost_FOUND) # try to find non-multithreaded if -mt not found, this flag @@ -1561,7 +1586,14 @@ elseif(WIN32) set(OPENCOLORIO_LIBPATH ${LIBDIR}/opencolorio/lib) set(OPENCOLORIO_DEFINITIONS) endif() - + + if(WITH_OPENVDB) + set(OPENVDB ${LIBDIR}/openvdb) + set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include) + set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES}) + set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib) + set(OPENVDB_DEFINITIONS) + endif() if(WITH_MOD_CLOTH_ELTOPO) set(LAPACK ${LIBDIR}/lapack) @@ -1834,6 +1866,14 @@ elseif(WIN32) set(SDL_LIBPATH ${SDL}/lib) endif() + if(WITH_OPENVDB) + set(OPENVDB ${LIBDIR}/openvdb) + set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include) + set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES}) + set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib) + set(OPENVDB_DEFINITIONS) + endif() + set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152") ## DISABLE - causes linking errors @@ -2139,6 +2179,14 @@ elseif(APPLE) set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib) endif() + if(WITH_OPENVDB) + set(OPENVDB ${LIBDIR}/openvdb) + set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include) + set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES}) + set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib) + set(OPENVDB_DEFINITIONS) + endif() + if(WITH_LLVM) set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation") set(LLVM_VERSION "3.4" CACHE STRING "Version of LLVM to use") @@ -2981,6 +3029,7 @@ if(FIRST_RUN) info_cfg_option(WITH_CYCLES) info_cfg_option(WITH_FREESTYLE) info_cfg_option(WITH_OPENCOLORIO) + info_cfg_option(WITH_OPENVDB) info_cfg_text("Compiler Options:") info_cfg_option(WITH_BUILDINFO) diff --git a/build_files/cmake/Modules/FindOpenVDB.cmake b/build_files/cmake/Modules/FindOpenVDB.cmake new file mode 100644 index 00000000000..a13feab8e0e --- /dev/null +++ b/build_files/cmake/Modules/FindOpenVDB.cmake @@ -0,0 +1,74 @@ +# - Find OPENVDB library +# Find the native OPENVDB includes and library +# This module defines +# OPENVDB_INCLUDE_DIRS, where to find openvdb.h, Set when +# OPENVDB_INCLUDE_DIR is found. +# OPENVDB_LIBRARIES, libraries to link against to use OPENVDB. +# OPENVDB_ROOT_DIR, The base directory to search for OPENVDB. +# This can also be an environment variable. +# OPENVDB_FOUND, If false, do not try to use OPENVDB. +# +# also defined, but not for general use are +# OPENVDB_LIBRARY, where to find the OPENVDB library. + +#============================================================================= +# Copyright 2015 Blender Foundation. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +# If OPENVDB_ROOT_DIR was defined in the environment, use it. +IF(NOT OPENVDB_ROOT_DIR AND NOT $ENV{OPENVDB_ROOT_DIR} STREQUAL "") + SET(OPENVDB_ROOT_DIR $ENV{OPENVDB_ROOT_DIR}) +ENDIF() + +SET(_openvdb_SEARCH_DIRS + ${OPENVDB_ROOT_DIR} + /usr/local + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt/openvdb + /opt/lib/openvdb +) + +FIND_PATH(OPENVDB_INCLUDE_DIR + NAMES + openvdb/openvdb.h + HINTS + ${_openvdb_SEARCH_DIRS} + PATH_SUFFIXES + include +) + +FIND_LIBRARY(OPENVDB_LIBRARY + NAMES + openvdb + HINTS + ${_openvdb_SEARCH_DIRS} + PATH_SUFFIXES + lib64 lib +) + +# handle the QUIETLY and REQUIRED arguments and set OPENVDB_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENVDB DEFAULT_MSG + OPENVDB_LIBRARY OPENVDB_INCLUDE_DIR) + +IF(OPENVDB_FOUND) + SET(OPENVDB_LIBRARIES ${OPENVDB_LIBRARY}) + SET(OPENVDB_INCLUDE_DIRS ${OPENVDB_INCLUDE_DIR}) +ENDIF(OPENVDB_FOUND) + +MARK_AS_ADVANCED( + OPENVDB_INCLUDE_DIR + OPENVDB_LIBRARY +) + +UNSET(_openvdb_SEARCH_DIRS) diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 99e90caf793..a479506d0d7 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -47,6 +47,7 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE) set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE) set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE) set(WITH_OPENMP OFF CACHE BOOL "" FORCE) +set(WITH_OPENVDB OFF CACHE BOOL "" FORCE) set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/bpy_module.cmake b/build_files/cmake/config/bpy_module.cmake index b5b13b40987..41140151f04 100644 --- a/build_files/cmake/config/bpy_module.cmake +++ b/build_files/cmake/config/bpy_module.cmake @@ -31,3 +31,4 @@ set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE) set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE) set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE) set(WITH_BULLET OFF CACHE BOOL "" FORCE) +set(WITH_OPENVDB OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 6194bd8351c..28617cd7142 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -282,6 +282,9 @@ function(SETUP_LIBDIRS) if(WITH_OPENCOLORIO) link_directories(${OPENCOLORIO_LIBPATH}) endif() + if(WITH_OPENVDB) + link_directories(${OPENVDB_LIBPATH}) + endif() if(WITH_IMAGE_OPENJPEG AND WITH_SYSTEM_OPENJPEG) link_directories(${OPENJPEG_LIBPATH}) endif() @@ -400,6 +403,9 @@ function(setup_liblinks target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES}) endif() endif() + if(WITH_OPENVDB) + target_link_libraries(${target} ${OPENVDB_LIBRARIES}) + endif() if(WITH_CYCLES_OSL) target_link_libraries(${target} ${OSL_LIBRARIES}) endif() @@ -713,6 +719,10 @@ function(SETUP_BLENDER_SORTED_LIBS) list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv) endif() + if(WITH_OPENVDB) + list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb) + endif() + foreach(SORTLIB ${BLENDER_SORTED_LIBS}) set(REMLIB ${SORTLIB}) foreach(SEARCHLIB ${BLENDER_LINK_LIBS}) diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index f5f2d1c0156..43e5b6bff3e 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -82,3 +82,7 @@ endif() if(WIN32) add_subdirectory(utfconv) endif() + +if(WITH_OPENVDB) + add_subdirectory(openvdb) +endif() diff --git a/intern/openvdb/CMakeLists.txt b/intern/openvdb/CMakeLists.txt new file mode 100644 index 00000000000..ce683e7d319 --- /dev/null +++ b/intern/openvdb/CMakeLists.txt @@ -0,0 +1,69 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2015, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Kevin Dietrich. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + intern +) + +set(INC_SYS +) + +set(SRC + openvdb_capi.h +) + +if(WITH_OPENVDB) + add_definitions( + -DWITH_OPENVDB + ) + + list(APPEND INC_SYS + ${BOOST_INCLUDE_DIR} + ${OPENEXR_INCLUDE_DIRS} + ${OPENVDB_INCLUDE_DIRS} + ) + + list(APPEND SRC + intern/openvdb_dense_convert.cc + intern/openvdb_reader.cc + intern/openvdb_writer.cc + openvdb_capi.cc + openvdb_util.cc + + intern/openvdb_dense_convert.h + intern/openvdb_reader.h + intern/openvdb_writer.h + openvdb_util.h + ) + + if(WITH_OPENVDB_BLOSC) + add_definitions( + -DWITH_OPENVDB_BLOSC + ) + endif() +endif() + +blender_add_lib(bf_intern_openvdb "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/openvdb/intern/openvdb_dense_convert.cc b/intern/openvdb/intern/openvdb_dense_convert.cc new file mode 100644 index 00000000000..d4f62776988 --- /dev/null +++ b/intern/openvdb/intern/openvdb_dense_convert.cc @@ -0,0 +1,167 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "openvdb_dense_convert.h" + +#include <openvdb/tools/ValueTransformer.h> /* for tools::foreach */ + +namespace internal { + +openvdb::Mat4R convertMatrix(const float mat[4][4]) +{ + return openvdb::Mat4R( + mat[0][0], mat[0][1], mat[0][2], mat[0][3], + mat[1][0], mat[1][1], mat[1][2], mat[1][3], + mat[2][0], mat[2][1], mat[2][2], mat[2][3], + mat[3][0], mat[3][1], mat[3][2], mat[3][3]); +} + + +class MergeScalarGrids { + typedef openvdb::FloatTree ScalarTree; + + openvdb::tree::ValueAccessor<const ScalarTree> m_acc_x, m_acc_y, m_acc_z; + +public: + MergeScalarGrids(const ScalarTree *x_tree, const ScalarTree *y_tree, const ScalarTree *z_tree) + : m_acc_x(*x_tree) + , m_acc_y(*y_tree) + , m_acc_z(*z_tree) + {} + + MergeScalarGrids(const MergeScalarGrids &other) + : m_acc_x(other.m_acc_x) + , m_acc_y(other.m_acc_y) + , m_acc_z(other.m_acc_z) + {} + + void operator()(const openvdb::Vec3STree::ValueOnIter &it) const + { + using namespace openvdb; + + const math::Coord xyz = it.getCoord(); + float x = m_acc_x.getValue(xyz); + float y = m_acc_y.getValue(xyz); + float z = m_acc_z.getValue(xyz); + + it.setValue(math::Vec3s(x, y, z)); + } +}; + +openvdb::GridBase *OpenVDB_export_vector_grid( + OpenVDBWriter *writer, + const openvdb::Name &name, + const float *data_x, const float *data_y, const float *data_z, + const int res[3], + float fluid_mat[4][4], + openvdb::VecType vec_type, + const bool is_color, + const openvdb::FloatGrid *mask) +{ + using namespace openvdb; + + math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1)); + Mat4R mat = convertMatrix(fluid_mat); + math::Transform::Ptr transform = math::Transform::createLinearTransform(mat); + + FloatGrid::Ptr grid[3]; + + grid[0] = FloatGrid::create(0.0f); + tools::Dense<const float, tools::LayoutXYZ> dense_grid_x(bbox, data_x); + tools::copyFromDense(dense_grid_x, grid[0]->tree(), TOLERANCE); + + grid[1] = FloatGrid::create(0.0f); + tools::Dense<const float, tools::LayoutXYZ> dense_grid_y(bbox, data_y); + tools::copyFromDense(dense_grid_y, grid[1]->tree(), TOLERANCE); + + grid[2] = FloatGrid::create(0.0f); + tools::Dense<const float, tools::LayoutXYZ> dense_grid_z(bbox, data_z); + tools::copyFromDense(dense_grid_z, grid[2]->tree(), TOLERANCE); + + Vec3SGrid::Ptr vecgrid = Vec3SGrid::create(Vec3s(0.0f)); + + /* Activate voxels in the vector grid based on the scalar grids to ensure + * thread safety later on */ + for (int i = 0; i < 3; ++i) { + vecgrid->tree().topologyUnion(grid[i]->tree()); + } + + MergeScalarGrids op(&(grid[0]->tree()), &(grid[1]->tree()), &(grid[2]->tree())); + tools::foreach(vecgrid->beginValueOn(), op, true, false); + + vecgrid->setTransform(transform); + + if (mask) { + vecgrid = tools::clip(*vecgrid, *mask); + } + + vecgrid->setName(name); + vecgrid->setIsInWorldSpace(false); + vecgrid->setVectorType(vec_type); + vecgrid->insertMeta("is_color", BoolMetadata(is_color)); + vecgrid->setGridClass(GRID_STAGGERED); + + writer->insert(vecgrid); + + return vecgrid.get(); +} + +void OpenVDB_import_grid_vector( + OpenVDBReader *reader, + const openvdb::Name &name, + float **data_x, float **data_y, float **data_z, + const int res[3]) +{ + using namespace openvdb; + + if (!reader->hasGrid(name)) { + std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str()); + memset(*data_x, 0, sizeof(float) * res[0] * res[1] * res[2]); + memset(*data_y, 0, sizeof(float) * res[0] * res[1] * res[2]); + memset(*data_z, 0, sizeof(float) * res[0] * res[1] * res[2]); + return; + } + + Vec3SGrid::Ptr vgrid = gridPtrCast<Vec3SGrid>(reader->getGrid(name)); + Vec3SGrid::ConstAccessor acc = vgrid->getConstAccessor(); + math::Coord xyz; + int &x = xyz[0], &y = xyz[1], &z = xyz[2]; + + size_t index = 0; + for (z = 0; z < res[2]; ++z) { + for (y = 0; y < res[1]; ++y) { + for (x = 0; x < res[0]; ++x, ++index) { + math::Vec3s value = acc.getValue(xyz); + (*data_x)[index] = value.x(); + (*data_y)[index] = value.y(); + (*data_z)[index] = value.z(); + } + } + } +} + +} /* namespace internal */ diff --git a/intern/openvdb/intern/openvdb_dense_convert.h b/intern/openvdb/intern/openvdb_dense_convert.h new file mode 100644 index 00000000000..fd10334c4ad --- /dev/null +++ b/intern/openvdb/intern/openvdb_dense_convert.h @@ -0,0 +1,130 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENVDB_DENSE_CONVERT_H__ +#define __OPENVDB_DENSE_CONVERT_H__ + +#include "openvdb_reader.h" +#include "openvdb_writer.h" + +#include <openvdb/tools/Clip.h> +#include <openvdb/tools/Dense.h> + +#include <cstdio> + +#define TOLERANCE 1e-3f + +namespace internal { + +openvdb::Mat4R convertMatrix(const float mat[4][4]); + +template <typename GridType, typename T> +GridType *OpenVDB_export_grid( + OpenVDBWriter *writer, + const openvdb::Name &name, + const T *data, + const int res[3], + float fluid_mat[4][4], + const openvdb::FloatGrid *mask) +{ + using namespace openvdb; + + math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1)); + Mat4R mat = convertMatrix(fluid_mat); + math::Transform::Ptr transform = math::Transform::createLinearTransform(mat); + + typename GridType::Ptr grid = GridType::create(T(0)); + + tools::Dense<const T, openvdb::tools::LayoutXYZ> dense_grid(bbox, data); + tools::copyFromDense(dense_grid, grid->tree(), (T)TOLERANCE); + + grid->setTransform(transform); + + if (mask) { + grid = tools::clip(*grid, *mask); + } + + grid->setName(name); + grid->setIsInWorldSpace(false); + grid->setVectorType(openvdb::VEC_INVARIANT); + + writer->insert(grid); + + return grid.get(); +} + +template <typename GridType, typename T> +void OpenVDB_import_grid( + OpenVDBReader *reader, + const openvdb::Name &name, + T **data, + const int res[3]) +{ + using namespace openvdb; + + if (!reader->hasGrid(name)) { + std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str()); + memset(*data, 0, sizeof(T) * res[0] * res[1] * res[2]); + return; + } + + typename GridType::Ptr grid = gridPtrCast<GridType>(reader->getGrid(name)); + typename GridType::ConstAccessor acc = grid->getConstAccessor(); + + math::Coord xyz; + int &x = xyz[0], &y = xyz[1], &z = xyz[2]; + + size_t index = 0; + for (z = 0; z < res[2]; ++z) { + for (y = 0; y < res[1]; ++y) { + for (x = 0; x < res[0]; ++x, ++index) { + (*data)[index] = acc.getValue(xyz); + } + } + } +} + +openvdb::GridBase *OpenVDB_export_vector_grid( + OpenVDBWriter *writer, + const openvdb::Name &name, + const float *data_x, const float *data_y, const float *data_z, + const int res[3], + float fluid_mat[4][4], + openvdb::VecType vec_type, + const bool is_color, + const openvdb::FloatGrid *mask); + + +void OpenVDB_import_grid_vector( + OpenVDBReader *reader, + const openvdb::Name &name, + float **data_x, float **data_y, float **data_z, + const int res[3]); + +} /* namespace internal */ + +#endif /* __OPENVDB_DENSE_CONVERT_H__ */ diff --git a/intern/openvdb/intern/openvdb_reader.cc b/intern/openvdb/intern/openvdb_reader.cc new file mode 100644 index 00000000000..8b15b81710d --- /dev/null +++ b/intern/openvdb/intern/openvdb_reader.cc @@ -0,0 +1,136 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "openvdb_reader.h" +#include "openvdb_util.h" + +OpenVDBReader::OpenVDBReader() + : m_meta_map(new openvdb::MetaMap) + , m_file(NULL) +{ + /* Although it is safe, it may not be good to have this here, could be done + * once instead of everytime we read a file. */ + openvdb::initialize(); +} + +OpenVDBReader::~OpenVDBReader() +{ + cleanupFile(); +} + +void OpenVDBReader::open(const openvdb::Name &filename) +{ + cleanupFile(); + + try { + m_file = new openvdb::io::File(filename); + m_file->setCopyMaxBytes(0); + m_file->open(); + + m_meta_map = m_file->getMetadata(); + } + /* Mostly to catch exceptions related to Blosc not being supported. */ + catch (const openvdb::IoError &e) { + std::cerr << e.what() << '\n'; + cleanupFile(); + } +} + +void OpenVDBReader::floatMeta(const openvdb::Name &name, float &value) const +{ + try { + value = m_meta_map->metaValue<float>(name); + } + CATCH_KEYERROR; +} + +void OpenVDBReader::intMeta(const openvdb::Name &name, int &value) const +{ + try { + value = m_meta_map->metaValue<int>(name); + } + CATCH_KEYERROR; +} + +void OpenVDBReader::vec3sMeta(const openvdb::Name &name, float value[3]) const +{ + try { + openvdb::Vec3s meta_val = m_meta_map->metaValue<openvdb::Vec3s>(name); + + value[0] = meta_val.x(); + value[1] = meta_val.y(); + value[2] = meta_val.z(); + } + CATCH_KEYERROR; +} + +void OpenVDBReader::vec3IMeta(const openvdb::Name &name, int value[3]) const +{ + try { + openvdb::Vec3i meta_val = m_meta_map->metaValue<openvdb::Vec3i>(name); + + value[0] = meta_val.x(); + value[1] = meta_val.y(); + value[2] = meta_val.z(); + } + CATCH_KEYERROR; +} + +void OpenVDBReader::mat4sMeta(const openvdb::Name &name, float value[4][4]) const +{ + try { + openvdb::Mat4s meta_val = m_meta_map->metaValue<openvdb::Mat4s>(name); + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + value[i][j] = meta_val[i][j]; + } + } + } + CATCH_KEYERROR; +} + +bool OpenVDBReader::hasGrid(const openvdb::Name &name) const +{ + return m_file->hasGrid(name); +} + +openvdb::GridBase::Ptr OpenVDBReader::getGrid(const openvdb::Name &name) const +{ + return m_file->readGrid(name); +} + +size_t OpenVDBReader::numGrids() const +{ + return m_file->getGrids()->size(); +} + +void OpenVDBReader::cleanupFile() +{ + if (m_file) { + m_file->close(); + delete m_file; + } +} diff --git a/intern/openvdb/intern/openvdb_reader.h b/intern/openvdb/intern/openvdb_reader.h new file mode 100644 index 00000000000..07f77130ff9 --- /dev/null +++ b/intern/openvdb/intern/openvdb_reader.h @@ -0,0 +1,55 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENVDB_READER_H__ +#define __OPENVDB_READER_H__ + +#include <openvdb/openvdb.h> + +struct OpenVDBReader { +private: + openvdb::MetaMap::Ptr m_meta_map; + openvdb::io::File *m_file; + + void cleanupFile(); + +public: + OpenVDBReader(); + ~OpenVDBReader(); + + void open(const openvdb::Name &filename); + + void floatMeta(const openvdb::Name &name, float &value) const; + void intMeta(const openvdb::Name &name, int &value) const; + void vec3sMeta(const openvdb::Name &name, float value[3]) const; + void vec3IMeta(const openvdb::Name &name, int value[3]) const; + void mat4sMeta(const openvdb::Name &name, float value[4][4]) const; + + bool hasGrid(const openvdb::Name &name) const; + openvdb::GridBase::Ptr getGrid(const openvdb::Name &name) const; + size_t numGrids() const; +}; + +#endif /* __OPENVDB_READER_H__ */ diff --git a/intern/openvdb/intern/openvdb_writer.cc b/intern/openvdb/intern/openvdb_writer.cc new file mode 100644 index 00000000000..923752909d9 --- /dev/null +++ b/intern/openvdb/intern/openvdb_writer.cc @@ -0,0 +1,118 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "openvdb_writer.h" +#include "openvdb_util.h" + +OpenVDBWriter::OpenVDBWriter() + : m_grids(new openvdb::GridPtrVec()) + , m_meta_map(new openvdb::MetaMap()) + , m_save_as_half(false) +{ + m_meta_map->insertMeta("creator", openvdb::StringMetadata("Blender/Smoke")); +} + +OpenVDBWriter::~OpenVDBWriter() +{} + +void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid) +{ + grid->setSaveFloatAsHalf(m_save_as_half); + m_grids->push_back(grid); +} + +void OpenVDBWriter::insert(const openvdb::GridBase &grid) +{ + m_grids->push_back(grid.copyGrid()); +} + +void OpenVDBWriter::insertFloatMeta(const openvdb::Name &name, const float value) +{ + try { + m_meta_map->insertMeta(name, openvdb::FloatMetadata(value)); + } + CATCH_KEYERROR; +} + +void OpenVDBWriter::insertIntMeta(const openvdb::Name &name, const int value) +{ + try { + m_meta_map->insertMeta(name, openvdb::Int32Metadata(value)); + } + CATCH_KEYERROR; +} + +void OpenVDBWriter::insertVec3sMeta(const openvdb::Name &name, const openvdb::Vec3s &value) +{ + try { + m_meta_map->insertMeta(name, openvdb::Vec3SMetadata(value)); + } + CATCH_KEYERROR; +} + +void OpenVDBWriter::insertVec3IMeta(const openvdb::Name &name, const openvdb::Vec3I &value) +{ + try { + m_meta_map->insertMeta(name, openvdb::Vec3IMetadata(value)); + } + CATCH_KEYERROR; +} + +void OpenVDBWriter::insertMat4sMeta(const openvdb::Name &name, const float value[4][4]) +{ + openvdb::Mat4s mat = openvdb::Mat4s( + value[0][0], value[0][1], value[0][2], value[0][3], + value[1][0], value[1][1], value[1][2], value[1][3], + value[2][0], value[2][1], value[2][2], value[2][3], + value[3][0], value[3][1], value[3][2], value[3][3]); + + try { + m_meta_map->insertMeta(name, openvdb::Mat4SMetadata(mat)); + } + CATCH_KEYERROR; +} + +void OpenVDBWriter::setFlags(const int compression, const bool save_as_half) +{ + m_compression_flags = compression; + m_save_as_half = save_as_half; +} + +void OpenVDBWriter::write(const openvdb::Name &filename) const +{ + try { + openvdb::io::File file(filename); + file.setCompression(m_compression_flags); + file.write(*m_grids, *m_meta_map); + file.close(); + + /* Should perhaps be an option at some point */ + m_grids->clear(); + } + /* Mostly to catch exceptions related to Blosc not being supported. */ + catch (const openvdb::IoError &e) { + std::cerr << e.what() << '\n'; + } +} diff --git a/intern/openvdb/intern/openvdb_writer.h b/intern/openvdb/intern/openvdb_writer.h new file mode 100644 index 00000000000..69f42473975 --- /dev/null +++ b/intern/openvdb/intern/openvdb_writer.h @@ -0,0 +1,57 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENVDB_WRITER_H__ +#define __OPENVDB_WRITER_H__ + +#include <openvdb/openvdb.h> + +struct OpenVDBWriter { +private: + openvdb::GridPtrVecPtr m_grids; + openvdb::MetaMap::Ptr m_meta_map; + + int m_compression_flags; + bool m_save_as_half; + +public: + OpenVDBWriter(); + ~OpenVDBWriter(); + + void insert(const openvdb::GridBase::Ptr &grid); + void insert(const openvdb::GridBase &grid); + + void insertFloatMeta(const openvdb::Name &name, const float value); + void insertIntMeta(const openvdb::Name &name, const int value); + void insertVec3sMeta(const openvdb::Name &name, const openvdb::Vec3s &value); + void insertVec3IMeta(const openvdb::Name &name, const openvdb::Vec3I &value); + void insertMat4sMeta(const openvdb::Name &name, const float value[4][4]); + + void setFlags(const int compression, const bool save_as_half); + + void write(const openvdb::Name &filename) const; +}; + +#endif /* __OPENVDB_WRITER_H__ */ diff --git a/intern/openvdb/openvdb_capi.cc b/intern/openvdb/openvdb_capi.cc new file mode 100644 index 00000000000..ef4f8c8820f --- /dev/null +++ b/intern/openvdb/openvdb_capi.cc @@ -0,0 +1,240 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "openvdb_capi.h" +#include "openvdb_dense_convert.h" +#include "openvdb_util.h" + +struct OpenVDBFloatGrid { int unused; }; +struct OpenVDBIntGrid { int unused; }; +struct OpenVDBVectorGrid { int unused; }; + +int OpenVDB_getVersionHex() +{ + return openvdb::OPENVDB_LIBRARY_VERSION; +} + +OpenVDBFloatGrid *OpenVDB_export_grid_fl( + OpenVDBWriter *writer, + const char *name, float *data, + const int res[3], float matrix[4][4], + OpenVDBFloatGrid *mask) +{ + Timer(__func__); + + using openvdb::FloatGrid; + + FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask); + FloatGrid *grid = internal::OpenVDB_export_grid<FloatGrid>( + writer, + name, + data, + res, + matrix, + mask_grid); + + return reinterpret_cast<OpenVDBFloatGrid *>(grid); +} + +OpenVDBIntGrid *OpenVDB_export_grid_ch( + OpenVDBWriter *writer, + const char *name, unsigned char *data, + const int res[3], float matrix[4][4], + OpenVDBFloatGrid *mask) +{ + Timer(__func__); + + using openvdb::FloatGrid; + using openvdb::Int32Grid; + + FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask); + Int32Grid *grid = internal::OpenVDB_export_grid<Int32Grid>( + writer, + name, + data, + res, + matrix, + mask_grid); + + return reinterpret_cast<OpenVDBIntGrid *>(grid); +} + +OpenVDBVectorGrid *OpenVDB_export_grid_vec( + struct OpenVDBWriter *writer, + const char *name, + const float *data_x, const float *data_y, const float *data_z, + const int res[3], float matrix[4][4], short vec_type, + const bool is_color, OpenVDBFloatGrid *mask) +{ + Timer(__func__); + + using openvdb::GridBase; + using openvdb::FloatGrid; + using openvdb::VecType; + + FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask); + GridBase *grid = internal::OpenVDB_export_vector_grid( + writer, + name, + data_x, + data_y, + data_z, + res, + matrix, + static_cast<VecType>(vec_type), + is_color, + mask_grid); + + return reinterpret_cast<OpenVDBVectorGrid *>(grid); +} + +void OpenVDB_import_grid_fl( + OpenVDBReader *reader, + const char *name, float **data, + const int res[3]) +{ + Timer(__func__); + + internal::OpenVDB_import_grid<openvdb::FloatGrid>(reader, name, data, res); +} + +void OpenVDB_import_grid_ch( + OpenVDBReader *reader, + const char *name, unsigned char **data, + const int res[3]) +{ + internal::OpenVDB_import_grid<openvdb::Int32Grid>(reader, name, data, res); +} + +void OpenVDB_import_grid_vec( + struct OpenVDBReader *reader, + const char *name, + float **data_x, float **data_y, float **data_z, + const int res[3]) +{ + Timer(__func__); + + internal::OpenVDB_import_grid_vector(reader, name, data_x, data_y, data_z, res); +} + +OpenVDBWriter *OpenVDBWriter_create() +{ + return new OpenVDBWriter(); +} + +void OpenVDBWriter_free(OpenVDBWriter *writer) +{ + delete writer; +} + +void OpenVDBWriter_set_flags(OpenVDBWriter *writer, const int flag, const bool half) +{ + int compression_flags = openvdb::io::COMPRESS_ACTIVE_MASK; + +#ifdef WITH_OPENVDB_BLOSC + if (flag == 0) { + compression_flags |= openvdb::io::COMPRESS_BLOSC; + } + else +#endif + if (flag == 1) { + compression_flags |= openvdb::io::COMPRESS_ZIP; + } + else { + compression_flags = openvdb::io::COMPRESS_NONE; + } + + writer->setFlags(compression_flags, half); +} + +void OpenVDBWriter_add_meta_fl(OpenVDBWriter *writer, const char *name, const float value) +{ + writer->insertFloatMeta(name, value); +} + +void OpenVDBWriter_add_meta_int(OpenVDBWriter *writer, const char *name, const int value) +{ + writer->insertIntMeta(name, value); +} + +void OpenVDBWriter_add_meta_v3(OpenVDBWriter *writer, const char *name, const float value[3]) +{ + writer->insertVec3sMeta(name, value); +} + +void OpenVDBWriter_add_meta_v3_int(OpenVDBWriter *writer, const char *name, const int value[3]) +{ + writer->insertVec3IMeta(name, value); +} + +void OpenVDBWriter_add_meta_mat4(OpenVDBWriter *writer, const char *name, float value[4][4]) +{ + writer->insertMat4sMeta(name, value); +} + +void OpenVDBWriter_write(OpenVDBWriter *writer, const char *filename) +{ + writer->write(filename); +} + +OpenVDBReader *OpenVDBReader_create() +{ + return new OpenVDBReader(); +} + +void OpenVDBReader_free(OpenVDBReader *reader) +{ + delete reader; +} + +void OpenVDBReader_open(OpenVDBReader *reader, const char *filename) +{ + reader->open(filename); +} + +void OpenVDBReader_get_meta_fl(OpenVDBReader *reader, const char *name, float *value) +{ + reader->floatMeta(name, *value); +} + +void OpenVDBReader_get_meta_int(OpenVDBReader *reader, const char *name, int *value) +{ + reader->intMeta(name, *value); +} + +void OpenVDBReader_get_meta_v3(OpenVDBReader *reader, const char *name, float value[3]) +{ + reader->vec3sMeta(name, value); +} + +void OpenVDBReader_get_meta_v3_int(OpenVDBReader *reader, const char *name, int value[3]) +{ + reader->vec3IMeta(name, value); +} + +void OpenVDBReader_get_meta_mat4(OpenVDBReader *reader, const char *name, float value[4][4]) +{ + reader->mat4sMeta(name, value); +} diff --git a/intern/openvdb/openvdb_capi.h b/intern/openvdb/openvdb_capi.h new file mode 100644 index 00000000000..2d2feeadcf1 --- /dev/null +++ b/intern/openvdb/openvdb_capi.h @@ -0,0 +1,108 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENVDB_CAPI_H__ +#define __OPENVDB_CAPI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct OpenVDBReader; +struct OpenVDBWriter; +struct OpenVDBFloatGrid; +struct OpenVDBIntGrid; +struct OpenVDBVectorGrid; + +int OpenVDB_getVersionHex(void); + +enum { + VEC_INVARIANT = 0, + VEC_COVARIANT = 1, + VEC_COVARIANT_NORMALIZE = 2, + VEC_CONTRAVARIANT_RELATIVE = 3, + VEC_CONTRAVARIANT_ABSOLUTE = 4, +}; + +struct OpenVDBFloatGrid *OpenVDB_export_grid_fl( + struct OpenVDBWriter *writer, + const char *name, float *data, + const int res[3], float matrix[4][4], + struct OpenVDBFloatGrid *mask); + +struct OpenVDBIntGrid *OpenVDB_export_grid_ch( + struct OpenVDBWriter *writer, + const char *name, unsigned char *data, + const int res[3], float matrix[4][4], + struct OpenVDBFloatGrid *mask); + +struct OpenVDBVectorGrid *OpenVDB_export_grid_vec( + struct OpenVDBWriter *writer, + const char *name, + const float *data_x, const float *data_y, const float *data_z, + const int res[3], float matrix[4][4], short vec_type, + const bool is_color, + struct OpenVDBFloatGrid *mask); + +void OpenVDB_import_grid_fl( + struct OpenVDBReader *reader, + const char *name, float **data, + const int res[3]); + +void OpenVDB_import_grid_ch( + struct OpenVDBReader *reader, + const char *name, unsigned char **data, + const int res[3]); + +void OpenVDB_import_grid_vec( + struct OpenVDBReader *reader, + const char *name, + float **data_x, float **data_y, float **data_z, + const int res[3]); + +struct OpenVDBWriter *OpenVDBWriter_create(void); +void OpenVDBWriter_free(struct OpenVDBWriter *writer); +void OpenVDBWriter_set_flags(struct OpenVDBWriter *writer, const int flag, const bool half); +void OpenVDBWriter_add_meta_fl(struct OpenVDBWriter *writer, const char *name, const float value); +void OpenVDBWriter_add_meta_int(struct OpenVDBWriter *writer, const char *name, const int value); +void OpenVDBWriter_add_meta_v3(struct OpenVDBWriter *writer, const char *name, const float value[3]); +void OpenVDBWriter_add_meta_v3_int(struct OpenVDBWriter *writer, const char *name, const int value[3]); +void OpenVDBWriter_add_meta_mat4(struct OpenVDBWriter *writer, const char *name, float value[4][4]); +void OpenVDBWriter_write(struct OpenVDBWriter *writer, const char *filename); + +struct OpenVDBReader *OpenVDBReader_create(void); +void OpenVDBReader_free(struct OpenVDBReader *reader); +void OpenVDBReader_open(struct OpenVDBReader *reader, const char *filename); +void OpenVDBReader_get_meta_fl(struct OpenVDBReader *reader, const char *name, float *value); +void OpenVDBReader_get_meta_int(struct OpenVDBReader *reader, const char *name, int *value); +void OpenVDBReader_get_meta_v3(struct OpenVDBReader *reader, const char *name, float value[3]); +void OpenVDBReader_get_meta_v3_int(struct OpenVDBReader *reader, const char *name, int value[3]); +void OpenVDBReader_get_meta_mat4(struct OpenVDBReader *reader, const char *name, float value[4][4]); + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENVDB_CAPI_H__ */ diff --git a/intern/openvdb/openvdb_util.cc b/intern/openvdb/openvdb_util.cc new file mode 100644 index 00000000000..d187f55970d --- /dev/null +++ b/intern/openvdb/openvdb_util.cc @@ -0,0 +1,38 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "openvdb_util.h" + +#include <cstdio> + +ScopeTimer::ScopeTimer(const std::string &message) + : m_message(message) + , m_timer() +{} + +ScopeTimer::~ScopeTimer() +{ + std::printf("%s: %fms\n", m_message.c_str(), m_timer.delta()); +} diff --git a/intern/openvdb/openvdb_util.h b/intern/openvdb/openvdb_util.h new file mode 100644 index 00000000000..8e14ed54345 --- /dev/null +++ b/intern/openvdb/openvdb_util.h @@ -0,0 +1,57 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __OPENVDB_UTIL_H__ +#define __OPENVDB_UTIL_H__ + +#include <openvdb/openvdb.h> +#include <openvdb/util/CpuTimer.h> + +#define CATCH_KEYERROR \ + catch (const openvdb::KeyError &e) { \ + std::cerr << e.what() << '\n'; \ + } + +//#define DEBUG_TIME + +/* A utility class which prints the time elapsed during its lifetime, useful for + * e.g. timing the overall execution time of a function */ +class ScopeTimer { + std::string m_message; + openvdb::util::CpuTimer m_timer; + +public: + ScopeTimer(const std::string &message); + ~ScopeTimer(); +}; + +#ifdef DEBUG_TIME +# define Timer(x) \ + ScopeTimer prof(x); +#else +# define Timer(x) +#endif + +#endif /* __OPENVDB_UTIL_H__ */ diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index c4b2d9ff897..382cb181d5f 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -151,6 +151,13 @@ def write_sysinfo(filepath): else: output.write("Blender was built without Cycles support\n") + openvdb = bpy.app.openvdb + output.write("OpenVDB: ") + if openvdb.supported: + output.write("%s\n" % openvdb.version_string) + else: + output.write("Blender was built without OpenVDB support\n") + if not bpy.app.build_options.sdl: output.write("SDL: Blender was built without SDL support\n") diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index 85d3c1d7dc4..32d5b287d83 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -304,12 +304,26 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout - md = context.smoke.domain_settings - cache = md.point_cache + domain = context.smoke.domain_settings + cache_file_format = domain.cache_file_format + + layout.prop(domain, "cache_file_format") + + if cache_file_format == 'POINTCACHE': + layout.label(text="Compression:") + layout.prop(domain, "point_cache_compress_type", expand=True) + elif cache_file_format == 'OPENVDB': + if not bpy.app.build_options.openvdb: + layout.label("Build without OpenVDB support.") + return - layout.label(text="Compression:") - layout.prop(md, "point_cache_compress_type", expand=True) + layout.label(text="Compression:") + layout.prop(domain, "openvdb_cache_compress_type", expand=True) + row = layout.row() + row.label("Data Depth:") + row.prop(domain, "data_depth", expand=True, text="Data Depth") + cache = domain.point_cache point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE') diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index d1b8aa672c5..40dbffe7222 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -94,6 +94,9 @@ struct SmokeModifierData; struct SoftBody; struct RigidBodyWorld; +struct OpenVDBReader; +struct OpenVDBWriter; + /* temp structure for read/write */ typedef struct PTCacheData { unsigned int index; @@ -119,13 +122,18 @@ typedef struct PTCacheFile { #define PTCACHE_VEL_PER_SEC 1 +enum { + PTCACHE_FILE_PTCACHE = 0, + PTCACHE_FILE_OPENVDB = 1, +}; + typedef struct PTCacheID { struct PTCacheID *next, *prev; struct Scene *scene; struct Object *ob; void *calldata; - unsigned int type; + unsigned int type, file_type; unsigned int stack_index; unsigned int flag; @@ -147,6 +155,11 @@ typedef struct PTCacheID { /* copies cache cata to point data */ int (*read_stream)(PTCacheFile *pf, void *calldata); + /* copies point data to cache data */ + int (*write_openvdb_stream)(struct OpenVDBWriter *writer, void *calldata); + /* copies cache cata to point data */ + int (*read_openvdb_stream)(struct OpenVDBReader *reader, void *calldata); + /* copies custom extradata to cache data */ void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra); /* copies custom extradata to cache data */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 3ba6eb6c66d..b0a105bb910 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -517,6 +517,19 @@ if(WITH_OPENSUBDIV) endif() endif() +if(WITH_OPENVDB) + add_definitions(-DWITH_OPENVDB) + list(APPEND INC + ../../../intern/openvdb + ) + + if(WITH_OPENVDB_BLOSC) + add_definitions( + -DWITH_OPENVDB_BLOSC + ) + endif() +endif() + ## Warnings as errors, this is too strict! #if(MSVC) # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index ad599942b50..8d6edcec0c7 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -83,6 +83,10 @@ #include "smoke_API.h" #endif +#ifdef WITH_OPENVDB +#include "openvdb_capi.h" +#endif + #ifdef WITH_LZO # ifdef WITH_SYSTEM_LZO # include <lzo/lzo1x.h> @@ -887,6 +891,274 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) return 1; } +#ifdef WITH_OPENVDB +/** + * Construct matrices which represent the fluid object, for low and high res: + * <pre> + * vs 0 0 0 + * 0 vs 0 0 + * 0 0 vs 0 + * px py pz 1 + * </pre> + * + * with `vs` = voxel size, and `px, py, pz`, + * the min position of the domain's bounding box. + */ +static void compute_fluid_matrices(SmokeDomainSettings *sds) +{ + float bbox_min[3]; + + copy_v3_v3(bbox_min, sds->p0); + + if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]); + bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]); + bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]); + add_v3_v3(bbox_min, sds->obj_shift_f); + } + + /* construct low res matrix */ + size_to_mat4(sds->fluidmat, sds->cell_size); + copy_v3_v3(sds->fluidmat[3], bbox_min); + + /* The smoke simulator stores voxels cell-centered, whilst VDB is node + * centered, so we offset the matrix by half a voxel to compensate. */ + madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f); + + mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat); + + if (sds->wt) { + float voxel_size_high[3]; + /* construct high res matrix */ + mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1)); + size_to_mat4(sds->fluidmat_wt, voxel_size_high); + copy_v3_v3(sds->fluidmat_wt[3], bbox_min); + + /* Same here, add half a voxel to adjust the position of the fluid. */ + madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f); + + mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt); + } +} + +static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v) +{ + SmokeModifierData *smd = (SmokeModifierData *)smoke_v; + SmokeDomainSettings *sds = smd->domain; + + OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16)); + + OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color); + OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat); + + int fluid_fields = smoke_get_data_flags(sds); + + struct OpenVDBFloatGrid *clip_grid = NULL; + + compute_fluid_matrices(sds); + + OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields); + + if (sds->wt) { + struct OpenVDBFloatGrid *wt_density_grid; + float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; + + smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + + wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, NULL); + clip_grid = wt_density_grid; + + if (fluid_fields & SM_ACTIVE_FIRE) { + OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid); + } + + OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid); + } + + if (sds->fluid) { + struct OpenVDBFloatGrid *density_grid; + float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; + unsigned char *obstacles; + + smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, + &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles); + + OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx); + OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt); + + const char *name = (!sds->wt) ? "density" : "density low"; + density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, NULL); + clip_grid = sds->wt ? clip_grid : density_grid; + + OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, NULL); + + if (fluid_fields & SM_ACTIVE_HEAT) { + OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, clip_grid); + OpenVDB_export_grid_fl(writer, "heat old", heatold, sds->res, sds->fluidmat, clip_grid); + } + + if (fluid_fields & SM_ACTIVE_FIRE) { + name = (!sds->wt) ? "flame" : "flame low"; + OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, density_grid); + name = (!sds->wt) ? "fuel" : "fuel low"; + OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, density_grid); + name = (!sds->wt) ? "react" : "react low"; + OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, density_grid); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + name = (!sds->wt) ? "color" : "color low"; + OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid); + } + + OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid); + OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, NULL); + } + + return 1; +} + +static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v) +{ + SmokeModifierData *smd = (SmokeModifierData *)smoke_v; + + if (!smd) { + return 0; + } + + SmokeDomainSettings *sds = smd->domain; + + int fluid_fields = smoke_get_data_flags(sds); + int active_fields, cache_fields = 0; + int cache_res[3]; + float cache_dx; + bool reallocate = false; + + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color); + OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat); + OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields); + OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields); + OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res); + + /* check if resolution has changed */ + if (sds->res[0] != cache_res[0] || + sds->res[1] != cache_res[1] || + sds->res[2] != cache_res[2]) + { + if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + reallocate = true; + } + else { + return 0; + } + } + + /* check if active fields have changed */ + if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) { + reallocate = true; + } + + /* reallocate fluid if needed*/ + if (reallocate) { + sds->active_fields = active_fields | cache_fields; + smoke_reallocate_fluid(sds, cache_dx, cache_res, 1); + sds->dx = cache_dx; + copy_v3_v3_int(sds->res, cache_res); + sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2]; + + if (sds->flags & MOD_SMOKE_HIGHRES) { + smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1); + } + } + + if (sds->fluid) { + float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; + unsigned char *obstacles; + + smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat, + &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles); + + OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt); + + OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res); + + const char *name = (!sds->wt) ? "density" : "density Low"; + OpenVDB_import_grid_fl(reader, name, &dens, sds->res); + + if (fluid_fields & SM_ACTIVE_HEAT) { + OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res); + OpenVDB_import_grid_fl(reader, "heat old", &heatold, sds->res); + } + + if (fluid_fields & SM_ACTIVE_FIRE) { + name = (!sds->wt) ? "flame" : "flame low"; + OpenVDB_import_grid_fl(reader, name, &flame, sds->res); + name = (!sds->wt) ? "fuel" : "fuel low"; + OpenVDB_import_grid_fl(reader, name, &fuel, sds->res); + name = (!sds->wt) ? "react" : "react low"; + OpenVDB_import_grid_fl(reader, name, &react, sds->res); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + name = (!sds->wt) ? "color" : "color low"; + OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res); + } + + OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res); + OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res); + } + + if (sds->wt) { + float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; + + smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + + OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt); + + if (fluid_fields & SM_ACTIVE_FIRE) { + OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt); + OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt); + OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt); + } + + if (fluid_fields & SM_ACTIVE_COLORS) { + OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt); + } + + OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res); + } + + OpenVDBReader_free(reader); + + return 1; +} +#endif + #else // WITH_SMOKE static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; } static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message)) { } @@ -894,6 +1166,20 @@ static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; } #endif // WITH_SMOKE +#if !defined(WITH_SMOKE) || !defined(WITH_OPENVDB) +static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v) +{ + UNUSED_VARS(writer, smoke_v); + return 0; +} + +static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v) +{ + UNUSED_VARS(reader, smoke_v); + return 0; +} +#endif + static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra)) { DynamicPaintSurface *surface = (DynamicPaintSurface*)sd; @@ -1113,6 +1399,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->write_stream = NULL; pid->read_stream = NULL; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1127,6 +1416,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) pid->default_step = 10; pid->max_step = 20; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys) { @@ -1154,6 +1444,9 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->write_stream = NULL; pid->read_stream = NULL; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1185,6 +1478,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p pid->default_step = 10; pid->max_step = 20; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd) { @@ -1204,6 +1498,9 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->read_point = ptcache_cloth_read; pid->interpolate_point = ptcache_cloth_interpolate; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_stream = NULL; pid->read_stream = NULL; @@ -1219,6 +1516,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->default_step = 1; pid->max_step = 1; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd) { @@ -1246,6 +1544,9 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo pid->read_stream = ptcache_smoke_read; pid->write_stream = ptcache_smoke_write; + pid->write_openvdb_stream = ptcache_smoke_openvdb_write; + pid->read_openvdb_stream = ptcache_smoke_openvdb_read; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1263,6 +1564,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo pid->default_step = 1; pid->max_step = 1; + pid->file_type = smd->domain->cache_file_format; } void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface) @@ -1286,6 +1588,9 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu pid->write_stream = ptcache_dynamicpaint_write; pid->read_stream = ptcache_dynamicpaint_read; + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; + pid->write_extra_data = NULL; pid->read_extra_data = NULL; pid->interpolate_extra_data = NULL; @@ -1300,6 +1605,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu pid->default_step = 1; pid->max_step = 1; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw) @@ -1322,6 +1628,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->write_stream = NULL; pid->read_stream = NULL; + + pid->write_openvdb_stream = NULL; + pid->read_openvdb_stream = NULL; pid->write_extra_data = NULL; pid->read_extra_data = NULL; @@ -1337,6 +1646,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->default_step = 1; pid->max_step = 1; + pid->file_type = PTCACHE_FILE_PTCACHE; } void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis) @@ -1429,6 +1739,38 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup /* File handling */ +static const char *ptcache_file_extension(const PTCacheID *pid) +{ + switch (pid->file_type) { + default: + case PTCACHE_FILE_PTCACHE: + return PTCACHE_EXT; + case PTCACHE_FILE_OPENVDB: + return ".vdb"; + } +} + +/** + * Similar to #BLI_path_frame_get, but takes into account the stack-index which is after the frame. + */ +static int ptcache_frame_from_filename(const char *filename, const char *ext) +{ + const int frame_len = 6; + const int ext_len = frame_len + strlen(ext); + const int len = strlen(filename); + + /* could crash if trying to copy a string out of this range */ + if (len > ext_len) { + /* using frame_len here gives compile error (vla) */ + char num[/* frame_len */6 + 1]; + BLI_strncpy(num, filename + len - ext_len, sizeof(num)); + + return atoi(num); + } + + return -1; +} + /* Takes an Object ID and returns a unique name * - id: object id * - cfra: frame for the cache, can be negative @@ -1507,18 +1849,19 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p } if (do_ext) { - if (pid->cache->index < 0) pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob); + const char *ext = ptcache_file_extension(pid); + if (pid->cache->flag & PTCACHE_EXTERNAL) { if (pid->cache->index >= 0) - BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */ else - BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */ } else { - BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */ } len += 16; } @@ -2156,6 +2499,36 @@ static int ptcache_read_stream(PTCacheID *pid, int cfra) return error == 0; } + +static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra) +{ +#ifdef WITH_OPENVDB + char filename[FILE_MAX * 2]; + + /* save blend file before using disk pointcache */ + if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) + return 0; + + ptcache_filename(pid, filename, cfra, 1, 1); + + if (!BLI_exists(filename)) { + return 0; + } + + struct OpenVDBReader *reader = OpenVDBReader_create(); + OpenVDBReader_open(reader, filename); + + if (!pid->read_openvdb_stream(reader, pid->calldata)) { + return 0; + } + + return 1; +#else + UNUSED_VARS(pid, cfra); + return 0; +#endif +} + static int ptcache_read(PTCacheID *pid, int cfra) { PTCacheMem *pm = NULL; @@ -2297,8 +2670,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra) return 0; if (cfra1) { - - if (pid->read_stream) { + if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) { + if (!ptcache_read_openvdb_stream(pid, cfra1)) { + return 0; + } + } + else if (pid->read_stream) { if (!ptcache_read_stream(pid, cfra1)) return 0; } @@ -2307,8 +2684,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra) } if (cfra2) { - - if (pid->read_stream) { + if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) { + if (!ptcache_read_openvdb_stream(pid, cfra2)) { + return 0; + } + } + else if (pid->read_stream) { if (!ptcache_read_stream(pid, cfra2)) return 0; } @@ -2374,6 +2755,28 @@ static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint) return error == 0; } +static int ptcache_write_openvdb_stream(PTCacheID *pid, int cfra) +{ +#ifdef WITH_OPENVDB + struct OpenVDBWriter *writer = OpenVDBWriter_create(); + char filename[FILE_MAX * 2]; + + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra); + + ptcache_filename(pid, filename, cfra, 1, 1); + BLI_make_existing_file(filename); + + int error = pid->write_openvdb_stream(writer, pid->calldata); + + OpenVDBWriter_write(writer, filename); + OpenVDBWriter_free(writer); + + return error == 0; +#else + UNUSED_VARS(pid, cfra); + return 0; +#endif +} static int ptcache_write(PTCacheID *pid, int cfra, int overwrite) { PointCache *cache = pid->cache; @@ -2505,7 +2908,10 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra) if (ptcache_write_needed(pid, cfra, &overwrite)==0) return 0; - if (pid->write_stream) { + if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->write_openvdb_stream) { + ptcache_write_openvdb_stream(pid, cfra); + } + else if (pid->write_stream) { ptcache_write_stream(pid, cfra, totpoint); } else if (pid->write_point) { @@ -2563,7 +2969,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) #endif /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */ - + + const char *fext = ptcache_file_extension(pid); + /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ switch (mode) { case PTCACHE_CLEAR_ALL: @@ -2585,7 +2993,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) len += 1; } - BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); + BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ @@ -2597,13 +3005,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) } else { /* read the number of the file */ - unsigned int frame, len2 = (int)strlen(de->d_name); - char num[7]; + const int frame = ptcache_frame_from_filename(de->d_name, ext); - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); - + if (frame != -1) { if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) || (mode == PTCACHE_CLEAR_AFTER && frame > cfra)) { @@ -2791,21 +3195,18 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra if (dir==NULL) return; - BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); + const char *fext = ptcache_file_extension(pid); + + BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */ /* read the number of the file */ - unsigned int frame, len2 = (int)strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); - - if (frame >= sta && frame <= end) - cache->cached_frames[frame-sta] = 1; + const int frame = ptcache_frame_from_filename(de->d_name, ext); + + if ((frame != -1) && (frame >= sta && frame <= end)) { + cache->cached_frames[frame-sta] = 1; } } } @@ -3466,7 +3867,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c return; } - BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index); + const char *fext = ptcache_file_extension(pid); + + BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext); /* put new name into cache */ BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name)); @@ -3475,13 +3878,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */ /* read the number of the file */ - int frame, len2 = (int)strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); + const int frame = ptcache_frame_from_filename(de->d_name, ext); + if (frame != -1) { BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name); ptcache_filename(pid, new_path_full, frame, 1, 1); BLI_rename(old_path_full, new_path_full); @@ -3521,22 +3920,20 @@ void BKE_ptcache_load_external(PTCacheID *pid) if (dir==NULL) return; + const char *fext = ptcache_file_extension(pid); + if (cache->index >= 0) - BLI_snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index); + BLI_snprintf(ext, sizeof(ext), "_%02d%s", cache->index, fext); else - BLI_strncpy(ext, PTCACHE_EXT, sizeof(ext)); + BLI_strncpy(ext, fext, sizeof(ext)); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */ /* read the number of the file */ - int frame, len2 = (int)strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); + const int frame = ptcache_frame_from_filename(de->d_name, ext); + if (frame != -1) { if (frame) { start = MIN2(start, frame); end = MAX2(end, frame); diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 2d3fa2a3818..c7215cc7d4c 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -527,6 +527,14 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG; smd->domain->effector_weights = BKE_add_effector_weights(NULL); + +#ifdef WITH_OPENVDB_BLOSC + smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; +#else + smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; +#endif + smd->domain->data_depth = 0; + smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -617,6 +625,9 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData MEM_freeN(tsmd->domain->effector_weights); tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights); + tsmd->domain->openvdb_comp = smd->domain->openvdb_comp; + tsmd->domain->data_depth = smd->domain->data_depth; + tsmd->domain->cache_file_format = smd->domain->cache_file_format; } else if (tsmd->flow) { tsmd->flow->psys = smd->flow->psys; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 732d699d48f..84cb28b3fc0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7812,9 +7812,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* draw adaptive domain bounds */ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) { - float p0[3], p1[3]; - BoundBox bb; /* draw domain max bounds */ + BoundBox bb; + float p0[3], p1[3]; VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res); VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res); BKE_boundbox_init_from_minmax(&bb, p0, p1); @@ -7825,6 +7825,20 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1); draw_box(bb.vec); #endif + + + /* draw a single voxel to hint the user about the resolution of the fluid */ + copy_v3_v3(p0, sds->p0); + + if (sds->flags & MOD_SMOKE_HIGHRES) { + madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1)); + } + else { + add_v3_v3v3(p1, p0, sds->cell_size); + } + + BKE_boundbox_init_from_minmax(&bb, p0, p1); + draw_box(bb.vec, false); } /* don't show smoke before simulation starts, this could be made an option in the future */ diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 5e011678fee..76de8443faa 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -77,6 +77,12 @@ enum { #define SM_ACTIVE_COLORS (1<<2) #define SM_ACTIVE_COLOR_SET (1<<3) +enum { + VDB_COMPRESSION_BLOSC = 0, + VDB_COMPRESSION_ZIP = 1, + VDB_COMPRESSION_NONE = 2, +}; + typedef struct SmokeDomainSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct FLUID_3D *fluid; @@ -103,6 +109,8 @@ typedef struct SmokeDomainSettings { float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock" domain while drawing) */ float imat[4][4]; /* domain object imat */ float obmat[4][4]; /* domain obmat */ + float fluidmat[4][4]; /* low res fluid matrix */ + float fluidmat_wt[4][4]; /* high res fluid matrix */ int base_res[3]; /* initial "non-adapted" resolution */ int res_min[3]; /* cell min */ @@ -129,8 +137,14 @@ typedef struct SmokeDomainSettings { float strength; int res_wt[3]; float dx_wt; + /* point cache options */ int cache_comp; int cache_high_comp; + /* OpenVDB cache options */ + int openvdb_comp; + char cache_file_format; + char data_depth; + char pad[2]; /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading old files. */ struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */ diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 987b594421f..31bf0c9389b 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -311,6 +311,14 @@ if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) endif() +if(WITH_OPENVDB) + add_definitions(-DWITH_OPENVDB) + + if(WITH_OPENVDB_BLOSC) + add_definitions(-DWITH_OPENVDB_BLOSC) + endif() +endif() + # Build makesrna executable blender_include_dirs( . diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 539f3c192be..ba3198a4843 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -35,6 +35,7 @@ #include "BKE_modifier.h" #include "BKE_smoke.h" +#include "BKE_pointcache.h" #include "BLI_threads.h" @@ -332,6 +333,15 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_compression_items[] = { + { VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression" }, +#ifdef WITH_OPENVDB_BLOSC + { VDB_COMPRESSION_BLOSC, "BLOSC", 0, "Blosc", "Multithreaded compression, similar in size and quality as 'Zip'" }, +#endif + { VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression" }, + { 0, NULL, 0, NULL, NULL } + }; + static EnumPropertyItem smoke_cache_comp_items[] = { {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Light", "Fast but not so effective compression"}, {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"}, @@ -345,6 +355,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem smoke_data_depth_items[] = { + {16, "16", 0, "Float (Half)", "Half float (16 bit data)"}, + {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */ + {0, NULL, 0, NULL, NULL}, + }; + static EnumPropertyItem smoke_domain_colli_items[] = { {SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"}, {SM_BORDER_VERTICAL, "BORDERVERTICAL", 0, "Vertically Open", @@ -353,6 +369,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem cache_file_type_items[] = { + {PTCACHE_FILE_PTCACHE, "POINTCACHE", 0, "Point Cache", "Blender specific point cache file format"}, +#ifdef WITH_OPENVDB + {PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"}, +#endif + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL); RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings"); RNA_def_struct_sdna(srna, "SmokeDomainSettings"); @@ -463,6 +487,19 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_enum_items(prop, smoke_cache_comp_items); RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used"); + prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp"); + RNA_def_property_enum_items(prop, prop_compression_items); + RNA_def_property_ui_text(prop, "Compression", "Compression method to be used"); + + prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth"); + RNA_def_property_enum_items(prop, smoke_data_depth_items); + RNA_def_property_ui_text(prop, "Data Depth", + "Bit depth for writing all scalar (including vector) " + "lower values reduce file size"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "border_collisions"); RNA_def_property_enum_items(prop, smoke_domain_colli_items); @@ -601,6 +638,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); + + prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_file_format"); + RNA_def_property_enum_items(prop, cache_file_type_items); + RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); } static void rna_def_smoke_flow_settings(BlenderRNA *brna) diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index cbfbe0a8768..5b39dbb062b 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC bpy_app_handlers.c bpy_app_ocio.c bpy_app_oiio.c + bpy_app_openvdb.c bpy_app_sdl.c bpy_app_translations.c bpy_driver.c @@ -84,6 +85,7 @@ set(SRC bpy_app_handlers.h bpy_app_ocio.h bpy_app_oiio.h + bpy_app_openvdb.h bpy_app_sdl.h bpy_app_translations.h bpy_driver.h @@ -267,6 +269,13 @@ if(WITH_OPENCOLORIO) add_definitions(-DWITH_OCIO) endif() +if(WITH_OPENVDB) + add_definitions(-DWITH_OPENVDB) + list(APPEND INC + ../../../../intern/openvdb + ) +endif() + if(WITH_OPENIMAGEIO) add_definitions(-DWITH_OPENIMAGEIO) list(APPEND INC diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index a0ea991fd05..595bb7b0f22 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -36,6 +36,7 @@ #include "bpy_app_ffmpeg.h" #include "bpy_app_ocio.h" #include "bpy_app_oiio.h" +#include "bpy_app_openvdb.h" #include "bpy_app_sdl.h" #include "bpy_app_build_options.h" @@ -106,6 +107,7 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"ffmpeg", (char *)"FFmpeg library information backend"}, {(char *)"ocio", (char *)"OpenColorIO library information backend"}, {(char *)"oiio", (char *)"OpenImageIO library information backend"}, + {(char *)"openvdb", (char *)"OpenVDB library information backend"}, {(char *)"sdl", (char *)"SDL library information backend"}, {(char *)"build_options", (char *)"A set containing most important enabled optional build features"}, {(char *)"handlers", (char *)"Application handler callbacks"}, @@ -183,6 +185,7 @@ static PyObject *make_app_info(void) SetObjItem(BPY_app_ffmpeg_struct()); SetObjItem(BPY_app_ocio_struct()); SetObjItem(BPY_app_oiio_struct()); + SetObjItem(BPY_app_openvdb_struct()); SetObjItem(BPY_app_sdl_struct()); SetObjItem(BPY_app_build_options_struct()); SetObjItem(BPY_app_handlers_struct()); diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index 975d76ca42d..692ebf552c7 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -69,6 +69,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"opencolorio", NULL}, {(char *)"player", NULL}, {(char *)"openmp", NULL}, + {(char *)"openvdb", NULL}, {NULL} }; @@ -303,6 +304,12 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif +#ifdef WITH_OPENVDB + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + #undef SetObjIncref return builtopts_info; diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c new file mode 100644 index 00000000000..8a24aaf0555 --- /dev/null +++ b/source/blender/python/intern/bpy_app_openvdb.c @@ -0,0 +1,117 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_openvdb.c + * \ingroup pythonintern + */ + +#include <Python.h> +#include "BLI_utildefines.h" + +#include "bpy_app_openvdb.h" + +#ifdef WITH_OPENVDB +# include "openvdb_capi.h" +#endif + +static PyTypeObject BlenderAppOVDBType; + +static PyStructSequence_Field app_openvdb_info_fields[] = { + {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenVDB support")}, + {(char *)("version"), (char *)("The OpenVDB version as a tuple of 3 numbers")}, + {(char *)("version_string"), (char *)("The OpenVDB version formatted as a string")}, + {NULL} +}; + +static PyStructSequence_Desc app_openvdb_info_desc = { + (char *)"bpy.app.openvdb", /* name */ + (char *)"This module contains information about OpenVDB blender is linked against", /* doc */ + app_openvdb_info_fields, /* fields */ + ARRAY_SIZE(app_openvdb_info_fields) - 1 +}; + +static PyObject *make_openvdb_info(void) +{ + PyObject *openvdb_info; + int pos = 0; + +#ifdef WITH_OPENVDB + int curversion; +#endif + + openvdb_info = PyStructSequence_New(&BlenderAppOVDBType); + if (openvdb_info == NULL) { + return NULL; + } + +#ifndef WITH_OPENVDB +#define SetStrItem(str) \ + PyStructSequence_SET_ITEM(openvdb_info, pos++, PyUnicode_FromString(str)) +#endif + +#define SetObjItem(obj) \ + PyStructSequence_SET_ITEM(openvdb_info, pos++, obj) + +#ifdef WITH_OPENVDB + curversion = OpenVDB_getVersionHex(); + SetObjItem(PyBool_FromLong(1)); + SetObjItem(Py_BuildValue("(iii)", + curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", + curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); +#else + SetObjItem(PyBool_FromLong(0)); + SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetStrItem("Unknown"); +#endif + + if (PyErr_Occurred()) { + Py_CLEAR(openvdb_info); + return NULL; + } + +#undef SetStrItem +#undef SetObjItem + + return openvdb_info; +} + +PyObject *BPY_app_openvdb_struct(void) +{ + PyObject *ret; + + PyStructSequence_InitType(&BlenderAppOVDBType, &app_openvdb_info_desc); + + ret = make_openvdb_info(); + + /* prevent user from creating new instances */ + BlenderAppOVDBType.tp_init = NULL; + BlenderAppOVDBType.tp_new = NULL; + BlenderAppOVDBType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */ + + return ret; +} diff --git a/source/blender/python/intern/bpy_app_openvdb.h b/source/blender/python/intern/bpy_app_openvdb.h new file mode 100644 index 00000000000..12fa54ea7a3 --- /dev/null +++ b/source/blender/python/intern/bpy_app_openvdb.h @@ -0,0 +1,38 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Kevin Dietrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_app_openvdb.h + * \ingroup pythonintern + */ + +#ifndef __BPY_APP_OPENVDB_H__ +#define __BPY_APP_OPENVDB_H__ + +PyObject *BPY_app_openvdb_struct(void); + +#endif /* __BPY_APP_OPENVDB_H__ */ + diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index e8c710e68ae..65432fc3f88 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -218,6 +218,10 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv) endif() + if(WITH_OPENVDB) + list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb) + endif() + foreach(SORTLIB ${BLENDER_SORTED_LIBS}) set(REMLIB ${SORTLIB}) foreach(SEARCHLIB ${BLENDER_LINK_LIBS}) |