Blender  V3.3
fluid.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_listbase.h"
11 
12 #include "BLI_fileops.h"
13 #include "BLI_hash.h"
14 #include "BLI_math.h"
15 #include "BLI_path_util.h"
16 #include "BLI_string.h"
17 #include "BLI_task.h"
18 #include "BLI_utildefines.h"
19 
20 #include "DNA_defaults.h"
21 #include "DNA_fluid_types.h"
22 #include "DNA_modifier_types.h"
23 #include "DNA_object_types.h"
24 #include "DNA_rigidbody_types.h"
25 
26 #include "BKE_attribute.h"
27 #include "BKE_effect.h"
28 #include "BKE_fluid.h"
29 #include "BKE_global.h"
30 #include "BKE_lib_id.h"
31 #include "BKE_modifier.h"
32 #include "BKE_pointcache.h"
33 
34 #ifdef WITH_FLUID
35 
36 # include <float.h>
37 # include <math.h>
38 # include <stdio.h>
39 # include <string.h> /* memset */
40 
41 # include "DNA_customdata_types.h"
42 # include "DNA_light_types.h"
43 # include "DNA_mesh_types.h"
44 # include "DNA_meshdata_types.h"
45 # include "DNA_particle_types.h"
46 # include "DNA_scene_types.h"
47 
48 # include "BLI_kdopbvh.h"
49 # include "BLI_kdtree.h"
50 # include "BLI_threads.h"
51 # include "BLI_voxel.h"
52 
53 # include "BKE_bvhutils.h"
54 # include "BKE_collision.h"
55 # include "BKE_colortools.h"
56 # include "BKE_customdata.h"
57 # include "BKE_deform.h"
58 # include "BKE_mesh.h"
59 # include "BKE_mesh_runtime.h"
60 # include "BKE_object.h"
61 # include "BKE_particle.h"
62 # include "BKE_scene.h"
63 # include "BKE_texture.h"
64 
65 # include "DEG_depsgraph.h"
66 # include "DEG_depsgraph_query.h"
67 
68 # include "RE_texture.h"
69 
70 # include "CLG_log.h"
71 
72 # include "manta_fluid_API.h"
73 
74 #endif /* WITH_FLUID */
75 
77 #define DT_DEFAULT 0.1f
78 
80 #define PHI_MAX 9999.0f
81 
82 static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock);
83 
84 #ifdef WITH_FLUID
85 // #define DEBUG_PRINT
86 
87 static CLG_LogRef LOG = {"bke.fluid"};
88 
89 /* -------------------------------------------------------------------- */
93 static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
94 
95 struct FluidModifierData;
96 struct Mesh;
97 struct Object;
98 struct Scene;
99 
100 # define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
101 # define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
102 # define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
103 
104 bool BKE_fluid_reallocate_fluid(FluidDomainSettings *fds, int res[3], int free_old)
105 {
106  if (free_old && fds->fluid) {
107  manta_free(fds->fluid);
108  }
109  if (!min_iii(res[0], res[1], res[2])) {
110  fds->fluid = NULL;
111  }
112  else {
113  fds->fluid = manta_init(res, fds->fmd);
114 
115  fds->res_noise[0] = res[0] * fds->noise_scale;
116  fds->res_noise[1] = res[1] * fds->noise_scale;
117  fds->res_noise[2] = res[2] * fds->noise_scale;
118  }
119 
120  return (fds->fluid != NULL);
121 }
122 
124  int o_res[3],
125  int n_res[3],
126  const int o_min[3],
127  const int n_min[3],
128  const int o_max[3],
129  int o_shift[3],
130  int n_shift[3])
131 {
132  struct MANTA *fluid_old = fds->fluid;
133  const int block_size = fds->noise_scale;
134  int new_shift[3] = {0};
135  sub_v3_v3v3_int(new_shift, n_shift, o_shift);
136 
137  /* Allocate new fluid data. */
138  BKE_fluid_reallocate_fluid(fds, n_res, 0);
139 
140  int o_total_cells = o_res[0] * o_res[1] * o_res[2];
141  int n_total_cells = n_res[0] * n_res[1] * n_res[2];
142 
143  /* Copy values from old fluid to new fluid object. */
144  if (o_total_cells > 1 && n_total_cells > 1) {
145  float *o_dens = manta_smoke_get_density(fluid_old);
146  float *o_react = manta_smoke_get_react(fluid_old);
147  float *o_flame = manta_smoke_get_flame(fluid_old);
148  float *o_fuel = manta_smoke_get_fuel(fluid_old);
149  float *o_heat = manta_smoke_get_heat(fluid_old);
150  float *o_vx = manta_get_velocity_x(fluid_old);
151  float *o_vy = manta_get_velocity_y(fluid_old);
152  float *o_vz = manta_get_velocity_z(fluid_old);
153  float *o_r = manta_smoke_get_color_r(fluid_old);
154  float *o_g = manta_smoke_get_color_g(fluid_old);
155  float *o_b = manta_smoke_get_color_b(fluid_old);
156 
157  float *n_dens = manta_smoke_get_density(fds->fluid);
158  float *n_react = manta_smoke_get_react(fds->fluid);
159  float *n_flame = manta_smoke_get_flame(fds->fluid);
160  float *n_fuel = manta_smoke_get_fuel(fds->fluid);
161  float *n_heat = manta_smoke_get_heat(fds->fluid);
162  float *n_vx = manta_get_velocity_x(fds->fluid);
163  float *n_vy = manta_get_velocity_y(fds->fluid);
164  float *n_vz = manta_get_velocity_z(fds->fluid);
165  float *n_r = manta_smoke_get_color_r(fds->fluid);
166  float *n_g = manta_smoke_get_color_g(fds->fluid);
167  float *n_b = manta_smoke_get_color_b(fds->fluid);
168 
169  /* Noise smoke fields. */
170  float *o_wt_dens = manta_noise_get_density(fluid_old);
171  float *o_wt_react = manta_noise_get_react(fluid_old);
172  float *o_wt_flame = manta_noise_get_flame(fluid_old);
173  float *o_wt_fuel = manta_noise_get_fuel(fluid_old);
174  float *o_wt_r = manta_noise_get_color_r(fluid_old);
175  float *o_wt_g = manta_noise_get_color_g(fluid_old);
176  float *o_wt_b = manta_noise_get_color_b(fluid_old);
177  float *o_wt_tcu = manta_noise_get_texture_u(fluid_old);
178  float *o_wt_tcv = manta_noise_get_texture_v(fluid_old);
179  float *o_wt_tcw = manta_noise_get_texture_w(fluid_old);
180  float *o_wt_tcu2 = manta_noise_get_texture_u2(fluid_old);
181  float *o_wt_tcv2 = manta_noise_get_texture_v2(fluid_old);
182  float *o_wt_tcw2 = manta_noise_get_texture_w2(fluid_old);
183 
184  float *n_wt_dens = manta_noise_get_density(fds->fluid);
185  float *n_wt_react = manta_noise_get_react(fds->fluid);
186  float *n_wt_flame = manta_noise_get_flame(fds->fluid);
187  float *n_wt_fuel = manta_noise_get_fuel(fds->fluid);
188  float *n_wt_r = manta_noise_get_color_r(fds->fluid);
189  float *n_wt_g = manta_noise_get_color_g(fds->fluid);
190  float *n_wt_b = manta_noise_get_color_b(fds->fluid);
191  float *n_wt_tcu = manta_noise_get_texture_u(fds->fluid);
192  float *n_wt_tcv = manta_noise_get_texture_v(fds->fluid);
193  float *n_wt_tcw = manta_noise_get_texture_w(fds->fluid);
194  float *n_wt_tcu2 = manta_noise_get_texture_u2(fds->fluid);
195  float *n_wt_tcv2 = manta_noise_get_texture_v2(fds->fluid);
196  float *n_wt_tcw2 = manta_noise_get_texture_w2(fds->fluid);
197 
198  int wt_res_old[3];
199  manta_noise_get_res(fluid_old, wt_res_old);
200 
201  for (int z = o_min[2]; z < o_max[2]; z++) {
202  for (int y = o_min[1]; y < o_max[1]; y++) {
203  for (int x = o_min[0]; x < o_max[0]; x++) {
204  /* old grid index */
205  int xo = x - o_min[0];
206  int yo = y - o_min[1];
207  int zo = z - o_min[2];
208  int index_old = manta_get_index(xo, o_res[0], yo, o_res[1], zo);
209  /* new grid index */
210  int xn = x - n_min[0] - new_shift[0];
211  int yn = y - n_min[1] - new_shift[1];
212  int zn = z - n_min[2] - new_shift[2];
213  int index_new = manta_get_index(xn, n_res[0], yn, n_res[1], zn);
214 
215  /* Skip if outside new domain. */
216  if (xn < 0 || xn >= n_res[0] || yn < 0 || yn >= n_res[1] || zn < 0 || zn >= n_res[2]) {
217  continue;
218  }
219 # if 0
220  /* Note (sebbas):
221  * Disabling this "skip section" as not copying borders results in weird cut-off effects.
222  * It is possible that this cutting off is the reason for line effects as seen in T74559.
223  * Since domain borders will be handled on the simulation side anyways,
224  * copying border values should not be an issue. */
225 
226  /* boundary cells will be skipped when copying data */
227  int bwidth = fds->boundary_width;
228 
229  /* Skip if trying to copy from old boundary cell. */
230  if (xo < bwidth || yo < bwidth || zo < bwidth || xo >= o_res[0] - bwidth ||
231  yo >= o_res[1] - bwidth || zo >= o_res[2] - bwidth) {
232  continue;
233  }
234  /* Skip if trying to copy into new boundary cell. */
235  if (xn < bwidth || yn < bwidth || zn < bwidth || xn >= n_res[0] - bwidth ||
236  yn >= n_res[1] - bwidth || zn >= n_res[2] - bwidth) {
237  continue;
238  }
239 # endif
240 
241  /* copy data */
242  if (fds->flags & FLUID_DOMAIN_USE_NOISE) {
243  int i, j, k;
244  /* old grid index */
245  int xx_o = xo * block_size;
246  int yy_o = yo * block_size;
247  int zz_o = zo * block_size;
248  /* new grid index */
249  int xx_n = xn * block_size;
250  int yy_n = yn * block_size;
251  int zz_n = zn * block_size;
252 
253  /* insert old texture values into new texture grids */
254  n_wt_tcu[index_new] = o_wt_tcu[index_old];
255  n_wt_tcv[index_new] = o_wt_tcv[index_old];
256  n_wt_tcw[index_new] = o_wt_tcw[index_old];
257 
258  n_wt_tcu2[index_new] = o_wt_tcu2[index_old];
259  n_wt_tcv2[index_new] = o_wt_tcv2[index_old];
260  n_wt_tcw2[index_new] = o_wt_tcw2[index_old];
261 
262  for (i = 0; i < block_size; i++) {
263  for (j = 0; j < block_size; j++) {
264  for (k = 0; k < block_size; k++) {
265  int big_index_old = manta_get_index(
266  xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k);
267  int big_index_new = manta_get_index(
268  xx_n + i, fds->res_noise[0], yy_n + j, fds->res_noise[1], zz_n + k);
269  /* copy data */
270  n_wt_dens[big_index_new] = o_wt_dens[big_index_old];
271  if (n_wt_flame && o_wt_flame) {
272  n_wt_flame[big_index_new] = o_wt_flame[big_index_old];
273  n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old];
274  n_wt_react[big_index_new] = o_wt_react[big_index_old];
275  }
276  if (n_wt_r && o_wt_r) {
277  n_wt_r[big_index_new] = o_wt_r[big_index_old];
278  n_wt_g[big_index_new] = o_wt_g[big_index_old];
279  n_wt_b[big_index_new] = o_wt_b[big_index_old];
280  }
281  }
282  }
283  }
284  }
285 
286  n_dens[index_new] = o_dens[index_old];
287  /* heat */
288  if (n_heat && o_heat) {
289  n_heat[index_new] = o_heat[index_old];
290  }
291  /* fuel */
292  if (n_fuel && o_fuel) {
293  n_flame[index_new] = o_flame[index_old];
294  n_fuel[index_new] = o_fuel[index_old];
295  n_react[index_new] = o_react[index_old];
296  }
297  /* color */
298  if (o_r && n_r) {
299  n_r[index_new] = o_r[index_old];
300  n_g[index_new] = o_g[index_old];
301  n_b[index_new] = o_b[index_old];
302  }
303  n_vx[index_new] = o_vx[index_old];
304  n_vy[index_new] = o_vy[index_old];
305  n_vz[index_new] = o_vz[index_old];
306  }
307  }
308  }
309  }
310  manta_free(fluid_old);
311 }
312 
314 {
318  BKE_fluid_cache_free(fds, ob, cache_map);
319 }
320 
321 void BKE_fluid_cache_free(FluidDomainSettings *fds, Object *ob, int cache_map)
322 {
323  char temp_dir[FILE_MAX];
324  int flags = fds->cache_flag;
325  const char *relbase = BKE_modifier_path_relbase_from_global(ob);
326 
327  if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
329  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
330  BLI_path_abs(temp_dir, relbase);
331  if (BLI_exists(temp_dir)) {
332  BLI_delete(temp_dir, true, true);
333  }
334  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
335  BLI_path_abs(temp_dir, relbase);
336  if (BLI_exists(temp_dir)) {
337  BLI_delete(temp_dir, true, true);
338  }
339  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
340  BLI_path_abs(temp_dir, relbase);
341  if (BLI_exists(temp_dir)) {
342  BLI_delete(temp_dir, true, true);
343  }
344  fds->cache_frame_pause_data = 0;
345  }
346  if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) {
348  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
349  BLI_path_abs(temp_dir, relbase);
350  if (BLI_exists(temp_dir)) {
351  BLI_delete(temp_dir, true, true);
352  }
353  fds->cache_frame_pause_noise = 0;
354  }
355  if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) {
357  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
358  BLI_path_abs(temp_dir, relbase);
359  if (BLI_exists(temp_dir)) {
360  BLI_delete(temp_dir, true, true);
361  }
362  fds->cache_frame_pause_mesh = 0;
363  }
364  if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) {
368  temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
369  BLI_path_abs(temp_dir, relbase);
370  if (BLI_exists(temp_dir)) {
371  BLI_delete(temp_dir, true, true);
372  }
374  }
375  if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) {
377  BLI_path_join(temp_dir, sizeof(temp_dir), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL);
378  BLI_path_abs(temp_dir, relbase);
379  if (BLI_exists(temp_dir)) {
380  BLI_delete(temp_dir, true, true);
381  }
382  fds->cache_frame_pause_guide = 0;
383  }
384  fds->cache_flag = flags;
385 }
386 
387 /* convert global position to domain cell space */
388 static void manta_pos_to_cell(FluidDomainSettings *fds, float pos[3])
389 {
390  mul_m4_v3(fds->imat, pos);
391  sub_v3_v3(pos, fds->p0);
392  pos[0] *= 1.0f / fds->cell_size[0];
393  pos[1] *= 1.0f / fds->cell_size[1];
394  pos[2] *= 1.0f / fds->cell_size[2];
395 }
396 
397 /* Set domain transformations and base resolution from object mesh. */
398 static void manta_set_domain_from_mesh(FluidDomainSettings *fds,
399  Object *ob,
400  Mesh *me,
401  bool init_resolution)
402 {
403  size_t i;
404  float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
405  float size[3];
406  MVert *verts = me->mvert;
407  float scale = 0.0;
408  int res;
409 
410  res = fds->maxres;
411 
412  /* Set minimum and maximum coordinates of BB. */
413  for (i = 0; i < me->totvert; i++) {
414  minmax_v3v3_v3(min, max, verts[i].co);
415  }
416 
417  /* Set domain bounds. */
418  copy_v3_v3(fds->p0, min);
419  copy_v3_v3(fds->p1, max);
420  fds->dx = 1.0f / res;
421 
422  /* Calculate domain dimensions. */
423  sub_v3_v3v3(size, max, min);
424  if (init_resolution) {
425  zero_v3_int(fds->base_res);
426  copy_v3_v3(fds->cell_size, size);
427  }
428  /* Apply object scale. */
429  for (i = 0; i < 3; i++) {
430  size[i] = fabsf(size[i] * ob->scale[i]);
431  }
432  copy_v3_v3(fds->global_size, size);
433  copy_v3_v3(fds->dp0, min);
434 
435  invert_m4_m4(fds->imat, ob->obmat);
436 
437  /* Prevent crash when initializing a plane as domain. */
438  if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) ||
439  (size[2] < FLT_EPSILON)) {
440  return;
441  }
442 
443  /* Define grid resolutions from longest domain side. */
444  if (size[0] >= MAX2(size[1], size[2])) {
445  scale = res / size[0];
446  fds->scale = size[0] / fabsf(ob->scale[0]);
447  fds->base_res[0] = res;
448  fds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
449  fds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
450  }
451  else if (size[1] >= MAX2(size[0], size[2])) {
452  scale = res / size[1];
453  fds->scale = size[1] / fabsf(ob->scale[1]);
454  fds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
455  fds->base_res[1] = res;
456  fds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
457  }
458  else {
459  scale = res / size[2];
460  fds->scale = size[2] / fabsf(ob->scale[2]);
461  fds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
462  fds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
463  fds->base_res[2] = res;
464  }
465 
466  /* Set cell size. */
467  fds->cell_size[0] /= (float)fds->base_res[0];
468  fds->cell_size[1] /= (float)fds->base_res[1];
469  fds->cell_size[2] /= (float)fds->base_res[2];
470 }
471 
472 static void update_final_gravity(FluidDomainSettings *fds, Scene *scene)
473 {
476  }
477  else {
478  copy_v3_v3(fds->gravity_final, fds->gravity);
479  }
481 }
482 
483 static bool BKE_fluid_modifier_init(
485 {
486  int scene_framenr = (int)DEG_get_ctime(depsgraph);
487 
488  if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain && !fmd->domain->fluid) {
489  FluidDomainSettings *fds = fmd->domain;
490  int res[3];
491  /* Set domain dimensions from mesh. */
492  manta_set_domain_from_mesh(fds, ob, me, true);
493  /* Set domain gravity, use global gravity if enabled. */
494  update_final_gravity(fds, scene);
495  /* Reset domain values. */
496  zero_v3_int(fds->shift);
497  zero_v3(fds->shift_f);
498  add_v3_fl(fds->shift_f, 0.5f);
499  zero_v3(fds->prev_loc);
500  mul_m4_v3(ob->obmat, fds->prev_loc);
501  copy_m4_m4(fds->obmat, ob->obmat);
502 
503  /* Set resolutions. */
504  if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
506  res[0] = res[1] = res[2] = 1; /* Use minimum res for adaptive init. */
507  }
508  else {
509  copy_v3_v3_int(res, fds->base_res);
510  }
511  copy_v3_v3_int(fds->res, res);
512  fds->total_cells = fds->res[0] * fds->res[1] * fds->res[2];
513  fds->res_min[0] = fds->res_min[1] = fds->res_min[2] = 0;
514  copy_v3_v3_int(fds->res_max, res);
515 
516  /* Set time, frame length = 0.1 is at 25fps. */
517  fds->frame_length = DT_DEFAULT * (25.0f / FPS) * fds->time_scale;
518  /* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */
519  fds->dt = fds->frame_length;
520  fds->time_per_frame = 0;
521 
522  fmd->time = scene_framenr;
523 
524  /* Allocate fluid. */
525  return BKE_fluid_reallocate_fluid(fds, fds->res, 0);
526  }
527  if (fmd->type & MOD_FLUID_TYPE_FLOW) {
528  if (!fmd->flow) {
530  }
531  fmd->time = scene_framenr;
532  return true;
533  }
534  if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
535  if (!fmd->effector) {
537  }
538  fmd->time = scene_framenr;
539  return true;
540  }
541  return false;
542 }
543 
544 /* Forward declarations. */
545 static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *view_layer);
546 static float calc_voxel_transp(
547  float *result, const float *input, int res[3], int *pixel, float *t_ray, float correct);
548 static void update_distances(int index,
549  float *distance_map,
550  BVHTreeFromMesh *tree_data,
551  const float ray_start[3],
552  float surface_thickness,
553  bool use_plane_init);
554 
555 static int get_light(ViewLayer *view_layer, float *light)
556 {
557  Base *base_tmp = NULL;
558  int found_light = 0;
559 
560  /* Try to find a lamp, preferably local. */
561  for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
562  if (base_tmp->object->type == OB_LAMP) {
563  Light *la = base_tmp->object->data;
564 
565  if (la->type == LA_LOCAL) {
566  copy_v3_v3(light, base_tmp->object->obmat[3]);
567  return 1;
568  }
569  if (!found_light) {
570  copy_v3_v3(light, base_tmp->object->obmat[3]);
571  found_light = 1;
572  }
573  }
574  }
575 
576  return found_light;
577 }
578 
579 static void clamp_bounds_in_domain(FluidDomainSettings *fds,
580  int min[3],
581  int max[3],
582  const float *min_vel,
583  const float *max_vel,
584  int margin,
585  float dt)
586 {
587  for (int i = 0; i < 3; i++) {
588  int adapt = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) ? fds->adapt_res : 0;
589  /* Add some margin. */
590  min[i] -= margin;
591  max[i] += margin;
592 
593  /* Adapt to velocity. */
594  if (min_vel && min_vel[i] < 0.0f) {
595  min[i] += (int)floor(min_vel[i] * dt);
596  }
597  if (max_vel && max_vel[i] > 0.0f) {
598  max[i] += (int)ceil(max_vel[i] * dt);
599  }
600 
601  /* Clamp within domain max size. */
602  CLAMP(min[i], -adapt, fds->base_res[i] + adapt);
603  CLAMP(max[i], -adapt, fds->base_res[i] + adapt);
604  }
605 }
606 
607 static bool is_static_object(Object *ob)
608 {
609  /* Check if the object has modifiers that might make the object "dynamic". */
610  VirtualModifierData virtualModifierData;
611  ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
612  for (; md; md = md->next) {
613  if (ELEM(md->type,
621  return false;
622  }
623  }
624 
625  /* Active rigid body objects considered to be dynamic fluid objects. */
627  return false;
628  }
629 
630  /* Finally, check if the object has animation data. If so, it is considered dynamic. */
631  return !BKE_object_moves_in_time(ob, true);
632 }
633 
636 /* -------------------------------------------------------------------- */
640 typedef struct FluidObjectBB {
641  float *influence;
642  float *velocity;
643  float *distances;
644  float *numobjs;
645  int min[3], max[3], res[3];
646  int hmin[3], hmax[3], hres[3];
647  int total_cells, valid;
648 } FluidObjectBB;
649 
650 static void bb_boundInsert(FluidObjectBB *bb, const float point[3])
651 {
652  int i = 0;
653  if (!bb->valid) {
654  for (; i < 3; i++) {
655  bb->min[i] = (int)floor(point[i]);
656  bb->max[i] = (int)ceil(point[i]);
657  }
658  bb->valid = 1;
659  }
660  else {
661  for (; i < 3; i++) {
662  if (point[i] < bb->min[i]) {
663  bb->min[i] = (int)floor(point[i]);
664  }
665  if (point[i] > bb->max[i]) {
666  bb->max[i] = (int)ceil(point[i]);
667  }
668  }
669  }
670 }
671 
672 static void bb_allocateData(FluidObjectBB *bb, bool use_velocity, bool use_influence)
673 {
674  int i, res[3];
675 
676  for (i = 0; i < 3; i++) {
677  res[i] = bb->max[i] - bb->min[i];
678  if (res[i] <= 0) {
679  return;
680  }
681  }
682  bb->total_cells = res[0] * res[1] * res[2];
683  copy_v3_v3_int(bb->res, res);
684 
685  bb->numobjs = MEM_calloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_numobjs");
686  if (use_influence) {
687  bb->influence = MEM_calloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_influence");
688  }
689  if (use_velocity) {
690  bb->velocity = MEM_calloc_arrayN(bb->total_cells, sizeof(float[3]), "fluid_bb_velocity");
691  }
692 
693  bb->distances = MEM_malloc_arrayN(bb->total_cells, sizeof(float), "fluid_bb_distances");
694  copy_vn_fl(bb->distances, bb->total_cells, FLT_MAX);
695 
696  bb->valid = true;
697 }
698 
699 static void bb_freeData(FluidObjectBB *bb)
700 {
701  if (bb->numobjs) {
702  MEM_freeN(bb->numobjs);
703  }
704  if (bb->influence) {
705  MEM_freeN(bb->influence);
706  }
707  if (bb->velocity) {
708  MEM_freeN(bb->velocity);
709  }
710  if (bb->distances) {
711  MEM_freeN(bb->distances);
712  }
713 }
714 
715 static void bb_combineMaps(FluidObjectBB *output,
716  FluidObjectBB *bb2,
717  int additive,
718  float sample_size)
719 {
720  int i, x, y, z;
721 
722  /* Copyfill input 1 struct and clear output for new allocation. */
723  FluidObjectBB bb1;
724  memcpy(&bb1, output, sizeof(FluidObjectBB));
725  memset(output, 0, sizeof(FluidObjectBB));
726 
727  for (i = 0; i < 3; i++) {
728  if (bb1.valid) {
729  output->min[i] = MIN2(bb1.min[i], bb2->min[i]);
730  output->max[i] = MAX2(bb1.max[i], bb2->max[i]);
731  }
732  else {
733  output->min[i] = bb2->min[i];
734  output->max[i] = bb2->max[i];
735  }
736  }
737  /* Allocate output map. */
738  bb_allocateData(output, (bb1.velocity || bb2->velocity), (bb1.influence || bb2->influence));
739 
740  /* Low through bounding box */
741  for (x = output->min[0]; x < output->max[0]; x++) {
742  for (y = output->min[1]; y < output->max[1]; y++) {
743  for (z = output->min[2]; z < output->max[2]; z++) {
744  int index_out = manta_get_index(x - output->min[0],
745  output->res[0],
746  y - output->min[1],
747  output->res[1],
748  z - output->min[2]);
749 
750  /* Initialize with first input if in range. */
751  if (x >= bb1.min[0] && x < bb1.max[0] && y >= bb1.min[1] && y < bb1.max[1] &&
752  z >= bb1.min[2] && z < bb1.max[2]) {
753  int index_in = manta_get_index(
754  x - bb1.min[0], bb1.res[0], y - bb1.min[1], bb1.res[1], z - bb1.min[2]);
755 
756  /* Values. */
757  output->numobjs[index_out] = bb1.numobjs[index_in];
758  if (output->influence && bb1.influence) {
759  output->influence[index_out] = bb1.influence[index_in];
760  }
761  output->distances[index_out] = bb1.distances[index_in];
762  if (output->velocity && bb1.velocity) {
763  copy_v3_v3(&output->velocity[index_out * 3], &bb1.velocity[index_in * 3]);
764  }
765  }
766 
767  /* Apply second input if in range. */
768  if (x >= bb2->min[0] && x < bb2->max[0] && y >= bb2->min[1] && y < bb2->max[1] &&
769  z >= bb2->min[2] && z < bb2->max[2]) {
770  int index_in = manta_get_index(
771  x - bb2->min[0], bb2->res[0], y - bb2->min[1], bb2->res[1], z - bb2->min[2]);
772 
773  /* Values. */
774  output->numobjs[index_out] = MAX2(bb2->numobjs[index_in], output->numobjs[index_out]);
775  if (output->influence && bb2->influence) {
776  if (additive) {
777  output->influence[index_out] += bb2->influence[index_in] * sample_size;
778  }
779  else {
780  output->influence[index_out] = MAX2(bb2->influence[index_in],
781  output->influence[index_out]);
782  }
783  }
784  output->distances[index_out] = MIN2(bb2->distances[index_in],
785  output->distances[index_out]);
786  if (output->velocity && bb2->velocity) {
787  /* Last sample replaces the velocity. */
788  output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3],
789  bb2->velocity[index_in * 3]);
790  output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1],
791  bb2->velocity[index_in * 3 + 1]);
792  output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2],
793  bb2->velocity[index_in * 3 + 2]);
794  }
795  }
796  } /* Low res loop. */
797  }
798  }
799 
800  /* Free original data. */
801  bb_freeData(&bb1);
802 }
803 
806 /* -------------------------------------------------------------------- */
810 BLI_INLINE void apply_effector_fields(FluidEffectorSettings *UNUSED(fes),
811  int index,
812  float src_distance_value,
813  float *dest_phi_in,
814  float src_numobjs_value,
815  float *dest_numobjs,
816  float const src_vel_value[3],
817  float *dest_vel_x,
818  float *dest_vel_y,
819  float *dest_vel_z)
820 {
821  /* Ensure that distance value is "joined" into the levelset. */
822  if (dest_phi_in) {
823  dest_phi_in[index] = MIN2(src_distance_value, dest_phi_in[index]);
824  }
825 
826  /* Accumulate effector object count (important once effector object overlap). */
827  if (dest_numobjs && src_numobjs_value > 0) {
828  dest_numobjs[index] += 1;
829  }
830 
831  /* Accumulate effector velocities for each cell. */
832  if (dest_vel_x && src_numobjs_value > 0) {
833  dest_vel_x[index] += src_vel_value[0];
834  dest_vel_y[index] += src_vel_value[1];
835  dest_vel_z[index] += src_vel_value[2];
836  }
837 }
838 
840  const MVert *mvert,
841  const MLoop *mloop,
842  const MLoopTri *mlooptri,
843  float *velocity_map,
844  int index,
845  BVHTreeFromMesh *tree_data,
846  const float ray_start[3],
847  const float *vert_vel,
848  bool has_velocity)
849 {
850  BVHTreeNearest nearest = {0};
851  nearest.index = -1;
852 
853  /* Distance between two opposing vertices in a unit cube.
854  * I.e. the unit cube diagonal or sqrt(3).
855  * This value is our nearest neighbor search distance. */
856  const float surface_distance = 1.732;
857  nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */
858 
859  /* Find the nearest point on the mesh. */
860  if (has_velocity &&
862  tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
863  float weights[3];
864  int v1, v2, v3, f_index = nearest.index;
865 
866  /* Calculate barycentric weights for nearest point. */
867  v1 = mloop[mlooptri[f_index].tri[0]].v;
868  v2 = mloop[mlooptri[f_index].tri[1]].v;
869  v3 = mloop[mlooptri[f_index].tri[2]].v;
870  interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
871 
872  /* Apply object velocity. */
873  float hit_vel[3];
874  interp_v3_v3v3v3(hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
875 
876  /* Guiding has additional velocity multiplier */
877  if (fes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
878  mul_v3_fl(hit_vel, fes->vel_multi);
879 
880  /* Absolute representation of new object velocity. */
881  float abs_hit_vel[3];
882  copy_v3_v3(abs_hit_vel, hit_vel);
883  abs_v3(abs_hit_vel);
884 
885  /* Absolute representation of current object velocity. */
886  float abs_vel[3];
887  copy_v3_v3(abs_vel, &velocity_map[index * 3]);
888  abs_v3(abs_vel);
889 
890  switch (fes->guide_mode) {
892  velocity_map[index * 3] = (velocity_map[index * 3] + hit_vel[0]) * 0.5f;
893  velocity_map[index * 3 + 1] = (velocity_map[index * 3 + 1] + hit_vel[1]) * 0.5f;
894  velocity_map[index * 3 + 2] = (velocity_map[index * 3 + 2] + hit_vel[2]) * 0.5f;
895  break;
897  velocity_map[index * 3] = hit_vel[0];
898  velocity_map[index * 3 + 1] = hit_vel[1];
899  velocity_map[index * 3 + 2] = hit_vel[2];
900  break;
902  velocity_map[index * 3] = MIN2(abs_hit_vel[0], abs_vel[0]);
903  velocity_map[index * 3 + 1] = MIN2(abs_hit_vel[1], abs_vel[1]);
904  velocity_map[index * 3 + 2] = MIN2(abs_hit_vel[2], abs_vel[2]);
905  break;
907  default:
908  velocity_map[index * 3] = MAX2(abs_hit_vel[0], abs_vel[0]);
909  velocity_map[index * 3 + 1] = MAX2(abs_hit_vel[1], abs_vel[1]);
910  velocity_map[index * 3 + 2] = MAX2(abs_hit_vel[2], abs_vel[2]);
911  break;
912  }
913  }
914  else if (fes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
915  velocity_map[index * 3] = hit_vel[0];
916  velocity_map[index * 3 + 1] = hit_vel[1];
917  velocity_map[index * 3 + 2] = hit_vel[2];
918 # ifdef DEBUG_PRINT
919  /* Debugging: Print object velocities. */
920  printf("setting effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
921 # endif
922  }
923  else {
924  /* Should never reach this block. */
926  }
927  }
928  else {
929  /* Clear velocities at cells that are not moving. */
930  copy_v3_fl(velocity_map, 0.0);
931  }
932 }
933 
934 typedef struct ObstaclesFromDMData {
936 
937  const MVert *mvert;
938  const MLoop *mloop;
939  const MLoopTri *mlooptri;
940 
942  FluidObjectBB *bb;
943 
944  bool has_velocity;
945  float *vert_vel;
946  int *min, *max, *res;
947 } ObstaclesFromDMData;
948 
949 static void obstacles_from_mesh_task_cb(void *__restrict userdata,
950  const int z,
951  const TaskParallelTLS *__restrict UNUSED(tls))
952 {
953  ObstaclesFromDMData *data = userdata;
954  FluidObjectBB *bb = data->bb;
955 
956  for (int x = data->min[0]; x < data->max[0]; x++) {
957  for (int y = data->min[1]; y < data->max[1]; y++) {
958  const int index = manta_get_index(
959  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
960  const float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
961 
962  /* Calculate levelset values from meshes. Result in bb->distances. */
963  update_distances(index,
964  bb->distances,
965  data->tree,
966  ray_start,
967  data->fes->surface_distance,
968  data->fes->flags & FLUID_EFFECTOR_USE_PLANE_INIT);
969 
970  /* Calculate object velocities. Result in bb->velocity. */
971  update_velocities(data->fes,
972  data->mvert,
973  data->mloop,
974  data->mlooptri,
975  bb->velocity,
976  index,
977  data->tree,
978  ray_start,
979  data->vert_vel,
980  data->has_velocity);
981 
982  /* Increase obstacle count inside of moving obstacles. */
983  if (bb->distances[index] < 0) {
984  bb->numobjs[index]++;
985  }
986  }
987  }
988 }
989 
990 static void obstacles_from_mesh(Object *coll_ob,
991  FluidDomainSettings *fds,
993  FluidObjectBB *bb,
994  float dt)
995 {
996  if (fes->mesh) {
997  Mesh *me = NULL;
998  MVert *mvert = NULL;
999  const MLoopTri *looptri;
1000  const MLoop *mloop;
1001  BVHTreeFromMesh tree_data = {NULL};
1002  int numverts, i;
1003 
1004  float *vert_vel = NULL;
1005  bool has_velocity = false;
1006 
1007  me = BKE_mesh_copy_for_eval(fes->mesh, true);
1008 
1009  int min[3], max[3], res[3];
1010 
1011  /* Duplicate vertices to modify. */
1012  if (me->mvert) {
1013  me->mvert = MEM_dupallocN(me->mvert);
1015  }
1016 
1017  mvert = me->mvert;
1018  mloop = me->mloop;
1019  looptri = BKE_mesh_runtime_looptri_ensure(me);
1020  numverts = me->totvert;
1021 
1022  /* TODO(sebbas): Make initialization of vertex velocities optional? */
1023  {
1024  vert_vel = MEM_callocN(sizeof(float[3]) * numverts, "manta_obs_velocity");
1025 
1026  if (fes->numverts != numverts || !fes->verts_old) {
1027  if (fes->verts_old) {
1028  MEM_freeN(fes->verts_old);
1029  }
1030 
1031  fes->verts_old = MEM_callocN(sizeof(float[3]) * numverts, "manta_obs_verts_old");
1032  fes->numverts = numverts;
1033  }
1034  else {
1035  has_velocity = true;
1036  }
1037  }
1038 
1039  /* Transform mesh vertices to domain grid space for fast lookups.
1040  * This is valid because the mesh is copied above. */
1041  for (i = 0; i < numverts; i++) {
1042  float co[3];
1043 
1044  /* Vertex position. */
1045  mul_m4_v3(coll_ob->obmat, mvert[i].co);
1046  manta_pos_to_cell(fds, mvert[i].co);
1047 
1048  /* Vertex velocity. */
1049  add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
1050  if (has_velocity) {
1051  sub_v3_v3v3(&vert_vel[i * 3], co, &fes->verts_old[i * 3]);
1052  mul_v3_fl(&vert_vel[i * 3], 1.0f / dt);
1053  }
1054  copy_v3_v3(&fes->verts_old[i * 3], co);
1055 
1056  /* Calculate emission map bounds. */
1057  bb_boundInsert(bb, mvert[i].co);
1058  }
1059 
1060  /* Set emission map.
1061  * Use 3 cell diagonals as margin (3 * 1.732 = 5.196). */
1062  int bounds_margin = (int)ceil(5.196);
1063  clamp_bounds_in_domain(fds, bb->min, bb->max, NULL, NULL, bounds_margin, dt);
1064  bb_allocateData(bb, true, false);
1065 
1066  /* Setup loop bounds. */
1067  for (i = 0; i < 3; i++) {
1068  min[i] = bb->min[i];
1069  max[i] = bb->max[i];
1070  res[i] = bb->res[i];
1071  }
1072 
1073  /* Skip effector sampling loop if object has disabled effector. */
1074  bool use_effector = fes->flags & FLUID_EFFECTOR_USE_EFFEC;
1075  if (use_effector && BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
1076 
1077  ObstaclesFromDMData data = {
1078  .fes = fes,
1079  .mvert = mvert,
1080  .mloop = mloop,
1081  .mlooptri = looptri,
1082  .tree = &tree_data,
1083  .bb = bb,
1084  .has_velocity = has_velocity,
1085  .vert_vel = vert_vel,
1086  .min = min,
1087  .max = max,
1088  .res = res,
1089  };
1090 
1091  TaskParallelSettings settings;
1093  settings.min_iter_per_thread = 2;
1094  BLI_task_parallel_range(min[2], max[2], &data, obstacles_from_mesh_task_cb, &settings);
1095  }
1096  /* Free bvh tree. */
1097  free_bvhtree_from_mesh(&tree_data);
1098 
1099  if (vert_vel) {
1100  MEM_freeN(vert_vel);
1101  }
1102  if (me->mvert) {
1103  MEM_freeN(me->mvert);
1104  }
1105  BKE_id_free(NULL, me);
1106  }
1107 }
1108 
1109 static void ensure_obstaclefields(FluidDomainSettings *fds)
1110 {
1112  manta_ensure_obstacle(fds->fluid, fds->fmd);
1113  }
1115  manta_ensure_guiding(fds->fluid, fds->fmd);
1116  }
1117  manta_update_pointers(fds->fluid, fds->fmd, false);
1118 }
1119 
1120 static void update_obstacleflags(FluidDomainSettings *fds,
1121  Object **coll_ob_array,
1122  int coll_ob_array_len)
1123 {
1124  int active_fields = fds->active_fields;
1125  uint coll_index;
1126 
1127  /* First, remove all flags that we want to update. */
1129  active_fields &= ~prev_flags;
1130 
1131  /* Monitor active fields based on flow settings */
1132  for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) {
1133  Object *coll_ob = coll_ob_array[coll_index];
1136 
1137  /* Sanity check. */
1138  if (!fmd2) {
1139  continue;
1140  }
1141 
1142  if ((fmd2->type & MOD_FLUID_TYPE_EFFEC) && fmd2->effector) {
1143  FluidEffectorSettings *fes = fmd2->effector;
1144  if (!fes) {
1145  break;
1146  }
1147  if (fes->flags & FLUID_EFFECTOR_NEEDS_UPDATE) {
1150  }
1151  if (fes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
1152  active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE;
1153  }
1154  if (fes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
1155  active_fields |= FLUID_DOMAIN_ACTIVE_GUIDE;
1156  }
1157  }
1158  }
1159  fds->active_fields = active_fields;
1160 }
1161 
1162 static bool escape_effectorobject(Object *flowobj,
1163  FluidDomainSettings *fds,
1165  int frame)
1166 {
1167  bool is_static = is_static_object(flowobj);
1168 
1169  bool is_resume = (fds->cache_frame_pause_data == frame);
1171  bool is_first_frame = (frame == fds->cache_frame_start);
1172 
1173  /* Cannot use static mode with adaptive domain.
1174  * The adaptive domain might expand and only later discover the static object. */
1175  if (is_adaptive) {
1176  is_static = false;
1177  }
1178  /* Skip static effector objects after initial frame. */
1179  if (is_static && !is_first_frame && !is_resume) {
1180  return true;
1181  }
1182  return false;
1183 }
1184 
1185 static void compute_obstaclesemission(Scene *scene,
1186  FluidObjectBB *bb_maps,
1187  struct Depsgraph *depsgraph,
1188  float dt,
1189  Object **effecobjs,
1190  int frame,
1191  float frame_length,
1192  FluidDomainSettings *fds,
1193  uint numeffecobjs,
1194  float time_per_frame)
1195 {
1196  bool is_first_frame = (frame == fds->cache_frame_start);
1197 
1198  /* Prepare effector maps. */
1199  for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
1200  Object *effecobj = effecobjs[effec_index];
1203 
1204  /* Sanity check. */
1205  if (!fmd2) {
1206  continue;
1207  }
1208 
1209  /* Check for initialized effector object. */
1210  if ((fmd2->type & MOD_FLUID_TYPE_EFFEC) && fmd2->effector) {
1211  FluidEffectorSettings *fes = fmd2->effector;
1212  int subframes = fes->subframes;
1213  FluidObjectBB *bb = &bb_maps[effec_index];
1214 
1215  /* Optimization: Skip this object under certain conditions. */
1216  if (escape_effectorobject(effecobj, fds, fes, frame)) {
1217  continue;
1218  }
1219 
1220  /* First frame cannot have any subframes because there is (obviously) no previous frame from
1221  * where subframes could come from. */
1222  if (is_first_frame) {
1223  subframes = 0;
1224  }
1225 
1226  /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
1227  float sample_size = 1.0f / (float)(subframes + 1);
1228  float subframe_dt = dt * sample_size;
1229 
1230  /* Emission loop. When not using subframes this will loop only once. */
1231  for (int subframe = 0; subframe <= subframes; subframe++) {
1232 
1233  /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
1234  FluidObjectBB bb_temp = {NULL};
1235 
1236  /* Set scene time */
1237  /* Handle emission subframe */
1238  if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
1239  !is_first_frame) {
1240  scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
1241  scene->r.cfra = frame - 1;
1242  }
1243  else {
1244  scene->r.subframe = 0.0f;
1245  scene->r.cfra = frame;
1246  }
1247  /* Sanity check: subframe portion must be between 0 and 1. */
1248  CLAMP(scene->r.subframe, 0.0f, 1.0f);
1249 # ifdef DEBUG_PRINT
1250  /* Debugging: Print subframe information. */
1251  printf(
1252  "effector: frame (is first: %d): %d // scene current frame: %d // scene current "
1253  "subframe: "
1254  "%f\n",
1255  is_first_frame,
1256  frame,
1257  scene->r.cfra,
1258  scene->r.subframe);
1259 # endif
1260  /* Update frame time, this is considering current subframe fraction
1261  * BLI_mutex_lock() called in manta_step(), so safe to update subframe here
1262  * TODO(sebbas): Using BKE_scene_ctime_get(scene) instead of new DEG_get_ctime(depsgraph)
1263  * as subframes don't work with the latter yet. */
1266 
1267  if (subframes) {
1268  obstacles_from_mesh(effecobj, fds, fes, &bb_temp, subframe_dt);
1269  }
1270  else {
1271  obstacles_from_mesh(effecobj, fds, fes, bb, subframe_dt);
1272  }
1273 
1274  /* If this we emitted with temp emission map in this loop (subframe emission), we combine
1275  * the temp map with the original emission map. */
1276  if (subframes) {
1277  /* Combine emission maps. */
1278  bb_combineMaps(bb, &bb_temp, 0, 0.0f);
1279  bb_freeData(&bb_temp);
1280  }
1281  }
1282  }
1283  }
1284 }
1285 
1286 static void update_obstacles(Depsgraph *depsgraph,
1287  Scene *scene,
1288  Object *ob,
1289  FluidDomainSettings *fds,
1290  float time_per_frame,
1291  float frame_length,
1292  int frame,
1293  float dt)
1294 {
1295  FluidObjectBB *bb_maps = NULL;
1296  Object **effecobjs = NULL;
1297  uint numeffecobjs = 0;
1298  bool is_resume = (fds->cache_frame_pause_data == frame);
1299  bool is_first_frame = (frame == fds->cache_frame_start);
1300 
1301  effecobjs = BKE_collision_objects_create(
1302  depsgraph, ob, fds->effector_group, &numeffecobjs, eModifierType_Fluid);
1303 
1304  /* Update all effector related flags and ensure that corresponding grids get initialized. */
1305  update_obstacleflags(fds, effecobjs, numeffecobjs);
1306  ensure_obstaclefields(fds);
1307 
1308  /* Allocate effector map for each effector object. */
1309  bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps");
1310 
1311  /* Initialize effector map for each effector object. */
1312  compute_obstaclesemission(scene,
1313  bb_maps,
1314  depsgraph,
1315  dt,
1316  effecobjs,
1317  frame,
1318  frame_length,
1319  fds,
1320  numeffecobjs,
1321  time_per_frame);
1322 
1323  float *vel_x = manta_get_ob_velocity_x(fds->fluid);
1324  float *vel_y = manta_get_ob_velocity_y(fds->fluid);
1325  float *vel_z = manta_get_ob_velocity_z(fds->fluid);
1326  float *vel_x_guide = manta_get_guide_velocity_x(fds->fluid);
1327  float *vel_y_guide = manta_get_guide_velocity_y(fds->fluid);
1328  float *vel_z_guide = manta_get_guide_velocity_z(fds->fluid);
1329  float *phi_obs_in = manta_get_phiobs_in(fds->fluid);
1330  float *phi_obsstatic_in = manta_get_phiobsstatic_in(fds->fluid);
1331  float *phi_guide_in = manta_get_phiguide_in(fds->fluid);
1332  float *num_obstacles = manta_get_num_obstacle(fds->fluid);
1333  float *num_guides = manta_get_num_guide(fds->fluid);
1334  uint z;
1335 
1336  bool use_adaptivedomain = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
1337 
1338  /* Grid reset before writing again. */
1339  for (z = 0; z < fds->res[0] * fds->res[1] * fds->res[2]; z++) {
1340 
1341  /* Use big value that's not inf to initialize levelset grids. */
1342  if (phi_obs_in) {
1343  phi_obs_in[z] = PHI_MAX;
1344  }
1345  /* Only reset static effectors on first frame. Only use static effectors without adaptive
1346  * domains. */
1347  if (phi_obsstatic_in && (is_first_frame || use_adaptivedomain)) {
1348  phi_obsstatic_in[z] = PHI_MAX;
1349  }
1350  if (phi_guide_in) {
1351  phi_guide_in[z] = PHI_MAX;
1352  }
1353  if (num_obstacles) {
1354  num_obstacles[z] = 0;
1355  }
1356  if (num_guides) {
1357  num_guides[z] = 0;
1358  }
1359  if (vel_x && vel_y && vel_z) {
1360  vel_x[z] = 0.0f;
1361  vel_y[z] = 0.0f;
1362  vel_z[z] = 0.0f;
1363  }
1364  if (vel_x_guide && vel_y_guide && vel_z_guide) {
1365  vel_x_guide[z] = 0.0f;
1366  vel_y_guide[z] = 0.0f;
1367  vel_z_guide[z] = 0.0f;
1368  }
1369  }
1370 
1371  /* Prepare grids from effector objects. */
1372  for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
1373  Object *effecobj = effecobjs[effec_index];
1376 
1377  /* Sanity check. */
1378  if (!fmd2) {
1379  continue;
1380  }
1381 
1382  /* Cannot use static mode with adaptive domain.
1383  * The adaptive domain might expand and only later in the simulations discover the static
1384  * object. */
1385  bool is_static = is_static_object(effecobj) && !use_adaptivedomain;
1386 
1387  /* Check for initialized effector object. */
1388  if ((fmd2->type & MOD_FLUID_TYPE_EFFEC) && fmd2->effector) {
1389  FluidEffectorSettings *fes = fmd2->effector;
1390 
1391  /* Optimization: Skip effector objects with disabled effec flag. */
1392  if ((fes->flags & FLUID_EFFECTOR_USE_EFFEC) == 0) {
1393  continue;
1394  }
1395 
1396  FluidObjectBB *bb = &bb_maps[effec_index];
1397  float *velocity_map = bb->velocity;
1398  float *numobjs_map = bb->numobjs;
1399  float *distance_map = bb->distances;
1400 
1401  int gx, gy, gz, ex, ey, ez, dx, dy, dz;
1402  size_t e_index, d_index;
1403 
1404  /* Loop through every emission map cell. */
1405  for (gx = bb->min[0]; gx < bb->max[0]; gx++) {
1406  for (gy = bb->min[1]; gy < bb->max[1]; gy++) {
1407  for (gz = bb->min[2]; gz < bb->max[2]; gz++) {
1408  /* Compute emission map index. */
1409  ex = gx - bb->min[0];
1410  ey = gy - bb->min[1];
1411  ez = gz - bb->min[2];
1412  e_index = manta_get_index(ex, bb->res[0], ey, bb->res[1], ez);
1413 
1414  /* Get domain index. */
1415  dx = gx - fds->res_min[0];
1416  dy = gy - fds->res_min[1];
1417  dz = gz - fds->res_min[2];
1418  d_index = manta_get_index(dx, fds->res[0], dy, fds->res[1], dz);
1419  /* Make sure emission cell is inside the new domain boundary. */
1420  if (dx < 0 || dy < 0 || dz < 0 || dx >= fds->res[0] || dy >= fds->res[1] ||
1421  dz >= fds->res[2]) {
1422  continue;
1423  }
1424 
1425  if (fes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
1426  float *levelset = ((is_first_frame || is_resume) && is_static) ? phi_obsstatic_in :
1427  phi_obs_in;
1428  apply_effector_fields(fes,
1429  d_index,
1430  distance_map[e_index],
1431  levelset,
1432  numobjs_map[e_index],
1433  num_obstacles,
1434  &velocity_map[e_index * 3],
1435  vel_x,
1436  vel_y,
1437  vel_z);
1438  }
1439  if (fes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
1440  apply_effector_fields(fes,
1441  d_index,
1442  distance_map[e_index],
1443  phi_guide_in,
1444  numobjs_map[e_index],
1445  num_guides,
1446  &velocity_map[e_index * 3],
1447  vel_x_guide,
1448  vel_y_guide,
1449  vel_z_guide);
1450  }
1451  }
1452  }
1453  } /* End of effector map loop. */
1454  bb_freeData(bb);
1455  } /* End of effector object loop. */
1456  }
1457 
1458  BKE_collision_objects_free(effecobjs);
1459  if (bb_maps) {
1460  MEM_freeN(bb_maps);
1461  }
1462 }
1463 
1466 /* -------------------------------------------------------------------- */
1470 typedef struct EmitFromParticlesData {
1471  FluidFlowSettings *ffs;
1472  KDTree_3d *tree;
1473 
1474  FluidObjectBB *bb;
1475  float *particle_vel;
1476  int *min, *max, *res;
1477 
1478  float solid;
1479  float smooth;
1480 } EmitFromParticlesData;
1481 
1482 static void emit_from_particles_task_cb(void *__restrict userdata,
1483  const int z,
1484  const TaskParallelTLS *__restrict UNUSED(tls))
1485 {
1486  EmitFromParticlesData *data = userdata;
1487  FluidFlowSettings *ffs = data->ffs;
1488  FluidObjectBB *bb = data->bb;
1489 
1490  for (int x = data->min[0]; x < data->max[0]; x++) {
1491  for (int y = data->min[1]; y < data->max[1]; y++) {
1492  const int index = manta_get_index(
1493  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
1494  const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f};
1495 
1496  /* Find particle distance from the kdtree. */
1497  KDTreeNearest_3d nearest;
1498  const float range = data->solid + data->smooth;
1499  BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest);
1500 
1501  if (nearest.dist < range) {
1502  bb->influence[index] = (nearest.dist < data->solid) ?
1503  1.0f :
1504  (1.0f - (nearest.dist - data->solid) / data->smooth);
1505  /* Uses particle velocity as initial velocity for smoke. */
1506  if (ffs->flags & FLUID_FLOW_INITVELOCITY && (ffs->psys->part->phystype != PART_PHYS_NO)) {
1507  madd_v3_v3fl(
1508  &bb->velocity[index * 3], &data->particle_vel[nearest.index * 3], ffs->vel_multi);
1509  }
1510  }
1511  }
1512  }
1513 }
1514 
1515 static void emit_from_particles(Object *flow_ob,
1516  FluidDomainSettings *fds,
1517  FluidFlowSettings *ffs,
1518  FluidObjectBB *bb,
1520  Scene *scene,
1521  float dt)
1522 {
1523  if (ffs && ffs->psys && ffs->psys->part &&
1524  ELEM(ffs->psys->part->type, PART_EMITTER, PART_FLUID)) /* Is particle system selected. */
1525  {
1527  ParticleSystem *psys = ffs->psys;
1528  float *particle_pos;
1529  float *particle_vel;
1530  int totpart = psys->totpart, totchild;
1531  int p = 0;
1532  int valid_particles = 0;
1533  int bounds_margin = 1;
1534 
1535  /* radius based flow */
1536  const float solid = ffs->particle_size * 0.5f;
1537  const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
1538  KDTree_3d *tree = NULL;
1539 
1540  sim.depsgraph = depsgraph;
1541  sim.scene = scene;
1542  sim.ob = flow_ob;
1543  sim.psys = psys;
1544 
1545  psys_sim_data_init(&sim);
1546 
1547  /* initialize particle cache */
1548  if (psys->part->type == PART_HAIR) {
1549  /* TODO: PART_HAIR not supported whatsoever. */
1550  totchild = 0;
1551  }
1552  else {
1553  totchild = psys->totchild * psys->part->disp / 100;
1554  }
1555 
1556  particle_pos = MEM_callocN(sizeof(float[3]) * (totpart + totchild),
1557  "manta_flow_particles_pos");
1558  particle_vel = MEM_callocN(sizeof(float[3]) * (totpart + totchild),
1559  "manta_flow_particles_vel");
1560 
1561  /* setup particle radius emission if enabled */
1562  if (ffs->flags & FLUID_FLOW_USE_PART_SIZE) {
1563  tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild);
1564  bounds_margin = (int)ceil(solid + smooth);
1565  }
1566 
1567  /* calculate local position for each particle */
1568  for (p = 0; p < totpart + totchild; p++) {
1570  float *pos, *vel;
1571  if (p < totpart) {
1572  if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
1573  continue;
1574  }
1575  }
1576  else {
1577  /* handle child particle */
1578  ChildParticle *cpa = &psys->child[p - totpart];
1579  if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
1580  continue;
1581  }
1582  }
1583 
1584  /* `DEG_get_ctime(depsgraph)` does not give sub-frame time. */
1586 
1587  if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
1588  continue;
1589  }
1590 
1591  /* location */
1592  pos = &particle_pos[valid_particles * 3];
1593  copy_v3_v3(pos, state.co);
1594  manta_pos_to_cell(fds, pos);
1595 
1596  /* velocity */
1597  vel = &particle_vel[valid_particles * 3];
1598  copy_v3_v3(vel, state.vel);
1599  mul_mat3_m4_v3(fds->imat, &particle_vel[valid_particles * 3]);
1600 
1601  if (ffs->flags & FLUID_FLOW_USE_PART_SIZE) {
1602  BLI_kdtree_3d_insert(tree, valid_particles, pos);
1603  }
1604 
1605  /* calculate emission map bounds */
1606  bb_boundInsert(bb, pos);
1607  valid_particles++;
1608  }
1609 
1610  /* set emission map */
1611  clamp_bounds_in_domain(fds, bb->min, bb->max, NULL, NULL, bounds_margin, dt);
1612  bb_allocateData(bb, ffs->flags & FLUID_FLOW_INITVELOCITY, true);
1613 
1614  if (!(ffs->flags & FLUID_FLOW_USE_PART_SIZE)) {
1615  for (p = 0; p < valid_particles; p++) {
1616  int cell[3];
1617  size_t i = 0;
1618  size_t index = 0;
1619  int badcell = 0;
1620 
1621  /* 1. get corresponding cell */
1622  cell[0] = floor(particle_pos[p * 3]) - bb->min[0];
1623  cell[1] = floor(particle_pos[p * 3 + 1]) - bb->min[1];
1624  cell[2] = floor(particle_pos[p * 3 + 2]) - bb->min[2];
1625  /* check if cell is valid (in the domain boundary) */
1626  for (i = 0; i < 3; i++) {
1627  if ((cell[i] > bb->res[i] - 1) || (cell[i] < 0)) {
1628  badcell = 1;
1629  break;
1630  }
1631  }
1632  if (badcell) {
1633  continue;
1634  }
1635  /* get cell index */
1636  index = manta_get_index(cell[0], bb->res[0], cell[1], bb->res[1], cell[2]);
1637  /* Add influence to emission map */
1638  bb->influence[index] = 1.0f;
1639  /* Uses particle velocity as initial velocity for smoke */
1640  if (ffs->flags & FLUID_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) {
1641  madd_v3_v3fl(&bb->velocity[index * 3], &particle_vel[p * 3], ffs->vel_multi);
1642  }
1643  } /* particles loop */
1644  }
1645  else if (valid_particles > 0) { /* #FLUID_FLOW_USE_PART_SIZE */
1646  int min[3], max[3], res[3];
1647 
1648  /* setup loop bounds */
1649  for (int i = 0; i < 3; i++) {
1650  min[i] = bb->min[i];
1651  max[i] = bb->max[i];
1652  res[i] = bb->res[i];
1653  }
1654 
1655  BLI_kdtree_3d_balance(tree);
1656 
1657  EmitFromParticlesData data = {
1658  .ffs = ffs,
1659  .tree = tree,
1660  .bb = bb,
1661  .particle_vel = particle_vel,
1662  .min = min,
1663  .max = max,
1664  .res = res,
1665  .solid = solid,
1666  .smooth = smooth,
1667  };
1668 
1669  TaskParallelSettings settings;
1671  settings.min_iter_per_thread = 2;
1672  BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings);
1673  }
1674 
1675  if (ffs->flags & FLUID_FLOW_USE_PART_SIZE) {
1676  BLI_kdtree_3d_free(tree);
1677  }
1678 
1679  /* free data */
1680  if (particle_pos) {
1681  MEM_freeN(particle_pos);
1682  }
1683  if (particle_vel) {
1684  MEM_freeN(particle_vel);
1685  }
1686 
1687  psys_sim_data_free(&sim);
1688  }
1689 }
1690 
1691 /* Calculate map of (minimum) distances to flow/obstacle surface. Distances outside mesh are
1692  * positive, inside negative. */
1693 static void update_distances(int index,
1694  float *distance_map,
1695  BVHTreeFromMesh *tree_data,
1696  const float ray_start[3],
1697  float surface_thickness,
1698  bool use_plane_init)
1699 {
1700  float min_dist = PHI_MAX;
1701 
1702  /* Planar initialization: Find nearest cells around mesh. */
1703  if (use_plane_init) {
1704  BVHTreeNearest nearest = {0};
1705  nearest.index = -1;
1706  /* Distance between two opposing vertices in a unit cube.
1707  * I.e. the unit cube diagonal or sqrt(3).
1708  * This value is our nearest neighbor search distance. */
1709  const float surface_distance = 1.732;
1710  nearest.dist_sq = surface_distance *
1711  surface_distance; /* find_nearest uses squared distance. */
1712 
1713  /* Subtract optional surface thickness value and virtually increase the object size. */
1714  if (surface_thickness) {
1715  nearest.dist_sq += surface_thickness;
1716  }
1717 
1719  tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
1720  float ray[3] = {0};
1721  sub_v3_v3v3(ray, ray_start, nearest.co);
1722  min_dist = len_v3(ray);
1723  min_dist = (-1.0f) * fabsf(min_dist);
1724  }
1725  }
1726  /* Volumetric initialization: Ray-casts around mesh object. */
1727  else {
1728  /* Ray-casts in 26 directions.
1729  * (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */
1730  float ray_dirs[26][3] = {
1731  {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f},
1732  {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f},
1733  {-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f},
1734  {-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f},
1735  {0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
1736  {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f},
1737  {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
1738 
1739  /* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face
1740  * normal direction. From this information it can be derived whether a cell is inside or
1741  * outside the mesh. */
1742  int miss_count = 0, dir_count = 0;
1743 
1744  for (int i = 0; i < ARRAY_SIZE(ray_dirs); i++) {
1745  BVHTreeRayHit hit_tree = {0};
1746  hit_tree.index = -1;
1747  hit_tree.dist = PHI_MAX;
1748 
1749  normalize_v3(ray_dirs[i]);
1750  BLI_bvhtree_ray_cast(tree_data->tree,
1751  ray_start,
1752  ray_dirs[i],
1753  0.0f,
1754  &hit_tree,
1755  tree_data->raycast_callback,
1756  tree_data);
1757 
1758  /* Ray did not hit mesh.
1759  * Current point definitely not inside mesh. Inside mesh as all rays have to hit. */
1760  if (hit_tree.index == -1) {
1761  miss_count++;
1762  /* Skip this ray since nothing was hit. */
1763  continue;
1764  }
1765 
1766  /* Ray and normal are pointing in opposite directions. */
1767  if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
1768  dir_count++;
1769  }
1770 
1771  if (hit_tree.dist < min_dist) {
1772  min_dist = hit_tree.dist;
1773  }
1774  }
1775 
1776  /* Point lies inside mesh. Use negative sign for distance value.
1777  * This "if statement" has 2 conditions that can be true for points outside mesh. */
1778  if (!(miss_count > 0 || dir_count == ARRAY_SIZE(ray_dirs))) {
1779  min_dist = (-1.0f) * fabsf(min_dist);
1780  }
1781 
1782  /* Subtract optional surface thickness value and virtually increase the object size. */
1783  if (surface_thickness) {
1784  min_dist -= surface_thickness;
1785  }
1786  }
1787 
1788  /* Update global distance array but ensure that older entries are not overridden. */
1789  distance_map[index] = MIN2(distance_map[index], min_dist);
1790 
1791  /* Sanity check: Ensure that distances don't explode. */
1792  CLAMP(distance_map[index], -PHI_MAX, PHI_MAX);
1793 }
1794 
1795 static void sample_mesh(FluidFlowSettings *ffs,
1796  const MVert *mvert,
1797  const float (*vert_normals)[3],
1798  const MLoop *mloop,
1799  const MLoopTri *mlooptri,
1800  const MLoopUV *mloopuv,
1801  float *influence_map,
1802  float *velocity_map,
1803  int index,
1804  const int base_res[3],
1805  const float global_size[3],
1806  const float flow_center[3],
1807  BVHTreeFromMesh *tree_data,
1808  const float ray_start[3],
1809  const float *vert_vel,
1810  bool has_velocity,
1811  int defgrp_index,
1812  const MDeformVert *dvert,
1813  float x,
1814  float y,
1815  float z)
1816 {
1817  float ray_dir[3] = {1.0f, 0.0f, 0.0f};
1818  BVHTreeRayHit hit = {0};
1819  BVHTreeNearest nearest = {0};
1820 
1821  float volume_factor = 0.0f;
1822 
1823  hit.index = -1;
1824  hit.dist = PHI_MAX;
1825  nearest.index = -1;
1826 
1827  /* Distance between two opposing vertices in a unit cube.
1828  * I.e. the unit cube diagonal or sqrt(3).
1829  * This value is our nearest neighbor search distance. */
1830  const float surface_distance = 1.732;
1831  nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance. */
1832 
1833  bool is_gas_flow = ELEM(
1835 
1836  /* Emission strength for gases will be computed below.
1837  * For liquids it's not needed. Just set to non zero value
1838  * to allow initial velocity computation. */
1839  float emission_strength = (is_gas_flow) ? 0.0f : 1.0f;
1840 
1841  /* Emission inside the flow object. */
1842  if (is_gas_flow && ffs->volume_density) {
1843  if (BLI_bvhtree_ray_cast(tree_data->tree,
1844  ray_start,
1845  ray_dir,
1846  0.0f,
1847  &hit,
1848  tree_data->raycast_callback,
1849  tree_data) != -1) {
1850  float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2];
1851  /* If ray and hit face normal are facing same direction hit point is inside a closed mesh. */
1852  if (dot >= 0) {
1853  /* Also cast a ray in opposite direction to make sure point is at least surrounded by two
1854  * faces. */
1855  negate_v3(ray_dir);
1856  hit.index = -1;
1857  hit.dist = PHI_MAX;
1858 
1859  BLI_bvhtree_ray_cast(tree_data->tree,
1860  ray_start,
1861  ray_dir,
1862  0.0f,
1863  &hit,
1864  tree_data->raycast_callback,
1865  tree_data);
1866  if (hit.index != -1) {
1867  volume_factor = ffs->volume_density;
1868  }
1869  }
1870  }
1871  }
1872 
1873  /* Find the nearest point on the mesh. */
1875  tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
1876  float weights[3];
1877  int v1, v2, v3, f_index = nearest.index;
1878  float hit_normal[3];
1879 
1880  /* Calculate barycentric weights for nearest point. */
1881  v1 = mloop[mlooptri[f_index].tri[0]].v;
1882  v2 = mloop[mlooptri[f_index].tri[1]].v;
1883  v3 = mloop[mlooptri[f_index].tri[2]].v;
1884  interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co);
1885 
1886  /* Compute emission strength for smoke flow. */
1887  if (is_gas_flow) {
1888  /* Emission from surface is based on UI configurable distance value. */
1889  if (ffs->surface_distance) {
1890  emission_strength = sqrtf(nearest.dist_sq) / ffs->surface_distance;
1891  CLAMP(emission_strength, 0.0f, 1.0f);
1892  emission_strength = pow(1.0f - emission_strength, 0.5f);
1893  }
1894  else {
1895  emission_strength = 0.0f;
1896  }
1897 
1898  /* Apply vertex group influence if it is being used. */
1899  if (defgrp_index != -1 && dvert) {
1900  float weight_mask = BKE_defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] +
1901  BKE_defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] +
1902  BKE_defvert_find_weight(&dvert[v3], defgrp_index) * weights[2];
1903  emission_strength *= weight_mask;
1904  }
1905 
1906  /* Apply emission texture. */
1907  if ((ffs->flags & FLUID_FLOW_TEXTUREEMIT) && ffs->noise_texture) {
1908  float tex_co[3] = {0};
1909  TexResult texres;
1910 
1912  tex_co[0] = ((x - flow_center[0]) / base_res[0]) / ffs->texture_size;
1913  tex_co[1] = ((y - flow_center[1]) / base_res[1]) / ffs->texture_size;
1914  tex_co[2] = ((z - flow_center[2]) / base_res[2] - ffs->texture_offset) /
1915  ffs->texture_size;
1916  }
1917  else if (mloopuv) {
1918  const float *uv[3];
1919  uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv;
1920  uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv;
1921  uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv;
1922 
1923  interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights);
1924 
1925  /* Map texture coord between -1.0f and 1.0f. */
1926  tex_co[0] = tex_co[0] * 2.0f - 1.0f;
1927  tex_co[1] = tex_co[1] * 2.0f - 1.0f;
1928  tex_co[2] = ffs->texture_offset;
1929  }
1930  BKE_texture_get_value(NULL, ffs->noise_texture, tex_co, &texres, false);
1931  emission_strength *= texres.tin;
1932  }
1933  }
1934 
1935  /* Initial velocity of flow object. Only compute velocity if emission is present. */
1936  if (ffs->flags & FLUID_FLOW_INITVELOCITY && velocity_map && emission_strength != 0.0) {
1937  /* Apply normal directional velocity. */
1938  if (ffs->vel_normal) {
1939  /* Interpolate vertex normal vectors to get nearest point normal. */
1941  hit_normal, vert_normals[v1], vert_normals[v2], vert_normals[v3], weights);
1942  normalize_v3(hit_normal);
1943 
1944  /* Apply normal directional velocity. */
1945  velocity_map[index * 3] += hit_normal[0] * ffs->vel_normal;
1946  velocity_map[index * 3 + 1] += hit_normal[1] * ffs->vel_normal;
1947  velocity_map[index * 3 + 2] += hit_normal[2] * ffs->vel_normal;
1948  }
1949  /* Apply object velocity. */
1950  if (has_velocity && ffs->vel_multi) {
1951  float hit_vel[3];
1953  hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
1954  velocity_map[index * 3] += hit_vel[0] * ffs->vel_multi;
1955  velocity_map[index * 3 + 1] += hit_vel[1] * ffs->vel_multi;
1956  velocity_map[index * 3 + 2] += hit_vel[2] * ffs->vel_multi;
1957 # ifdef DEBUG_PRINT
1958  /* Debugging: Print flow object velocities. */
1959  printf("adding flow object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
1960 # endif
1961  }
1962  /* Convert xyz velocities flow settings from world to grid space. */
1963  float convert_vel[3];
1964  copy_v3_v3(convert_vel, ffs->vel_coord);
1965  float time_mult = 1.0 / (25.0f * DT_DEFAULT);
1966  float size_mult = MAX3(base_res[0], base_res[1], base_res[2]) /
1968  mul_v3_v3fl(convert_vel, ffs->vel_coord, size_mult * time_mult);
1969 
1970  velocity_map[index * 3] += convert_vel[0];
1971  velocity_map[index * 3 + 1] += convert_vel[1];
1972  velocity_map[index * 3 + 2] += convert_vel[2];
1973 # ifdef DEBUG_PRINT
1974  printf("initial vel: [%f, %f, %f]\n",
1975  velocity_map[index * 3],
1976  velocity_map[index * 3 + 1],
1977  velocity_map[index * 3 + 2]);
1978 # endif
1979  }
1980  }
1981 
1982  /* Apply final influence value but also consider volume initialization factor. */
1983  influence_map[index] = MAX2(volume_factor, emission_strength);
1984 }
1985 
1986 typedef struct EmitFromDMData {
1987  FluidDomainSettings *fds;
1988  FluidFlowSettings *ffs;
1989 
1990  const MVert *mvert;
1991  const float (*vert_normals)[3];
1992  const MLoop *mloop;
1993  const MLoopTri *mlooptri;
1994  const MLoopUV *mloopuv;
1995  const MDeformVert *dvert;
1996  int defgrp_index;
1997 
1999  FluidObjectBB *bb;
2000 
2001  bool has_velocity;
2002  float *vert_vel;
2003  float *flow_center;
2004  int *min, *max, *res;
2005 } EmitFromDMData;
2006 
2007 static void emit_from_mesh_task_cb(void *__restrict userdata,
2008  const int z,
2009  const TaskParallelTLS *__restrict UNUSED(tls))
2010 {
2011  EmitFromDMData *data = userdata;
2012  FluidObjectBB *bb = data->bb;
2013 
2014  for (int x = data->min[0]; x < data->max[0]; x++) {
2015  for (int y = data->min[1]; y < data->max[1]; y++) {
2016  const int index = manta_get_index(
2017  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
2018  const float ray_start[3] = {((float)x) + 0.5f, ((float)y) + 0.5f, ((float)z) + 0.5f};
2019 
2020  /* Compute emission only for flow objects that produce fluid (i.e. skip outflow objects).
2021  * Result in bb->influence. Also computes initial velocities. Result in bb->velocity. */
2023  sample_mesh(data->ffs,
2024  data->mvert,
2025  data->vert_normals,
2026  data->mloop,
2027  data->mlooptri,
2028  data->mloopuv,
2029  bb->influence,
2030  bb->velocity,
2031  index,
2032  data->fds->base_res,
2033  data->fds->global_size,
2034  data->flow_center,
2035  data->tree,
2036  ray_start,
2037  data->vert_vel,
2038  data->has_velocity,
2039  data->defgrp_index,
2040  data->dvert,
2041  (float)x,
2042  (float)y,
2043  (float)z);
2044  }
2045 
2046  /* Calculate levelset values from meshes. Result in bb->distances. */
2047  update_distances(index,
2048  bb->distances,
2049  data->tree,
2050  ray_start,
2051  data->ffs->surface_distance,
2052  data->ffs->flags & FLUID_FLOW_USE_PLANE_INIT);
2053  }
2054  }
2055 }
2056 
2057 static void emit_from_mesh(
2058  Object *flow_ob, FluidDomainSettings *fds, FluidFlowSettings *ffs, FluidObjectBB *bb, float dt)
2059 {
2060  if (ffs->mesh) {
2061  BVHTreeFromMesh tree_data = {NULL};
2062  int i;
2063 
2064  float *vert_vel = NULL;
2065  bool has_velocity = false;
2066 
2067  int defgrp_index = ffs->vgroup_density - 1;
2068  float flow_center[3] = {0};
2069  int min[3], max[3], res[3];
2070 
2071  /* Copy mesh for thread safety as we modify it.
2072  * Main issue is its VertArray being modified, then replaced and freed. */
2073  Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh, true);
2074 
2075  /* Duplicate vertices to modify. */
2076  if (me->mvert) {
2077  me->mvert = MEM_dupallocN(me->mvert);
2079  }
2080 
2081  MVert *mvert = me->mvert;
2082  const MLoop *mloop = me->mloop;
2083  const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
2084  const int numverts = me->totvert;
2085  const MDeformVert *dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
2086  const MLoopUV *mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ffs->uvlayer_name);
2087 
2088  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
2089  vert_vel = MEM_callocN(sizeof(float[3]) * numverts, "manta_flow_velocity");
2090 
2091  if (ffs->numverts != numverts || !ffs->verts_old) {
2092  if (ffs->verts_old) {
2093  MEM_freeN(ffs->verts_old);
2094  }
2095  ffs->verts_old = MEM_callocN(sizeof(float[3]) * numverts, "manta_flow_verts_old");
2096  ffs->numverts = numverts;
2097  }
2098  else {
2099  has_velocity = true;
2100  }
2101  }
2102 
2103  /* Transform mesh vertices to domain grid space for fast lookups.
2104  * This is valid because the mesh is copied above. */
2106  float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
2107  for (i = 0; i < numverts; i++) {
2108  /* Vertex position. */
2109  mul_m4_v3(flow_ob->obmat, mvert[i].co);
2110  manta_pos_to_cell(fds, mvert[i].co);
2111 
2112  /* Vertex normal. */
2113  mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]);
2114  mul_mat3_m4_v3(fds->imat, vert_normals[i]);
2115  normalize_v3(vert_normals[i]);
2116 
2117  /* Vertex velocity. */
2118  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
2119  float co[3];
2120  add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
2121  if (has_velocity) {
2122  sub_v3_v3v3(&vert_vel[i * 3], co, &ffs->verts_old[i * 3]);
2123  mul_v3_fl(&vert_vel[i * 3], 1.0 / dt);
2124  }
2125  copy_v3_v3(&ffs->verts_old[i * 3], co);
2126  }
2127 
2128  /* Calculate emission map bounds. */
2129  bb_boundInsert(bb, mvert[i].co);
2130  }
2131  mul_m4_v3(flow_ob->obmat, flow_center);
2132  manta_pos_to_cell(fds, flow_center);
2133 
2134  /* Set emission map.
2135  * Use 3 cell diagonals as margin (3 * 1.732 = 5.196). */
2136  int bounds_margin = (int)ceil(5.196);
2137  clamp_bounds_in_domain(fds, bb->min, bb->max, NULL, NULL, bounds_margin, dt);
2138  bb_allocateData(bb, ffs->flags & FLUID_FLOW_INITVELOCITY, true);
2139 
2140  /* Setup loop bounds. */
2141  for (i = 0; i < 3; i++) {
2142  min[i] = bb->min[i];
2143  max[i] = bb->max[i];
2144  res[i] = bb->res[i];
2145  }
2146 
2147  /* Skip flow sampling loop if object has disabled flow. */
2148  bool use_flow = ffs->flags & FLUID_FLOW_USE_INFLOW;
2149  if (use_flow && BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) {
2150 
2151  EmitFromDMData data = {
2152  .fds = fds,
2153  .ffs = ffs,
2154  .mvert = mvert,
2155  .vert_normals = vert_normals,
2156  .mloop = mloop,
2157  .mlooptri = mlooptri,
2158  .mloopuv = mloopuv,
2159  .dvert = dvert,
2160  .defgrp_index = defgrp_index,
2161  .tree = &tree_data,
2162  .bb = bb,
2163  .has_velocity = has_velocity,
2164  .vert_vel = vert_vel,
2165  .flow_center = flow_center,
2166  .min = min,
2167  .max = max,
2168  .res = res,
2169  };
2170 
2171  TaskParallelSettings settings;
2173  settings.min_iter_per_thread = 2;
2174  BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings);
2175  }
2176  /* Free bvh tree. */
2177  free_bvhtree_from_mesh(&tree_data);
2178 
2179  if (vert_vel) {
2180  MEM_freeN(vert_vel);
2181  }
2182  if (me->mvert) {
2183  MEM_freeN(me->mvert);
2184  }
2185  BKE_id_free(NULL, me);
2186  }
2187 }
2188 
2191 /* -------------------------------------------------------------------- */
2195 static void adaptive_domain_adjust(
2196  FluidDomainSettings *fds, Object *ob, FluidObjectBB *bb_maps, uint numflowobj, float dt)
2197 {
2198  /* calculate domain shift for current frame */
2199  int new_shift[3] = {0};
2200  int total_shift[3];
2201  float frame_shift_f[3];
2202  float ob_loc[3] = {0};
2203 
2204  mul_m4_v3(ob->obmat, ob_loc);
2205 
2206  sub_v3_v3v3(frame_shift_f, ob_loc, fds->prev_loc);
2207  copy_v3_v3(fds->prev_loc, ob_loc);
2208  /* convert global space shift to local "cell" space */
2209  mul_mat3_m4_v3(fds->imat, frame_shift_f);
2210  frame_shift_f[0] = frame_shift_f[0] / fds->cell_size[0];
2211  frame_shift_f[1] = frame_shift_f[1] / fds->cell_size[1];
2212  frame_shift_f[2] = frame_shift_f[2] / fds->cell_size[2];
2213  /* add to total shift */
2214  add_v3_v3(fds->shift_f, frame_shift_f);
2215  /* convert to integer */
2216  total_shift[0] = (int)(floorf(fds->shift_f[0]));
2217  total_shift[1] = (int)(floorf(fds->shift_f[1]));
2218  total_shift[2] = (int)(floorf(fds->shift_f[2]));
2219  int temp_shift[3];
2220  copy_v3_v3_int(temp_shift, fds->shift);
2221  sub_v3_v3v3_int(new_shift, total_shift, fds->shift);
2222  copy_v3_v3_int(fds->shift, total_shift);
2223 
2224  /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */
2225  fds->p0[0] = fds->dp0[0] - fds->cell_size[0] * (fds->shift_f[0] - total_shift[0] - 0.5f);
2226  fds->p0[1] = fds->dp0[1] - fds->cell_size[1] * (fds->shift_f[1] - total_shift[1] - 0.5f);
2227  fds->p0[2] = fds->dp0[2] - fds->cell_size[2] * (fds->shift_f[2] - total_shift[2] - 0.5f);
2228  fds->p1[0] = fds->p0[0] + fds->cell_size[0] * fds->base_res[0];
2229  fds->p1[1] = fds->p0[1] + fds->cell_size[1] * fds->base_res[1];
2230  fds->p1[2] = fds->p0[2] + fds->cell_size[2] * fds->base_res[2];
2231 
2232  /* adjust domain resolution */
2233  const int block_size = fds->noise_scale;
2234  int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
2235  int total_cells = 1, res_changed = 0, shift_changed = 0;
2236  float min_vel[3], max_vel[3];
2237  int x, y, z;
2238  float *density = manta_smoke_get_density(fds->fluid);
2239  float *fuel = manta_smoke_get_fuel(fds->fluid);
2240  float *bigdensity = manta_noise_get_density(fds->fluid);
2241  float *bigfuel = manta_noise_get_fuel(fds->fluid);
2242  float *vx = manta_get_velocity_x(fds->fluid);
2243  float *vy = manta_get_velocity_y(fds->fluid);
2244  float *vz = manta_get_velocity_z(fds->fluid);
2245  int wt_res[3];
2246 
2247  if (fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
2248  manta_noise_get_res(fds->fluid, wt_res);
2249  }
2250 
2251  INIT_MINMAX(min_vel, max_vel);
2252 
2253  /* Calculate bounds for current domain content */
2254  for (x = fds->res_min[0]; x < fds->res_max[0]; x++) {
2255  for (y = fds->res_min[1]; y < fds->res_max[1]; y++) {
2256  for (z = fds->res_min[2]; z < fds->res_max[2]; z++) {
2257  int xn = x - new_shift[0];
2258  int yn = y - new_shift[1];
2259  int zn = z - new_shift[2];
2260  int index;
2261  float max_den;
2262 
2263  /* skip if cell already belongs to new area */
2264  if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] &&
2265  zn <= max[2]) {
2266  continue;
2267  }
2268 
2269  index = manta_get_index(x - fds->res_min[0],
2270  fds->res[0],
2271  y - fds->res_min[1],
2272  fds->res[1],
2273  z - fds->res_min[2]);
2274  max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index];
2275 
2276  /* Check high resolution bounds if max density isn't already high enough. */
2277  if (max_den < fds->adapt_threshold && fds->flags & FLUID_DOMAIN_USE_NOISE && fds->fluid) {
2278  int i, j, k;
2279  /* high res grid index */
2280  int xx = (x - fds->res_min[0]) * block_size;
2281  int yy = (y - fds->res_min[1]) * block_size;
2282  int zz = (z - fds->res_min[2]) * block_size;
2283 
2284  for (i = 0; i < block_size; i++) {
2285  for (j = 0; j < block_size; j++) {
2286  for (k = 0; k < block_size; k++) {
2287  int big_index = manta_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k);
2288  float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) :
2289  bigdensity[big_index];
2290  if (den > max_den) {
2291  max_den = den;
2292  }
2293  }
2294  }
2295  }
2296  }
2297 
2298  /* content bounds (use shifted coordinates) */
2299  if (max_den >= fds->adapt_threshold) {
2300  if (min[0] > xn) {
2301  min[0] = xn;
2302  }
2303  if (min[1] > yn) {
2304  min[1] = yn;
2305  }
2306  if (min[2] > zn) {
2307  min[2] = zn;
2308  }
2309  if (max[0] < xn) {
2310  max[0] = xn;
2311  }
2312  if (max[1] < yn) {
2313  max[1] = yn;
2314  }
2315  if (max[2] < zn) {
2316  max[2] = zn;
2317  }
2318  }
2319 
2320  /* velocity bounds */
2321  if (min_vel[0] > vx[index]) {
2322  min_vel[0] = vx[index];
2323  }
2324  if (min_vel[1] > vy[index]) {
2325  min_vel[1] = vy[index];
2326  }
2327  if (min_vel[2] > vz[index]) {
2328  min_vel[2] = vz[index];
2329  }
2330  if (max_vel[0] < vx[index]) {
2331  max_vel[0] = vx[index];
2332  }
2333  if (max_vel[1] < vy[index]) {
2334  max_vel[1] = vy[index];
2335  }
2336  if (max_vel[2] < vz[index]) {
2337  max_vel[2] = vz[index];
2338  }
2339  }
2340  }
2341  }
2342 
2343  /* also apply emission maps */
2344  for (int i = 0; i < numflowobj; i++) {
2345  FluidObjectBB *bb = &bb_maps[i];
2346 
2347  for (x = bb->min[0]; x < bb->max[0]; x++) {
2348  for (y = bb->min[1]; y < bb->max[1]; y++) {
2349  for (z = bb->min[2]; z < bb->max[2]; z++) {
2350  int index = manta_get_index(
2351  x - bb->min[0], bb->res[0], y - bb->min[1], bb->res[1], z - bb->min[2]);
2352  float max_den = bb->influence[index];
2353 
2354  /* density bounds */
2355  if (max_den >= fds->adapt_threshold) {
2356  if (min[0] > x) {
2357  min[0] = x;
2358  }
2359  if (min[1] > y) {
2360  min[1] = y;
2361  }
2362  if (min[2] > z) {
2363  min[2] = z;
2364  }
2365  if (max[0] < x) {
2366  max[0] = x;
2367  }
2368  if (max[1] < y) {
2369  max[1] = y;
2370  }
2371  if (max[2] < z) {
2372  max[2] = z;
2373  }
2374  }
2375  }
2376  }
2377  }
2378  }
2379 
2380  /* calculate new bounds based on these values */
2381  clamp_bounds_in_domain(fds, min, max, min_vel, max_vel, fds->adapt_margin + 1, dt);
2382 
2383  for (int i = 0; i < 3; i++) {
2384  /* calculate new resolution */
2385  res[i] = max[i] - min[i];
2386  total_cells *= res[i];
2387 
2388  if (new_shift[i]) {
2389  shift_changed = 1;
2390  }
2391 
2392  /* if no content set minimum dimensions */
2393  if (res[i] <= 0) {
2394  int j;
2395  for (j = 0; j < 3; j++) {
2396  min[j] = 0;
2397  max[j] = 1;
2398  res[j] = 1;
2399  }
2400  res_changed = 1;
2401  total_cells = 1;
2402  break;
2403  }
2404  if (min[i] != fds->res_min[i] || max[i] != fds->res_max[i]) {
2405  res_changed = 1;
2406  }
2407  }
2408 
2409  if (res_changed || shift_changed) {
2411  fds, fds->res, res, fds->res_min, min, fds->res_max, temp_shift, total_shift);
2412 
2413  /* set new domain dimensions */
2414  copy_v3_v3_int(fds->res_min, min);
2415  copy_v3_v3_int(fds->res_max, max);
2416  copy_v3_v3_int(fds->res, res);
2417  fds->total_cells = total_cells;
2418 
2419  /* Redo adapt time step in manta to refresh solver state (ie time variables) */
2421  }
2422 }
2423 
2424 BLI_INLINE void apply_outflow_fields(int index,
2425  float distance_value,
2426  float *density,
2427  float *heat,
2428  float *fuel,
2429  float *react,
2430  float *color_r,
2431  float *color_g,
2432  float *color_b,
2433  float *phiout)
2434 {
2435  /* Set levelset value for liquid inflow.
2436  * Ensure that distance value is "joined" into the levelset. */
2437  if (phiout) {
2438  phiout[index] = MIN2(distance_value, phiout[index]);
2439  }
2440 
2441  /* Set smoke outflow, i.e. reset cell to zero. */
2442  if (density) {
2443  density[index] = 0.0f;
2444  }
2445  if (heat) {
2446  heat[index] = 0.0f;
2447  }
2448  if (fuel) {
2449  fuel[index] = 0.0f;
2450  react[index] = 0.0f;
2451  }
2452  if (color_r) {
2453  color_r[index] = 0.0f;
2454  color_g[index] = 0.0f;
2455  color_b[index] = 0.0f;
2456  }
2457 }
2458 
2459 BLI_INLINE void apply_inflow_fields(FluidFlowSettings *ffs,
2460  float emission_value,
2461  float distance_value,
2462  int index,
2463  float *density_in,
2464  const float *density,
2465  float *heat_in,
2466  const float *heat,
2467  float *fuel_in,
2468  const float *fuel,
2469  float *react_in,
2470  const float *react,
2471  float *color_r_in,
2472  const float *color_r,
2473  float *color_g_in,
2474  const float *color_g,
2475  float *color_b_in,
2476  const float *color_b,
2477  float *phi_in,
2478  float *emission_in)
2479 {
2480  /* Set levelset value for liquid inflow.
2481  * Ensure that distance value is "joined" into the levelset. */
2482  if (phi_in) {
2483  phi_in[index] = MIN2(distance_value, phi_in[index]);
2484  }
2485 
2486  /* Set emission value for smoke inflow.
2487  * Ensure that emission value is "maximized". */
2488  if (emission_in) {
2489  emission_in[index] = MAX2(emission_value, emission_in[index]);
2490  }
2491 
2492  /* Set inflow for smoke from here on. */
2493  int absolute_flow = (ffs->flags & FLUID_FLOW_ABSOLUTE);
2494  float dens_old = (density) ? density[index] : 0.0;
2495  // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */
2496  float dens_flow = (ffs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * ffs->density;
2497  float fuel_flow = (fuel) ? emission_value * ffs->fuel_amount : 0.0f;
2498  /* Set heat inflow. */
2499  if (heat && heat_in) {
2500  if (emission_value > 0.0f) {
2501  heat_in[index] = ADD_IF_LOWER(heat[index], ffs->temperature);
2502  }
2503  }
2504 
2505  /* Set density and fuel - absolute mode. */
2506  if (absolute_flow) {
2507  if (density && density_in) {
2508  if (ffs->type != FLUID_FLOW_TYPE_FIRE && dens_flow > density[index]) {
2509  /* Use MAX2 to preserve values from other emitters at this cell. */
2510  density_in[index] = MAX2(dens_flow, density_in[index]);
2511  }
2512  }
2513  if (fuel && fuel_in) {
2514  if (ffs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow && fuel_flow > fuel[index]) {
2515  /* Use MAX2 to preserve values from other emitters at this cell. */
2516  fuel_in[index] = MAX2(fuel_flow, fuel_in[index]);
2517  }
2518  }
2519  }
2520  /* Set density and fuel - additive mode. */
2521  else {
2522  if (density && density_in) {
2523  if (ffs->type != FLUID_FLOW_TYPE_FIRE) {
2524  density_in[index] += dens_flow;
2525  CLAMP(density_in[index], 0.0f, 1.0f);
2526  }
2527  }
2528  if (fuel && fuel_in) {
2529  if (ffs->type != FLUID_FLOW_TYPE_SMOKE && ffs->fuel_amount) {
2530  fuel_in[index] += fuel_flow;
2531  CLAMP(fuel_in[index], 0.0f, 10.0f);
2532  }
2533  }
2534  }
2535 
2536  /* Set color. */
2537  if (color_r && color_r_in) {
2538  if (dens_flow) {
2539  float total_dens = density[index] / (dens_old + dens_flow);
2540  color_r_in[index] = (color_r[index] + ffs->color[0] * dens_flow) * total_dens;
2541  color_g_in[index] = (color_g[index] + ffs->color[1] * dens_flow) * total_dens;
2542  color_b_in[index] = (color_b[index] + ffs->color[2] * dens_flow) * total_dens;
2543  }
2544  }
2545 
2546  /* Set fire reaction coordinate. */
2547  if (fuel && fuel_in) {
2548  /* Instead of using 1.0 for all new fuel add slight falloff to reduce flow blocky-ness. */
2549  float value = 1.0f - pow2f(1.0f - emission_value);
2550 
2551  if (fuel_in[index] > FLT_EPSILON && value > react[index]) {
2552  float f = fuel_flow / fuel_in[index];
2553  react_in[index] = value * f + (1.0f - f) * react[index];
2554  CLAMP(react_in[index], 0.0f, value);
2555  }
2556  }
2557 }
2558 
2559 static void ensure_flowsfields(FluidDomainSettings *fds)
2560 {
2562  manta_ensure_invelocity(fds->fluid, fds->fmd);
2563  }
2565  manta_ensure_outflow(fds->fluid, fds->fmd);
2566  }
2568  manta_smoke_ensure_heat(fds->fluid, fds->fmd);
2569  }
2571  manta_smoke_ensure_fire(fds->fluid, fds->fmd);
2572  }
2574  /* Initialize all smoke with "active_color". */
2575  manta_smoke_ensure_colors(fds->fluid, fds->fmd);
2576  }
2577  if (fds->type == FLUID_DOMAIN_TYPE_LIQUID &&
2582  }
2583  manta_update_pointers(fds->fluid, fds->fmd, false);
2584 }
2585 
2586 static void update_flowsflags(FluidDomainSettings *fds, Object **flowobjs, int numflowobj)
2587 {
2588  int active_fields = fds->active_fields;
2589  uint flow_index;
2590 
2591  /* First, remove all flags that we want to update. */
2594  active_fields &= ~prev_flags;
2595 
2596  /* Monitor active fields based on flow settings. */
2597  for (flow_index = 0; flow_index < numflowobj; flow_index++) {
2598  Object *flow_ob = flowobjs[flow_index];
2601 
2602  /* Sanity check. */
2603  if (!fmd2) {
2604  continue;
2605  }
2606 
2607  /* Activate specific grids if at least one flow object requires this grid. */
2608  if ((fmd2->type & MOD_FLUID_TYPE_FLOW) && fmd2->flow) {
2609  FluidFlowSettings *ffs = fmd2->flow;
2610  if (!ffs) {
2611  break;
2612  }
2613  if (ffs->flags & FLUID_FLOW_NEEDS_UPDATE) {
2614  ffs->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
2616  }
2617  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
2618  active_fields |= FLUID_DOMAIN_ACTIVE_INVEL;
2619  }
2620  if (ffs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) {
2621  active_fields |= FLUID_DOMAIN_ACTIVE_OUTFLOW;
2622  }
2623  /* liquids done from here */
2624  if (fds->type == FLUID_DOMAIN_TYPE_LIQUID) {
2625  continue;
2626  }
2627 
2628  /* Activate heat field if a flow object produces any heat. */
2629  if (ffs->temperature != 0.0) {
2630  active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
2631  }
2632  /* Activate fuel field if a flow object is of fire type. */
2633  if (ffs->fuel_amount != 0.0 || ffs->type == FLUID_FLOW_TYPE_FIRE ||
2634  ffs->type == FLUID_FLOW_TYPE_SMOKEFIRE) {
2635  active_fields |= FLUID_DOMAIN_ACTIVE_FIRE;
2636  }
2637  /* Activate color field if flows add smoke with varying colors. */
2638  if (ffs->density != 0.0 &&
2640  if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
2641  copy_v3_v3(fds->active_color, ffs->color);
2642  active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
2643  }
2644  else if (!equals_v3v3(fds->active_color, ffs->color)) {
2645  copy_v3_v3(fds->active_color, ffs->color);
2646  active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
2647  }
2648  }
2649  }
2650  }
2651  /* Monitor active fields based on domain settings. */
2652  if (fds->type == FLUID_DOMAIN_TYPE_GAS && active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
2653  /* Heat is always needed for fire. */
2654  active_fields |= FLUID_DOMAIN_ACTIVE_HEAT;
2655  /* Also activate colors if domain smoke color differs from active color. */
2656  if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) {
2658  active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET;
2659  }
2660  else if (!equals_v3v3(fds->active_color, fds->flame_smoke_color)) {
2662  active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
2663  }
2664  }
2665  fds->active_fields = active_fields;
2666 }
2667 
2668 static bool escape_flowsobject(Object *flowobj,
2669  FluidDomainSettings *fds,
2670  FluidFlowSettings *ffs,
2671  int frame)
2672 {
2673  bool use_velocity = (ffs->flags & FLUID_FLOW_INITVELOCITY);
2674  bool is_static = is_static_object(flowobj);
2675 
2676  bool liquid_flow = ffs->type == FLUID_FLOW_TYPE_LIQUID;
2677  bool gas_flow = ELEM(
2679  bool is_geometry = (ffs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
2680 
2681  bool liquid_domain = fds->type == FLUID_DOMAIN_TYPE_LIQUID;
2682  bool gas_domain = fds->type == FLUID_DOMAIN_TYPE_GAS;
2684  bool is_resume = (fds->cache_frame_pause_data == frame);
2685  bool is_first_frame = (fds->cache_frame_start == frame);
2686 
2687  /* Cannot use static mode with adaptive domain.
2688  * The adaptive domain might expand and only later discover the static object. */
2689  if (is_adaptive) {
2690  is_static = false;
2691  }
2692  /* No need to compute emission value if it won't be applied. */
2693  if (liquid_flow && is_geometry && !is_first_frame) {
2694  return true;
2695  }
2696  /* Skip flow object if it does not "belong" to this domain type. */
2697  if ((liquid_flow && gas_domain) || (gas_flow && liquid_domain)) {
2698  return true;
2699  }
2700  /* Optimization: Static liquid flow objects don't need emission after first frame.
2701  * TODO(sebbas): Also do not use static mode if initial velocities are enabled. */
2702  if (liquid_flow && is_static && !is_first_frame && !is_resume && !use_velocity) {
2703  return true;
2704  }
2705  return false;
2706 }
2707 
2708 static void compute_flowsemission(Scene *scene,
2709  FluidObjectBB *bb_maps,
2710  struct Depsgraph *depsgraph,
2711  float dt,
2712  Object **flowobjs,
2713  int frame,
2714  float frame_length,
2715  FluidDomainSettings *fds,
2716  uint numflowobjs,
2717  float time_per_frame)
2718 {
2719  bool is_first_frame = (frame == fds->cache_frame_start);
2720 
2721  /* Prepare flow emission maps. */
2722  for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
2723  Object *flowobj = flowobjs[flow_index];
2726 
2727  /* Sanity check. */
2728  if (!fmd2) {
2729  continue;
2730  }
2731 
2732  /* Check for initialized flow object. */
2733  if ((fmd2->type & MOD_FLUID_TYPE_FLOW) && fmd2->flow) {
2734  FluidFlowSettings *ffs = fmd2->flow;
2735  int subframes = ffs->subframes;
2736  FluidObjectBB *bb = &bb_maps[flow_index];
2737 
2738  /* Optimization: Skip this object under certain conditions. */
2739  if (escape_flowsobject(flowobj, fds, ffs, frame)) {
2740  continue;
2741  }
2742 
2743  /* First frame cannot have any subframes because there is (obviously) no previous frame from
2744  * where subframes could come from. */
2745  if (is_first_frame) {
2746  subframes = 0;
2747  }
2748 
2749  /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
2750  float sample_size = 1.0f / (float)(subframes + 1);
2751  float subframe_dt = dt * sample_size;
2752 
2753  /* Emission loop. When not using subframes this will loop only once. */
2754  for (int subframe = 0; subframe <= subframes; subframe++) {
2755  /* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
2756  FluidObjectBB bb_temp = {NULL};
2757 
2758  /* Set scene time */
2759  if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
2760  !is_first_frame) {
2761  scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
2762  scene->r.cfra = frame - 1;
2763  }
2764  else {
2765  scene->r.subframe = 0.0f;
2766  scene->r.cfra = frame;
2767  }
2768 
2769  /* Sanity check: subframe portion must be between 0 and 1. */
2770  CLAMP(scene->r.subframe, 0.0f, 1.0f);
2771 # ifdef DEBUG_PRINT
2772  /* Debugging: Print subframe information. */
2773  printf(
2774  "flow: frame (is first: %d): %d // scene current frame: %d // scene current subframe: "
2775  "%f\n",
2776  is_first_frame,
2777  frame,
2778  scene->r.cfra,
2779  scene->r.subframe);
2780 # endif
2781  /* Update frame time, this is considering current subframe fraction
2782  * BLI_mutex_lock() called in manta_step(), so safe to update subframe here
2783  * TODO(sebbas): Using BKE_scene_ctime_get(scene) instead of new DEG_get_ctime(depsgraph)
2784  * as subframes don't work with the latter yet. */
2787 
2788  /* Emission from particles. */
2789  if (ffs->source == FLUID_FLOW_SOURCE_PARTICLES) {
2790  if (subframes) {
2791  emit_from_particles(flowobj, fds, ffs, &bb_temp, depsgraph, scene, subframe_dt);
2792  }
2793  else {
2794  emit_from_particles(flowobj, fds, ffs, bb, depsgraph, scene, subframe_dt);
2795  }
2796  }
2797  /* Emission from mesh. */
2798  else if (ffs->source == FLUID_FLOW_SOURCE_MESH) {
2799  if (subframes) {
2800  emit_from_mesh(flowobj, fds, ffs, &bb_temp, subframe_dt);
2801  }
2802  else {
2803  emit_from_mesh(flowobj, fds, ffs, bb, subframe_dt);
2804  }
2805  }
2806  else {
2807  printf("Error: unknown flow emission source\n");
2808  }
2809 
2810  /* If this we emitted with temp emission map in this loop (subframe emission), we combine
2811  * the temp map with the original emission map. */
2812  if (subframes) {
2813  /* Combine emission maps. */
2814  bb_combineMaps(bb, &bb_temp, !(ffs->flags & FLUID_FLOW_ABSOLUTE), sample_size);
2815  bb_freeData(&bb_temp);
2816  }
2817  }
2818  }
2819  }
2820 # ifdef DEBUG_PRINT
2821  /* Debugging: Print time information. */
2822  printf("flow: frame: %d // time per frame: %f // frame length: %f // dt: %f\n",
2823  frame,
2824  time_per_frame,
2825  frame_length,
2826  dt);
2827 # endif
2828 }
2829 
2830 static void update_flowsfluids(struct Depsgraph *depsgraph,
2831  Scene *scene,
2832  Object *ob,
2833  FluidDomainSettings *fds,
2834  float time_per_frame,
2835  float frame_length,
2836  int frame,
2837  float dt)
2838 {
2839  FluidObjectBB *bb_maps = NULL;
2840  Object **flowobjs = NULL;
2841  uint numflowobjs = 0;
2842  bool is_resume = (fds->cache_frame_pause_data == frame);
2843  bool is_first_frame = (fds->cache_frame_start == frame);
2844 
2845  flowobjs = BKE_collision_objects_create(
2846  depsgraph, ob, fds->fluid_group, &numflowobjs, eModifierType_Fluid);
2847 
2848  /* Update all flow related flags and ensure that corresponding grids get initialized. */
2849  update_flowsflags(fds, flowobjs, numflowobjs);
2850  ensure_flowsfields(fds);
2851 
2852  /* Allocate emission map for each flow object. */
2853  bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobjs, "fluid_flow_bb_maps");
2854 
2855  /* Initialize emission map for each flow object. */
2856  compute_flowsemission(scene,
2857  bb_maps,
2858  depsgraph,
2859  dt,
2860  flowobjs,
2861  frame,
2862  frame_length,
2863  fds,
2864  numflowobjs,
2865  time_per_frame);
2866 
2867  /* Adjust domain size if needed. Only do this once for every frame. */
2869  adaptive_domain_adjust(fds, ob, bb_maps, numflowobjs, dt);
2870  }
2871 
2872  float *phi_in = manta_get_phi_in(fds->fluid);
2873  float *phistatic_in = manta_get_phistatic_in(fds->fluid);
2874  float *phiout_in = manta_get_phiout_in(fds->fluid);
2875  float *phioutstatic_in = manta_get_phioutstatic_in(fds->fluid);
2876 
2877  float *density = manta_smoke_get_density(fds->fluid);
2878  float *color_r = manta_smoke_get_color_r(fds->fluid);
2879  float *color_g = manta_smoke_get_color_g(fds->fluid);
2880  float *color_b = manta_smoke_get_color_b(fds->fluid);
2881  float *fuel = manta_smoke_get_fuel(fds->fluid);
2882  float *heat = manta_smoke_get_heat(fds->fluid);
2883  float *react = manta_smoke_get_react(fds->fluid);
2884 
2885  float *density_in = manta_smoke_get_density_in(fds->fluid);
2886  float *heat_in = manta_smoke_get_heat_in(fds->fluid);
2887  float *color_r_in = manta_smoke_get_color_r_in(fds->fluid);
2888  float *color_g_in = manta_smoke_get_color_g_in(fds->fluid);
2889  float *color_b_in = manta_smoke_get_color_b_in(fds->fluid);
2890  float *fuel_in = manta_smoke_get_fuel_in(fds->fluid);
2891  float *react_in = manta_smoke_get_react_in(fds->fluid);
2892  float *emission_in = manta_smoke_get_emission_in(fds->fluid);
2893 
2894  float *velx_initial = manta_get_in_velocity_x(fds->fluid);
2895  float *vely_initial = manta_get_in_velocity_y(fds->fluid);
2896  float *velz_initial = manta_get_in_velocity_z(fds->fluid);
2897 
2898  float *forcex = manta_get_force_x(fds->fluid);
2899  float *forcey = manta_get_force_y(fds->fluid);
2900  float *forcez = manta_get_force_z(fds->fluid);
2901 
2902  BLI_assert(forcex && forcey && forcez);
2903 
2904  /* Either all or no components have to exist. */
2905  BLI_assert((color_r && color_g && color_b) || (!color_r && !color_g && !color_b));
2906  BLI_assert((color_r_in && color_g_in && color_b_in) ||
2907  (!color_r_in && !color_g_in && !color_b_in));
2908  BLI_assert((velx_initial && vely_initial && velz_initial) ||
2909  (!velx_initial && !vely_initial && !velz_initial));
2910 
2911  uint z;
2912  /* Grid reset before writing again. */
2913  for (z = 0; z < fds->res[0] * fds->res[1] * fds->res[2]; z++) {
2914  /* Only reset static phi on first frame, dynamic phi gets reset every time. */
2915  if (phistatic_in && is_first_frame) {
2916  phistatic_in[z] = PHI_MAX;
2917  }
2918  if (phi_in) {
2919  phi_in[z] = PHI_MAX;
2920  }
2921  /* Only reset static phi on first frame, dynamic phi gets reset every time. */
2922  if (phioutstatic_in && is_first_frame) {
2923  phioutstatic_in[z] = PHI_MAX;
2924  }
2925  if (phiout_in) {
2926  phiout_in[z] = PHI_MAX;
2927  }
2928  /* Sync smoke inflow grids with their counterparts (simulation grids). */
2929  if (density_in) {
2930  density_in[z] = density[z];
2931  }
2932  if (heat_in) {
2933  heat_in[z] = heat[z];
2934  }
2935  if (color_r_in && color_g_in && color_b_in) {
2936  color_r_in[z] = color_r[z];
2937  color_g_in[z] = color_b[z];
2938  color_b_in[z] = color_g[z];
2939  }
2940  if (fuel_in) {
2941  fuel_in[z] = fuel[z];
2942  react_in[z] = react[z];
2943  }
2944  if (emission_in) {
2945  emission_in[z] = 0.0f;
2946  }
2947  if (velx_initial && vely_initial && velz_initial) {
2948  velx_initial[z] = 0.0f;
2949  vely_initial[z] = 0.0f;
2950  velz_initial[z] = 0.0f;
2951  }
2952  /* Reset forces here as update_effectors() is skipped when no external forces are present. */
2953  forcex[z] = 0.0f;
2954  forcey[z] = 0.0f;
2955  forcez[z] = 0.0f;
2956  }
2957 
2958  /* Apply emission data for every flow object. */
2959  for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
2960  Object *flowobj = flowobjs[flow_index];
2963 
2964  /* Sanity check. */
2965  if (!fmd2) {
2966  continue;
2967  }
2968 
2969  /* Check for initialized flow object. */
2970  if ((fmd2->type & MOD_FLUID_TYPE_FLOW) && fmd2->flow) {
2971  FluidFlowSettings *ffs = fmd2->flow;
2972 
2973  bool is_inflow = (ffs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW);
2974  bool is_geometry = (ffs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
2975  bool is_outflow = (ffs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW);
2976  bool is_static = is_static_object(flowobj) &&
2977  ((fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0);
2978 
2979  FluidObjectBB *bb = &bb_maps[flow_index];
2980  float *velocity_map = bb->velocity;
2981  float *emission_map = bb->influence;
2982  float *distance_map = bb->distances;
2983 
2984  int gx, gy, gz, ex, ey, ez, dx, dy, dz;
2985  size_t e_index, d_index;
2986 
2987  /* Loop through every emission map cell. */
2988  for (gx = bb->min[0]; gx < bb->max[0]; gx++) {
2989  for (gy = bb->min[1]; gy < bb->max[1]; gy++) {
2990  for (gz = bb->min[2]; gz < bb->max[2]; gz++) {
2991  /* Compute emission map index. */
2992  ex = gx - bb->min[0];
2993  ey = gy - bb->min[1];
2994  ez = gz - bb->min[2];
2995  e_index = manta_get_index(ex, bb->res[0], ey, bb->res[1], ez);
2996 
2997  /* Get domain index. */
2998  dx = gx - fds->res_min[0];
2999  dy = gy - fds->res_min[1];
3000  dz = gz - fds->res_min[2];
3001  d_index = manta_get_index(dx, fds->res[0], dy, fds->res[1], dz);
3002  /* Make sure emission cell is inside the new domain boundary. */
3003  if (dx < 0 || dy < 0 || dz < 0 || dx >= fds->res[0] || dy >= fds->res[1] ||
3004  dz >= fds->res[2]) {
3005  continue;
3006  }
3007 
3008  /* Delete fluid in outflow regions. */
3009  if (is_outflow) {
3010  float *levelset = ((is_first_frame || is_resume) && is_static) ? phioutstatic_in :
3011  phiout_in;
3012  apply_outflow_fields(d_index,
3013  distance_map[e_index],
3014  density_in,
3015  heat_in,
3016  fuel_in,
3017  react_in,
3018  color_r_in,
3019  color_g_in,
3020  color_b_in,
3021  levelset);
3022  }
3023  /* Do not apply inflow after the first frame when in geometry mode. */
3024  else if (is_geometry && !is_first_frame) {
3025  apply_inflow_fields(ffs,
3026  0.0f,
3027  PHI_MAX,
3028  d_index,
3029  density_in,
3030  density,
3031  heat_in,
3032  heat,
3033  fuel_in,
3034  fuel,
3035  react_in,
3036  react,
3037  color_r_in,
3038  color_r,
3039  color_g_in,
3040  color_g,
3041  color_b_in,
3042  color_b,
3043  phi_in,
3044  emission_in);
3045  }
3046  /* Main inflow application. */
3047  else if (is_geometry || is_inflow) {
3048  float *levelset = ((is_first_frame || is_resume) && is_static && !is_geometry) ?
3049  phistatic_in :
3050  phi_in;
3051  apply_inflow_fields(ffs,
3052  emission_map[e_index],
3053  distance_map[e_index],
3054  d_index,
3055  density_in,
3056  density,
3057  heat_in,
3058  heat,
3059  fuel_in,
3060  fuel,
3061  react_in,
3062  react,
3063  color_r_in,
3064  color_r,
3065  color_g_in,
3066  color_g,
3067  color_b_in,
3068  color_b,
3069  levelset,
3070  emission_in);
3071  if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
3072  /* Use the initial velocity from the inflow object with the highest velocity for
3073  * now. */
3074  float vel_initial[3];
3075  vel_initial[0] = velx_initial[d_index];
3076  vel_initial[1] = vely_initial[d_index];
3077  vel_initial[2] = velz_initial[d_index];
3078  float vel_initial_strength = len_squared_v3(vel_initial);
3079  float vel_map_strength = len_squared_v3(velocity_map + 3 * e_index);
3080  if (vel_map_strength > vel_initial_strength) {
3081  velx_initial[d_index] = velocity_map[e_index * 3];
3082  vely_initial[d_index] = velocity_map[e_index * 3 + 1];
3083  velz_initial[d_index] = velocity_map[e_index * 3 + 2];
3084  }
3085  }
3086  }
3087  }
3088  }
3089  } /* End of flow emission map loop. */
3090  bb_freeData(bb);
3091  } /* End of flow object loop. */
3092  }
3093 
3094  BKE_collision_objects_free(flowobjs);
3095  if (bb_maps) {
3096  MEM_freeN(bb_maps);
3097  }
3098 }
3099 
3100 typedef struct UpdateEffectorsData {
3101  Scene *scene;
3102  FluidDomainSettings *fds;
3103  ListBase *effectors;
3104 
3105  float *density;
3106  float *fuel;
3107  float *force_x;
3108  float *force_y;
3109  float *force_z;
3110  float *velocity_x;
3111  float *velocity_y;
3112  float *velocity_z;
3113  int *flags;
3114  float *phi_obs_in;
3115 } UpdateEffectorsData;
3116 
3117 static void update_effectors_task_cb(void *__restrict userdata,
3118  const int x,
3119  const TaskParallelTLS *__restrict UNUSED(tls))
3120 {
3121  UpdateEffectorsData *data = userdata;
3122  FluidDomainSettings *fds = data->fds;
3123 
3124  for (int y = 0; y < fds->res[1]; y++) {
3125  for (int z = 0; z < fds->res[2]; z++) {
3126  EffectedPoint epoint;
3127  float mag;
3128  float voxel_center[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
3129  const uint index = manta_get_index(x, fds->res[0], y, fds->res[1], z);
3130 
3131  if ((data->fuel && MAX2(data->density[index], data->fuel[index]) < FLT_EPSILON) ||
3132  (data->density && data->density[index] < FLT_EPSILON) ||
3133  (data->phi_obs_in && data->phi_obs_in[index] < 0.0f) ||
3134  data->flags[index] & 2) /* Manta-flow convention: `2 == FlagObstacle`. */
3135  {
3136  continue;
3137  }
3138 
3139  /* Get velocities from manta grid space and convert to blender units. */
3140  vel[0] = data->velocity_x[index];
3141  vel[1] = data->velocity_y[index];
3142  vel[2] = data->velocity_z[index];
3143  mul_v3_fl(vel, fds->dx);
3144 
3145  /* Convert vel to global space. */
3146  mag = len_v3(vel);
3147  mul_mat3_m4_v3(fds->obmat, vel);
3148  normalize_v3(vel);
3149  mul_v3_fl(vel, mag);
3150 
3151  voxel_center[0] = fds->p0[0] + fds->cell_size[0] * ((float)(x + fds->res_min[0]) + 0.5f);
3152  voxel_center[1] = fds->p0[1] + fds->cell_size[1] * ((float)(y + fds->res_min[1]) + 0.5f);
3153  voxel_center[2] = fds->p0[2] + fds->cell_size[2] * ((float)(z + fds->res_min[2]) + 0.5f);
3154  mul_m4_v3(fds->obmat, voxel_center);
3155 
3156  /* Do effectors. */
3157  pd_point_from_loc(data->scene, voxel_center, vel, index, &epoint);
3159  data->effectors, NULL, fds->effector_weights, &epoint, retvel, NULL, NULL);
3160 
3161  /* Convert retvel to local space. */
3162  mag = len_v3(retvel);
3163  mul_mat3_m4_v3(fds->imat, retvel);
3164  normalize_v3(retvel);
3165  mul_v3_fl(retvel, mag);
3166 
3167  /* Copy computed force to fluid solver forces. */
3168  mul_v3_fl(retvel, 0.2f); /* Factor from 0e6820cc5d62. */
3169  CLAMP3(retvel, -1.0f, 1.0f); /* Restrict forces to +-1 interval. */
3170  data->force_x[index] = retvel[0];
3171  data->force_y[index] = retvel[1];
3172  data->force_z[index] = retvel[2];
3173 
3174 # ifdef DEBUG_PRINT
3175  /* Debugging: Print forces. */
3176  printf("setting force: [%f, %f, %f]\n",
3177  data->force_x[index],
3178  data->force_y[index],
3179  data->force_z[index]);
3180 # endif
3181  }
3182  }
3183 }
3184 
3185 static void update_effectors(
3186  Depsgraph *depsgraph, Scene *scene, Object *ob, FluidDomainSettings *fds, float UNUSED(dt))
3187 {
3188  ListBase *effectors;
3189  /* make sure smoke flow influence is 0.0f */
3191  effectors = BKE_effectors_create(depsgraph, ob, NULL, fds->effector_weights, false);
3192 
3193  if (effectors) {
3194  /* Precalculate wind forces. */
3195  UpdateEffectorsData data;
3196  data.scene = scene;
3197  data.fds = fds;
3198  data.effectors = effectors;
3199  data.density = manta_smoke_get_density(fds->fluid);
3200  data.fuel = manta_smoke_get_fuel(fds->fluid);
3201  data.force_x = manta_get_force_x(fds->fluid);
3202  data.force_y = manta_get_force_y(fds->fluid);
3203  data.force_z = manta_get_force_z(fds->fluid);
3204  data.velocity_x = manta_get_velocity_x(fds->fluid);
3205  data.velocity_y = manta_get_velocity_y(fds->fluid);
3206  data.velocity_z = manta_get_velocity_z(fds->fluid);
3207  data.flags = manta_smoke_get_flags(fds->fluid);
3208  data.phi_obs_in = manta_get_phiobs_in(fds->fluid);
3209 
3210  TaskParallelSettings settings;
3212  settings.min_iter_per_thread = 2;
3213  BLI_task_parallel_range(0, fds->res[0], &data, update_effectors_task_cb, &settings);
3214  }
3215 
3216  BKE_effectors_free(effectors);
3217 }
3218 
3219 static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
3220  Scene *scene,
3221  Mesh *orgmesh,
3222  Object *ob)
3223 {
3224  Mesh *me;
3225  MVert *mverts;
3226  MPoly *mpolys;
3227  MLoop *mloops;
3228  float min[3];
3229  float max[3];
3230  float size[3];
3231  float cell_size_scaled[3];
3232 
3233  /* Assign material + flags to new mesh.
3234  * If there are no faces in original mesh, keep materials and flags unchanged. */
3235  MPoly *mpoly;
3236  MPoly mp_example = {0};
3237  mpoly = orgmesh->mpoly;
3238  if (mpoly) {
3239  mp_example = *mpoly;
3240  }
3241 
3242  const short mp_mat_nr = mp_example.mat_nr;
3243  const char mp_flag = mp_example.flag;
3244 
3245  int i;
3246  int num_verts, num_faces;
3247 
3248  if (!fds->fluid) {
3249  return NULL;
3250  }
3251 
3252  num_verts = manta_liquid_get_num_verts(fds->fluid);
3253  num_faces = manta_liquid_get_num_triangles(fds->fluid);
3254 
3255 # ifdef DEBUG_PRINT
3256  /* Debugging: Print number of vertices, normals, and faces. */
3257  printf("num_verts: %d, num_faces: %d\n", num_verts, num_faces);
3258 # endif
3259 
3260  if (!num_verts || !num_faces) {
3261  return NULL;
3262  }
3263 
3264  me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
3265  if (!me) {
3266  return NULL;
3267  }
3268  mverts = me->mvert;
3269  mpolys = me->mpoly;
3270  mloops = me->mloop;
3271 
3272  /* Get size (dimension) but considering scaling. */
3273  copy_v3_v3(cell_size_scaled, fds->cell_size);
3274  mul_v3_v3(cell_size_scaled, ob->scale);
3275  madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, cell_size_scaled, fds->res_min);
3276  madd_v3fl_v3fl_v3fl_v3i(max, fds->p0, cell_size_scaled, fds->res_max);
3277  sub_v3_v3v3(size, max, min);
3278 
3279  /* Biggest dimension will be used for upscaling. */
3280  float max_size = MAX3(size[0], size[1], size[2]);
3281 
3282  float co_scale[3];
3283  co_scale[0] = max_size / ob->scale[0];
3284  co_scale[1] = max_size / ob->scale[1];
3285  co_scale[2] = max_size / ob->scale[2];
3286 
3287  float co_offset[3];
3288  co_offset[0] = (fds->p0[0] + fds->p1[0]) / 2.0f;
3289  co_offset[1] = (fds->p0[1] + fds->p1[1]) / 2.0f;
3290  co_offset[2] = (fds->p0[2] + fds->p1[2]) / 2.0f;
3291 
3292  /* Velocities. */
3293  /* If needed, vertex velocities will be read too. */
3294  bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
3295  float(*velarray)[3] = NULL;
3296  float time_mult = fds->dx / (DT_DEFAULT * (25.0f / FPS));
3297 
3298  if (use_speedvectors) {
3299  CustomDataLayer *velocity_layer = BKE_id_attribute_new(
3300  &me->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, NULL);
3301  velarray = velocity_layer->data;
3302  }
3303 
3304  /* Loop for vertices and normals. */
3305  for (i = 0; i < num_verts; i++, mverts++) {
3306 
3307  /* Vertices (data is normalized cube around domain origin). */
3308  mverts->co[0] = manta_liquid_get_vertex_x_at(fds->fluid, i);
3309  mverts->co[1] = manta_liquid_get_vertex_y_at(fds->fluid, i);
3310  mverts->co[2] = manta_liquid_get_vertex_z_at(fds->fluid, i);
3311 
3312  /* Adjust coordinates from Mantaflow to match viewport scaling. */
3313  float tmp[3] = {(float)fds->res[0], (float)fds->res[1], (float)fds->res[2]};
3314  /* Scale to unit cube around 0. */
3315  mul_v3_fl(tmp, fds->mesh_scale * 0.5f);
3316  sub_v3_v3(mverts->co, tmp);
3317  /* Apply scaling of domain object. */
3318  mul_v3_fl(mverts->co, fds->dx / fds->mesh_scale);
3319 
3320  mul_v3_v3(mverts->co, co_scale);
3321  add_v3_v3(mverts->co, co_offset);
3322 
3323 # ifdef DEBUG_PRINT
3324  /* Debugging: Print coordinates of vertices. */
3325  printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n",
3326  mverts->co[0],
3327  mverts->co[1],
3328  mverts->co[2]);
3329 # endif
3330 
3331 # ifdef DEBUG_PRINT
3332  /* Debugging: Print coordinates of normals. */
3333  printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
3334 # endif
3335 
3336  if (use_speedvectors) {
3337  velarray[i][0] = manta_liquid_get_vertvel_x_at(fds->fluid, i) * time_mult;
3338  velarray[i][1] = manta_liquid_get_vertvel_y_at(fds->fluid, i) * time_mult;
3339  velarray[i][2] = manta_liquid_get_vertvel_z_at(fds->fluid, i) * time_mult;
3340 # ifdef DEBUG_PRINT
3341  /* Debugging: Print velocities of vertices. */
3342  printf("velarray[%d][0]: %f, velarray[%d][1]: %f, velarray[%d][2]: %f\n",
3343  i,
3344  velarray[i][0],
3345  i,
3346  velarray[i][1],
3347  i,
3348  velarray[i][2]);
3349 # endif
3350  }
3351  }
3352 
3353  /* Loop for triangles. */
3354  for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) {
3355  /* Initialize from existing face. */
3356  mpolys->mat_nr = mp_mat_nr;
3357  mpolys->flag = mp_flag;
3358 
3359  mpolys->loopstart = i * 3;
3360  mpolys->totloop = 3;
3361 
3362  mloops[0].v = manta_liquid_get_triangle_x_at(fds->fluid, i);
3363  mloops[1].v = manta_liquid_get_triangle_y_at(fds->fluid, i);
3364  mloops[2].v = manta_liquid_get_triangle_z_at(fds->fluid, i);
3365 # ifdef DEBUG_PRINT
3366  /* Debugging: Print mesh faces. */
3367  printf("mloops[0].v: %d, mloops[1].v: %d, mloops[2].v: %d\n",
3368  mloops[0].v,
3369  mloops[1].v,
3370  mloops[2].v);
3371 # endif
3372  }
3373 
3374  BKE_mesh_calc_edges(me, false, false);
3375 
3376  return me;
3377 }
3378 
3379 static Mesh *create_smoke_geometry(FluidDomainSettings *fds, Mesh *orgmesh, Object *ob)
3380 {
3381  Mesh *result;
3382  MVert *mverts;
3383  MPoly *mpolys;
3384  MLoop *mloops;
3385  float min[3];
3386  float max[3];
3387  float *co;
3388  MPoly *mp;
3389  MLoop *ml;
3390 
3391  int num_verts = 8;
3392  int num_faces = 6;
3393  float ob_loc[3] = {0};
3394  float ob_cache_loc[3] = {0};
3395 
3396  /* Just copy existing mesh if there is no content or if the adaptive domain is not being used. */
3397  if (fds->total_cells <= 1 || (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) {
3398  return BKE_mesh_copy_for_eval(orgmesh, false);
3399  }
3400 
3401  result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
3402  mverts = result->mvert;
3403  mpolys = result->mpoly;
3404  mloops = result->mloop;
3405 
3406  if (num_verts) {
3407  /* Volume bounds. */
3408  madd_v3fl_v3fl_v3fl_v3i(min, fds->p0, fds->cell_size, fds->res_min);
3409  madd_v3fl_v3fl_v3fl_v3i(max, fds->p0, fds->cell_size, fds->res_max);
3410 
3411  /* Set vertices of smoke BB. Especially important, when BB changes (adaptive domain). */
3412  /* Top slab */
3413  co = mverts[0].co;
3414  co[0] = min[0];
3415  co[1] = min[1];
3416  co[2] = max[2];
3417  co = mverts[1].co;
3418  co[0] = max[0];
3419  co[1] = min[1];
3420  co[2] = max[2];
3421  co = mverts[2].co;
3422  co[0] = max[0];
3423  co[1] = max[1];
3424  co[2] = max[2];
3425  co = mverts[3].co;
3426  co[0] = min[0];
3427  co[1] = max[1];
3428  co[2] = max[2];
3429  /* Bottom slab. */
3430  co = mverts[4].co;
3431  co[0] = min[0];
3432  co[1] = min[1];
3433  co[2] = min[2];
3434  co = mverts[5].co;
3435  co[0] = max[0];
3436  co[1] = min[1];
3437  co[2] = min[2];
3438  co = mverts[6].co;
3439  co[0] = max[0];
3440  co[1] = max[1];
3441  co[2] = min[2];
3442  co = mverts[7].co;
3443  co[0] = min[0];
3444  co[1] = max[1];
3445  co[2] = min[2];
3446 
3447  /* Create faces. */
3448  /* Top side. */
3449  mp = &mpolys[0];
3450  ml = &mloops[0 * 4];
3451  mp->loopstart = 0 * 4;
3452  mp->totloop = 4;
3453  ml[0].v = 0;
3454  ml[1].v = 1;
3455  ml[2].v = 2;
3456  ml[3].v = 3;
3457  /* Right side. */
3458  mp = &mpolys[1];
3459  ml = &mloops[1 * 4];
3460  mp->loopstart = 1 * 4;
3461  mp->totloop = 4;
3462  ml[0].v = 2;
3463  ml[1].v = 1;
3464  ml[2].v = 5;
3465  ml[3].v = 6;
3466  /* Bottom side. */
3467  mp = &mpolys[2];
3468  ml = &mloops[2 * 4];
3469  mp->loopstart = 2 * 4;
3470  mp->totloop = 4;
3471  ml[0].v = 7;
3472  ml[1].v = 6;
3473  ml[2].v = 5;
3474  ml[3].v = 4;
3475  /* Left side. */
3476  mp = &mpolys[3];
3477  ml = &mloops[3 * 4];
3478  mp->loopstart = 3 * 4;
3479  mp->totloop = 4;
3480  ml[0].v = 0;
3481  ml[1].v = 3;
3482  ml[2].v = 7;
3483  ml[3].v = 4;
3484  /* Front side. */
3485  mp = &mpolys[4];
3486  ml = &mloops[4 * 4];
3487  mp->loopstart = 4 * 4;
3488  mp->totloop = 4;
3489  ml[0].v = 3;
3490  ml[1].v = 2;
3491  ml[2].v = 6;
3492  ml[3].v = 7;
3493  /* Back side. */
3494  mp = &mpolys[5];
3495  ml = &mloops[5 * 4];
3496  mp->loopstart = 5 * 4;
3497  mp->totloop = 4;
3498  ml[0].v = 1;
3499  ml[1].v = 0;
3500  ml[2].v = 4;
3501  ml[3].v = 5;
3502 
3503  /* Calculate required shift to match domain's global position
3504  * it was originally simulated at (if object moves without manta step). */
3505  invert_m4_m4(ob->imat, ob->obmat);
3506  mul_m4_v3(ob->obmat, ob_loc);
3507  mul_m4_v3(fds->obmat, ob_cache_loc);
3508  sub_v3_v3v3(fds->obj_shift_f, ob_cache_loc, ob_loc);
3509  /* Convert shift to local space and apply to vertices. */
3510  mul_mat3_m4_v3(ob->imat, fds->obj_shift_f);
3511  /* Apply shift to vertices. */
3512  for (int i = 0; i < num_verts; i++) {
3513  add_v3_v3(mverts[i].co, fds->obj_shift_f);
3514  }
3515  }
3516 
3517  BKE_mesh_calc_edges(result, false, false);
3518  return result;
3519 }
3520 
3521 static int manta_step(
3522  Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *fmd, int frame)
3523 {
3524  FluidDomainSettings *fds = fmd->domain;
3525  float dt, frame_length, time_total, time_total_old;
3526  float time_per_frame;
3527  bool init_resolution = true;
3528 
3529  /* Store baking success - bake might be aborted anytime by user. */
3530  int result = 1;
3531  int mode = fds->cache_type;
3532  bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY);
3533 
3534  /* Update object state. */
3535  invert_m4_m4(fds->imat, ob->obmat);
3536  copy_m4_m4(fds->obmat, ob->obmat);
3537 
3538  /* Gas domain might use adaptive domain. */
3539  if (fds->type == FLUID_DOMAIN_TYPE_GAS) {
3540  init_resolution = (fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) != 0;
3541  }
3542  manta_set_domain_from_mesh(fds, ob, me, init_resolution);
3543 
3544  /* Use local variables for adaptive loop, dt can change. */
3545  frame_length = fds->frame_length;
3546  dt = fds->dt;
3547  time_per_frame = 0;
3548  time_total = fds->time_total;
3549  /* Keep track of original total time to correct small errors at end of step. */
3550  time_total_old = fds->time_total;
3551 
3552  BLI_mutex_lock(&object_update_lock);
3553 
3554  /* Loop as long as time_per_frame (sum of sub dt's) does not exceed actual framelength. */
3555  while (time_per_frame + FLT_EPSILON < frame_length) {
3557  dt = manta_get_timestep(fds->fluid);
3558 
3559  /* Save adapted dt so that MANTA object can access it (important when adaptive domain creates
3560  * new MANTA object). */
3561  fds->dt = dt;
3562 
3563  /* Calculate inflow geometry. */
3564  update_flowsfluids(depsgraph, scene, ob, fds, time_per_frame, frame_length, frame, dt);
3565 
3566  /* If user requested stop, quit baking */
3567  if (G.is_break && !mode_replay) {
3568  result = 0;
3569  break;
3570  }
3571 
3572  manta_update_variables(fds->fluid, fmd);
3573 
3574  /* Calculate obstacle geometry. */
3575  update_obstacles(depsgraph, scene, ob, fds, time_per_frame, frame_length, frame, dt);
3576 
3577  /* If user requested stop, quit baking */
3578  if (G.is_break && !mode_replay) {
3579  result = 0;
3580  break;
3581  }
3582 
3583  /* Only bake if the domain is bigger than one cell (important for adaptive domain). */
3584  if (fds->total_cells > 1) {
3585  update_effectors(depsgraph, scene, ob, fds, dt);
3586  manta_bake_data(fds->fluid, fmd, frame);
3587  }
3588 
3589  /* Count for how long this while loop is running. */
3590  time_per_frame += dt;
3591  time_total += dt;
3592 
3593  fds->time_per_frame = time_per_frame;
3594  fds->time_total = time_total;
3595  }
3596 
3597  /* Total time must not exceed framecount times framelength. Correct tiny errors here. */
3598  CLAMP_MAX(fds->time_total, time_total_old + fds->frame_length);
3599 
3600  /* Compute shadow grid for gas simulations. Make sure to skip if bake job was canceled early. */
3601  if (fds->type == FLUID_DOMAIN_TYPE_GAS && result) {
3602  manta_smoke_calc_transparency(fds, DEG_get_evaluated_view_layer(depsgraph));
3603  }
3604 
3605  BLI_mutex_unlock(&object_update_lock);
3606  return result;
3607 }
3608 
3609 static void manta_guiding(
3610  Depsgraph *depsgraph, Scene *scene, Object *ob, FluidModifierData *fmd, int frame)
3611 {
3612  FluidDomainSettings *fds = fmd->domain;
3613  float dt = DT_DEFAULT * (25.0f / FPS) * fds->time_scale;
3614 
3615  BLI_mutex_lock(&object_update_lock);
3616 
3617  update_obstacles(depsgraph, scene, ob, fds, dt, dt, frame, dt);
3618  manta_bake_guiding(fds->fluid, fmd, frame);
3619 
3620  BLI_mutex_unlock(&object_update_lock);
3621 }
3622 
3623 static void BKE_fluid_modifier_processFlow(FluidModifierData *fmd,
3625  Scene *scene,
3626  Object *ob,
3627  Mesh *me,
3628  const int scene_framenr)
3629 {
3630  if (scene_framenr >= fmd->time) {
3631  BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me);
3632  }
3633 
3634  if (fmd->flow) {
3635  if (fmd->flow->mesh) {
3636  BKE_id_free(NULL, fmd->flow->mesh);
3637  }
3638  fmd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
3639  }
3640 
3641  if (scene_framenr > fmd->time) {
3642  fmd->time = scene_framenr;
3643  }
3644  else if (scene_framenr < fmd->time) {
3645  fmd->time = scene_framenr;
3646  BKE_fluid_modifier_reset_ex(fmd, false);
3647  }
3648 }
3649 
3650 static void BKE_fluid_modifier_processEffector(FluidModifierData *fmd,
3652  Scene *scene,
3653  Object *ob,
3654  Mesh *me,
3655  const int scene_framenr)
3656 {
3657  if (scene_framenr >= fmd->time) {
3658  BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me);
3659  }
3660 
3661  if (fmd->effector) {
3662  if (fmd->effector->mesh) {
3663  BKE_id_free(NULL, fmd->effector->mesh);
3664  }
3665  fmd->effector->mesh = BKE_mesh_copy_for_eval(me, false);
3666  }
3667 
3668  if (scene_framenr > fmd->time) {
3669  fmd->time = scene_framenr;
3670  }
3671  else if (scene_framenr < fmd->time) {
3672  fmd->time = scene_framenr;
3673  BKE_fluid_modifier_reset_ex(fmd, false);
3674  }
3675 }
3676 
3677 static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
3679  Scene *scene,
3680  Object *ob,
3681  Mesh *me,
3682  const int scene_framenr)
3683 {
3684  FluidDomainSettings *fds = fmd->domain;
3685  Object *guide_parent = NULL;
3686  Object **objs = NULL;
3687  uint numobj = 0;
3688  FluidModifierData *fmd_parent = NULL;
3689 
3690  bool is_startframe, has_advanced;
3691  is_startframe = (scene_framenr == fds->cache_frame_start);
3692  has_advanced = (scene_framenr == fmd->time + 1);
3693  int mode = fds->cache_type;
3694 
3695  /* Do not process modifier if current frame is out of cache range. */
3696  bool escape = false;
3697  switch (mode) {
3700  if (fds->cache_frame_offset > 0) {
3701  if (scene_framenr < fds->cache_frame_start ||
3702  scene_framenr > fds->cache_frame_end + fds->cache_frame_offset) {
3703  escape = true;
3704  }
3705  }
3706  else {
3707  if (scene_framenr < fds->cache_frame_start + fds->cache_frame_offset ||
3708  scene_framenr > fds->cache_frame_end) {
3709  escape = true;
3710  }
3711  }
3712  break;
3714  default:
3715  if (scene_framenr < fds->cache_frame_start || scene_framenr > fds->cache_frame_end) {
3716  escape = true;
3717  }
3718  break;
3719  }
3720  /* If modifier will not be processed, update/flush pointers from (old) fluid object once more. */
3721  if (escape && fds->fluid) {
3722  manta_update_pointers(fds->fluid, fmd, true);
3723  return;
3724  }
3725 
3726  /* Reset fluid if no fluid present. Also resets active fields. */
3727  if (!fds->fluid) {
3728  BKE_fluid_modifier_reset_ex(fmd, false);
3729  }
3730 
3731  /* Ensure cache directory is not relative. */
3732  const char *relbase = BKE_modifier_path_relbase_from_global(ob);
3733  BLI_path_abs(fds->cache_directory, relbase);
3734 
3735  /* If 'outdated', reset the cache here. */
3736  if (is_startframe && mode == FLUID_DOMAIN_CACHE_REPLAY) {
3737  PTCacheID pid;
3738  BKE_ptcache_id_from_smoke(&pid, ob, fmd);
3739  if (pid.cache->flag & PTCACHE_OUTDATED) {
3741  BKE_fluid_cache_free_all(fds, ob);
3742  BKE_fluid_modifier_reset_ex(fmd, false);
3743  }
3744  }
3745 
3746  /* Ensure that all flags are up to date before doing any baking and/or cache reading. */
3748  depsgraph, ob, fds->fluid_group, &numobj, eModifierType_Fluid);
3749  update_flowsflags(fds, objs, numobj);
3750  if (objs) {
3751  MEM_freeN(objs);
3752  }
3754  depsgraph, ob, fds->effector_group, &numobj, eModifierType_Fluid);
3755  update_obstacleflags(fds, objs, numobj);
3756  if (objs) {
3757  MEM_freeN(objs);
3758  }
3759 
3760  /* Fluid domain init must not fail in order to continue modifier evaluation. */
3761  if (!fds->fluid && !BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me)) {
3762  CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!");
3763  return;
3764  }
3765  BLI_assert(fds->fluid);
3766 
3767  /* Guiding parent res pointer needs initialization. */
3768  guide_parent = fds->guide_parent;
3769  if (guide_parent) {
3770  fmd_parent = (FluidModifierData *)BKE_modifiers_findby_type(guide_parent, eModifierType_Fluid);
3771  if (fmd_parent && fmd_parent->domain) {
3772  copy_v3_v3_int(fds->guide_res, fmd_parent->domain->res);
3773  }
3774  }
3775 
3776  /* Adaptive domain needs to know about current state, so save it here. */
3777  int o_res[3], o_min[3], o_max[3], o_shift[3];
3778  copy_v3_v3_int(o_res, fds->res);
3779  copy_v3_v3_int(o_min, fds->res_min);
3780  copy_v3_v3_int(o_max, fds->res_max);
3781  copy_v3_v3_int(o_shift, fds->shift);
3782 
3783  /* Ensure that time parameters are initialized correctly before every step. */
3784  fds->frame_length = DT_DEFAULT * (25.0f / FPS) * fds->time_scale;
3785  fds->dt = fds->frame_length;
3786  fds->time_per_frame = 0;
3787 
3788  /* Ensure that gravity is copied over every frame (could be keyframed). */
3789  update_final_gravity(fds, scene);
3790 
3791  int next_frame = scene_framenr + 1;
3792  int prev_frame = scene_framenr - 1;
3793  /* Ensure positive of previous frame. */
3794  CLAMP_MIN(prev_frame, fds->cache_frame_start);
3795 
3796  int data_frame = scene_framenr, noise_frame = scene_framenr;
3797  int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr;
3798 
3799  bool with_smoke, with_liquid;
3800  with_smoke = fds->type == FLUID_DOMAIN_TYPE_GAS;
3801  with_liquid = fds->type == FLUID_DOMAIN_TYPE_LIQUID;
3802 
3803  bool drops, bubble, floater;
3806  floater = fds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
3807 
3808  bool with_resumable_cache = fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE;
3809  bool with_script, with_noise, with_mesh, with_particles, with_guide;
3810  with_script = fds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT;
3811  with_noise = fds->flags & FLUID_DOMAIN_USE_NOISE;
3812  with_mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
3813  with_guide = fds->flags & FLUID_DOMAIN_USE_GUIDE;
3814  with_particles = drops || bubble || floater;
3815 
3816  bool has_data, has_noise, has_mesh, has_particles, has_guide, has_config;
3817  has_data = manta_has_data(fds->fluid, fmd, scene_framenr);
3818  has_noise = manta_has_noise(fds->fluid, fmd, scene_framenr);
3819  has_mesh = manta_has_mesh(fds->fluid, fmd, scene_framenr);
3820  has_particles = manta_has_particles(fds->fluid, fmd, scene_framenr);
3821  has_guide = manta_has_guiding(fds->fluid, fmd, scene_framenr, guide_parent);
3822  has_config = manta_read_config(fds->fluid, fmd, scene_framenr);
3823 
3824  /* When reading data from cache (has_config == true) ensure that active fields are allocated.
3825  * update_flowsflags() and update_obstacleflags() will not find flow sources hidden from renders.
3826  * See also: T72192. */
3827  if (has_config) {
3828  ensure_flowsfields(fds);
3829  ensure_obstaclefields(fds);
3830  }
3831 
3832  bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
3833  baking_data = fds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
3834  baking_noise = fds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
3835  baking_mesh = fds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
3836  baking_particles = fds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
3837  baking_guide = fds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
3838 
3839  bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide;
3840  resume_data = (!is_startframe) && (fds->cache_frame_pause_data == scene_framenr);
3841  resume_noise = (!is_startframe) && (fds->cache_frame_pause_noise == scene_framenr);
3842  resume_mesh = (!is_startframe) && (fds->cache_frame_pause_mesh == scene_framenr);
3843  resume_particles = (!is_startframe) && (fds->cache_frame_pause_particles == scene_framenr);
3844  resume_guide = (!is_startframe) && (fds->cache_frame_pause_guide == scene_framenr);
3845 
3846  bool read_cache, bake_cache;
3847  read_cache = false;
3848  bake_cache = baking_data || baking_noise || baking_mesh || baking_particles || baking_guide;
3849 
3850  bool next_data, next_noise, next_mesh, next_particles, next_guide;
3851  next_data = manta_has_data(fds->fluid, fmd, next_frame);
3852  next_noise = manta_has_noise(fds->fluid, fmd, next_frame);
3853  next_mesh = manta_has_mesh(fds->fluid, fmd, next_frame);
3854  next_particles = manta_has_particles(fds->fluid, fmd, next_frame);
3855  next_guide = manta_has_guiding(fds->fluid, fmd, next_frame, guide_parent);
3856 
3857  bool prev_data, prev_noise, prev_mesh, prev_particles, prev_guide;
3858  prev_data = manta_has_data(fds->fluid, fmd, prev_frame);
3859  prev_noise = manta_has_noise(fds->fluid, fmd, prev_frame);
3860  prev_mesh = manta_has_mesh(fds->fluid, fmd, prev_frame);
3861  prev_particles = manta_has_particles(fds->fluid, fmd, prev_frame);
3862  prev_guide = manta_has_guiding(fds->fluid, fmd, prev_frame, guide_parent);
3863 
3864  /* Unused for now. */
3865  UNUSED_VARS(next_mesh, next_guide);
3866 
3867  bool with_gdomain;
3868  with_gdomain = (fds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN);
3869 
3870  /* Cache mode specific settings. */
3871  switch (mode) {
3874  /* Just load the data that has already been baked */
3875  if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
3876  read_cache = true;
3877  bake_cache = false;
3878 
3879  /* Apply frame offset. */
3880  data_frame -= fmd->domain->cache_frame_offset;
3881  noise_frame -= fmd->domain->cache_frame_offset;
3882  mesh_frame -= fmd->domain->cache_frame_offset;
3883  particles_frame -= fmd->domain->cache_frame_offset;
3884  break;
3885  }
3886 
3887  /* Set to previous frame if the bake was resumed
3888  * ie don't read all of the already baked frames, just the one before bake resumes */
3889  if (baking_data && resume_data) {
3890  data_frame = prev_frame;
3891  }
3892  if (baking_noise && resume_noise) {
3893  noise_frame = prev_frame;
3894  }
3895  if (baking_mesh && resume_mesh) {
3896  mesh_frame = prev_frame;
3897  }
3898  if (baking_particles && resume_particles) {
3899  particles_frame = prev_frame;
3900  }
3901  if (baking_guide && resume_guide) {
3902  guide_frame = prev_frame;
3903  }
3904 
3905  /* Noise, mesh and particles can never be baked more than data. */
3906  CLAMP_MAX(noise_frame, data_frame);
3907  CLAMP_MAX(mesh_frame, data_frame);
3908  CLAMP_MAX(particles_frame, data_frame);
3909  CLAMP_MAX(guide_frame, fds->cache_frame_end);
3910 
3911  /* Force to read cache as we're resuming the bake */
3912  read_cache = true;
3913  break;
3915  default:
3916  baking_data = !has_data && (is_startframe || prev_data);
3917  if (with_smoke && with_noise) {
3918  baking_noise = !has_noise && (is_startframe || prev_noise);
3919  }
3920  if (with_liquid && with_mesh) {
3921  baking_mesh = !has_mesh && (is_startframe || prev_mesh);
3922  }
3923  if (with_liquid && with_particles) {
3924  baking_particles = !has_particles && (is_startframe || prev_particles);
3925  }
3926 
3927  /* Always trying to read the cache in replay mode. */
3928  read_cache = true;
3929  bake_cache = false;
3930  break;
3931  }
3932 
3933  bool read_partial = false, read_all = false;
3934  bool grid_display = fds->use_coba;
3935 
3936  /* Try to read from cache and keep track of read success. */
3937  if (read_cache) {
3938 
3939  /* Read mesh cache. */
3940  if (with_liquid && with_mesh) {
3941  if (mesh_frame != scene_framenr) {
3942  has_config = manta_read_config(fds->fluid, fmd, mesh_frame);
3943  }
3944 
3945  /* Only load the mesh at the resolution it ways originally simulated at.
3946  * The mesh files don't have a header, i.e. the don't store the grid resolution. */
3947  if (!manta_needs_realloc(fds->fluid, fmd)) {
3948  has_mesh = manta_read_mesh(fds->fluid, fmd, mesh_frame);
3949  }
3950  }
3951 
3952  /* Read particles cache. */
3953  if (with_liquid && with_particles) {
3954  if (particles_frame != scene_framenr) {
3955  has_config = manta_read_config(fds->fluid, fmd, particles_frame);
3956  }
3957 
3958  read_partial = !baking_data && !baking_particles && next_particles;
3959  read_all = !read_partial && with_resumable_cache;
3960  has_particles = manta_read_particles(fds->fluid, fmd, particles_frame, read_all);
3961  }
3962 
3963  /* Read guide cache. */
3964  if (with_guide) {
3965  FluidModifierData *fmd2 = (with_gdomain) ? fmd_parent : fmd;
3966  has_guide = manta_read_guiding(fds->fluid, fmd2, scene_framenr, with_gdomain);
3967  }
3968 
3969  /* Read noise and data cache */
3970  if (with_smoke && with_noise) {
3971  if (noise_frame != scene_framenr) {
3972  has_config = manta_read_config(fds->fluid, fmd, noise_frame);
3973  }
3974 
3975  /* Only reallocate when just reading cache or when resuming during bake. */
3976  if (has_data && has_config && manta_needs_realloc(fds->fluid, fmd)) {
3978  fds, o_res, fds->res, o_min, fds->res_min, o_max, o_shift, fds->shift);
3979  }
3980 
3981  read_partial = !baking_data && !baking_noise && next_noise;
3982  read_all = !read_partial && with_resumable_cache;
3983  has_noise = manta_read_noise(fds->fluid, fmd, noise_frame, read_all);
3984 
3985  read_partial = !baking_data && !baking_noise && next_data && next_noise;
3986  read_all = !read_partial && with_resumable_cache;
3987  has_data = manta_read_data(fds->fluid, fmd, data_frame, read_all);
3988  }
3989  /* Read data cache only */
3990  else {
3991  if (data_frame != scene_framenr) {
3992  has_config = manta_read_config(fds->fluid, fmd, data_frame);
3993  }
3994 
3995  if (with_smoke) {
3996  /* Read config and realloc fluid object if needed. */
3997  if (has_config && manta_needs_realloc(fds->fluid, fmd)) {
3998  BKE_fluid_reallocate_fluid(fds, fds->res, 1);
3999  }
4000  }
4001 
4002  read_partial = !baking_data && !baking_particles && !baking_mesh && next_data &&
4003  !grid_display;
4004  read_all = !read_partial && with_resumable_cache;
4005  has_data = manta_read_data(fds->fluid, fmd, data_frame, read_all);
4006  }
4007  }
4008 
4009  /* Cache mode specific settings */
4010  switch (mode) {
4013  if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
4014  bake_cache = false;
4015  }
4016  break;
4018  default:
4019  if (with_guide) {
4020  baking_guide = !has_guide && (is_startframe || prev_guide);
4021  }
4022  baking_data = !has_data && (is_startframe || prev_data);
4023  if (with_smoke && with_noise) {
4024  baking_noise = !has_noise && (is_startframe || prev_noise);
4025  }
4026  if (with_liquid && with_mesh) {
4027  baking_mesh = !has_mesh && (is_startframe || prev_mesh);
4028  }
4029  if (with_liquid && with_particles) {
4030  baking_particles = !has_particles && (is_startframe || prev_particles);
4031  }
4032 
4033  /* Only bake if time advanced by one frame. */
4034  if (is_startframe || has_advanced) {
4035  bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
4036  }
4037  break;
4038  }
4039 
4040  /* Trigger bake calls individually */
4041  if (bake_cache) {
4042  /* Ensure fresh variables at every animation step */
4043  manta_update_variables(fds->fluid, fmd);
4044 
4045  /* Export mantaflow python script on first frame (once only) and for any bake type */
4046  if (with_script && is_startframe) {
4047  if (with_smoke) {
4049  }
4050  if (with_liquid) {
4052  }
4053  }
4054 
4055  if (baking_guide && with_guide) {
4056  manta_guiding(depsgraph, scene, ob, fmd, scene_framenr);
4057  }
4058  if (baking_data) {
4059  /* Only save baked data if all of it completed successfully. */
4060  if (manta_step(depsgraph, scene, ob, me, fmd, scene_framenr)) {
4061  manta_write_config(fds->fluid, fmd, scene_framenr);
4062  manta_write_data(fds->fluid, fmd, scene_framenr);
4063  }
4064  }
4065  if (has_data || baking_data) {
4066  if (baking_noise && with_smoke && with_noise) {
4067  /* Ensure that no bake occurs if domain was minimized by adaptive domain. */
4068  if (fds->total_cells > 1) {
4069  manta_bake_noise(fds->fluid, fmd, scene_framenr);
4070  }
4071  manta_write_noise(fds->fluid, fmd, scene_framenr);
4072  }
4073  if (baking_mesh && with_liquid && with_mesh) {
4074  manta_bake_mesh(fds->fluid, fmd, scene_framenr);
4075  }
4076  if (baking_particles && with_liquid && with_particles) {
4077  manta_bake_particles(fds->fluid, fmd, scene_framenr);
4078  }
4079  }
4080  }
4081 
4082  /* Ensure that fluid pointers are always up to date at the end of modifier processing. */
4083  manta_update_pointers(fds->fluid, fmd, false);
4084 
4085  fds->flags &= ~FLUID_DOMAIN_FILE_LOAD;
4086  fmd->time = scene_framenr;
4087 }
4088 
4089 static void BKE_fluid_modifier_process(
4091 {
4092  const int scene_framenr = (int)DEG_get_ctime(depsgraph);
4093 
4094  if (fmd->type & MOD_FLUID_TYPE_FLOW) {
4095  BKE_fluid_modifier_processFlow(fmd, depsgraph, scene, ob, me, scene_framenr);
4096  }
4097  else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
4098  BKE_fluid_modifier_processEffector(fmd, depsgraph, scene, ob, me, scene_framenr);
4099  }
4100  else if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
4101  BKE_fluid_modifier_processDomain(fmd, depsgraph, scene, ob, me, scene_framenr);
4102  }
4103 }
4104 
4105 struct Mesh *BKE_fluid_modifier_do(
4107 {
4108  /* Optimization: Do not update viewport during bakes (except in replay mode)
4109  * Reason: UI is locked and updated liquid / smoke geometry is not visible anyways. */
4110  bool needs_viewport_update = false;
4111 
4112  /* Optimization: Only process modifier if object is not being altered. */
4113  if (!G.moving) {
4114  /* Lock so preview render does not read smoke data while it gets modified. */
4115  if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
4117  }
4118 
4119  BKE_fluid_modifier_process(fmd, depsgraph, scene, ob, me);
4120 
4121  if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
4123  }
4124 
4125  if (fmd->domain) {
4126  FluidDomainSettings *fds = fmd->domain;
4127 
4128  /* Always update viewport in cache replay mode. */
4129  if (fds->cache_type == FLUID_DOMAIN_CACHE_REPLAY ||
4131  needs_viewport_update = true;
4132  }
4133  /* In other cache modes, only update the viewport when no bake is going on. */
4134  else {
4135  bool with_mesh;
4136  with_mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
4137  bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
4138  baking_data = fds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
4139  baking_noise = fds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
4140  baking_mesh = fds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
4141  baking_particles = fds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
4142  baking_guide = fds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
4143 
4144  if (with_mesh && !baking_data && !baking_noise && !baking_mesh && !baking_particles &&
4145  !baking_guide) {
4146  needs_viewport_update = true;
4147  }
4148  }
4149  }
4150  }
4151 
4152  Mesh *result = NULL;
4153  if (fmd->type & MOD_FLUID_TYPE_DOMAIN && fmd->domain) {
4154  if (needs_viewport_update) {
4155  /* Return generated geometry depending on domain type. */
4156  if (fmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) {
4157  result = create_liquid_geometry(fmd->domain, scene, me, ob);
4158  }
4159  if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
4160  result = create_smoke_geometry(fmd->domain, me, ob);
4161  }
4162  }
4163 
4164  /* Clear flag outside of locked block (above). */
4170  }
4171 
4172  if (!result) {
4173  result = BKE_mesh_copy_for_eval(me, false);
4174  }
4175  else {
4177  }
4178 
4179  /* Liquid simulation has a texture space that based on the bounds of the fluid mesh.
4180  * This does not seem particularly useful, but it's backwards compatible.
4181  *
4182  * Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
4183  * original mesh. So recompute it at this point in the modifier stack. See T58492. */
4185 
4186  return result;
4187 }
4188 
4189 static float calc_voxel_transp(
4190  float *result, const float *input, int res[3], int *pixel, float *t_ray, float correct)
4191 {
4192  const size_t index = manta_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]);
4193 
4194  /* `T_ray *= T_vox`. */
4195  *t_ray *= expf(input[index] * correct);
4196 
4197  if (result[index] < 0.0f) {
4198  result[index] = *t_ray;
4199  }
4200 
4201  return *t_ray;
4202 }
4203 
4204 static void bresenham_linie_3D(int x1,
4205  int y1,
4206  int z1,
4207  int x2,
4208  int y2,
4209  int z2,
4210  float *t_ray,
4212  float *result,
4213  float *input,
4214  int res[3],
4215  float correct)
4216 {
4217  int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
4218  int pixel[3];
4219 
4220  pixel[0] = x1;
4221  pixel[1] = y1;
4222  pixel[2] = z1;
4223 
4224  dx = x2 - x1;
4225  dy = y2 - y1;
4226  dz = z2 - z1;
4227 
4228  x_inc = (dx < 0) ? -1 : 1;
4229  l = abs(dx);
4230  y_inc = (dy < 0) ? -1 : 1;
4231  m = abs(dy);
4232  z_inc = (dz < 0) ? -1 : 1;
4233  n = abs(dz);
4234  dx2 = l << 1;
4235  dy2 = m << 1;
4236  dz2 = n << 1;
4237 
4238  if ((l >= m) && (l >= n)) {
4239  err_1 = dy2 - l;
4240  err_2 = dz2 - l;
4241  for (i = 0; i < l; i++) {
4242  if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
4243  break;
4244  }
4245  if (err_1 > 0) {
4246  pixel[1] += y_inc;
4247  err_1 -= dx2;
4248  }
4249  if (err_2 > 0) {
4250  pixel[2] += z_inc;
4251  err_2 -= dx2;
4252  }
4253  err_1 += dy2;
4254  err_2 += dz2;
4255  pixel[0] += x_inc;
4256  }
4257  }
4258  else if ((m >= l) && (m >= n)) {
4259  err_1 = dx2 - m;
4260  err_2 = dz2 - m;
4261  for (i = 0; i < m; i++) {
4262  if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
4263  break;
4264  }
4265  if (err_1 > 0) {
4266  pixel[0] += x_inc;
4267  err_1 -= dy2;
4268  }
4269  if (err_2 > 0) {
4270  pixel[2] += z_inc;
4271  err_2 -= dy2;
4272  }
4273  err_1 += dx2;
4274  err_2 += dz2;
4275  pixel[1] += y_inc;
4276  }
4277  }
4278  else {
4279  err_1 = dy2 - n;
4280  err_2 = dx2 - n;
4281  for (i = 0; i < n; i++) {
4282  if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) {
4283  break;
4284  }
4285  if (err_1 > 0) {
4286  pixel[1] += y_inc;
4287  err_1 -= dz2;
4288  }
4289  if (err_2 > 0) {
4290  pixel[0] += x_inc;
4291  err_2 -= dz2;
4292  }
4293  err_1 += dy2;
4294  err_2 += dx2;
4295  pixel[2] += z_inc;
4296  }
4297  }
4298  cb(result, input, res, pixel, t_ray, correct);
4299 }
4300 
4301 static void manta_smoke_calc_transparency(FluidDomainSettings *fds, ViewLayer *view_layer)
4302 {
4303  float bv[6] = {0};
4304  float light[3];
4305  int slabsize = fds->res[0] * fds->res[1];
4306  float *density = manta_smoke_get_density(fds->fluid);
4307  float *shadow = manta_smoke_get_shadow(fds->fluid);
4308  float correct = -7.0f * fds->dx;
4309 
4310  if (!get_light(view_layer, light)) {
4311  return;
4312  }
4313 
4314  /* Convert light pos to sim cell space. */
4315  mul_m4_v3(fds->imat, light);
4316  light[0] = (light[0] - fds->p0[0]) / fds->cell_size[0] - 0.5f - (float)fds->res_min[0];
4317  light[1] = (light[1] - fds->p0[1]) / fds->cell_size[1] - 0.5f - (float)fds->res_min[1];
4318  light[2] = (light[2] - fds->p0[2]) / fds->cell_size[2] - 0.5f - (float)fds->res_min[2];
4319 
4320  /* Calculate domain bounds in sim cell space. */
4321  /* 0,2,4 = 0.0f */
4322  bv[1] = (float)fds->res[0]; /* X */
4323  bv[3] = (float)fds->res[1]; /* Y */
4324  bv[5] = (float)fds->res[2]; /* Z */
4325 
4326  for (int z = 0; z < fds->res[2]; z++) {
4327  size_t index = z * slabsize;
4328 
4329  for (int y = 0; y < fds->res[1]; y++) {
4330  for (int x = 0; x < fds->res[0]; x++, index++) {
4331  float voxel_center[3];
4332  float pos[3];
4333  int cell[3];
4334  float t_ray = 1.0;
4335 
4336  /* Reset shadow value. */
4337  shadow[index] = -1.0f;
4338 
4339  voxel_center[0] = (float)x;
4340  voxel_center[1] = (float)y;
4341  voxel_center[2] = (float)z;
4342 
4343  /* Get starting cell (light pos). */
4344  if (BLI_bvhtree_bb_raycast(bv, light, voxel_center, pos) > FLT_EPSILON) {
4345  /* We're outside -> use point on side of domain. */
4346  cell[0] = (int)floor(pos[0]);
4347  cell[1] = (int)floor(pos[1]);
4348  cell[2] = (int)floor(pos[2]);
4349  }
4350  else {
4351  /* We're inside -> use light itself. */
4352  cell[0] = (int)floor(light[0]);
4353  cell[1] = (int)floor(light[1]);
4354  cell[2] = (int)floor(light[2]);
4355  }
4356  /* Clamp within grid bounds */
4357  CLAMP(cell[0], 0, fds->res[0] - 1);
4358  CLAMP(cell[1], 0, fds->res[1] - 1);
4359  CLAMP(cell[2], 0, fds->res[2] - 1);
4360 
4361  bresenham_linie_3D(cell[0],
4362  cell[1],
4363  cell[2],
4364  x,
4365  y,
4366  z,
4367  &t_ray,
4368  calc_voxel_transp,
4369  shadow,
4370  density,
4371  fds->res,
4372  correct);
4373 
4374  /* Convention -> from a RGBA float array, use G value for t_ray. */
4375  shadow[index] = t_ray;
4376  }
4377  }
4378  }
4379 }
4380 
4381 float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
4382 {
4384  zero_v3(velocity);
4385 
4386  if (fmd && (fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain && fmd->domain->fluid) {
4387  FluidDomainSettings *fds = fmd->domain;
4388  float time_mult = 25.0f * DT_DEFAULT;
4389  float size_mult = MAX3(fds->global_size[0], fds->global_size[1], fds->global_size[2]) /
4390  MAX3(fds->base_res[0], fds->base_res[1], fds->base_res[2]);
4391  float vel_mag;
4392  float density = 0.0f, fuel = 0.0f;
4393  float pos[3];
4394  copy_v3_v3(pos, position);
4395  manta_pos_to_cell(fds, pos);
4396 
4397  /* Check if position is outside domain max bounds. */
4398  if (pos[0] < fds->res_min[0] || pos[1] < fds->res_min[1] || pos[2] < fds->res_min[2]) {
4399  return -1.0f;
4400  }
4401  if (pos[0] > fds->res_max[0] || pos[1] > fds->res_max[1] || pos[2] > fds->res_max[2]) {
4402  return -1.0f;
4403  }
4404 
4405  /* map pos between 0.0 - 1.0 */
4406  pos[0] = (pos[0] - fds->res_min[0]) / ((float)fds->res[0]);
4407  pos[1] = (pos[1] - fds->res_min[1]) / ((float)fds->res[1]);
4408  pos[2] = (pos[2] - fds->res_min[2]) / ((float)fds->res[2]);
4409 
4410  /* Check if position is outside active area. */
4412  if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
4413  return 0.0f;
4414  }
4415  if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) {
4416  return 0.0f;
4417  }
4418  }
4419 
4420  /* Get interpolated velocity at given position. */
4421  velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(fds->fluid), fds->res, pos);
4422  velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(fds->fluid), fds->res, pos);
4423  velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(fds->fluid), fds->res, pos);
4424 
4425  /* Convert simulation units to Blender units. */
4426  mul_v3_fl(velocity, size_mult);
4427  mul_v3_fl(velocity, time_mult);
4428 
4429  /* Convert velocity direction to global space. */
4430  vel_mag = len_v3(velocity);
4431  mul_mat3_m4_v3(fds->obmat, velocity);
4432  normalize_v3(velocity);
4433  mul_v3_fl(velocity, vel_mag);
4434 
4435  /* Use max value of fuel or smoke density. */
4437  if (manta_smoke_has_fuel(fds->fluid)) {
4439  }
4440  return MAX2(density, fuel);
4441  }
4442  return -1.0f;
4443 }
4444 
4446 {
4447  int flags = 0;
4448 
4449  if (fds->fluid) {
4450  if (manta_smoke_has_heat(fds->fluid)) {
4451  flags |= FLUID_DOMAIN_ACTIVE_HEAT;
4452  }
4453  if (manta_smoke_has_fuel(fds->fluid)) {
4454  flags |= FLUID_DOMAIN_ACTIVE_FIRE;
4455  }
4456  if (manta_smoke_has_colors(fds->fluid)) {
4457  flags |= FLUID_DOMAIN_ACTIVE_COLORS;
4458  }
4459  }
4460 
4461  return flags;
4462 }
4463 
4464 void BKE_fluid_particle_system_create(struct Main *bmain,
4465  struct Object *ob,
4466  const char *pset_name,
4467  const char *parts_name,
4468  const char *psys_name,
4469  const int psys_type)
4470 {
4471  ParticleSystem *psys;
4472  ParticleSettings *part;
4474 
4475  /* add particle system */
4476  part = BKE_particlesettings_add(bmain, pset_name);
4477  psys = MEM_callocN(sizeof(ParticleSystem), "particle_system");
4478 
4479  part->type = psys_type;
4480  part->totpart = 0;
4481  part->draw_size = 0.01f; /* Make fluid particles more subtle in viewport. */
4482  part->draw_col = PART_DRAW_COL_VEL;
4483  part->phystype = PART_PHYS_NO; /* No physics needed, part system only used to display data. */
4484  psys->part = part;
4485  psys->pointcache = BKE_ptcache_add(&psys->ptcaches);
4486  BLI_strncpy(psys->name, parts_name, sizeof(psys->name));
4487  BLI_addtail(&ob->particlesystem, psys);
4488 
4489  /* add modifier */
4491  BLI_strncpy(pfmd->modifier.name, psys_name, sizeof(pfmd->modifier.name));
4492  pfmd->psys = psys;
4493  BLI_addtail(&ob->modifiers, pfmd);
4495 }
4496 
4497 void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type)
4498 {
4500  ParticleSystem *psys, *next_psys;
4501 
4502  for (psys = ob->particlesystem.first; psys; psys = next_psys) {
4503  next_psys = psys->next;
4504  if (psys->part->type == particle_type) {
4505  /* clear modifier */
4506  pfmd = psys_get_modifier(ob, psys);
4509 
4510  /* clear particle system */
4511  BLI_remlink(&ob->particlesystem, psys);
4512  psys_free(ob, psys);
4513  }
4514  }
4515 }
4516 
4519 #endif /* WITH_FLUID */
4520 
4521 /* -------------------------------------------------------------------- */
4528 {
4529  settings->cache_frame_start = (value > settings->cache_frame_end) ? settings->cache_frame_end :
4530  value;
4531 }
4532 
4534 {
4535  settings->cache_frame_end = (value < settings->cache_frame_start) ? settings->cache_frame_start :
4536  value;
4537 }
4538 
4539 void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
4540 {
4541  if (cache_mesh_format == settings->cache_mesh_format) {
4542  return;
4543  }
4544  /* TODO(sebbas): Clear old caches. */
4545  settings->cache_mesh_format = cache_mesh_format;
4546 }
4547 
4548 void BKE_fluid_cachetype_data_set(FluidDomainSettings *settings, int cache_data_format)
4549 {
4550  if (cache_data_format == settings->cache_data_format) {
4551  return;
4552  }
4553  /* TODO(sebbas): Clear old caches. */
4554  settings->cache_data_format = cache_data_format;
4555 }
4556 
4557 void BKE_fluid_cachetype_particle_set(FluidDomainSettings *settings, int cache_particle_format)
4558 {
4559  if (cache_particle_format == settings->cache_particle_format) {
4560  return;
4561  }
4562  /* TODO(sebbas): Clear old caches. */
4563  settings->cache_particle_format = cache_particle_format;
4564 }
4565 
4566 void BKE_fluid_cachetype_noise_set(FluidDomainSettings *settings, int cache_noise_format)
4567 {
4568  if (cache_noise_format == settings->cache_noise_format) {
4569  return;
4570  }
4571  /* TODO(sebbas): Clear old caches. */
4572  settings->cache_noise_format = cache_noise_format;
4573 }
4574 
4576 {
4577  if (clear) {
4578  settings->border_collisions &= value;
4579  }
4580  else {
4581  settings->border_collisions |= value;
4582  }
4583 }
4584 
4585 void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clear)
4586 {
4587  if (clear) {
4588  settings->particle_type &= ~value;
4589  }
4590  else {
4591  settings->particle_type |= value;
4592  }
4593 }
4594 
4596 {
4597  /* Set values for border collision:
4598  * Liquids should have a closed domain, smoke domains should be open. */
4599  if (type == FLUID_DOMAIN_TYPE_GAS) {
4606  object->dt = OB_WIRE;
4607  }
4608  else if (type == FLUID_DOMAIN_TYPE_LIQUID) {
4615  object->dt = OB_SOLID;
4616  }
4617 
4618  /* Set actual domain type. */
4619  settings->type = type;
4620 }
4621 
4622 void BKE_fluid_flow_behavior_set(Object *UNUSED(object), FluidFlowSettings *settings, int behavior)
4623 {
4624  settings->behavior = behavior;
4625 }
4626 
4628 {
4629  /* By default, liquid flow objects should behave like their geometry (geometry behavior),
4630  * gas flow objects should continuously produce smoke (inflow behavior). */
4631  if (type == FLUID_FLOW_TYPE_LIQUID) {
4633  }
4634  else {
4636  }
4637 
4638  /* Set actual flow type. */
4639  settings->type = type;
4640 }
4641 
4643 {
4644  settings->type = type;
4645 }
4646 
4648 {
4649  /* Based on the domain type, certain fields are defaulted accordingly if the selected field
4650  * is unsupported. */
4651  const char coba_field = settings->coba_field;
4652  const char data_depth = settings->openvdb_data_depth;
4653 
4654  if (settings->type == FLUID_DOMAIN_TYPE_GAS) {
4655  if (ELEM(coba_field,
4660  /* Defaulted to density for gas domain. */
4662  }
4663 
4664  /* Gas domains do not support vdb mini precision. */
4665  if (data_depth == VDB_PRECISION_MINI_FLOAT) {
4667  }
4668  }
4669  else if (settings->type == FLUID_DOMAIN_TYPE_LIQUID) {
4670  if (ELEM(coba_field,
4678  /* Defaulted to phi for liquid domain. */
4679  settings->coba_field = FLUID_DOMAIN_FIELD_PHI;
4680  }
4681  }
4682 }
4683 
4686 /* -------------------------------------------------------------------- */
4693 {
4694  if (fmd->domain) {
4695  if (fmd->domain->fluid) {
4696 #ifdef WITH_FLUID
4697  manta_free(fmd->domain->fluid);
4698 #endif
4699  }
4700 
4701  if (fmd->domain->fluid_mutex) {
4703  }
4704 
4706 
4707  if (!(fmd->modifier.flag & eModifierFlag_SharedCaches)) {
4708  BKE_ptcache_free_list(&(fmd->domain->ptcaches[0]));
4709  fmd->domain->point_cache[0] = NULL;
4710  }
4711 
4712  if (fmd->domain->coba) {
4713  MEM_freeN(fmd->domain->coba);
4714  }
4715 
4716  MEM_freeN(fmd->domain);
4717  fmd->domain = NULL;
4718  }
4719 }
4720 
4722 {
4723  if (fmd->flow) {
4724  if (fmd->flow->mesh) {
4725  BKE_id_free(NULL, fmd->flow->mesh);
4726  }
4727  fmd->flow->mesh = NULL;
4728 
4729  MEM_SAFE_FREE(fmd->flow->verts_old);
4730  fmd->flow->numverts = 0;
4732 
4733  MEM_freeN(fmd->flow);
4734  fmd->flow = NULL;
4735  }
4736 }
4737 
4739 {
4740  if (fmd->effector) {
4741  if (fmd->effector->mesh) {
4742  BKE_id_free(NULL, fmd->effector->mesh);
4743  }
4744  fmd->effector->mesh = NULL;
4745 
4747  fmd->effector->numverts = 0;
4749 
4750  MEM_freeN(fmd->effector);
4751  fmd->effector = NULL;
4752  }
4753 }
4754 
4755 static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock)
4756 {
4757  if (!fmd) {
4758  return;
4759  }
4760 
4761  if (fmd->domain) {
4762  if (fmd->domain->fluid) {
4763  if (need_lock) {
4765  }
4766 
4767 #ifdef WITH_FLUID
4768  manta_free(fmd->domain->fluid);
4769 #endif
4770  fmd->domain->fluid = NULL;
4771 
4772  if (need_lock) {
4774  }
4775  }
4776 
4777  fmd->time = -1;
4778  fmd->domain->total_cells = 0;
4779  fmd->domain->active_fields = 0;
4780  }
4781  else if (fmd->flow) {
4782  MEM_SAFE_FREE(fmd->flow->verts_old);
4783  fmd->flow->numverts = 0;
4785  }
4786  else if (fmd->effector) {
4788  fmd->effector->numverts = 0;
4790  }
4791 }
4792 
4794 {
4795  BKE_fluid_modifier_reset_ex(fmd, true);
4796 }
4797 
4799 {
4800  if (!fmd) {
4801  return;
4802  }
4803 
4807 }
4808 
4810 {
4811  if (!fmd) {
4812  return;
4813  }
4814 
4815  if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
4816  if (fmd->domain) {
4818  }
4819 
4821  fmd->domain->fmd = fmd;
4822 
4823  /* Turn off incompatible options. */
4824 #ifndef WITH_OPENVDB
4828 #endif
4829 #ifndef WITH_OPENVDB_BLOSC
4831 #endif
4832 
4835 
4836  char cache_name[64];
4837  BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
4839  fmd->domain->cache_directory, sizeof(fmd->domain->cache_directory), cache_name);
4840 
4841  /* pointcache options */
4842  fmd->domain->point_cache[0] = BKE_ptcache_add(&(fmd->domain->ptcaches[0]));
4844  fmd->domain->point_cache[0]->step = 1;
4845  fmd->domain->point_cache[1] = NULL; /* Deprecated */
4846  }
4847  else if (fmd->type & MOD_FLUID_TYPE_FLOW) {
4848  if (fmd->flow) {
4850  }
4851 
4853  fmd->flow->fmd = fmd;
4854  }
4855  else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
4856  if (fmd->effector) {
4858  }
4859 
4861  fmd->effector->fmd = fmd;
4862  }
4863 }
4864 
4866  struct FluidModifierData *tfmd,
4867  const int flag)
4868 {
4869  tfmd->type = fmd->type;
4870  tfmd->time = fmd->time;
4871 
4873 
4874  if (tfmd->domain) {
4875  FluidDomainSettings *tfds = tfmd->domain;
4876  FluidDomainSettings *fds = fmd->domain;
4877 
4878  /* domain object data */
4879  tfds->fluid_group = fds->fluid_group;
4880  tfds->force_group = fds->force_group;
4881  tfds->effector_group = fds->effector_group;
4882  if (tfds->effector_weights) {
4883  MEM_freeN(tfds->effector_weights);
4884  }
4886 
4887  /* adaptive domain options */
4888  tfds->adapt_margin = fds->adapt_margin;
4889  tfds->adapt_res = fds->adapt_res;
4890  tfds->adapt_threshold = fds->adapt_threshold;
4891 
4892  /* fluid domain options */
4893  tfds->maxres = fds->maxres;
4894  tfds->solver_res = fds->solver_res;
4895  tfds->border_collisions = fds->border_collisions;
4896  tfds->flags = fds->flags;
4897  tfds->gravity[0] = fds->gravity[0];
4898  tfds->gravity[1] = fds->gravity[1];
4899  tfds->gravity[2] = fds->gravity[2];
4900  tfds->active_fields = fds->active_fields;
4901  tfds->type = fds->type;
4902  tfds->boundary_width = fds->boundary_width;
4903 
4904  /* smoke domain options */
4905  tfds->alpha = fds->alpha;
4906  tfds->beta = fds->beta;
4907  tfds->diss_speed = fds->diss_speed;
4908  tfds->vorticity = fds->vorticity;
4909  tfds->highres_sampling = fds->highres_sampling;
4910 
4911  /* flame options */
4912  tfds->burning_rate = fds->burning_rate;
4913  tfds->flame_smoke = fds->flame_smoke;
4914  tfds->flame_vorticity = fds->flame_vorticity;
4915  tfds->flame_ignition = fds->flame_ignition;
4916  tfds->flame_max_temp = fds->flame_max_temp;
4918 
4919  /* noise options */
4920  tfds->noise_strength = fds->noise_strength;
4921  tfds->noise_pos_scale = fds->noise_pos_scale;
4922  tfds->noise_time_anim = fds->noise_time_anim;
4923  tfds->noise_scale = fds->noise_scale;
4924 
4925  /* liquid domain options */
4926  tfds->flip_ratio = fds->flip_ratio;
4928  tfds->particle_number = fds->particle_number;
4929  tfds->particle_minimum = fds->particle_minimum;
4930  tfds->particle_maximum = fds->particle_maximum;
4931  tfds->particle_radius = fds->particle_radius;
4936  tfds->simulation_method = fds->simulation_method;
4937 
4938  /* viscosity options */
4939  tfds->viscosity_value = fds->viscosity_value;
4940 
4941  /* Diffusion options. */
4942  tfds->surface_tension = fds->surface_tension;
4943  tfds->viscosity_base = fds->viscosity_base;
4945 
4946  /* mesh options */
4950  tfds->mesh_smoothen_pos = fds->mesh_smoothen_pos;
4951  tfds->mesh_smoothen_neg = fds->mesh_smoothen_neg;
4952  tfds->mesh_scale = fds->mesh_scale;
4953  tfds->mesh_generator = fds->mesh_generator;
4954 
4955  /* secondary particle options */
4956  tfds->sndparticle_k_b = fds->sndparticle_k_b;
4957  tfds->sndparticle_k_d = fds->sndparticle_k_d;
4958  tfds->sndparticle_k_ta = fds->sndparticle_k_ta;
4959  tfds->sndparticle_k_wc = fds->sndparticle_k_wc;
4960  tfds->sndparticle_l_max = fds->sndparticle_l_max;
4961  tfds->sndparticle_l_min = fds->sndparticle_l_min;
4972  tfds->particle_type = fds->particle_type;
4973  tfds->particle_scale = fds->particle_scale;
4974 
4975  /* fluid guide options */
4976  tfds->guide_parent = fds->guide_parent;
4977  tfds->guide_alpha = fds->guide_alpha;
4978  tfds->guide_beta = fds->guide_beta;
4979  tfds->guide_vel_factor = fds->guide_vel_factor;
4980  copy_v3_v3_int(tfds->guide_res, fds->guide_res);
4981  tfds->guide_source = fds->guide_source;
4982 
4983  /* cache options */
4984  tfds->cache_frame_start = fds->cache_frame_start;
4985  tfds->cache_frame_end = fds->cache_frame_end;
4992  tfds->cache_flag = fds->cache_flag;
4993  tfds->cache_type = fds->cache_type;
4994  tfds->cache_mesh_format = fds->cache_mesh_format;
4995  tfds->cache_data_format = fds->cache_data_format;
4998  BLI_strncpy(tfds->cache_directory, fds->cache_directory, sizeof(tfds->cache_directory));
4999 
5000  /* time options */
5001  tfds->time_scale = fds->time_scale;
5002  tfds->cfl_condition = fds->cfl_condition;
5003  tfds->timesteps_minimum = fds->timesteps_minimum;
5004  tfds->timesteps_maximum = fds->timesteps_maximum;
5005 
5006  /* display options */
5007  tfds->axis_slice_method = fds->axis_slice_method;
5008  tfds->slice_axis = fds->slice_axis;
5009  tfds->interp_method = fds->interp_method;
5010  tfds->draw_velocity = fds->draw_velocity;
5011  tfds->slice_per_voxel = fds->slice_per_voxel;
5012  tfds->slice_depth = fds->slice_depth;
5013  tfds->display_thickness = fds->display_thickness;
5014  tfds->show_gridlines = fds->show_gridlines;
5015  if (fds->coba) {
5016  tfds->coba = MEM_dupallocN(fds->coba);
5017  }
5018  tfds->vector_scale = fds->vector_scale;
5019  tfds->vector_draw_type = fds->vector_draw_type;
5020  tfds->vector_field = fds->vector_field;
5023  tfds->use_coba = fds->use_coba;
5024  tfds->coba_field = fds->coba_field;
5025  tfds->grid_scale = fds->grid_scale;
5031 
5032  /* -- Deprecated / unused options (below)-- */
5033 
5034  /* pointcache options */
5035  BKE_ptcache_free_list(&(tfds->ptcaches[0]));
5037  /* Share the cache with the original object's modifier. */
5039  tfds->point_cache[0] = fds->point_cache[0];
5040  tfds->ptcaches[0] = fds->ptcaches[0];
5041  }
5042  else {
5044  &(tfds->ptcaches[0]), &(fds->ptcaches[0]), flag);
5045  }
5046 
5047  /* OpenVDB cache options */
5049  tfds->clipping = fds->clipping;
5051 
5052  /* Render options. */
5053  tfds->velocity_scale = fds->velocity_scale;
5054  }
5055  else if (tfmd->flow) {
5056  FluidFlowSettings *tffs = tfmd->flow;
5057  FluidFlowSettings *ffs = fmd->flow;
5058 
5059  /* NOTE: This is dangerous, as it will generate invalid data in case we are copying between
5060  * different objects. Extra external code has to be called then to ensure proper remapping of
5061  * that pointer. See e.g. `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
5062  tffs->psys = ffs->psys;
5063  tffs->noise_texture = ffs->noise_texture;
5064 
5065  /* initial velocity */
5066  tffs->vel_multi = ffs->vel_multi;
5067  tffs->vel_normal = ffs->vel_normal;
5068  tffs->vel_random = ffs->vel_random;
5069  tffs->vel_coord[0] = ffs->vel_coord[0];
5070  tffs->vel_coord[1] = ffs->vel_coord[1];
5071  tffs->vel_coord[2] = ffs->vel_coord[2];
5072 
5073  /* emission */
5074  tffs->density = ffs->density;
5075  copy_v3_v3(tffs->color, ffs->color);
5076  tffs->fuel_amount = ffs->fuel_amount;
5077  tffs->temperature = ffs->temperature;
5078  tffs->volume_density = ffs->volume_density;
5079  tffs->surface_distance = ffs->surface_distance;
5080  tffs->particle_size = ffs->particle_size;
5081  tffs->subframes = ffs->subframes;
5082 
5083  /* texture control */
5084  tffs->texture_size = ffs->texture_size;
5085  tffs->texture_offset = ffs->texture_offset;
5086  BLI_strncpy(tffs->uvlayer_name, ffs->uvlayer_name, sizeof(tffs->uvlayer_name));
5087  tffs->vgroup_density = ffs->vgroup_density;
5088 
5089  tffs->type = ffs->type;
5090  tffs->behavior = ffs->behavior;
5091  tffs->source = ffs->source;
5092  tffs->texture_type = ffs->texture_type;
5093  tffs->flags = ffs->flags;
5094  }
5095  else if (tfmd->effector) {
5096  FluidEffectorSettings *tfes = tfmd->effector;
5097  FluidEffectorSettings *fes = fmd->effector;
5098 
5099  tfes->surface_distance = fes->surface_distance;
5100  tfes->type = fes->type;
5101  tfes->flags = fes->flags;
5102  tfes->subframes = fes->subframes;
5103 
5104  /* guide options */
5105  tfes->guide_mode = fes->guide_mode;
5106  tfes->vel_multi = fes->vel_multi;
5107  }
5108 }
5109 
5110 void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name)
5111 {
5112  static int counter = 1;
5113  BLI_snprintf(r_name, maxlen, FLUID_DOMAIN_DIR_DEFAULT "_%x", BLI_hash_int(counter));
5114  counter++;
5115 }
5116 
typedef float(TangentPoint)[2]
Generic geometry attributes built on CustomData.
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
struct CustomDataLayer * BKE_id_attribute_new(struct ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports)
Definition: attribute.cc:220
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:73
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition: bvhutils.cc:1213
struct Object ** BKE_collision_objects_create(struct Depsgraph *depsgraph, struct Object *self, struct Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
Definition: collision.c:1275
void BKE_collision_objects_free(struct Object **objects)
Definition: collision.c:1315
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_set_layer(const struct CustomData *data, int type, void *ptr)
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_get_layer(const struct CustomData *data, int type)
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
void BKE_effectors_free(struct ListBase *lb)
Definition: effect.c:369
void BKE_effectors_apply(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *wind_force, float *impulse)
Definition: effect.c:1114
struct EffectorWeights * BKE_effector_add_weights(struct Collection *collection)
Definition: effect.c:58
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point)
Definition: effect.c:419
struct ListBase * BKE_effectors_create(struct Depsgraph *depsgraph, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool use_rotation)
Definition: effect.c:314
void BKE_fluid_cache_free_all(struct FluidDomainSettings *fds, struct Object *ob)
int BKE_fluid_get_data_flags(struct FluidDomainSettings *fds)
bool BKE_fluid_reallocate_fluid(struct FluidDomainSettings *fds, int res[3], int free_old)
void BKE_fluid_particle_system_destroy(struct Object *ob, int particle_type)
void BKE_fluid_particle_system_create(struct Main *bmain, struct Object *ob, const char *pset_name, const char *parts_name, const char *psys_name, int psys_type)
struct Mesh * BKE_fluid_modifier_do(struct FluidModifierData *fmd, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Mesh *me)
float(* BKE_Fluid_BresenhamFn)(float *result, const float *input, int res[3], int *pixel, float *tRay, float correct)
Definition: BKE_fluid.h:22
void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *fds, int o_res[3], int n_res[3], const int o_min[3], const int n_min[3], const int o_max[3], int o_shift[3], int n_shift[3])
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
void BKE_fluid_cache_free(struct FluidDomainSettings *fds, struct Object *ob, int cache_map)
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
Definition: BKE_lib_id.h:143
void BKE_id_free(struct Main *bmain, void *idv)
float(* BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3]
struct Mesh * BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference)
void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *me_src)
const float(* BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3]
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
void BKE_mesh_texspace_calc(struct Mesh *me)
Definition: mesh.cc:1231
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
void BKE_modifier_free(struct ModifierData *md)
struct ModifierData * BKE_modifiers_get_virtual_modifierlist(const struct Object *ob, struct VirtualModifierData *data)
const char * BKE_modifier_path_relbase_from_global(struct Object *ob)
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
void BKE_modifier_remove_from_list(struct Object *ob, struct ModifierData *md)
struct ModifierData * BKE_modifier_new(int type)
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md)
General operations, lookup, etc. for blender objects.
bool BKE_object_modifier_update_subframe(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, bool update_mesh, int parent_recursion, float frame, int type)
Definition: object.cc:5405
bool BKE_object_moves_in_time(const struct Object *object, bool recurse_parent)
struct ParticleSettings * BKE_particlesettings_add(struct Main *bmain, const char *name)
Definition: particle.c:4115
void psys_sim_data_free(struct ParticleSimulationData *sim)
Definition: particle.c:726
struct ParticleSystemModifierData * psys_get_modifier(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:2230
void psys_free(struct Object *ob, struct ParticleSystem *psys)
Definition: particle.c:1068
void psys_sim_data_init(struct ParticleSimulationData *sim)
Definition: particle.c:685
bool psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, bool always)
Definition: particle.c:4884
struct PointCache * BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const struct ListBase *ptcaches_old, int flag)
int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode)
Definition: pointcache.c:2870
struct PointCache * BKE_ptcache_add(struct ListBase *ptcaches)
Definition: pointcache.c:3014
void BKE_ptcache_free_list(struct ListBase *ptcaches)
Definition: pointcache.c:3052
#define PTCACHE_RESET_OUTDATED
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *fmd)
Definition: pointcache.c:999
float BKE_scene_ctime_get(const struct Scene *scene)
void BKE_texture_get_value(const struct Scene *scene, struct Tex *texture, const float *tex_co, struct TexResult *texres, bool use_color_management)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:314
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL()
Definition: fileops.c:934
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
Definition: BLI_hash.h:89
float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3])
Definition: BLI_kdopbvh.c:1954
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1942
int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1616
A KD-tree for nearest neighbor search.
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
MINLINE float pow2f(float x)
MINLINE int max_ii(int a, int b)
MINLINE int min_iii(int a, int b, int c)
void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3])
Definition: math_geom.c:3603
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:790
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_fl(float r[3], float f)
MINLINE void madd_v3fl_v3fl_v3fl_v3i(float r[3], const float a[3], const float b[3], const int c[3])
MINLINE float normalize_v3(float r[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3])
Definition: math_vector.c:160
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v2_v2v2v2(float r[2], const float a[2], const float b[2], const float c[2], const float t[3])
Definition: math_vector.c:22
MINLINE void copy_v3_v3_int(int r[3], const int a[3])
void copy_vn_fl(float *array_tar, int size, float val)
Definition: math_vector.c:1259
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3_int(int r[3])
MINLINE void abs_v3(float r[3])
MINLINE void negate_v3(float r[3])
MINLINE void sub_v3_v3v3_int(int r[3], const int a[3], const int b[3])
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first,...) ATTR_NONNULL(1
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:897
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define THREAD_LOCK_WRITE
Definition: BLI_threads.h:121
#define BLI_MUTEX_INITIALIZER
Definition: BLI_threads.h:83
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition: threads.cc:488
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:373
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:378
ThreadRWMutex * BLI_rw_mutex_alloc(void)
Definition: threads.cc:508
void BLI_rw_mutex_free(ThreadRWMutex *mutex)
Definition: threads.cc:516
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
Definition: threads.cc:498
pthread_mutex_t ThreadMutex
Definition: BLI_threads.h:82
#define CLAMP_MAX(a, c)
#define INIT_MINMAX(min, max)
#define MAX3(a, b, c)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED(x)
#define UNPACK3(a)
#define MAX2(a, b)
#define ELEM(...)
#define MIN2(a, b)
#define CLAMP3(vec, b, c)
#define CLAMP_MIN(a, b)
float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3])
Definition: voxel.c:54
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
float DEG_get_ctime(const Depsgraph *graph)
struct ViewLayer * DEG_get_evaluated_view_layer(const struct Depsgraph *graph)
@ CD_PROP_FLOAT3
@ CD_MDEFORMVERT
@ CD_MVERT
@ CD_MLOOPUV
#define DNA_struct_default_alloc(struct_name)
Definition: DNA_defaults.h:32
@ FLUID_FLOW_ABSOLUTE
@ FLUID_FLOW_TEXTUREEMIT
@ FLUID_FLOW_USE_PART_SIZE
@ FLUID_FLOW_NEEDS_UPDATE
@ FLUID_FLOW_USE_PLANE_INIT
@ FLUID_FLOW_INITVELOCITY
@ FLUID_FLOW_USE_INFLOW
@ FLUID_EFFECTOR_GUIDE_MAX
@ FLUID_EFFECTOR_GUIDE_OVERRIDE
@ FLUID_EFFECTOR_GUIDE_AVERAGED
@ FLUID_EFFECTOR_GUIDE_MIN
#define FLUID_DOMAIN_DIR_DATA
#define FLUID_DOMAIN_DIR_PARTICLES
@ FLUID_DOMAIN_TYPE_GAS
@ FLUID_DOMAIN_TYPE_LIQUID
@ FLUID_FLOW_SOURCE_PARTICLES
@ FLUID_FLOW_SOURCE_MESH
#define FLUID_DOMAIN_DIR_DEFAULT
#define FLUID_DOMAIN_DIR_MESH
#define FLUID_DOMAIN_DIR_GUIDE
#define FLUID_DOMAIN_DIR_SCRIPT
@ FLUID_DOMAIN_PARTICLE_SPRAY
@ FLUID_DOMAIN_PARTICLE_FOAM
@ FLUID_DOMAIN_PARTICLE_TRACER
@ FLUID_DOMAIN_PARTICLE_BUBBLE
@ FLUID_DOMAIN_CACHE_ALL
@ FLUID_DOMAIN_CACHE_REPLAY
@ FLUID_DOMAIN_CACHE_MODULAR
@ FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN
@ FLUID_DOMAIN_USE_MESH
@ FLUID_DOMAIN_USE_RESUMABLE_CACHE
@ FLUID_DOMAIN_USE_GUIDE
@ FLUID_DOMAIN_EXPORT_MANTA_SCRIPT
@ FLUID_DOMAIN_USE_SPEED_VECTORS
@ FLUID_DOMAIN_USE_NOISE
@ FLUID_DOMAIN_FILE_LOAD
@ FLUID_DOMAIN_ACTIVE_COLORS
@ FLUID_DOMAIN_ACTIVE_FIRE
@ FLUID_DOMAIN_ACTIVE_INVEL
@ FLUID_DOMAIN_ACTIVE_GUIDE
@ FLUID_DOMAIN_ACTIVE_OUTFLOW
@ FLUID_DOMAIN_ACTIVE_COLOR_SET
@ FLUID_DOMAIN_ACTIVE_HEAT
@ FLUID_DOMAIN_ACTIVE_OBSTACLE
@ VDB_PRECISION_MINI_FLOAT
@ VDB_PRECISION_HALF_FLOAT
@ FLUID_DOMAIN_FIELD_COLOR_B
@ FLUID_DOMAIN_FIELD_FLAME
@ FLUID_DOMAIN_FIELD_PHI_OUT
@ FLUID_DOMAIN_FIELD_PHI_OBSTACLE
@ FLUID_DOMAIN_FIELD_PHI
@ FLUID_DOMAIN_FIELD_DENSITY
@ FLUID_DOMAIN_FIELD_PHI_IN
@ FLUID_DOMAIN_FIELD_HEAT
@ FLUID_DOMAIN_FIELD_COLOR_G
@ FLUID_DOMAIN_FIELD_FUEL
@ FLUID_DOMAIN_FIELD_COLOR_R
#define FLUID_DOMAIN_DIR_CONFIG
@ FLUID_DOMAIN_BAKED_DATA
@ FLUID_DOMAIN_OUTDATED_GUIDE
@ FLUID_DOMAIN_OUTDATED_PARTICLES
@ FLUID_DOMAIN_BAKING_MESH
@ FLUID_DOMAIN_BAKING_NOISE
@ FLUID_DOMAIN_BAKING_GUIDE
@ FLUID_DOMAIN_OUTDATED_NOISE
@ FLUID_DOMAIN_BAKED_NOISE
@ FLUID_DOMAIN_BAKED_MESH
@ FLUID_DOMAIN_OUTDATED_MESH
@ FLUID_DOMAIN_BAKING_DATA
@ FLUID_DOMAIN_BAKED_GUIDE
@ FLUID_DOMAIN_BAKED_PARTICLES
@ FLUID_DOMAIN_OUTDATED_DATA
@ FLUID_DOMAIN_BAKING_PARTICLES
@ FLUID_FLOW_TYPE_FIRE
@ FLUID_FLOW_TYPE_SMOKEFIRE
@ FLUID_FLOW_TYPE_LIQUID
@ FLUID_FLOW_TYPE_SMOKE
@ FLUID_DOMAIN_BORDER_BOTTOM
@ FLUID_DOMAIN_BORDER_LEFT
@ FLUID_DOMAIN_BORDER_RIGHT
@ FLUID_DOMAIN_BORDER_FRONT
@ FLUID_DOMAIN_BORDER_TOP
@ FLUID_DOMAIN_BORDER_BACK
@ VDB_COMPRESSION_ZIP
@ FLUID_DOMAIN_FILE_UNI
@ FLUID_DOMAIN_GUIDE_SRC_DOMAIN
@ FLUID_FLOW_TEXTURE_MAP_AUTO
@ FLUID_EFFECTOR_NEEDS_UPDATE
@ FLUID_EFFECTOR_USE_EFFEC
@ FLUID_EFFECTOR_USE_PLANE_INIT
#define FLUID_DOMAIN_DIR_NOISE
@ FLUID_FLOW_BEHAVIOR_GEOMETRY
@ FLUID_FLOW_BEHAVIOR_OUTFLOW
@ FLUID_FLOW_BEHAVIOR_INFLOW
@ FLUID_EFFECTOR_TYPE_GUIDE
@ FLUID_EFFECTOR_TYPE_COLLISION
#define LA_LOCAL
@ eModifierFlag_SharedCaches
@ eModifierType_ParticleSystem
@ eModifierType_Explode
@ eModifierType_Cloth
@ eModifierType_Fluid
@ eModifierType_ShapeKey
@ eModifierType_Ocean
@ eModifierType_Nodes
@ eModifierType_DynamicPaint
@ eModifierType_Softbody
@ MOD_FLUID_TYPE_EFFEC
@ MOD_FLUID_TYPE_DOMAIN
@ MOD_FLUID_TYPE_FLOW
@ OB_WIRE
@ OB_SOLID
@ PFIELD_FLUIDFLOW
Object is a sort of wrapper for general info.
@ OB_LAMP
#define PARS_UNEXIST
#define PARS_NO_DISP
@ PART_EMITTER
@ PART_FLUID
@ PART_HAIR
#define PART_PHYS_NO
#define PART_DRAW_COL_VEL
@ PTCACHE_OUTDATED
@ PTCACHE_DISK_CACHE
Types and defines for representing Rigid Body entities.
@ RBO_TYPE_ACTIVE
#define FIRSTBASE(_view_layer)
#define PHYS_GLOBAL_GRAVITY
#define FPS
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_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
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
size_t index
#define expf(x)
Definition: cuda/compat.h:106
double time
Scene scene
const Depsgraph * depsgraph
SyclQueue void void size_t num_bytes SyclQueue void const char void *memory_device_pointer KernelContext int size_t global_size
void * tree
#define PHI_MAX
Definition: fluid.c:80
void BKE_fluid_modifier_reset(struct FluidModifierData *fmd)
Definition: fluid.c:4793
#define DT_DEFAULT
Definition: fluid.c:77
void BKE_fluid_cachetype_noise_set(FluidDomainSettings *settings, int cache_noise_format)
Definition: fluid.c:4566
static void BKE_fluid_modifier_freeDomain(FluidModifierData *fmd)
Definition: fluid.c:4692
void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd, struct FluidModifierData *tfmd, const int flag)
Definition: fluid.c:4865
void BKE_fluid_cachetype_particle_set(FluidDomainSettings *settings, int cache_particle_format)
Definition: fluid.c:4557
void BKE_fluid_flow_behavior_set(Object *UNUSED(object), FluidFlowSettings *settings, int behavior)
Definition: fluid.c:4622
void BKE_fluid_domain_type_set(Object *object, FluidDomainSettings *settings, int type)
Definition: fluid.c:4595
void BKE_fluid_particles_set(FluidDomainSettings *settings, int value, bool clear)
Definition: fluid.c:4585
static void BKE_fluid_modifier_freeFlow(FluidModifierData *fmd)
Definition: fluid.c:4721
void BKE_fluid_cachetype_data_set(FluidDomainSettings *settings, int cache_data_format)
Definition: fluid.c:4548
static void BKE_fluid_modifier_freeEffector(FluidModifierData *fmd)
Definition: fluid.c:4738
static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock)
Definition: fluid.c:4755
void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd)
Definition: fluid.c:4809
void BKE_fluid_collisionextents_set(FluidDomainSettings *settings, int value, bool clear)
Definition: fluid.c:4575
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name)
Definition: fluid.c:5110
void BKE_fluid_cache_endframe_set(FluidDomainSettings *settings, int value)
Definition: fluid.c:4533
void BKE_fluid_fields_sanitize(FluidDomainSettings *settings)
Definition: fluid.c:4647
void BKE_fluid_cache_startframe_set(FluidDomainSettings *settings, int value)
Definition: fluid.c:4527
void BKE_fluid_flow_type_set(Object *object, FluidFlowSettings *settings, int type)
Definition: fluid.c:4627
void BKE_fluid_effector_type_set(Object *UNUSED(object), FluidEffectorSettings *settings, int type)
Definition: fluid.c:4642
void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
Definition: fluid.c:4539
void BKE_fluid_modifier_free(FluidModifierData *fmd)
Definition: fluid.c:4798
static float verts[][3]
uint pos
ccl_gpu_kernel_postfix ccl_global int * counter
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
const int state
#define LOG(severity)
Definition: log.h:36
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
float * manta_smoke_get_heat_in(struct MANTA *smoke)
bool manta_has_particles(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_smoke_get_shadow(struct MANTA *fluid)
float * manta_smoke_get_color_g(struct MANTA *smoke)
float * manta_get_force_y(struct MANTA *fluid)
bool manta_has_mesh(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_phiobs_in(struct MANTA *fluid)
float manta_liquid_get_vertex_y_at(struct MANTA *liquid, int i)
float * manta_smoke_get_color_b(struct MANTA *smoke)
float * manta_smoke_get_emission_in(struct MANTA *smoke)
float * manta_noise_get_texture_w2(struct MANTA *smoke)
bool manta_ensure_invelocity(struct MANTA *fluid, struct FluidModifierData *fmd)
bool manta_read_guiding(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool sourceDomain)
bool manta_has_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
bool manta_bake_particles(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_phioutstatic_in(struct MANTA *fluid)
float * manta_smoke_get_fuel(struct MANTA *smoke)
float * manta_smoke_get_heat(struct MANTA *smoke)
bool manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *fmd)
void manta_free(struct MANTA *fluid)
bool manta_smoke_has_heat(struct MANTA *smoke)
int manta_liquid_get_num_triangles(struct MANTA *liquid)
bool manta_bake_mesh(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_get_timestep(struct MANTA *fluid)
float * manta_get_in_velocity_x(struct MANTA *fluid)
bool manta_bake_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_smoke_get_color_g_in(struct MANTA *smoke)
float * manta_smoke_get_color_b_in(struct MANTA *smoke)
float * manta_noise_get_texture_u2(struct MANTA *smoke)
float * manta_smoke_get_color_r_in(struct MANTA *smoke)
float * manta_get_phistatic_in(struct MANTA *fluid)
float * manta_get_guide_velocity_z(struct MANTA *fluid)
float * manta_smoke_get_density(struct MANTA *smoke)
float * manta_smoke_get_color_r(struct MANTA *smoke)
bool manta_read_mesh(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
bool manta_liquid_ensure_sndparts(struct MANTA *fluid, struct FluidModifierData *fmd)
float * manta_get_force_x(struct MANTA *fluid)
float * manta_get_velocity_x(struct MANTA *fluid)
float * manta_smoke_get_flame(struct MANTA *smoke)
float * manta_noise_get_texture_v2(struct MANTA *smoke)
bool manta_write_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
int * manta_smoke_get_flags(struct MANTA *smoke)
float * manta_get_phi_in(struct MANTA *fluid)
bool manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *fmd)
float * manta_get_velocity_y(struct MANTA *fluid)
void manta_noise_get_res(struct MANTA *smoke, int *res)
float * manta_noise_get_fuel(struct MANTA *smoke)
float manta_liquid_get_vertvel_y_at(struct MANTA *liquid, int i)
int manta_liquid_get_num_verts(struct MANTA *liquid)
bool manta_ensure_obstacle(struct MANTA *fluid, struct FluidModifierData *fmd)
bool manta_write_config(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_in_velocity_z(struct MANTA *fluid)
float * manta_noise_get_texture_v(struct MANTA *smoke)
bool manta_needs_realloc(struct MANTA *fluid, struct FluidModifierData *fmd)
bool manta_has_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_liquid_get_vertvel_z_at(struct MANTA *liquid, int i)
bool manta_read_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool resumable)
float * manta_get_num_guide(struct MANTA *fluid)
size_t manta_get_index(int x, int max_x, int y, int max_y, int z)
bool manta_read_particles(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool resumable)
bool manta_write_noise(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_force_z(struct MANTA *fluid)
float manta_liquid_get_vertvel_x_at(struct MANTA *liquid, int i)
float * manta_get_ob_velocity_x(struct MANTA *fluid)
float * manta_smoke_get_fuel_in(struct MANTA *smoke)
bool manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *fmd)
void manta_update_pointers(struct MANTA *fluid, struct FluidModifierData *fmd, bool flush)
bool manta_ensure_guiding(struct MANTA *fluid, struct FluidModifierData *fmd)
float * manta_noise_get_density(struct MANTA *smoke)
bool manta_read_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool resumable)
float * manta_noise_get_color_b(struct MANTA *smoke)
float * manta_get_ob_velocity_z(struct MANTA *fluid)
float * manta_get_guide_velocity_x(struct MANTA *fluid)
float * manta_get_phiout_in(struct MANTA *fluid)
bool manta_has_guiding(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr, bool domain)
float * manta_noise_get_react(struct MANTA *smoke)
float * manta_noise_get_flame(struct MANTA *smoke)
bool manta_smoke_has_colors(struct MANTA *smoke)
bool manta_read_config(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float manta_liquid_get_vertex_z_at(struct MANTA *liquid, int i)
float * manta_smoke_get_react_in(struct MANTA *smoke)
float * manta_get_in_velocity_y(struct MANTA *fluid)
float * manta_get_velocity_z(struct MANTA *fluid)
float * manta_noise_get_texture_w(struct MANTA *smoke)
int manta_liquid_get_triangle_z_at(struct MANTA *liquid, int i)
bool manta_smoke_has_fuel(struct MANTA *smoke)
float manta_liquid_get_vertex_x_at(struct MANTA *liquid, int i)
float * manta_smoke_get_react(struct MANTA *smoke)
bool manta_liquid_export_script(struct MANTA *smoke, struct FluidModifierData *fmd)
bool manta_ensure_outflow(struct MANTA *fluid, struct FluidModifierData *fmd)
void manta_update_variables(struct MANTA *fluid, struct FluidModifierData *fmd)
int manta_liquid_get_triangle_x_at(struct MANTA *liquid, int i)
float * manta_get_num_obstacle(struct MANTA *fluid)
float * manta_get_phiguide_in(struct MANTA *fluid)
struct MANTA * manta_init(int *res, struct FluidModifierData *fmd)
float * manta_get_guide_velocity_y(struct MANTA *fluid)
float * manta_get_ob_velocity_y(struct MANTA *fluid)
void manta_adapt_timestep(struct MANTA *fluid)
int manta_liquid_get_triangle_y_at(struct MANTA *liquid, int i)
float * manta_noise_get_texture_u(struct MANTA *smoke)
bool manta_bake_data(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
bool manta_smoke_export_script(struct MANTA *smoke, struct FluidModifierData *fmd)
float * manta_noise_get_color_r(struct MANTA *smoke)
bool manta_bake_guiding(struct MANTA *fluid, struct FluidModifierData *fmd, int framenr)
float * manta_get_phiobsstatic_in(struct MANTA *fluid)
float * manta_noise_get_color_g(struct MANTA *smoke)
float * manta_smoke_get_density_in(struct MANTA *smoke)
ccl_device_inline float3 ceil(const float3 &a)
Definition: math_float3.h:363
ccl_device_inline float3 pow(float3 v, float e)
Definition: math_float3.h:533
#define G(x, y, z)
#define floorf(x)
Definition: metal/compat.h:224
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static void clear(Message *msg)
Definition: msgfmt.c:278
T floor(const T &a)
T abs(const T &a)
bool is_adaptive(CpuPatchTable *patch_table)
Definition: eval_output.cc:24
static const pxr::TfToken density("density", pxr::TfToken::Immortal)
smooth(Type::FLOAT, "mask_weight")
static void update_velocities(PTCacheEdit *edit)
#define min(a, b)
Definition: sort.c:35
BVHTree_RayCastCallback raycast_callback
Definition: BKE_bvhutils.h:54
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
BVHTree_NearestPointCallback nearest_callback
Definition: BKE_bvhutils.h:53
float co[3]
Definition: BLI_kdopbvh.h:43
float no[3]
Definition: BLI_kdopbvh.h:70
struct Base * next
struct Object * object
struct ListBase ptcaches[2]
struct FluidModifierData * fmd
struct Collection * force_group
struct Collection * effector_group
struct MANTA * fluid
struct PointCache * point_cache[2]
char cache_directory[1024]
struct ColorBand * coba
float gridlines_range_color[4]
struct Object * guide_parent
struct Collection * fluid_group
struct EffectorWeights * effector_weights
struct FluidModifierData * fmd
struct FluidModifierData * fmd
struct ParticleSystem * psys
struct Mesh * mesh
struct Tex * noise_texture
struct FluidDomainSettings * domain
struct FluidEffectorSettings * effector
struct FluidFlowSettings * flow
short type
void * first
Definition: DNA_listBase.h:31
unsigned int tri[3]
unsigned int v
short mat_nr
float co[3]
Definition: BKE_main.h:121
CustomData vdata
struct MVert * mvert
uint16_t flag
int totvert
struct MLoop * mloop
struct MPoly * mpoly
CustomData ldata
struct ModifierData * next
ListBase particlesystem
ListBase modifiers
struct RigidBodyOb * rigidbody_object
float scale[3]
float imat[4][4]
float obmat[4][4]
void * data
struct PointCache * cache
struct Depsgraph * depsgraph
Definition: BKE_particle.h:69
struct Scene * scene
Definition: BKE_particle.h:70
struct ParticleSystem * psys
Definition: BKE_particle.h:72
struct Object * ob
Definition: BKE_particle.h:71
struct ParticleSystem * psys
ChildParticle * child
struct ListBase ptcaches
ParticleData * particles
ParticleSettings * part
struct ParticleSystem * next
struct PointCache * pointcache
struct PhysicsSettings physics_settings
struct RenderData r
float tin
Definition: RE_texture.h:86
float max