Blender  V3.3
dynamicpaint.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "MEM_guardedalloc.h"
8 
9 #include <math.h>
10 #include <stdio.h>
11 
12 #include "BLI_blenlib.h"
13 #include "BLI_kdtree.h"
14 #include "BLI_math.h"
15 #include "BLI_string_utils.h"
16 #include "BLI_task.h"
17 #include "BLI_threads.h"
18 #include "BLI_utildefines.h"
19 
20 #include "BLT_translation.h"
21 
22 #include "DNA_anim_types.h"
23 #include "DNA_armature_types.h"
24 #include "DNA_collection_types.h"
25 #include "DNA_constraint_types.h"
26 #include "DNA_dynamicpaint_types.h"
27 #include "DNA_material_types.h"
28 #include "DNA_mesh_types.h"
29 #include "DNA_meshdata_types.h"
30 #include "DNA_modifier_types.h"
31 #include "DNA_object_force_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_texture_types.h"
35 
36 #include "BKE_armature.h"
37 #include "BKE_bvhutils.h" /* bvh tree */
38 #include "BKE_collection.h"
39 #include "BKE_collision.h"
40 #include "BKE_colorband.h"
41 #include "BKE_constraint.h"
42 #include "BKE_customdata.h"
43 #include "BKE_deform.h"
44 #include "BKE_dynamicpaint.h"
45 #include "BKE_effect.h"
46 #include "BKE_image.h"
47 #include "BKE_image_format.h"
48 #include "BKE_lib_id.h"
49 #include "BKE_main.h"
50 #include "BKE_material.h"
51 #include "BKE_mesh.h"
52 #include "BKE_mesh_mapping.h"
53 #include "BKE_mesh_runtime.h"
54 #include "BKE_modifier.h"
55 #include "BKE_object.h"
56 #include "BKE_particle.h"
57 #include "BKE_pointcache.h"
58 #include "BKE_scene.h"
59 
60 #include "DEG_depsgraph.h"
61 #include "DEG_depsgraph_query.h"
62 
63 /* for image output */
64 #include "IMB_imbuf.h"
65 #include "IMB_imbuf_types.h"
66 
67 #include "RE_texture.h"
68 
69 #include "atomic_ops.h"
70 
71 #include "CLG_log.h"
72 
73 /* could enable at some point but for now there are far too many conversions */
74 #ifdef __GNUC__
75 //# pragma GCC diagnostic ignored "-Wdouble-promotion"
76 #endif
77 
78 static CLG_LogRef LOG = {"bke.dynamicpaint"};
79 
80 /* precalculated gaussian factors for 5x super sampling */
81 static const float gaussianFactors[5] = {
82  0.996849f,
83  0.596145f,
84  0.596145f,
85  0.596145f,
86  0.524141f,
87 };
88 static const float gaussianTotal = 3.309425f;
89 
90 /* UV Image neighboring pixel table x and y list */
91 static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
92 static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
93 
94 /* Neighbor x/y list that prioritizes grid directions over diagonals */
95 static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
96 static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
97 
98 /* subframe_updateObject() flags */
99 #define SUBFRAME_RECURSION 5
100 /* surface_getBrushFlags() return vals */
101 #define BRUSH_USES_VELOCITY (1 << 0)
102 /* Brush mesh ray-cast status. */
103 #define HIT_VOLUME 1
104 #define HIT_PROXIMITY 2
105 /* dynamicPaint_findNeighborPixel() return codes */
106 #define NOT_FOUND -1
107 #define ON_MESH_EDGE -2
108 #define OUT_OF_TEXTURE -3
109 /* paint effect default movement per frame in global units */
110 #define EFF_MOVEMENT_PER_FRAME 0.05f
111 /* initial wave time factor */
112 #define WAVE_TIME_FAC (1.0f / 24.0f)
113 #define CANVAS_REL_SIZE 5.0f
114 /* drying limits */
115 #define MIN_WETNESS 0.001f
116 #define MAX_WETNESS 5.0f
117 
118 /* dissolve inline function */
119 BLI_INLINE void value_dissolve(float *r_value,
120  const float time,
121  const float scale,
122  const bool is_log)
123 {
124  *r_value = (is_log) ? (*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
125  (*r_value) - 1.0f / time * scale;
126 }
127 
128 /***************************** Internal Structs ***************************/
129 
130 typedef struct Bounds2D {
131  float min[2], max[2];
133 
134 typedef struct Bounds3D {
135  float min[3], max[3];
136  bool valid;
138 
139 typedef struct VolumeGrid {
140  int dim[3];
143 
147  int *s_pos;
149  int *s_num;
151  int *t_index;
152 
155 
156 typedef struct Vec3f {
157  float v[3];
159 
160 typedef struct BakeAdjPoint {
162  float dir[3];
164  float dist;
166 
168 typedef struct PaintBakeNormal {
170  float invNorm[3];
174 
176 typedef struct PaintBakeData {
177  /* point space data */
180  int *s_pos;
182  int *s_num;
186  float dim[3];
187 
188  /* adjacency info */
191  double average_dist;
192  /* space partitioning */
195 
196  /* velocity and movement */
206  float prev_obmat[4][4];
208  int clear;
210 
212 typedef struct PaintUVPoint {
213  /* Pixel / mesh data */
215  unsigned int tri_index;
216  unsigned int pixel_index;
217  /* vertex indexes */
218  unsigned int v1, v2, v3;
219 
221  unsigned int neighbor_pixel;
223 
224 typedef struct ImgSeqFormatData {
226  Vec3f *barycentricWeights; /* b-weights for all pixel samples */
228 
229 /* adjacency data flags */
230 #define ADJ_ON_MESH_EDGE (1 << 0)
231 #define ADJ_BORDER_PIXEL (1 << 1)
232 
233 typedef struct PaintAdjData {
235  int *n_target;
237  int *n_index;
239  int *n_num;
241  int *flags;
245  int *border;
249 
250 /************************* Runtime evaluation store ***************************/
251 
253 {
254  if (runtime_data == NULL) {
255  return;
256  }
257  if (runtime_data->canvas_mesh) {
258  BKE_id_free(NULL, runtime_data->canvas_mesh);
259  }
260  if (runtime_data->brush_mesh) {
261  BKE_id_free(NULL, runtime_data->brush_mesh);
262  }
263  MEM_freeN(runtime_data);
264 }
265 
267 {
268  if (pmd->modifier.runtime == NULL) {
269  pmd->modifier.runtime = MEM_callocN(sizeof(DynamicPaintRuntime), "dynamic paint runtime");
270  }
271  return (DynamicPaintRuntime *)pmd->modifier.runtime;
272 }
273 
275 {
276  if (canvas->pmd->modifier.runtime == NULL) {
277  return NULL;
278  }
279  DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)canvas->pmd->modifier.runtime;
280  return runtime_data->canvas_mesh;
281 }
282 
284 {
285  if (brush->pmd->modifier.runtime == NULL) {
286  return NULL;
287  }
288  DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)brush->pmd->modifier.runtime;
289  return runtime_data->brush_mesh;
290 }
291 
292 /***************************** General Utils ******************************/
293 
294 /* Set canvas error string to display at the bake report */
295 static bool setError(DynamicPaintCanvasSettings *canvas, const char *string)
296 {
297  /* Add error to canvas ui info label */
298  BLI_strncpy(canvas->error, string, sizeof(canvas->error));
299  CLOG_STR_ERROR(&LOG, string);
300  return false;
301 }
302 
303 /* Get number of surface points for cached types */
305 {
306  if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
307  return 0; /* Not supported at the moment. */
308  }
309  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
310  const Mesh *canvas_mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
311  return (canvas_mesh) ? canvas_mesh->totvert : 0;
312  }
313 
314  return 0;
315 }
316 
318 {
319  return BLI_findlink(&canvas->surfaces, canvas->active_sur);
320 }
321 
323 {
324  const char *name;
325 
326  if (output == 0) {
327  name = surface->output_name;
328  }
329  else if (output == 1) {
330  name = surface->output_name2;
331  }
332  else {
333  return false;
334  }
335 
336  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
337  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
338  Mesh *me = ob->data;
339  return (CustomData_get_named_layer_index(&me->ldata, CD_PROP_BYTE_COLOR, name) != -1);
340  }
341  if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
342  return (BKE_object_defgroup_name_index(ob, name) != -1);
343  }
344  }
345 
346  return false;
347 }
348 
349 static bool surface_duplicateOutputExists(void *arg, const char *name)
350 {
351  DynamicPaintSurface *t_surface = arg;
353 
354  for (; surface; surface = surface->next) {
355  if (surface != t_surface && surface->type == t_surface->type &&
356  surface->format == t_surface->format) {
357  if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
358  (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2))) {
359  return true;
360  }
361  }
362  }
363  return false;
364 }
365 
367 {
368  char name[64];
369  BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
370  if (output == 0) {
372  surface,
373  name,
374  '.',
375  surface->output_name,
376  sizeof(surface->output_name));
377  }
378  else if (output == 1) {
380  surface,
381  name,
382  '.',
383  surface->output_name2,
384  sizeof(surface->output_name2));
385  }
386 }
387 
388 static bool surface_duplicateNameExists(void *arg, const char *name)
389 {
390  DynamicPaintSurface *t_surface = arg;
392 
393  for (; surface; surface = surface->next) {
394  if (surface != t_surface && STREQ(name, surface->name)) {
395  return true;
396  }
397  }
398  return false;
399 }
400 
402 {
403  char name[64];
404  BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
406  surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
407 }
408 
410 {
411  if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
412  surface->output_name[0] = '\0';
413  surface->output_name2[0] = '\0';
414  surface->flags |= MOD_DPAINT_ANTIALIAS;
415  surface->depth_clamp = 1.0f;
416  }
417  else {
418  strcpy(surface->output_name, "dp_");
419  BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2));
420  surface->flags &= ~MOD_DPAINT_ANTIALIAS;
421  surface->depth_clamp = 0.0f;
422  }
423 
424  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
425  strcat(surface->output_name, "paintmap");
426  strcat(surface->output_name2, "wetmap");
427  surface_setUniqueOutputName(surface, surface->output_name2, 1);
428  }
429  else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
430  strcat(surface->output_name, "displace");
431  }
432  else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
433  strcat(surface->output_name, "weight");
434  }
435  else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
436  strcat(surface->output_name, "wave");
437  }
438 
439  surface_setUniqueOutputName(surface, surface->output_name, 0);
440 }
441 
443 {
445  return (surface->data->total_points * 5);
446  }
448  surface->data->adj_data) {
449  return (surface->data->total_points + surface->data->adj_data->total_targets);
450  }
451 
452  return surface->data->total_points;
453 }
454 
455 static void blendColors(const float t_color[3],
456  const float t_alpha,
457  const float s_color[3],
458  const float s_alpha,
459  float result[4])
460 {
461  /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
462  float i_alpha = 1.0f - s_alpha;
463  float f_alpha = t_alpha * i_alpha + s_alpha;
464 
465  /* blend colors */
466  if (f_alpha) {
467  for (int i = 0; i < 3; i++) {
468  result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
469  }
470  }
471  else {
472  copy_v3_v3(result, t_color);
473  }
474  /* return final alpha */
475  result[3] = f_alpha;
476 }
477 
478 /* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */
479 static float mixColors(
480  float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
481 {
482  float weight_ratio, factor;
483  if (b_weight) {
484  /* if first value has no weight just use b_color */
485  if (!a_weight) {
486  copy_v3_v3(a_color, b_color);
487  return b_weight * ratio;
488  }
489  weight_ratio = b_weight / (a_weight + b_weight);
490  }
491  else {
492  return a_weight * (1.0f - ratio);
493  }
494 
495  /* calculate final interpolation factor */
496  if (ratio <= 0.5f) {
497  factor = weight_ratio * (ratio * 2.0f);
498  }
499  else {
500  ratio = (ratio * 2.0f - 1.0f);
501  factor = weight_ratio * (1.0f - ratio) + ratio;
502  }
503  /* mix final color */
504  interp_v3_v3v3(a_color, a_color, b_color, factor);
505  return (1.0f - factor) * a_weight + factor * b_weight;
506 }
507 
508 static void scene_setSubframe(Scene *scene, float subframe)
509 {
510  /* dynamic paint subframes must be done on previous frame */
511  scene->r.cfra -= 1;
512  scene->r.subframe = subframe;
513 }
514 
516 {
517  unsigned int numobjects;
519  depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
520 
521  int flags = 0;
522 
523  for (int i = 0; i < numobjects; i++) {
524  Object *brushObj = objects[i];
525 
527  if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
529 
530  if (pmd2->brush) {
531  DynamicPaintBrushSettings *brush = pmd2->brush;
532 
533  if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
534  flags |= BRUSH_USES_VELOCITY;
535  }
536  }
537  }
538  }
539 
541 
542  return flags;
543 }
544 
545 /* check whether two bounds intersect */
546 static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
547 {
548  if (!b1->valid || !b2->valid) {
549  return false;
550  }
551  for (int i = 2; i--;) {
552  if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) {
553  return false;
554  }
555  }
556  return true;
557 }
558 
559 /* check whether two bounds intersect inside defined proximity */
560 static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
561 {
562  if (!b1->valid || !b2->valid) {
563  return false;
564  }
565  for (int i = 2; i--;) {
566  if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) {
567  return false;
568  }
569  }
570  return true;
571 }
572 
573 /* check whether bounds intersects a point with given radius */
574 static bool boundIntersectPoint(Bounds3D *b, const float point[3], const float radius)
575 {
576  if (!b->valid) {
577  return false;
578  }
579  for (int i = 2; i--;) {
580  if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) {
581  return false;
582  }
583  }
584  return true;
585 }
586 
587 /* expand bounds by a new point */
588 static void boundInsert(Bounds3D *b, const float point[3])
589 {
590  if (!b->valid) {
591  copy_v3_v3(b->min, point);
592  copy_v3_v3(b->max, point);
593  b->valid = true;
594  return;
595  }
596 
597  minmax_v3v3_v3(b->min, b->max, point);
598 }
599 
601 {
602  Bounds3D *mb = &sData->bData->mesh_bounds;
603  return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
604 }
605 
607 {
608  PaintBakeData *bData = data->bData;
609  VolumeGrid *grid = bData->grid;
610 
611  if (grid->bounds) {
612  MEM_freeN(grid->bounds);
613  }
614  if (grid->s_pos) {
615  MEM_freeN(grid->s_pos);
616  }
617  if (grid->s_num) {
618  MEM_freeN(grid->s_num);
619  }
620  if (grid->t_index) {
621  MEM_freeN(grid->t_index);
622  }
623 
624  MEM_freeN(bData->grid);
625  bData->grid = NULL;
626 }
627 
628 static void grid_bound_insert_cb_ex(void *__restrict userdata,
629  const int i,
630  const TaskParallelTLS *__restrict tls)
631 {
632  PaintBakeData *bData = userdata;
633 
634  Bounds3D *grid_bound = tls->userdata_chunk;
635 
636  boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
637 }
638 
639 static void grid_bound_insert_reduce(const void *__restrict UNUSED(userdata),
640  void *__restrict chunk_join,
641  void *__restrict chunk)
642 {
643  Bounds3D *join = chunk_join;
644  Bounds3D *grid_bound = chunk;
645 
646  boundInsert(join, grid_bound->min);
647  boundInsert(join, grid_bound->max);
648 }
649 
650 static void grid_cell_points_cb_ex(void *__restrict userdata,
651  const int i,
652  const TaskParallelTLS *__restrict tls)
653 {
654  PaintBakeData *bData = userdata;
655  VolumeGrid *grid = bData->grid;
656  int *temp_t_index = grid->temp_t_index;
657  int *s_num = tls->userdata_chunk;
658 
659  int co[3];
660 
661  for (int j = 3; j--;) {
662  co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
663  bData->dim[j] * grid->dim[j]);
664  CLAMP(co[j], 0, grid->dim[j] - 1);
665  }
666 
667  temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
668  s_num[temp_t_index[i]]++;
669 }
670 
671 static void grid_cell_points_reduce(const void *__restrict userdata,
672  void *__restrict chunk_join,
673  void *__restrict chunk)
674 {
675  const PaintBakeData *bData = userdata;
676  const VolumeGrid *grid = bData->grid;
677  const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
678 
679  int *join_s_num = chunk_join;
680  int *s_num = chunk;
681 
682  /* calculate grid indexes */
683  for (int i = 0; i < grid_cells; i++) {
684  join_s_num[i] += s_num[i];
685  }
686 }
687 
688 static void grid_cell_bounds_cb(void *__restrict userdata,
689  const int x,
690  const TaskParallelTLS *__restrict UNUSED(tls))
691 {
692  PaintBakeData *bData = userdata;
693  VolumeGrid *grid = bData->grid;
694  float *dim = bData->dim;
695  int *grid_dim = grid->dim;
696 
697  for (int y = 0; y < grid_dim[1]; y++) {
698  for (int z = 0; z < grid_dim[2]; z++) {
699  const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
700  /* set bounds */
701  for (int j = 3; j--;) {
702  const int s = (j == 0) ? x : ((j == 1) ? y : z);
703  grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
704  grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
705  }
706  grid->bounds[b_index].valid = true;
707  }
708  }
709 }
710 
712 {
713  PaintSurfaceData *sData = surface->data;
714  PaintBakeData *bData = sData->bData;
715  VolumeGrid *grid;
716  int grid_cells, axis = 3;
717  int *temp_t_index = NULL;
718  int *temp_s_num = NULL;
719 
720  if (bData->grid) {
721  freeGrid(sData);
722  }
723 
724  bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
725  grid = bData->grid;
726 
727  {
728  int i, error = 0;
729  float dim_factor, volume, dim[3];
730  float td[3];
731  float min_dim;
732 
733  /* calculate canvas dimensions */
734  /* Important to init correctly our ref grid_bound... */
735  boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
736  {
737  TaskParallelSettings settings;
739  settings.use_threading = (sData->total_points > 1000);
740  settings.userdata_chunk = &grid->grid_bounds;
741  settings.userdata_chunk_size = sizeof(grid->grid_bounds);
743  BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings);
744  }
745  /* get dimensions */
746  sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
747  copy_v3_v3(td, dim);
748  copy_v3_v3(bData->dim, dim);
749  min_dim = max_fff(td[0], td[1], td[2]) / 1000.0f;
750 
751  /* deactivate zero axes */
752  for (i = 0; i < 3; i++) {
753  if (td[i] < min_dim) {
754  td[i] = 1.0f;
755  axis--;
756  }
757  }
758 
759  if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
760  MEM_freeN(bData->grid);
761  bData->grid = NULL;
762  return;
763  }
764 
765  /* now calculate grid volume/area/width depending on num of active axis */
766  volume = td[0] * td[1] * td[2];
767 
768  /* determine final grid size by trying to fit average 10.000 points per grid cell */
769  dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0),
770  1.0 / (double)axis);
771 
772  /* define final grid size using dim_factor, use min 3 for active axes */
773  for (i = 0; i < 3; i++) {
774  grid->dim[i] = (int)floor(td[i] / dim_factor);
775  CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
776  }
777  grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
778 
779  /* allocate memory for grids */
780  grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
781  grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
782 
783  grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
784  temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
785  grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
786  grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points,
787  "Temp Surface Grid Target Ids");
788 
789  /* in case of an allocation failure abort here */
790  if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num ||
791  !temp_t_index) {
792  error = 1;
793  }
794 
795  if (!error) {
796  /* calculate number of points within each cell */
797  {
798  TaskParallelSettings settings;
800  settings.use_threading = (sData->total_points > 1000);
801  settings.userdata_chunk = grid->s_num;
802  settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
804  BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
805  }
806 
807  /* calculate grid indexes (not needed for first cell, which is zero). */
808  for (i = 1; i < grid_cells; i++) {
809  grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
810  }
811 
812  /* save point indexes to final array */
813  for (i = 0; i < sData->total_points; i++) {
814  int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
815  grid->t_index[pos] = i;
816 
817  temp_s_num[temp_t_index[i]]++;
818  }
819 
820  /* calculate cell bounds */
821  {
822  TaskParallelSettings settings;
824  settings.use_threading = (grid_cells > 1000);
825  BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, &settings);
826  }
827  }
828 
829  if (temp_s_num) {
830  MEM_freeN(temp_s_num);
831  }
832  MEM_SAFE_FREE(temp_t_index);
833 
834  if (error || !grid->s_num) {
835  setError(surface->canvas, N_("Not enough free memory"));
836  freeGrid(sData);
837  }
838  }
839 }
840 
841 /***************************** Freeing data ******************************/
842 
844 {
845  if (pmd->brush) {
846  if (pmd->brush->paint_ramp) {
847  MEM_freeN(pmd->brush->paint_ramp);
848  }
849  if (pmd->brush->vel_ramp) {
850  MEM_freeN(pmd->brush->vel_ramp);
851  }
852 
853  MEM_freeN(pmd->brush);
854  pmd->brush = NULL;
855  }
856 }
857 
859 {
860  if (data->adj_data) {
861  if (data->adj_data->n_index) {
862  MEM_freeN(data->adj_data->n_index);
863  }
864  if (data->adj_data->n_num) {
865  MEM_freeN(data->adj_data->n_num);
866  }
867  if (data->adj_data->n_target) {
868  MEM_freeN(data->adj_data->n_target);
869  }
870  if (data->adj_data->flags) {
871  MEM_freeN(data->adj_data->flags);
872  }
873  if (data->adj_data->border) {
874  MEM_freeN(data->adj_data->border);
875  }
876  MEM_freeN(data->adj_data);
877  data->adj_data = NULL;
878  }
879 }
880 
882 {
883  PaintBakeData *bData = data->bData;
884  if (bData) {
885  if (bData->bNormal) {
886  MEM_freeN(bData->bNormal);
887  }
888  if (bData->s_pos) {
889  MEM_freeN(bData->s_pos);
890  }
891  if (bData->s_num) {
892  MEM_freeN(bData->s_num);
893  }
894  if (bData->realCoord) {
895  MEM_freeN(bData->realCoord);
896  }
897  if (bData->bNeighs) {
898  MEM_freeN(bData->bNeighs);
899  }
900  if (bData->grid) {
901  freeGrid(data);
902  }
903  if (bData->prev_verts) {
904  MEM_freeN(bData->prev_verts);
905  }
906  if (bData->velocity) {
907  MEM_freeN(bData->velocity);
908  }
909  if (bData->prev_velocity) {
910  MEM_freeN(bData->prev_velocity);
911  }
912 
913  MEM_freeN(data->bData);
914  data->bData = NULL;
915  }
916 }
917 
918 /* free surface data if it's not used anymore */
920 {
921  if (!surface->data) {
922  return;
923  }
924 
925  /* free bakedata if not active or surface is baked */
926  if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
927  (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
928  free_bakeData(surface->data);
929  }
930 }
931 
933 {
934  PaintSurfaceData *data = surface->data;
935  if (!data) {
936  return;
937  }
938 
939  if (data->format_data) {
940  /* format specific free */
941  if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
942  ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
943  if (format_data->uv_p) {
944  MEM_freeN(format_data->uv_p);
945  }
946  if (format_data->barycentricWeights) {
947  MEM_freeN(format_data->barycentricWeights);
948  }
949  }
950  MEM_freeN(data->format_data);
951  }
952  /* type data */
953  if (data->type_data) {
954  MEM_freeN(data->type_data);
955  }
957  /* bake data */
959 
960  MEM_freeN(surface->data);
961  surface->data = NULL;
962 }
963 
965 {
966  /* point cache */
967  if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
968  BKE_ptcache_free_list(&(surface->ptcaches));
969  }
970  surface->pointcache = NULL;
971 
972  MEM_SAFE_FREE(surface->effector_weights);
973 
974  BLI_remlink(&(surface->canvas->surfaces), surface);
977 }
978 
980 {
981  if (pmd->canvas) {
982  /* Free surface data */
984  DynamicPaintSurface *next_surface = NULL;
985 
986  while (surface) {
987  next_surface = surface->next;
989  surface = next_surface;
990  }
991 
992  MEM_freeN(pmd->canvas);
993  pmd->canvas = NULL;
994  }
995 }
996 
998 {
999  if (pmd == NULL) {
1000  return;
1001  }
1005 }
1006 
1007 /***************************** Initialize and reset ******************************/
1008 
1010  Scene *scene)
1011 {
1012  DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
1013  if (!surface) {
1014  return NULL;
1015  }
1016 
1017  surface->canvas = canvas;
1020 
1021  /* cache */
1022  surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
1023  surface->pointcache->flag |= PTCACHE_DISK_CACHE;
1024  surface->pointcache->step = 1;
1025 
1026  /* Set initial values */
1030  surface->effect = 0;
1031  surface->effect_ui = 1;
1032 
1033  surface->diss_speed = 250;
1034  surface->dry_speed = 500;
1035  surface->color_dry_threshold = 1.0f;
1036  surface->depth_clamp = 0.0f;
1037  surface->disp_factor = 1.0f;
1038  surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
1039  surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
1040 
1041  surface->influence_scale = 1.0f;
1042  surface->radius_scale = 1.0f;
1043 
1044  surface->init_color[0] = 1.0f;
1045  surface->init_color[1] = 1.0f;
1046  surface->init_color[2] = 1.0f;
1047  surface->init_color[3] = 1.0f;
1048 
1049  surface->image_resolution = 256;
1050  surface->substeps = 0;
1051 
1052  if (scene) {
1053  surface->start_frame = scene->r.sfra;
1054  surface->end_frame = scene->r.efra;
1055  }
1056  else {
1057  surface->start_frame = 1;
1058  surface->end_frame = 250;
1059  }
1060 
1061  surface->spread_speed = 1.0f;
1062  surface->color_spread_speed = 1.0f;
1063  surface->shrink_speed = 1.0f;
1064 
1065  surface->wave_damping = 0.04f;
1066  surface->wave_speed = 1.0f;
1067  surface->wave_timescale = 1.0f;
1068  surface->wave_spring = 0.20f;
1069  surface->wave_smoothness = 1.0f;
1070 
1072  surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
1073 
1074  /* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
1076 
1077  surface->effector_weights = BKE_effector_add_weights(NULL);
1078 
1080 
1081  BLI_addtail(&canvas->surfaces, surface);
1082 
1083  return surface;
1084 }
1085 
1087 {
1088  if (pmd) {
1091  if (pmd->canvas) {
1093  }
1094 
1095  canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings),
1096  "DynamicPaint Canvas");
1097  if (!canvas) {
1098  return false;
1099  }
1100  canvas->pmd = pmd;
1101 
1102  /* Create one surface */
1103  if (!dynamicPaint_createNewSurface(canvas, scene)) {
1104  return false;
1105  }
1106  }
1107  else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
1109  if (pmd->brush) {
1111  }
1112 
1113  brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
1114  if (!brush) {
1115  return false;
1116  }
1117  brush->pmd = pmd;
1118 
1119  brush->psys = NULL;
1120 
1123 
1124  brush->r = 0.15f;
1125  brush->g = 0.4f;
1126  brush->b = 0.8f;
1127  brush->alpha = 1.0f;
1128  brush->wetness = 1.0f;
1129 
1130  brush->paint_distance = 1.0f;
1132 
1133  brush->particle_radius = 0.2f;
1134  brush->particle_smooth = 0.05f;
1135 
1137  brush->wave_factor = 1.0f;
1138  brush->wave_clamp = 0.0f;
1139  brush->smudge_strength = 0.3f;
1140  brush->max_velocity = 1.0f;
1141 
1142  /* Paint proximity falloff colorramp. */
1143  {
1144  CBData *ramp;
1145 
1146  brush->paint_ramp = BKE_colorband_add(false);
1147  if (!brush->paint_ramp) {
1148  return false;
1149  }
1150  ramp = brush->paint_ramp->data;
1151  /* Add default smooth-falloff ramp. */
1152  ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
1153  ramp[0].pos = 0.0f;
1154  ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
1155  ramp[1].a = 0.0f;
1156  pmd->brush->paint_ramp->tot = 2;
1157  }
1158 
1159  /* Brush velocity ramp. */
1160  {
1161  CBData *ramp;
1162 
1163  brush->vel_ramp = BKE_colorband_add(false);
1164  if (!brush->vel_ramp) {
1165  return false;
1166  }
1167  ramp = brush->vel_ramp->data;
1168  ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
1169  ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
1170  brush->paint_ramp->tot = 2;
1171  }
1172  }
1173  }
1174  else {
1175  return false;
1176  }
1177 
1178  return true;
1179 }
1180 
1182  struct DynamicPaintModifierData *tpmd,
1183  int flag)
1184 {
1185  /* Init modifier */
1186  tpmd->type = pmd->type;
1187  if (pmd->canvas) {
1189  }
1190  if (pmd->brush) {
1192  }
1193 
1194  /* Copy data */
1195  if (tpmd->canvas) {
1197  tpmd->canvas->pmd = tpmd;
1198  /* free default surface */
1199  if (tpmd->canvas->surfaces.first) {
1201  }
1202 
1203  tpmd->canvas->active_sur = pmd->canvas->active_sur;
1204 
1205  /* copy existing surfaces */
1206  for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
1208  if (flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) {
1209  /* TODO(sergey): Consider passing some tips to the surface
1210  * creation to avoid this allocate-and-free cache behavior. */
1211  BKE_ptcache_free_list(&t_surface->ptcaches);
1213  t_surface->ptcaches = surface->ptcaches;
1214  t_surface->pointcache = surface->pointcache;
1215  }
1216 
1217  /* surface settings */
1218  t_surface->brush_group = surface->brush_group;
1219  MEM_freeN(t_surface->effector_weights);
1220  t_surface->effector_weights = MEM_dupallocN(surface->effector_weights);
1221 
1222  BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name));
1223  t_surface->format = surface->format;
1224  t_surface->type = surface->type;
1225  t_surface->disp_type = surface->disp_type;
1226  t_surface->image_fileformat = surface->image_fileformat;
1227  t_surface->effect_ui = surface->effect_ui;
1228  t_surface->init_color_type = surface->init_color_type;
1229  t_surface->flags = surface->flags;
1230  t_surface->effect = surface->effect;
1231 
1232  t_surface->image_resolution = surface->image_resolution;
1233  t_surface->substeps = surface->substeps;
1234  t_surface->start_frame = surface->start_frame;
1235  t_surface->end_frame = surface->end_frame;
1236 
1237  copy_v4_v4(t_surface->init_color, surface->init_color);
1238  t_surface->init_texture = surface->init_texture;
1239  BLI_strncpy(
1240  t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername));
1241 
1242  t_surface->dry_speed = surface->dry_speed;
1243  t_surface->diss_speed = surface->diss_speed;
1244  t_surface->color_dry_threshold = surface->color_dry_threshold;
1245  t_surface->depth_clamp = surface->depth_clamp;
1246  t_surface->disp_factor = surface->disp_factor;
1247 
1248  t_surface->spread_speed = surface->spread_speed;
1249  t_surface->color_spread_speed = surface->color_spread_speed;
1250  t_surface->shrink_speed = surface->shrink_speed;
1251  t_surface->drip_vel = surface->drip_vel;
1252  t_surface->drip_acc = surface->drip_acc;
1253 
1254  t_surface->influence_scale = surface->influence_scale;
1255  t_surface->radius_scale = surface->radius_scale;
1256 
1257  t_surface->wave_damping = surface->wave_damping;
1258  t_surface->wave_speed = surface->wave_speed;
1259  t_surface->wave_timescale = surface->wave_timescale;
1260  t_surface->wave_spring = surface->wave_spring;
1261  t_surface->wave_smoothness = surface->wave_smoothness;
1262 
1263  BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name));
1264  BLI_strncpy(t_surface->image_output_path,
1265  surface->image_output_path,
1266  sizeof(t_surface->image_output_path));
1267  BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name));
1268  BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2));
1269  }
1270  }
1271  if (tpmd->brush) {
1272  DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
1273  t_brush->pmd = tpmd;
1274 
1275  t_brush->flags = brush->flags;
1276  t_brush->collision = brush->collision;
1277 
1278  t_brush->r = brush->r;
1279  t_brush->g = brush->g;
1280  t_brush->b = brush->b;
1281  t_brush->alpha = brush->alpha;
1282  t_brush->wetness = brush->wetness;
1283 
1284  t_brush->particle_radius = brush->particle_radius;
1285  t_brush->particle_smooth = brush->particle_smooth;
1286  t_brush->paint_distance = brush->paint_distance;
1287 
1288  /* NOTE: This is dangerous, as it will generate invalid data in case we are copying between
1289  * different objects. Extra external code has to be called then to ensure proper remapping of
1290  * that pointer. See e.g. `BKE_object_copy_particlesystems` or `BKE_object_copy_modifier`. */
1291  t_brush->psys = brush->psys;
1292 
1293  if (brush->paint_ramp) {
1294  memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
1295  }
1296  if (brush->vel_ramp) {
1297  memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
1298  }
1299 
1300  t_brush->proximity_falloff = brush->proximity_falloff;
1301  t_brush->wave_type = brush->wave_type;
1302  t_brush->ray_dir = brush->ray_dir;
1303 
1304  t_brush->wave_factor = brush->wave_factor;
1305  t_brush->wave_clamp = brush->wave_clamp;
1306  t_brush->max_velocity = brush->max_velocity;
1307  t_brush->smudge_strength = brush->smudge_strength;
1308  }
1309 }
1310 
1311 /* allocates surface data depending on surface type */
1313 {
1314  PaintSurfaceData *sData = surface->data;
1315 
1316  switch (surface->type) {
1318  sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points,
1319  "DynamicPaintSurface Data");
1320  break;
1322  sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
1323  "DynamicPaintSurface DepthData");
1324  break;
1326  sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
1327  "DynamicPaintSurface WeightData");
1328  break;
1330  sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points,
1331  "DynamicPaintSurface WaveData");
1332  break;
1333  }
1334 
1335  if (sData->type_data == NULL) {
1336  setError(surface->canvas, N_("Not enough free memory"));
1337  }
1338 }
1339 
1341 {
1342  return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
1343  (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
1344 }
1345 
1347 {
1349  surface->flags & MOD_DPAINT_ANTIALIAS));
1350 }
1351 
1352 /* initialize surface adjacency data */
1353 static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
1354 {
1355  PaintSurfaceData *sData = surface->data;
1357  PaintAdjData *ad;
1358  int *temp_data;
1359  int neigh_points = 0;
1360 
1361  if (!force_init && !surface_usesAdjData(surface)) {
1362  return;
1363  }
1364 
1365  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1366  /* For vertex format, neighbors are connected by edges */
1367  neigh_points = 2 * mesh->totedge;
1368  }
1369  else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1370  neigh_points = sData->total_points * 8;
1371  }
1372 
1373  if (!neigh_points) {
1374  return;
1375  }
1376 
1377  /* allocate memory */
1378  ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
1379  if (!ad) {
1380  return;
1381  }
1382  ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
1383  ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
1384  temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
1385  ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
1386  ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
1387  ad->total_targets = neigh_points;
1388  ad->border = NULL;
1389  ad->total_border = 0;
1390 
1391  /* in case of allocation error, free memory */
1392  if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
1393  dynamicPaint_freeAdjData(sData);
1394  if (temp_data) {
1395  MEM_freeN(temp_data);
1396  }
1397  setError(surface->canvas, N_("Not enough free memory"));
1398  return;
1399  }
1400 
1401  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1402  /* For vertex format, count every vertex that is connected by an edge */
1403  int numOfEdges = mesh->totedge;
1404  int numOfPolys = mesh->totpoly;
1405  struct MEdge *edge = mesh->medge;
1406  struct MPoly *mpoly = mesh->mpoly;
1407  struct MLoop *mloop = mesh->mloop;
1408 
1409  /* count number of edges per vertex */
1410  for (int i = 0; i < numOfEdges; i++) {
1411  ad->n_num[edge[i].v1]++;
1412  ad->n_num[edge[i].v2]++;
1413 
1414  temp_data[edge[i].v1]++;
1415  temp_data[edge[i].v2]++;
1416  }
1417 
1418  /* also add number of vertices to temp_data
1419  * to locate points on "mesh edge" */
1420  for (int i = 0; i < numOfPolys; i++) {
1421  for (int j = 0; j < mpoly[i].totloop; j++) {
1422  temp_data[mloop[mpoly[i].loopstart + j].v]++;
1423  }
1424  }
1425 
1426  /* now check if total number of edges+faces for
1427  * each vertex is even, if not -> vertex is on mesh edge */
1428  for (int i = 0; i < sData->total_points; i++) {
1429  if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
1430  ad->flags[i] |= ADJ_ON_MESH_EDGE;
1431  }
1432 
1433  /* reset temp data */
1434  temp_data[i] = 0;
1435  }
1436 
1437  /* order n_index array */
1438  int n_pos = 0;
1439  for (int i = 0; i < sData->total_points; i++) {
1440  ad->n_index[i] = n_pos;
1441  n_pos += ad->n_num[i];
1442  }
1443 
1444  /* and now add neighbor data using that info */
1445  for (int i = 0; i < numOfEdges; i++) {
1446  /* first vertex */
1447  int index = edge[i].v1;
1448  n_pos = ad->n_index[index] + temp_data[index];
1449  ad->n_target[n_pos] = edge[i].v2;
1450  temp_data[index]++;
1451 
1452  /* second vertex */
1453  index = edge[i].v2;
1454  n_pos = ad->n_index[index] + temp_data[index];
1455  ad->n_target[n_pos] = edge[i].v1;
1456  temp_data[index]++;
1457  }
1458  }
1459  else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1460  /* for image sequences, only allocate memory.
1461  * bake initialization takes care of rest */
1462  }
1463 
1464  MEM_freeN(temp_data);
1465 }
1466 
1469 
1470  const MLoop *mloop;
1474  struct ImagePool *pool;
1475 
1478 
1480  void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
1481 {
1482  const DynamicPaintSetInitColorData *data = userdata;
1483 
1484  const PaintSurfaceData *sData = data->surface->data;
1485  PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1486 
1487  const MLoop *mloop = data->mloop;
1488  const MLoopTri *mlooptri = data->mlooptri;
1489  const MLoopUV *mloopuv = data->mloopuv;
1490  struct ImagePool *pool = data->pool;
1491  Tex *tex = data->surface->init_texture;
1492 
1493  const bool scene_color_manage = data->scene_color_manage;
1494 
1495  float uv[3] = {0.0f};
1496 
1497  for (int j = 3; j--;) {
1498  TexResult texres = {0};
1499  const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
1500 
1501  /* remap to [-1.0, 1.0] */
1502  uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
1503  uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
1504 
1505  multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
1506 
1507  if (texres.tin > pPoint[vert].color[3]) {
1508  copy_v3_v3(pPoint[vert].color, texres.trgba);
1509  pPoint[vert].color[3] = texres.tin;
1510  }
1511  }
1512 }
1513 
1515  void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
1516 {
1517  const DynamicPaintSetInitColorData *data = userdata;
1518 
1519  const PaintSurfaceData *sData = data->surface->data;
1520  PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1521 
1522  const MLoopTri *mlooptri = data->mlooptri;
1523  const MLoopUV *mloopuv = data->mloopuv;
1524  Tex *tex = data->surface->init_texture;
1525  ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
1526  const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
1527 
1528  const bool scene_color_manage = data->scene_color_manage;
1529 
1530  float uv[9] = {0.0f};
1531  float uv_final[3] = {0.0f};
1532 
1533  TexResult texres = {0};
1534 
1535  /* collect all uvs */
1536  for (int j = 3; j--;) {
1537  copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
1538  }
1539 
1540  /* interpolate final uv pos */
1541  interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
1542  /* remap to [-1.0, 1.0] */
1543  uv_final[0] = uv_final[0] * 2.0f - 1.0f;
1544  uv_final[1] = uv_final[1] * 2.0f - 1.0f;
1545 
1546  multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
1547 
1548  /* apply color */
1549  copy_v3_v3(pPoint[i].color, texres.trgba);
1550  pPoint[i].color[3] = texres.tin;
1551 }
1552 
1554  void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
1555 {
1556  const DynamicPaintSetInitColorData *data = userdata;
1557 
1558  const PaintSurfaceData *sData = data->surface->data;
1559  PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1560 
1561  const MLoopTri *mlooptri = data->mlooptri;
1562  const MLoopCol *mloopcol = data->mloopcol;
1563  ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
1564  const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
1565 
1566  const int tri_idx = f_data->uv_p[i].tri_index;
1567  float colors[3][4];
1568  float final_color[4];
1569 
1570  /* collect color values */
1571  for (int j = 3; j--;) {
1572  rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
1573  }
1574 
1575  /* interpolate final color */
1576  interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
1577 
1578  copy_v4_v4(pPoint[i].color, final_color);
1579 }
1580 
1582 {
1583  PaintSurfaceData *sData = surface->data;
1584  PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1586  const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
1587 
1588  if (surface->type != MOD_DPAINT_SURFACE_T_PAINT) {
1589  return;
1590  }
1591 
1592  if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE) {
1593  return;
1594  }
1595 
1596  /* Single color */
1597  if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
1598  /* apply color to every surface point */
1599  for (int i = 0; i < sData->total_points; i++) {
1600  copy_v4_v4(pPoint[i].color, surface->init_color);
1601  }
1602  }
1603  /* UV mapped texture */
1604  else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
1605  Tex *tex = surface->init_texture;
1606 
1607  const MLoop *mloop = mesh->mloop;
1608  const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
1609  const int tottri = BKE_mesh_runtime_looptri_len(mesh);
1610 
1611  char uvname[MAX_CUSTOMDATA_LAYER_NAME];
1612 
1613  if (!tex) {
1614  return;
1615  }
1616 
1617  /* get uv map */
1618  CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
1619  const MLoopUV *mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
1620  if (!mloopuv) {
1621  return;
1622  }
1623 
1624  /* for vertex surface loop through tfaces and find uv color
1625  * that provides highest alpha */
1626  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1627  struct ImagePool *pool = BKE_image_pool_new();
1628 
1630  .surface = surface,
1631  .mloop = mloop,
1632  .mlooptri = mlooptri,
1633  .mloopuv = mloopuv,
1634  .pool = pool,
1635  .scene_color_manage = scene_color_manage,
1636  };
1637  TaskParallelSettings settings;
1639  settings.use_threading = (tottri > 1000);
1641  0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
1643  }
1644  else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1646  .surface = surface,
1647  .mlooptri = mlooptri,
1648  .mloopuv = mloopuv,
1649  .scene_color_manage = scene_color_manage,
1650  };
1651  TaskParallelSettings settings;
1653  settings.use_threading = (sData->total_points > 1000);
1656  }
1657  }
1658  /* vertex color layer */
1659  else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
1660 
1661  /* for vertex surface, just copy colors from mcol */
1662  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1663  const MLoop *mloop = mesh->mloop;
1664  const int totloop = mesh->totloop;
1666  &mesh->ldata, CD_PROP_BYTE_COLOR, surface->init_layername);
1667  if (!col) {
1668  return;
1669  }
1670 
1671  for (int i = 0; i < totloop; i++) {
1672  rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[i].r);
1673  }
1674  }
1675  else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1676  const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
1678  &mesh->ldata, CD_PROP_BYTE_COLOR, surface->init_layername);
1679  if (!col) {
1680  return;
1681  }
1682 
1684  .surface = surface,
1685  .mlooptri = mlooptri,
1686  .mloopcol = col,
1687  };
1688  TaskParallelSettings settings;
1690  settings.use_threading = (sData->total_points > 1000);
1693  }
1694  }
1695 }
1696 
1698 {
1699  PaintSurfaceData *sData = surface->data;
1700  if (sData && sData->type_data) {
1701  unsigned int data_size;
1702 
1703  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1704  data_size = sizeof(PaintPoint);
1705  }
1706  else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
1707  data_size = sizeof(PaintWavePoint);
1708  }
1709  else {
1710  data_size = sizeof(float);
1711  }
1712 
1713  memset(sData->type_data, 0, data_size * sData->total_points);
1714 
1715  /* set initial color */
1716  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1718  }
1719 
1720  if (sData->bData) {
1721  sData->bData->clear = 1;
1722  }
1723  }
1724 }
1725 
1727 {
1728  int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
1729  /* free existing data */
1730  if (surface->data) {
1732  }
1733 
1734  /* don't reallocate for image sequence types. they get handled only on bake */
1735  if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1736  return true;
1737  }
1738  if (numOfPoints < 1) {
1739  return false;
1740  }
1741 
1742  /* allocate memory */
1743  surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
1744  if (!surface->data) {
1745  return false;
1746  }
1747 
1748  /* allocate data depending on surface type and format */
1749  surface->data->total_points = numOfPoints;
1752 
1753  /* set initial color */
1754  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1756  }
1757 
1758  return true;
1759 }
1760 
1761 /* make sure allocated surface size matches current requirements */
1763 {
1764  if (!surface->data ||
1765  ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
1767  }
1768  return true;
1769 }
1770 
1771 /***************************** Modifier processing ******************************/
1772 
1776 
1778  const float (*vert_normals)[3];
1779  const MLoop *mloop;
1780  const MPoly *mpoly;
1781 
1782  float (*fcolor)[4];
1786 
1787 static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
1788  const int i,
1789  const TaskParallelTLS *__restrict UNUSED(tls))
1790 {
1791  const DynamicPaintModifierApplyData *data = userdata;
1792 
1793  const DynamicPaintSurface *surface = data->surface;
1794  MVert *mvert = data->mvert;
1795 
1796  const float *value = (float *)surface->data->type_data;
1797  const float val = value[i] * surface->disp_factor;
1798 
1799  /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
1800  madd_v3_v3fl(mvert[i].co, data->vert_normals[i], -val);
1801 }
1802 
1803 /* apply displacing vertex surface to the derived mesh */
1805 {
1806  PaintSurfaceData *sData = surface->data;
1807 
1808  if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) {
1809  return;
1810  }
1811 
1812  /* displace paint */
1813  if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
1814  MVert *mvert = result->mvert;
1815 
1817  .surface = surface,
1818  .mvert = mvert,
1819  .vert_normals = BKE_mesh_vertex_normals_ensure(result),
1820  };
1821  TaskParallelSettings settings;
1823  settings.use_threading = (sData->total_points > 10000);
1826  }
1827 }
1828 
1830  void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
1831 {
1832  const DynamicPaintModifierApplyData *data = userdata;
1833 
1834  PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
1835  float(*fcolor)[4] = data->fcolor;
1836 
1837  /* blend dry and wet layer */
1838  blendColors(
1839  pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
1840 }
1841 
1842 static void dynamic_paint_apply_surface_vpaint_cb(void *__restrict userdata,
1843  const int p_index,
1844  const TaskParallelTLS *__restrict UNUSED(tls))
1845 {
1846  const DynamicPaintModifierApplyData *data = userdata;
1847 
1848  const MLoop *mloop = data->mloop;
1849  const MPoly *mpoly = data->mpoly;
1850 
1851  const DynamicPaintSurface *surface = data->surface;
1852  PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
1853  float(*fcolor)[4] = data->fcolor;
1854 
1855  MLoopCol *mloopcol = data->mloopcol;
1856  MLoopCol *mloopcol_wet = data->mloopcol_wet;
1857 
1858  for (int j = 0; j < mpoly[p_index].totloop; j++) {
1859  const int l_index = mpoly[p_index].loopstart + j;
1860  const int v_index = mloop[l_index].v;
1861 
1862  /* save layer data to output layer */
1863  /* apply color */
1864  if (mloopcol) {
1865  rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
1866  }
1867  /* apply wetness */
1868  if (mloopcol_wet) {
1869  const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
1870  mloopcol_wet[l_index].r = c;
1871  mloopcol_wet[l_index].g = c;
1872  mloopcol_wet[l_index].b = c;
1873  mloopcol_wet[l_index].a = 255;
1874  }
1875  }
1876 }
1877 
1878 static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
1879  const int i,
1880  const TaskParallelTLS *__restrict UNUSED(tls))
1881 {
1882  const DynamicPaintModifierApplyData *data = userdata;
1883 
1884  PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
1885  MVert *mvert = data->mvert;
1886 
1887  madd_v3_v3fl(mvert[i].co, data->vert_normals[i], wPoint[i].height);
1888 }
1889 
1890 /*
1891  * Apply canvas data to the object derived mesh
1892  */
1894 {
1896 
1897  if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING) &&
1899 
1901 
1902  /* loop through surfaces */
1903  for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
1904  PaintSurfaceData *sData = surface->data;
1905 
1906  if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
1907  if (!(surface->flags & MOD_DPAINT_ACTIVE)) {
1908  continue;
1909  }
1910 
1911  /* process vertex surface previews */
1912  if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1913 
1914  /* vertex color paint */
1915  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1916  MLoop *mloop = result->mloop;
1917  const int totloop = result->totloop;
1918  MPoly *mpoly = result->mpoly;
1919  const int totpoly = result->totpoly;
1920 
1921  /* paint is stored on dry and wet layers, so mix final color first */
1922  float(*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points,
1923  "Temp paint color");
1924 
1926  .surface = surface,
1927  .fcolor = fcolor,
1928  };
1929  {
1930  TaskParallelSettings settings;
1932  settings.use_threading = (sData->total_points > 1000);
1934  sData->total_points,
1935  &data,
1937  &settings);
1938  }
1939 
1940  /* paint layer */
1942  &result->ldata, CD_PROP_BYTE_COLOR, surface->output_name);
1943  /* if output layer is lost from a constructive modifier, re-add it */
1944  if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
1945  mloopcol = CustomData_add_layer_named(&result->ldata,
1947  CD_CALLOC,
1948  NULL,
1949  totloop,
1950  surface->output_name);
1951  }
1952 
1953  /* wet layer */
1954  MLoopCol *mloopcol_wet = CustomData_get_layer_named(
1955  &result->ldata, CD_PROP_BYTE_COLOR, surface->output_name2);
1956  /* if output layer is lost from a constructive modifier, re-add it */
1957  if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
1958  mloopcol_wet = CustomData_add_layer_named(&result->ldata,
1960  CD_CALLOC,
1961  NULL,
1962  totloop,
1963  surface->output_name2);
1964  }
1965 
1966  data.ob = ob;
1967  data.mloop = mloop;
1968  data.mpoly = mpoly;
1969  data.mloopcol = mloopcol;
1970  data.mloopcol_wet = mloopcol_wet;
1971 
1972  {
1973  TaskParallelSettings settings;
1975  settings.use_threading = (totpoly > 1000);
1977  0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb, &settings);
1978  }
1979 
1980  MEM_freeN(fcolor);
1981  }
1982  /* vertex group paint */
1983  else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
1984  int defgrp_index = BKE_object_defgroup_name_index(ob, surface->output_name);
1986  float *weight = (float *)sData->type_data;
1987 
1988  /* apply weights into a vertex group, if doesn't exists add a new layer */
1989  if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
1990  dvert = CustomData_add_layer(
1991  &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points);
1992  /* Make the dvert layer easily accessible from the mesh data. */
1993  result->dvert = dvert;
1994  }
1995  if (defgrp_index != -1 && dvert) {
1996  for (int i = 0; i < sData->total_points; i++) {
1997  MDeformVert *dv = &dvert[i];
1998  MDeformWeight *def_weight = BKE_defvert_find_index(dv, defgrp_index);
1999 
2000  /* skip if weight value is 0 and no existing weight is found */
2001  if ((def_weight != NULL) || (weight[i] != 0.0f)) {
2002  /* if not found, add a weight for it */
2003  if (def_weight == NULL) {
2004  def_weight = BKE_defvert_ensure_index(dv, defgrp_index);
2005  }
2006 
2007  /* set weight value */
2008  def_weight->weight = weight[i];
2009  }
2010  }
2011  }
2012  }
2013  /* wave simulation */
2014  else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
2015  MVert *mvert = result->mvert;
2016 
2018  .surface = surface,
2019  .mvert = mvert,
2020  .vert_normals = BKE_mesh_vertex_normals_ensure(result),
2021  };
2022  TaskParallelSettings settings;
2024  settings.use_threading = (sData->total_points > 1000);
2026  0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
2028  }
2029 
2030  /* displace */
2031  if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
2034  }
2035  }
2036  }
2037  }
2038  }
2039  /* make a copy of mesh to use as brush data */
2040  else if (pmd->brush && pmd->type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
2042  if (runtime_data->brush_mesh != NULL) {
2043  BKE_id_free(NULL, runtime_data->brush_mesh);
2044  }
2045  runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false);
2046  }
2047 
2048  return result;
2049 }
2050 
2052 {
2053  if (surface->pointcache) {
2054  surface->pointcache->startframe = surface->start_frame;
2055  surface->pointcache->endframe = surface->end_frame;
2056  }
2057 }
2058 
2060 {
2062  if (runtime->canvas_mesh != NULL) {
2063  BKE_id_free(NULL, runtime->canvas_mesh);
2064  }
2065 
2066  runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false);
2067 }
2068 
2069 /*
2070  * Updates derived mesh copy and processes dynamic paint step / caches.
2071  */
2073  struct Depsgraph *depsgraph,
2074  Scene *scene,
2075  Object *ob,
2076  Mesh *mesh)
2077 {
2078  if (pmd->canvas) {
2079  DynamicPaintCanvasSettings *canvas = pmd->canvas;
2081 
2082  /* update derived mesh copy */
2083  canvas_copyMesh(canvas, mesh);
2084 
2085  /* in case image sequence baking, stop here */
2086  if (canvas->flags & MOD_DPAINT_BAKING) {
2087  return;
2088  }
2089 
2090  /* loop through surfaces */
2091  for (; surface; surface = surface->next) {
2092  int current_frame = (int)scene->r.cfra;
2093  bool no_surface_data;
2094 
2095  /* free bake data if not required anymore */
2097 
2098  /* image sequences are handled by bake operator */
2099  if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) ||
2100  !(surface->flags & MOD_DPAINT_ACTIVE)) {
2101  continue;
2102  }
2103 
2104  /* make sure surface is valid */
2105  no_surface_data = surface->data == NULL;
2107  continue;
2108  }
2109 
2110  /* limit frame range */
2111  CLAMP(current_frame, surface->start_frame, surface->end_frame);
2112 
2113  if (no_surface_data || current_frame != surface->current_frame ||
2114  (int)scene->r.cfra == surface->start_frame) {
2115  PointCache *cache = surface->pointcache;
2116  PTCacheID pid;
2117  surface->current_frame = current_frame;
2118 
2119  /* read point cache */
2121  pid.cache->startframe = surface->start_frame;
2122  pid.cache->endframe = surface->end_frame;
2123  BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
2124 
2125  /* reset non-baked cache at first frame */
2126  if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
2127  cache->flag |= PTCACHE_REDO_NEEDED;
2129  cache->flag &= ~PTCACHE_REDO_NEEDED;
2130  }
2131 
2132  /* try to read from cache */
2133  bool can_simulate = ((int)scene->r.cfra == current_frame) &&
2134  !(cache->flag & PTCACHE_BAKED);
2135 
2136  if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
2137  BKE_ptcache_validate(cache, (int)scene->r.cfra);
2138  }
2139  /* if read failed and we're on surface range do recalculate */
2140  else if (can_simulate) {
2141  /* calculate surface frame */
2142  canvas->flags |= MOD_DPAINT_BAKING;
2143  dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
2144  canvas->flags &= ~MOD_DPAINT_BAKING;
2145 
2146  /* restore canvas mesh if required */
2147  if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
2148  surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next) {
2149  canvas_copyMesh(canvas, mesh);
2150  }
2151 
2152  BKE_ptcache_validate(cache, surface->current_frame);
2153  BKE_ptcache_write(&pid, surface->current_frame);
2154  }
2155  }
2156  }
2157  }
2158 }
2159 
2161  struct Depsgraph *depsgraph,
2162  Scene *scene,
2163  Object *ob,
2164  Mesh *mesh)
2165 {
2166  /* Update canvas data for a new frame */
2168 
2169  /* Return output mesh */
2170  return dynamicPaint_Modifier_apply(pmd, ob, mesh);
2171 }
2172 
2173 /* -------------------------------------------------------------------- */
2177 /* Create a surface for uv image sequence format. */
2178 #define JITTER_SAMPLES \
2179  { \
2180  0.0f, 0.0f, -0.2f, -0.4f, 0.2f, 0.4f, 0.4f, -0.2f, -0.4f, 0.3f, \
2181  }
2182 
2185 
2188 
2191  const MLoop *mloop;
2192  const int tottri;
2193 
2197 
2199  void *__restrict userdata, const int ty, const TaskParallelTLS *__restrict UNUSED(tls))
2200 {
2201  const DynamicPaintCreateUVSurfaceData *data = userdata;
2202 
2203  const DynamicPaintSurface *surface = data->surface;
2204  PaintUVPoint *tempPoints = data->tempPoints;
2205  Vec3f *tempWeights = data->tempWeights;
2206 
2207  const MLoopTri *mlooptri = data->mlooptri;
2208  const MLoopUV *mloopuv = data->mloopuv;
2209  const MLoop *mloop = data->mloop;
2210  const int tottri = data->tottri;
2211 
2212  const Bounds2D *faceBB = data->faceBB;
2213 
2214  const float jitter5sample[10] = JITTER_SAMPLES;
2215  const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2216  const int w = surface->image_resolution;
2217  const int h = w;
2218 
2219  for (int tx = 0; tx < w; tx++) {
2220  const int index = tx + w * ty;
2221  PaintUVPoint *tPoint = &tempPoints[index];
2222  float point[5][2];
2223 
2224  /* Init per pixel settings */
2225  tPoint->tri_index = -1;
2226  tPoint->neighbor_pixel = -1;
2227  tPoint->pixel_index = index;
2228 
2229  /* Actual pixel center, used when collision is found */
2230  point[0][0] = ((float)tx + 0.5f) / w;
2231  point[0][1] = ((float)ty + 0.5f) / h;
2232 
2233  /*
2234  * A pixel middle sample isn't enough to find very narrow polygons
2235  * So using 4 samples of each corner too
2236  */
2237  point[1][0] = ((float)tx) / w;
2238  point[1][1] = ((float)ty) / h;
2239 
2240  point[2][0] = ((float)tx + 1) / w;
2241  point[2][1] = ((float)ty) / h;
2242 
2243  point[3][0] = ((float)tx) / w;
2244  point[3][1] = ((float)ty + 1) / h;
2245 
2246  point[4][0] = ((float)tx + 1) / w;
2247  point[4][1] = ((float)ty + 1) / h;
2248 
2249  /* Loop through samples, starting from middle point */
2250  for (int sample = 0; sample < 5; sample++) {
2251  /* Loop through every face in the mesh */
2252  /* XXX TODO: This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here!
2253  */
2254  for (int i = 0; i < tottri; i++) {
2255  /* Check uv bb */
2256  if ((faceBB[i].min[0] > point[sample][0]) || (faceBB[i].min[1] > point[sample][1]) ||
2257  (faceBB[i].max[0] < point[sample][0]) || (faceBB[i].max[1] < point[sample][1])) {
2258  continue;
2259  }
2260 
2261  const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
2262  const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
2263  const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
2264 
2265  /* If point is inside the face */
2266  if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
2267  float uv[2];
2268 
2269  /* Add b-weights per anti-aliasing sample */
2270  for (int j = 0; j < aa_samples; j++) {
2271  uv[0] = point[0][0] + jitter5sample[j * 2] / w;
2272  uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
2273 
2274  barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
2275  }
2276 
2277  /* Set surface point face values */
2278  tPoint->tri_index = i;
2279 
2280  /* save vertex indexes */
2281  tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
2282  tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
2283  tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
2284 
2285  sample = 5; /* make sure we exit sample loop as well */
2286  break;
2287  }
2288  }
2289  }
2290  }
2291 }
2292 
2294  void *__restrict userdata, const int ty, const TaskParallelTLS *__restrict UNUSED(tls))
2295 {
2296  const DynamicPaintCreateUVSurfaceData *data = userdata;
2297 
2298  const DynamicPaintSurface *surface = data->surface;
2299  PaintUVPoint *tempPoints = data->tempPoints;
2300  Vec3f *tempWeights = data->tempWeights;
2301 
2302  const MLoopTri *mlooptri = data->mlooptri;
2303  const MLoopUV *mloopuv = data->mloopuv;
2304  const MLoop *mloop = data->mloop;
2305 
2306  uint32_t *active_points = data->active_points;
2307 
2308  const float jitter5sample[10] = JITTER_SAMPLES;
2309  const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2310  const int w = surface->image_resolution;
2311  const int h = w;
2312 
2313  for (int tx = 0; tx < w; tx++) {
2314  const int index = tx + w * ty;
2315  PaintUVPoint *tPoint = &tempPoints[index];
2316 
2317  /* If point isn't on canvas mesh */
2318  if (tPoint->tri_index == -1) {
2319  float point[2];
2320 
2321  /* get loop area */
2322  const int u_min = (tx > 0) ? -1 : 0;
2323  const int u_max = (tx < (w - 1)) ? 1 : 0;
2324  const int v_min = (ty > 0) ? -1 : 0;
2325  const int v_max = (ty < (h - 1)) ? 1 : 0;
2326 
2327  point[0] = ((float)tx + 0.5f) / w;
2328  point[1] = ((float)ty + 0.5f) / h;
2329 
2330  /* search through defined area for neighbor, checking grid directions first */
2331  for (int ni = 0; ni < 8; ni++) {
2332  int u = neighStraightX[ni];
2333  int v = neighStraightY[ni];
2334 
2335  if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
2336  /* if not this pixel itself */
2337  if (u != 0 || v != 0) {
2338  const int ind = (tx + u) + w * (ty + v);
2339 
2340  /* if neighbor has index */
2341  if (tempPoints[ind].neighbor_pixel == -1 && tempPoints[ind].tri_index != -1) {
2342  float uv[2];
2343  const int i = tempPoints[ind].tri_index;
2344  const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
2345  const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
2346  const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
2347 
2348  /* tri index */
2349  /* There is a low possibility of actually having a neighbor point which tri is
2350  * already set from another neighbor in a separate thread here.
2351  * Checking for both tri_index and neighbor_pixel above reduces that probability
2352  * but it remains possible.
2353  * That atomic op (and its memory fence) ensures tPoint->neighbor_pixel is set
2354  * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbor).
2355  */
2356  tPoint->neighbor_pixel = ind - 1;
2358  tPoint->tri_index = i;
2359 
2360  /* Now calculate pixel data for this pixel as it was on polygon surface */
2361  /* Add b-weights per anti-aliasing sample */
2362  for (int j = 0; j < aa_samples; j++) {
2363  uv[0] = point[0] + jitter5sample[j * 2] / w;
2364  uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
2365  barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
2366  }
2367 
2368  /* save vertex indexes */
2369  tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
2370  tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
2371  tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
2372 
2373  break;
2374  }
2375  }
2376  }
2377  }
2378  }
2379 
2380  /* Increase the final number of active surface points if relevant. */
2381  if (tPoint->tri_index != -1) {
2382  atomic_add_and_fetch_uint32(active_points, 1);
2383  }
2384  }
2385 }
2386 
2387 #undef JITTER_SAMPLES
2388 
2389 static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
2390  const MLoopUV *mloopuv,
2391  int tri_index,
2392  const float point[2])
2393 {
2394  BLI_assert(tri_index >= 0);
2395 
2396  float min_distance = FLT_MAX;
2397 
2398  for (int i = 0; i < 3; i++) {
2399  const float dist_squared = dist_squared_to_line_segment_v2(
2400  point,
2401  mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
2402  mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv);
2403 
2404  if (dist_squared < min_distance) {
2405  min_distance = dist_squared;
2406  }
2407  }
2408 
2409  return min_distance;
2410 }
2411 
2414  int w, h, px, py;
2415 
2419 
2422  int tri_index,
2423  const float pixel[2],
2424  int in_edge,
2425  int depth);
2426 
2427 /* Tries to find the neighboring pixel in given (uv space) direction.
2428  * Result is used by effect system to move paint on the surface.
2429  *
2430  * px, py : origin pixel x and y
2431  * n_index : lookup direction index (use neighX, neighY to get final index)
2432  */
2434  const MeshElemMap *vert_to_looptri_map,
2435  const int w,
2436  const int h,
2437  const int px,
2438  const int py,
2439  const int n_index)
2440 {
2441  /* NOTE: Current method only uses polygon edges to detect neighboring pixels.
2442  * -> It doesn't always lead to the optimum pixel but is accurate enough
2443  * and faster/simpler than including possible face tip point links)
2444  */
2445 
2446  /* shift position by given n_index */
2447  const int x = px + neighX[n_index];
2448  const int y = py + neighY[n_index];
2449 
2450  if (x < 0 || x >= w || y < 0 || y >= h) {
2451  return OUT_OF_TEXTURE;
2452  }
2453 
2454  const PaintUVPoint *tempPoints = data->tempPoints;
2455  const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
2456  const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
2457 
2458  /* Check if shifted point is on same face -> it's a correct neighbor
2459  * (and if it isn't marked as an "edge pixel") */
2460  if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbor_pixel == -1)) {
2461  return (x + w * y);
2462  }
2463 
2464  /* Even if shifted point is on another face
2465  * -> use this point.
2466  *
2467  * !! Replace with "is uv faces linked" check !!
2468  * This should work fine as long as uv island margin is > 1 pixel.
2469  */
2470  if ((tPoint->tri_index != -1) && (tPoint->neighbor_pixel == -1)) {
2471  return (x + w * y);
2472  }
2473 
2474  /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
2475  * and we have to find its "real" position.
2476  *
2477  * Simple neighboring face finding algorithm:
2478  * - find closest uv edge to shifted pixel and get the another face that shares that edge
2479  * - find corresponding position of that new face edge in uv space
2480  *
2481  * TODO: Implement something more accurate / optimized?
2482  */
2483  {
2485  .vert_to_looptri_map = vert_to_looptri_map,
2486  .w = w,
2487  .h = h,
2488  .px = px,
2489  .py = py,
2490  .best_index = NOT_FOUND,
2491  .best_weight = 1.0f,
2492  };
2493 
2494  float pixel[2];
2495 
2496  pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
2497  pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
2498 
2499  /* Do a small recursive search for the best island edge. */
2500  dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
2501 
2502  return bdata.best_index;
2503  }
2504 }
2505 
2508  int tri_index,
2509  const float pixel[2],
2510  int in_edge,
2511  int depth)
2512 {
2513  const MLoop *mloop = data->mloop;
2514  const MLoopTri *mlooptri = data->mlooptri;
2515  const MLoopUV *mloopuv = data->mloopuv;
2516 
2517  const unsigned int *loop_idx = mlooptri[tri_index].tri;
2518 
2519  /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
2520  for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
2521  /* but not the edge we have just recursed through */
2522  if (edge_idx == in_edge) {
2523  continue;
2524  }
2525 
2526  float uv0[2], uv1[2], uv2[2];
2527 
2528  copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
2529  copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
2530  copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
2531 
2532  /* Verify the target point is on the opposite side of the edge from the third triangle
2533  * vertex, to ensure that we always move closer to the goal point. */
2534  const float sidep = line_point_side_v2(uv0, uv1, pixel);
2535  const float side2 = line_point_side_v2(uv0, uv1, uv2);
2536 
2537  if (side2 == 0.0f) {
2538  continue;
2539  }
2540 
2541  /* Hack: allow all edges of the original triangle */
2542  const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) ||
2543  (sidep > 0 && side2 < 0);
2544 
2545  /* Allow exactly on edge for the non-recursive case */
2546  if (!correct_side && sidep != 0.0f) {
2547  continue;
2548  }
2549 
2550  /* Now find another face that is linked to that edge. */
2551  const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
2552  const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
2553 
2554  /* Use a pre-computed vert-to-looptri mapping,
2555  * speeds up things a lot compared to looping over all looptri. */
2556  const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
2557 
2558  bool found_other = false;
2559  int target_tri = -1;
2560  int target_edge = -1;
2561 
2562  float ouv0[2], ouv1[2];
2563 
2564  for (int i = 0; i < map->count && !found_other; i++) {
2565  const int lt_index = map->indices[i];
2566 
2567  if (lt_index == tri_index) {
2568  continue;
2569  }
2570 
2571  const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
2572 
2573  /* Check edges for match, looping in the same order as the outer loop. */
2574  for (int j = 0; j < 3; j++) {
2575  const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
2576  const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
2577 
2578  /* Allow for swapped vertex order */
2579  if (overt0 == vert0 && overt1 == vert1) {
2580  found_other = true;
2581  copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
2582  copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
2583  }
2584  else if (overt0 == vert1 && overt1 == vert0) {
2585  found_other = true;
2586  copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
2587  copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
2588  }
2589 
2590  if (found_other) {
2591  target_tri = lt_index;
2592  target_edge = j;
2593  break;
2594  }
2595  }
2596  }
2597 
2598  if (!found_other) {
2599  if (bdata->best_index < 0) {
2600  bdata->best_index = ON_MESH_EDGE;
2601  }
2602 
2603  continue;
2604  }
2605 
2606  /* If this edge is connected in UV space too, recurse */
2607  if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
2608  if (depth > 0 && correct_side) {
2609  dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
2610  }
2611 
2612  continue;
2613  }
2614 
2615  /* Otherwise try to map to the other side of the edge.
2616  * First check if there already is a better solution. */
2617  const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
2618 
2619  if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight) {
2620  continue;
2621  }
2622 
2623  /*
2624  * Find a point that is relatively at same edge position
2625  * on this other face UV
2626  */
2627  float closest_point[2], dir_vec[2], tgt_pixel[2];
2628 
2629  float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
2630  CLAMP(lambda, 0.0f, 1.0f);
2631 
2632  sub_v2_v2v2(dir_vec, ouv1, ouv0);
2633  madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
2634 
2635  int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
2636 
2637  const int final_pixel[2] = {(int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h)};
2638 
2639  /* If current pixel uv is outside of texture */
2640  if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
2641  if (bdata->best_index == NOT_FOUND) {
2642  bdata->best_index = OUT_OF_TEXTURE;
2643  }
2644 
2645  continue;
2646  }
2647 
2648  const PaintUVPoint *tempPoints = data->tempPoints;
2649  int final_index = final_pixel[0] + w * final_pixel[1];
2650 
2651  /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
2652  if (final_index == (px + w * py)) {
2653  continue;
2654  }
2655 
2656  /* If final point is an "edge pixel", use its "real" neighbor instead */
2657  if (tempPoints[final_index].neighbor_pixel != -1) {
2658  final_index = tempPoints[final_index].neighbor_pixel;
2659 
2660  /* If we ended up to our origin point */
2661  if (final_index == (px + w * py)) {
2662  continue;
2663  }
2664  }
2665 
2666  const int final_tri_index = tempPoints[final_index].tri_index;
2667  /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
2668  if (!ELEM(final_tri_index, target_tri, -1)) {
2669  /* Check if it's close enough to likely touch the intended triangle. Any triangle
2670  * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
2671  const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
2672  const float threshold = square_f(0.7f) / (w * h);
2673 
2674  if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, final_tri_index, final_pt) >
2675  threshold) {
2676  continue;
2677  }
2678  }
2679 
2680  bdata->best_index = final_index;
2681  bdata->best_weight = dist_squared;
2682  }
2683 }
2684 
2685 static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
2686 {
2687  const int idx = ed->n_index[index];
2688 
2689  for (int i = 0; i < ed->n_num[index]; i++) {
2690  if (ed->n_target[idx + i] == neighbor) {
2691  return true;
2692  }
2693  }
2694 
2695  return false;
2696 }
2697 
2698 /* Makes the adjacency data symmetric, except for border pixels.
2699  * I.e. if A is neighbor of B, B is neighbor of A. */
2700 static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
2701 {
2702  int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
2703  int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
2704 
2705  if (new_n_num && new_n_index) {
2706  /* Count symmetrized neighbors */
2707  int total_targets = 0;
2708 
2709  for (int index = 0; index < active_points; index++) {
2710  total_targets += ed->n_num[index];
2711  new_n_num[index] = ed->n_num[index];
2712  }
2713 
2714  for (int index = 0; index < active_points; index++) {
2715  if (ed->flags[index] & ADJ_BORDER_PIXEL) {
2716  continue;
2717  }
2718 
2719  for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
2720  const int target = ed->n_target[idx + i];
2721 
2722  BLI_assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
2723 
2724  if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
2725  new_n_num[target]++;
2726  total_targets++;
2727  }
2728  }
2729  }
2730 
2731  /* Allocate a new target map */
2732  int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
2733 
2734  if (new_n_target) {
2735  /* Copy existing neighbors to the new map */
2736  int n_pos = 0;
2737 
2738  for (int index = 0; index < active_points; index++) {
2739  new_n_index[index] = n_pos;
2740  memcpy(&new_n_target[n_pos],
2741  &ed->n_target[ed->n_index[index]],
2742  sizeof(int) * ed->n_num[index]);
2743 
2744  /* Reset count to old, but advance position by new, leaving a gap to fill below. */
2745  n_pos += new_n_num[index];
2746  new_n_num[index] = ed->n_num[index];
2747  }
2748 
2749  BLI_assert(n_pos == total_targets);
2750 
2751  /* Add symmetrized - this loop behavior must exactly match the count pass above */
2752  for (int index = 0; index < active_points; index++) {
2753  if (ed->flags[index] & ADJ_BORDER_PIXEL) {
2754  continue;
2755  }
2756 
2757  for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
2758  const int target = ed->n_target[idx + i];
2759 
2760  if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
2761  const int num = new_n_num[target]++;
2762  new_n_target[new_n_index[target] + num] = index;
2763  }
2764  }
2765  }
2766 
2767  /* Swap maps */
2768  MEM_freeN(ed->n_target);
2769  ed->n_target = new_n_target;
2770 
2771  MEM_freeN(ed->n_index);
2772  ed->n_index = new_n_index;
2773 
2774  MEM_freeN(ed->n_num);
2775  ed->n_num = new_n_num;
2776 
2777  ed->total_targets = total_targets;
2778  return true;
2779  }
2780  }
2781 
2782  if (new_n_index) {
2783  MEM_freeN(new_n_index);
2784  }
2785  if (new_n_num) {
2786  MEM_freeN(new_n_num);
2787  }
2788 
2789  return false;
2790 }
2791 
2794  float *progress,
2795  short *do_update)
2796 {
2797  /* Antialias jitter point relative coords */
2798  const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2799  char uvname[MAX_CUSTOMDATA_LAYER_NAME];
2800  uint32_t active_points = 0;
2801  bool error = false;
2802 
2803  PaintSurfaceData *sData;
2804  DynamicPaintCanvasSettings *canvas = surface->canvas;
2806 
2807  PaintUVPoint *tempPoints = NULL;
2808  Vec3f *tempWeights = NULL;
2809  const MLoopTri *mlooptri = NULL;
2810  const MLoopUV *mloopuv = NULL;
2811  const MLoop *mloop = NULL;
2812 
2813  Bounds2D *faceBB = NULL;
2814  int *final_index;
2815 
2816  *progress = 0.0f;
2817  *do_update = true;
2818 
2819  if (!mesh) {
2820  return setError(canvas, N_("Canvas mesh not updated"));
2821  }
2822  if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) {
2823  return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
2824  }
2825 
2826  mloop = mesh->mloop;
2828  const int tottri = BKE_mesh_runtime_looptri_len(mesh);
2829 
2830  /* get uv map */
2832  CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
2833  mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
2834  }
2835 
2836  /* Check for validity */
2837  if (!mloopuv) {
2838  return setError(canvas, N_("No UV data on canvas"));
2839  }
2840  if (surface->image_resolution < 16 || surface->image_resolution > 8192) {
2841  return setError(canvas, N_("Invalid resolution"));
2842  }
2843 
2844  const int w = surface->image_resolution;
2845  const int h = w;
2846 
2847  /*
2848  * Start generating the surface
2849  */
2850  CLOG_INFO(&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, tottri);
2851 
2852  /* Init data struct */
2853  if (surface->data) {
2855  }
2856  sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
2857  if (!surface->data) {
2858  return setError(canvas, N_("Not enough free memory"));
2859  }
2860 
2861  tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
2862  if (!tempPoints) {
2863  error = true;
2864  }
2865 
2866  final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
2867  if (!final_index) {
2868  error = true;
2869  }
2870 
2871  tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
2872  if (!tempWeights) {
2873  error = true;
2874  }
2875 
2876  /*
2877  * Generate a temporary bounding box array for UV faces to optimize
2878  * the pixel-inside-a-face search.
2879  */
2880  if (!error) {
2881  faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
2882  if (!faceBB) {
2883  error = true;
2884  }
2885  }
2886 
2887  *progress = 0.01f;
2888  *do_update = true;
2889 
2890  if (!error) {
2891  for (int i = 0; i < tottri; i++) {
2892  copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
2893  copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
2894 
2895  for (int j = 1; j < 3; j++) {
2896  minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
2897  }
2898  }
2899 
2900  *progress = 0.02f;
2901  *do_update = true;
2902 
2903  /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
2905  .surface = surface,
2906  .tempPoints = tempPoints,
2907  .tempWeights = tempWeights,
2908  .mlooptri = mlooptri,
2909  .mloopuv = mloopuv,
2910  .mloop = mloop,
2911  .tottri = tottri,
2912  .faceBB = faceBB,
2913  };
2914  {
2915  TaskParallelSettings settings;
2917  settings.use_threading = (h > 64 || tottri > 1000);
2919  }
2920 
2921  *progress = 0.04f;
2922  *do_update = true;
2923 
2924  /*
2925  * Now loop through every pixel that was left without index
2926  * and find if they have neighboring pixels that have an index.
2927  * If so use that polygon as pixel surface.
2928  * (To avoid seams on uv island edges)
2929  */
2930  data.active_points = &active_points;
2931  {
2932  TaskParallelSettings settings;
2934  settings.use_threading = (h > 64);
2936  }
2937 
2938  *progress = 0.06f;
2939  *do_update = true;
2940 
2941  /* Generate surface adjacency data. */
2942  {
2943  int cursor = 0;
2944 
2945  /* Create a temporary array of final indexes (before unassigned
2946  * pixels have been dropped) */
2947  for (int i = 0; i < w * h; i++) {
2948  if (tempPoints[i].tri_index != -1) {
2949  final_index[i] = cursor;
2950  cursor++;
2951  }
2952  }
2953  /* allocate memory */
2954  sData->total_points = w * h;
2956 
2957  if (sData->adj_data) {
2958  PaintAdjData *ed = sData->adj_data;
2959  int n_pos = 0;
2960 
2961  MeshElemMap *vert_to_looptri_map;
2962  int *vert_to_looptri_map_mem;
2963 
2964  BKE_mesh_vert_looptri_map_create(&vert_to_looptri_map,
2965  &vert_to_looptri_map_mem,
2966  mesh->mvert,
2967  mesh->totvert,
2968  mlooptri,
2969  tottri,
2970  mloop,
2971  mesh->totloop);
2972 
2973  int total_border = 0;
2974 
2975  for (int ty = 0; ty < h; ty++) {
2976  for (int tx = 0; tx < w; tx++) {
2977  const int index = tx + w * ty;
2978 
2979  if (tempPoints[index].tri_index != -1) {
2980  ed->n_index[final_index[index]] = n_pos;
2981  ed->n_num[final_index[index]] = 0;
2982 
2983  if (tempPoints[index].neighbor_pixel != -1) {
2984  ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
2985  total_border++;
2986  }
2987 
2988  for (int i = 0; i < 8; i++) {
2989  /* Try to find a neighboring pixel in defined direction.
2990  * If not found, -1 is returned */
2991  const int n_target = dynamic_paint_find_neighbor_pixel(
2992  &data, vert_to_looptri_map, w, h, tx, ty, i);
2993 
2994  if (n_target >= 0 && n_target != index) {
2996  ed, final_index[index], final_index[n_target])) {
2997  ed->n_target[n_pos] = final_index[n_target];
2998  ed->n_num[final_index[index]]++;
2999  n_pos++;
3000  }
3001  }
3002  else if (ELEM(n_target, ON_MESH_EDGE, OUT_OF_TEXTURE)) {
3003  ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
3004  }
3005  }
3006  }
3007  }
3008  }
3009 
3010  MEM_freeN(vert_to_looptri_map);
3011  MEM_freeN(vert_to_looptri_map_mem);
3012 
3013  /* Make neighbors symmetric */
3014  if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
3015  error = true;
3016  }
3017 
3018  /* Create a list of border pixels */
3019  ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
3020 
3021  if (ed->border) {
3022  ed->total_border = total_border;
3023 
3024  for (int i = 0, next = 0; i < active_points; i++) {
3025  if (ed->flags[i] & ADJ_BORDER_PIXEL) {
3026  ed->border[next++] = i;
3027  }
3028  }
3029  }
3030 
3031 #if 0
3032  /* -----------------------------------------------------------------
3033  * For debug, write a dump of adjacency data to a file.
3034  * -----------------------------------------------------------------*/
3035  FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
3036  int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
3037  for (int ty = 0; ty < h; ty++) {
3038  for (int tx = 0; tx < w; tx++) {
3039  const int index = tx + w * ty;
3040  if (tempPoints[index].tri_index != -1) {
3041  tmp[final_index[index]] = index;
3042  }
3043  }
3044  }
3045  for (int ty = 0; ty < h; ty++) {
3046  for (int tx = 0; tx < w; tx++) {
3047  const int index = tx + w * ty;
3048  const int fidx = final_index[index];
3049 
3050  if (tempPoints[index].tri_index != -1) {
3051  int nidx = tempPoints[index].neighbor_pixel;
3052  fprintf(dump_file,
3053  "%d\t%d,%d\t%u\t%d,%d\t%d\t",
3054  fidx,
3055  tx,
3056  h - 1 - ty,
3057  tempPoints[index].tri_index,
3058  nidx < 0 ? -1 : (nidx % w),
3059  nidx < 0 ? -1 : h - 1 - (nidx / w),
3060  ed->flags[fidx]);
3061  for (int i = 0; i < ed->n_num[fidx]; i++) {
3062  int tgt = tmp[ed->n_target[ed->n_index[fidx] + i]];
3063  fprintf(dump_file, "%s%d,%d", i ? " " : "", tgt % w, h - 1 - tgt / w);
3064  }
3065  fprintf(dump_file, "\n");
3066  }
3067  }
3068  }
3069  MEM_freeN(tmp);
3070  fclose(dump_file);
3071 #endif
3072  }
3073  }
3074 
3075  *progress = 0.08f;
3076  *do_update = true;
3077 
3078  /* Create final surface data without inactive points */
3079  ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
3080  if (f_data) {
3081  f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
3082  f_data->barycentricWeights = MEM_callocN(
3083  active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
3084 
3085  if (!f_data->uv_p || !f_data->barycentricWeights) {
3086  error = 1;
3087  }
3088  }
3089  else {
3090  error = 1;
3091  }
3092 
3093  /* in case of allocation error, free everything */
3094  if (error) {
3095  if (f_data) {
3096  if (f_data->uv_p) {
3097  MEM_freeN(f_data->uv_p);
3098  }
3099  if (f_data->barycentricWeights) {
3100  MEM_freeN(f_data->barycentricWeights);
3101  }
3102  MEM_freeN(f_data);
3103  }
3104  sData->total_points = 0;
3105  }
3106  else {
3107  sData->total_points = (int)active_points;
3108  sData->format_data = f_data;
3109 
3110  for (int index = 0, cursor = 0; index < (w * h); index++) {
3111  if (tempPoints[index].tri_index != -1) {
3112  memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
3113  memcpy(&f_data->barycentricWeights[cursor * aa_samples],
3114  &tempWeights[index * aa_samples],
3115  sizeof(*tempWeights) * aa_samples);
3116  cursor++;
3117  }
3118  }
3119  }
3120  }
3121  if (error == 1) {
3122  setError(canvas, N_("Not enough free memory"));
3123  }
3124 
3125  if (faceBB) {
3126  MEM_freeN(faceBB);
3127  }
3128  if (tempPoints) {
3129  MEM_freeN(tempPoints);
3130  }
3131  if (tempWeights) {
3132  MEM_freeN(tempWeights);
3133  }
3134  if (final_index) {
3135  MEM_freeN(final_index);
3136  }
3137 
3138  /* Init surface type data */
3139  if (!error) {
3141 
3142 #if 0
3143  /* -----------------------------------------------------------------
3144  * For debug, output pixel statuses to the color map
3145  * -----------------------------------------------------------------*/
3146  for (index = 0; index < sData->total_points; index++) {
3147  ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
3148  PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
3149  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
3150  pPoint->alpha = 1.0f;
3151 
3152  /* Every pixel that is assigned as "edge pixel" gets blue color */
3153  if (uvPoint->neighbor_pixel != -1) {
3154  pPoint->color[2] = 1.0f;
3155  }
3156  /* and every pixel that finally got an polygon gets red color */
3157  /* green color shows pixel face index hash */
3158  if (uvPoint->tri_index != -1) {
3159  pPoint->color[0] = 1.0f;
3160  pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
3161  }
3162  }
3163 #endif
3164 
3166  }
3167 
3168  *progress = 0.09f;
3169  *do_update = true;
3170 
3171  return (error == 0);
3172 }
3173 
3174 /*
3175  * Outputs an image file from uv surface data.
3176  */
3181 
3183  void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
3184 {
3185  const DynamicPaintOutputSurfaceImageData *data = userdata;
3186 
3187  const DynamicPaintSurface *surface = data->surface;
3188  const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
3189 
3190  ImBuf *ibuf = data->ibuf;
3191  /* image buffer position */
3192  const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3193 
3194  /* blend wet and dry layers */
3195  blendColors(
3196  point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
3197 
3198  /* Multiply color by alpha if enabled */
3199  if (surface->flags & MOD_DPAINT_MULALPHA) {
3200  mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
3201  }
3202 }
3203 
3205  void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
3206 {
3207  const DynamicPaintOutputSurfaceImageData *data = userdata;
3208 
3209  const DynamicPaintSurface *surface = data->surface;
3210  float depth = ((float *)surface->data->type_data)[index];
3211 
3212  ImBuf *ibuf = data->ibuf;
3213  /* image buffer position */
3214  const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3215 
3216  if (surface->depth_clamp) {
3217  depth /= surface->depth_clamp;
3218  }
3219 
3220  if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
3221  depth = (0.5f - depth / 2.0f);
3222  }
3223 
3224  CLAMP(depth, 0.0f, 1.0f);
3225 
3226  copy_v3_fl(&ibuf->rect_float[pos], depth);
3227  ibuf->rect_float[pos + 3] = 1.0f;
3228 }
3229 
3231  void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
3232 {
3233  const DynamicPaintOutputSurfaceImageData *data = userdata;
3234 
3235  const DynamicPaintSurface *surface = data->surface;
3236  const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
3237  float depth = wPoint->height;
3238 
3239  ImBuf *ibuf = data->ibuf;
3240  /* image buffer position */
3241  const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3242 
3243  if (surface->depth_clamp) {
3244  depth /= surface->depth_clamp;
3245  }
3246 
3247  depth = (0.5f + depth / 2.0f);
3248  CLAMP(depth, 0.0f, 1.0f);
3249 
3250  copy_v3_fl(&ibuf->rect_float[pos], depth);
3251  ibuf->rect_float[pos + 3] = 1.0f;
3252 }
3253 
3255  void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
3256 {
3257  const DynamicPaintOutputSurfaceImageData *data = userdata;
3258 
3259  const DynamicPaintSurface *surface = data->surface;
3260  const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
3261 
3262  ImBuf *ibuf = data->ibuf;
3263  /* image buffer position */
3264  const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
3265 
3266  copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
3267  ibuf->rect_float[pos + 3] = 1.0f;
3268 }
3269 
3271  const char *filepath,
3272  short output_layer)
3273 {
3274  ImBuf *ibuf = NULL;
3275  PaintSurfaceData *sData = surface->data;
3276  /* OpenEXR or PNG */
3277  int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR :
3279  char output_file[FILE_MAX];
3280 
3281  if (!sData->type_data) {
3282  setError(surface->canvas, N_("Image save failed: invalid surface"));
3283  return;
3284  }
3285  /* if selected format is openexr, but current build doesn't support one */
3286 #ifndef WITH_OPENEXR
3287  if (format == R_IMF_IMTYPE_OPENEXR) {
3289  }
3290 #endif
3291  BLI_strncpy(output_file, filepath, sizeof(output_file));
3293 
3294  /* Validate output file path */
3296  BLI_make_existing_file(output_file);
3297 
3298  /* Init image buffer */
3299  ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
3300  if (ibuf == NULL) {
3301  setError(surface->canvas, N_("Image save failed: not enough free memory"));
3302  return;
3303  }
3304 
3306  .surface = surface,
3307  .ibuf = ibuf,
3308  };
3309  switch (surface->type) {
3311  switch (output_layer) {
3312  case 0: {
3313  TaskParallelSettings settings;
3315  settings.use_threading = (sData->total_points > 10000);
3317  sData->total_points,
3318  &data,
3320  &settings);
3321  break;
3322  }
3323  case 1: {
3324  TaskParallelSettings settings;
3326  settings.use_threading = (sData->total_points > 10000);
3328  sData->total_points,
3329  &data,
3331  &settings);
3332  break;
3333  }
3334  default:
3335  BLI_assert(0);
3336  break;
3337  }
3338  break;
3340  switch (output_layer) {
3341  case 0: {
3342  TaskParallelSettings settings;
3344  settings.use_threading = (sData->total_points > 10000);
3346  sData->total_points,
3347  &data,
3349  &settings);
3350  break;
3351  }
3352  case 1:
3353  break;
3354  default:
3355  BLI_assert(0);
3356  break;
3357  }
3358  break;
3360  switch (output_layer) {
3361  case 0: {
3362  TaskParallelSettings settings;
3364  settings.use_threading = (sData->total_points > 10000);
3366  sData->total_points,
3367  &data,
3369  &settings);
3370  break;
3371  }
3372  case 1:
3373  break;
3374  default:
3375  BLI_assert(0);
3376  break;
3377  }
3378  break;
3379  default:
3380  BLI_assert(0);
3381  break;
3382  }
3383 
3384  /* Set output format, PNG in case EXR isn't supported. */
3385 #ifdef WITH_OPENEXR
3386  if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
3387  ibuf->ftype = IMB_FTYPE_OPENEXR;
3388  ibuf->foptions.flag |= OPENEXR_COMPRESS;
3389  }
3390  else
3391 #endif
3392  {
3393  ibuf->ftype = IMB_FTYPE_PNG;
3394  ibuf->foptions.quality = 15;
3395  }
3396 
3397  /* Save image */
3398  IMB_saveiff(ibuf, output_file, IB_rectfloat);
3399  IMB_freeImBuf(ibuf);
3400 }
3401 
3404 /***************************** Ray / Nearest Point Utils ******************************/
3405 
3406 /* A modified callback to bvh tree ray-cast.
3407  * The tree must have been built using bvhtree_from_mesh_looptri.
3408  * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
3409  *
3410  * To optimize brush detection speed this doesn't calculate hit coordinates or normal.
3411  */
3412 static void mesh_tris_spherecast_dp(void *userdata,
3413  int index,
3414  const BVHTreeRay *ray,
3415  BVHTreeRayHit *hit)
3416 {
3417  const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
3418  const MVert *vert = data->vert;
3419  const MLoopTri *mlooptri = data->looptri;
3420  const MLoop *mloop = data->loop;
3421 
3422  const float *t0, *t1, *t2;
3423  float dist;
3424 
3425  t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
3426  t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
3427  t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
3428 
3429  dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
3430 
3431  if (dist >= 0 && dist < hit->dist) {
3432  hit->index = index;
3433  hit->dist = dist;
3434  hit->no[0] = 0.0f;
3435  }
3436 }
3437 
3438 /* A modified callback to bvh tree nearest point.
3439  * The tree must have been built using bvhtree_from_mesh_looptri.
3440  * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
3441  *
3442  * To optimize brush detection speed this doesn't calculate hit normal.
3443  */
3444 static void mesh_tris_nearest_point_dp(void *userdata,
3445  int index,
3446  const float co[3],
3447  BVHTreeNearest *nearest)
3448 {
3449  const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
3450  const MVert *vert = data->vert;
3451  const MLoopTri *mlooptri = data->looptri;
3452  const MLoop *mloop = data->loop;
3453  float nearest_tmp[3], dist_sq;
3454 
3455  const float *t0, *t1, *t2;
3456  t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
3457  t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
3458  t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
3459 
3460  closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
3461  dist_sq = len_squared_v3v3(co, nearest_tmp);
3462 
3463  if (dist_sq < nearest->dist_sq) {
3464  nearest->index = index;
3465  nearest->dist_sq = dist_sq;
3466  copy_v3_v3(nearest->co, nearest_tmp);
3467  nearest->no[0] = 0.0f;
3468  }
3469 }
3470 
3471 /***************************** Brush Painting Calls ******************************/
3472 
3484  const int index,
3485  const int paintFlags,
3486  const float paintColor[3],
3487  const float paintAlpha,
3488  const float paintWetness,
3489  const float timescale)
3490 {
3491  PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
3492 
3493  /* Add paint */
3494  if (!(paintFlags & MOD_DPAINT_ERASE)) {
3495  float mix[4];
3496  float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
3497 
3498  /* mix brush color with wet layer color */
3499  blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
3500  copy_v3_v3(pPoint->e_color, mix);
3501 
3502  /* mix wetness and alpha depending on selected alpha mode */
3503  if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
3504  /* update values to the brush level unless they're higher already */
3505  CLAMP_MIN(pPoint->e_color[3], paintAlpha);
3506  CLAMP_MIN(pPoint->wetness, paintWetness);
3507  }
3508  else {
3509  float wetness = paintWetness;
3510  CLAMP(wetness, 0.0f, 1.0f);
3511  pPoint->e_color[3] = mix[3];
3512  pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
3513  }
3514 
3515  CLAMP_MIN(pPoint->wetness, MIN_WETNESS);
3516 
3517  pPoint->state = DPAINT_PAINT_NEW;
3518  }
3519  /* Erase paint */
3520  else {
3521  float a_ratio, a_highest;
3522  float wetness;
3523  float invFact = 1.0f - paintAlpha;
3524 
3525  /*
3526  * Make highest alpha to match erased value
3527  * but maintain alpha ratio
3528  */
3529  if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
3530  a_highest = max_ff(pPoint->color[3], pPoint->e_color[3]);
3531  if (a_highest > invFact) {
3532  a_ratio = invFact / a_highest;
3533 
3534  pPoint->e_color[3] *= a_ratio;
3535  pPoint->color[3] *= a_ratio;
3536  }
3537  }
3538  else {
3539  pPoint->e_color[3] -= paintAlpha * timescale;
3540  CLAMP_MIN(pPoint->e_color[3], 0.0f);
3541  pPoint->color[3] -= paintAlpha * timescale;
3542  CLAMP_MIN(pPoint->color[3], 0.0f);
3543  }
3544 
3545  wetness = (1.0f - paintWetness) * pPoint->e_color[3];
3546  CLAMP_MAX(pPoint->wetness, wetness);
3547  }
3548 }
3549 
3550 /* applies given brush intersection value for wave surface */
3552  const DynamicPaintBrushSettings *brush,
3553  float isect_height)
3554 {
3555  const float isect_change = isect_height - wPoint->brush_isect;
3556  const float wave_factor = brush->wave_factor;
3557  bool hit = false;
3558 
3559  /* intersection marked regardless of brush type or hit */
3560  wPoint->brush_isect = isect_height;
3561  wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
3562 
3563  isect_height *= wave_factor;
3564 
3565  /* determine hit depending on wave_factor */
3566  if (wave_factor > 0.0f && wPoint->height > isect_height) {
3567  hit = true;
3568  }
3569  else if (wave_factor < 0.0f && wPoint->height < isect_height) {
3570  hit = true;
3571  }
3572 
3573  if (hit) {
3574  switch (brush->wave_type) {
3576  wPoint->height = isect_height;
3577  wPoint->state = DPAINT_WAVE_OBSTACLE;
3578  wPoint->velocity = 0.0f;
3579  break;
3581  wPoint->velocity = isect_height;
3582  break;
3584  wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
3585  break;
3587  if (isect_change < 0.0f) {
3588  wPoint->height += isect_change * wave_factor;
3589  }
3590  break;
3591  default:
3592  BLI_assert(0);
3593  break;
3594  }
3595  }
3596 }
3597 
3598 /*
3599  * add brush results to the surface data depending on surface type
3600  */
3602  const int index,
3603  const DynamicPaintBrushSettings *brush,
3604  float paint[3],
3605  float influence,
3606  float depth,
3607  float vel_factor,
3608  const float timescale)
3609 {
3610  PaintSurfaceData *sData = surface->data;
3611  float strength;
3612 
3613  /* apply influence scale */
3614  influence *= surface->influence_scale;
3615  depth *= surface->influence_scale;
3616 
3617  strength = influence * brush->alpha;
3618  CLAMP(strength, 0.0f, 1.0f);
3619 
3620  /* Sample velocity colorband if required */
3621  if (brush->flags &
3623  float coba_res[4];
3624  vel_factor /= brush->max_velocity;
3625  CLAMP(vel_factor, 0.0f, 1.0f);
3626 
3627  if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
3628  if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
3629  copy_v3_v3(paint, coba_res);
3630  }
3631  if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA) {
3632  strength *= coba_res[3];
3633  }
3634  if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH) {
3635  depth *= coba_res[3];
3636  }
3637  }
3638  }
3639 
3640  /* mix paint surface */
3641  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
3642  float paintWetness = brush->wetness * strength;
3643  float paintAlpha = strength;
3644 
3646  surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
3647  }
3648  /* displace surface */
3649  else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
3650  float *value = (float *)sData->type_data;
3651 
3653  depth = value[index] + depth;
3654  }
3655 
3656  if (surface->depth_clamp) {
3657  CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
3658  }
3659 
3660  if (brush->flags & MOD_DPAINT_ERASE) {
3661  value[index] *= (1.0f - strength);
3662  CLAMP_MIN(value[index], 0.0f);
3663  }
3664  else {
3665  CLAMP_MIN(value[index], depth);
3666  }
3667  }
3668  /* vertex weight group surface */
3669  else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
3670  float *value = (float *)sData->type_data;
3671 
3672  if (brush->flags & MOD_DPAINT_ERASE) {
3673  value[index] *= (1.0f - strength);
3674  CLAMP_MIN(value[index], 0.0f);
3675  }
3676  else {
3677  CLAMP_MIN(value[index], strength);
3678  }
3679  }
3680  /* wave surface */
3681  else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
3682  if (brush->wave_clamp) {
3683  CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
3684  }
3685 
3686  dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
3687  }
3688 
3689  /* doing velocity based painting */
3690  if (sData->bData->brush_velocity) {
3691  sData->bData->brush_velocity[index * 4 + 3] *= influence;
3692  }
3693 }
3694 
3695 /* checks whether surface and brush bounds intersect depending on brush type */
3697  Bounds3D *b2,
3699  float brush_radius)
3700 {
3701  if (brush->collision == MOD_DPAINT_COL_VOLUME) {
3702  return boundsIntersect(b1, b2);
3703  }
3705  return boundsIntersectDist(b1, b2, brush_radius);
3706  }
3707  return true;
3708 }
3709 
3710 /* calculate velocity for mesh vertices */
3713 
3714  const MVert *mvert_p;
3715  const MVert *mvert_c;
3716 
3717  float (*obmat)[4];
3719 
3720  const float timescale;
3722 
3723 static void dynamic_paint_brush_velocity_compute_cb(void *__restrict userdata,
3724  const int i,
3725  const TaskParallelTLS *__restrict UNUSED(tls))
3726 {
3727  const DynamicPaintBrushVelocityData *data = userdata;
3728 
3729  Vec3f *brush_vel = data->brush_vel;
3730 
3731  const MVert *mvert_p = data->mvert_p;
3732  const MVert *mvert_c = data->mvert_c;
3733 
3734  float(*obmat)[4] = data->obmat;
3735  float(*prev_obmat)[4] = data->prev_obmat;
3736 
3737  const float timescale = data->timescale;
3738 
3739  float p1[3], p2[3];
3740 
3741  copy_v3_v3(p1, mvert_p[i].co);
3742  mul_m4_v3(prev_obmat, p1);
3743 
3744  copy_v3_v3(p2, mvert_c[i].co);
3745  mul_m4_v3(obmat, p2);
3746 
3747  sub_v3_v3v3(brush_vel[i].v, p2, p1);
3748  mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
3749 }
3750 
3752  Scene *scene,
3753  Object *ob,
3755  Vec3f **brushVel,
3756  float timescale)
3757 {
3758  float prev_obmat[4][4];
3759  Mesh *mesh_p, *mesh_c;
3760  MVert *mvert_p, *mvert_c;
3761  int numOfVerts_p, numOfVerts_c;
3762 
3763  float cur_sfra = scene->r.subframe;
3764  int cur_fra = scene->r.cfra;
3765  float prev_sfra = cur_sfra - timescale;
3766  int prev_fra = cur_fra;
3767 
3768  if (prev_sfra < 0.0f) {
3769  prev_sfra += 1.0f;
3770  prev_fra = cur_fra - 1;
3771  }
3772 
3773  /* previous frame mesh */
3774  scene->r.cfra = prev_fra;
3775  scene->r.subframe = prev_sfra;
3776 
3778  scene,
3779  ob,
3780  true,
3784  mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false);
3785  numOfVerts_p = mesh_p->totvert;
3786  mvert_p = mesh_p->mvert;
3787  copy_m4_m4(prev_obmat, ob->obmat);
3788 
3789  /* current frame mesh */
3790  scene->r.cfra = cur_fra;
3791  scene->r.subframe = cur_sfra;
3792 
3794  scene,
3795  ob,
3796  true,
3800  mesh_c = dynamicPaint_brush_mesh_get(brush);
3801  numOfVerts_c = mesh_c->totvert;
3802  mvert_c = mesh_c->mvert;
3803 
3804  (*brushVel) = (struct Vec3f *)MEM_mallocN(numOfVerts_c * sizeof(Vec3f),
3805  "Dynamic Paint brush velocity");
3806  if (!(*brushVel)) {
3807  return;
3808  }
3809 
3810  /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
3811  if (numOfVerts_p != numOfVerts_c) {
3812  mvert_p = mvert_c;
3813  }
3814 
3815  /* calculate speed */
3817  .brush_vel = *brushVel,
3818  .mvert_p = mvert_p,
3819  .mvert_c = mvert_c,
3820  .obmat = ob->obmat,
3821  .prev_obmat = prev_obmat,
3822  .timescale = timescale,
3823  };
3824  TaskParallelSettings settings;
3826  settings.use_threading = (numOfVerts_c > 10000);
3828  0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, &settings);
3829 
3830  BKE_id_free(NULL, mesh_p);
3831 }
3832 
3833 /* calculate velocity for object center point */
3835  Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
3836 {
3837  float prev_obmat[4][4];
3838  float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
3839 
3840  float cur_sfra = scene->r.subframe;
3841  int cur_fra = scene->r.cfra;
3842  float prev_sfra = cur_sfra - timescale;
3843  int prev_fra = cur_fra;
3844 
3845  if (prev_sfra < 0.0f) {
3846  prev_sfra += 1.0f;
3847  prev_fra = cur_fra - 1;
3848  }
3849 
3850  /* previous frame mesh */
3851  scene->r.cfra = prev_fra;
3852  scene->r.subframe = prev_sfra;
3854  scene,
3855  ob,
3856  false,
3860  copy_m4_m4(prev_obmat, ob->obmat);
3861 
3862  /* current frame mesh */
3863  scene->r.cfra = cur_fra;
3864  scene->r.subframe = cur_sfra;
3866  scene,
3867  ob,
3868  false,
3872 
3873  /* calculate speed */
3874  mul_m4_v3(prev_obmat, prev_loc);
3875  mul_m4_v3(ob->obmat, cur_loc);
3876 
3877  sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
3878  mul_v3_fl(brushVel->v, 1.0f / timescale);
3879 }
3880 
3881 typedef struct DynamicPaintPaintData {
3885  const Scene *scene;
3886  const float timescale;
3887  const int c_index;
3888 
3890  const MVert *mvert;
3891  const MLoop *mloop;
3893  const float brush_radius;
3894  const float *avg_brushNor;
3896 
3898  const float solidradius;
3899 
3900  void *treeData;
3901 
3902  float *pointCoord;
3904 
3905 /*
3906  * Paint a brush object mesh to the surface
3907  */
3909  void *__restrict userdata, const int id, const TaskParallelTLS *__restrict UNUSED(tls))
3910 {
3911  const DynamicPaintPaintData *data = userdata;
3912 
3913  const DynamicPaintSurface *surface = data->surface;
3914  const PaintSurfaceData *sData = surface->data;
3915  const PaintBakeData *bData = sData->bData;
3916  VolumeGrid *grid = bData->grid;
3917 
3918  const DynamicPaintBrushSettings *brush = data->brush;
3919 
3920  const float timescale = data->timescale;
3921  const int c_index = data->c_index;
3922 
3923  const MVert *mvert = data->mvert;
3924  const MLoop *mloop = data->mloop;
3925  const MLoopTri *mlooptri = data->mlooptri;
3926  const float brush_radius = data->brush_radius;
3927  const float *avg_brushNor = data->avg_brushNor;
3928  const Vec3f *brushVelocity = data->brushVelocity;
3929 
3930  BVHTreeFromMesh *treeData = data->treeData;
3931 
3932  const int index = grid->t_index[grid->s_pos[c_index] + id];
3933  const int samples = bData->s_num[index];
3934  int ss;
3935  float total_sample = (float)samples;
3936  float brushStrength = 0.0f; /* brush influence factor */
3937  float depth = 0.0f; /* brush intersection depth */
3938  float velocity_val = 0.0f;
3939 
3940  float paintColor[3] = {0.0f};
3941  int numOfHits = 0;
3942 
3943  /* for image sequence anti-aliasing, use gaussian factors */
3944  if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
3945  total_sample = gaussianTotal;
3946  }
3947 
3948  /* Super-sampling */
3949  for (ss = 0; ss < samples; ss++) {
3950  float ray_start[3], ray_dir[3];
3951  float sample_factor = 0.0f;
3952  float sampleStrength = 0.0f;
3953  BVHTreeRayHit hit;
3954  BVHTreeNearest nearest;
3955  short hit_found = 0;
3956 
3957  /* volume sample */
3958  float volume_factor = 0.0f;
3959  /* proximity sample */
3960  float proximity_factor = 0.0f;
3961  float prox_colorband[4] = {0.0f};
3962  const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
3963  brush->collision == MOD_DPAINT_COL_VOLDIST);
3964 
3965  /* hit data */
3966  float hitCoord[3];
3967  int hitTri = -1;
3968 
3969  /* Super-sampling factor. */
3970  if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
3971  sample_factor = gaussianFactors[ss];
3972  }
3973  else {
3974  sample_factor = 1.0f;
3975  }
3976 
3977  /* Get current sample position in world coordinates */
3978  copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
3979  copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
3980 
3981  /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
3982  add_v3_fl(ray_start, 0.001f);
3983 
3984  hit.index = -1;
3985  hit.dist = BVH_RAYCAST_DIST_MAX;
3986  nearest.index = -1;
3987  nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
3988 
3989  /* Check volume collision */
3992  treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
3993  if (hit.index != -1) {
3994  /* We hit a triangle, now check if collision point normal is facing the point */
3995 
3996  /* For optimization sake, hit point normal isn't calculated in ray cast loop */
3997  const int vtri[3] = {
3998  mloop[mlooptri[hit.index].tri[0]].v,
3999  mloop[mlooptri[hit.index].tri[1]].v,
4000  mloop[mlooptri[hit.index].tri[2]].v,
4001  };
4002  float dot;
4003 
4004  normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
4005  dot = dot_v3v3(ray_dir, hit.no);
4006 
4007  /* If ray and hit face normal are facing same direction
4008  * hit point is inside a closed mesh. */
4009  if (dot >= 0.0f) {
4010  const float dist = hit.dist;
4011  const int f_index = hit.index;
4012 
4013  /* Also cast a ray in opposite direction to make sure
4014  * point is at least surrounded by two brush faces */
4015  negate_v3(ray_dir);
4016  hit.index = -1;
4017  hit.dist = BVH_RAYCAST_DIST_MAX;
4018 
4020  treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
4021 
4022  if (hit.index != -1) {
4023  /* Add factor on super-sample filter. */
4024  volume_factor = 1.0f;
4025  hit_found = HIT_VOLUME;
4026 
4027  /* Mark hit info */
4028 
4029  /* Calculate final hit coordinates */
4030  madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist);
4031 
4032  depth += dist * sample_factor;
4033  hitTri = f_index;
4034  }
4035  }
4036  }
4037  }
4038 
4039  /* Check proximity collision */
4041  (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX))) {
4042  float proxDist = -1.0f;
4043  float hitCo[3] = {0.0f, 0.0f, 0.0f};
4044  int tri = 0;
4045 
4046  /* if inverse prox and no hit found, skip this sample */
4047  if (inner_proximity && !hit_found) {
4048  continue;
4049  }
4050 
4051  /* If pure distance proximity, find the nearest point on the mesh */
4052  if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
4054  treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
4055  if (nearest.index != -1) {
4056  proxDist = sqrtf(nearest.dist_sq);
4057  copy_v3_v3(hitCo, nearest.co);
4058  tri = nearest.index;
4059  }
4060  }
4061  else { /* else cast a ray in defined projection direction */
4062  float proj_ray[3] = {0.0f};
4063 
4064  if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
4065  copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
4066  negate_v3(proj_ray);
4067  }
4068  else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
4069  copy_v3_v3(proj_ray, avg_brushNor);
4070  }
4071  else { /* MOD_DPAINT_RAY_ZPLUS */
4072  proj_ray[2] = 1.0f;
4073  }
4074  hit.index = -1;
4075  hit.dist = brush_radius;
4076 
4077  /* Do a face normal directional ray-cast, and use that distance. */
4079  treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
4080  if (hit.index != -1) {
4081  proxDist = hit.dist;
4082 
4083  /* Calculate final hit coordinates */
4084  madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist);
4085 
4086  tri = hit.index;
4087  }
4088  }
4089 
4090  /* If a hit was found, calculate required values */
4091  if (proxDist >= 0.0f && proxDist <= brush_radius) {
4092  proximity_factor = proxDist / brush_radius;
4093  CLAMP(proximity_factor, 0.0f, 1.0f);
4094  if (!inner_proximity) {
4095  proximity_factor = 1.0f - proximity_factor;
4096  }
4097 
4098  hit_found = HIT_PROXIMITY;
4099 
4100  /* if no volume hit, use prox point face info */
4101  if (hitTri == -1) {
4102  copy_v3_v3(hitCoord, hitCo);
4103  hitTri = tri;
4104  }
4105  }
4106  }
4107 
4108  /* mix final sample strength depending on brush settings */
4109  if (hit_found) {
4110  /* If "negate volume" enabled, negate all factors within volume. */
4111  if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) {
4112  volume_factor = 1.0f - volume_factor;
4113  if (inner_proximity) {
4114  proximity_factor = 1.0f - proximity_factor;
4115  }
4116  }
4117 
4118  /* apply final sample depending on final hit type */
4119  if (hit_found == HIT_VOLUME) {
4120  sampleStrength = volume_factor;
4121  }
4122  else if (hit_found == HIT_PROXIMITY) {
4123  /* apply falloff curve to the proximity_factor */
4124  if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
4125  BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband)) {
4126  proximity_factor = prox_colorband[3];
4127  }
4128  else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
4129  proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f :
4130  0.0f;
4131  }
4132  /* apply sample */
4133  sampleStrength = proximity_factor;
4134  }
4135 
4136  sampleStrength *= sample_factor;
4137  }
4138  else {
4139  continue;
4140  }
4141 
4142  /* velocity brush, only do on main sample */
4143  if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
4144  float weights[3];
4145  float brushPointVelocity[3];
4146  float velocity[3];
4147 
4148  const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
4149  const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
4150  const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
4151 
4152  /* calculate barycentric weights for hit point */
4153  interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
4154 
4155  /* Simple check based on brush surface velocity,
4156  * TODO: perhaps implement something that handles volume movement as well. */
4157 
4158  /* interpolate vertex speed vectors to get hit point velocity */
4159  interp_v3_v3v3v3(brushPointVelocity,
4160  brushVelocity[v1].v,
4161  brushVelocity[v2].v,
4162  brushVelocity[v3].v,
4163  weights);
4164 
4165  /* subtract canvas point velocity */
4166  if (bData->velocity) {
4167  sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
4168  }
4169  else {
4170  copy_v3_v3(velocity, brushPointVelocity);
4171  }
4172  velocity_val = normalize_v3(velocity);
4173 
4174  /* if brush has smudge enabled store brush velocity */
4175  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
4176  bData->brush_velocity) {
4177  copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
4178  bData->brush_velocity[index * 4 + 3] = velocity_val;
4179  }
4180  }
4181 
4182  /*
4183  * Process hit color and alpha
4184  */
4185  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4186  float sampleColor[3];
4187  float alpha_factor = 1.0f;
4188 
4189  sampleColor[0] = brush->r;
4190  sampleColor[1] = brush->g;
4191  sampleColor[2] = brush->b;
4192 
4193  /* Sample proximity colorband if required */
4194  if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
4195  if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
4196  sampleColor[0] = prox_colorband[0];
4197  sampleColor[1] = prox_colorband[1];
4198  sampleColor[2] = prox_colorband[2];
4199  }
4200  }
4201 
4202  /* Add AA sample */
4203  paintColor[0] += sampleColor[0];
4204  paintColor[1] += sampleColor[1];
4205  paintColor[2] += sampleColor[2];
4206  sampleStrength *= alpha_factor;
4207  numOfHits++;
4208  }
4209 
4210  /* Apply sample strength. */
4211  brushStrength += sampleStrength;
4212  } /* End super-sampling. */
4213 
4214  /* If any sample was inside paint range. */
4215  if (brushStrength > 0.0f || depth > 0.0f) {
4216  /* Apply super-sampling results. */
4217  if (samples > 1) {
4218  brushStrength /= total_sample;
4219  }
4220  CLAMP(brushStrength, 0.0f, 1.0f);
4221 
4222  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4223  /* Get final pixel color and alpha. */
4224  paintColor[0] /= numOfHits;
4225  paintColor[1] /= numOfHits;
4226  paintColor[2] /= numOfHits;
4227  }
4228  /* Get final object space depth. */
4230  depth /= bData->bNormal[index].normal_scale * total_sample;
4231  }
4232 
4234  surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
4235  }
4236 }
4237 
4241  Object *brushOb,
4242  Scene *scene,
4243  float timescale)
4244 {
4245  PaintSurfaceData *sData = surface->data;
4246  PaintBakeData *bData = sData->bData;
4247  Mesh *mesh = NULL;
4248  Vec3f *brushVelocity = NULL;
4249  MVert *mvert = NULL;
4250  const MLoopTri *mlooptri = NULL;
4251  const MLoop *mloop = NULL;
4252 
4253  if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
4255  depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
4256  }
4257 
4258  Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
4259  if (brush_mesh == NULL) {
4260  return false;
4261  }
4262 
4263  {
4264  BVHTreeFromMesh treeData = {NULL};
4265  float avg_brushNor[3] = {0.0f};
4266  const float brush_radius = brush->paint_distance * surface->radius_scale;
4267  int numOfVerts;
4268  int ii;
4269  Bounds3D mesh_bb = {{0}};
4270  VolumeGrid *grid = bData->grid;
4271 
4272  mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
4273  mvert = mesh->mvert;
4274  const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
4276  mloop = mesh->mloop;
4277  numOfVerts = mesh->totvert;
4278 
4279  /* Transform collider vertices to global space
4280  * (Faster than transforming per surface point
4281  * coordinates and normals to object space) */
4282  for (ii = 0; ii < numOfVerts; ii++) {
4283  mul_m4_v3(brushOb->obmat, mvert[ii].co);
4284  boundInsert(&mesh_bb, mvert[ii].co);
4285 
4286  /* for proximity project calculate average normal */
4287  if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
4288  float nor[3];
4289  copy_v3_v3(nor, vert_normals[ii]);
4290  mul_mat3_m4_v3(brushOb->obmat, nor);
4291  normalize_v3(nor);
4292 
4293  add_v3_v3(avg_brushNor, nor);
4294  }
4295  }
4296 
4297  if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
4298  mul_v3_fl(avg_brushNor, 1.0f / (float)numOfVerts);
4299  /* instead of null vector use positive z */
4300  if (UNLIKELY(normalize_v3(avg_brushNor) == 0.0f)) {
4301  avg_brushNor[2] = 1.0f;
4302  }
4303  }
4304 
4305  /* check bounding box collision */
4306  if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
4307  /* Build a bvh tree from transformed vertices */
4308  if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
4309  int c_index;
4310  int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
4311 
4312  /* loop through space partitioning grid */
4313  for (c_index = 0; c_index < total_cells; c_index++) {
4314  /* check grid cell bounding box */
4315  if (!grid->s_num[c_index] ||
4316  !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius)) {
4317  continue;
4318  }
4319 
4320  /* loop through cell points and process brush */
4322  .surface = surface,
4323  .brush = brush,
4324  .brushOb = brushOb,
4325  .scene = scene,
4326  .timescale = timescale,
4327  .c_index = c_index,
4328  .mesh = mesh,
4329  .mvert = mvert,
4330  .mloop = mloop,
4331  .mlooptri = mlooptri,
4332  .brush_radius = brush_radius,
4333  .avg_brushNor = avg_brushNor,
4334  .brushVelocity = brushVelocity,
4335  .treeData = &treeData,
4336  };
4337  TaskParallelSettings settings;
4339  settings.use_threading = (grid->s_num[c_index] > 250);
4341  grid->s_num[c_index],
4342  &data,
4344  &settings);
4345  }
4346  }
4347  }
4348  /* free bvh tree */
4349  free_bvhtree_from_mesh(&treeData);
4350  BKE_id_free(NULL, mesh);
4351  }
4352 
4353  /* free brush velocity data */
4354  if (brushVelocity) {
4355  MEM_freeN(brushVelocity);
4356  }
4357 
4358  return true;
4359 }
4360 
4361 /*
4362  * Paint a particle system to the surface
4363  */
4365  void *__restrict userdata, const int id, const TaskParallelTLS *__restrict UNUSED(tls))
4366 {
4367  const DynamicPaintPaintData *data = userdata;
4368 
4369  const DynamicPaintSurface *surface = data->surface;
4370  const PaintSurfaceData *sData = surface->data;
4371  const PaintBakeData *bData = sData->bData;
4372  VolumeGrid *grid = bData->grid;
4373 
4374  const DynamicPaintBrushSettings *brush = data->brush;
4375 
4376  const ParticleSystem *psys = data->psys;
4377 
4378  const float timescale = data->timescale;
4379  const int c_index = data->c_index;
4380 
4381  KDTree_3d *tree = data->treeData;
4382 
4383  const float solidradius = data->solidradius;
4384  const float smooth = brush->particle_smooth * surface->radius_scale;
4385  const float range = solidradius + smooth;
4386  const float particle_timestep = 0.04f * psys->part->timetweak;
4387 
4388  const int index = grid->t_index[grid->s_pos[c_index] + id];
4389  float disp_intersect = 0.0f;
4390  float radius = 0.0f;
4391  float strength = 0.0f;
4392  int part_index = -1;
4393 
4394  /*
4395  * With predefined radius, there is no variation between particles.
4396  * It's enough to just find the nearest one.
4397  */
4398  {
4399  KDTreeNearest_3d nearest;
4400  float smooth_range, part_solidradius;
4401 
4402  /* Find nearest particle and get distance to it */
4403  BLI_kdtree_3d_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
4404  /* if outside maximum range, no other particle can influence either */
4405  if (nearest.dist > range) {
4406  return;
4407  }
4408 
4409  if (brush->flags & MOD_DPAINT_PART_RAD) {
4410  /* use particles individual size */
4411  ParticleData *pa = psys->particles + nearest.index;
4412  part_solidradius = pa->size;
4413  }
4414  else {
4415  part_solidradius = solidradius;
4416  }
4417  radius = part_solidradius + smooth;
4418  if (nearest.dist < radius) {
4419  /* distances inside solid radius has maximum influence -> dist = 0 */
4420  smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
4421  /* do smoothness if enabled */
4422  if (smooth) {
4423  smooth_range /= smooth;
4424  }
4425 
4426  strength = 1.0f - smooth_range;
4427  disp_intersect = radius - nearest.dist;
4428  part_index = nearest.index;
4429  }
4430  }
4431  /* If using random per particle radius and closest particle didn't give max influence */
4432  if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
4433  /*
4434  * If we use per particle radius, we have to sample all particles
4435  * within max radius range
4436  */
4437  KDTreeNearest_3d *nearest;
4438 
4439  float smooth_range = smooth * (1.0f - strength), dist;
4440  /* calculate max range that can have particles with higher influence than the nearest one */
4441  const float max_range = smooth - strength * smooth + solidradius;
4442  /* Make gcc happy! */
4443  dist = max_range;
4444 
4445  const int particles = BLI_kdtree_3d_range_search(
4446  tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
4447 
4448  /* Find particle that produces highest influence */
4449  for (int n = 0; n < particles; n++) {
4450  ParticleData *pa = &psys->particles[nearest[n].index];
4451 
4452  /* skip if out of range */
4453  if (nearest[n].dist > (pa->size + smooth)) {
4454  continue;
4455  }
4456 
4457  /* update hit data */
4458  const float s_range = nearest[n].dist - pa->size;
4459  /* skip if higher influence is already found */
4460  if (smooth_range < s_range) {
4461  continue;
4462  }
4463 
4464  /* update hit data */
4465  smooth_range = s_range;
4466  dist = nearest[n].dist;
4467  part_index = nearest[n].index;
4468 
4469  /* If inside solid range and no disp depth required, no need to seek further */
4470  if ((s_range < 0.0f) &&
4472  break;
4473  }
4474  }
4475 
4476  if (nearest) {
4477  MEM_freeN(nearest);
4478  }
4479 
4480  /* now calculate influence for this particle */
4481  const float rad = radius + smooth;
4482  if ((rad - dist) > disp_intersect) {
4483  disp_intersect = radius - dist;
4484  radius = rad;
4485  }
4486 
4487  /* do smoothness if enabled */
4488  CLAMP_MIN(smooth_range, 0.0f);
4489  if (smooth) {
4490  smooth_range /= smooth;
4491  }
4492 
4493  const float str = 1.0f - smooth_range;
4494  /* if influence is greater, use this one */
4495  if (str > strength) {
4496  strength = str;
4497  }
4498  }
4499 
4500  if (strength > 0.001f) {
4501  float paintColor[4] = {0.0f};
4502  float depth = 0.0f;
4503  float velocity_val = 0.0f;
4504 
4505  /* apply velocity */
4506  if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
4507  float velocity[3];
4508  ParticleData *pa = psys->particles + part_index;
4509  mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
4510 
4511  /* subtract canvas point velocity */
4512  if (bData->velocity) {
4513  sub_v3_v3(velocity, bData->velocity[index].v);
4514  }
4515  velocity_val = normalize_v3(velocity);
4516 
4517  /* store brush velocity for smudge */
4518  if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
4519  (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)) {
4520  copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
4521  bData->brush_velocity[index * 4 + 3] = velocity_val;
4522  }
4523  }
4524 
4525  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4526  copy_v3_v3(paintColor, &brush->r);
4527  }
4529  /* get displace depth */
4530  disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
4531  depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
4532  }
4533 
4535  surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
4536  }
4537 }
4538 
4540  ParticleSystem *psys,
4542  float timescale)
4543 {
4544  ParticleSettings *part = psys->part;
4545  PaintSurfaceData *sData = surface->data;
4546  PaintBakeData *bData = sData->bData;
4547  VolumeGrid *grid = bData->grid;
4548 
4549  KDTree_3d *tree;
4550  int particlesAdded = 0;
4551  int invalidParticles = 0;
4552  int p = 0;
4553 
4554  const float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ?
4555  part->size :
4556  brush->particle_radius);
4557  const float smooth = brush->particle_smooth * surface->radius_scale;
4558 
4559  const float range = solidradius + smooth;
4560 
4561  Bounds3D part_bb = {{0}};
4562 
4563  if (psys->totpart < 1) {
4564  return true;
4565  }
4566 
4567  /*
4568  * Build a KD-tree to optimize distance search
4569  */
4570  tree = BLI_kdtree_3d_new(psys->totpart);
4571 
4572  /* loop through particles and insert valid ones to the tree */
4573  p = 0;
4574  for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
4575  /* Proceed only if particle is active */
4576  if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
4577  (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) || (pa->flag & PARS_UNEXIST)) {
4578  continue;
4579  }
4580 
4581  /* for debug purposes check if any NAN particle proceeds
4582  * For some reason they get past activity check, this should rule most of them out */
4583  if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
4584  invalidParticles++;
4585  continue;
4586  }
4587 
4588  /* make sure particle is close enough to canvas */
4589  if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range)) {
4590  continue;
4591  }
4592 
4593  BLI_kdtree_3d_insert(tree, p, pa->state.co);
4594 
4595  /* calc particle system bounds */
4596  boundInsert(&part_bb, pa->state.co);
4597 
4598  particlesAdded++;
4599  }
4600  if (invalidParticles) {
4601  CLOG_WARN(&LOG, "Invalid particle(s) found!");
4602  }
4603 
4604  /* If no suitable particles were found, exit */
4605  if (particlesAdded < 1) {
4606  BLI_kdtree_3d_free(tree);
4607  return true;
4608  }
4609 
4610  /* only continue if particle bb is close enough to canvas bb */
4611  if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
4612  int c_index;
4613  int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
4614 
4615  /* balance tree */
4616  BLI_kdtree_3d_balance(tree);
4617 
4618  /* loop through space partitioning grid */
4619  for (c_index = 0; c_index < total_cells; c_index++) {
4620  /* check cell bounding box */
4621  if (!grid->s_num[c_index] || !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range)) {
4622  continue;
4623  }
4624 
4625  /* loop through cell points */
4627  .surface = surface,
4628  .brush = brush,
4629  .psys = psys,
4630  .solidradius = solidradius,
4631  .timescale = timescale,
4632  .c_index = c_index,
4633  .treeData = tree,
4634  };
4635  TaskParallelSettings settings;
4637  settings.use_threading = (grid->s_num[c_index] > 250);
4639  grid->s_num[c_index],
4640  &data,
4642  &settings);
4643  }
4644  }
4645  BLI_kdtree_3d_free(tree);
4646 
4647  return true;
4648 }
4649 
4650 /* paint a single point of defined proximity radius to the surface */
4651 static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata,
4652  const int index,
4653  const TaskParallelTLS *__restrict UNUSED(tls))
4654 {
4655  const DynamicPaintPaintData *data = userdata;
4656 
4657  const DynamicPaintSurface *surface = data->surface;
4658  const PaintSurfaceData *sData = surface->data;
4659  const PaintBakeData *bData = sData->bData;
4660 
4661  const DynamicPaintBrushSettings *brush = data->brush;
4662 
4663  const float timescale = data->timescale;
4664 
4665  const float brush_radius = data->brush_radius;
4666  const Vec3f *brushVelocity = data->brushVelocity;
4667 
4668  float *pointCoord = data->pointCoord;
4669 
4670  const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
4671  float colorband[4] = {0.0f};
4672  float strength;
4673 
4674  if (distance > brush_radius) {
4675  return;
4676  }
4677 
4678  /* Smooth range or color ramp */
4680  strength = 1.0f - distance / brush_radius;
4681  CLAMP(strength, 0.0f, 1.0f);
4682  }
4683  else {
4684  strength = 1.0f;
4685  }
4686 
4687  if (strength >= 0.001f) {
4688  float paintColor[3] = {0.0f};
4689  float depth = 0.0f;
4690  float velocity_val = 0.0f;
4691 
4692  /* color ramp */
4693  if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
4694  BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband)) {
4695  strength = colorband[3];
4696  }
4697 
4698  if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
4699  float velocity[3];
4700 
4701  /* subtract canvas point velocity */
4702  if (bData->velocity) {
4703  sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
4704  }
4705  else {
4706  copy_v3_v3(velocity, brushVelocity->v);
4707  }
4708  velocity_val = len_v3(velocity);
4709 
4710  /* store brush velocity for smudge */
4711  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
4712  bData->brush_velocity) {
4713  mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
4714  bData->brush_velocity[index * 4 + 3] = velocity_val;
4715  }
4716  }
4717 
4718  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
4719  if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
4720  !(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
4721  paintColor[0] = colorband[0];
4722  paintColor[1] = colorband[1];
4723  paintColor[2] = colorband[2];
4724  }
4725  else {
4726  paintColor[0] = brush->r;
4727  paintColor[1] = brush->g;
4728  paintColor[2] = brush->b;
4729  }
4730  }
4732  /* get displace depth */
4733  const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) *
4734  brush_radius;
4735  depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
4736  }
4738  surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
4739  }
4740 }
4741 
4745  /* Cannot be const, because it is assigned to non-const variable.
4746  * NOLINTNEXTLINE: readability-non-const-parameter. */
4747  float *pointCoord,
4749  Object *brushOb,
4750  Scene *scene,
4751  float timescale)
4752 {
4753  PaintSurfaceData *sData = surface->data;
4754  float brush_radius = brush->paint_distance * surface->radius_scale;
4755  Vec3f brushVel;
4756 
4757  if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
4758  dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
4759  }
4760 
4761  const Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
4762  const MVert *mvert = brush_mesh->mvert;
4763 
4764  /*
4765  * Loop through every surface point
4766  */
4768  .surface = surface,
4769  .brush = brush,
4770  .brushOb = brushOb,
4771  .scene = scene,
4772  .timescale = timescale,
4773  .mvert = mvert,
4774  .brush_radius = brush_radius,
4775  .brushVelocity = &brushVel,
4776  .pointCoord = pointCoord,
4777  };
4778  TaskParallelSettings settings;
4780  settings.use_threading = (sData->total_points > 1000);
4782  0, sData->total_points, &data, dynamic_paint_paint_single_point_cb_ex, &settings);
4783 
4784  return true;
4785 }
4786 
4787 /***************************** Dynamic Paint Step / Baking ******************************/
4788 
4789 /*
4790  * Calculate current frame distances and directions for adjacency data
4791  */
4792 
4793 static void dynamic_paint_prepare_adjacency_cb(void *__restrict userdata,
4794  const int index,
4795  const TaskParallelTLS *__restrict UNUSED(tls))
4796 {
4797  PaintSurfaceData *sData = userdata;
4798  PaintBakeData *bData = sData->bData;
4799  BakeAdjPoint *bNeighs = bData->bNeighs;
4800  PaintAdjData *adj_data = sData->adj_data;
4801  Vec3f *realCoord = bData->realCoord;
4802 
4803  const int num_neighs = adj_data->n_num[index];
4804 
4805  for (int i = 0; i < num_neighs; i++) {
4806  const int n_index = adj_data->n_index[index] + i;
4807  const int t_index = adj_data->n_target[n_index];
4808 
4809  /* dir vec */
4810  sub_v3_v3v3(bNeighs[n_index].dir,
4811  realCoord[bData->s_pos[t_index]].v,
4812  realCoord[bData->s_pos[index]].v);
4813  /* dist */
4814  bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
4815  }
4816 }
4817 
4819 {
4820  PaintSurfaceData *sData = surface->data;
4821  PaintBakeData *bData = sData->bData;
4822  BakeAdjPoint *bNeighs;
4823  PaintAdjData *adj_data = sData->adj_data;
4824 
4825  int index;
4826 
4827  if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data) {
4828  return;
4829  }
4830 
4831  if (bData->bNeighs) {
4832  MEM_freeN(bData->bNeighs);
4833  }
4834  bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs),
4835  "PaintEffectBake");
4836  if (!bNeighs) {
4837  return;
4838  }
4839 
4840  TaskParallelSettings settings;
4842  settings.use_threading = (sData->total_points > 1000);
4844  0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
4845 
4846  /* calculate average values (single thread).
4847  * NOTE: tried to put this in threaded callback (using _reduce feature),
4848  * but gave ~30% slower result! */
4849  bData->average_dist = 0.0;
4850  for (index = 0; index < sData->total_points; index++) {
4851  int numOfNeighs = adj_data->n_num[index];
4852 
4853  for (int i = 0; i < numOfNeighs; i++) {
4854  bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
4855  }
4856  }
4857  bData->average_dist /= adj_data->total_targets;
4858 }
4859 
4860 /* Find two adjacency points (closest_id) and influence (closest_d)
4861  * to move paint towards when affected by a force. */
4863  const int index,
4864  const float force[3],
4865  float closest_d[2],
4866  int closest_id[2])
4867 {
4868  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
4869  const int numOfNeighs = sData->adj_data->n_num[index];
4870 
4871  closest_id[0] = closest_id[1] = -1;
4872  closest_d[0] = closest_d[1] = -1.0f;
4873 
4874  /* find closest neigh */
4875  for (int i = 0; i < numOfNeighs; i++) {
4876  const int n_index = sData->adj_data->n_index[index] + i;
4877  const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
4878 
4879  if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
4880  closest_d[0] = dir_dot;
4881  closest_id[0] = n_index;
4882  }
4883  }
4884 
4885  if (closest_d[0] < 0.0f) {
4886  return;
4887  }
4888 
4889  /* find second closest neigh */
4890  for (int i = 0; i < numOfNeighs; i++) {
4891  const int n_index = sData->adj_data->n_index[index] + i;
4892 
4893  if (n_index == closest_id[0]) {
4894  continue;
4895  }
4896 
4897  const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
4898  const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
4899 
4900  /* only accept neighbor at "other side" of the first one in relation to force dir
4901  * so make sure angle between this and closest neigh is greater than first angle. */
4902  if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
4903  closest_d[1] = dir_dot;
4904  closest_id[1] = n_index;
4905  }
4906  }
4907 
4908  /* if two valid neighs found, calculate how force effect is divided evenly between them
4909  * (so that d[0] + d[1] = 1.0) */
4910  if (closest_id[1] != -1) {
4911  float force_proj[3];
4912  float tangent[3];
4913  const float neigh_diff = acosf(
4914  dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
4915  float force_intersect;
4916  float temp;
4917 
4918  /* project force vector on the plane determined by these two neighbor points
4919  * and calculate relative force angle from it. */
4920  cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
4921  normalize_v3(tangent);
4922  force_intersect = dot_v3v3(force, tangent);
4923  madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
4924  normalize_v3(force_proj);
4925 
4926  /* get drip factor based on force dir in relation to angle between those neighbors */
4927  temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
4928  CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
4929  closest_d[1] = acosf(temp) / neigh_diff;
4930  closest_d[0] = 1.0f - closest_d[1];
4931 
4932  /* and multiply depending on how deeply force intersects surface */
4933  temp = fabsf(force_intersect);
4934  CLAMP(temp, 0.0f, 1.0f);
4935  mul_v2_fl(closest_d, acosf(temp) / (float)M_PI_2);
4936  }
4937  else {
4938  /* if only single neighbor, still linearize force intersection effect */
4939  closest_d[0] = 1.0f - acosf(closest_d[0]) / (float)M_PI_2;
4940  }
4941 }
4942 
4945  float timescale)
4946 {
4947  PaintSurfaceData *sData = surface->data;
4948  PaintBakeData *bData = sData->bData;
4949  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
4950  float max_velocity = 0.0f;
4951 
4952  if (!sData->adj_data) {
4953  return;
4954  }
4955 
4956  /* find max velocity */
4957  for (int index = 0; index < sData->total_points; index++) {
4958  float vel = bData->brush_velocity[index * 4 + 3];
4959  CLAMP_MIN(max_velocity, vel);
4960  }
4961 
4962  int steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
4963  CLAMP(steps, 0, 12);
4964  float eff_scale = brush->smudge_strength / (float)steps * timescale;
4965 
4966  for (int step = 0; step < steps; step++) {
4967  for (int index = 0; index < sData->total_points; index++) {
4968 
4969  if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
4970  continue;
4971  }
4972 
4973  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
4974  float smudge_str = bData->brush_velocity[index * 4 + 3];
4975 
4976  /* force targets */
4977  int closest_id[2];
4978  float closest_d[2];
4979 
4980  if (!smudge_str) {
4981  continue;
4982  }
4983 
4984  /* get force affect points */
4986  sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
4987 
4988  /* Apply movement towards those two points */
4989  for (int i = 0; i < 2; i++) {
4990  int n_index = closest_id[i];
4991  if (n_index != -1 && closest_d[i] > 0.0f) {
4992  float dir_dot = closest_d[i], dir_factor;
4993  float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
4994  PaintPoint *ePoint = &(
4995  (PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
4996 
4997  /* just skip if angle is too extreme */
4998  if (dir_dot <= 0.0f) {
4999  continue;
5000  }
5001 
5002  dir_factor = dir_dot * speed_scale;
5003  CLAMP_MAX(dir_factor, brush->smudge_strength);
5004 
5005  /* mix new color and alpha */
5006  mixColors(ePoint->color, ePoint->color[3], pPoint->color, pPoint->color[3], dir_factor);
5007  ePoint->color[3] = ePoint->color[3] * (1.0f - dir_factor) +
5008  pPoint->color[3] * dir_factor;
5009 
5010  /* smudge "wet layer" */
5011  mixColors(ePoint->e_color,
5012  ePoint->e_color[3],
5013  pPoint->e_color,
5014  pPoint->e_color[3],
5015  dir_factor);
5016  ePoint->e_color[3] = ePoint->e_color[3] * (1.0f - dir_factor) +
5017  pPoint->e_color[3] * dir_factor;
5018  pPoint->wetness *= (1.0f - dir_factor);
5019  }
5020  }
5021  }
5022  }
5023 }
5024 
5025 typedef struct DynamicPaintEffectData {
5028 
5029  float *force;
5031  const void *prevPoint;
5032  const float eff_scale;
5033 
5035 
5036  const float wave_speed;
5037  const float wave_scale;
5038  const float wave_max_slope;
5039 
5040  const float dt;
5041  const float min_dist;
5042  const float damp_factor;
5043  const bool reset_wave;
5045 
5046 /*
5047  * Prepare data required by effects for current frame.
5048  * Returns number of steps required
5049  */
5050 static void dynamic_paint_prepare_effect_cb(void *__restrict userdata,
5051  const int index,
5052  const TaskParallelTLS *__restrict UNUSED(tls))
5053 {
5054  const DynamicPaintEffectData *data = userdata;
5055 
5056  const DynamicPaintSurface *surface = data->surface;
5057  const PaintSurfaceData *sData = surface->data;
5058  const PaintBakeData *bData = sData->bData;
5059  Vec3f *realCoord = bData->realCoord;
5060 
5061  Scene *scene = data->scene;
5062 
5063  float *force = data->force;
5064  ListBase *effectors = data->effectors;
5065 
5066  float forc[3] = {0};
5067  float vel[3] = {0};
5068 
5069  /* apply force fields */
5070  if (effectors) {
5071  EffectedPoint epoint;
5072  pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
5073  epoint.vel_to_sec = 1.0f;
5074  BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL, NULL);
5075  }
5076 
5077  /* if global gravity is enabled, add it too */
5079  /* also divide by 10 to about match default grav
5080  * with default force strength (1.0). */
5081  madd_v3_v3fl(forc,
5083  surface->effector_weights->global_gravity * surface->effector_weights->weight[0] /
5084  10.0f);
5085  }
5086 
5087  /* add surface point velocity and acceleration if enabled */
5088  if (bData->velocity) {
5089  if (surface->drip_vel) {
5090  madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
5091  }
5092 
5093  /* acceleration */
5094  if (bData->prev_velocity && surface->drip_acc) {
5095  float acc[3];
5096  copy_v3_v3(acc, bData->velocity[index].v);
5097  sub_v3_v3(acc, bData->prev_velocity[index].v);
5098  madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
5099  }
5100  }
5101 
5102  /* force strength, and normalize force vec */
5103  force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
5104 }
5105 
5108  Scene *scene,
5109  Object *ob,
5110  float **force,
5111  float timescale)
5112 {
5113  double average_force = 0.0f;
5114  float shrink_speed = 0.0f, spread_speed = 0.0f;
5115  float fastest_effect, avg_dist;
5116  int steps;
5117  PaintSurfaceData *sData = surface->data;
5118  PaintBakeData *bData = sData->bData;
5119 
5120  /* Init force data if required */
5121  if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
5122  ListBase *effectors = BKE_effectors_create(
5123  depsgraph, ob, NULL, surface->effector_weights, false);
5124 
5125  /* allocate memory for force data (dir vector + strength) */
5126  *force = MEM_mallocN(sizeof(float[4]) * sData->total_points, "PaintEffectForces");
5127 
5128  if (*force) {
5130  .surface = surface,
5131  .scene = scene,
5132  .force = *force,
5133  .effectors = effectors,
5134  };
5135  TaskParallelSettings settings;
5137  settings.use_threading = (sData->total_points > 1000);
5139  0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, &settings);
5140 
5141  /* calculate average values (single thread) */
5142  for (int index = 0; index < sData->total_points; index++) {
5143  average_force += (double)(*force)[index * 4 + 3];
5144  }
5145  average_force /= sData->total_points;
5146  }
5147  BKE_effectors_free(effectors);
5148  }
5149 
5150  /* Get number of required steps using average point distance
5151  * so that just a few ultra close pixels won't increase substeps to max. */
5152 
5153  /* adjust number of required substep by fastest active effect */
5154  if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
5155  spread_speed = surface->spread_speed;
5156  }
5157  if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
5158  shrink_speed = surface->shrink_speed;
5159  }
5160 
5161  fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
5162  avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
5163 
5164  steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
5165  CLAMP(steps, 1, 20);
5166 
5167  return steps;
5168 }
5169 
5173 static void dynamic_paint_effect_spread_cb(void *__restrict userdata,
5174  const int index,
5175  const TaskParallelTLS *__restrict UNUSED(tls))
5176 {
5177  const DynamicPaintEffectData *data = userdata;
5178 
5179  const DynamicPaintSurface *surface = data->surface;
5180  const PaintSurfaceData *sData = surface->data;
5181 
5182  if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5183  return;
5184  }
5185 
5186  const int numOfNeighs = sData->adj_data->n_num[index];
5187  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5188  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5189  const PaintPoint *prevPoint = data->prevPoint;
5190  const float eff_scale = data->eff_scale;
5191 
5192  const int *n_index = sData->adj_data->n_index;
5193  const int *n_target = sData->adj_data->n_target;
5194 
5195  /* Loop through neighboring points */
5196  for (int i = 0; i < numOfNeighs; i++) {
5197  const int n_idx = n_index[index] + i;
5198  float w_factor;
5199  const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
5200  const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
5201  eff_scale / bNeighs[n_idx].dist;
5202  const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f *
5203  surface->color_spread_speed;
5204 
5205  /* do color mixing */
5206  if (color_mix) {
5207  mixColors(pPoint->e_color,
5208  pPoint->e_color[3],
5209  pPoint_prev->e_color,
5210  pPoint_prev->e_color[3],
5211  color_mix);
5212  }
5213 
5214  /* Only continue if surrounding point has higher wetness */
5215  if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS) {
5216  continue;
5217  }
5218 
5219  w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
5220  CLAMP(w_factor, 0.0f, 1.0f);
5221 
5222  /* mix new wetness and color */
5223  pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
5224  pPoint->e_color[3] = mixColors(pPoint->e_color,
5225  pPoint->e_color[3],
5226  pPoint_prev->e_color,
5227  pPoint_prev->e_color[3],
5228  w_factor);
5229  }
5230 }
5231 
5232 static void dynamic_paint_effect_shrink_cb(void *__restrict userdata,
5233  const int index,
5234  const TaskParallelTLS *__restrict UNUSED(tls))
5235 {
5236  const DynamicPaintEffectData *data = userdata;
5237 
5238  const DynamicPaintSurface *surface = data->surface;
5239  const PaintSurfaceData *sData = surface->data;
5240 
5241  if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5242  return;
5243  }
5244 
5245  const int numOfNeighs = sData->adj_data->n_num[index];
5246  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5247  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5248  const PaintPoint *prevPoint = data->prevPoint;
5249  const float eff_scale = data->eff_scale;
5250 
5251  const int *n_index = sData->adj_data->n_index;
5252  const int *n_target = sData->adj_data->n_target;
5253 
5254  /* Loop through neighboring points */
5255  for (int i = 0; i < numOfNeighs; i++) {
5256  const int n_idx = n_index[index] + i;
5257  const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
5258  eff_scale / bNeighs[n_idx].dist;
5259  const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
5260  float a_factor, ea_factor, w_factor;
5261 
5262  /* Check if neighboring point has lower alpha,
5263  * if so, decrease this point's alpha as well. */
5264  if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f) {
5265  continue;
5266  }
5267 
5268  /* decrease factor for dry paint alpha */
5269  a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs *
5270  (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale,
5271  0.0f);
5272  /* decrease factor for wet paint alpha */
5273  ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 *
5274  (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale,
5275  0.0f);
5276  /* decrease factor for paint wetness */
5277  w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 *
5278  (pPoint->wetness - pPoint_prev->wetness) * speed_scale,
5279  0.0f);
5280 
5281  pPoint->color[3] -= a_factor;
5282  CLAMP_MIN(pPoint->color[3], 0.0f);
5283  pPoint->e_color[3] -= ea_factor;
5284  CLAMP_MIN(pPoint->e_color[3], 0.0f);
5285  pPoint->wetness -= w_factor;
5286  CLAMP_MIN(pPoint->wetness, 0.0f);
5287  }
5288 }
5289 
5290 static void dynamic_paint_effect_drip_cb(void *__restrict userdata,
5291  const int index,
5292  const TaskParallelTLS *__restrict UNUSED(tls))
5293 {
5294  const DynamicPaintEffectData *data = userdata;
5295 
5296  const DynamicPaintSurface *surface = data->surface;
5297  const PaintSurfaceData *sData = surface->data;
5298 
5299  if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) {
5300  return;
5301  }
5302 
5303  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5304  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5305  const PaintPoint *prevPoint = data->prevPoint;
5306  const PaintPoint *pPoint_prev = &prevPoint[index];
5307  const float *force = data->force;
5308  const float eff_scale = data->eff_scale;
5309 
5310  const int *n_target = sData->adj_data->n_target;
5311 
5312  uint8_t *point_locks = data->point_locks;
5313 
5314  int closest_id[2];
5315  float closest_d[2];
5316 
5317  /* adjust drip speed depending on wetness */
5318  float w_factor = pPoint_prev->wetness - 0.025f;
5319  if (w_factor <= 0) {
5320  return;
5321  }
5322  CLAMP(w_factor, 0.0f, 1.0f);
5323 
5324  float ppoint_wetness_diff = 0.0f;
5325 
5326  /* get force affect points */
5327  surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
5328 
5329  /* Apply movement towards those two points */
5330  for (int i = 0; i < 2; i++) {
5331  const int n_idx = closest_id[i];
5332  if (n_idx != -1 && closest_d[i] > 0.0f) {
5333  const float dir_dot = closest_d[i];
5334 
5335  /* just skip if angle is too extreme */
5336  if (dir_dot <= 0.0f) {
5337  continue;
5338  }
5339 
5340  float dir_factor, a_factor;
5341  const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
5342 
5343  const unsigned int n_trgt = (unsigned int)n_target[n_idx];
5344 
5345  /* Sort of spinlock, but only for given ePoint.
5346  * Since the odds a same ePoint is modified at the same time by several threads is very low,
5347  * this is much more efficient than a global spin lock. */
5348  const unsigned int epointlock_idx = n_trgt / 8;
5349  const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
5350  while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) &
5351  epointlock_bitmask) {
5352  /* pass */
5353  }
5354 
5355  PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
5356  const float e_wet = ePoint->wetness;
5357 
5358  dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
5359 
5360  /* mix new wetness */
5361  ePoint->wetness += dir_factor;
5362  CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
5363 
5364  /* mix new color */
5365  a_factor = dir_factor / pPoint_prev->wetness;
5366  CLAMP(a_factor, 0.0f, 1.0f);
5367  mixColors(ePoint->e_color,
5368  ePoint->e_color[3],
5369  pPoint_prev->e_color,
5370  pPoint_prev->e_color[3],
5371  a_factor);
5372  /* dripping is supposed to preserve alpha level */
5373  if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
5374  ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
5375  CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
5376  }
5377 
5378  /* Decrease paint wetness on current point (just store diff here,
5379  * that way we can only lock current point once at the end to apply it). */
5380  ppoint_wetness_diff += (ePoint->wetness - e_wet);
5381 
5382 #ifndef NDEBUG
5383  {
5384  uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx],
5385  ~epointlock_bitmask);
5386  BLI_assert(ret & epointlock_bitmask);
5387  }
5388 #else
5389  atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
5390 #endif
5391  }
5392  }
5393 
5394  {
5395  const unsigned int ppointlock_idx = index / 8;
5396  const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
5397  while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) &
5398  ppointlock_bitmask) {
5399  /* pass */
5400  }
5401 
5402  pPoint->wetness -= ppoint_wetness_diff;
5403  CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
5404 
5405 #ifndef NDEBUG
5406  {
5407  uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
5408  BLI_assert(ret & ppointlock_bitmask);
5409  }
5410 #else
5411  atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
5412 #endif
5413  }
5414 }
5415 
5418  /* Cannot be const, because it is assigned to non-const variable.
5419  * NOLINTNEXTLINE: readability-non-const-parameter. */
5420  float *force,
5421  PaintPoint *prevPoint,
5422  float timescale,
5423  float steps)
5424 {
5425  PaintSurfaceData *sData = surface->data;
5426 
5427  const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
5428  timescale /= steps;
5429 
5430  if (!sData->adj_data) {
5431  return;
5432  }
5433 
5434  /*
5435  * Spread Effect
5436  */
5437  if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
5438  const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed *
5439  timescale;
5440 
5441  /* Copy current surface to the previous points array to read unmodified values */
5442  memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
5443 
5445  .surface = surface,
5446  .prevPoint = prevPoint,
5447  .eff_scale = eff_scale,
5448  };
5449  TaskParallelSettings settings;
5451  settings.use_threading = (sData->total_points > 1000);
5453  0, sData->total_points, &data, dynamic_paint_effect_spread_cb, &settings);
5454  }
5455 
5456  /*
5457  * Shrink Effect
5458  */
5459  if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
5460  const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed *
5461  timescale;
5462 
5463  /* Copy current surface to the previous points array to read unmodified values */
5464  memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
5465 
5467  .surface = surface,
5468  .prevPoint = prevPoint,
5469  .eff_scale = eff_scale,
5470  };
5471  TaskParallelSettings settings;
5473  settings.use_threading = (sData->total_points > 1000);
5475  0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, &settings);
5476  }
5477 
5478  /*
5479  * Drip Effect
5480  */
5481  if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
5482  const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
5483 
5484  /* Same as #BLI_bitmask, but handled atomically as 'ePoint' locks. */
5485  const size_t point_locks_size = (sData->total_points / 8) + 1;
5486  uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
5487 
5488  /* Copy current surface to the previous points array to read unmodified values */
5489  memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
5490 
5492  .surface = surface,
5493  .prevPoint = prevPoint,
5494  .eff_scale = eff_scale,
5495  .force = force,
5496  .point_locks = point_locks,
5497  };
5498  TaskParallelSettings settings;
5500  settings.use_threading = (sData->total_points > 1000);
5502  0, sData->total_points, &data, dynamic_paint_effect_drip_cb, &settings);
5503 
5504  MEM_freeN(point_locks);
5505  }
5506 }
5507 
5508 static void dynamic_paint_border_cb(void *__restrict userdata,
5509  const int b_index,
5510  const TaskParallelTLS *__restrict UNUSED(tls))
5511 {
5512  const DynamicPaintEffectData *data = userdata;
5513 
5514  const DynamicPaintSurface *surface = data->surface;
5515  const PaintSurfaceData *sData = surface->data;
5516 
5517  const int index = sData->adj_data->border[b_index];
5518 
5519  const int numOfNeighs = sData->adj_data->n_num[index];
5520  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5521 
5522  const int *n_index = sData->adj_data->n_index;
5523  const int *n_target = sData->adj_data->n_target;
5524 
5525  /* Average neighboring points. Intermediaries use premultiplied alpha. */
5526  float mix_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
5527  float mix_e_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
5528  float mix_wetness = 0.0f;
5529 
5530  for (int i = 0; i < numOfNeighs; i++) {
5531  const int n_idx = n_index[index] + i;
5532  const int target = n_target[n_idx];
5533 
5534  PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
5535 
5536  BLI_assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
5537 
5538  madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
5539  mix_color[3] += pPoint2->color[3];
5540 
5541  madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
5542  mix_e_color[3] += pPoint2->e_color[3];
5543 
5544  mix_wetness += pPoint2->wetness;
5545  }
5546 
5547  const float divisor = 1.0f / numOfNeighs;
5548 
5549  if (mix_color[3]) {
5550  pPoint->color[3] = mix_color[3] * divisor;
5551  mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
5552  }
5553  else {
5554  pPoint->color[3] = 0.0f;
5555  }
5556 
5557  if (mix_e_color[3]) {
5558  pPoint->e_color[3] = mix_e_color[3] * divisor;
5559  mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
5560  }
5561  else {
5562  pPoint->e_color[3] = 0.0f;
5563  }
5564 
5565  pPoint->wetness = mix_wetness / numOfNeighs;
5566 }
5567 
5569 {
5570  PaintSurfaceData *sData = surface->data;
5571 
5572  if (!sData->adj_data || !sData->adj_data->border) {
5573  return;
5574  }
5575 
5576  /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
5578  .surface = surface,
5579  };
5580 
5581  TaskParallelSettings settings;
5583  settings.use_threading = (sData->adj_data->total_border > 1000);
5585  0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, &settings);
5586 }
5587 
5588 static void dynamic_paint_wave_step_cb(void *__restrict userdata,
5589  const int index,
5590  const TaskParallelTLS *__restrict UNUSED(tls))
5591 {
5592  const DynamicPaintEffectData *data = userdata;
5593 
5594  const DynamicPaintSurface *surface = data->surface;
5595  const PaintSurfaceData *sData = surface->data;
5596  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5597  const PaintWavePoint *prevPoint = data->prevPoint;
5598 
5599  const float wave_speed = data->wave_speed;
5600  const float wave_scale = data->wave_scale;
5601  const float wave_max_slope = data->wave_max_slope;
5602 
5603  const float dt = data->dt;
5604  const float min_dist = data->min_dist;
5605  const float damp_factor = data->damp_factor;
5606 
5607  PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
5608  const int numOfNeighs = sData->adj_data->n_num[index];
5609  float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
5610  int numOfN = 0, numOfRN = 0;
5611 
5612  if (wPoint->state > 0) {
5613  return;
5614  }
5615 
5616  const int *n_index = sData->adj_data->n_index;
5617  const int *n_target = sData->adj_data->n_target;
5618  const int *adj_flags = sData->adj_data->flags;
5619 
5620  /* calculate force from surrounding points */
5621  for (int i = 0; i < numOfNeighs; i++) {
5622  const int n_idx = n_index[index] + i;
5623  float dist = bNeighs[n_idx].dist * wave_scale;
5624  const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
5625 
5626  if (!dist || tPoint->state > 0) {
5627  continue;
5628  }
5629 
5630  CLAMP_MIN(dist, min_dist);
5631  avg_dist += dist;
5632  numOfN++;
5633 
5634  /* count average height for edge points for open borders */
5635  if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
5636  avg_n_height += tPoint->height;
5637  numOfRN++;
5638  }
5639 
5640  force += (tPoint->height - wPoint->height) / (dist * dist);
5641  avg_height += tPoint->height;
5642  }
5643  avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
5644 
5645  if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
5646  /* if open borders, apply a fake height to keep waves going on */
5647  avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
5648  wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
5649  (avg_dist + dt * wave_speed);
5650  }
5651  /* else do wave eq */
5652  else {
5653  /* add force towards zero height based on average dist */
5654  if (avg_dist) {
5655  force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
5656  }
5657 
5658  /* change point velocity */
5659  wPoint->velocity += force * dt * wave_speed * wave_speed;
5660  /* damping */
5661  wPoint->velocity *= damp_factor;
5662  /* and new height */
5663  wPoint->height += wPoint->velocity * dt;
5664 
5665  /* limit wave slope steepness */
5666  if (wave_max_slope && avg_dist) {
5667  const float max_offset = wave_max_slope * avg_dist;
5668  const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
5669  if (offset > max_offset) {
5670  wPoint->height += offset - max_offset;
5671  }
5672  else if (offset < -max_offset) {
5673  wPoint->height += offset + max_offset;
5674  }
5675  }
5676  }
5677 
5678  if (data->reset_wave) {
5679  /* if there wasn't any brush intersection, clear isect height */
5680  if (wPoint->state == DPAINT_WAVE_NONE) {
5681  wPoint->brush_isect = 0.0f;
5682  }
5683  wPoint->state = DPAINT_WAVE_NONE;
5684  }
5685 }
5686 
5688 {
5689  PaintSurfaceData *sData = surface->data;
5690  BakeAdjPoint *bNeighs = sData->bData->bNeighs;
5691  int index;
5692  int steps, ss;
5693  float dt, min_dist, damp_factor;
5694  const float wave_speed = surface->wave_speed;
5695  const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ?
5696  (0.5f / surface->wave_smoothness) :
5697  0.0f;
5698  double average_dist = 0.0f;
5699  const float canvas_size = getSurfaceDimension(sData);
5700  const float wave_scale = CANVAS_REL_SIZE / canvas_size;
5701 
5702  /* allocate memory */
5703  PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), __func__);
5704  if (!prevPoint) {
5705  return;
5706  }
5707 
5708  /* calculate average neigh distance (single thread) */
5709  for (index = 0; index < sData->total_points; index++) {
5710  int numOfNeighs = sData->adj_data->n_num[index];
5711 
5712  for (int i = 0; i < numOfNeighs; i++) {
5713  average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
5714  }
5715  }
5716  average_dist *= (double)wave_scale / sData->adj_data->total_targets;
5717 
5718  /* determine number of required steps */
5719  steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
5720  (average_dist / (double)wave_speed / 3));
5721  CLAMP(steps, 1, 20);
5722  timescale /= steps;
5723 
5724  /* apply simulation values for final timescale */
5725  dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
5726  min_dist = wave_speed * dt * 1.5f;
5727  damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
5728 
5729  for (ss = 0; ss < steps; ss++) {
5730  /* copy previous frame data */
5731  memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
5732 
5734  .surface = surface,
5735  .prevPoint = prevPoint,
5736  .wave_speed = wave_speed,
5737  .wave_scale = wave_scale,
5738  .wave_max_slope = wave_max_slope,
5739  .dt = dt,
5740  .min_dist = min_dist,
5741  .damp_factor = damp_factor,
5742  .reset_wave = (ss == steps - 1),
5743  };
5744  TaskParallelSettings settings;
5746  settings.use_threading = (sData->total_points > 1000);
5748  }
5749 
5750  MEM_freeN(prevPoint);
5751 }
5752 
5753 /* Do dissolve and fading effects */
5755 {
5756  return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
5759  (surface->flags & MOD_DPAINT_DISSOLVE)));
5760 }
5761 
5764  const float timescale;
5766 
5767 static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata,
5768  const int index,
5769  const TaskParallelTLS *__restrict UNUSED(tls))
5770 {
5771  const DynamicPaintDissolveDryData *data = userdata;
5772 
5773  const DynamicPaintSurface *surface = data->surface;
5774  const PaintSurfaceData *sData = surface->data;
5775  const float timescale = data->timescale;
5776 
5777  /* Do drying dissolve effects */
5778  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
5779  PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
5780  /* drying */
5781  if (surface->flags & MOD_DPAINT_USE_DRYING) {
5782  if (pPoint->wetness >= MIN_WETNESS) {
5783  float f_color[4];
5784  float p_wetness = pPoint->wetness;
5785 
5786  value_dissolve(&pPoint->wetness,
5787  surface->dry_speed,
5788  timescale,
5789  (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
5790  CLAMP_MIN(pPoint->wetness, 0.0f);
5791 
5792  if (pPoint->wetness < surface->color_dry_threshold) {
5793  float dry_ratio = pPoint->wetness / p_wetness;
5794 
5795  /*
5796  * Slowly "shift" paint from wet layer to dry layer as it drys:
5797  */
5798  /* make sure alpha values are within proper range */
5799  CLAMP(pPoint->color[3], 0.0f, 1.0f);
5800  CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
5801 
5802  /* get current final blended color of these layers */
5803  blendColors(
5804  pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
5805  /* reduce wet layer alpha by dry factor */
5806  pPoint->e_color[3] *= dry_ratio;
5807 
5808  /* Now calculate new alpha for dry layer that keeps final blended color unchanged. */
5809  pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
5810  /* For each rgb component, calculate a new dry layer color that keeps the final blend
5811  * color with these new alpha values. (wet layer color doesn't change). */
5812  if (pPoint->color[3]) {
5813  for (int i = 0; i < 3; i++) {
5814  pPoint->color[i] = (f_color[i] * f_color[3] -
5815  pPoint->e_color[i] * pPoint->e_color[3]) /
5816  (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
5817  }
5818  }
5819  }
5820 
5821  pPoint->state = DPAINT_PAINT_WET;
5822  }
5823  /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
5824  else if (pPoint->state > 0) {
5825  float f_color[4];
5826  blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
5827  copy_v4_v4(pPoint->color, f_color);
5828  /* clear wet layer */
5829  pPoint->wetness = 0.0f;
5830  pPoint->e_color[3] = 0.0f;
5831  pPoint->state = DPAINT_PAINT_DRY;
5832  }
5833  }
5834 
5835  if (surface->flags & MOD_DPAINT_DISSOLVE) {
5836  value_dissolve(&pPoint->color[3],
5837  surface->diss_speed,
5838  timescale,
5839  (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
5840  CLAMP_MIN(pPoint->color[3], 0.0f);
5841 
5842  value_dissolve(&pPoint->e_color[3],
5843  surface->diss_speed,
5844  timescale,
5845  (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
5846  CLAMP_MIN(pPoint->e_color[3], 0.0f);
5847  }
5848  }
5849  /* dissolve for float types */
5850  else if (surface->flags & MOD_DPAINT_DISSOLVE &&
5852  float *point = &((float *)sData->type_data)[index];
5853  /* log or linear */
5855  point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
5856  CLAMP_MIN(*point, 0.0f);
5857  }
5858 }
5859 
5861 {
5862  PaintSurfaceData *sData = surface->data;
5863  PaintBakeData *bData = sData->bData;
5865  MVert *mvert = mesh->mvert;
5866 
5867  int numOfVerts = mesh->totvert;
5868 
5869  if (!bData->prev_verts) {
5870  return true;
5871  }
5872 
5873  /* matrix comparison */
5874  if (!equals_m4m4(bData->prev_obmat, ob->obmat)) {
5875  return true;
5876  }
5877 
5878  /* vertices */
5879  for (int i = 0; i < numOfVerts; i++) {
5880  if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
5881  return true;
5882  }
5883  }
5884 
5885  return false;
5886 }
5887 
5888 /* Prepare for surface step by creating PaintBakeNormal data */
5892 
5893  const MVert *mvert;
5894  const float (*vert_normals)[3];
5896 
5897  const bool do_velocity_data;
5898  const bool new_bdata;
5900 
5901 static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
5902  const int index,
5903  const TaskParallelTLS *__restrict UNUSED(tls))
5904 {
5905  const DynamicPaintGenerateBakeData *data = userdata;
5906 
5907  const DynamicPaintSurface *surface = data->surface;
5908  const PaintSurfaceData *sData = surface->data;
5909  const PaintAdjData *adj_data = sData->adj_data;
5910  const PaintBakeData *bData = sData->bData;
5911 
5912  Object *ob = data->ob;
5913 
5914  const Vec3f *canvas_verts = data->canvas_verts;
5915 
5916  const bool do_velocity_data = data->do_velocity_data;
5917  const bool new_bdata = data->new_bdata;
5918 
5919  float prev_point[3] = {0.0f, 0.0f, 0.0f};
5920  float temp_nor[3];
5921 
5922  if (do_velocity_data && !new_bdata) {
5923  copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
5924  }
5925 
5926  /*
5927  * Calculate current 3D-position and normal of each surface point
5928  */
5929  if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
5930  float n1[3], n2[3], n3[3];
5931  const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
5932  const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
5933 
5934  bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
5935  bData->s_pos[index] = index * bData->s_num[index];
5936 
5937  /* per sample coordinates */
5938  for (int ss = 0; ss < bData->s_num[index]; ss++) {
5939  interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
5940  canvas_verts[tPoint->v1].v,
5941  canvas_verts[tPoint->v2].v,
5942  canvas_verts[tPoint->v3].v,
5943  f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
5944  }
5945 
5946  /* Calculate current pixel surface normal */
5947  copy_v3_v3(n1, data->vert_normals[tPoint->v1]);
5948  copy_v3_v3(n2, data->vert_normals[tPoint->v2]);
5949  copy_v3_v3(n3, data->vert_normals[tPoint->v3]);
5950 
5952  temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
5953  normalize_v3(temp_nor);
5955  /* Prepare surface normal directional scale to easily convert
5956  * brush intersection amount between global and local space */
5957  float scaled_nor[3];
5958  mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
5959  bData->bNormal[index].normal_scale = len_v3(scaled_nor);
5960  }
5961  mul_mat3_m4_v3(ob->obmat, temp_nor);
5962  normalize_v3(temp_nor);
5963  negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
5964  }
5965  else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
5966  int ss;
5967  if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
5968  bData->s_num[index] = adj_data->n_num[index] + 1;
5969  bData->s_pos[index] = adj_data->n_index[index] + index;
5970  }
5971  else {
5972  bData->s_num[index] = 1;
5973  bData->s_pos[index] = index;
5974  }
5975 
5976  /* calculate position for each sample */
5977  for (ss = 0; ss < bData->s_num[index]; ss++) {
5978  /* first sample is always point center */
5979  copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
5980  if (ss > 0) {
5981  int t_index = adj_data->n_index[index] + (ss - 1);
5982  /* get vertex position at 1/3 of each neigh edge */
5983  mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
5984  madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
5985  canvas_verts[adj_data->n_target[t_index]].v,
5986  1.0f / 3.0f);
5987  }
5988  }
5989 
5990  /* normal */
5991  copy_v3_v3(temp_nor, data->vert_normals[index]);
5993  /* Prepare surface normal directional scale to easily convert
5994  * brush intersection amount between global and local space */
5995  float scaled_nor[3];
5996  mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
5997  bData->bNormal[index].normal_scale = len_v3(scaled_nor);
5998  }
5999  mul_mat3_m4_v3(ob->obmat, temp_nor);
6000  normalize_v3(temp_nor);
6001  negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
6002  }
6003 
6004  /* calculate speed vector */
6005  if (do_velocity_data && !new_bdata && !bData->clear) {
6006  sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
6007  }
6008 }
6009 
6012  Object *ob)
6013 {
6014  PaintSurfaceData *sData = surface->data;
6015  PaintBakeData *bData = sData->bData;
6017  int index;
6018  bool new_bdata = false;
6019  const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
6022  const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
6023 
6024  int canvasNumOfVerts = mesh->totvert;
6025  MVert *mvert = mesh->mvert;
6026  Vec3f *canvas_verts;
6027 
6028  if (bData) {
6029  const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
6030 
6031  /* Get previous speed for acceleration. */
6032  if (do_accel_data && bData->prev_velocity && bData->velocity) {
6033  memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
6034  }
6035 
6036  /* reset speed vectors */
6037  if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved)) {
6038  memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
6039  }
6040 
6041  /* if previous data exists and mesh hasn't moved, no need to recalc */
6042  if (!surface_moved) {
6043  return true;
6044  }
6045  }
6046 
6047  canvas_verts = (struct Vec3f *)MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f),
6048  "Dynamic Paint transformed canvas verts");
6049  if (!canvas_verts) {
6050  return false;
6051  }
6052 
6053  /* allocate memory if required */
6054  if (!bData) {
6055  sData->bData = bData = (struct PaintBakeData *)MEM_callocN(sizeof(struct PaintBakeData),
6056  "Dynamic Paint bake data");
6057  if (!bData) {
6058  if (canvas_verts) {
6059  MEM_freeN(canvas_verts);
6060  }
6061  return false;
6062  }
6063 
6064  /* Init bdata */
6065  bData->bNormal = (struct PaintBakeNormal *)MEM_mallocN(
6066  sData->total_points * sizeof(struct PaintBakeNormal), "Dynamic Paint step data");
6067  bData->s_pos = MEM_mallocN(sData->total_points * sizeof(unsigned int),
6068  "Dynamic Paint bData s_pos");
6069  bData->s_num = MEM_mallocN(sData->total_points * sizeof(unsigned int),
6070  "Dynamic Paint bData s_num");
6071  bData->realCoord = (struct Vec3f *)MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f),
6072  "Dynamic Paint point coords");
6073  bData->prev_verts = MEM_mallocN(canvasNumOfVerts * sizeof(MVert),
6074  "Dynamic Paint bData prev_verts");
6075 
6076  /* if any allocation failed, free everything */
6077  if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
6078  if (bData->bNormal) {
6079  MEM_freeN(bData->bNormal);
6080  }
6081  if (bData->s_pos) {
6082  MEM_freeN(bData->s_pos);
6083  }
6084  if (bData->s_num) {
6085  MEM_freeN(bData->s_num);
6086  }
6087  if (bData->realCoord) {
6088  MEM_freeN(bData->realCoord);
6089  }
6090  if (canvas_verts) {
6091  MEM_freeN(canvas_verts);
6092  }
6093 
6094  return setError(surface->canvas, N_("Not enough free memory"));
6095  }
6096 
6097  new_bdata = true;
6098  }
6099 
6100  if (do_velocity_data && !bData->velocity) {
6101  bData->velocity = (struct Vec3f *)MEM_callocN(sData->total_points * sizeof(Vec3f),
6102  "Dynamic Paint velocity");
6103  }
6104  if (do_accel_data && !bData->prev_velocity) {
6105  bData->prev_velocity = (struct Vec3f *)MEM_mallocN(sData->total_points * sizeof(Vec3f),
6106  "Dynamic Paint prev velocity");
6107  /* copy previous vel */
6108  if (bData->prev_velocity && bData->velocity) {
6109  memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
6110  }
6111  }
6112 
6113  /*
6114  * Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
6115  */
6116  bData->mesh_bounds.valid = false;
6117  for (index = 0; index < canvasNumOfVerts; index++) {
6118  copy_v3_v3(canvas_verts[index].v, mvert[index].co);
6119  mul_m4_v3(ob->obmat, canvas_verts[index].v);
6120  boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
6121  }
6122 
6123  /*
6124  * Prepare each surface point for a new step
6125  */
6127  .surface = surface,
6128  .ob = ob,
6129  .mvert = mvert,
6130  .vert_normals = BKE_mesh_vertex_normals_ensure(mesh),
6131  .canvas_verts = canvas_verts,
6132  .do_velocity_data = do_velocity_data,
6133  .new_bdata = new_bdata,
6134  };
6135  TaskParallelSettings settings;
6137  settings.use_threading = (sData->total_points > 1000);
6139  0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, &settings);
6140 
6141  MEM_freeN(canvas_verts);
6142 
6143  /* generate surface space partitioning grid */
6145  /* Calculate current frame adjacency point distances and global directions. */
6147 
6148  /* Copy current frame vertices to check against in next frame */
6149  copy_m4_m4(bData->prev_obmat, ob->obmat);
6150  memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
6151 
6152  bData->clear = 0;
6153 
6154  return true;
6155 }
6156 
6157 /*
6158  * Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
6159  */
6161  Scene *scene,
6162  Object *ob,
6164  float timescale,
6165  float subframe)
6166 {
6167  PaintSurfaceData *sData = surface->data;
6168  PaintBakeData *bData = sData->bData;
6169  DynamicPaintCanvasSettings *canvas = surface->canvas;
6170  const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
6171  int ret = 1;
6172 
6173  if (sData->total_points < 1) {
6174  return 0;
6175  }
6176 
6179  .surface = surface,
6180  .timescale = timescale,
6181  };
6182  TaskParallelSettings settings;
6184  settings.use_threading = (sData->total_points > 1000);
6186  0, sData->total_points, &data, dynamic_paint_surface_pre_step_cb, &settings);
6187  }
6188 
6189  /*
6190  * Loop through surface's target paint objects and do painting
6191  */
6192  {
6193  unsigned int numobjects;
6195  depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
6196 
6197  /* backup current scene frame */
6198  int scene_frame = scene->r.cfra;
6199  float scene_subframe = scene->r.subframe;
6200 
6201  for (int i = 0; i < numobjects; i++) {
6202  Object *brushObj = objects[i];
6203 
6204  /* check if target has an active dp modifier */
6206  if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
6208  /* make sure we're dealing with a brush */
6209  if (pmd2->brush && pmd2->type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
6210  DynamicPaintBrushSettings *brush = pmd2->brush;
6211 
6212  /* calculate brush speed vectors if required */
6213  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
6214  bData->brush_velocity = MEM_callocN(sizeof(float[4]) * sData->total_points,
6215  "Dynamic Paint brush velocity");
6216  /* init adjacency data if not already */
6217  if (!sData->adj_data) {
6219  }
6220  if (!bData->bNeighs) {
6222  }
6223  }
6224 
6225  /* update object data on this subframe */
6226  if (subframe) {
6227  scene_setSubframe(scene, subframe);
6229  scene,
6230  brushObj,
6231  true,
6235  }
6236 
6237  /* Apply brush on the surface depending on its collision type */
6238  if (brush->psys && brush->psys->part &&
6239  ELEM(brush->psys->part->type,
6240  PART_EMITTER,
6241  PART_FLUID,
6251  psys_check_enabled(brushObj, brush->psys, for_render)) {
6252  /* Paint a particle system */
6253  dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
6254  }
6255  /* Object center distance: */
6256  if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
6258  depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
6259  }
6260  /* Mesh volume/proximity: */
6261  else if (brushObj != ob) {
6262  dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
6263  }
6264 
6265  /* reset object to its original state */
6266  if (subframe) {
6267  scene->r.cfra = scene_frame;
6268  scene->r.subframe = scene_subframe;
6270  scene,
6271  brushObj,
6272  true,
6276  }
6277 
6278  /* process special brush effects, like smudge */
6279  if (bData->brush_velocity) {
6280  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
6281  brush->flags & MOD_DPAINT_DO_SMUDGE) {
6282  dynamicPaint_doSmudge(surface, brush, timescale);
6283  }
6284  MEM_freeN(bData->brush_velocity);
6285  bData->brush_velocity = NULL;
6286  }
6287  }
6288  }
6289  }
6290 
6291  BKE_collision_objects_free(objects);
6292  }
6293 
6294  /* surfaces operations that use adjacency data */
6295  if (sData->adj_data && bData->bNeighs) {
6296  /* wave type surface simulation step */
6297  if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
6298  dynamicPaint_doWaveStep(surface, timescale);
6299  }
6300 
6301  /* paint surface effects */
6302  if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
6303  int steps = 1, s;
6304  PaintPoint *prevPoint;
6305  float *force = NULL;
6306 
6307  /* Allocate memory for surface previous points to read unchanged values from */
6308  prevPoint = MEM_mallocN(sData->total_points * sizeof(struct PaintPoint),
6309  "PaintSurfaceDataCopy");
6310  if (!prevPoint) {
6311  return setError(canvas, N_("Not enough free memory"));
6312  }
6313 
6314  /* Prepare effects and get number of required steps */
6315  steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
6316  for (s = 0; s < steps; s++) {
6317  dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
6318  }
6319 
6320  /* Free temporary effect data */
6321  if (prevPoint) {
6322  MEM_freeN(prevPoint);
6323  }
6324  if (force) {
6325  MEM_freeN(force);
6326  }
6327  }
6328 
6329  /* paint island border pixels */
6330  if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
6332  }
6333  }
6334 
6335  return ret;
6336 }
6337 
6339  struct Depsgraph *depsgraph,
6340  Scene *scene,
6341  Object *cObject,
6342  int frame)
6343 {
6344  float timescale = 1.0f;
6345 
6346  /* apply previous displace on derivedmesh if incremental surface */
6347  if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
6349  }
6350 
6351  /* update bake data */
6353 
6354  /* don't do substeps for first frame */
6355  if (surface->substeps && (frame != surface->start_frame)) {
6356  int st;
6357  timescale = 1.0f / (surface->substeps + 1);
6358 
6359  for (st = 1; st <= surface->substeps; st++) {
6360  float subframe = ((float)st) / (surface->substeps + 1);
6361  if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe)) {
6362  return 0;
6363  }
6364  }
6365  }
6366 
6367  return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
6368 }
typedef float(TangentPoint)[2]
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:73
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, float m_dist, const float v0[3], const float v1[3], const float v2[3])
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
struct ColorBand * BKE_colorband_add(bool rangetype)
Definition: colorband.c:296
bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4])
CustomData interface, see also DNA_customdata_types.h.
@ CD_CALLOC
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
Definition: customdata.cc:2792
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
void CustomData_validate_layer_name(const struct CustomData *data, int type, const char *name, char *outname)
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, int defgroup)
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
struct PaintPoint PaintPoint
struct PaintWavePoint PaintWavePoint
#define DPAINT_PAINT_NEW
#define DPAINT_PAINT_DRY
#define DPAINT_WAVE_ISECT_CHANGED
#define DPAINT_WAVE_REFLECT_ONLY
#define DPAINT_PAINT_WET
#define DPAINT_WAVE_NONE
#define DPAINT_WAVE_OBSTACLE
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
struct ImagePool * BKE_image_pool_new(void)
void BKE_image_pool_free(struct ImagePool *pool)
int BKE_image_path_ensure_ext_from_imtype(char *string, char imtype)
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
Definition: BKE_lib_id.h:143
void BKE_id_free(struct Main *bmain, void *idv)
const char * BKE_main_blendfile_path_from_global(void)
Definition: main.c:562
General operations, lookup, etc. for materials.
struct Mesh * BKE_mesh_copy_for_eval(const struct Mesh *source, bool reference)
const float(* BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3]
void BKE_mesh_tag_coords_changed(struct Mesh *mesh)
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map, int **r_mem, const struct MVert *mvert, int totvert, const struct MLoopTri *mlooptri, int totlooptri, const struct MLoop *mloop, int totloop)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
struct ModifierData * BKE_modifiers_findby_type(const struct Object *ob, ModifierType type)
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 psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params)
Definition: particle.c:801
void BKE_ptcache_id_time(PTCacheID *pid, struct Scene *scene, float cfra, int *startframe, int *endframe, float *timescale)
Definition: pointcache.c:2773
void BKE_ptcache_validate(struct PointCache *cache, int framenr)
Definition: pointcache.c:3789
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface)
Definition: pointcache.c:1016
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
int BKE_ptcache_read(PTCacheID *pid, float cfra, bool no_extrapolate_old)
Definition: pointcache.c:2280
int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
Definition: pointcache.c:2540
void BKE_ptcache_free_list(struct ListBase *ptcaches)
Definition: pointcache.c:3052
#define PTCACHE_RESET_OUTDATED
float BKE_scene_ctime_get(const struct Scene *scene)
bool BKE_scene_check_color_management_enabled(const struct Scene *scene)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
#define BVH_RAYCAST_DIST_MAX
Definition: BLI_kdopbvh.h:89
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
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define M_PI_2
Definition: BLI_math_base.h:23
MINLINE float square_f(float a)
MINLINE float min_fff(float a, float b, float c)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:383
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
Definition: math_color.c:396
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
Definition: math_geom.c:3700
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 closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:980
float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:3183
int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], const float v3[2])
Definition: math_geom.c:1516
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:283
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:790
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
Definition: math_matrix.c:2531
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_v3v3(const float a[3], const float b[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 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_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float r[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 float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:890
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void interp_v4_v4v4v4(float p[4], const float v1[4], const float v2[4], const float v3[4], const float w[3])
Definition: math_vector.c:180
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2]) ATTR_WARN_UNUSED_RESULT
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 madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
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
bool BLI_make_existing_file(const char *name)
Definition: path_util.c:1197
#define FILE_MAX
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:897
#define BLI_path_cmp
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len)
Definition: string_utils.c:233
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 CLAMP_MAX(a, c)
#define UNUSED(x)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
#define BLT_I18NCONTEXT_ID_BRUSH
#define CTX_DATA_(context, msgid)
typedef double(DMatrix)[4][4]
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
#define CLOG_STR_ERROR(clg_ref, str)
Definition: CLG_log.h:196
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ DAG_EVAL_RENDER
Definition: DEG_depsgraph.h:46
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
Object groups, one object can be in many groups at once.
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_PROP_BYTE_COLOR
@ CD_MDEFORMVERT
@ CD_MLOOPUV
@ MOD_DPAINT_INITIAL_NONE
@ MOD_DPAINT_INITIAL_VERTEXCOLOR
@ MOD_DPAINT_INITIAL_COLOR
@ MOD_DPAINT_INITIAL_TEXTURE
@ MOD_DPAINT_SURFACE_T_WEIGHT
@ MOD_DPAINT_SURFACE_T_PAINT
@ MOD_DPAINT_SURFACE_T_DISPLACE
@ MOD_DPAINT_SURFACE_T_WAVE
@ MOD_DPAINT_RAY_BRUSH_AVG
@ MOD_DPAINT_RAY_CANVAS
@ MOD_DPAINT_COL_DIST
@ MOD_DPAINT_COL_VOLDIST
@ MOD_DPAINT_COL_POINT
@ MOD_DPAINT_COL_VOLUME
@ MOD_DPAINT_ACTIVE
@ MOD_DPAINT_USE_DRYING
@ MOD_DPAINT_ANTIALIAS
@ MOD_DPAINT_WAVE_OPEN_BORDERS
@ MOD_DPAINT_DISP_INCREMENTAL
@ MOD_DPAINT_OUT1
@ MOD_DPAINT_DISSOLVE
@ MOD_DPAINT_MULALPHA
@ MOD_DPAINT_DISSOLVE_LOG
@ MOD_DPAINT_DRY_LOG
@ MOD_DPAINT_PRFALL_CONSTANT
@ MOD_DPAINT_PRFALL_SMOOTH
@ MOD_DPAINT_PRFALL_RAMP
@ MOD_DPAINT_BAKING
@ MOD_DPAINT_DISP_DISPLACE
@ MOD_DPAINT_PROX_PROJECT
@ MOD_DPAINT_ABS_ALPHA
@ MOD_DPAINT_RAMP_ALPHA
@ MOD_DPAINT_INVERSE_PROX
@ MOD_DPAINT_USES_VELOCITY
@ MOD_DPAINT_VELOCITY_ALPHA
@ MOD_DPAINT_VELOCITY_DEPTH
@ MOD_DPAINT_ERASE
@ MOD_DPAINT_VELOCITY_COLOR
@ MOD_DPAINT_DO_SMUDGE
@ MOD_DPAINT_PART_RAD
@ MOD_DPAINT_NEGATE_VOLUME
@ MOD_DPAINT_EFFECT_DO_DRIP
@ MOD_DPAINT_EFFECT_DO_SPREAD
@ MOD_DPAINT_EFFECT_DO_SHRINK
@ MOD_DPAINT_WAVEB_REFLECT
@ MOD_DPAINT_WAVEB_DEPTH
@ MOD_DPAINT_WAVEB_CHANGE
@ MOD_DPAINT_WAVEB_FORCE
@ MOD_DPAINT_SURFACE_F_PTEX
@ MOD_DPAINT_SURFACE_F_VERTEX
@ MOD_DPAINT_SURFACE_F_IMAGESEQ
@ MOD_DPAINT_IMGFORMAT_OPENEXR
@ MOD_DPAINT_IMGFORMAT_PNG
@ eModifierFlag_SharedCaches
@ eModifierMode_Render
@ eModifierMode_Realtime
@ MOD_DYNAMICPAINT_TYPE_BRUSH
@ MOD_DYNAMICPAINT_TYPE_CANVAS
@ eModifierType_DynamicPaint
Object is a sort of wrapper for general info.
#define PARS_UNEXIST
#define PART_UNBORN
@ PART_FLUID_FLIP
@ PART_EMITTER
@ PART_FLUID_BUBBLE
@ PART_FLUID_SPRAYBUBBLE
@ PART_FLUID_TRACER
@ PART_FLUID
@ PART_FLUID_FOAM
@ PART_FLUID_SPRAYFOAMBUBBLE
@ PART_FLUID_SPRAYFOAM
@ PART_FLUID_SPRAY
@ PART_FLUID_FOAMBUBBLE
#define PARS_DEAD
#define PART_DIED
#define PARS_UNBORN
@ PTCACHE_BAKED
@ PTCACHE_DISK_CACHE
@ PTCACHE_REDO_NEEDED
#define PHYS_GLOBAL_GRAVITY
#define R_IMF_IMTYPE_PNG
#define R_IMF_IMTYPE_OPENEXR
_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 GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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 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
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags)
Definition: writeimage.c:22
Contains defines and structs used throughout the imbuf module.
@ IB_rectfloat
#define OPENEXR_COMPRESS
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
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 a value between a minimum and a maximum Vector Perform vector math operation Invert a color
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b)
ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b)
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define powf(x, y)
Definition: cuda/compat.h:103
static char * basename(char *string)
Definition: datatoc.c:17
double time
Scene scene
const Depsgraph * depsgraph
static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface)
int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, struct Depsgraph *depsgraph, Scene *scene, Object *cObject, int frame)
static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, Object *brushOb, Scene *scene, float timescale)
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
static int dynamic_paint_find_neighbor_pixel(const DynamicPaintCreateUVSurfaceData *data, const MeshElemMap *vert_to_looptri_map, const int w, const int h, const int px, const int py, const int n_index)
struct PaintBakeNormal PaintBakeNormal
static void freeGrid(PaintSurfaceData *data)
Definition: dynamicpaint.c:606
static void dynamicPaint_mixPaintColors(const DynamicPaintSurface *surface, const int index, const int paintFlags, const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
static void dynamic_paint_apply_surface_vpaint_blend_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, float timescale)
static void dynamic_paint_border_cb(void *__restrict userdata, const int b_index, const TaskParallelTLS *__restrict UNUSED(tls))
static void free_bakeData(PaintSurfaceData *data)
Definition: dynamicpaint.c:881
static void grid_cell_points_reduce(const void *__restrict userdata, void *__restrict chunk_join, void *__restrict chunk)
Definition: dynamicpaint.c:671
static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
static void scene_setSubframe(Scene *scene, float subframe)
Definition: dynamicpaint.c:508
static const float gaussianTotal
Definition: dynamicpaint.c:88
static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
#define NOT_FOUND
Definition: dynamicpaint.c:106
static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
Definition: dynamicpaint.c:546
static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
static int neighX[8]
Definition: dynamicpaint.c:91
void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintSurface *surface)
Definition: dynamicpaint.c:964
static void grid_bound_insert_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
Definition: dynamicpaint.c:628
static const float gaussianFactors[5]
Definition: dynamicpaint.c:81
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
struct DynamicPaintDissolveDryData DynamicPaintDissolveDryData
struct DynamicPaintBrushVelocityData DynamicPaintBrushVelocityData
static void dynamic_paint_output_surface_image_wetmap_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
struct PaintUVPoint PaintUVPoint
static Mesh * dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
static bool boundIntersectPoint(Bounds3D *b, const float point[3], const float radius)
Definition: dynamicpaint.c:574
static void dynamic_paint_output_surface_image_displace_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
Definition: dynamicpaint.c:409
static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
static void dynamic_paint_create_uv_surface_direct_cb(void *__restrict userdata, const int ty, const TaskParallelTLS *__restrict UNUSED(tls))
struct Bounds2D Bounds2D
static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata, int tri_index, const float pixel[2], int in_edge, int depth)
static void surface_freeUnusedData(DynamicPaintSurface *surface)
Definition: dynamicpaint.c:919
static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
Definition: dynamicpaint.c:366
static void dynamic_paint_paint_particle_cell_point_cb_ex(void *__restrict userdata, const int id, const TaskParallelTLS *__restrict UNUSED(tls))
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
static void dynamic_paint_effect_spread_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
Definition: dynamicpaint.c:401
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
#define HIT_VOLUME
Definition: dynamicpaint.c:103
static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
static void dynamic_paint_apply_surface_vpaint_cb(void *__restrict userdata, const int p_index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamic_paint_effect_drip_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static int neighStraightX[8]
Definition: dynamicpaint.c:95
static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
#define EFF_MOVEMENT_PER_FRAME
Definition: dynamicpaint.c:110
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
struct PaintBakeData PaintBakeData
static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
#define WAVE_TIME_FAC
Definition: dynamicpaint.c:112
struct DynamicPaintFindIslandBorderData DynamicPaintFindIslandBorderData
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, const char *filepath, short output_layer)
struct DynamicPaintGenerateBakeData DynamicPaintGenerateBakeData
struct Bounds3D Bounds3D
#define CANVAS_REL_SIZE
Definition: dynamicpaint.c:113
static void dynamic_paint_brush_velocity_compute_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
static bool setError(DynamicPaintCanvasSettings *canvas, const char *string)
Definition: dynamicpaint.c:295
static Mesh * dynamicPaint_canvas_mesh_get(DynamicPaintCanvasSettings *canvas)
Definition: dynamicpaint.c:274
static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph, Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
#define MAX_WETNESS
Definition: dynamicpaint.c:116
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
Definition: dynamicpaint.c:843
#define HIT_PROXIMITY
Definition: dynamicpaint.c:104
static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamic_paint_set_init_color_vcol_to_imseq_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamic_paint_effect_shrink_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
#define JITTER_SAMPLES
static void surface_determineForceTargetPoints(const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
Definition: dynamicpaint.c:119
static float getSurfaceDimension(PaintSurfaceData *sData)
Definition: dynamicpaint.c:600
static int surface_totalSamples(DynamicPaintSurface *surface)
Definition: dynamicpaint.c:442
#define ADJ_ON_MESH_EDGE
Definition: dynamicpaint.c:230
static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob)
#define SUBFRAME_RECURSION
Definition: dynamicpaint.c:99
struct VolumeGrid VolumeGrid
struct DynamicPaintModifierApplyData DynamicPaintModifierApplyData
static void dynamic_paint_prepare_adjacency_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
#define MIN_WETNESS
Definition: dynamicpaint.c:115
static void dynamic_paint_wave_step_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamicPaint_brushObjectCalculateVelocity(Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
static int neighY[8]
Definition: dynamicpaint.c:92
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
struct PaintAdjData PaintAdjData
static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
Definition: dynamicpaint.c:560
DynamicPaintSurface * get_activeSurface(DynamicPaintCanvasSettings *canvas)
Definition: dynamicpaint.c:317
static void grid_cell_points_cb_ex(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict tls)
Definition: dynamicpaint.c:650
static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
struct DynamicPaintOutputSurfaceImageData DynamicPaintOutputSurfaceImageData
static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
struct DynamicPaintPaintData DynamicPaintPaintData
static void boundInsert(Bounds3D *b, const float point[3])
Definition: dynamicpaint.c:588
struct DynamicPaintEffectData DynamicPaintEffectData
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
Definition: dynamicpaint.c:711
static CLG_LogRef LOG
Definition: dynamicpaint.c:78
static void grid_cell_bounds_cb(void *__restrict userdata, const int x, const TaskParallelTLS *__restrict UNUSED(tls))
Definition: dynamicpaint.c:688
#define ADJ_BORDER_PIXEL
Definition: dynamicpaint.c:231
static void dynamic_paint_prepare_effect_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
static bool surface_duplicateOutputExists(void *arg, const char *name)
Definition: dynamicpaint.c:349
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
Definition: dynamicpaint.c:932
static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph)
Definition: dynamicpaint.c:515
struct ImgSeqFormatData ImgSeqFormatData
static void dynamic_paint_create_uv_surface_neighbor_cb(void *__restrict userdata, const int ty, const TaskParallelTLS *__restrict UNUSED(tls))
#define BRUSH_USES_VELOCITY
Definition: dynamicpaint.c:101
static bool dynamicPaint_paintParticles(DynamicPaintSurface *surface, ParticleSystem *psys, DynamicPaintBrushSettings *brush, float timescale)
static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
Definition: dynamicpaint.c:997
static DynamicPaintRuntime * dynamicPaint_Modifier_runtime_ensure(DynamicPaintModifierData *pmd)
Definition: dynamicpaint.c:266
struct DynamicPaintCreateUVSurfaceData DynamicPaintCreateUVSurfaceData
static void blendColors(const float t_color[3], const float t_alpha, const float s_color[3], const float s_alpha, float result[4])
Definition: dynamicpaint.c:455
Mesh * dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh)
static int dynamicPaint_doStep(Depsgraph *depsgraph, Scene *scene, Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
static bool dynamicPaint_paintSinglePoint(Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush, Object *brushOb, Scene *scene, float timescale)
struct BakeAdjPoint BakeAdjPoint
static int neighStraightY[8]
Definition: dynamicpaint.c:96
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
Definition: dynamicpaint.c:979
#define ON_MESH_EDGE
Definition: dynamicpaint.c:107
static bool surface_duplicateNameExists(void *arg, const char *name)
Definition: dynamicpaint.c:388
struct DynamicPaintSetInitColorData DynamicPaintSetInitColorData
static Mesh * dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
Definition: dynamicpaint.c:283
static void dynamic_paint_output_surface_image_wave_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tpmd, int flag)
static int dynamicPaint_prepareEffectStep(struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
static float mixColors(float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
Definition: dynamicpaint.c:479
static void dynamic_paint_paint_mesh_cell_point_cb_ex(void *__restrict userdata, const int id, const TaskParallelTLS *__restrict UNUSED(tls))
static void grid_bound_insert_reduce(const void *__restrict UNUSED(userdata), void *__restrict chunk_join, void *__restrict chunk)
Definition: dynamicpaint.c:639
void dynamicPaint_Modifier_free_runtime(DynamicPaintRuntime *runtime_data)
Definition: dynamicpaint.c:252
static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
static bool surface_usesAdjData(DynamicPaintSurface *surface)
#define OUT_OF_TEXTURE
Definition: dynamicpaint.c:108
static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
Definition: dynamicpaint.c:304
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output)
Definition: dynamicpaint.c:322
DynamicPaintSurface * dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene)
static void dynamic_paint_output_surface_image_paint_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
static void dynamicPaint_updatePointData(const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush, float paint[3], float influence, float depth, float vel_factor, const float timescale)
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
Definition: dynamicpaint.c:858
struct Vec3f Vec3f
static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls))
void * tree
struct @211::@212 surface
#define str(s)
uint pos
uint nor
uint col
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
@ IMB_FTYPE_OPENEXR
@ IMB_FTYPE_PNG
#define mix(a, b, c)
Definition: hash.h:17
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
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
static ulong * next
static void error(const char *str)
Definition: meshlaplacian.c:51
#define ceilf(x)
Definition: metal/compat.h:225
#define floorf(x)
Definition: metal/compat.h:224
#define acosf(x)
Definition: metal/compat.h:222
#define fabsf(x)
Definition: metal/compat.h:219
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned c
Definition: RandGen.cpp:83
static Color mix_color(Color col_src, Color col_dst, typename Traits::BlendType fac)
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
T distance(const T &a, const T &b)
T floor(const T &a)
bool isnan(double i)
Definition: numeric.h:451
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
SocketIndexByIdentifierMap * map
smooth(Type::FLOAT, "mask_weight")
return ret
static const int steps
Definition: sky_nishita.cpp:19
#define min(a, b)
Definition: sort.c:35
unsigned int uint32_t
Definition: stdint.h:80
unsigned char uint8_t
Definition: stdint.h:78
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
float co[3]
Definition: BLI_kdopbvh.h:43
float no[3]
Definition: BLI_kdopbvh.h:46
float no[3]
Definition: BLI_kdopbvh.h:70
float dir[3]
Definition: dynamicpaint.c:162
float min[2]
Definition: dynamicpaint.c:131
float max[2]
Definition: dynamicpaint.c:131
float min[3]
Definition: dynamicpaint.c:135
float max[3]
Definition: dynamicpaint.c:135
bool valid
Definition: dynamicpaint.c:136
CBData data[32]
struct DynamicPaintModifierData * pmd
struct ParticleSystem * psys
struct DynamicPaintModifierData * pmd
const DynamicPaintSurface * surface
const DynamicPaintSurface * surface
const float wave_max_slope
const DynamicPaintSurface * surface
const MeshElemMap * vert_to_looptri_map
const float(* vert_normals)[3]
const DynamicPaintSurface * surface
const float(* vert_normals)[3]
const DynamicPaintSurface * surface
struct DynamicPaintCanvasSettings * canvas
struct DynamicPaintBrushSettings * brush
const DynamicPaintSurface * surface
const DynamicPaintBrushSettings * brush
const float * avg_brushNor
const float brush_radius
const ParticleSystem * psys
const MLoopTri * mlooptri
const DynamicPaintSurface * surface
const Vec3f * brushVelocity
const DynamicPaintSurface * surface
struct DynamicPaintCanvasSettings * canvas
struct Collection * brush_group
struct EffectorWeights * effector_weights
struct PointCache * pointcache
float vel_to_sec
Definition: BKE_effect.h:34
ImbFormatOptions foptions
enum eImbFileType ftype
float * rect_float
PaintUVPoint * uv_p
Definition: dynamicpaint.c:225
Vec3f * barycentricWeights
Definition: dynamicpaint.c:226
void * first
Definition: DNA_listBase.h:31
unsigned char a
unsigned char b
unsigned char r
unsigned char g
unsigned int tri[3]
unsigned int v
float co[3]
struct MEdge * medge
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
CustomData ldata
float loc[3]
float scale[3]
float obmat[4][4]
void * data
struct PointCache * cache
double average_dist
Definition: dynamicpaint.c:191
BakeAdjPoint * bNeighs
Definition: dynamicpaint.c:190
Vec3f * prev_velocity
Definition: dynamicpaint.c:199
Vec3f * realCoord
Definition: dynamicpaint.c:184
float prev_obmat[4][4]
Definition: dynamicpaint.c:206
VolumeGrid * grid
Definition: dynamicpaint.c:194
float * brush_velocity
Definition: dynamicpaint.c:202
MVert * prev_verts
Definition: dynamicpaint.c:204
Vec3f * velocity
Definition: dynamicpaint.c:198
Bounds3D mesh_bounds
Definition: dynamicpaint.c:185
float dim[3]
Definition: dynamicpaint.c:186
PaintBakeNormal * bNormal
Definition: dynamicpaint.c:178
float invNorm[3]
Definition: dynamicpaint.c:170
float color[4]
float e_color[4]
struct PaintBakeData * bData
struct PaintAdjData * adj_data
unsigned int v3
Definition: dynamicpaint.c:218
unsigned int pixel_index
Definition: dynamicpaint.c:216
unsigned int neighbor_pixel
Definition: dynamicpaint.c:221
unsigned int v2
Definition: dynamicpaint.c:218
unsigned int v1
Definition: dynamicpaint.c:218
unsigned int tri_index
Definition: dynamicpaint.c:215
ParticleKey state
ParticleData * particles
ParticleSettings * part
struct PhysicsSettings physics_settings
struct RenderData r
TaskParallelReduceFunc func_reduce
Definition: BLI_task.h:181
size_t userdata_chunk_size
Definition: BLI_task.h:169
float tin
Definition: RE_texture.h:86
float trgba[4]
Definition: RE_texture.h:87
float v[3]
Definition: dynamicpaint.c:157
Bounds3D grid_bounds
Definition: dynamicpaint.c:142
int * t_index
Definition: dynamicpaint.c:151
int * temp_t_index
Definition: dynamicpaint.c:153
int dim[3]
Definition: dynamicpaint.c:140
Bounds3D * bounds
Definition: dynamicpaint.c:145
int multitex_ext_safe(Tex *tex, const float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
float max
#define N_(msgid)