Implementation of OpenVDB as a possible cache format for smoke
authorKévin Dietrich <kevin.dietrich@mailoo.org>
Sat, 23 Jan 2016 07:39:29 +0000 (08:39 +0100)
committerKévin Dietrich <kevin.dietrich@mailoo.org>
Sat, 23 Jan 2016 07:39:40 +0000 (08:39 +0100)
simulations.

This commits implements OpenVDB as an extra cache format in the Point
Cache system for smoke simulations. Compilation with the library is
turned off by default for now, and shall be enabled when the library is
present.

A documentation of its doings is available here: http://
wiki.blender.org/index.php/User:Kevindietrich/OpenVDBSmokeExport.

A guide to compile OpenVDB can be found here (Linux): http://
wiki.blender.org/index.php?title=Dev:Doc/Building_Blender/Linux/
Dependencies_From_Source#OpenVDB

Reviewers: sergey, lukastoenne, brecht, campbellbarton

Reviewed By: brecht, campbellbarton

Subscribers: galenb, Blendify, robocyte, Lapineige, bliblubli,
jtheninja, lukasstockner97, dingto, brecht

Differential Revision: https://developer.blender.org/D1721

33 files changed:
CMakeLists.txt
build_files/cmake/Modules/FindOpenVDB.cmake [new file with mode: 0644]
build_files/cmake/config/blender_lite.cmake
build_files/cmake/config/bpy_module.cmake
build_files/cmake/macros.cmake
intern/CMakeLists.txt
intern/openvdb/CMakeLists.txt [new file with mode: 0644]
intern/openvdb/intern/openvdb_dense_convert.cc [new file with mode: 0644]
intern/openvdb/intern/openvdb_dense_convert.h [new file with mode: 0644]
intern/openvdb/intern/openvdb_reader.cc [new file with mode: 0644]
intern/openvdb/intern/openvdb_reader.h [new file with mode: 0644]
intern/openvdb/intern/openvdb_writer.cc [new file with mode: 0644]
intern/openvdb/intern/openvdb_writer.h [new file with mode: 0644]
intern/openvdb/openvdb_capi.cc [new file with mode: 0644]
intern/openvdb/openvdb_capi.h [new file with mode: 0644]
intern/openvdb/openvdb_util.cc [new file with mode: 0644]
intern/openvdb/openvdb_util.h [new file with mode: 0644]
release/scripts/modules/sys_info.py
release/scripts/startup/bl_ui/properties_physics_smoke.py
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/smoke.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_smoke_types.h
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/rna_smoke.c
source/blender/python/intern/CMakeLists.txt
source/blender/python/intern/bpy_app.c
source/blender/python/intern/bpy_app_build_options.c
source/blender/python/intern/bpy_app_openvdb.c [new file with mode: 0644]
source/blender/python/intern/bpy_app_openvdb.h [new file with mode: 0644]
source/blenderplayer/CMakeLists.txt

index e0326f1..4ec5053 100644 (file)
@@ -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 (file)
index 0000000..a13feab
--- /dev/null
@@ -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)
index 99e90ca..a479506 100644 (file)
@@ -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)
index b5b13b4..4114015 100644 (file)
@@ -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)
index 6194bd8..28617cd 100644 (file)
@@ -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})
index f5f2d1c..43e5b6b 100644 (file)
@@ -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 (file)
index 0000000..ce683e7
--- /dev/null
@@ -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 (file)
index 0000000..d4f6277
--- /dev/null
@@ -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 (file)
index 0000000..fd10334
--- /dev/null
@@ -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 (file)
index 0000000..8b15b81
--- /dev/null
@@ -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 (file)
index 0000000..07f7713
--- /dev/null
@@ -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 (file)
index 0000000..9237529
--- /dev/null
@@ -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 (file)
index 0000000..69f4247
--- /dev/null
@@ -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 (file)
index 0000000..ef4f8c8
--- /dev/null
@@ -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 (file)
index 0000000..2d2feea
--- /dev/null
@@ -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 (file)
index 0000000..d187f55
--- /dev/null
@@ -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 (file)
index 0000000..8e14ed5
--- /dev/null
@@ -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__ */
index c4b2d9f..382cb18 100644 (file)
@@ -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")
 
index 85d3c1d..32d5b28 100644 (file)
@@ -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')
 
 
index d1b8aa6..40dbffe 100644 (file)
@@ -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 */
index 3ba6eb6..b0a105b 100644 (file)
@@ -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")
index ad59994..8d6edce 100644 (file)
 #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);
index 2d3fa2a..c7215cc 100644 (file)
@@ -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;
index 732d699..84cb28b 100644 (file)
@@ -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 */
index 5e01167..76de844 100644 (file)
@@ -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 */
index 987b594..31bf0c9 100644 (file)
@@ -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(
        .
index 539f3c1..ba3198a 100644 (file)
@@ -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)
index cbfbe0a..5b39dbb 100644 (file)
@@ -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
index a0ea991..595bb7b 100644 (file)
@@ -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());
index 975d76c..692ebf5 100644 (file)
@@ -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 (file)
index 0000000..8a24aaf
--- /dev/null
@@ -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 (file)
index 0000000..12fa54e
--- /dev/null
@@ -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__ */
+
index e8c710e..65432fc 100644 (file)
@@ -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})