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