2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Miika Hämäläinen
20 * ***** END GPL LICENSE BLOCK *****
24 #include "MEM_guardedalloc.h"
29 #include "BLI_blenlib.h"
31 #include "BLI_kdtree.h"
32 #include "BLI_threads.h"
33 #include "BLI_utildefines.h"
35 #include "BLF_translation.h"
37 #include "DNA_anim_types.h"
38 #include "DNA_armature_types.h"
39 #include "DNA_constraint_types.h"
40 #include "DNA_dynamicpaint_types.h"
41 #include "DNA_group_types.h" /*GroupObject*/
42 #include "DNA_material_types.h"
43 #include "DNA_mesh_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_modifier_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_texture_types.h"
51 #include "BKE_animsys.h"
52 #include "BKE_armature.h"
53 #include "BKE_bvhutils.h" /* bvh tree */
54 #include "BKE_blender.h"
55 #include "BKE_cdderivedmesh.h"
56 #include "BKE_constraint.h"
57 #include "BKE_context.h"
58 #include "BKE_customdata.h"
59 #include "BKE_colortools.h"
60 #include "BKE_deform.h"
61 #include "BKE_depsgraph.h"
62 #include "BKE_DerivedMesh.h"
63 #include "BKE_dynamicpaint.h"
64 #include "BKE_effect.h"
65 #include "BKE_global.h"
66 #include "BKE_image.h"
68 #include "BKE_material.h"
69 #include "BKE_modifier.h"
70 #include "BKE_object.h"
71 #include "BKE_particle.h"
72 #include "BKE_pointcache.h"
73 #include "BKE_scene.h"
74 #include "BKE_texture.h"
76 #include "RNA_access.h"
77 #include "RNA_define.h"
78 #include "RNA_enum_types.h"
80 /* for image output */
81 #include "IMB_imbuf_types.h"
82 #include "IMB_imbuf.h"
84 /* to read material/texture color */
85 #include "RE_render_ext.h"
86 #include "RE_shader_ext.h"
92 /* could enable at some point but for now there are far too many conversions */
93 #pragma GCC diagnostic ignored "-Wdouble-promotion"
95 /* precalculated gaussian factors for 5x super sampling */
96 static float gaussianFactors[5] = {0.996849f,
101 static float gaussianTotal = 3.309425f;
103 /* UV Image neighboring pixel table x and y list */
104 static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
105 static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
107 /* subframe_updateObject() flags */
108 #define UPDATE_PARENTS (1 << 0)
109 #define UPDATE_MESH (1 << 1)
110 #define UPDATE_EVERYTHING (UPDATE_PARENTS | UPDATE_MESH)
111 /* surface_getBrushFlags() return vals */
112 #define BRUSH_USES_VELOCITY (1 << 0)
113 /* brush mesh raycast status */
115 #define HIT_PROXIMITY 2
116 /* dynamicPaint_findNeighbourPixel() return codes */
118 #define ON_MESH_EDGE -2
119 #define OUT_OF_TEXTURE -3
120 /* paint effect default movement per frame in global units */
121 #define EFF_MOVEMENT_PER_FRAME 0.05f
122 /* initial wave time factor */
123 #define WAVE_TIME_FAC (1.0f / 24.f)
124 #define CANVAS_REL_SIZE 5.0f
126 #define MIN_WETNESS 0.001f
127 #define MAX_WETNESS 5.0f
130 /* dissolve inline function */
131 BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const int is_log)
133 *r_value = (is_log) ?
134 (*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
135 (*r_value) - 1.0f / time * scale;
139 /***************************** Internal Structs ***************************/
141 typedef struct Bounds2D {
142 float min[2], max[2];
145 typedef struct Bounds3D {
147 float min[3], max[3];
150 typedef struct VolumeGrid {
152 Bounds3D grid_bounds; /* whole grid bounds */
154 Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
155 int *s_pos; /* (x*y*z) t_index begin id */
156 int *s_num; /* (x*y*z) number of t_index points */
157 int *t_index; /* actual surface point index,
158 * access: (s_pos+s_num) */
161 typedef struct Vec3f {
165 typedef struct BakeAdjPoint {
166 float dir[3]; /* vector pointing towards this neighbor */
167 float dist; /* distance to */
170 /* Surface data used while processing a frame */
171 typedef struct PaintBakeNormal {
172 float invNorm[3]; /* current pixel world-space inverted normal */
173 float normal_scale; /* normal directional scale for displace mapping */
176 /* Temp surface data used to process a frame */
177 typedef struct PaintBakeData {
178 /* point space data */
179 PaintBakeNormal *bNormal;
180 int *s_pos; /* index to start reading point sample realCoord */
181 int *s_num; /* num of realCoord samples */
182 Vec3f *realCoord; /* current pixel center world-space coordinates for each sample
183 * ordered as (s_pos+s_num)*/
184 Bounds3D mesh_bounds;
187 BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
189 /* space partitioning */
190 VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
192 /* velocity and movement */
193 Vec3f *velocity; /* speed vector in global space movement per frame, if required */
194 Vec3f *prev_velocity;
195 float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
196 * 3 float dir vec + 1 float str */
197 MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
198 float prev_obmat[4][4]; /* previous frame object matrix */
199 int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
203 /* UV Image sequence format point */
204 typedef struct PaintUVPoint {
205 /* Pixel / mesh data */
206 unsigned int face_index, pixel_index; /* face index on domain derived mesh */
207 unsigned int v1, v2, v3; /* vertex indexes */
209 unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face,
210 * but it's neighboring pixel is */
214 typedef struct ImgSeqFormatData {
216 Vec3f *barycentricWeights; /* b-weights for all pixel samples */
219 /* adjacency data flags */
220 #define ADJ_ON_MESH_EDGE (1 << 0)
222 typedef struct PaintAdjData {
223 int *n_target; /* array of neighboring point indexes,
224 * for single sample use (n_index + neigh_num) */
225 int *n_index; /* index to start reading n_target for each point */
226 int *n_num; /* num of neighs for each point */
227 int *flags; /* vertex adjacency flags */
228 int total_targets; /* size of n_target */
231 /***************************** General Utils ******************************/
233 /* Set canvas error string to display at the bake report */
234 static int setError(DynamicPaintCanvasSettings *canvas, const char *string)
236 /* Add error to canvas ui info label */
237 BLI_strncpy(canvas->error, string, sizeof(canvas->error));
241 /* Get number of surface points for cached types */
242 static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
244 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
245 return 0; /* not supported atm */
247 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
248 if (!surface->canvas->dm) return 0; /* invalid derived mesh */
249 return surface->canvas->dm->getNumVerts(surface->canvas->dm);
255 /* checks whether surface's format/type has realtime preview */
256 int dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
258 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
261 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
262 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
263 surface->type == MOD_DPAINT_SURFACE_T_WAVE)
276 /* get currently active surface (in user interface) */
277 DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
279 DynamicPaintSurface *surface = canvas->surfaces.first;
282 for (i = 0; surface; surface = surface->next) {
283 if (i == canvas->active_sur)
290 /* set preview to first previewable surface */
291 void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
293 DynamicPaintSurface *surface = canvas->surfaces.first;
296 for (; surface; surface = surface->next) {
297 if (!done && dynamicPaint_surfaceHasColorPreview(surface)) {
298 surface->flags |= MOD_DPAINT_PREVIEW;
302 surface->flags &= ~MOD_DPAINT_PREVIEW;
306 /* set preview to defined surface */
307 static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface)
309 DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
310 for (; surface; surface = surface->next) {
311 if (surface == t_surface)
312 surface->flags |= MOD_DPAINT_PREVIEW;
314 surface->flags &= ~MOD_DPAINT_PREVIEW;
318 int dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output)
323 name = surface->output_name;
324 else if (output == 1)
325 name = surface->output_name2;
329 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
330 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
332 return (CustomData_get_named_layer_index(&me->fdata, CD_MCOL, name) != -1);
334 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)
335 return (defgroup_name_index(ob, surface->output_name) != -1);
341 static int surface_duplicateOutputExists(void *arg, const char *name)
343 DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
344 DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
346 for (; surface; surface = surface->next) {
347 if (surface != t_surface && surface->type == t_surface->type &&
348 surface->format == t_surface->format)
350 if (surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) return 1;
351 if (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)) return 1;
357 static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
360 BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
362 BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name, sizeof(surface->output_name));
364 BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.', surface->output_name2, sizeof(surface->output_name2));
368 static int surface_duplicateNameExists(void *arg, const char *name)
370 DynamicPaintSurface *t_surface = (DynamicPaintSurface *)arg;
371 DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
373 for (; surface; surface = surface->next) {
374 if (surface != t_surface && !strcmp(name, surface->name)) return 1;
379 void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
382 BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
383 BLI_uniquename_cb(surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
387 /* change surface data to defaults on new type */
388 void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
390 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
391 surface->output_name[0] = '\0';
392 surface->output_name2[0] = '\0';
393 surface->flags |= MOD_DPAINT_ANTIALIAS;
394 surface->depth_clamp = 1.0f;
397 strcpy(surface->output_name, "dp_");
398 strcpy(surface->output_name2, surface->output_name);
399 surface->flags &= ~MOD_DPAINT_ANTIALIAS;
400 surface->depth_clamp = 0.0f;
403 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
404 strcat(surface->output_name, "paintmap");
405 strcat(surface->output_name2, "wetmap");
406 surface_setUniqueOutputName(surface, surface->output_name2, 1);
408 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
409 strcat(surface->output_name, "displace");
411 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
412 strcat(surface->output_name, "weight");
414 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
415 strcat(surface->output_name, "wave");
418 surface_setUniqueOutputName(surface, surface->output_name, 0);
421 if (dynamicPaint_surfaceHasColorPreview(surface))
422 dynamicPaint_setPreview(surface);
424 dynamicPaint_resetPreview(surface->canvas);
427 static int surface_totalSamples(DynamicPaintSurface *surface)
429 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ &&
430 surface->flags & MOD_DPAINT_ANTIALIAS)
432 return (surface->data->total_points * 5);
434 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
435 surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data)
437 return (surface->data->total_points + surface->data->adj_data->total_targets);
440 return surface->data->total_points;
443 static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], float s_alpha, float result[4])
446 float i_alpha = 1.0f - s_alpha;
447 float f_alpha = t_alpha * i_alpha + s_alpha;
451 for (i = 0; i < 3; i++) {
452 result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
456 copy_v3_v3(result, t_color);
458 /* return final alpha */
462 /* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */
463 static float mixColors(float a_color[3], float a_weight, float b_color[3], float b_weight, float ratio)
465 float weight_ratio, factor;
467 /* if first value has no weight just use b_color */
469 copy_v3_v3(a_color, b_color);
470 return b_weight * ratio;
472 weight_ratio = b_weight / (a_weight + b_weight);
474 else return a_weight * (1.0f - ratio);
476 /* calculate final interpolation factor */
478 factor = weight_ratio * (ratio * 2.0f);
481 ratio = (ratio * 2.0f - 1.0f);
482 factor = weight_ratio * (1.0f - ratio) + ratio;
484 /* mix final color */
485 interp_v3_v3v3(a_color, a_color, b_color, factor);
486 return (1.0f - factor) * a_weight + factor * b_weight;
489 /* set "ignore cache" flag for all caches on this object */
490 static void object_cacheIgnoreClear(Object *ob, int state)
494 BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
496 for (pid = pidlist.first; pid; pid = pid->next) {
499 pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
501 pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
505 BLI_freelistN(&pidlist);
508 static int subframe_updateObject(Scene *scene, Object *ob, int flags, float frame)
510 DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
513 /* if other is dynamic paint canvas, don't update */
514 if (pmd && pmd->canvas)
517 /* if object has parents, update them too */
518 if (flags & UPDATE_PARENTS) {
520 if (ob->parent) is_canvas += subframe_updateObject(scene, ob->parent, 0, frame);
521 if (ob->track) is_canvas += subframe_updateObject(scene, ob->track, 0, frame);
523 /* skip subframe if object is parented
524 * to vertex of a dynamic paint canvas */
525 if (is_canvas && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
528 /* also update constraint targets */
529 for (con = ob->constraints.first; con; con = con->next) {
530 bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
531 ListBase targets = {NULL, NULL};
533 if (cti && cti->get_constraint_targets) {
534 bConstraintTarget *ct;
535 cti->get_constraint_targets(con, &targets);
536 for (ct = targets.first; ct; ct = ct->next) {
538 subframe_updateObject(scene, ct->tar, 0, frame);
540 /* free temp targets */
541 if (cti->flush_constraint_targets)
542 cti->flush_constraint_targets(con, &targets, 0);
547 /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
548 ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
549 BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
550 if (flags & UPDATE_MESH) {
551 /* ignore cache clear during subframe updates
552 * to not mess up cache validity */
553 object_cacheIgnoreClear(ob, 1);
554 BKE_object_handle_update(scene, ob);
555 object_cacheIgnoreClear(ob, 0);
558 BKE_object_where_is_calc_time(scene, ob, frame);
560 /* for curve following objects, parented curve has to be updated too */
561 if (ob->type == OB_CURVE) {
562 Curve *cu = ob->data;
563 BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
565 /* and armatures... */
566 if (ob->type == OB_ARMATURE) {
567 bArmature *arm = ob->data;
568 BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
569 BKE_pose_where_is(scene, ob);
575 static void scene_setSubframe(Scene *scene, float subframe)
577 /* dynamic paint subframes must be done on previous frame */
579 scene->r.subframe = subframe;
582 static int surface_getBrushFlags(DynamicPaintSurface *surface, Scene *scene)
585 GroupObject *go = NULL;
586 Object *brushObj = NULL;
587 ModifierData *md = NULL;
591 if (surface->brush_group)
592 go = surface->brush_group->gobject.first;
594 base = scene->base.first;
600 if (surface->brush_group) {
601 if (go->ob) brushObj = go->ob;
604 brushObj = base->object;
607 if (surface->brush_group) go = go->next;
608 else base = base->next;
612 if (surface->brush_group)
617 md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
618 if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
619 DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
622 DynamicPaintBrushSettings *brush = pmd2->brush;
624 if (brush->flags & MOD_DPAINT_USES_VELOCITY)
625 flags |= BRUSH_USES_VELOCITY;
633 static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
635 return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!strcmp(scene->r.engine, "BLENDER_RENDER")));
638 /* check whether two bounds intersect */
639 static int boundsIntersect(Bounds3D *b1, Bounds3D *b2)
642 if (!b1->valid || !b2->valid) return 0;
643 for (; i >= 0; i -= 1)
644 if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i])) return 0;
648 /* check whether two bounds intersect inside defined proximity */
649 static int boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, float dist)
652 if (!b1->valid || !b2->valid) return 0;
653 for (; i >= 0; i -= 1)
654 if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist))) return 0;
658 /* check whether bounds intersects a point with given radius */
659 static int boundIntersectPoint(Bounds3D *b, float point[3], float radius)
662 if (!b->valid) return 0;
663 for (; i >= 0; i -= 1)
664 if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius))) return 0;
668 /* expand bounds by a new point */
669 static void boundInsert(Bounds3D *b, float point[3])
673 copy_v3_v3(b->min, point);
674 copy_v3_v3(b->max, point);
678 for (; i >= 0; i -= 1) {
679 if (point[i] < b->min[i]) b->min[i] = point[i];
680 if (point[i] > b->max[i]) b->max[i] = point[i];
685 static float getSurfaceDimension(PaintSurfaceData *sData)
687 Bounds3D *mb = &sData->bData->mesh_bounds;
688 return MAX3((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
691 static void freeGrid(PaintSurfaceData *data)
693 PaintBakeData *bData = data->bData;
694 VolumeGrid *grid = bData->grid;
696 if (grid->bounds) MEM_freeN(grid->bounds);
697 if (grid->s_pos) MEM_freeN(grid->s_pos);
698 if (grid->s_num) MEM_freeN(grid->s_num);
699 if (grid->t_index) MEM_freeN(grid->t_index);
701 MEM_freeN(bData->grid);
705 static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
707 PaintSurfaceData *sData = surface->data;
708 PaintBakeData *bData = sData->bData;
709 Bounds3D *grid_bounds;
711 int grid_cells, axis = 3;
712 int *temp_t_index = NULL;
713 int *temp_s_num = NULL;
716 int num_of_threads = omp_get_max_threads();
718 int num_of_threads = 1;
724 /* allocate separate bounds for each thread */
725 grid_bounds = MEM_callocN(sizeof(Bounds3D) * num_of_threads, "Grid Bounds");
726 bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
729 if (grid && grid_bounds) {
731 float dim_factor, volume, dim[3];
735 /* calculate canvas dimensions */
736 #pragma omp parallel for schedule(static)
737 for (i = 0; i < sData->total_points; i++) {
739 int id = omp_get_thread_num();
740 boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v));
742 boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v));
746 /* get final dimensions */
747 for (i = 0; i < num_of_threads; i++) {
748 boundInsert(&grid->grid_bounds, grid_bounds[i].min);
749 boundInsert(&grid->grid_bounds, grid_bounds[i].max);
753 sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
755 min_dim = MAX3(td[0], td[1], td[2]) / 1000.f;
757 /* deactivate zero axises */
758 for (i = 0; i < 3; i++) {
759 if (td[i] < min_dim) { td[i] = 1.0f; axis -= 1; }
762 if (axis == 0 || MAX3(td[0], td[1], td[2]) < 0.0001f) {
763 MEM_freeN(grid_bounds);
764 MEM_freeN(bData->grid);
769 /* now calculate grid volume/area/width depending on num of active axis */
770 volume = td[0] * td[1] * td[2];
772 /* determine final grid size by trying to fit average 10.000 points per grid cell */
773 dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis);
775 /* define final grid size using dim_factor, use min 3 for active axises */
776 for (i = 0; i < 3; i++) {
777 grid->dim[i] = (int)floor(td[i] / dim_factor);
778 CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
780 grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
782 /* allocate memory for grids */
783 grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
784 grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
785 grid->s_num = MEM_callocN(sizeof(int) * grid_cells * num_of_threads, "Surface Grid Points");
786 temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
787 grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
788 temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
790 /* in case of an allocation failure abort here */
791 if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
795 /* calculate number of points withing each cell */
796 #pragma omp parallel for schedule(static)
797 for (i = 0; i < sData->total_points; i++) {
799 for (j = 0; j < 3; j++) {
800 co[j] = (int)floor((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) / dim[j] * grid->dim[j]);
801 CLAMP(co[j], 0, grid->dim[j] - 1);
804 temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
806 grid->s_num[temp_t_index[i] + omp_get_thread_num() * grid_cells]++;
808 grid->s_num[temp_t_index[i]]++;
812 /* for first cell only calc s_num */
813 for (i = 1; i < num_of_threads; i++) {
814 grid->s_num[0] += grid->s_num[i * grid_cells];
817 /* calculate grid indexes */
818 for (i = 1; i < grid_cells; i++) {
820 for (id = 1; id < num_of_threads; id++) {
821 grid->s_num[i] += grid->s_num[i + id * grid_cells];
823 grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
826 /* save point indexes to final array */
827 for (i = 0; i < sData->total_points; i++) {
828 int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
829 grid->t_index[pos] = i;
831 temp_s_num[temp_t_index[i]]++;
834 /* calculate cell bounds */
837 #pragma omp parallel for schedule(static)
838 for (x = 0; x < grid->dim[0]; x++) {
840 for (y = 0; y < grid->dim[1]; y++) {
842 for (z = 0; z < grid->dim[2]; z++) {
843 int j, b_index = x + y * grid->dim[0] + z * grid->dim[0] * grid->dim[1];
845 for (j = 0; j < 3; j++) {
846 int s = (j == 0) ? x : ((j == 1) ? y : z);
847 grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * s;
848 grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid->dim[j] * (s + 1);
850 grid->bounds[b_index].valid = 1;
857 if (temp_s_num) MEM_freeN(temp_s_num);
858 if (temp_t_index) MEM_freeN(temp_t_index);
860 /* free per thread s_num values */
861 grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells);
863 if (error || !grid->s_num) {
864 setError(surface->canvas, N_("Not enough free memory"));
869 if (grid_bounds) MEM_freeN(grid_bounds);
872 /***************************** Freeing data ******************************/
874 /* Free brush data */
875 void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
879 pmd->brush->dm->release(pmd->brush->dm);
880 pmd->brush->dm = NULL;
882 if (pmd->brush->paint_ramp)
883 MEM_freeN(pmd->brush->paint_ramp);
884 pmd->brush->paint_ramp = NULL;
885 if (pmd->brush->vel_ramp)
886 MEM_freeN(pmd->brush->vel_ramp);
887 pmd->brush->vel_ramp = NULL;
889 MEM_freeN(pmd->brush);
894 static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
896 if (data->adj_data) {
897 if (data->adj_data->n_index) MEM_freeN(data->adj_data->n_index);
898 if (data->adj_data->n_num) MEM_freeN(data->adj_data->n_num);
899 if (data->adj_data->n_target) MEM_freeN(data->adj_data->n_target);
900 if (data->adj_data->flags) MEM_freeN(data->adj_data->flags);
901 MEM_freeN(data->adj_data);
902 data->adj_data = NULL;
906 static void free_bakeData(PaintSurfaceData *data)
908 PaintBakeData *bData = data->bData;
910 if (bData->bNormal) MEM_freeN(bData->bNormal);
911 if (bData->s_pos) MEM_freeN(bData->s_pos);
912 if (bData->s_num) MEM_freeN(bData->s_num);
913 if (bData->realCoord) MEM_freeN(bData->realCoord);
914 if (bData->bNeighs) MEM_freeN(bData->bNeighs);
915 if (bData->grid) freeGrid(data);
916 if (bData->prev_verts) MEM_freeN(bData->prev_verts);
917 if (bData->velocity) MEM_freeN(bData->velocity);
918 if (bData->prev_velocity) MEM_freeN(bData->prev_velocity);
920 MEM_freeN(data->bData);
925 /* free surface data if it's not used anymore */
926 static void surface_freeUnusedData(DynamicPaintSurface *surface)
928 if (!surface->data) return;
930 /* free bakedata if not active or surface is baked */
931 if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
932 (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED))
934 free_bakeData(surface->data);
938 void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
940 PaintSurfaceData *data = surface->data;
942 if (data->format_data) {
943 /* format specific free */
944 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
945 ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
946 if (format_data->uv_p)
947 MEM_freeN(format_data->uv_p);
948 if (format_data->barycentricWeights)
949 MEM_freeN(format_data->barycentricWeights);
951 MEM_freeN(data->format_data);
954 if (data->type_data) MEM_freeN(data->type_data);
955 dynamicPaint_freeAdjData(data);
959 MEM_freeN(surface->data);
960 surface->data = NULL;
963 void dynamicPaint_freeSurface(DynamicPaintSurface *surface)
966 BKE_ptcache_free_list(&(surface->ptcaches));
967 surface->pointcache = NULL;
969 if (surface->effector_weights)
970 MEM_freeN(surface->effector_weights);
971 surface->effector_weights = NULL;
973 BLI_remlink(&(surface->canvas->surfaces), surface);
974 dynamicPaint_freeSurfaceData(surface);
978 /* Free canvas data */
979 void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
982 /* Free surface data */
983 DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
984 DynamicPaintSurface *next_surface = NULL;
987 next_surface = surface->next;
988 dynamicPaint_freeSurface(surface);
989 surface = next_surface;
994 pmd->canvas->dm->release(pmd->canvas->dm);
995 pmd->canvas->dm = NULL;
997 MEM_freeN(pmd->canvas);
1002 /* Free whole dp modifier */
1003 void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd)
1006 dynamicPaint_freeCanvas(pmd);
1007 dynamicPaint_freeBrush(pmd);
1012 /***************************** Initialize and reset ******************************/
1015 * Creates a new surface and adds it to the list
1016 * If scene is null, frame range of 1-250 is used
1017 * A pointer to this surface is returned
1019 DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene)
1021 DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
1022 if (!surface) return NULL;
1024 surface->canvas = canvas;
1025 surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
1026 surface->type = MOD_DPAINT_SURFACE_T_PAINT;
1029 surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
1030 surface->pointcache->flag |= PTCACHE_DISK_CACHE;
1031 surface->pointcache->step = 1;
1033 /* Set initial values */
1034 surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG |
1035 MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
1036 surface->effect = 0;
1037 surface->effect_ui = 1;
1039 surface->diss_speed = 250;
1040 surface->dry_speed = 500;
1041 surface->color_dry_threshold = 1.0f;
1042 surface->depth_clamp = 0.0f;
1043 surface->disp_factor = 1.0f;
1044 surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
1045 surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
1047 surface->influence_scale = 1.0f;
1048 surface->radius_scale = 1.0f;
1050 surface->init_color[0] = 1.0f;
1051 surface->init_color[1] = 1.0f;
1052 surface->init_color[2] = 1.0f;
1053 surface->init_color[3] = 1.0f;
1055 surface->image_resolution = 256;
1056 surface->substeps = 0;
1059 surface->start_frame = scene->r.sfra;
1060 surface->end_frame = scene->r.efra;
1063 surface->start_frame = 1;
1064 surface->end_frame = 250;
1067 surface->spread_speed = 1.0f;
1068 surface->color_spread_speed = 1.0f;
1069 surface->shrink_speed = 1.0f;
1071 surface->wave_damping = 0.04f;
1072 surface->wave_speed = 1.0f;
1073 surface->wave_timescale = 1.0f;
1074 surface->wave_spring = 0.20f;
1076 modifier_path_init(surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
1078 dynamicPaintSurface_setUniqueName(surface, "Surface");
1080 surface->effector_weights = BKE_add_effector_weights(NULL);
1082 dynamicPaintSurface_updateType(surface);
1084 BLI_addtail(&canvas->surfaces, surface);
1090 * Initialize modifier data
1092 int dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
1095 if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
1096 DynamicPaintCanvasSettings *canvas;
1098 dynamicPaint_freeCanvas(pmd);
1100 canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas");
1106 /* Create one surface */
1107 if (!dynamicPaint_createNewSurface(canvas, scene))
1111 else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
1112 DynamicPaintBrushSettings *brush;
1114 dynamicPaint_freeBrush(pmd);
1116 brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
1123 brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
1124 brush->collision = MOD_DPAINT_COL_VOLUME;
1130 brush->alpha = 1.0f;
1131 brush->wetness = 1.0f;
1133 brush->paint_distance = 1.0f;
1134 brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH;
1136 brush->particle_radius = 0.2f;
1137 brush->particle_smooth = 0.05f;
1139 brush->wave_type = MOD_DPAINT_WAVEB_CHANGE;
1140 brush->wave_factor = 1.0f;
1141 brush->wave_clamp = 0.0f;
1142 brush->smudge_strength = 0.3f;
1143 brush->max_velocity = 1.0f;
1147 /* Paint proximity falloff colorramp. */
1151 brush->paint_ramp = add_colorband(0);
1152 if (!brush->paint_ramp)
1154 ramp = brush->paint_ramp->data;
1155 /* Add default smooth-falloff ramp. */
1156 ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
1158 ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
1160 pmd->brush->paint_ramp->tot = 2;
1163 /* Brush velocity ramp. */
1167 brush->vel_ramp = add_colorband(0);
1168 if (!brush->vel_ramp)
1170 ramp = brush->vel_ramp->data;
1171 ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
1172 ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
1173 brush->paint_ramp->tot = 2;
1183 void dynamicPaint_Modifier_copy(struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tpmd)
1186 tpmd->type = pmd->type;
1188 dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL);
1190 dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL);
1194 tpmd->canvas->pmd = tpmd;
1196 else if (tpmd->brush) {
1197 DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
1198 t_brush->pmd = tpmd;
1200 t_brush->flags = brush->flags;
1201 t_brush->collision = brush->collision;
1203 t_brush->mat = brush->mat;
1204 t_brush->r = brush->r;
1205 t_brush->g = brush->g;
1206 t_brush->b = brush->b;
1207 t_brush->alpha = brush->alpha;
1208 t_brush->wetness = brush->wetness;
1210 t_brush->particle_radius = brush->particle_radius;
1211 t_brush->particle_smooth = brush->particle_smooth;
1212 t_brush->paint_distance = brush->paint_distance;
1213 t_brush->psys = brush->psys;
1215 if (brush->paint_ramp)
1216 memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
1217 if (brush->vel_ramp)
1218 memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
1220 t_brush->proximity_falloff = brush->proximity_falloff;
1221 t_brush->wave_type = brush->wave_type;
1222 t_brush->ray_dir = brush->ray_dir;
1224 t_brush->wave_factor = brush->wave_factor;
1225 t_brush->wave_clamp = brush->wave_clamp;
1226 t_brush->max_velocity = brush->max_velocity;
1227 t_brush->smudge_strength = brush->smudge_strength;
1231 /* allocates surface data depending on surface type */
1232 static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
1234 PaintSurfaceData *sData = surface->data;
1236 switch (surface->type) {
1237 case MOD_DPAINT_SURFACE_T_PAINT:
1238 sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points, "DynamicPaintSurface Data");
1240 case MOD_DPAINT_SURFACE_T_DISPLACE:
1241 sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface DepthData");
1243 case MOD_DPAINT_SURFACE_T_WEIGHT:
1244 sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface WeightData");
1246 case MOD_DPAINT_SURFACE_T_WAVE:
1247 sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points, "DynamicPaintSurface WaveData");
1251 if (sData->type_data == NULL) setError(surface->canvas, N_("Not enough free memory"));
1254 static int surface_usesAdjDistance(DynamicPaintSurface *surface)
1256 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) return 1;
1257 if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) return 1;
1261 static int surface_usesAdjData(DynamicPaintSurface *surface)
1263 if (surface_usesAdjDistance(surface)) return 1;
1264 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
1265 surface->flags & MOD_DPAINT_ANTIALIAS)
1274 /* initialize surface adjacency data */
1275 static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, int force_init)
1277 PaintSurfaceData *sData = surface->data;
1278 DerivedMesh *dm = surface->canvas->dm;
1281 int neigh_points = 0;
1283 if (!surface_usesAdjData(surface) && !force_init) return;
1285 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1286 /* For vertex format, neighbors are connected by edges */
1287 neigh_points = 2 * dm->getNumEdges(dm);
1289 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
1290 neigh_points = sData->total_points * 8;
1292 if (!neigh_points) return;
1294 /* allocate memory */
1295 ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
1297 ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
1298 ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
1299 temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
1300 ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
1301 ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
1302 ad->total_targets = neigh_points;
1304 /* in case of allocation error, free memory */
1305 if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
1306 dynamicPaint_freeAdjData(sData);
1307 if (temp_data) MEM_freeN(temp_data);
1308 setError(surface->canvas, N_("Not enough free memory"));
1312 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1316 /* For vertex format, count every vertex that is connected by an edge */
1317 int numOfEdges = dm->getNumEdges(dm);
1318 int numOfPolys = dm->getNumPolys(dm);
1319 struct MEdge *edge = dm->getEdgeArray(dm);
1320 struct MPoly *mpoly = dm->getPolyArray(dm);
1321 struct MLoop *mloop = dm->getLoopArray(dm);
1323 /* count number of edges per vertex */
1324 for (i = 0; i < numOfEdges; i++) {
1325 ad->n_num[edge[i].v1]++;
1326 ad->n_num[edge[i].v2]++;
1328 temp_data[edge[i].v1]++;
1329 temp_data[edge[i].v2]++;
1332 /* also add number of vertices to temp_data
1333 * to locate points on "mesh edge" */
1334 for (i = 0; i < numOfPolys; i++) {
1336 for (; j < mpoly[i].totloop; j++) {
1337 temp_data[mloop[mpoly[i].loopstart + j].v]++;
1341 /* now check if total number of edges+faces for
1342 * each vertex is even, if not -> vertex is on mesh edge */
1343 for (i = 0; i < sData->total_points; i++) {
1344 if ((temp_data[i] % 2) ||
1347 ad->flags[i] |= ADJ_ON_MESH_EDGE;
1350 /* reset temp data */
1354 /* order n_index array */
1356 for (i = 0; i < sData->total_points; i++) {
1357 ad->n_index[i] = n_pos;
1358 n_pos += ad->n_num[i];
1361 /* and now add neighbor data using that info */
1362 for (i = 0; i < numOfEdges; i++) {
1364 int index = edge[i].v1;
1365 n_pos = ad->n_index[index] + temp_data[index];
1366 ad->n_target[n_pos] = edge[i].v2;
1371 n_pos = ad->n_index[index] + temp_data[index];
1372 ad->n_target[n_pos] = edge[i].v1;
1376 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1377 /* for image sequences, only allocate memory.
1378 * bake initialization takes care of rest */
1381 MEM_freeN(temp_data);
1384 static void dynamicPaint_setInitialColor(DynamicPaintSurface *surface)
1386 PaintSurfaceData *sData = surface->data;
1387 PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1388 DerivedMesh *dm = surface->canvas->dm;
1391 if (surface->type != MOD_DPAINT_SURFACE_T_PAINT)
1394 if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
1397 else if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
1398 /* apply color to every surface point */
1399 #pragma omp parallel for schedule(static)
1400 for (i = 0; i < sData->total_points; i++) {
1401 copy_v3_v3(pPoint[i].color, surface->init_color);
1402 pPoint[i].alpha = surface->init_color[3];
1405 /* UV mapped texture */
1406 else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
1407 Tex *tex = surface->init_texture;
1409 MFace *mface = dm->getTessFaceArray(dm);
1410 int numOfFaces = dm->getNumTessFaces(dm);
1411 char uvname[MAX_CUSTOMDATA_LAYER_NAME];
1416 CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->init_layername, uvname);
1417 tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
1420 /* for vertex surface loop through tfaces and find uv color
1421 * that provides highest alpha */
1422 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1423 #pragma omp parallel for schedule(static)
1424 for (i = 0; i < numOfFaces; i++) {
1425 int numOfVert = (mface[i].v4) ? 4 : 3;
1426 float uv[3] = {0.0f};
1428 for (j = 0; j < numOfVert; j++) {
1429 TexResult texres = {0};
1430 unsigned int *vert = (&mface[i].v1) + j;
1432 /* remap to -1.0 to 1.0 */
1433 uv[0] = tface[i].uv[j][0] * 2.0f - 1.0f;
1434 uv[1] = tface[i].uv[j][1] * 2.0f - 1.0f;
1436 multitex_ext_safe(tex, uv, &texres);
1438 if (texres.tin > pPoint[*vert].alpha) {
1439 copy_v3_v3(pPoint[*vert].color, &texres.tr);
1440 pPoint[*vert].alpha = texres.tin;
1445 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1446 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
1447 int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
1449 #pragma omp parallel for schedule(static)
1450 for (i = 0; i < sData->total_points; i++) {
1451 float uv[9] = {0.0f};
1452 float uv_final[3] = {0.0f};
1454 TexResult texres = {0};
1456 /* collect all uvs */
1457 for (j = 0; j < 3; j++) {
1458 int v = (f_data->uv_p[i].quad && j > 0) ? j + 1 : j;
1459 copy_v2_v2(&uv[j * 3], tface[f_data->uv_p[i].face_index].uv[v]);
1462 /* interpolate final uv pos */
1463 interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6],
1464 f_data->barycentricWeights[i * samples].v);
1465 /* remap to -1.0 to 1.0 */
1466 uv_final[0] = uv_final[0] * 2.0f - 1.0f;
1467 uv_final[1] = uv_final[1] * 2.0f - 1.0f;
1469 multitex_ext_safe(tex, uv_final, &texres);
1472 copy_v3_v3(pPoint[i].color, &texres.tr);
1473 pPoint[i].alpha = texres.tin;
1477 /* vertex color layer */
1478 else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
1480 /* for vertex surface, just copy colors from mcol */
1481 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1482 MLoop *mloop = dm->getLoopArray(dm);
1483 int numOfLoops = dm->getNumLoops(dm);
1484 MCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
1487 #pragma omp parallel for schedule(static)
1488 for (i = 0; i < numOfLoops; i++) {
1489 pPoint[mloop[i].v].color[0] = 1.0f / 255.f * (float)col[i].b;
1490 pPoint[mloop[i].v].color[1] = 1.0f / 255.f * (float)col[i].g;
1491 pPoint[mloop[i].v].color[2] = 1.0f / 255.f * (float)col[i].r;
1492 pPoint[mloop[i].v].alpha = 1.0f / 255.f * (float)col[i].a;
1495 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
1496 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
1497 int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
1498 MCol *col = CustomData_get_layer_named(&dm->faceData, CD_MCOL, surface->init_layername);
1501 #pragma omp parallel for schedule(static)
1502 for (i = 0; i < sData->total_points; i++) {
1503 int face_ind = f_data->uv_p[i].face_index;
1504 float colors[3][4] = {{0.0f, 0.0f, 0.0f, 0.0f}};
1505 float final_color[4];
1507 /* collect color values */
1508 for (j = 0; j < 3; j++) {
1509 int v = (f_data->uv_p[i].quad && j > 0) ? j + 1 : j;
1510 colors[j][0] = 1.0f / 255.f * (float)col[face_ind * 4 + v].b;
1511 colors[j][1] = 1.0f / 255.f * (float)col[face_ind * 4 + v].g;
1512 colors[j][2] = 1.0f / 255.f * (float)col[face_ind * 4 + v].r;
1513 colors[j][3] = 1.0f / 255.f * (float)col[face_ind * 4 + v].a;
1516 /* interpolate final color */
1517 interp_v4_v4v4v4(final_color, colors[0], colors[1], colors[2],
1518 f_data->barycentricWeights[i * samples].v);
1520 copy_v3_v3(pPoint[i].color, final_color);
1521 pPoint[i].alpha = final_color[3];
1527 /* clears surface data back to zero */
1528 void dynamicPaint_clearSurface(DynamicPaintSurface *surface)
1530 PaintSurfaceData *sData = surface->data;
1531 if (sData && sData->type_data) {
1532 unsigned int data_size;
1534 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
1535 data_size = sizeof(PaintPoint);
1536 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
1537 data_size = sizeof(PaintWavePoint);
1539 data_size = sizeof(float);
1541 memset(sData->type_data, 0, data_size * sData->total_points);
1543 /* set initial color */
1544 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
1545 dynamicPaint_setInitialColor(surface);
1548 sData->bData->clear = 1;
1552 /* completely (re)initializes surface (only for point cache types)*/
1553 int dynamicPaint_resetSurface(DynamicPaintSurface *surface)
1555 int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
1556 /* free existing data */
1557 if (surface->data) dynamicPaint_freeSurfaceData(surface);
1559 /* don't reallocate for image sequence types. they get handled only on bake */
1560 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return 1;
1561 if (numOfPoints < 1) return 0;
1563 /* allocate memory */
1564 surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
1565 if (!surface->data) return 0;
1567 /* allocate data depending on surface type and format */
1568 surface->data->total_points = numOfPoints;
1569 dynamicPaint_allocateSurfaceType(surface);
1570 dynamicPaint_initAdjacencyData(surface, 0);
1572 /* set initial color */
1573 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
1574 dynamicPaint_setInitialColor(surface);
1579 /* make sure allocated surface size matches current requirements */
1580 static int dynamicPaint_checkSurfaceData(DynamicPaintSurface *surface)
1582 if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
1583 return dynamicPaint_resetSurface(surface);
1589 /***************************** Modifier processing ******************************/
1592 /* apply displacing vertex surface to the derived mesh */
1593 static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
1595 PaintSurfaceData *sData = surface->data;
1597 if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX) return;
1599 /* displace paint */
1600 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
1601 MVert *mvert = result->getVertArray(result);
1603 float *value = (float *)sData->type_data;
1605 #pragma omp parallel for schedule(static)
1606 for (i = 0; i < sData->total_points; i++) {
1607 float normal[3], val = value[i] * surface->disp_factor;
1608 normal_short_to_float_v3(normal, mvert[i].no);
1609 normalize_v3(normal);
1611 mvert[i].co[0] -= normal[0] * val;
1612 mvert[i].co[1] -= normal[1] * val;
1613 mvert[i].co[2] -= normal[2] * val;
1619 * Apply canvas data to the object derived mesh
1621 static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
1625 DerivedMesh *result = CDDM_copy(dm);
1627 if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
1629 DynamicPaintSurface *surface;
1630 int update_normals = 0;
1632 /* loop through surfaces */
1633 for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
1634 PaintSurfaceData *sData = surface->data;
1636 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
1637 if (!(surface->flags & (MOD_DPAINT_ACTIVE))) continue;
1639 /* process vertex surface previews */
1640 if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
1642 /* vertex color paint */
1643 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
1646 PaintPoint *pPoint = (PaintPoint *)sData->type_data;
1647 MLoopCol *col = NULL;
1648 MLoop *mloop = CDDM_get_loops(result);
1649 int totloop = result->numLoopData;
1651 /* paint is stored on dry and wet layers, so mix final color first */
1652 float *fcolor = MEM_callocN(sizeof(float) * sData->total_points * 4, "Temp paint color");
1654 #pragma omp parallel for schedule(static)
1655 for (i = 0; i < sData->total_points; i++) {
1656 /* blend dry and wet layer */
1657 blendColors(pPoint[i].color, pPoint[i].alpha, pPoint[i].e_color, pPoint[i].e_alpha, &fcolor[i * 4]);
1660 /* viewport preview */
1661 if (surface->flags & MOD_DPAINT_PREVIEW) {
1662 MPoly *mp = CDDM_get_polys(result);
1663 int totpoly = result->numPolyData;
1666 /* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev
1667 * (after a SubSurf mod, eg)... */
1668 if (!result->getTessFaceDataArray(result, CD_PREVIEW_MCOL)) {
1669 int numFaces = result->getNumTessFaces(result);
1670 CustomData_add_layer(&result->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
1674 /* Save preview results to weight layer to be
1675 * able to share same drawing methods */
1676 col = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
1678 col = CustomData_add_layer(&result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC,
1682 #pragma omp parallel for schedule(static)
1683 for (i = 0; i < totpoly; i++) {
1685 Material *material = give_current_material(ob, mp[i].mat_nr + 1);
1687 for (; j < mp[i].totloop; j++) {
1688 int l_index = mp[i].loopstart + j;
1689 int v_index = mloop[l_index].v;
1691 if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
1695 /* Apply material color as base vertex color for preview */
1696 col[l_index].a = 255;
1702 else { /* default gray */
1707 /* mix surface color */
1708 interp_v3_v3v3(c, c, &fcolor[v_index], fcolor[v_index + 3]);
1710 rgb_float_to_uchar((unsigned char *)&col[l_index].r, c);
1715 col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
1716 col[l_index].a = 255;
1724 /* save layer data to output layer */
1727 col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
1728 /* if output layer is lost from a constructive modifier, re-add it */
1729 if (!col && dynamicPaint_outputLayerExists(surface, ob, 0))
1730 col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
1733 #pragma omp parallel for schedule(static)
1734 for (i = 0; i < totloop; i++) {
1735 int index = mloop[i].v * 4;
1736 rgb_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
1737 col[i].a = FTOCHAR(fcolor[index + 3]); /* IS THIS NEEDED? */
1744 col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
1745 /* if output layer is lost from a constructive modifier, re-add it */
1746 if (!col && dynamicPaint_outputLayerExists(surface, ob, 1))
1747 col = CustomData_add_layer_named(&result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
1750 #pragma omp parallel for schedule(static)
1751 for (i = 0; i < totloop; i++) {
1752 int index = mloop[i].v;
1755 col[i].b = FTOCHAR(pPoint[index].wetness);
1760 /* Mark tessellated CD layers as dirty. */
1761 result->dirty |= DM_DIRTY_TESS_CDLAYERS;
1763 /* vertex group paint */
1764 else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
1765 int defgrp_index = defgroup_name_index(ob, surface->output_name);
1766 MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT);
1767 float *weight = (float *)sData->type_data;
1769 /* viewport preview */
1770 if (surface->flags & MOD_DPAINT_PREVIEW) {
1771 /* Save preview results to weight layer to be
1772 * able to share same drawing methods.
1773 * Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
1774 DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
1777 /* apply weights into a vertex group, if doesnt exists add a new layer */
1778 if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0'))
1779 dvert = CustomData_add_layer_named(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
1780 NULL, sData->total_points, surface->output_name);
1781 if (defgrp_index != -1 && dvert) {
1783 for (i = 0; i < sData->total_points; i++) {
1784 MDeformVert *dv = &dvert[i];
1785 MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index);
1787 /* skip if weight value is 0 and no existing weight is found */
1788 if ((def_weight != NULL) || (weight[i] != 0.0f)) {
1790 /* if not found, add a weight for it */
1791 if (def_weight == NULL) {
1792 def_weight = defvert_verify_index(dv, defgrp_index);
1795 /* set weight value */
1796 def_weight->weight = weight[i];
1801 /* wave simulation */
1802 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
1803 MVert *mvert = result->getVertArray(result);
1805 PaintWavePoint *wPoint = (PaintWavePoint *)sData->type_data;
1807 #pragma omp parallel for schedule(static)
1808 for (i = 0; i < sData->total_points; i++) {
1810 normal_short_to_float_v3(normal, mvert[i].no);
1811 madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
1817 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
1818 dynamicPaint_applySurfaceDisplace(surface, result);
1826 CDDM_calc_normals(result);
1828 /* make a copy of dm to use as brush data */
1830 if (pmd->brush->dm) pmd->brush->dm->release(pmd->brush->dm);
1831 pmd->brush->dm = CDDM_copy(result);
1837 /* update cache frame range */
1838 void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
1840 if (surface->pointcache) {
1841 surface->pointcache->startframe = surface->start_frame;
1842 surface->pointcache->endframe = surface->end_frame;
1846 static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm)
1849 canvas->dm->release(canvas->dm);
1852 canvas->dm = CDDM_copy(dm);
1856 * Updates derived mesh copy and processes dynamic paint step / caches.
1858 static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
1861 DynamicPaintCanvasSettings *canvas = pmd->canvas;
1862 DynamicPaintSurface *surface = canvas->surfaces.first;
1864 /* update derived mesh copy */
1865 canvas_copyDerivedMesh(canvas, dm);
1867 /* in case image sequence baking, stop here */
1868 if (canvas->flags & MOD_DPAINT_BAKING) return;
1870 /* loop through surfaces */
1871 for (; surface; surface = surface->next) {
1872 int current_frame = (int)scene->r.cfra;
1874 /* free bake data if not required anymore */
1875 surface_freeUnusedData(surface);
1877 /* image sequences are handled by bake operator */
1878 if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) continue;
1879 if (!(surface->flags & MOD_DPAINT_ACTIVE)) continue;
1881 /* make sure surface is valid */
1882 if (!dynamicPaint_checkSurfaceData(surface)) continue;
1884 /* limit frame range */
1885 CLAMP(current_frame, surface->start_frame, surface->end_frame);
1887 if (current_frame != surface->current_frame || (int)scene->r.cfra == surface->start_frame) {
1888 PointCache *cache = surface->pointcache;
1890 surface->current_frame = current_frame;
1892 /* read point cache */
1893 BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
1894 pid.cache->startframe = surface->start_frame;
1895 pid.cache->endframe = surface->end_frame;
1896 BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
1898 /* reset non-baked cache at first frame */
1899 if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
1900 cache->flag |= PTCACHE_REDO_NEEDED;
1901 BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
1902 cache->flag &= ~PTCACHE_REDO_NEEDED;
1905 /* try to read from cache */
1906 if (BKE_ptcache_read(&pid, (float)scene->r.cfra)) {
1907 BKE_ptcache_validate(cache, (int)scene->r.cfra);
1909 /* if read failed and we're on surface range do recalculate */
1910 else if ((int)scene->r.cfra == current_frame && !(cache->flag & PTCACHE_BAKED)) {
1911 /* calculate surface frame */
1912 canvas->flags |= MOD_DPAINT_BAKING;
1913 dynamicPaint_calculateFrame(surface, scene, ob, current_frame);
1914 canvas->flags &= ~MOD_DPAINT_BAKING;
1916 /* restore canvas derivedmesh if required */
1917 if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
1918 surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
1920 canvas_copyDerivedMesh(canvas, dm);
1923 BKE_ptcache_validate(cache, surface->current_frame);
1924 BKE_ptcache_write(&pid, surface->current_frame);
1931 /* Modifier call. Processes dynamic paint modifier step. */
1932 DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
1934 /* For now generate tessfaces in every case
1935 * XXX - move/remove when most of dpaint functions are converted to use bmesh types */
1936 DM_ensure_tessface(dm);
1938 /* Update canvas data for a new frame */
1939 dynamicPaint_frameUpdate(pmd, scene, ob, dm);
1941 /* Return output mesh */
1942 return dynamicPaint_Modifier_apply(pmd, ob, dm);
1946 /***************************** Image Sequence / UV Image Surface Calls ******************************/
1949 * Tries to find the neighboring pixel in given (uv space) direction.
1950 * Result is used by effect system to move paint on the surface.
1952 * px, py : origin pixel x and y
1953 * n_index : lookup direction index (use neighX, neighY to get final index)
1955 static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm,
1956 const char *uvname, int w, int h, int px, int py, int n_index)
1958 /* Note: Current method only uses polygon edges to detect neighboring pixels.
1959 * -> It doesn't always lead to the optimum pixel but is accurate enough
1960 * and faster/simpler than including possible face tip point links)
1964 PaintUVPoint *tPoint = NULL;
1965 PaintUVPoint *cPoint = NULL;
1967 /* shift position by given n_index */
1968 x = px + neighX[n_index];
1969 y = py + neighY[n_index];
1971 if (x < 0 || x >= w) return OUT_OF_TEXTURE;
1972 if (y < 0 || y >= h) return OUT_OF_TEXTURE;
1974 tPoint = &tempPoints[x + w * y]; /* UV neighbor */
1975 cPoint = &tempPoints[px + w * py]; /* Origin point */
1978 * Check if shifted point is on same face -> it's a correct neighbor
1979 * (and if it isn't marked as an "edge pixel")
1981 if ((tPoint->face_index == cPoint->face_index) && (tPoint->neighbour_pixel == -1))
1985 * Even if shifted point is on another face
1986 * -> use this point.
1988 * !! Replace with "is uv faces linked" check !!
1989 * This should work fine as long as uv island
1990 * margin is > 1 pixel.
1992 if ((tPoint->face_index != -1) && (tPoint->neighbour_pixel == -1)) {
1997 * If we get here, the actual neighboring pixel
1998 * is located on a non-linked uv face, and we have to find
1999 * it's "real" position.
2001 * Simple neighboring face finding algorithm:
2002 * - find closest uv edge to shifted pixel and get
2003 * the another face that shares that edge
2004 * - find corresponding position of that new face edge
2007 * TODO: Implement something more accurate / optimized?
2010 int numOfFaces = dm->getNumTessFaces(dm);
2011 MFace *mface = dm->getTessFaceArray(dm);
2012 MTFace *tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
2014 /* Get closest edge to that subpixel on UV map */
2017 /* distances only used for comparison */
2018 float dist_squared, t_dist_squared;
2020 int i, uindex[3], edge1_index, edge2_index,
2021 e1_index, e2_index, target_face;
2022 float closest_point[2], lambda, dir_vec[2];
2023 int target_uv1, target_uv2, final_pixel[2], final_index;
2025 float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
2027 pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
2028 pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
2030 /* Get uv indexes for current face part */
2032 uindex[0] = 0; uindex[1] = 2; uindex[2] = 3;
2035 uindex[0] = 0; uindex[1] = 1; uindex[2] = 2;
2039 * Find closest edge to that pixel
2041 /* Dist to first edge */
2042 e1_index = cPoint->v1; e2_index = cPoint->v2; edge1_index = uindex[0]; edge2_index = uindex[1];
2043 dist_squared = dist_squared_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]);
2045 /* Dist to second edge */
2046 t_dist_squared = dist_squared_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[1]], tface[cPoint->face_index].uv[uindex[2]]);
2047 if (t_dist_squared < dist_squared) { e1_index = cPoint->v2; e2_index = cPoint->v3; edge1_index = uindex[1]; edge2_index = uindex[2]; dist_squared = t_dist_squared; }
2049 /* Dist to third edge */
2050 t_dist_squared = dist_squared_to_line_segment_v2(pixel, tface[cPoint->face_index].uv[uindex[2]], tface[cPoint->face_index].uv[uindex[0]]);
2051 if (t_dist_squared < dist_squared) { e1_index = cPoint->v3; e2_index = cPoint->v1; edge1_index = uindex[2]; edge2_index = uindex[0]; dist_squared = t_dist_squared; }
2055 * Now find another face that is linked to that edge
2059 for (i = 0; i < numOfFaces; i++) {
2061 * Check if both edge vertices share this face
2063 int v4 = (mface[i].v4) ? mface[i].v4 : -1;
2065 if ((e1_index == mface[i].v1 || e1_index == mface[i].v2 || e1_index == mface[i].v3 || e1_index == v4) &&
2066 (e2_index == mface[i].v1 || e2_index == mface[i].v2 || e2_index == mface[i].v3 || e2_index == v4))
2068 if (i == cPoint->face_index) continue;
2075 if (e1_index == mface[i].v1) target_uv1 = 0;
2076 else if (e1_index == mface[i].v2) target_uv1 = 1;
2077 else if (e1_index == mface[i].v3) target_uv1 = 2;
2078 else target_uv1 = 3;
2080 if (e2_index == mface[i].v1) target_uv2 = 0;
2081 else if (e2_index == mface[i].v2) target_uv2 = 1;
2082 else if (e2_index == mface[i].v3) target_uv2 = 2;
2083 else target_uv2 = 3;
2089 /* If none found pixel is on mesh edge */
2090 if (target_face == -1) return ON_MESH_EDGE;
2093 * If target face is connected in UV space as well, just use original index
2095 s_uv1 = (float *)tface[cPoint->face_index].uv[edge1_index];
2096 s_uv2 = (float *)tface[cPoint->face_index].uv[edge2_index];
2097 t_uv1 = (float *)tface[target_face].uv[target_uv1];
2098 t_uv2 = (float *)tface[target_face].uv[target_uv2];
2100 //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
2102 if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
2103 (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
2104 ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
2105 (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) ))
2107 return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
2111 * Find a point that is relatively at same edge position
2112 * on this other face UV
2114 lambda = closest_to_line_v2(closest_point, pixel, tface[cPoint->face_index].uv[edge1_index], tface[cPoint->face_index].uv[edge2_index]);
2115 if (lambda < 0.0f) lambda = 0.0f;
2116 if (lambda > 1.0f) lambda = 1.0f;
2118 sub_v2_v2v2(dir_vec, tface[target_face].uv[target_uv2], tface[target_face].uv[target_uv1]);
2120 mul_v2_fl(dir_vec, lambda);
2122 copy_v2_v2(pixel, tface[target_face].uv[target_uv1]);
2123 add_v2_v2(pixel, dir_vec);
2124 pixel[0] = (pixel[0] * (float)w) - 0.5f;
2125 pixel[1] = (pixel[1] * (float)h) - 0.5f;
2127 final_pixel[0] = (int)floor(pixel[0]);
2128 final_pixel[1] = (int)floor(pixel[1]);
2130 /* If current pixel uv is outside of texture */
2131 if (final_pixel[0] < 0 || final_pixel[0] >= w) return OUT_OF_TEXTURE;
2132 if (final_pixel[1] < 0 || final_pixel[1] >= h) return OUT_OF_TEXTURE;
2134 final_index = final_pixel[0] + w * final_pixel[1];
2136 /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
2137 if (final_index == (px + w * py)) return NOT_FOUND;
2138 /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
2139 if (tempPoints[final_index].face_index != target_face) return NOT_FOUND;
2142 * If final point is an "edge pixel", use it's "real" neighbor instead
2144 if (tempPoints[final_index].neighbour_pixel != -1) final_index = cPoint->neighbour_pixel;
2152 * Create a surface for uv image sequence format
2154 int dynamicPaint_createUVSurface(DynamicPaintSurface *surface)
2156 /* Antialias jitter point relative coords */
2157 float jitter5sample[10] = {0.0f, 0.0f,
2165 char uvname[MAX_CUSTOMDATA_LAYER_NAME];
2166 int active_points = 0;
2169 PaintSurfaceData *sData;
2170 DynamicPaintCanvasSettings *canvas = surface->canvas;
2171 DerivedMesh *dm = canvas->dm;
2173 PaintUVPoint *tempPoints = NULL;
2174 Vec3f *tempWeights = NULL;
2175 MFace *mface = NULL;
2176 MTFace *tface = NULL;
2177 Bounds2D *faceBB = NULL;
2182 return setError(canvas, N_("Canvas mesh not updated"));
2183 if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
2184 return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
2186 numOfFaces = dm->getNumTessFaces(dm);
2187 mface = dm->getTessFaceArray(dm);
2190 CustomData_validate_layer_name(&dm->faceData, CD_MTFACE, surface->uvlayer_name, uvname);
2191 tface = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname);
2193 /* Check for validity */
2195 return setError(canvas, N_("No UV data on canvas"));
2196 if (surface->image_resolution < 16 || surface->image_resolution > 8192)
2197 return setError(canvas, N_("Invalid resolution"));
2199 w = h = surface->image_resolution;
2202 * Start generating the surface
2204 printf("DynamicPaint: Preparing UV surface of %ix%i pixels and %i faces.\n", w, h, numOfFaces);
2206 /* Init data struct */
2207 if (surface->data) dynamicPaint_freeSurfaceData(surface);
2208 sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
2210 return setError(canvas, N_("Not enough free memory"));
2212 aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
2213 tempPoints = (struct PaintUVPoint *) MEM_callocN(w * h * sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
2214 if (!tempPoints) error = 1;
2216 final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
2217 if (!final_index) error = 1;
2219 tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
2220 if (!tempWeights) error = 1;
2223 * Generate a temporary bounding box array for UV faces to optimize
2224 * the pixel-inside-a-face search.
2227 faceBB = (struct Bounds2D *) MEM_mallocN(numOfFaces * sizeof(struct Bounds2D), "MPCanvasFaceBB");
2228 if (!faceBB) error = 1;
2232 for (ty = 0; ty < numOfFaces; ty++) {
2233 int numOfVert = (mface[ty].v4) ? 4 : 3;
2236 copy_v2_v2(faceBB[ty].min, tface[ty].uv[0]);
2237 copy_v2_v2(faceBB[ty].max, tface[ty].uv[0]);
2239 for (i = 1; i < numOfVert; i++) {
2240 if (tface[ty].uv[i][0] < faceBB[ty].min[0]) faceBB[ty].min[0] = tface[ty].uv[i][0];
2241 if (tface[ty].uv[i][1] < faceBB[ty].min[1]) faceBB[ty].min[1] = tface[ty].uv[i][1];
2242 if (tface[ty].uv[i][0] > faceBB[ty].max[0]) faceBB[ty].max[0] = tface[ty].uv[i][0];
2243 if (tface[ty].uv[i][1] > faceBB[ty].max[1]) faceBB[ty].max[1] = tface[ty].uv[i][1];
2249 * Loop through every pixel and check
2250 * if pixel is uv-mapped on a canvas face.
2253 #pragma omp parallel for schedule(static)
2254 for (ty = 0; ty < h; ty++) {
2256 for (tx = 0; tx < w; tx++) {
2258 int index = tx + w * ty;
2259 PaintUVPoint *tPoint = (&tempPoints[index]);
2261 short isInside = 0; /* if point is inside a uv face */
2263 float d1[2], d2[2], d3[2], point[5][2];
2264 float dot00, dot01, dot02, dot11, dot12, invDenom, u, v;
2266 /* Init per pixel settings */
2267 tPoint->face_index = -1;
2268 tPoint->neighbour_pixel = -1;
2269 tPoint->pixel_index = index;
2271 /* Actual pixel center, used when collision is found */
2272 point[0][0] = ((float)tx + 0.5f) / w;
2273 point[0][1] = ((float)ty + 0.5f) / h;
2276 * A pixel middle sample isn't enough to find very narrow polygons
2277 * So using 4 samples of each corner too
2279 point[1][0] = ((float)tx) / w;
2280 point[1][1] = ((float)ty) / h;
2282 point[2][0] = ((float)tx + 1) / w;
2283 point[2][1] = ((float)ty) / h;
2285 point[3][0] = ((float)tx) / w;
2286 point[3][1] = ((float)ty + 1) / h;
2288 point[4][0] = ((float)tx + 1) / w;
2289 point[4][1] = ((float)ty + 1) / h;
2292 /* Loop through samples, starting from middle point */
2293 for (sample = 0; sample < 5; sample++) {
2295 /* Loop through every face in the mesh */
2296 for (i = 0; i < numOfFaces; i++) {
2299 if (faceBB[i].min[0] > (point[sample][0])) continue;
2300 if (faceBB[i].min[1] > (point[sample][1])) continue;
2301 if (faceBB[i].max[0] < (point[sample][0])) continue;
2302 if (faceBB[i].max[1] < (point[sample][1])) continue;
2304 /* Calculate point inside a triangle check
2306 sub_v2_v2v2(d1, tface[i].uv[2], tface[i].uv[0]); // uv2 - uv0
2307 sub_v2_v2v2(d2, tface[i].uv[1], tface[i].uv[0]); // uv1 - uv0
2308 sub_v2_v2v2(d3, point[sample], tface[i].uv[0]); // point - uv0
2310 dot00 = d1[0] * d1[0] + d1[1] * d1[1];
2311 dot01 = d1[0] * d2[0] + d1[1] * d2[1];
2312 dot02 = d1[0] * d3[0] + d1[1] * d3[1];
2313 dot11 = d2[0] * d2[0] + d2[1] * d2[1];
2314 dot12 = d2[0] * d3[0] + d2[1] * d3[1];
2316 invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
2317 u = (dot11 * dot02 - dot01 * dot12) * invDenom;
2318 v = (dot00 * dot12 - dot01 * dot02) * invDenom;
2320 if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = 1; } /* is inside a triangle */
2322 /* If collision wasn't found but the face is a quad
2323 * do another check for the second half */
2324 if ((!isInside) && mface[i].v4) {
2326 /* change d2 to test the other half */
2327 sub_v2_v2v2(d2, tface[i].uv[3], tface[i].uv[0]); // uv3 - uv0
2330 dot00 = d1[0] * d1[0] + d1[1] * d1[1];
2331 dot01 = d1[0] * d2[0] + d1[1] * d2[1];
2332 dot02 = d1[0] * d3[0] + d1[1] * d3[1];
2333 dot11 = d2[0] * d2[0] + d2[1] * d2[1];
2334 dot12 = d2[0] * d3[0] + d2[1] * d3[1];
2336 invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
2337 u = (dot11 * dot02 - dot01 * dot12) * invDenom;
2338 v = (dot00 * dot12 - dot01 * dot02) * invDenom;
2340 if ((u > 0) && (v > 0) && (u + v < 1)) { isInside = 2; } /* is inside the second half of the quad */
2345 * If point was inside the face
2347 if (isInside != 0) {
2349 float uv1co[2], uv2co[2], uv3co[2], uv[2];
2352 /* Get triagnle uvs */
2353 if (isInside == 1) {
2354 copy_v2_v2(uv1co, tface[i].uv[0]);
2355 copy_v2_v2(uv2co, tface[i].uv[1]);
2356 copy_v2_v2(uv3co, tface[i].uv[2]);
2359 copy_v2_v2(uv1co, tface[i].uv[0]);
2360 copy_v2_v2(uv2co, tface[i].uv[2]);
2361 copy_v2_v2(uv3co, tface[i].uv[3]);
2364 /* Add b-weights per anti-aliasing sample */
2365 for (j = 0; j < aa_samples; j++) {
2366 uv[0] = point[0][0] + jitter5sample[j * 2] / w;
2367 uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
2369 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
2372 /* Set surface point face values */
2373 tPoint->face_index = i; /* face index */
2374 tPoint->quad = (isInside == 2) ? 1 : 0; /* quad or tri part*/
2376 /* save vertex indexes */
2377 tPoint->v1 = mface[i].v1;
2378 tPoint->v2 = (isInside == 2) ? mface[i].v3 : mface[i].v2;
2379 tPoint->v3 = (isInside == 2) ? mface[i].v4 : mface[i].v3;
2381 sample = 5; /* make sure we exit sample loop as well */
2390 * Now loop through every pixel that was left without index
2391 * and find if they have neighboring pixels that have an index.
2392 * If so use that polygon as pixel surface.
2393 * (To avoid seams on uv island edges)
2395 #pragma omp parallel for schedule(static)
2396 for (ty = 0; ty < h; ty++) {
2398 for (tx = 0; tx < w; tx++) {
2399 int index = tx + w * ty;
2400 PaintUVPoint *tPoint = (&tempPoints[index]);
2402 /* If point isn't't on canvas mesh */
2403 if (tPoint->face_index == -1) {
2404 int u_min, u_max, v_min, v_max;
2409 u_min = (tx > 0) ? -1 : 0;
2410 u_max = (tx < (w - 1)) ? 1 : 0;
2411 v_min = (ty > 0) ? -1 : 0;
2412 v_max = (ty < (h - 1)) ? 1 : 0;
2414 point[0] = ((float)tx + 0.5f) / w;
2415 point[1] = ((float)ty + 0.5f) / h;
2417 /* search through defined area for neighbor */
2418 for (u = u_min; u <= u_max; u++)
2419 for (v = v_min; v <= v_max; v++) {
2420 /* if not this pixel itself */
2421 if (u != 0 || v != 0) {
2422 ind = (tx + u) + w * (ty + v);
2424 /* if neighbor has index */
2425 if (tempPoints[ind].face_index != -1) {
2427 float uv1co[2], uv2co[2], uv3co[2], uv[2];
2428 int i = tempPoints[ind].face_index, j;
2430 /* Now calculate pixel data for this pixel as it was on polygon surface */
2431 if (!tempPoints[ind].quad) {
2432 copy_v2_v2(uv1co, tface[i].uv[0]);
2433 copy_v2_v2(uv2co, tface[i].uv[1]);
2434 copy_v2_v2(uv3co, tface[i].uv[2]);
2437 copy_v2_v2(uv1co, tface[i].uv[0]);
2438 copy_v2_v2(uv2co, tface[i].uv[2]);
2439 copy_v2_v2(uv3co, tface[i].uv[3]);
2442 /* Add b-weights per anti-aliasing sample */
2443 for (j = 0; j < aa_samples; j++) {
2445 uv[0] = point[0] + jitter5sample[j * 2] / w;
2446 uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
2447 barycentric_weights_v2(uv1co, uv2co, uv3co, uv, tempWeights[index * aa_samples + j].v);
2451 tPoint->neighbour_pixel = ind; // face index
2452 tPoint->quad = tempPoints[ind].quad; // quad or tri
2454 /* save vertex indexes */
2455 tPoint->v1 = mface[i].v1;
2456 tPoint->v2 = (tPoint->quad) ? mface[i].v3 : mface[i].v2;
2457 tPoint->v3 = (tPoint->quad) ? mface[i].v4 : mface[i].v3;
2459 u = u_max + 1; /* make sure we exit outer loop as well */
2469 * When base loop is over convert found neighbor indexes to real ones
2470 * Also count the final number of active surface points
2472 for (ty = 0; ty < h; ty++) {
2474 for (tx = 0; tx < w; tx++) {
2475 int index = tx + w * ty;
2476 PaintUVPoint *tPoint = (&tempPoints[index]);
2478 if (tPoint->face_index == -1 && tPoint->neighbour_pixel != -1) tPoint->face_index = tempPoints[tPoint->neighbour_pixel].face_index;
2479 if (tPoint->face_index != -1) active_points++;
2483 /* Generate surface adjacency data. */
2487 /* Create a temporary array of final indexes (before unassigned
2488 * pixels have been dropped) */
2489 for (i = 0; i < w * h; i++) {
2490 if (tempPoints[i].face_index != -1) {
2491 final_index[i] = cursor;
2495 /* allocate memory */
2496 sData->total_points = w * h;
2497 dynamicPaint_initAdjacencyData(surface, 1);
2499 if (sData->adj_data) {
2500 PaintAdjData *ed = sData->adj_data;
2501 unsigned int n_pos = 0;
2502 for (ty = 0; ty < h; ty++) {
2504 for (tx = 0; tx < w; tx++) {
2505 int i, index = tx + w * ty;
2507 if (tempPoints[index].face_index != -1) {
2508 ed->n_index[final_index[index]] = n_pos;
2509 ed->n_num[final_index[index]] = 0;
2511 for (i = 0; i < 8; i++) {
2513 /* Try to find a neighboring pixel in defined direction
2514 * If not found, -1 is returned */
2515 int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, i);
2517 if (n_target >= 0) {
2518 ed->n_target[n_pos] = final_index[n_target];
2519 ed->n_num[final_index[index]]++;
2522 else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
2523 ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
2532 /* Create final surface data without inactive points */
2534 ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
2536 f_data->uv_p = MEM_callocN(active_points * sizeof(struct PaintUVPoint), "PaintUVPoint");
2537 f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(struct Vec3f), "PaintUVPoint");
2539 if (!f_data->uv_p || !f_data->barycentricWeights) error = 1;
2543 sData->total_points = active_points;
2545 /* in case of allocation error, free everything */
2548 if (f_data->uv_p) MEM_freeN(f_data->uv_p);
2549 if (f_data->barycentricWeights) MEM_freeN(f_data->barycentricWeights);
2554 int index, cursor = 0;
2555 sData->total_points = active_points;
2556 sData->format_data = f_data;
2558 for (index = 0; index < (w * h); index++) {
2559 if (tempPoints[index].face_index != -1) {
2560 memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
2561 memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples], sizeof(Vec3f) * aa_samples);
2569 setError(canvas, N_("Not enough free memory"));
2571 if (faceBB) MEM_freeN(faceBB);
2572 if (tempPoints) MEM_freeN(tempPoints);
2573 if (tempWeights) MEM_freeN(tempWeights);
2574 if (final_index) MEM_freeN(final_index);
2576 /* Init surface type data */
2578 dynamicPaint_allocateSurfaceType(surface);
2581 /* -----------------------------------------------------------------
2582 * For debug, output pixel statuses to the color map
2583 * -----------------------------------------------------------------*/
2584 #pragma omp parallel for schedule(static)
2585 for (index = 0; index < sData->total_points; index++)
2587 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
2588 PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
2589 PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
2590 pPoint->alpha = 1.0f;
2592 /* Every pixel that is assigned as "edge pixel" gets blue color */
2593 if (uvPoint->neighbour_pixel != -1) pPoint->color[2] = 1.0f;
2594 /* and every pixel that finally got an polygon gets red color */
2595 if (uvPoint->face_index != -1) pPoint->color[0] = 1.0f;
2596 /* green color shows pixel face index hash */
2597 if (uvPoint->face_index != -1) pPoint->color[1] = (float)(uvPoint->face_index % 255) / 256.0f;
2601 dynamicPaint_setInitialColor(surface);
2604 return (error == 0);
2608 * Outputs an image file from uv surface data.
2610 void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
2614 PaintSurfaceData *sData = surface->data;
2615 ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
2616 /* OpenEXR or PNG */
2617 int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
2618 char output_file[FILE_MAX];
2620 if (!sData->type_data) {
2621 setError(surface->canvas, N_("Image save failed: invalid surface"));
2624 /* if selected format is openexr, but current build doesnt support one */
2625 #ifndef WITH_OPENEXR
2626 if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG;
2628 BLI_strncpy(output_file, filename, sizeof(output_file));
2629 BKE_add_image_extension(output_file, format);
2631 /* Validate output file path */
2632 BLI_path_abs(output_file, G.main->name);
2633 BLI_make_existing_file(output_file);
2635 /* Init image buffer */
2636 ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
2638 setError(surface->canvas, N_("Image save failed: not enough free memory"));
2642 #pragma omp parallel for schedule(static)
2643 for (index = 0; index < sData->total_points; index++) {
2644 int pos = f_data->uv_p[index].pixel_index * 4; /* image buffer position */
2646 /* Set values of preferred type */
2647 if (output_layer == 1) {
2649 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
2650 PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
2651 float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
2653 ibuf->rect_float[pos] = value;
2654 ibuf->rect_float[pos + 1] = value;
2655 ibuf->rect_float[pos + 2] = value;
2656 ibuf->rect_float[pos + 3] = 1.0f;
2659 else if (output_layer == 0) {
2661 if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
2662 PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
2664 /* blend wet and dry layers */
2665 blendColors(point->color, point->alpha, point->e_color, point->e_alpha, &ibuf->rect_float[pos]);
2667 /* Multiply color by alpha if enabled */
2668 if (surface->flags & MOD_DPAINT_MULALPHA) {
2669 ibuf->rect_float[pos] *= ibuf->rect_float[pos + 3];
2670 ibuf->rect_float[pos + 1] *= ibuf->rect_float[pos + 3];
2671 ibuf->rect_float[pos + 2] *= ibuf->rect_float[pos + 3];
2675 else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
2676 float depth = ((float *)sData->type_data)[index];
2677 if (surface->depth_clamp)
2678 depth /= surface->depth_clamp;
2680 if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
2681 depth = (0.5f - depth / 2.0f);
2684 CLAMP(depth, 0.0f, 1.0f);
2686 ibuf->rect_float[pos] = depth;
2687 ibuf->rect_float[pos + 1] = depth;
2688 ibuf->rect_float[pos + 2] = depth;
2689 ibuf->rect_float[pos + 3] = 1.0f;
2692 else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
2693 PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
2694 float depth = wPoint->height;
2695 if (surface->depth_clamp)
2696 depth /= surface->depth_clamp;
2697 depth = (0.5f + depth / 2.0f);
2698 CLAMP(depth, 0.0f, 1.0f);
2700 ibuf->rect_float[pos] = depth;
2701 ibuf->rect_float[pos + 1] = depth;
2702 ibuf->rect_float[pos + 2] = depth;
2703 ibuf->rect_float[pos + 3] = 1.0f;
2708 /* Set output format, png in case exr isn't supported */
2709 ibuf->ftype = PNG | 95;
2711 if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
2712 ibuf->ftype = OPENEXR | OPENEXR_COMPRESS;
2717 IMB_saveiff(ibuf, output_file, IB_rectfloat);
2718 IMB_freeImBuf(ibuf);
2722 /***************************** Material / Texture Sampling ******************************/
2724 /* stores a copy of required materials to allow doing adjustments
2725 * without interfering the render/preview */
2726 typedef struct BrushMaterials {
2732 /* Initialize materials for brush object:
2733 * Calculates inverse matrices for linked objects, updates
2734 * volume caches etc. */
2735 static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
2737 /* Calculate inverse transformation matrix
2738 * for this object */
2739 invert_m4_m4(brushOb->imat, brushOb->obmat);
2740 copy_m4_m4(brushOb->imat_ren, brushOb->imat);
2742 /* Now process every material linked to this brush object */
2743 if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) {
2744 int i, tot = (*give_totcolp(brushOb));
2746 /* allocate material pointer array */
2748 bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
2749 for (i = 0; i < tot; i++) {
2750 bMats->ob_mats[i] = RE_init_sample_material(give_current_material(brushOb, (i + 1)), scene);
2756 bMats->mat = RE_init_sample_material(ui_mat, scene);
2760 /* free all data allocated by dynamicPaint_updateBrushMaterials() */
2761 static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
2763 /* Now process every material linked to this brush object */
2764 if (bMats->ob_mats) {
2766 for (i = 0; i < bMats->tot; i++) {
2767 RE_free_sample_material(bMats->ob_mats[i]);
2769 MEM_freeN(bMats->ob_mats);
2771 else if (bMats->mat) {
2772 RE_free_sample_material(bMats->mat);
2777 * Get material diffuse color and alpha (including linked textures) in given coordinates
2779 static void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, const float volume_co[3], const float surface_co[3], int faceIndex, short isQuad, DerivedMesh *orcoDm)
2781 Material *mat = bMats->mat;
2782 MFace *mface = orcoDm->getTessFaceArray(orcoDm);
2784 /* If no material defined, use the one assigned to the mesh face */
2786 if (bMats->ob_mats) {
2787 int mat_nr = mface[faceIndex].mat_nr;
2788 if (mat_nr >= (*give_totcolp(brushOb))) return;
2789 mat = bMats->ob_mats[mat_nr];
2790 if (mat == NULL) return; /* No material assigned */
2795 RE_sample_material_color(mat, color, alpha, volume_co, surface_co, faceIndex, isQuad, orcoDm, brushOb);