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