1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup bke
19  */
20 
21 #include "MEM_guardedalloc.h"
22 
23 #include "DNA_defaults.h"
24 #include "DNA_material_types.h"
25 #include "DNA_object_types.h"
26 #include "DNA_scene_types.h"
27 #include "DNA_volume_types.h"
28 
29 #include "BLI_compiler_compat.h"
30 #include "BLI_fileops.h"
31 #include "BLI_ghash.h"
32 #include "BLI_map.hh"
33 #include "BLI_math.h"
34 #include "BLI_path_util.h"
35 #include "BLI_string.h"
36 #include "BLI_utildefines.h"
37 
38 #include "BKE_anim_data.h"
39 #include "BKE_global.h"
40 #include "BKE_idtype.h"
41 #include "BKE_lib_id.h"
42 #include "BKE_lib_query.h"
43 #include "BKE_lib_remap.h"
44 #include "BKE_main.h"
45 #include "BKE_modifier.h"
46 #include "BKE_object.h"
47 #include "BKE_packedFile.h"
48 #include "BKE_report.h"
49 #include "BKE_scene.h"
50 #include "BKE_volume.h"
51 
52 #include "BLT_translation.h"
53 
54 #include "DEG_depsgraph_query.h"
55 
56 #include "BLO_read_write.h"
57 
58 #include "CLG_log.h"
59 
60 #ifdef WITH_OPENVDB
61 static CLG_LogRef LOG = {"bke.volume"};
62 #endif
63 
64 #define VOLUME_FRAME_NONE INT_MAX
65 
66 #ifdef WITH_OPENVDB
67 #  include <atomic>
68 #  include <list>
69 #  include <mutex>
70 #  include <unordered_set>
71 
72 #  include <openvdb/openvdb.h>
73 #  include <openvdb/points/PointDataGrid.h>
74 #  include <openvdb/tools/GridTransformer.h>
75 
76 /* Global Volume File Cache
77  *
78  * Global cache of grids read from VDB files. This is used for sharing grids
79  * between multiple volume datablocks with the same filepath, and sharing grids
80  * between original and copy-on-write datablocks created by the depsgraph.
81  *
82  * There are two types of users. Some datablocks only need the grid metadata,
83  * example an original datablock volume showing the list of grids in the
84  * properties editor. Other datablocks also need the tree and voxel data, for
85  * rendering for example. So, depending on the users the grid in the cache may
86  * have a tree or not.
87  *
88  * When the number of users drops to zero, the grid data is immediately deleted.
89  *
90  * TODO: also add a cache for OpenVDB files rather than individual grids,
91  * so getting the list of grids is also cached.
92  * TODO: Further, we could cache openvdb::io::File so that loading a grid
93  * does not re-open it every time. But then we have to take care not to run
94  * out of file descriptors or prevent other applications from writing to it.
95  */
96 
97 static struct VolumeFileCache {
98   /* Cache Entry */
99   struct Entry {
EntryVolumeFileCache::Entry100     Entry(const std::string &filepath, const openvdb::GridBase::Ptr &grid)
101         : filepath(filepath),
102           grid_name(grid->getName()),
103           grid(grid),
104           is_loaded(false),
105           num_metadata_users(0),
106           num_tree_users(0)
107     {
108     }
109 
EntryVolumeFileCache::Entry110     Entry(const Entry &other)
111         : filepath(other.filepath),
112           grid_name(other.grid_name),
113           grid(other.grid),
114           is_loaded(other.is_loaded),
115           num_metadata_users(0),
116           num_tree_users(0)
117     {
118     }
119 
120     /* Returns the original grid or a simplified version depending on the given #simplify_level. */
simplified_gridVolumeFileCache::Entry121     openvdb::GridBase::Ptr simplified_grid(const int simplify_level)
122     {
123       BLI_assert(simplify_level >= 0);
124       if (simplify_level == 0 || !is_loaded) {
125         return grid;
126       }
127 
128       std::lock_guard<std::mutex> lock(mutex);
129       return simplified_grids.lookup_or_add_cb(simplify_level, [&]() {
130         const float resolution_factor = 1.0f / (1 << simplify_level);
131         const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(grid);
132         return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor);
133       });
134     }
135 
136     /* Unique key: filename + grid name. */
137     std::string filepath;
138     std::string grid_name;
139 
140     /* OpenVDB grid. */
141     openvdb::GridBase::Ptr grid;
142 
143     /* Simplified versions of #grid. The integer key is the simplification level. */
144     blender::Map<int, openvdb::GridBase::Ptr> simplified_grids;
145 
146     /* Has the grid tree been loaded? */
147     bool is_loaded;
148     /* Error message if an error occured during loading. */
149     std::string error_msg;
150     /* User counting. */
151     int num_metadata_users;
152     int num_tree_users;
153     /* Mutex for on-demand reading of tree. */
154     std::mutex mutex;
155   };
156 
157   struct EntryHasher {
operator ()VolumeFileCache::EntryHasher158     std::size_t operator()(const Entry &entry) const
159     {
160       std::hash<std::string> string_hasher;
161       return BLI_ghashutil_combine_hash(string_hasher(entry.filepath),
162                                         string_hasher(entry.grid_name));
163     }
164   };
165 
166   struct EntryEqual {
operator ()VolumeFileCache::EntryEqual167     bool operator()(const Entry &a, const Entry &b) const
168     {
169       return a.filepath == b.filepath && a.grid_name == b.grid_name;
170     }
171   };
172 
173   /* Cache */
VolumeFileCacheVolumeFileCache174   VolumeFileCache()
175   {
176   }
177 
~VolumeFileCacheVolumeFileCache178   ~VolumeFileCache()
179   {
180     BLI_assert(cache.empty());
181   }
182 
add_metadata_userVolumeFileCache183   Entry *add_metadata_user(const Entry &template_entry)
184   {
185     std::lock_guard<std::mutex> lock(mutex);
186     EntrySet::iterator it = cache.find(template_entry);
187     if (it == cache.end()) {
188       it = cache.emplace(template_entry).first;
189     }
190 
191     /* Casting const away is weak, but it's convenient having key and value in one. */
192     Entry &entry = (Entry &)*it;
193     entry.num_metadata_users++;
194 
195     /* Note: pointers to unordered_set values are not invalidated when adding
196      * or removing other values. */
197     return &entry;
198   }
199 
copy_userVolumeFileCache200   void copy_user(Entry &entry, const bool tree_user)
201   {
202     std::lock_guard<std::mutex> lock(mutex);
203     if (tree_user) {
204       entry.num_tree_users++;
205     }
206     else {
207       entry.num_metadata_users++;
208     }
209   }
210 
remove_userVolumeFileCache211   void remove_user(Entry &entry, const bool tree_user)
212   {
213     std::lock_guard<std::mutex> lock(mutex);
214     if (tree_user) {
215       entry.num_tree_users--;
216     }
217     else {
218       entry.num_metadata_users--;
219     }
220     update_for_remove_user(entry);
221   }
222 
change_to_tree_userVolumeFileCache223   void change_to_tree_user(Entry &entry)
224   {
225     std::lock_guard<std::mutex> lock(mutex);
226     entry.num_tree_users++;
227     entry.num_metadata_users--;
228     update_for_remove_user(entry);
229   }
230 
change_to_metadata_userVolumeFileCache231   void change_to_metadata_user(Entry &entry)
232   {
233     std::lock_guard<std::mutex> lock(mutex);
234     entry.num_metadata_users++;
235     entry.num_tree_users--;
236     update_for_remove_user(entry);
237   }
238 
239  protected:
update_for_remove_userVolumeFileCache240   void update_for_remove_user(Entry &entry)
241   {
242     if (entry.num_metadata_users + entry.num_tree_users == 0) {
243       cache.erase(entry);
244     }
245     else if (entry.num_tree_users == 0) {
246       /* Note we replace the grid rather than clearing, so that if there is
247        * any other shared pointer to the grid it will keep the tree. */
248       entry.grid = entry.grid->copyGridWithNewTree();
249       entry.simplified_grids.clear();
250       entry.is_loaded = false;
251     }
252   }
253 
254   /* Cache contents */
255   typedef std::unordered_set<Entry, EntryHasher, EntryEqual> EntrySet;
256   EntrySet cache;
257   /* Mutex for multithreaded access. */
258   std::mutex mutex;
259 } GLOBAL_CACHE;
260 
261 /* VolumeGrid
262  *
263  * Wrapper around OpenVDB grid. Grids loaded from OpenVDB files are always
264  * stored in the global cache. Procedurally generated grids are not. */
265 
266 struct VolumeGrid {
VolumeGridVolumeGrid267   VolumeGrid(const VolumeFileCache::Entry &template_entry, const int simplify_level)
268       : entry(NULL), simplify_level(simplify_level), is_loaded(false)
269   {
270     entry = GLOBAL_CACHE.add_metadata_user(template_entry);
271   }
272 
VolumeGridVolumeGrid273   VolumeGrid(const openvdb::GridBase::Ptr &grid) : entry(NULL), local_grid(grid), is_loaded(true)
274   {
275   }
276 
VolumeGridVolumeGrid277   VolumeGrid(const VolumeGrid &other)
278       : entry(other.entry),
279         simplify_level(other.simplify_level),
280         local_grid(other.local_grid),
281         is_loaded(other.is_loaded)
282   {
283     if (entry) {
284       GLOBAL_CACHE.copy_user(*entry, is_loaded);
285     }
286   }
287 
~VolumeGridVolumeGrid288   ~VolumeGrid()
289   {
290     if (entry) {
291       GLOBAL_CACHE.remove_user(*entry, is_loaded);
292     }
293   }
294 
loadVolumeGrid295   void load(const char *volume_name, const char *filepath)
296   {
297     /* If already loaded or not file-backed, nothing to do. */
298     if (is_loaded || entry == NULL) {
299       return;
300     }
301 
302     /* Double-checked lock. */
303     std::lock_guard<std::mutex> lock(entry->mutex);
304     if (is_loaded) {
305       return;
306     }
307 
308     /* Change metadata user to tree user. */
309     GLOBAL_CACHE.change_to_tree_user(*entry);
310 
311     /* If already loaded by another user, nothing further to do. */
312     if (entry->is_loaded) {
313       is_loaded = true;
314       return;
315     }
316 
317     /* Load grid from file. */
318     CLOG_INFO(&LOG, 1, "Volume %s: load grid '%s'", volume_name, name());
319 
320     openvdb::io::File file(filepath);
321 
322     try {
323       file.setCopyMaxBytes(0);
324       file.open();
325       openvdb::GridBase::Ptr vdb_grid = file.readGrid(name());
326       entry->grid->setTree(vdb_grid->baseTreePtr());
327     }
328     catch (const openvdb::IoError &e) {
329       entry->error_msg = e.what();
330     }
331 
332     std::atomic_thread_fence(std::memory_order_release);
333     entry->is_loaded = true;
334     is_loaded = true;
335   }
336 
unloadVolumeGrid337   void unload(const char *volume_name)
338   {
339     /* Not loaded or not file-backed, nothing to do. */
340     if (!is_loaded || entry == NULL) {
341       return;
342     }
343 
344     /* Double-checked lock. */
345     std::lock_guard<std::mutex> lock(entry->mutex);
346     if (!is_loaded) {
347       return;
348     }
349 
350     CLOG_INFO(&LOG, 1, "Volume %s: unload grid '%s'", volume_name, name());
351 
352     /* Change tree user to metadata user. */
353     GLOBAL_CACHE.change_to_metadata_user(*entry);
354 
355     /* Indicate we no longer have a tree. The actual grid may still
356      * have it due to another user. */
357     std::atomic_thread_fence(std::memory_order_release);
358     is_loaded = false;
359   }
360 
clear_referenceVolumeGrid361   void clear_reference(const char *UNUSED(volume_name))
362   {
363     /* Clear any reference to a grid in the file cache. */
364     local_grid = grid()->copyGridWithNewTree();
365     if (entry) {
366       GLOBAL_CACHE.remove_user(*entry, is_loaded);
367       entry = NULL;
368     }
369     is_loaded = true;
370   }
371 
duplicate_referenceVolumeGrid372   void duplicate_reference(const char *volume_name, const char *filepath)
373   {
374     /* Make a deep copy of the grid and remove any reference to a grid in the
375      * file cache. Load file grid into memory first if needed. */
376     load(volume_name, filepath);
377     /* TODO: avoid deep copy if we are the only user. */
378     local_grid = grid()->deepCopyGrid();
379     if (entry) {
380       GLOBAL_CACHE.remove_user(*entry, is_loaded);
381       entry = NULL;
382     }
383     is_loaded = true;
384   }
385 
nameVolumeGrid386   const char *name() const
387   {
388     /* Don't use vdb.getName() since it copies the string, we want a pointer to the
389      * original so it doesn't get freed out of scope. */
390     openvdb::StringMetadata::ConstPtr name_meta =
391         main_grid()->getMetadata<openvdb::StringMetadata>(openvdb::GridBase::META_GRID_NAME);
392     return (name_meta) ? name_meta->value().c_str() : "";
393   }
394 
error_messageVolumeGrid395   const char *error_message() const
396   {
397     if (is_loaded && entry && !entry->error_msg.empty()) {
398       return entry->error_msg.c_str();
399     }
400 
401     return NULL;
402   }
403 
grid_is_loadedVolumeGrid404   bool grid_is_loaded() const
405   {
406     return is_loaded;
407   }
408 
gridVolumeGrid409   openvdb::GridBase::Ptr grid() const
410   {
411     if (entry) {
412       return entry->simplified_grid(simplify_level);
413     }
414     return local_grid;
415   }
416 
set_simplify_levelVolumeGrid417   void set_simplify_level(const int simplify_level)
418   {
419     BLI_assert(simplify_level >= 0);
420     this->simplify_level = simplify_level;
421   }
422 
423  private:
main_gridVolumeGrid424   const openvdb::GridBase::Ptr &main_grid() const
425   {
426     return (entry) ? entry->grid : local_grid;
427   }
428 
429  protected:
430   /* File cache entry when grid comes directly from a file and may be shared
431    * with other volume datablocks. */
432   VolumeFileCache::Entry *entry;
433   /* If this volume grid is in the global file cache, we can reference a simplified version of it,
434    * instead of the original high resolution grid. */
435   int simplify_level = 0;
436   /* OpenVDB grid if it's not shared through the file cache. */
437   openvdb::GridBase::Ptr local_grid;
438   /* Indicates if the tree has been loaded for this grid. Note that vdb.tree()
439    * may actually be loaded by another user while this is false. But only after
440    * calling load() and is_loaded changes to true is it safe to access. */
441   bool is_loaded;
442 };
443 
444 /* Volume Grid Vector
445  *
446  * List of grids contained in a volume datablock. This is runtime-only data,
447  * the actual grids are always saved in a VDB file. */
448 
449 struct VolumeGridVector : public std::list<VolumeGrid> {
VolumeGridVectorVolumeGridVector450   VolumeGridVector() : metadata(new openvdb::MetaMap())
451   {
452     filepath[0] = '\0';
453   }
454 
VolumeGridVectorVolumeGridVector455   VolumeGridVector(const VolumeGridVector &other)
456       : std::list<VolumeGrid>(other), error_msg(other.error_msg), metadata(other.metadata)
457   {
458     memcpy(filepath, other.filepath, sizeof(filepath));
459   }
460 
is_loadedVolumeGridVector461   bool is_loaded() const
462   {
463     return filepath[0] != '\0';
464   }
465 
clear_allVolumeGridVector466   void clear_all()
467   {
468     std::list<VolumeGrid>::clear();
469     filepath[0] = '\0';
470     error_msg.clear();
471     metadata.reset();
472   }
473 
474   /* Absolute file path that grids have been loaded from. */
475   char filepath[FILE_MAX];
476   /* File loading error message. */
477   std::string error_msg;
478   /* File Metadata. */
479   openvdb::MetaMap::Ptr metadata;
480   /* Mutex for file loading of grids list. */
481   std::mutex mutex;
482 };
483 #endif
484 
485 /* Module */
486 
BKE_volumes_init()487 void BKE_volumes_init()
488 {
489 #ifdef WITH_OPENVDB
490   openvdb::initialize();
491 #endif
492 }
493 
494 /* Volume datablock */
495 
volume_init_data(ID * id)496 static void volume_init_data(ID *id)
497 {
498   Volume *volume = (Volume *)id;
499   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(volume, id));
500 
501   MEMCPY_STRUCT_AFTER(volume, DNA_struct_default_get(Volume), id);
502 
503   BKE_volume_init_grids(volume);
504 }
505 
volume_copy_data(Main * UNUSED (bmain),ID * id_dst,const ID * id_src,const int UNUSED (flag))506 static void volume_copy_data(Main *UNUSED(bmain),
507                              ID *id_dst,
508                              const ID *id_src,
509                              const int UNUSED(flag))
510 {
511   Volume *volume_dst = (Volume *)id_dst;
512   const Volume *volume_src = (const Volume *)id_src;
513 
514   if (volume_src->packedfile) {
515     volume_dst->packedfile = BKE_packedfile_duplicate(volume_src->packedfile);
516   }
517 
518   volume_dst->mat = (Material **)MEM_dupallocN(volume_src->mat);
519 #ifdef WITH_OPENVDB
520   if (volume_src->runtime.grids) {
521     const VolumeGridVector &grids_src = *(volume_src->runtime.grids);
522     volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
523   }
524 #endif
525 }
526 
volume_free_data(ID * id)527 static void volume_free_data(ID *id)
528 {
529   Volume *volume = (Volume *)id;
530   BKE_animdata_free(&volume->id, false);
531   BKE_volume_batch_cache_free(volume);
532   MEM_SAFE_FREE(volume->mat);
533 #ifdef WITH_OPENVDB
534   OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector);
535 #endif
536 }
537 
volume_foreach_id(ID * id,LibraryForeachIDData * data)538 static void volume_foreach_id(ID *id, LibraryForeachIDData *data)
539 {
540   Volume *volume = (Volume *)id;
541   for (int i = 0; i < volume->totcol; i++) {
542     BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER);
543   }
544 }
545 
volume_foreach_cache(ID * id,IDTypeForeachCacheFunctionCallback function_callback,void * user_data)546 static void volume_foreach_cache(ID *id,
547                                  IDTypeForeachCacheFunctionCallback function_callback,
548                                  void *user_data)
549 {
550   Volume *volume = (Volume *)id;
551   IDCacheKey key = {
552       /* id_session_uuid */ id->session_uuid,
553       /*offset_in_ID*/ offsetof(Volume, runtime.grids),
554       /* cache_v */ volume->runtime.grids,
555   };
556 
557   function_callback(id, &key, (void **)&volume->runtime.grids, 0, user_data);
558 }
559 
volume_blend_write(BlendWriter * writer,ID * id,const void * id_address)560 static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address)
561 {
562   Volume *volume = (Volume *)id;
563   if (volume->id.us > 0 || BLO_write_is_undo(writer)) {
564     /* Clean up, important in undo case to reduce false detection of changed datablocks. */
565     volume->runtime.grids = 0;
566 
567     /* write LibData */
568     BLO_write_id_struct(writer, Volume, id_address, &volume->id);
569     BKE_id_blend_write(writer, &volume->id);
570 
571     /* direct data */
572     BLO_write_pointer_array(writer, volume->totcol, volume->mat);
573     if (volume->adt) {
574       BKE_animdata_blend_write(writer, volume->adt);
575     }
576 
577     BKE_packedfile_blend_write(writer, volume->packedfile);
578   }
579 }
580 
volume_blend_read_data(BlendDataReader * reader,ID * id)581 static void volume_blend_read_data(BlendDataReader *reader, ID *id)
582 {
583   Volume *volume = (Volume *)id;
584   BLO_read_data_address(reader, &volume->adt);
585   BKE_animdata_blend_read_data(reader, volume->adt);
586 
587   BKE_packedfile_blend_read(reader, &volume->packedfile);
588   volume->runtime.frame = 0;
589 
590   /* materials */
591   BLO_read_pointer_array(reader, (void **)&volume->mat);
592 }
593 
volume_blend_read_lib(BlendLibReader * reader,ID * id)594 static void volume_blend_read_lib(BlendLibReader *reader, ID *id)
595 {
596   Volume *volume = (Volume *)id;
597   /* Needs to be done *after* cache pointers are restored (call to
598    * `foreach_cache`/`blo_cache_storage_entry_restore_in_new`), easier for now to do it in
599    * lib_link... */
600   BKE_volume_init_grids(volume);
601 
602   for (int a = 0; a < volume->totcol; a++) {
603     BLO_read_id_address(reader, volume->id.lib, &volume->mat[a]);
604   }
605 }
606 
volume_blend_read_expand(BlendExpander * expander,ID * id)607 static void volume_blend_read_expand(BlendExpander *expander, ID *id)
608 {
609   Volume *volume = (Volume *)id;
610   for (int a = 0; a < volume->totcol; a++) {
611     BLO_expand(expander, volume->mat[a]);
612   }
613 }
614 
615 IDTypeInfo IDType_ID_VO = {
616     /* id_code */ ID_VO,
617     /* id_filter */ FILTER_ID_VO,
618     /* main_listbase_index */ INDEX_ID_VO,
619     /* struct_size */ sizeof(Volume),
620     /* name */ "Volume",
621     /* name_plural */ "volumes",
622     /* translation_context */ BLT_I18NCONTEXT_ID_VOLUME,
623     /* flags */ 0,
624 
625     /* init_data */ volume_init_data,
626     /* copy_data */ volume_copy_data,
627     /* free_data */ volume_free_data,
628     /* make_local */ nullptr,
629     /* foreach_id */ volume_foreach_id,
630     /* foreach_cache */ volume_foreach_cache,
631 
632     /* blend_write */ volume_blend_write,
633     /* blend_read_data */ volume_blend_read_data,
634     /* blend_read_lib */ volume_blend_read_lib,
635     /* blend_read_expand */ volume_blend_read_expand,
636 };
637 
BKE_volume_init_grids(Volume * volume)638 void BKE_volume_init_grids(Volume *volume)
639 {
640 #ifdef WITH_OPENVDB
641   if (volume->runtime.grids == NULL) {
642     volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
643   }
644 #else
645   UNUSED_VARS(volume);
646 #endif
647 }
648 
BKE_volume_add(Main * bmain,const char * name)649 void *BKE_volume_add(Main *bmain, const char *name)
650 {
651   Volume *volume = (Volume *)BKE_id_new(bmain, ID_VO, name);
652 
653   return volume;
654 }
655 
656 /* Sequence */
657 
volume_sequence_frame(const Depsgraph * depsgraph,const Volume * volume)658 static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volume)
659 {
660   if (!volume->is_sequence) {
661     return 0;
662   }
663 
664   char filepath[FILE_MAX];
665   STRNCPY(filepath, volume->filepath);
666   int path_frame, path_digits;
667   if (!(volume->is_sequence && BLI_path_frame_get(filepath, &path_frame, &path_digits))) {
668     return 0;
669   }
670 
671   const int scene_frame = DEG_get_ctime(depsgraph);
672   const VolumeSequenceMode mode = (VolumeSequenceMode)volume->sequence_mode;
673   const int frame_duration = volume->frame_duration;
674   const int frame_start = volume->frame_start;
675   const int frame_offset = volume->frame_offset;
676 
677   if (frame_duration == 0) {
678     return VOLUME_FRAME_NONE;
679   }
680 
681   int frame = scene_frame - frame_start + 1;
682 
683   switch (mode) {
684     case VOLUME_SEQUENCE_CLIP: {
685       if (frame < 1 || frame > frame_duration) {
686         return VOLUME_FRAME_NONE;
687       }
688       break;
689     }
690     case VOLUME_SEQUENCE_EXTEND: {
691       frame = clamp_i(frame, 1, frame_duration);
692       break;
693     }
694     case VOLUME_SEQUENCE_REPEAT: {
695       frame = frame % frame_duration;
696       if (frame < 0) {
697         frame += frame_duration;
698       }
699       if (frame == 0) {
700         frame = frame_duration;
701       }
702       break;
703     }
704     case VOLUME_SEQUENCE_PING_PONG: {
705       const int pingpong_duration = frame_duration * 2 - 2;
706       frame = frame % pingpong_duration;
707       if (frame < 0) {
708         frame += pingpong_duration;
709       }
710       if (frame == 0) {
711         frame = pingpong_duration;
712       }
713       if (frame > frame_duration) {
714         frame = frame_duration * 2 - frame;
715       }
716       break;
717     }
718   }
719 
720   /* Important to apply after, else we cant loop on e.g. frames 100 - 110. */
721   frame += frame_offset;
722 
723   return frame;
724 }
725 
726 #ifdef WITH_OPENVDB
volume_filepath_get(const Main * bmain,const Volume * volume,char r_filepath[FILE_MAX])727 static void volume_filepath_get(const Main *bmain, const Volume *volume, char r_filepath[FILE_MAX])
728 {
729   BLI_strncpy(r_filepath, volume->filepath, FILE_MAX);
730   BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &volume->id));
731 
732   int path_frame, path_digits;
733   if (volume->is_sequence && BLI_path_frame_get(r_filepath, &path_frame, &path_digits)) {
734     char ext[32];
735     BLI_path_frame_strip(r_filepath, ext);
736     BLI_path_frame(r_filepath, volume->runtime.frame, path_digits);
737     BLI_path_extension_ensure(r_filepath, FILE_MAX, ext);
738   }
739 }
740 #endif
741 
742 /* File Load */
743 
BKE_volume_is_loaded(const Volume * volume)744 bool BKE_volume_is_loaded(const Volume *volume)
745 {
746 #ifdef WITH_OPENVDB
747   /* Test if there is a file to load, or if already loaded. */
748   return (volume->filepath[0] == '\0' || volume->runtime.grids->is_loaded());
749 #else
750   UNUSED_VARS(volume);
751   return true;
752 #endif
753 }
754 
BKE_volume_load(Volume * volume,Main * bmain)755 bool BKE_volume_load(Volume *volume, Main *bmain)
756 {
757 #ifdef WITH_OPENVDB
758   VolumeGridVector &grids = *volume->runtime.grids;
759 
760   if (volume->runtime.frame == VOLUME_FRAME_NONE) {
761     /* Skip loading this frame, outside of sequence range. */
762     return true;
763   }
764 
765   if (BKE_volume_is_loaded(volume)) {
766     return grids.error_msg.empty();
767   }
768 
769   /* Double-checked lock. */
770   std::lock_guard<std::mutex> lock(grids.mutex);
771   if (BKE_volume_is_loaded(volume)) {
772     return grids.error_msg.empty();
773   }
774 
775   /* Get absolute file path at current frame. */
776   const char *volume_name = volume->id.name + 2;
777   volume_filepath_get(bmain, volume, grids.filepath);
778 
779   CLOG_INFO(&LOG, 1, "Volume %s: load %s", volume_name, grids.filepath);
780 
781   /* Test if file exists. */
782   if (!BLI_exists(grids.filepath)) {
783     char filename[FILE_MAX];
784     BLI_split_file_part(grids.filepath, filename, sizeof(filename));
785     grids.error_msg = filename + std::string(" not found");
786     CLOG_INFO(&LOG, 1, "Volume %s: %s", volume_name, grids.error_msg.c_str());
787     return false;
788   }
789 
790   /* Open OpenVDB file. */
791   openvdb::io::File file(grids.filepath);
792   openvdb::GridPtrVec vdb_grids;
793 
794   try {
795     file.setCopyMaxBytes(0);
796     file.open();
797     vdb_grids = *(file.readAllGridMetadata());
798     grids.metadata = file.getMetadata();
799   }
800   catch (const openvdb::IoError &e) {
801     grids.error_msg = e.what();
802     CLOG_INFO(&LOG, 1, "Volume %s: %s", volume_name, grids.error_msg.c_str());
803   }
804 
805   /* Add grids read from file to own vector, filtering out any NULL pointers. */
806   for (const openvdb::GridBase::Ptr &vdb_grid : vdb_grids) {
807     if (vdb_grid) {
808       VolumeFileCache::Entry template_entry(grids.filepath, vdb_grid);
809       grids.emplace_back(template_entry, volume->runtime.default_simplify_level);
810     }
811   }
812 
813   return grids.error_msg.empty();
814 #else
815   UNUSED_VARS(bmain, volume);
816   return true;
817 #endif
818 }
819 
BKE_volume_unload(Volume * volume)820 void BKE_volume_unload(Volume *volume)
821 {
822 #ifdef WITH_OPENVDB
823   VolumeGridVector &grids = *volume->runtime.grids;
824   if (grids.filepath[0] != '\0') {
825     const char *volume_name = volume->id.name + 2;
826     CLOG_INFO(&LOG, 1, "Volume %s: unload", volume_name);
827     grids.clear_all();
828   }
829 #else
830   UNUSED_VARS(volume);
831 #endif
832 }
833 
834 /* File Save */
835 
BKE_volume_save(Volume * volume,Main * bmain,ReportList * reports,const char * filepath)836 bool BKE_volume_save(Volume *volume, Main *bmain, ReportList *reports, const char *filepath)
837 {
838 #ifdef WITH_OPENVDB
839   if (!BKE_volume_load(volume, bmain)) {
840     BKE_reportf(reports, RPT_ERROR, "Could not load volume for writing");
841     return false;
842   }
843 
844   VolumeGridVector &grids = *volume->runtime.grids;
845   openvdb::GridCPtrVec vdb_grids;
846 
847   for (VolumeGrid &grid : grids) {
848     vdb_grids.push_back(BKE_volume_grid_openvdb_for_read(volume, &grid));
849   }
850 
851   try {
852     openvdb::io::File file(filepath);
853     file.write(vdb_grids, *grids.metadata);
854     file.close();
855   }
856   catch (const openvdb::IoError &e) {
857     BKE_reportf(reports, RPT_ERROR, "Could not write volume: %s", e.what());
858     return false;
859   }
860 
861   return true;
862 #else
863   UNUSED_VARS(volume, bmain, reports, filepath);
864   return false;
865 #endif
866 }
867 
BKE_volume_boundbox_get(Object * ob)868 BoundBox *BKE_volume_boundbox_get(Object *ob)
869 {
870   BLI_assert(ob->type == OB_VOLUME);
871 
872   if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
873     return ob->runtime.bb;
874   }
875 
876   if (ob->runtime.bb == NULL) {
877     Volume *volume = (Volume *)ob->data;
878 
879     ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "volume boundbox");
880 
881     float min[3], max[3];
882     bool have_minmax = false;
883     INIT_MINMAX(min, max);
884 
885     /* TODO: if we know the volume is going to be displayed, it may be good to
886      * load it as part of dependency graph evaluation for better threading. We
887      * could also share the bounding box computation in the global volume cache. */
888     if (BKE_volume_load(volume, G.main)) {
889       const int num_grids = BKE_volume_num_grids(volume);
890 
891       for (int i = 0; i < num_grids; i++) {
892         VolumeGrid *grid = BKE_volume_grid_get(volume, i);
893         float grid_min[3], grid_max[3];
894 
895         BKE_volume_grid_load(volume, grid);
896         if (BKE_volume_grid_bounds(grid, grid_min, grid_max)) {
897           DO_MIN(grid_min, min);
898           DO_MAX(grid_max, max);
899           have_minmax = true;
900         }
901       }
902     }
903 
904     if (!have_minmax) {
905       min[0] = min[1] = min[2] = -1.0f;
906       max[0] = max[1] = max[2] = 1.0f;
907     }
908 
909     BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
910   }
911 
912   return ob->runtime.bb;
913 }
914 
BKE_volume_is_y_up(const Volume * volume)915 bool BKE_volume_is_y_up(const Volume *volume)
916 {
917   /* Simple heuristic for common files to open the right way up. */
918 #ifdef WITH_OPENVDB
919   VolumeGridVector &grids = *volume->runtime.grids;
920   if (grids.metadata) {
921     openvdb::StringMetadata::ConstPtr creator =
922         grids.metadata->getMetadata<openvdb::StringMetadata>("creator");
923     if (!creator) {
924       creator = grids.metadata->getMetadata<openvdb::StringMetadata>("Creator");
925     }
926     return (creator && creator->str().rfind("Houdini", 0) == 0);
927   }
928 #else
929   UNUSED_VARS(volume);
930 #endif
931 
932   return false;
933 }
934 
BKE_volume_is_points_only(const Volume * volume)935 bool BKE_volume_is_points_only(const Volume *volume)
936 {
937   int num_grids = BKE_volume_num_grids(volume);
938   if (num_grids == 0) {
939     return false;
940   }
941 
942   for (int i = 0; i < num_grids; i++) {
943     VolumeGrid *grid = BKE_volume_grid_get(volume, i);
944     if (BKE_volume_grid_type(grid) != VOLUME_GRID_POINTS) {
945       return false;
946     }
947   }
948 
949   return true;
950 }
951 
952 /* Dependency Graph */
953 
volume_update_simplify_level(Volume * volume,const Depsgraph * depsgraph)954 static void volume_update_simplify_level(Volume *volume, const Depsgraph *depsgraph)
955 {
956 #ifdef WITH_OPENVDB
957   const int simplify_level = BKE_volume_simplify_level(depsgraph);
958   if (volume->runtime.grids) {
959     for (VolumeGrid &grid : *volume->runtime.grids) {
960       grid.set_simplify_level(simplify_level);
961     }
962   }
963   volume->runtime.default_simplify_level = simplify_level;
964 #else
965   UNUSED_VARS(volume, depsgraph);
966 #endif
967 }
968 
volume_evaluate_modifiers(struct Depsgraph * depsgraph,struct Scene * scene,Object * object,Volume * volume_input)969 static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
970                                          struct Scene *scene,
971                                          Object *object,
972                                          Volume *volume_input)
973 {
974   Volume *volume = volume_input;
975 
976   /* Modifier evaluation modes. */
977   const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
978   const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
979   ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
980   const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
981 
982   /* Get effective list of modifiers to execute. Some effects like shape keys
983    * are added as virtual modifiers before the user created modifiers. */
984   VirtualModifierData virtualModifierData;
985   ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
986 
987   /* Evaluate modifiers. */
988   for (; md; md = md->next) {
989     const ModifierTypeInfo *mti = (const ModifierTypeInfo *)BKE_modifier_get_info(
990         (ModifierType)md->type);
991 
992     if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
993       continue;
994     }
995 
996     if (mti->modifyVolume) {
997       /* Ensure we are not modifying the input. */
998       if (volume == volume_input) {
999         volume = BKE_volume_copy_for_eval(volume, true);
1000       }
1001 
1002       Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
1003 
1004       if (volume_next && volume_next != volume) {
1005         /* If the modifier returned a new volume, release the old one. */
1006         if (volume != volume_input) {
1007           BKE_id_free(NULL, volume);
1008         }
1009         volume = volume_next;
1010       }
1011     }
1012   }
1013 
1014   return volume;
1015 }
1016 
BKE_volume_eval_geometry(struct Depsgraph * depsgraph,Volume * volume)1017 void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
1018 {
1019   volume_update_simplify_level(volume, depsgraph);
1020 
1021   /* TODO: can we avoid modifier re-evaluation when frame did not change? */
1022   int frame = volume_sequence_frame(depsgraph, volume);
1023   if (frame != volume->runtime.frame) {
1024     BKE_volume_unload(volume);
1025     volume->runtime.frame = frame;
1026   }
1027 
1028   /* Flush back to original. */
1029   if (DEG_is_active(depsgraph)) {
1030     Volume *volume_orig = (Volume *)DEG_get_original_id(&volume->id);
1031     if (volume_orig->runtime.frame != volume->runtime.frame) {
1032       BKE_volume_unload(volume_orig);
1033       volume_orig->runtime.frame = volume->runtime.frame;
1034     }
1035   }
1036 }
1037 
BKE_volume_data_update(struct Depsgraph * depsgraph,struct Scene * scene,Object * object)1038 void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
1039 {
1040   /* Free any evaluated data and restore original data. */
1041   BKE_object_free_derived_caches(object);
1042 
1043   /* Evaluate modifiers. */
1044   Volume *volume = (Volume *)object->data;
1045   Volume *volume_eval = volume_evaluate_modifiers(depsgraph, scene, object, volume);
1046 
1047   /* Assign evaluated object. */
1048   const bool is_owned = (volume != volume_eval);
1049   BKE_object_eval_assign_data(object, &volume_eval->id, is_owned);
1050 }
1051 
BKE_volume_grids_backup_restore(Volume * volume,VolumeGridVector * grids,const char * filepath)1052 void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, const char *filepath)
1053 {
1054 #ifdef WITH_OPENVDB
1055   /* Restore grids after datablock was re-copied from original by depsgraph,
1056    * we don't want to load them again if possible. */
1057   BLI_assert(volume->id.tag & LIB_TAG_COPIED_ON_WRITE);
1058   BLI_assert(volume->runtime.grids != NULL && grids != NULL);
1059 
1060   if (!grids->is_loaded()) {
1061     /* No grids loaded in CoW datablock, nothing lost by discarding. */
1062     OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
1063   }
1064   else if (!STREQ(volume->filepath, filepath)) {
1065     /* Filepath changed, discard grids from CoW datablock. */
1066     OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
1067   }
1068   else {
1069     /* Keep grids from CoW datablock. We might still unload them a little
1070      * later in BKE_volume_eval_geometry if the frame changes. */
1071     OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector);
1072     volume->runtime.grids = grids;
1073   }
1074 #else
1075   UNUSED_VARS(volume, grids, filepath);
1076 #endif
1077 }
1078 
1079 /* Draw Cache */
1080 
1081 void (*BKE_volume_batch_cache_dirty_tag_cb)(Volume *volume, int mode) = NULL;
1082 void (*BKE_volume_batch_cache_free_cb)(Volume *volume) = NULL;
1083 
BKE_volume_batch_cache_dirty_tag(Volume * volume,int mode)1084 void BKE_volume_batch_cache_dirty_tag(Volume *volume, int mode)
1085 {
1086   if (volume->batch_cache) {
1087     BKE_volume_batch_cache_dirty_tag_cb(volume, mode);
1088   }
1089 }
1090 
BKE_volume_batch_cache_free(Volume * volume)1091 void BKE_volume_batch_cache_free(Volume *volume)
1092 {
1093   if (volume->batch_cache) {
1094     BKE_volume_batch_cache_free_cb(volume);
1095   }
1096 }
1097 
1098 /* Grids */
1099 
BKE_volume_num_grids(const Volume * volume)1100 int BKE_volume_num_grids(const Volume *volume)
1101 {
1102 #ifdef WITH_OPENVDB
1103   return volume->runtime.grids->size();
1104 #else
1105   UNUSED_VARS(volume);
1106   return 0;
1107 #endif
1108 }
1109 
BKE_volume_grids_error_msg(const Volume * volume)1110 const char *BKE_volume_grids_error_msg(const Volume *volume)
1111 {
1112 #ifdef WITH_OPENVDB
1113   return volume->runtime.grids->error_msg.c_str();
1114 #else
1115   UNUSED_VARS(volume);
1116   return "";
1117 #endif
1118 }
1119 
BKE_volume_grids_frame_filepath(const Volume * volume)1120 const char *BKE_volume_grids_frame_filepath(const Volume *volume)
1121 {
1122 #ifdef WITH_OPENVDB
1123   return volume->runtime.grids->filepath;
1124 #else
1125   UNUSED_VARS(volume);
1126   return "";
1127 #endif
1128 }
1129 
BKE_volume_grid_get(const Volume * volume,int grid_index)1130 VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
1131 {
1132 #ifdef WITH_OPENVDB
1133   VolumeGridVector &grids = *volume->runtime.grids;
1134   for (VolumeGrid &grid : grids) {
1135     if (grid_index-- == 0) {
1136       return &grid;
1137     }
1138   }
1139   return NULL;
1140 #else
1141   UNUSED_VARS(volume, grid_index);
1142   return NULL;
1143 #endif
1144 }
1145 
BKE_volume_grid_active_get(const Volume * volume)1146 VolumeGrid *BKE_volume_grid_active_get(const Volume *volume)
1147 {
1148   const int num_grids = BKE_volume_num_grids(volume);
1149   if (num_grids == 0) {
1150     return NULL;
1151   }
1152 
1153   const int index = clamp_i(volume->active_grid, 0, num_grids - 1);
1154   return BKE_volume_grid_get(volume, index);
1155 }
1156 
1157 /* Tries to find a grid with the given name. Make sure that that the volume has been loaded. */
BKE_volume_grid_find(const Volume * volume,const char * name)1158 VolumeGrid *BKE_volume_grid_find(const Volume *volume, const char *name)
1159 {
1160   int num_grids = BKE_volume_num_grids(volume);
1161   for (int i = 0; i < num_grids; i++) {
1162     VolumeGrid *grid = BKE_volume_grid_get(volume, i);
1163     if (STREQ(BKE_volume_grid_name(grid), name)) {
1164       return grid;
1165     }
1166   }
1167 
1168   return NULL;
1169 }
1170 
1171 /* Grid Loading */
1172 
BKE_volume_grid_load(const Volume * volume,VolumeGrid * grid)1173 bool BKE_volume_grid_load(const Volume *volume, VolumeGrid *grid)
1174 {
1175 #ifdef WITH_OPENVDB
1176   VolumeGridVector &grids = *volume->runtime.grids;
1177   const char *volume_name = volume->id.name + 2;
1178   grid->load(volume_name, grids.filepath);
1179   const char *error_msg = grid->error_message();
1180   if (error_msg) {
1181     grids.error_msg = error_msg;
1182     return false;
1183   }
1184   return true;
1185 #else
1186   UNUSED_VARS(volume, grid);
1187   return true;
1188 #endif
1189 }
1190 
BKE_volume_grid_unload(const Volume * volume,VolumeGrid * grid)1191 void BKE_volume_grid_unload(const Volume *volume, VolumeGrid *grid)
1192 {
1193 #ifdef WITH_OPENVDB
1194   const char *volume_name = volume->id.name + 2;
1195   grid->unload(volume_name);
1196 #else
1197   UNUSED_VARS(volume, grid);
1198 #endif
1199 }
1200 
BKE_volume_grid_is_loaded(const VolumeGrid * grid)1201 bool BKE_volume_grid_is_loaded(const VolumeGrid *grid)
1202 {
1203 #ifdef WITH_OPENVDB
1204   return grid->grid_is_loaded();
1205 #else
1206   UNUSED_VARS(grid);
1207   return true;
1208 #endif
1209 }
1210 
1211 /* Grid Metadata */
1212 
BKE_volume_grid_name(const VolumeGrid * volume_grid)1213 const char *BKE_volume_grid_name(const VolumeGrid *volume_grid)
1214 {
1215 #ifdef WITH_OPENVDB
1216   return volume_grid->name();
1217 #else
1218   UNUSED_VARS(volume_grid);
1219   return "density";
1220 #endif
1221 }
1222 
1223 #ifdef WITH_OPENVDB
BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr & grid)1224 VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase::Ptr &grid)
1225 {
1226   if (grid->isType<openvdb::FloatGrid>()) {
1227     return VOLUME_GRID_FLOAT;
1228   }
1229   if (grid->isType<openvdb::Vec3fGrid>()) {
1230     return VOLUME_GRID_VECTOR_FLOAT;
1231   }
1232   if (grid->isType<openvdb::BoolGrid>()) {
1233     return VOLUME_GRID_BOOLEAN;
1234   }
1235   if (grid->isType<openvdb::DoubleGrid>()) {
1236     return VOLUME_GRID_DOUBLE;
1237   }
1238   if (grid->isType<openvdb::Int32Grid>()) {
1239     return VOLUME_GRID_INT;
1240   }
1241   if (grid->isType<openvdb::Int64Grid>()) {
1242     return VOLUME_GRID_INT64;
1243   }
1244   if (grid->isType<openvdb::Vec3IGrid>()) {
1245     return VOLUME_GRID_VECTOR_INT;
1246   }
1247   if (grid->isType<openvdb::Vec3dGrid>()) {
1248     return VOLUME_GRID_VECTOR_DOUBLE;
1249   }
1250   if (grid->isType<openvdb::StringGrid>()) {
1251     return VOLUME_GRID_STRING;
1252   }
1253   if (grid->isType<openvdb::MaskGrid>()) {
1254     return VOLUME_GRID_MASK;
1255   }
1256   if (grid->isType<openvdb::points::PointDataGrid>()) {
1257     return VOLUME_GRID_POINTS;
1258   }
1259   return VOLUME_GRID_UNKNOWN;
1260 }
1261 #endif
1262 
BKE_volume_grid_type(const VolumeGrid * volume_grid)1263 VolumeGridType BKE_volume_grid_type(const VolumeGrid *volume_grid)
1264 {
1265 #ifdef WITH_OPENVDB
1266   const openvdb::GridBase::Ptr grid = volume_grid->grid();
1267   return BKE_volume_grid_type_openvdb(grid);
1268 #else
1269   UNUSED_VARS(volume_grid);
1270 #endif
1271   return VOLUME_GRID_UNKNOWN;
1272 }
1273 
BKE_volume_grid_channels(const VolumeGrid * grid)1274 int BKE_volume_grid_channels(const VolumeGrid *grid)
1275 {
1276   switch (BKE_volume_grid_type(grid)) {
1277     case VOLUME_GRID_BOOLEAN:
1278     case VOLUME_GRID_FLOAT:
1279     case VOLUME_GRID_DOUBLE:
1280     case VOLUME_GRID_INT:
1281     case VOLUME_GRID_INT64:
1282     case VOLUME_GRID_MASK:
1283       return 1;
1284     case VOLUME_GRID_VECTOR_FLOAT:
1285     case VOLUME_GRID_VECTOR_DOUBLE:
1286     case VOLUME_GRID_VECTOR_INT:
1287       return 3;
1288     case VOLUME_GRID_STRING:
1289     case VOLUME_GRID_POINTS:
1290     case VOLUME_GRID_UNKNOWN:
1291       return 0;
1292   }
1293 
1294   return 0;
1295 }
1296 
1297 /* Transformation from index space to object space. */
BKE_volume_grid_transform_matrix(const VolumeGrid * volume_grid,float mat[4][4])1298 void BKE_volume_grid_transform_matrix(const VolumeGrid *volume_grid, float mat[4][4])
1299 {
1300 #ifdef WITH_OPENVDB
1301   const openvdb::GridBase::Ptr grid = volume_grid->grid();
1302   const openvdb::math::Transform &transform = grid->transform();
1303 
1304   /* Perspective not supported for now, getAffineMap() will leave out the
1305    * perspective part of the transform. */
1306   openvdb::math::Mat4f matrix = transform.baseMap()->getAffineMap()->getMat4();
1307   /* Blender column-major and OpenVDB right-multiplication conventions match. */
1308   for (int col = 0; col < 4; col++) {
1309     for (int row = 0; row < 4; row++) {
1310       mat[col][row] = matrix(col, row);
1311     }
1312   }
1313 #else
1314   unit_m4(mat);
1315   UNUSED_VARS(volume_grid);
1316 #endif
1317 }
1318 
1319 /* Grid Tree and Voxels */
1320 
BKE_volume_grid_bounds(const VolumeGrid * volume_grid,float min[3],float max[3])1321 bool BKE_volume_grid_bounds(const VolumeGrid *volume_grid, float min[3], float max[3])
1322 {
1323 #ifdef WITH_OPENVDB
1324   /* TODO: we can get this from grid metadata in some cases? */
1325   const openvdb::GridBase::Ptr grid = volume_grid->grid();
1326   BLI_assert(BKE_volume_grid_is_loaded(volume_grid));
1327 
1328   openvdb::CoordBBox coordbbox;
1329   if (!grid->baseTree().evalLeafBoundingBox(coordbbox)) {
1330     INIT_MINMAX(min, max);
1331     return false;
1332   }
1333 
1334   openvdb::BBoxd bbox = grid->transform().indexToWorld(coordbbox);
1335   min[0] = (float)bbox.min().x();
1336   min[1] = (float)bbox.min().y();
1337   min[2] = (float)bbox.min().z();
1338   max[0] = (float)bbox.max().x();
1339   max[1] = (float)bbox.max().y();
1340   max[2] = (float)bbox.max().z();
1341   return true;
1342 #else
1343   UNUSED_VARS(volume_grid);
1344   INIT_MINMAX(min, max);
1345   return false;
1346 #endif
1347 }
1348 
1349 /* Volume Editing */
1350 
BKE_volume_new_for_eval(const Volume * volume_src)1351 Volume *BKE_volume_new_for_eval(const Volume *volume_src)
1352 {
1353   Volume *volume_dst = (Volume *)BKE_id_new_nomain(ID_VO, NULL);
1354 
1355   STRNCPY(volume_dst->id.name, volume_src->id.name);
1356   volume_dst->mat = (Material **)MEM_dupallocN(volume_src->mat);
1357   volume_dst->totcol = volume_src->totcol;
1358   volume_dst->render = volume_src->render;
1359   volume_dst->display = volume_src->display;
1360   BKE_volume_init_grids(volume_dst);
1361 
1362   return volume_dst;
1363 }
1364 
BKE_volume_copy_for_eval(Volume * volume_src,bool reference)1365 Volume *BKE_volume_copy_for_eval(Volume *volume_src, bool reference)
1366 {
1367   int flags = LIB_ID_COPY_LOCALIZE;
1368 
1369   if (reference) {
1370     flags |= LIB_ID_COPY_CD_REFERENCE;
1371   }
1372 
1373   Volume *result = (Volume *)BKE_id_copy_ex(NULL, &volume_src->id, NULL, flags);
1374 
1375   return result;
1376 }
1377 
1378 #ifdef WITH_OPENVDB
1379 struct CreateGridOp {
operator ()CreateGridOp1380   template<typename GridType> typename openvdb::GridBase::Ptr operator()()
1381   {
1382     if constexpr (std::is_same_v<GridType, openvdb::points::PointDataGrid>) {
1383       return {};
1384     }
1385     else {
1386       return GridType::create();
1387     }
1388   }
1389 };
1390 #endif
1391 
BKE_volume_grid_add(Volume * volume,const char * name,VolumeGridType type)1392 VolumeGrid *BKE_volume_grid_add(Volume *volume, const char *name, VolumeGridType type)
1393 {
1394 #ifdef WITH_OPENVDB
1395   VolumeGridVector &grids = *volume->runtime.grids;
1396   BLI_assert(BKE_volume_grid_find(volume, name) == NULL);
1397   BLI_assert(type != VOLUME_GRID_UNKNOWN);
1398 
1399   openvdb::GridBase::Ptr vdb_grid = BKE_volume_grid_type_operation(type, CreateGridOp{});
1400   if (!vdb_grid) {
1401     return NULL;
1402   }
1403 
1404   vdb_grid->setName(name);
1405   grids.emplace_back(vdb_grid);
1406   return &grids.back();
1407 #else
1408   UNUSED_VARS(volume, name, type);
1409   return NULL;
1410 #endif
1411 }
1412 
BKE_volume_grid_remove(Volume * volume,VolumeGrid * grid)1413 void BKE_volume_grid_remove(Volume *volume, VolumeGrid *grid)
1414 {
1415 #ifdef WITH_OPENVDB
1416   VolumeGridVector &grids = *volume->runtime.grids;
1417   for (VolumeGridVector::iterator it = grids.begin(); it != grids.end(); it++) {
1418     if (&*it == grid) {
1419       grids.erase(it);
1420       break;
1421     }
1422   }
1423 #else
1424   UNUSED_VARS(volume, grid);
1425 #endif
1426 }
1427 
BKE_volume_simplify_level(const Depsgraph * depsgraph)1428 int BKE_volume_simplify_level(const Depsgraph *depsgraph)
1429 {
1430   if (DEG_get_mode(depsgraph) != DAG_EVAL_RENDER) {
1431     const Scene *scene = DEG_get_input_scene(depsgraph);
1432     if (scene->r.mode & R_SIMPLIFY) {
1433       const float simplify = scene->r.simplify_volumes;
1434       if (simplify == 0.0f) {
1435         /* log2 is not defined at 0.0f, so just use some high simplify level. */
1436         return 16;
1437       }
1438       return ceilf(-log2(simplify));
1439     }
1440   }
1441   return 0;
1442 }
1443 
BKE_volume_simplify_factor(const Depsgraph * depsgraph)1444 float BKE_volume_simplify_factor(const Depsgraph *depsgraph)
1445 {
1446   if (DEG_get_mode(depsgraph) != DAG_EVAL_RENDER) {
1447     const Scene *scene = DEG_get_input_scene(depsgraph);
1448     if (scene->r.mode & R_SIMPLIFY) {
1449       return scene->r.simplify_volumes;
1450     }
1451   }
1452   return 1.0f;
1453 }
1454 
1455 /* OpenVDB Grid Access */
1456 
1457 #ifdef WITH_OPENVDB
BKE_volume_grid_openvdb_for_metadata(const VolumeGrid * grid)1458 openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_metadata(const VolumeGrid *grid)
1459 {
1460   return grid->grid();
1461 }
1462 
BKE_volume_grid_openvdb_for_read(const Volume * volume,VolumeGrid * grid)1463 openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const Volume *volume,
1464                                                              VolumeGrid *grid)
1465 {
1466   BKE_volume_grid_load(volume, grid);
1467   return grid->grid();
1468 }
1469 
BKE_volume_grid_openvdb_for_write(const Volume * volume,VolumeGrid * grid,const bool clear)1470 openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const Volume *volume,
1471                                                          VolumeGrid *grid,
1472                                                          const bool clear)
1473 {
1474   const char *volume_name = volume->id.name + 2;
1475   if (clear) {
1476     grid->clear_reference(volume_name);
1477   }
1478   else {
1479     VolumeGridVector &grids = *volume->runtime.grids;
1480     grid->duplicate_reference(volume_name, grids.filepath);
1481   }
1482 
1483   return grid->grid();
1484 }
1485 
1486 /* Changing the resolution of a grid. */
1487 
1488 /**
1489  * Returns a grid of the same type as the input, but with more/less resolution. If
1490  * resolution_factor is 1/2, the resolution on each axis is halved. The transform of the returned
1491  * grid is adjusted to match the original grid. */
1492 template<typename GridType>
create_grid_with_changed_resolution(const GridType & old_grid,const float resolution_factor)1493 static typename GridType::Ptr create_grid_with_changed_resolution(const GridType &old_grid,
1494                                                                   const float resolution_factor)
1495 {
1496   BLI_assert(resolution_factor > 0.0f);
1497 
1498   openvdb::Mat4R xform;
1499   xform.setToScale(openvdb::Vec3d(resolution_factor));
1500   openvdb::tools::GridTransformer transformer{xform};
1501 
1502   typename GridType::Ptr new_grid = old_grid.copyWithNewTree();
1503   transformer.transformGrid<openvdb::tools::BoxSampler>(old_grid, *new_grid);
1504   new_grid->transform() = old_grid.transform();
1505   new_grid->transform().preScale(1.0f / resolution_factor);
1506   new_grid->transform().postTranslate(-new_grid->voxelSize() / 2.0f);
1507   return new_grid;
1508 }
1509 
1510 struct CreateGridWithChangedResolutionOp {
1511   const openvdb::GridBase &grid;
1512   const float resolution_factor;
1513 
operator ()CreateGridWithChangedResolutionOp1514   template<typename GridType> typename openvdb::GridBase::Ptr operator()()
1515   {
1516     if constexpr (std::is_same_v<GridType, openvdb::StringGrid>) {
1517       return {};
1518     }
1519     else {
1520       return create_grid_with_changed_resolution(static_cast<const GridType &>(grid),
1521                                                  resolution_factor);
1522     }
1523   }
1524 };
1525 
BKE_volume_grid_create_with_changed_resolution(const VolumeGridType grid_type,const openvdb::GridBase & old_grid,const float resolution_factor)1526 openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution(
1527     const VolumeGridType grid_type,
1528     const openvdb::GridBase &old_grid,
1529     const float resolution_factor)
1530 {
1531   CreateGridWithChangedResolutionOp op{old_grid, resolution_factor};
1532   return BKE_volume_grid_type_operation(grid_type, op);
1533 }
1534 
1535 #endif
1536