Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/dynamicpaint.c')
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c10534
1 files changed, 5348 insertions, 5186 deletions
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index aedc301af92..7bbdfa6c52d 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -48,7 +48,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
-#include "BKE_bvhutils.h" /* bvh tree */
+#include "BKE_bvhutils.h" /* bvh tree */
#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_colorband.h"
@@ -73,7 +73,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-/* for image output */
+/* for image output */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -107,8 +107,8 @@ static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* Neighbor x/y list that prioritizes grid directions over diagonals */
-static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
-static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
+static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
+static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
/* subframe_updateObject() flags */
#define SUBFRAME_RECURSION 5
@@ -130,92 +130,94 @@ static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
#define MIN_WETNESS 0.001f
#define MAX_WETNESS 5.0f
-
/* dissolve inline function */
-BLI_INLINE void value_dissolve(float *r_value, const float time, const float scale, const bool is_log)
+BLI_INLINE void value_dissolve(float *r_value,
+ const float time,
+ const float scale,
+ const bool is_log)
{
- *r_value = (is_log) ?
- (*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
- (*r_value) - 1.0f / time * scale;
+ *r_value = (is_log) ? (*r_value) * (powf(MIN_WETNESS, 1.0f / (1.2f * time / scale))) :
+ (*r_value) - 1.0f / time * scale;
}
-
/***************************** Internal Structs ***************************/
typedef struct Bounds2D {
- float min[2], max[2];
+ float min[2], max[2];
} Bounds2D;
typedef struct Bounds3D {
- float min[3], max[3];
- bool valid;
+ float min[3], max[3];
+ bool valid;
} Bounds3D;
typedef struct VolumeGrid {
- int dim[3];
- Bounds3D grid_bounds; /* whole grid bounds */
+ int dim[3];
+ Bounds3D grid_bounds; /* whole grid bounds */
- Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
- int *s_pos; /* (x*y*z) t_index begin id */
- int *s_num; /* (x*y*z) number of t_index points */
- int *t_index; /* actual surface point index, access: (s_pos + s_num) */
+ Bounds3D *bounds; /* (x*y*z) precalculated grid cell bounds */
+ int *s_pos; /* (x*y*z) t_index begin id */
+ int *s_num; /* (x*y*z) number of t_index points */
+ int *t_index; /* actual surface point index, access: (s_pos + s_num) */
- int *temp_t_index;
+ int *temp_t_index;
} VolumeGrid;
typedef struct Vec3f {
- float v[3];
+ float v[3];
} Vec3f;
typedef struct BakeAdjPoint {
- float dir[3]; /* vector pointing towards this neighbor */
- float dist; /* distance to */
+ float dir[3]; /* vector pointing towards this neighbor */
+ float dist; /* distance to */
} BakeAdjPoint;
/* Surface data used while processing a frame */
typedef struct PaintBakeNormal {
- float invNorm[3]; /* current pixel world-space inverted normal */
- float normal_scale; /* normal directional scale for displace mapping */
+ float invNorm[3]; /* current pixel world-space inverted normal */
+ float normal_scale; /* normal directional scale for displace mapping */
} PaintBakeNormal;
/* Temp surface data used to process a frame */
typedef struct PaintBakeData {
- /* point space data */
- PaintBakeNormal *bNormal;
- int *s_pos; /* index to start reading point sample realCoord */
- int *s_num; /* num of realCoord samples */
- Vec3f *realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
- Bounds3D mesh_bounds;
- float dim[3];
-
- /* adjacency info */
- BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
- double average_dist;
- /* space partitioning */
- VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
-
- /* velocity and movement */
- Vec3f *velocity; /* speed vector in global space movement per frame, if required */
- Vec3f *prev_velocity;
- float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
- * 3 float dir vec + 1 float str */
- MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
- float prev_obmat[4][4]; /* previous frame object matrix */
- int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
+ /* point space data */
+ PaintBakeNormal *bNormal;
+ int *s_pos; /* index to start reading point sample realCoord */
+ int *s_num; /* num of realCoord samples */
+ Vec3f *
+ realCoord; /* current pixel center world-space coordinates for each sample ordered as (s_pos + s_num) */
+ Bounds3D mesh_bounds;
+ float dim[3];
+
+ /* adjacency info */
+ BakeAdjPoint *bNeighs; /* current global neighbor distances and directions, if required */
+ double average_dist;
+ /* space partitioning */
+ VolumeGrid *grid; /* space partitioning grid to optimize brush checks */
+
+ /* velocity and movement */
+ Vec3f *velocity; /* speed vector in global space movement per frame, if required */
+ Vec3f *prev_velocity;
+ float *brush_velocity; /* special temp data for post-p velocity based brushes like smudge
+ * 3 float dir vec + 1 float str */
+ MVert *prev_verts; /* copy of previous frame vertices. used to observe surface movement */
+ float prev_obmat[4][4]; /* previous frame object matrix */
+ int clear; /* flag to check if surface was cleared/reset -> have to redo velocity etc. */
} PaintBakeData;
/* UV Image sequence format point */
typedef struct PaintUVPoint {
- /* Pixel / mesh data */
- unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
- unsigned int v1, v2, v3; /* vertex indexes */
+ /* Pixel / mesh data */
+ unsigned int tri_index, pixel_index; /* tri index on domain derived mesh */
+ unsigned int v1, v2, v3; /* vertex indexes */
- unsigned int neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
+ unsigned int
+ neighbour_pixel; /* If this pixel isn't uv mapped to any face, but it's neighboring pixel is */
} PaintUVPoint;
typedef struct ImgSeqFormatData {
- PaintUVPoint *uv_p;
- Vec3f *barycentricWeights; /* b-weights for all pixel samples */
+ PaintUVPoint *uv_p;
+ Vec3f *barycentricWeights; /* b-weights for all pixel samples */
} ImgSeqFormatData;
/* adjacency data flags */
@@ -223,57 +225,56 @@ typedef struct ImgSeqFormatData {
#define ADJ_BORDER_PIXEL (1 << 1)
typedef struct PaintAdjData {
- int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
- int *n_index; /* index to start reading n_target for each point */
- int *n_num; /* num of neighs for each point */
- int *flags; /* vertex adjacency flags */
- int total_targets; /* size of n_target */
- int *border; /* indices of border pixels (only for texture paint) */
- int total_border; /* size of border */
+ int *
+ n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */
+ int *n_index; /* index to start reading n_target for each point */
+ int *n_num; /* num of neighs for each point */
+ int *flags; /* vertex adjacency flags */
+ int total_targets; /* size of n_target */
+ int *border; /* indices of border pixels (only for texture paint) */
+ int total_border; /* size of border */
} PaintAdjData;
/************************* Runtime evaluation store ***************************/
void dynamicPaint_Modifier_free_runtime(DynamicPaintRuntime *runtime_data)
{
- if (runtime_data == NULL) {
- return;
- }
- if (runtime_data->canvas_mesh) {
- BKE_id_free(NULL, runtime_data->canvas_mesh);
- }
- if (runtime_data->brush_mesh) {
- BKE_id_free(NULL, runtime_data->brush_mesh);
- }
- MEM_freeN(runtime_data);
+ if (runtime_data == NULL) {
+ return;
+ }
+ if (runtime_data->canvas_mesh) {
+ BKE_id_free(NULL, runtime_data->canvas_mesh);
+ }
+ if (runtime_data->brush_mesh) {
+ BKE_id_free(NULL, runtime_data->brush_mesh);
+ }
+ MEM_freeN(runtime_data);
}
-static DynamicPaintRuntime *dynamicPaint_Modifier_runtime_ensure(
- DynamicPaintModifierData *pmd)
+static DynamicPaintRuntime *dynamicPaint_Modifier_runtime_ensure(DynamicPaintModifierData *pmd)
{
- if (pmd->modifier.runtime == NULL) {
- pmd->modifier.runtime = MEM_callocN(
- sizeof(DynamicPaintRuntime), "dynamic paint runtime");
- }
- return (DynamicPaintRuntime *)pmd->modifier.runtime;
+ if (pmd->modifier.runtime == NULL) {
+ pmd->modifier.runtime = MEM_callocN(sizeof(DynamicPaintRuntime), "dynamic paint runtime");
+ }
+ return (DynamicPaintRuntime *)pmd->modifier.runtime;
}
static Mesh *dynamicPaint_canvas_mesh_get(DynamicPaintCanvasSettings *canvas)
{
- if (canvas->pmd->modifier.runtime == NULL) {
- return NULL;
- }
- DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)canvas->pmd->modifier.runtime;
- return runtime_data->canvas_mesh;
+ if (canvas->pmd->modifier.runtime == NULL) {
+ return NULL;
+ }
+ DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)canvas->pmd->modifier.runtime;
+ return runtime_data->canvas_mesh;
}
static Mesh *dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
{
- if (brush->pmd->modifier.runtime == NULL) {
- return NULL;
- }
- DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)brush->pmd->modifier.runtime;
- return runtime_data->brush_mesh;
+ if (brush->pmd->modifier.runtime == NULL) {
+ return NULL;
+ }
+ DynamicPaintRuntime *runtime_data = (DynamicPaintRuntime *)brush->pmd->modifier.runtime;
+ return runtime_data->brush_mesh;
}
/***************************** General Utils ******************************/
@@ -281,575 +282,580 @@ static Mesh *dynamicPaint_brush_mesh_get(DynamicPaintBrushSettings *brush)
/* Set canvas error string to display at the bake report */
static int setError(DynamicPaintCanvasSettings *canvas, const char *string)
{
- /* Add error to canvas ui info label */
- BLI_strncpy(canvas->error, string, sizeof(canvas->error));
- CLOG_STR_ERROR(&LOG, string);
- return 0;
+ /* Add error to canvas ui info label */
+ BLI_strncpy(canvas->error, string, sizeof(canvas->error));
+ CLOG_STR_ERROR(&LOG, string);
+ return 0;
}
/* Get number of surface points for cached types */
static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
- return 0; /* not supported atm */
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- const Mesh *canvas_mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- return (canvas_mesh) ? canvas_mesh->totvert : 0;
- }
-
- return 0;
+ if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
+ return 0; /* not supported atm */
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ const Mesh *canvas_mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ return (canvas_mesh) ? canvas_mesh->totvert : 0;
+ }
+
+ return 0;
}
/* checks whether surface's format/type has realtime preview */
bool dynamicPaint_surfaceHasColorPreview(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- return false;
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
- }
-
- return true;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ return false;
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ return !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE);
+ }
+
+ return true;
}
/* get currently active surface (in user interface) */
DynamicPaintSurface *get_activeSurface(DynamicPaintCanvasSettings *canvas)
{
- return BLI_findlink(&canvas->surfaces, canvas->active_sur);
+ return BLI_findlink(&canvas->surfaces, canvas->active_sur);
}
/* set preview to first previewable surface */
void dynamicPaint_resetPreview(DynamicPaintCanvasSettings *canvas)
{
- DynamicPaintSurface *surface = canvas->surfaces.first;
- bool done = false;
-
- for (; surface; surface = surface->next) {
- if (!done && dynamicPaint_surfaceHasColorPreview(surface)) {
- surface->flags |= MOD_DPAINT_PREVIEW;
- done = true;
- }
- else {
- surface->flags &= ~MOD_DPAINT_PREVIEW;
- }
- }
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+ bool done = false;
+
+ for (; surface; surface = surface->next) {
+ if (!done && dynamicPaint_surfaceHasColorPreview(surface)) {
+ surface->flags |= MOD_DPAINT_PREVIEW;
+ done = true;
+ }
+ else {
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
+ }
}
/* set preview to defined surface */
static void dynamicPaint_setPreview(DynamicPaintSurface *t_surface)
{
- DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
- for (; surface; surface = surface->next) {
- if (surface == t_surface)
- surface->flags |= MOD_DPAINT_PREVIEW;
- else
- surface->flags &= ~MOD_DPAINT_PREVIEW;
- }
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+ for (; surface; surface = surface->next) {
+ if (surface == t_surface)
+ surface->flags |= MOD_DPAINT_PREVIEW;
+ else
+ surface->flags &= ~MOD_DPAINT_PREVIEW;
+ }
}
bool dynamicPaint_outputLayerExists(struct DynamicPaintSurface *surface, Object *ob, int output)
{
- const char *name;
-
- if (output == 0)
- name = surface->output_name;
- else if (output == 1)
- name = surface->output_name2;
- else
- return false;
-
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- Mesh *me = ob->data;
- return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- return (defgroup_name_index(ob, name) != -1);
- }
- }
-
- return false;
+ const char *name;
+
+ if (output == 0)
+ name = surface->output_name;
+ else if (output == 1)
+ name = surface->output_name2;
+ else
+ return false;
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ Mesh *me = ob->data;
+ return (CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name) != -1);
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ return (defgroup_name_index(ob, name) != -1);
+ }
+ }
+
+ return false;
}
static bool surface_duplicateOutputExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = arg;
- DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
-
- for (; surface; surface = surface->next) {
- if (surface != t_surface && surface->type == t_surface->type && surface->format == t_surface->format) {
- if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
- (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2)))
- {
- return true;
- }
- }
- }
- return false;
+ DynamicPaintSurface *t_surface = arg;
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+
+ for (; surface; surface = surface->next) {
+ if (surface != t_surface && surface->type == t_surface->type &&
+ surface->format == t_surface->format) {
+ if ((surface->output_name[0] != '\0' && !BLI_path_cmp(name, surface->output_name)) ||
+ (surface->output_name2[0] != '\0' && !BLI_path_cmp(name, surface->output_name2))) {
+ return true;
+ }
+ }
+ }
+ return false;
}
static void surface_setUniqueOutputName(DynamicPaintSurface *surface, char *basename, int output)
{
- char name[64];
- BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- if (output == 0) {
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
- surface->output_name, sizeof(surface->output_name));
- }
- else if (output == 1) {
- BLI_uniquename_cb(surface_duplicateOutputExists, surface, name, '.',
- surface->output_name2, sizeof(surface->output_name2));
- }
+ char name[64];
+ BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
+ if (output == 0) {
+ BLI_uniquename_cb(surface_duplicateOutputExists,
+ surface,
+ name,
+ '.',
+ surface->output_name,
+ sizeof(surface->output_name));
+ }
+ else if (output == 1) {
+ BLI_uniquename_cb(surface_duplicateOutputExists,
+ surface,
+ name,
+ '.',
+ surface->output_name2,
+ sizeof(surface->output_name2));
+ }
}
-
static bool surface_duplicateNameExists(void *arg, const char *name)
{
- DynamicPaintSurface *t_surface = arg;
- DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
-
- for (; surface; surface = surface->next) {
- if (surface != t_surface && STREQ(name, surface->name))
- return true;
- }
- return false;
+ DynamicPaintSurface *t_surface = arg;
+ DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
+
+ for (; surface; surface = surface->next) {
+ if (surface != t_surface && STREQ(name, surface->name))
+ return true;
+ }
+ return false;
}
void dynamicPaintSurface_setUniqueName(DynamicPaintSurface *surface, const char *basename)
{
- char name[64];
- BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
- BLI_uniquename_cb(surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
+ char name[64];
+ BLI_strncpy(name, basename, sizeof(name)); /* in case basename is surface->name use a copy */
+ BLI_uniquename_cb(
+ surface_duplicateNameExists, surface, name, '.', surface->name, sizeof(surface->name));
}
-
/* change surface data to defaults on new type */
void dynamicPaintSurface_updateType(struct DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- surface->output_name[0] = '\0';
- surface->output_name2[0] = '\0';
- surface->flags |= MOD_DPAINT_ANTIALIAS;
- surface->depth_clamp = 1.0f;
- }
- else {
- strcpy(surface->output_name, "dp_");
- BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2));
- surface->flags &= ~MOD_DPAINT_ANTIALIAS;
- surface->depth_clamp = 0.0f;
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- strcat(surface->output_name, "paintmap");
- strcat(surface->output_name2, "wetmap");
- surface_setUniqueOutputName(surface, surface->output_name2, 1);
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- strcat(surface->output_name, "displace");
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- strcat(surface->output_name, "weight");
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- strcat(surface->output_name, "wave");
- }
-
- surface_setUniqueOutputName(surface, surface->output_name, 0);
-
- /* update preview */
- if (dynamicPaint_surfaceHasColorPreview(surface))
- dynamicPaint_setPreview(surface);
- else
- dynamicPaint_resetPreview(surface->canvas);
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ surface->output_name[0] = '\0';
+ surface->output_name2[0] = '\0';
+ surface->flags |= MOD_DPAINT_ANTIALIAS;
+ surface->depth_clamp = 1.0f;
+ }
+ else {
+ strcpy(surface->output_name, "dp_");
+ BLI_strncpy(surface->output_name2, surface->output_name, sizeof(surface->output_name2));
+ surface->flags &= ~MOD_DPAINT_ANTIALIAS;
+ surface->depth_clamp = 0.0f;
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ strcat(surface->output_name, "paintmap");
+ strcat(surface->output_name2, "wetmap");
+ surface_setUniqueOutputName(surface, surface->output_name2, 1);
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ strcat(surface->output_name, "displace");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ strcat(surface->output_name, "weight");
+ }
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ strcat(surface->output_name, "wave");
+ }
+
+ surface_setUniqueOutputName(surface, surface->output_name, 0);
+
+ /* update preview */
+ if (dynamicPaint_surfaceHasColorPreview(surface))
+ dynamicPaint_setPreview(surface);
+ else
+ dynamicPaint_resetPreview(surface->canvas);
}
static int surface_totalSamples(DynamicPaintSurface *surface)
{
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
- return (surface->data->total_points * 5);
- }
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
- surface->flags & MOD_DPAINT_ANTIALIAS && surface->data->adj_data)
- {
- return (surface->data->total_points + surface->data->adj_data->total_targets);
- }
-
- return surface->data->total_points;
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ && surface->flags & MOD_DPAINT_ANTIALIAS) {
+ return (surface->data->total_points * 5);
+ }
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS &&
+ surface->data->adj_data) {
+ return (surface->data->total_points + surface->data->adj_data->total_targets);
+ }
+
+ return surface->data->total_points;
}
-static void blendColors(
- const float t_color[3], const float t_alpha, const float s_color[3], const float s_alpha, float result[4])
+static void blendColors(const float t_color[3],
+ const float t_alpha,
+ const float s_color[3],
+ const float s_alpha,
+ float result[4])
{
- /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
- int i;
- float i_alpha = 1.0f - s_alpha;
- float f_alpha = t_alpha * i_alpha + s_alpha;
-
- /* blend colors */
- if (f_alpha) {
- for (i = 0; i < 3; i++) {
- result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
- }
- }
- else {
- copy_v3_v3(result, t_color);
- }
- /* return final alpha */
- result[3] = f_alpha;
+ /* Same thing as BLI's blend_color_mix_float(), but for non-premultiplied alpha. */
+ int i;
+ float i_alpha = 1.0f - s_alpha;
+ float f_alpha = t_alpha * i_alpha + s_alpha;
+
+ /* blend colors */
+ if (f_alpha) {
+ for (i = 0; i < 3; i++) {
+ result[i] = (t_color[i] * t_alpha * i_alpha + s_color[i] * s_alpha) / f_alpha;
+ }
+ }
+ else {
+ copy_v3_v3(result, t_color);
+ }
+ /* return final alpha */
+ result[3] = f_alpha;
}
/* Mix two alpha weighed colors by a defined ratio. output is saved at a_color */
-static float mixColors(float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
+static float mixColors(
+ float a_color[3], float a_weight, const float b_color[3], float b_weight, float ratio)
{
- float weight_ratio, factor;
- if (b_weight) {
- /* if first value has no weight just use b_color */
- if (!a_weight) {
- copy_v3_v3(a_color, b_color);
- return b_weight * ratio;
- }
- weight_ratio = b_weight / (a_weight + b_weight);
- }
- else {
- return a_weight * (1.0f - ratio);
- }
-
- /* calculate final interpolation factor */
- if (ratio <= 0.5f) {
- factor = weight_ratio * (ratio * 2.0f);
- }
- else {
- ratio = (ratio * 2.0f - 1.0f);
- factor = weight_ratio * (1.0f - ratio) + ratio;
- }
- /* mix final color */
- interp_v3_v3v3(a_color, a_color, b_color, factor);
- return (1.0f - factor) * a_weight + factor * b_weight;
+ float weight_ratio, factor;
+ if (b_weight) {
+ /* if first value has no weight just use b_color */
+ if (!a_weight) {
+ copy_v3_v3(a_color, b_color);
+ return b_weight * ratio;
+ }
+ weight_ratio = b_weight / (a_weight + b_weight);
+ }
+ else {
+ return a_weight * (1.0f - ratio);
+ }
+
+ /* calculate final interpolation factor */
+ if (ratio <= 0.5f) {
+ factor = weight_ratio * (ratio * 2.0f);
+ }
+ else {
+ ratio = (ratio * 2.0f - 1.0f);
+ factor = weight_ratio * (1.0f - ratio) + ratio;
+ }
+ /* mix final color */
+ interp_v3_v3v3(a_color, a_color, b_color, factor);
+ return (1.0f - factor) * a_weight + factor * b_weight;
}
static void scene_setSubframe(Scene *scene, float subframe)
{
- /* dynamic paint subframes must be done on previous frame */
- scene->r.cfra -= 1;
- scene->r.subframe = subframe;
+ /* dynamic paint subframes must be done on previous frame */
+ scene->r.cfra -= 1;
+ scene->r.subframe = subframe;
}
static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph)
{
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
- int flags = 0;
+ int flags = 0;
- for (int i = 0; i < numobjects; i++) {
- Object *brushObj = objects[i];
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
- if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
- DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
+ DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
- if (pmd2->brush) {
- DynamicPaintBrushSettings *brush = pmd2->brush;
+ if (pmd2->brush) {
+ DynamicPaintBrushSettings *brush = pmd2->brush;
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- flags |= BRUSH_USES_VELOCITY;
- }
- }
- }
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ flags |= BRUSH_USES_VELOCITY;
+ }
+ }
+ }
- BKE_collision_objects_free(objects);
+ BKE_collision_objects_free(objects);
- return flags;
+ return flags;
}
/* check whether two bounds intersect */
static bool boundsIntersect(Bounds3D *b1, Bounds3D *b2)
{
- if (!b1->valid || !b2->valid)
- return false;
- for (int i = 2; i--;) {
- if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
- return false;
- }
- return true;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= b2->max[i] && b1->max[i] >= b2->min[i]))
+ return false;
+ }
+ return true;
}
/* check whether two bounds intersect inside defined proximity */
static bool boundsIntersectDist(Bounds3D *b1, Bounds3D *b2, const float dist)
{
- if (!b1->valid || !b2->valid)
- return false;
- for (int i = 2; i--;) {
- if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
- return false;
- }
- return true;
+ if (!b1->valid || !b2->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b1->min[i] <= (b2->max[i] + dist) && b1->max[i] >= (b2->min[i] - dist)))
+ return false;
+ }
+ return true;
}
/* check whether bounds intersects a point with given radius */
static bool boundIntersectPoint(Bounds3D *b, float point[3], const float radius)
{
- if (!b->valid)
- return false;
- for (int i = 2; i--;) {
- if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
- return false;
- }
- return true;
+ if (!b->valid)
+ return false;
+ for (int i = 2; i--;) {
+ if (!(b->min[i] <= (point[i] + radius) && b->max[i] >= (point[i] - radius)))
+ return false;
+ }
+ return true;
}
/* expand bounds by a new point */
static void boundInsert(Bounds3D *b, float point[3])
{
- if (!b->valid) {
- copy_v3_v3(b->min, point);
- copy_v3_v3(b->max, point);
- b->valid = true;
- return;
- }
-
- minmax_v3v3_v3(b->min, b->max, point);
+ if (!b->valid) {
+ copy_v3_v3(b->min, point);
+ copy_v3_v3(b->max, point);
+ b->valid = true;
+ return;
+ }
+
+ minmax_v3v3_v3(b->min, b->max, point);
}
static float getSurfaceDimension(PaintSurfaceData *sData)
{
- Bounds3D *mb = &sData->bData->mesh_bounds;
- return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
+ Bounds3D *mb = &sData->bData->mesh_bounds;
+ return max_fff((mb->max[0] - mb->min[0]), (mb->max[1] - mb->min[1]), (mb->max[2] - mb->min[2]));
}
static void freeGrid(PaintSurfaceData *data)
{
- PaintBakeData *bData = data->bData;
- VolumeGrid *grid = bData->grid;
-
- if (grid->bounds) MEM_freeN(grid->bounds);
- if (grid->s_pos) MEM_freeN(grid->s_pos);
- if (grid->s_num) MEM_freeN(grid->s_num);
- if (grid->t_index) MEM_freeN(grid->t_index);
-
- MEM_freeN(bData->grid);
- bData->grid = NULL;
+ PaintBakeData *bData = data->bData;
+ VolumeGrid *grid = bData->grid;
+
+ if (grid->bounds)
+ MEM_freeN(grid->bounds);
+ if (grid->s_pos)
+ MEM_freeN(grid->s_pos);
+ if (grid->s_num)
+ MEM_freeN(grid->s_num);
+ if (grid->t_index)
+ MEM_freeN(grid->t_index);
+
+ MEM_freeN(bData->grid);
+ bData->grid = NULL;
}
static void grid_bound_insert_cb_ex(void *__restrict userdata,
const int i,
const ParallelRangeTLS *__restrict tls)
{
- PaintBakeData *bData = userdata;
+ PaintBakeData *bData = userdata;
- Bounds3D *grid_bound = tls->userdata_chunk;
+ Bounds3D *grid_bound = tls->userdata_chunk;
- boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
+ boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
}
-static void grid_bound_insert_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void grid_bound_insert_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
- Bounds3D *grid_bound = userdata_chunk;
+ Bounds3D *grid_bound = userdata_chunk;
- boundInsert(&grid->grid_bounds, grid_bound->min);
- boundInsert(&grid->grid_bounds, grid_bound->max);
+ boundInsert(&grid->grid_bounds, grid_bound->min);
+ boundInsert(&grid->grid_bounds, grid_bound->max);
}
static void grid_cell_points_cb_ex(void *__restrict userdata,
const int i,
const ParallelRangeTLS *__restrict tls)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
- int *temp_t_index = grid->temp_t_index;
- int *s_num = tls->userdata_chunk;
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ int *temp_t_index = grid->temp_t_index;
+ int *s_num = tls->userdata_chunk;
- int co[3];
+ int co[3];
- for (int j = 3; j--;) {
- co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
- bData->dim[j] * grid->dim[j]);
- CLAMP(co[j], 0, grid->dim[j] - 1);
- }
+ for (int j = 3; j--;) {
+ co[j] = (int)floorf((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) /
+ bData->dim[j] * grid->dim[j]);
+ CLAMP(co[j], 0, grid->dim[j] - 1);
+ }
- temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
- s_num[temp_t_index[i]]++;
+ temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
+ s_num[temp_t_index[i]]++;
}
-static void grid_cell_points_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void grid_cell_points_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
- const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
- int *s_num = userdata_chunk;
+ int *s_num = userdata_chunk;
- /* calculate grid indexes */
- for (int i = 0; i < grid_cells; i++) {
- grid->s_num[i] += s_num[i];
- }
+ /* calculate grid indexes */
+ for (int i = 0; i < grid_cells; i++) {
+ grid->s_num[i] += s_num[i];
+ }
}
static void grid_cell_bounds_cb(void *__restrict userdata,
const int x,
const ParallelRangeTLS *__restrict UNUSED(tls))
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
- float *dim = bData->dim;
- int *grid_dim = grid->dim;
-
- for (int y = 0; y < grid_dim[1]; y++) {
- for (int z = 0; z < grid_dim[2]; z++) {
- const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
- /* set bounds */
- for (int j = 3; j--;) {
- const int s = (j == 0) ? x : ((j == 1) ? y : z);
- grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
- grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
- }
- grid->bounds[b_index].valid = true;
- }
- }
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ float *dim = bData->dim;
+ int *grid_dim = grid->dim;
+
+ for (int y = 0; y < grid_dim[1]; y++) {
+ for (int z = 0; z < grid_dim[2]; z++) {
+ const int b_index = x + y * grid_dim[0] + z * grid_dim[0] * grid_dim[1];
+ /* set bounds */
+ for (int j = 3; j--;) {
+ const int s = (j == 0) ? x : ((j == 1) ? y : z);
+ grid->bounds[b_index].min[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * s;
+ grid->bounds[b_index].max[j] = grid->grid_bounds.min[j] + dim[j] / grid_dim[j] * (s + 1);
+ }
+ grid->bounds[b_index].valid = true;
+ }
+ }
}
static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- VolumeGrid *grid;
- int grid_cells, axis = 3;
- int *temp_t_index = NULL;
- int *temp_s_num = NULL;
-
- if (bData->grid)
- freeGrid(sData);
-
- bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
- grid = bData->grid;
-
- {
- int i, error = 0;
- float dim_factor, volume, dim[3];
- float td[3];
- float min_dim;
-
- /* calculate canvas dimensions */
- /* Important to init correctly our ref grid_bound... */
- boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- settings.userdata_chunk = &grid->grid_bounds;
- settings.userdata_chunk_size = sizeof(grid->grid_bounds);
- settings.func_finalize = grid_bound_insert_finalize;
- BLI_task_parallel_range(
- 0, sData->total_points,
- bData,
- grid_bound_insert_cb_ex,
- &settings);
- }
- /* get dimensions */
- sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
- copy_v3_v3(td, dim);
- copy_v3_v3(bData->dim, dim);
- min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
-
- /* deactivate zero axises */
- for (i = 0; i < 3; i++) {
- if (td[i] < min_dim) {
- td[i] = 1.0f;
- axis--;
- }
- }
-
- if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
- MEM_freeN(bData->grid);
- bData->grid = NULL;
- return;
- }
-
- /* now calculate grid volume/area/width depending on num of active axis */
- volume = td[0] * td[1] * td[2];
-
- /* determine final grid size by trying to fit average 10.000 points per grid cell */
- dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis);
-
- /* define final grid size using dim_factor, use min 3 for active axises */
- for (i = 0; i < 3; i++) {
- grid->dim[i] = (int)floor(td[i] / dim_factor);
- CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
- }
- grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
- /* allocate memory for grids */
- grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
- grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
-
- grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
- temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
- grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
- grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp Surface Grid Target Ids");
-
- /* in case of an allocation failure abort here */
- if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num || !temp_t_index)
- error = 1;
-
- if (!error) {
- /* calculate number of points within each cell */
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- settings.userdata_chunk = grid->s_num;
- settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
- settings.func_finalize = grid_cell_points_finalize;
- BLI_task_parallel_range(
- 0, sData->total_points,
- bData,
- grid_cell_points_cb_ex,
- &settings);
- }
-
- /* calculate grid indexes (not needed for first cell, which is zero). */
- for (i = 1; i < grid_cells; i++) {
- grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
- }
-
- /* save point indexes to final array */
- for (i = 0; i < sData->total_points; i++) {
- int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
- grid->t_index[pos] = i;
-
- temp_s_num[temp_t_index[i]]++;
- }
-
- /* calculate cell bounds */
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (grid_cells > 1000);
- BLI_task_parallel_range(0, grid->dim[0],
- bData,
- grid_cell_bounds_cb,
- &settings);
- }
- }
-
- if (temp_s_num)
- MEM_freeN(temp_s_num);
- if (temp_t_index)
- MEM_freeN(temp_t_index);
- grid->temp_t_index = NULL;
-
- if (error || !grid->s_num) {
- setError(surface->canvas, N_("Not enough free memory"));
- freeGrid(sData);
- }
- }
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid;
+ int grid_cells, axis = 3;
+ int *temp_t_index = NULL;
+ int *temp_s_num = NULL;
+
+ if (bData->grid)
+ freeGrid(sData);
+
+ bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
+ grid = bData->grid;
+
+ {
+ int i, error = 0;
+ float dim_factor, volume, dim[3];
+ float td[3];
+ float min_dim;
+
+ /* calculate canvas dimensions */
+ /* Important to init correctly our ref grid_bound... */
+ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ settings.userdata_chunk = &grid->grid_bounds;
+ settings.userdata_chunk_size = sizeof(grid->grid_bounds);
+ settings.func_finalize = grid_bound_insert_finalize;
+ BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings);
+ }
+ /* get dimensions */
+ sub_v3_v3v3(dim, grid->grid_bounds.max, grid->grid_bounds.min);
+ copy_v3_v3(td, dim);
+ copy_v3_v3(bData->dim, dim);
+ min_dim = max_fff(td[0], td[1], td[2]) / 1000.f;
+
+ /* deactivate zero axises */
+ for (i = 0; i < 3; i++) {
+ if (td[i] < min_dim) {
+ td[i] = 1.0f;
+ axis--;
+ }
+ }
+
+ if (axis == 0 || max_fff(td[0], td[1], td[2]) < 0.0001f) {
+ MEM_freeN(bData->grid);
+ bData->grid = NULL;
+ return;
+ }
+
+ /* now calculate grid volume/area/width depending on num of active axis */
+ volume = td[0] * td[1] * td[2];
+
+ /* determine final grid size by trying to fit average 10.000 points per grid cell */
+ dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0),
+ 1.0 / (double)axis);
+
+ /* define final grid size using dim_factor, use min 3 for active axises */
+ for (i = 0; i < 3; i++) {
+ grid->dim[i] = (int)floor(td[i] / dim_factor);
+ CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100);
+ }
+ grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ /* allocate memory for grids */
+ grid->bounds = MEM_callocN(sizeof(Bounds3D) * grid_cells, "Surface Grid Bounds");
+ grid->s_pos = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Position");
+
+ grid->s_num = MEM_callocN(sizeof(int) * grid_cells, "Surface Grid Points");
+ temp_s_num = MEM_callocN(sizeof(int) * grid_cells, "Temp Surface Grid Points");
+ grid->t_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Grid Target Ids");
+ grid->temp_t_index = temp_t_index = MEM_callocN(sizeof(int) * sData->total_points,
+ "Temp Surface Grid Target Ids");
+
+ /* in case of an allocation failure abort here */
+ if (!grid->bounds || !grid->s_pos || !grid->s_num || !grid->t_index || !temp_s_num ||
+ !temp_t_index)
+ error = 1;
+
+ if (!error) {
+ /* calculate number of points within each cell */
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ settings.userdata_chunk = grid->s_num;
+ settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
+ settings.func_finalize = grid_cell_points_finalize;
+ BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
+ }
+
+ /* calculate grid indexes (not needed for first cell, which is zero). */
+ for (i = 1; i < grid_cells; i++) {
+ grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
+ }
+
+ /* save point indexes to final array */
+ for (i = 0; i < sData->total_points; i++) {
+ int pos = grid->s_pos[temp_t_index[i]] + temp_s_num[temp_t_index[i]];
+ grid->t_index[pos] = i;
+
+ temp_s_num[temp_t_index[i]]++;
+ }
+
+ /* calculate cell bounds */
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid_cells > 1000);
+ BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, &settings);
+ }
+ }
+
+ if (temp_s_num)
+ MEM_freeN(temp_s_num);
+ if (temp_t_index)
+ MEM_freeN(temp_t_index);
+ grid->temp_t_index = NULL;
+
+ if (error || !grid->s_num) {
+ setError(surface->canvas, N_("Not enough free memory"));
+ freeGrid(sData);
+ }
+ }
}
/***************************** Freeing data ******************************/
@@ -857,149 +863,149 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* Free brush data */
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
- if (pmd->brush) {
- if (pmd->brush->paint_ramp)
- MEM_freeN(pmd->brush->paint_ramp);
- if (pmd->brush->vel_ramp)
- MEM_freeN(pmd->brush->vel_ramp);
-
- MEM_freeN(pmd->brush);
- pmd->brush = NULL;
- }
+ if (pmd->brush) {
+ if (pmd->brush->paint_ramp)
+ MEM_freeN(pmd->brush->paint_ramp);
+ if (pmd->brush->vel_ramp)
+ MEM_freeN(pmd->brush->vel_ramp);
+
+ MEM_freeN(pmd->brush);
+ pmd->brush = NULL;
+ }
}
static void dynamicPaint_freeAdjData(PaintSurfaceData *data)
{
- if (data->adj_data) {
- if (data->adj_data->n_index)
- MEM_freeN(data->adj_data->n_index);
- if (data->adj_data->n_num)
- MEM_freeN(data->adj_data->n_num);
- if (data->adj_data->n_target)
- MEM_freeN(data->adj_data->n_target);
- if (data->adj_data->flags)
- MEM_freeN(data->adj_data->flags);
- if (data->adj_data->border)
- MEM_freeN(data->adj_data->border);
- MEM_freeN(data->adj_data);
- data->adj_data = NULL;
- }
+ if (data->adj_data) {
+ if (data->adj_data->n_index)
+ MEM_freeN(data->adj_data->n_index);
+ if (data->adj_data->n_num)
+ MEM_freeN(data->adj_data->n_num);
+ if (data->adj_data->n_target)
+ MEM_freeN(data->adj_data->n_target);
+ if (data->adj_data->flags)
+ MEM_freeN(data->adj_data->flags);
+ if (data->adj_data->border)
+ MEM_freeN(data->adj_data->border);
+ MEM_freeN(data->adj_data);
+ data->adj_data = NULL;
+ }
}
static void free_bakeData(PaintSurfaceData *data)
{
- PaintBakeData *bData = data->bData;
- if (bData) {
- if (bData->bNormal)
- MEM_freeN(bData->bNormal);
- if (bData->s_pos)
- MEM_freeN(bData->s_pos);
- if (bData->s_num)
- MEM_freeN(bData->s_num);
- if (bData->realCoord)
- MEM_freeN(bData->realCoord);
- if (bData->bNeighs)
- MEM_freeN(bData->bNeighs);
- if (bData->grid)
- freeGrid(data);
- if (bData->prev_verts)
- MEM_freeN(bData->prev_verts);
- if (bData->velocity)
- MEM_freeN(bData->velocity);
- if (bData->prev_velocity)
- MEM_freeN(bData->prev_velocity);
-
- MEM_freeN(data->bData);
- data->bData = NULL;
- }
+ PaintBakeData *bData = data->bData;
+ if (bData) {
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ if (bData->grid)
+ freeGrid(data);
+ if (bData->prev_verts)
+ MEM_freeN(bData->prev_verts);
+ if (bData->velocity)
+ MEM_freeN(bData->velocity);
+ if (bData->prev_velocity)
+ MEM_freeN(bData->prev_velocity);
+
+ MEM_freeN(data->bData);
+ data->bData = NULL;
+ }
}
/* free surface data if it's not used anymore */
static void surface_freeUnusedData(DynamicPaintSurface *surface)
{
- if (!surface->data)
- return;
-
- /* free bakedata if not active or surface is baked */
- if (!(surface->flags & MOD_DPAINT_ACTIVE) || (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
- free_bakeData(surface->data);
- }
+ if (!surface->data)
+ return;
+
+ /* free bakedata if not active or surface is baked */
+ if (!(surface->flags & MOD_DPAINT_ACTIVE) ||
+ (surface->pointcache && surface->pointcache->flag & PTCACHE_BAKED)) {
+ free_bakeData(surface->data);
+ }
}
void dynamicPaint_freeSurfaceData(DynamicPaintSurface *surface)
{
- PaintSurfaceData *data = surface->data;
- if (!data)
- return;
-
- if (data->format_data) {
- /* format specific free */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
- if (format_data->uv_p)
- MEM_freeN(format_data->uv_p);
- if (format_data->barycentricWeights)
- MEM_freeN(format_data->barycentricWeights);
- }
- MEM_freeN(data->format_data);
- }
- /* type data */
- if (data->type_data)
- MEM_freeN(data->type_data);
- dynamicPaint_freeAdjData(data);
- /* bake data */
- free_bakeData(data);
-
- MEM_freeN(surface->data);
- surface->data = NULL;
+ PaintSurfaceData *data = surface->data;
+ if (!data)
+ return;
+
+ if (data->format_data) {
+ /* format specific free */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ ImgSeqFormatData *format_data = (ImgSeqFormatData *)data->format_data;
+ if (format_data->uv_p)
+ MEM_freeN(format_data->uv_p);
+ if (format_data->barycentricWeights)
+ MEM_freeN(format_data->barycentricWeights);
+ }
+ MEM_freeN(data->format_data);
+ }
+ /* type data */
+ if (data->type_data)
+ MEM_freeN(data->type_data);
+ dynamicPaint_freeAdjData(data);
+ /* bake data */
+ free_bakeData(data);
+
+ MEM_freeN(surface->data);
+ surface->data = NULL;
}
-void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd,
- DynamicPaintSurface *surface)
+void dynamicPaint_freeSurface(const DynamicPaintModifierData *pmd, DynamicPaintSurface *surface)
{
- /* point cache */
- if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
- BKE_ptcache_free_list(&(surface->ptcaches));
- }
- surface->pointcache = NULL;
-
- if (surface->effector_weights)
- MEM_freeN(surface->effector_weights);
- surface->effector_weights = NULL;
-
- BLI_remlink(&(surface->canvas->surfaces), surface);
- dynamicPaint_freeSurfaceData(surface);
- MEM_freeN(surface);
+ /* point cache */
+ if ((pmd->modifier.flag & eModifierFlag_SharedCaches) == 0) {
+ BKE_ptcache_free_list(&(surface->ptcaches));
+ }
+ surface->pointcache = NULL;
+
+ if (surface->effector_weights)
+ MEM_freeN(surface->effector_weights);
+ surface->effector_weights = NULL;
+
+ BLI_remlink(&(surface->canvas->surfaces), surface);
+ dynamicPaint_freeSurfaceData(surface);
+ MEM_freeN(surface);
}
/* Free canvas data */
void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
{
- if (pmd->canvas) {
- /* Free surface data */
- DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
- DynamicPaintSurface *next_surface = NULL;
-
- while (surface) {
- next_surface = surface->next;
- dynamicPaint_freeSurface(pmd, surface);
- surface = next_surface;
- }
-
- MEM_freeN(pmd->canvas);
- pmd->canvas = NULL;
- }
+ if (pmd->canvas) {
+ /* Free surface data */
+ DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
+ DynamicPaintSurface *next_surface = NULL;
+
+ while (surface) {
+ next_surface = surface->next;
+ dynamicPaint_freeSurface(pmd, surface);
+ surface = next_surface;
+ }
+
+ MEM_freeN(pmd->canvas);
+ pmd->canvas = NULL;
+ }
}
/* Free whole dp modifier */
void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
{
- if (pmd == NULL) {
- return;
- }
- dynamicPaint_freeCanvas(pmd);
- dynamicPaint_freeBrush(pmd);
- dynamicPaint_Modifier_free_runtime(pmd->modifier.runtime);
+ if (pmd == NULL) {
+ return;
+ }
+ dynamicPaint_freeCanvas(pmd);
+ dynamicPaint_freeBrush(pmd);
+ dynamicPaint_Modifier_free_runtime(pmd->modifier.runtime);
}
/***************************** Initialize and reset ******************************/
@@ -1009,77 +1015,80 @@ void dynamicPaint_Modifier_free(DynamicPaintModifierData *pmd)
* If scene is null, frame range of 1-250 is used
* A pointer to this surface is returned
*/
-DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas, Scene *scene)
+DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *canvas,
+ Scene *scene)
{
- DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
- if (!surface)
- return NULL;
-
- surface->canvas = canvas;
- surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
- surface->type = MOD_DPAINT_SURFACE_T_PAINT;
-
- /* cache */
- surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
- surface->pointcache->flag |= PTCACHE_DISK_CACHE;
- surface->pointcache->step = 1;
-
- /* Set initial values */
- surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG | MOD_DPAINT_DISSOLVE_LOG |
- MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW | MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
- surface->effect = 0;
- surface->effect_ui = 1;
-
- surface->diss_speed = 250;
- surface->dry_speed = 500;
- surface->color_dry_threshold = 1.0f;
- surface->depth_clamp = 0.0f;
- surface->disp_factor = 1.0f;
- surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
- surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
-
- surface->influence_scale = 1.0f;
- surface->radius_scale = 1.0f;
-
- surface->init_color[0] = 1.0f;
- surface->init_color[1] = 1.0f;
- surface->init_color[2] = 1.0f;
- surface->init_color[3] = 1.0f;
-
- surface->image_resolution = 256;
- surface->substeps = 0;
-
- if (scene) {
- surface->start_frame = scene->r.sfra;
- surface->end_frame = scene->r.efra;
- }
- else {
- surface->start_frame = 1;
- surface->end_frame = 250;
- }
-
- surface->spread_speed = 1.0f;
- surface->color_spread_speed = 1.0f;
- surface->shrink_speed = 1.0f;
-
- surface->wave_damping = 0.04f;
- surface->wave_speed = 1.0f;
- surface->wave_timescale = 1.0f;
- surface->wave_spring = 0.20f;
- surface->wave_smoothness = 1.0f;
-
- modifier_path_init(surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
-
- /* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
- dynamicPaintSurface_setUniqueName(surface, CTX_DATA_(BLT_I18NCONTEXT_ID_BRUSH, "Surface"));
-
- surface->effector_weights = BKE_effector_add_weights(NULL);
-
- dynamicPaintSurface_updateType(surface);
-
- BLI_addtail(&canvas->surfaces, surface);
-
- return surface;
+ DynamicPaintSurface *surface = MEM_callocN(sizeof(DynamicPaintSurface), "DynamicPaintSurface");
+ if (!surface)
+ return NULL;
+
+ surface->canvas = canvas;
+ surface->format = MOD_DPAINT_SURFACE_F_VERTEX;
+ surface->type = MOD_DPAINT_SURFACE_T_PAINT;
+
+ /* cache */
+ surface->pointcache = BKE_ptcache_add(&(surface->ptcaches));
+ surface->pointcache->flag |= PTCACHE_DISK_CACHE;
+ surface->pointcache->step = 1;
+
+ /* Set initial values */
+ surface->flags = MOD_DPAINT_ANTIALIAS | MOD_DPAINT_MULALPHA | MOD_DPAINT_DRY_LOG |
+ MOD_DPAINT_DISSOLVE_LOG | MOD_DPAINT_ACTIVE | MOD_DPAINT_PREVIEW |
+ MOD_DPAINT_OUT1 | MOD_DPAINT_USE_DRYING;
+ surface->effect = 0;
+ surface->effect_ui = 1;
+
+ surface->diss_speed = 250;
+ surface->dry_speed = 500;
+ surface->color_dry_threshold = 1.0f;
+ surface->depth_clamp = 0.0f;
+ surface->disp_factor = 1.0f;
+ surface->disp_type = MOD_DPAINT_DISP_DISPLACE;
+ surface->image_fileformat = MOD_DPAINT_IMGFORMAT_PNG;
+
+ surface->influence_scale = 1.0f;
+ surface->radius_scale = 1.0f;
+
+ surface->init_color[0] = 1.0f;
+ surface->init_color[1] = 1.0f;
+ surface->init_color[2] = 1.0f;
+ surface->init_color[3] = 1.0f;
+
+ surface->image_resolution = 256;
+ surface->substeps = 0;
+
+ if (scene) {
+ surface->start_frame = scene->r.sfra;
+ surface->end_frame = scene->r.efra;
+ }
+ else {
+ surface->start_frame = 1;
+ surface->end_frame = 250;
+ }
+
+ surface->spread_speed = 1.0f;
+ surface->color_spread_speed = 1.0f;
+ surface->shrink_speed = 1.0f;
+
+ surface->wave_damping = 0.04f;
+ surface->wave_speed = 1.0f;
+ surface->wave_timescale = 1.0f;
+ surface->wave_spring = 0.20f;
+ surface->wave_smoothness = 1.0f;
+
+ modifier_path_init(
+ surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
+
+ /* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
+ dynamicPaintSurface_setUniqueName(surface, CTX_DATA_(BLT_I18NCONTEXT_ID_BRUSH, "Surface"));
+
+ surface->effector_weights = BKE_effector_add_weights(NULL);
+
+ dynamicPaintSurface_updateType(surface);
+
+ BLI_addtail(&canvas->surfaces, surface);
+
+ return surface;
}
/*
@@ -1087,1380 +1096,1378 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
*/
bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, struct Scene *scene)
{
- if (pmd) {
- if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
- DynamicPaintCanvasSettings *canvas;
- if (pmd->canvas)
- dynamicPaint_freeCanvas(pmd);
-
- canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings), "DynamicPaint Canvas");
- if (!canvas)
- return false;
- canvas->pmd = pmd;
-
- /* Create one surface */
- if (!dynamicPaint_createNewSurface(canvas, scene))
- return false;
-
- }
- else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
- DynamicPaintBrushSettings *brush;
- if (pmd->brush)
- dynamicPaint_freeBrush(pmd);
-
- brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
- if (!brush)
- return false;
- brush->pmd = pmd;
-
- brush->psys = NULL;
-
- brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
- brush->collision = MOD_DPAINT_COL_VOLUME;
-
- brush->r = 0.15f;
- brush->g = 0.4f;
- brush->b = 0.8f;
- brush->alpha = 1.0f;
- brush->wetness = 1.0f;
-
- brush->paint_distance = 1.0f;
- brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH;
-
- brush->particle_radius = 0.2f;
- brush->particle_smooth = 0.05f;
-
- brush->wave_type = MOD_DPAINT_WAVEB_CHANGE;
- brush->wave_factor = 1.0f;
- brush->wave_clamp = 0.0f;
- brush->smudge_strength = 0.3f;
- brush->max_velocity = 1.0f;
-
- /* Paint proximity falloff colorramp. */
- {
- CBData *ramp;
-
- brush->paint_ramp = BKE_colorband_add(false);
- if (!brush->paint_ramp)
- return false;
- ramp = brush->paint_ramp->data;
- /* Add default smooth-falloff ramp. */
- ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
- ramp[0].pos = 0.0f;
- ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
- ramp[1].a = 0.0f;
- pmd->brush->paint_ramp->tot = 2;
- }
-
- /* Brush velocity ramp. */
- {
- CBData *ramp;
-
- brush->vel_ramp = BKE_colorband_add(false);
- if (!brush->vel_ramp)
- return false;
- ramp = brush->vel_ramp->data;
- ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
- ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
- brush->paint_ramp->tot = 2;
- }
- }
- }
- else {
- return false;
- }
-
- return true;
+ if (pmd) {
+ if (type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
+ DynamicPaintCanvasSettings *canvas;
+ if (pmd->canvas)
+ dynamicPaint_freeCanvas(pmd);
+
+ canvas = pmd->canvas = MEM_callocN(sizeof(DynamicPaintCanvasSettings),
+ "DynamicPaint Canvas");
+ if (!canvas)
+ return false;
+ canvas->pmd = pmd;
+
+ /* Create one surface */
+ if (!dynamicPaint_createNewSurface(canvas, scene))
+ return false;
+ }
+ else if (type == MOD_DYNAMICPAINT_TYPE_BRUSH) {
+ DynamicPaintBrushSettings *brush;
+ if (pmd->brush)
+ dynamicPaint_freeBrush(pmd);
+
+ brush = pmd->brush = MEM_callocN(sizeof(DynamicPaintBrushSettings), "DynamicPaint Paint");
+ if (!brush)
+ return false;
+ brush->pmd = pmd;
+
+ brush->psys = NULL;
+
+ brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
+ brush->collision = MOD_DPAINT_COL_VOLUME;
+
+ brush->r = 0.15f;
+ brush->g = 0.4f;
+ brush->b = 0.8f;
+ brush->alpha = 1.0f;
+ brush->wetness = 1.0f;
+
+ brush->paint_distance = 1.0f;
+ brush->proximity_falloff = MOD_DPAINT_PRFALL_SMOOTH;
+
+ brush->particle_radius = 0.2f;
+ brush->particle_smooth = 0.05f;
+
+ brush->wave_type = MOD_DPAINT_WAVEB_CHANGE;
+ brush->wave_factor = 1.0f;
+ brush->wave_clamp = 0.0f;
+ brush->smudge_strength = 0.3f;
+ brush->max_velocity = 1.0f;
+
+ /* Paint proximity falloff colorramp. */
+ {
+ CBData *ramp;
+
+ brush->paint_ramp = BKE_colorband_add(false);
+ if (!brush->paint_ramp)
+ return false;
+ ramp = brush->paint_ramp->data;
+ /* Add default smooth-falloff ramp. */
+ ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
+ ramp[0].pos = 0.0f;
+ ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].pos = 1.0f;
+ ramp[1].a = 0.0f;
+ pmd->brush->paint_ramp->tot = 2;
+ }
+
+ /* Brush velocity ramp. */
+ {
+ CBData *ramp;
+
+ brush->vel_ramp = BKE_colorband_add(false);
+ if (!brush->vel_ramp)
+ return false;
+ ramp = brush->vel_ramp->data;
+ ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = ramp[0].pos = 0.0f;
+ ramp[1].r = ramp[1].g = ramp[1].b = ramp[1].a = ramp[1].pos = 1.0f;
+ brush->paint_ramp->tot = 2;
+ }
+ }
+ }
+ else {
+ return false;
+ }
+
+ return true;
}
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd,
struct DynamicPaintModifierData *tpmd,
int flag)
{
- /* Init modifier */
- tpmd->type = pmd->type;
- if (pmd->canvas)
- dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL);
- if (pmd->brush)
- dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL);
-
- /* Copy data */
- if (tpmd->canvas) {
- DynamicPaintSurface *surface;
- tpmd->canvas->pmd = tpmd;
- /* free default surface */
- if (tpmd->canvas->surfaces.first)
- dynamicPaint_freeSurface(tpmd, tpmd->canvas->surfaces.first);
-
- /* copy existing surfaces */
- for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
- DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL);
- if (flag & LIB_ID_CREATE_NO_MAIN) {
- /* TODO(sergey): Consider passing some tips to the surface
- * creation to avoid this allocate-and-free cache behavior. */
- BKE_ptcache_free_list(&t_surface->ptcaches);
- tpmd->modifier.flag |= eModifierFlag_SharedCaches;
- t_surface->ptcaches = surface->ptcaches;
- t_surface->pointcache = surface->pointcache;
- }
-
- /* surface settings */
- t_surface->brush_group = surface->brush_group;
- MEM_freeN(t_surface->effector_weights);
- t_surface->effector_weights = MEM_dupallocN(surface->effector_weights);
-
- BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name));
- t_surface->format = surface->format;
- t_surface->type = surface->type;
- t_surface->disp_type = surface->disp_type;
- t_surface->image_fileformat = surface->image_fileformat;
- t_surface->effect_ui = surface->effect_ui;
- t_surface->preview_id = surface->preview_id;
- t_surface->init_color_type = surface->init_color_type;
- t_surface->flags = surface->flags;
- t_surface->effect = surface->effect;
-
- t_surface->image_resolution = surface->image_resolution;
- t_surface->substeps = surface->substeps;
- t_surface->start_frame = surface->start_frame;
- t_surface->end_frame = surface->end_frame;
-
- copy_v4_v4(t_surface->init_color, surface->init_color);
- t_surface->init_texture = surface->init_texture;
- BLI_strncpy(t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername));
-
- t_surface->dry_speed = surface->dry_speed;
- t_surface->diss_speed = surface->diss_speed;
- t_surface->color_dry_threshold = surface->color_dry_threshold;
- t_surface->depth_clamp = surface->depth_clamp;
- t_surface->disp_factor = surface->disp_factor;
-
-
- t_surface->spread_speed = surface->spread_speed;
- t_surface->color_spread_speed = surface->color_spread_speed;
- t_surface->shrink_speed = surface->shrink_speed;
- t_surface->drip_vel = surface->drip_vel;
- t_surface->drip_acc = surface->drip_acc;
-
- t_surface->influence_scale = surface->influence_scale;
- t_surface->radius_scale = surface->radius_scale;
-
- t_surface->wave_damping = surface->wave_damping;
- t_surface->wave_speed = surface->wave_speed;
- t_surface->wave_timescale = surface->wave_timescale;
- t_surface->wave_spring = surface->wave_spring;
- t_surface->wave_smoothness = surface->wave_smoothness;
-
- BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name));
- BLI_strncpy(t_surface->image_output_path, surface->image_output_path, sizeof(t_surface->image_output_path));
- BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name));
- BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2));
- }
- dynamicPaint_resetPreview(tpmd->canvas);
- }
- else if (tpmd->brush) {
- DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
- t_brush->pmd = tpmd;
-
- t_brush->flags = brush->flags;
- t_brush->collision = brush->collision;
-
- t_brush->r = brush->r;
- t_brush->g = brush->g;
- t_brush->b = brush->b;
- t_brush->alpha = brush->alpha;
- t_brush->wetness = brush->wetness;
-
- t_brush->particle_radius = brush->particle_radius;
- t_brush->particle_smooth = brush->particle_smooth;
- t_brush->paint_distance = brush->paint_distance;
- t_brush->psys = brush->psys;
-
- if (brush->paint_ramp)
- memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
- if (brush->vel_ramp)
- memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
-
- t_brush->proximity_falloff = brush->proximity_falloff;
- t_brush->wave_type = brush->wave_type;
- t_brush->ray_dir = brush->ray_dir;
-
- t_brush->wave_factor = brush->wave_factor;
- t_brush->wave_clamp = brush->wave_clamp;
- t_brush->max_velocity = brush->max_velocity;
- t_brush->smudge_strength = brush->smudge_strength;
- }
+ /* Init modifier */
+ tpmd->type = pmd->type;
+ if (pmd->canvas)
+ dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_CANVAS, NULL);
+ if (pmd->brush)
+ dynamicPaint_createType(tpmd, MOD_DYNAMICPAINT_TYPE_BRUSH, NULL);
+
+ /* Copy data */
+ if (tpmd->canvas) {
+ DynamicPaintSurface *surface;
+ tpmd->canvas->pmd = tpmd;
+ /* free default surface */
+ if (tpmd->canvas->surfaces.first)
+ dynamicPaint_freeSurface(tpmd, tpmd->canvas->surfaces.first);
+
+ /* copy existing surfaces */
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ DynamicPaintSurface *t_surface = dynamicPaint_createNewSurface(tpmd->canvas, NULL);
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* TODO(sergey): Consider passing some tips to the surface
+ * creation to avoid this allocate-and-free cache behavior. */
+ BKE_ptcache_free_list(&t_surface->ptcaches);
+ tpmd->modifier.flag |= eModifierFlag_SharedCaches;
+ t_surface->ptcaches = surface->ptcaches;
+ t_surface->pointcache = surface->pointcache;
+ }
+
+ /* surface settings */
+ t_surface->brush_group = surface->brush_group;
+ MEM_freeN(t_surface->effector_weights);
+ t_surface->effector_weights = MEM_dupallocN(surface->effector_weights);
+
+ BLI_strncpy(t_surface->name, surface->name, sizeof(t_surface->name));
+ t_surface->format = surface->format;
+ t_surface->type = surface->type;
+ t_surface->disp_type = surface->disp_type;
+ t_surface->image_fileformat = surface->image_fileformat;
+ t_surface->effect_ui = surface->effect_ui;
+ t_surface->preview_id = surface->preview_id;
+ t_surface->init_color_type = surface->init_color_type;
+ t_surface->flags = surface->flags;
+ t_surface->effect = surface->effect;
+
+ t_surface->image_resolution = surface->image_resolution;
+ t_surface->substeps = surface->substeps;
+ t_surface->start_frame = surface->start_frame;
+ t_surface->end_frame = surface->end_frame;
+
+ copy_v4_v4(t_surface->init_color, surface->init_color);
+ t_surface->init_texture = surface->init_texture;
+ BLI_strncpy(
+ t_surface->init_layername, surface->init_layername, sizeof(t_surface->init_layername));
+
+ t_surface->dry_speed = surface->dry_speed;
+ t_surface->diss_speed = surface->diss_speed;
+ t_surface->color_dry_threshold = surface->color_dry_threshold;
+ t_surface->depth_clamp = surface->depth_clamp;
+ t_surface->disp_factor = surface->disp_factor;
+
+ t_surface->spread_speed = surface->spread_speed;
+ t_surface->color_spread_speed = surface->color_spread_speed;
+ t_surface->shrink_speed = surface->shrink_speed;
+ t_surface->drip_vel = surface->drip_vel;
+ t_surface->drip_acc = surface->drip_acc;
+
+ t_surface->influence_scale = surface->influence_scale;
+ t_surface->radius_scale = surface->radius_scale;
+
+ t_surface->wave_damping = surface->wave_damping;
+ t_surface->wave_speed = surface->wave_speed;
+ t_surface->wave_timescale = surface->wave_timescale;
+ t_surface->wave_spring = surface->wave_spring;
+ t_surface->wave_smoothness = surface->wave_smoothness;
+
+ BLI_strncpy(t_surface->uvlayer_name, surface->uvlayer_name, sizeof(t_surface->uvlayer_name));
+ BLI_strncpy(t_surface->image_output_path,
+ surface->image_output_path,
+ sizeof(t_surface->image_output_path));
+ BLI_strncpy(t_surface->output_name, surface->output_name, sizeof(t_surface->output_name));
+ BLI_strncpy(t_surface->output_name2, surface->output_name2, sizeof(t_surface->output_name2));
+ }
+ dynamicPaint_resetPreview(tpmd->canvas);
+ }
+ else if (tpmd->brush) {
+ DynamicPaintBrushSettings *brush = pmd->brush, *t_brush = tpmd->brush;
+ t_brush->pmd = tpmd;
+
+ t_brush->flags = brush->flags;
+ t_brush->collision = brush->collision;
+
+ t_brush->r = brush->r;
+ t_brush->g = brush->g;
+ t_brush->b = brush->b;
+ t_brush->alpha = brush->alpha;
+ t_brush->wetness = brush->wetness;
+
+ t_brush->particle_radius = brush->particle_radius;
+ t_brush->particle_smooth = brush->particle_smooth;
+ t_brush->paint_distance = brush->paint_distance;
+ t_brush->psys = brush->psys;
+
+ if (brush->paint_ramp)
+ memcpy(t_brush->paint_ramp, brush->paint_ramp, sizeof(ColorBand));
+ if (brush->vel_ramp)
+ memcpy(t_brush->vel_ramp, brush->vel_ramp, sizeof(ColorBand));
+
+ t_brush->proximity_falloff = brush->proximity_falloff;
+ t_brush->wave_type = brush->wave_type;
+ t_brush->ray_dir = brush->ray_dir;
+
+ t_brush->wave_factor = brush->wave_factor;
+ t_brush->wave_clamp = brush->wave_clamp;
+ t_brush->max_velocity = brush->max_velocity;
+ t_brush->smudge_strength = brush->smudge_strength;
+ }
}
/* allocates surface data depending on surface type */
static void dynamicPaint_allocateSurfaceType(DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
-
- switch (surface->type) {
- case MOD_DPAINT_SURFACE_T_PAINT:
- sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points, "DynamicPaintSurface Data");
- break;
- case MOD_DPAINT_SURFACE_T_DISPLACE:
- sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface DepthData");
- break;
- case MOD_DPAINT_SURFACE_T_WEIGHT:
- sData->type_data = MEM_callocN(sizeof(float) * sData->total_points, "DynamicPaintSurface WeightData");
- break;
- case MOD_DPAINT_SURFACE_T_WAVE:
- sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points, "DynamicPaintSurface WaveData");
- break;
- }
-
- if (sData->type_data == NULL)
- setError(surface->canvas, N_("Not enough free memory"));
+ PaintSurfaceData *sData = surface->data;
+
+ switch (surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ sData->type_data = MEM_callocN(sizeof(PaintPoint) * sData->total_points,
+ "DynamicPaintSurface Data");
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
+ "DynamicPaintSurface DepthData");
+ break;
+ case MOD_DPAINT_SURFACE_T_WEIGHT:
+ sData->type_data = MEM_callocN(sizeof(float) * sData->total_points,
+ "DynamicPaintSurface WeightData");
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ sData->type_data = MEM_callocN(sizeof(PaintWavePoint) * sData->total_points,
+ "DynamicPaintSurface WaveData");
+ break;
+ }
+
+ if (sData->type_data == NULL)
+ setError(surface->canvas, N_("Not enough free memory"));
}
static bool surface_usesAdjDistance(DynamicPaintSurface *surface)
{
- return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
- (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
+ return ((surface->type == MOD_DPAINT_SURFACE_T_PAINT && surface->effect) ||
+ (surface->type == MOD_DPAINT_SURFACE_T_WAVE));
}
static bool surface_usesAdjData(DynamicPaintSurface *surface)
{
- return (surface_usesAdjDistance(surface) ||
- (surface->format == MOD_DPAINT_SURFACE_F_VERTEX && surface->flags & MOD_DPAINT_ANTIALIAS));
+ return (surface_usesAdjDistance(surface) || (surface->format == MOD_DPAINT_SURFACE_F_VERTEX &&
+ surface->flags & MOD_DPAINT_ANTIALIAS));
}
/* initialize surface adjacency data */
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
- PaintSurfaceData *sData = surface->data;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- PaintAdjData *ad;
- int *temp_data;
- int neigh_points = 0;
-
- if (!force_init && !surface_usesAdjData(surface))
- return;
-
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- /* For vertex format, neighbors are connected by edges */
- neigh_points = 2 * mesh->totedge;
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- neigh_points = sData->total_points * 8;
- }
-
- if (!neigh_points)
- return;
-
- /* allocate memory */
- ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
- if (!ad)
- return;
- ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
- ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
- temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
- ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
- ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
- ad->total_targets = neigh_points;
- ad->border = NULL;
- ad->total_border = 0;
-
- /* in case of allocation error, free memory */
- if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
- dynamicPaint_freeAdjData(sData);
- if (temp_data)
- MEM_freeN(temp_data);
- setError(surface->canvas, N_("Not enough free memory"));
- return;
- }
-
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int i;
- int n_pos;
-
- /* For vertex format, count every vertex that is connected by an edge */
- int numOfEdges = mesh->totedge;
- int numOfPolys = mesh->totpoly;
- struct MEdge *edge = mesh->medge;
- struct MPoly *mpoly = mesh->mpoly;
- struct MLoop *mloop = mesh->mloop;
-
- /* count number of edges per vertex */
- for (i = 0; i < numOfEdges; i++) {
- ad->n_num[edge[i].v1]++;
- ad->n_num[edge[i].v2]++;
-
- temp_data[edge[i].v1]++;
- temp_data[edge[i].v2]++;
- }
-
- /* also add number of vertices to temp_data
- * to locate points on "mesh edge" */
- for (i = 0; i < numOfPolys; i++) {
- for (int j = 0; j < mpoly[i].totloop; j++) {
- temp_data[mloop[mpoly[i].loopstart + j].v]++;
- }
- }
-
- /* now check if total number of edges+faces for
- * each vertex is even, if not -> vertex is on mesh edge */
- for (i = 0; i < sData->total_points; i++) {
- if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
- ad->flags[i] |= ADJ_ON_MESH_EDGE;
- }
-
- /* reset temp data */
- temp_data[i] = 0;
- }
-
- /* order n_index array */
- n_pos = 0;
- for (i = 0; i < sData->total_points; i++) {
- ad->n_index[i] = n_pos;
- n_pos += ad->n_num[i];
- }
-
- /* and now add neighbor data using that info */
- for (i = 0; i < numOfEdges; i++) {
- /* first vertex */
- int index = edge[i].v1;
- n_pos = ad->n_index[index] + temp_data[index];
- ad->n_target[n_pos] = edge[i].v2;
- temp_data[index]++;
-
- /* second vertex */
- index = edge[i].v2;
- n_pos = ad->n_index[index] + temp_data[index];
- ad->n_target[n_pos] = edge[i].v1;
- temp_data[index]++;
- }
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- /* for image sequences, only allocate memory.
- * bake initialization takes care of rest */
- }
-
- MEM_freeN(temp_data);
+ PaintSurfaceData *sData = surface->data;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ PaintAdjData *ad;
+ int *temp_data;
+ int neigh_points = 0;
+
+ if (!force_init && !surface_usesAdjData(surface))
+ return;
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ /* For vertex format, neighbors are connected by edges */
+ neigh_points = 2 * mesh->totedge;
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ neigh_points = sData->total_points * 8;
+ }
+
+ if (!neigh_points)
+ return;
+
+ /* allocate memory */
+ ad = sData->adj_data = MEM_callocN(sizeof(PaintAdjData), "Surface Adj Data");
+ if (!ad)
+ return;
+ ad->n_index = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Index");
+ ad->n_num = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Counts");
+ temp_data = MEM_callocN(sizeof(int) * sData->total_points, "Temp Adj Data");
+ ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets");
+ ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags");
+ ad->total_targets = neigh_points;
+ ad->border = NULL;
+ ad->total_border = 0;
+
+ /* in case of allocation error, free memory */
+ if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) {
+ dynamicPaint_freeAdjData(sData);
+ if (temp_data)
+ MEM_freeN(temp_data);
+ setError(surface->canvas, N_("Not enough free memory"));
+ return;
+ }
+
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int i;
+ int n_pos;
+
+ /* For vertex format, count every vertex that is connected by an edge */
+ int numOfEdges = mesh->totedge;
+ int numOfPolys = mesh->totpoly;
+ struct MEdge *edge = mesh->medge;
+ struct MPoly *mpoly = mesh->mpoly;
+ struct MLoop *mloop = mesh->mloop;
+
+ /* count number of edges per vertex */
+ for (i = 0; i < numOfEdges; i++) {
+ ad->n_num[edge[i].v1]++;
+ ad->n_num[edge[i].v2]++;
+
+ temp_data[edge[i].v1]++;
+ temp_data[edge[i].v2]++;
+ }
+
+ /* also add number of vertices to temp_data
+ * to locate points on "mesh edge" */
+ for (i = 0; i < numOfPolys; i++) {
+ for (int j = 0; j < mpoly[i].totloop; j++) {
+ temp_data[mloop[mpoly[i].loopstart + j].v]++;
+ }
+ }
+
+ /* now check if total number of edges+faces for
+ * each vertex is even, if not -> vertex is on mesh edge */
+ for (i = 0; i < sData->total_points; i++) {
+ if ((temp_data[i] % 2) || (temp_data[i] < 4)) {
+ ad->flags[i] |= ADJ_ON_MESH_EDGE;
+ }
+
+ /* reset temp data */
+ temp_data[i] = 0;
+ }
+
+ /* order n_index array */
+ n_pos = 0;
+ for (i = 0; i < sData->total_points; i++) {
+ ad->n_index[i] = n_pos;
+ n_pos += ad->n_num[i];
+ }
+
+ /* and now add neighbor data using that info */
+ for (i = 0; i < numOfEdges; i++) {
+ /* first vertex */
+ int index = edge[i].v1;
+ n_pos = ad->n_index[index] + temp_data[index];
+ ad->n_target[n_pos] = edge[i].v2;
+ temp_data[index]++;
+
+ /* second vertex */
+ index = edge[i].v2;
+ n_pos = ad->n_index[index] + temp_data[index];
+ ad->n_target[n_pos] = edge[i].v1;
+ temp_data[index]++;
+ }
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ /* for image sequences, only allocate memory.
+ * bake initialization takes care of rest */
+ }
+
+ MEM_freeN(temp_data);
}
typedef struct DynamicPaintSetInitColorData {
- const DynamicPaintSurface *surface;
+ const DynamicPaintSurface *surface;
- const MLoop *mloop;
- const MLoopUV *mloopuv;
- const MLoopTri *mlooptri;
- const MLoopCol *mloopcol;
- struct ImagePool *pool;
+ const MLoop *mloop;
+ const MLoopUV *mloopuv;
+ const MLoopTri *mlooptri;
+ const MLoopCol *mloopcol;
+ struct ImagePool *pool;
- const bool scene_color_manage;
+ const bool scene_color_manage;
} DynamicPaintSetInitColorData;
static void dynamic_paint_set_init_color_tex_to_vcol_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintSetInitColorData *data = userdata;
+ const DynamicPaintSetInitColorData *data = userdata;
- const PaintSurfaceData *sData = data->surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- struct ImagePool *pool = data->pool;
- Tex *tex = data->surface->init_texture;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ struct ImagePool *pool = data->pool;
+ Tex *tex = data->surface->init_texture;
- const bool scene_color_manage = data->scene_color_manage;
+ const bool scene_color_manage = data->scene_color_manage;
- float uv[3] = {0.0f};
+ float uv[3] = {0.0f};
- for (int j = 3; j--;) {
- TexResult texres = {0};
- const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
+ for (int j = 3; j--;) {
+ TexResult texres = {0};
+ const unsigned int vert = mloop[mlooptri[i].tri[j]].v;
- /* remap to [-1.0, 1.0] */
- uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
- uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
+ /* remap to [-1.0, 1.0] */
+ uv[0] = mloopuv[mlooptri[i].tri[j]].uv[0] * 2.0f - 1.0f;
+ uv[1] = mloopuv[mlooptri[i].tri[j]].uv[1] * 2.0f - 1.0f;
- multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
+ multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
- if (texres.tin > pPoint[vert].color[3]) {
- copy_v3_v3(pPoint[vert].color, &texres.tr);
- pPoint[vert].color[3] = texres.tin;
- }
- }
+ if (texres.tin > pPoint[vert].color[3]) {
+ copy_v3_v3(pPoint[vert].color, &texres.tr);
+ pPoint[vert].color[3] = texres.tin;
+ }
+ }
}
static void dynamic_paint_set_init_color_tex_to_imseq_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintSetInitColorData *data = userdata;
+ const DynamicPaintSetInitColorData *data = userdata;
- const PaintSurfaceData *sData = data->surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- Tex *tex = data->surface->init_texture;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ Tex *tex = data->surface->init_texture;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const bool scene_color_manage = data->scene_color_manage;
+ const bool scene_color_manage = data->scene_color_manage;
- float uv[9] = {0.0f};
- float uv_final[3] = {0.0f};
+ float uv[9] = {0.0f};
+ float uv_final[3] = {0.0f};
- TexResult texres = {0};
+ TexResult texres = {0};
- /* collect all uvs */
- for (int j = 3; j--;) {
- copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
- }
+ /* collect all uvs */
+ for (int j = 3; j--;) {
+ copy_v2_v2(&uv[j * 3], mloopuv[mlooptri[f_data->uv_p[i].tri_index].tri[j]].uv);
+ }
- /* interpolate final uv pos */
- interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
- /* remap to [-1.0, 1.0] */
- uv_final[0] = uv_final[0] * 2.0f - 1.0f;
- uv_final[1] = uv_final[1] * 2.0f - 1.0f;
+ /* interpolate final uv pos */
+ interp_v3_v3v3v3(uv_final, &uv[0], &uv[3], &uv[6], f_data->barycentricWeights[i * samples].v);
+ /* remap to [-1.0, 1.0] */
+ uv_final[0] = uv_final[0] * 2.0f - 1.0f;
+ uv_final[1] = uv_final[1] * 2.0f - 1.0f;
- multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
+ multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
- /* apply color */
- copy_v3_v3(pPoint[i].color, &texres.tr);
- pPoint[i].color[3] = texres.tin;
+ /* apply color */
+ copy_v3_v3(pPoint[i].color, &texres.tr);
+ pPoint[i].color[3] = texres.tin;
}
static void dynamic_paint_set_init_color_vcol_to_imseq_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintSetInitColorData *data = userdata;
+ const DynamicPaintSetInitColorData *data = userdata;
- const PaintSurfaceData *sData = data->surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ const PaintSurfaceData *sData = data->surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopCol *mloopcol = data->mloopcol;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopCol *mloopcol = data->mloopcol;
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const int samples = (data->surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const int tri_idx = f_data->uv_p[i].tri_index;
- float colors[3][4];
- float final_color[4];
+ const int tri_idx = f_data->uv_p[i].tri_index;
+ float colors[3][4];
+ float final_color[4];
- /* collect color values */
- for (int j = 3; j--;) {
- rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
- }
+ /* collect color values */
+ for (int j = 3; j--;) {
+ rgba_uchar_to_float(colors[j], (const unsigned char *)&mloopcol[mlooptri[tri_idx].tri[j]].r);
+ }
- /* interpolate final color */
- interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
+ /* interpolate final color */
+ interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
- copy_v4_v4(pPoint[i].color, final_color);
+ copy_v4_v4(pPoint[i].color, final_color);
}
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- int i;
- const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
-
- if (surface->type != MOD_DPAINT_SURFACE_T_PAINT)
- return;
-
- if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
- return;
-
- /* Single color */
- if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
- /* apply color to every surface point */
- for (i = 0; i < sData->total_points; i++) {
- copy_v4_v4(pPoint[i].color, surface->init_color);
- }
- }
- /* UV mapped texture */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
- Tex *tex = surface->init_texture;
-
- const MLoop *mloop = mesh->mloop;
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- const int tottri = BKE_mesh_runtime_looptri_len(mesh);
- const MLoopUV *mloopuv = NULL;
-
- char uvname[MAX_CUSTOMDATA_LAYER_NAME];
-
- if (!tex)
- return;
-
- /* get uv map */
- CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
- mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
- if (!mloopuv)
- return;
-
- /* for vertex surface loop through tfaces and find uv color
- * that provides highest alpha */
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- struct ImagePool *pool = BKE_image_pool_new();
-
- DynamicPaintSetInitColorData data = {
- .surface = surface,
- .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
- .scene_color_manage = scene_color_manage,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (tottri > 1000);
- BLI_task_parallel_range(0, tottri,
- &data,
- dynamic_paint_set_init_color_tex_to_vcol_cb,
- &settings);
- BKE_image_pool_free(pool);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- DynamicPaintSetInitColorData data = {
- .surface = surface,
- .mlooptri = mlooptri, .mloopuv = mloopuv,
- .scene_color_manage = scene_color_manage,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_set_init_color_tex_to_imseq_cb,
- &settings);
- }
- }
- /* vertex color layer */
- else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
-
- /* for vertex surface, just copy colors from mcol */
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- const MLoop *mloop = mesh->mloop;
- const int totloop = mesh->totloop;
- const MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
- if (!col)
- return;
-
- for (i = 0; i < totloop; i++) {
- rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
- }
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
- if (!col)
- return;
-
- DynamicPaintSetInitColorData data = {
- .surface = surface,
- .mlooptri = mlooptri, .mloopcol = col,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_set_init_color_vcol_to_imseq_cb,
- &settings);
- }
- }
+ PaintSurfaceData *sData = surface->data;
+ PaintPoint *pPoint = (PaintPoint *)sData->type_data;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ int i;
+ const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
+
+ if (surface->type != MOD_DPAINT_SURFACE_T_PAINT)
+ return;
+
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_NONE)
+ return;
+
+ /* Single color */
+ if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
+ /* apply color to every surface point */
+ for (i = 0; i < sData->total_points; i++) {
+ copy_v4_v4(pPoint[i].color, surface->init_color);
+ }
+ }
+ /* UV mapped texture */
+ else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
+ Tex *tex = surface->init_texture;
+
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
+ const MLoopUV *mloopuv = NULL;
+
+ char uvname[MAX_CUSTOMDATA_LAYER_NAME];
+
+ if (!tex)
+ return;
+
+ /* get uv map */
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
+ if (!mloopuv)
+ return;
+
+ /* for vertex surface loop through tfaces and find uv color
+ * that provides highest alpha */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ struct ImagePool *pool = BKE_image_pool_new();
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .pool = pool,
+ .scene_color_manage = scene_color_manage,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (tottri > 1000);
+ BLI_task_parallel_range(
+ 0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, &settings);
+ BKE_image_pool_free(pool);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .scene_color_manage = scene_color_manage,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb, &settings);
+ }
+ }
+ /* vertex color layer */
+ else if (surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
+
+ /* for vertex surface, just copy colors from mcol */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ const MLoop *mloop = mesh->mloop;
+ const int totloop = mesh->totloop;
+ const MLoopCol *col = CustomData_get_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, surface->init_layername);
+ if (!col)
+ return;
+
+ for (i = 0; i < totloop; i++) {
+ rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
+ }
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ MLoopCol *col = CustomData_get_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, surface->init_layername);
+ if (!col)
+ return;
+
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri,
+ .mloopcol = col,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb, &settings);
+ }
+ }
}
/* clears surface data back to zero */
void dynamicPaint_clearSurface(const Scene *scene, DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
- if (sData && sData->type_data) {
- unsigned int data_size;
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
- data_size = sizeof(PaintPoint);
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- data_size = sizeof(PaintWavePoint);
- else
- data_size = sizeof(float);
-
- memset(sData->type_data, 0, data_size * sData->total_points);
-
- /* set initial color */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
- dynamicPaint_setInitialColor(scene, surface);
-
- if (sData->bData)
- sData->bData->clear = 1;
- }
+ PaintSurfaceData *sData = surface->data;
+ if (sData && sData->type_data) {
+ unsigned int data_size;
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ data_size = sizeof(PaintPoint);
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE)
+ data_size = sizeof(PaintWavePoint);
+ else
+ data_size = sizeof(float);
+
+ memset(sData->type_data, 0, data_size * sData->total_points);
+
+ /* set initial color */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ dynamicPaint_setInitialColor(scene, surface);
+
+ if (sData->bData)
+ sData->bData->clear = 1;
+ }
}
/* completely (re)initializes surface (only for point cache types)*/
bool dynamicPaint_resetSurface(const Scene *scene, DynamicPaintSurface *surface)
{
- int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
- /* free existing data */
- if (surface->data)
- dynamicPaint_freeSurfaceData(surface);
-
- /* don't reallocate for image sequence types. they get handled only on bake */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- return true;
- if (numOfPoints < 1)
- return false;
-
- /* allocate memory */
- surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data)
- return false;
-
- /* allocate data depending on surface type and format */
- surface->data->total_points = numOfPoints;
- dynamicPaint_allocateSurfaceType(surface);
- dynamicPaint_initAdjacencyData(surface, false);
-
- /* set initial color */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
- dynamicPaint_setInitialColor(scene, surface);
-
- return true;
+ int numOfPoints = dynamicPaint_surfaceNumOfPoints(surface);
+ /* free existing data */
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
+
+ /* don't reallocate for image sequence types. they get handled only on bake */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return true;
+ if (numOfPoints < 1)
+ return false;
+
+ /* allocate memory */
+ surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
+ if (!surface->data)
+ return false;
+
+ /* allocate data depending on surface type and format */
+ surface->data->total_points = numOfPoints;
+ dynamicPaint_allocateSurfaceType(surface);
+ dynamicPaint_initAdjacencyData(surface, false);
+
+ /* set initial color */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT)
+ dynamicPaint_setInitialColor(scene, surface);
+
+ return true;
}
/* make sure allocated surface size matches current requirements */
static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurface *surface)
{
- if (!surface->data || ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
- return dynamicPaint_resetSurface(scene, surface);
- }
- return true;
+ if (!surface->data ||
+ ((dynamicPaint_surfaceNumOfPoints(surface) != surface->data->total_points))) {
+ return dynamicPaint_resetSurface(scene, surface);
+ }
+ return true;
}
-
/***************************** Modifier processing ******************************/
typedef struct DynamicPaintModifierApplyData {
- const DynamicPaintSurface *surface;
- Object *ob;
+ const DynamicPaintSurface *surface;
+ Object *ob;
- MVert *mvert;
- const MLoop *mloop;
- const MPoly *mpoly;
+ MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly;
- float (*fcolor)[4];
- MLoopCol *mloopcol;
- MLoopCol *mloopcol_wet;
- MLoopCol *mloopcol_preview;
+ float (*fcolor)[4];
+ MLoopCol *mloopcol;
+ MLoopCol *mloopcol_wet;
+ MLoopCol *mloopcol_preview;
} DynamicPaintModifierApplyData;
-static void dynamic_paint_apply_surface_displace_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
+ const DynamicPaintModifierApplyData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- MVert *mvert = data->mvert;
+ const DynamicPaintSurface *surface = data->surface;
+ MVert *mvert = data->mvert;
- float normal[3];
- const float *value = (float *)surface->data->type_data;
- const float val = value[i] * surface->disp_factor;
+ float normal[3];
+ const float *value = (float *)surface->data->type_data;
+ const float val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
+ normal_short_to_float_v3(normal, mvert[i].no);
- /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
- madd_v3_v3fl(mvert[i].co, normal, -val);
+ /* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
+ madd_v3_v3fl(mvert[i].co, normal, -val);
}
/* apply displacing vertex surface to the derived mesh */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
{
- PaintSurfaceData *sData = surface->data;
-
- if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
- return;
-
- /* displace paint */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- MVert *mvert = result->mvert;
-
- DynamicPaintModifierApplyData data = { .surface = surface, .mvert = mvert, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_apply_surface_displace_cb,
- &settings);
- }
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData || surface->format != MOD_DPAINT_SURFACE_F_VERTEX)
+ return;
+
+ /* displace paint */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ MVert *mvert = result->mvert;
+
+ DynamicPaintModifierApplyData data = {
+ .surface = surface,
+ .mvert = mvert,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb, &settings);
+ }
}
static void dynamic_paint_apply_surface_vpaint_blend_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int i, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
+ const DynamicPaintModifierApplyData *data = userdata;
- PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
- float (*fcolor)[4] = data->fcolor;
+ PaintPoint *pPoint = (PaintPoint *)data->surface->data->type_data;
+ float(*fcolor)[4] = data->fcolor;
- /* blend dry and wet layer */
- blendColors(pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
+ /* blend dry and wet layer */
+ blendColors(
+ pPoint[i].color, pPoint[i].color[3], pPoint[i].e_color, pPoint[i].e_color[3], fcolor[i]);
}
-static void dynamic_paint_apply_surface_vpaint_cb(
- void *__restrict userdata,
- const int p_index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_apply_surface_vpaint_cb(void *__restrict userdata,
+ const int p_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
- Object *ob = data->ob;
-
- const MLoop *mloop = data->mloop;
- const MPoly *mpoly = data->mpoly;
-
- const DynamicPaintSurface *surface = data->surface;
- PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
- float (*fcolor)[4] = data->fcolor;
-
- MLoopCol *mloopcol = data->mloopcol;
- MLoopCol *mloopcol_wet = data->mloopcol_wet;
- MLoopCol *mloopcol_preview = data->mloopcol_preview;
-
- const Material *material = mloopcol_preview ?
- give_current_material(ob, mpoly[p_index].mat_nr + 1) : NULL;
-
- for (int j = 0; j < mpoly[p_index].totloop; j++) {
- const int l_index = mpoly[p_index].loopstart + j;
- const int v_index = mloop[l_index].v;
-
- /* save layer data to output layer */
- /* apply color */
- if (mloopcol) {
- rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
- }
- /* apply wetness */
- if (mloopcol_wet) {
- const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
- mloopcol_wet[l_index].r = c;
- mloopcol_wet[l_index].g = c;
- mloopcol_wet[l_index].b = c;
- mloopcol_wet[l_index].a = 255;
- }
-
- /* viewport preview */
- if (mloopcol_preview) {
- if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
- float c[3];
-
- /* Apply material color as base vertex color for preview */
- mloopcol_preview[l_index].a = 255;
- if (material) {
- c[0] = material->r;
- c[1] = material->g;
- c[2] = material->b;
- }
- else { /* default gray */
- c[0] = 0.65f;
- c[1] = 0.65f;
- c[2] = 0.65f;
- }
- /* mix surface color */
- interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
-
- rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
- }
- else {
- const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
- mloopcol_preview[l_index].r = c;
- mloopcol_preview[l_index].g = c;
- mloopcol_preview[l_index].b = c;
- mloopcol_preview[l_index].a = 255;
- }
- }
- }
+ const DynamicPaintModifierApplyData *data = userdata;
+ Object *ob = data->ob;
+
+ const MLoop *mloop = data->mloop;
+ const MPoly *mpoly = data->mpoly;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintPoint *pPoint = (PaintPoint *)surface->data->type_data;
+ float(*fcolor)[4] = data->fcolor;
+
+ MLoopCol *mloopcol = data->mloopcol;
+ MLoopCol *mloopcol_wet = data->mloopcol_wet;
+ MLoopCol *mloopcol_preview = data->mloopcol_preview;
+
+ const Material *material = mloopcol_preview ?
+ give_current_material(ob, mpoly[p_index].mat_nr + 1) :
+ NULL;
+
+ for (int j = 0; j < mpoly[p_index].totloop; j++) {
+ const int l_index = mpoly[p_index].loopstart + j;
+ const int v_index = mloop[l_index].v;
+
+ /* save layer data to output layer */
+ /* apply color */
+ if (mloopcol) {
+ rgba_float_to_uchar((unsigned char *)&mloopcol[l_index].r, fcolor[v_index]);
+ }
+ /* apply wetness */
+ if (mloopcol_wet) {
+ const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
+ mloopcol_wet[l_index].r = c;
+ mloopcol_wet[l_index].g = c;
+ mloopcol_wet[l_index].b = c;
+ mloopcol_wet[l_index].a = 255;
+ }
+
+ /* viewport preview */
+ if (mloopcol_preview) {
+ if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
+ float c[3];
+
+ /* Apply material color as base vertex color for preview */
+ mloopcol_preview[l_index].a = 255;
+ if (material) {
+ c[0] = material->r;
+ c[1] = material->g;
+ c[2] = material->b;
+ }
+ else { /* default gray */
+ c[0] = 0.65f;
+ c[1] = 0.65f;
+ c[2] = 0.65f;
+ }
+ /* mix surface color */
+ interp_v3_v3v3(c, c, fcolor[v_index], fcolor[v_index][3]);
+
+ rgb_float_to_uchar((unsigned char *)&mloopcol_preview[l_index].r, c);
+ }
+ else {
+ const char c = unit_float_to_uchar_clamp(pPoint[v_index].wetness);
+ mloopcol_preview[l_index].r = c;
+ mloopcol_preview[l_index].g = c;
+ mloopcol_preview[l_index].b = c;
+ mloopcol_preview[l_index].a = 255;
+ }
+ }
+ }
}
-static void dynamic_paint_apply_surface_wave_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintModifierApplyData *data = userdata;
+ const DynamicPaintModifierApplyData *data = userdata;
- PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
- MVert *mvert = data->mvert;
- float normal[3];
+ PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
+ MVert *mvert = data->mvert;
+ float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+ normal_short_to_float_v3(normal, mvert[i].no);
+ madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
}
/*
* Apply canvas data to the object derived mesh
*/
-static Mesh *dynamicPaint_Modifier_apply(
- DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
+static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
{
- Mesh *result = BKE_mesh_copy_for_eval(mesh, false);
-
- if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
-
- DynamicPaintSurface *surface;
- bool update_normals = false;
-
- /* loop through surfaces */
- for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
- PaintSurfaceData *sData = surface->data;
-
- if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
- if (!(surface->flags & MOD_DPAINT_ACTIVE))
- continue;
-
- /* process vertex surface previews */
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
-
- /* vertex color paint */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- MLoop *mloop = result->mloop;
- const int totloop = result->totloop;
- MPoly *mpoly = result->mpoly;
- const int totpoly = result->totpoly;
-
- /* paint is stored on dry and wet layers, so mix final color first */
- float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
-
- DynamicPaintModifierApplyData data = { .surface = surface, .fcolor = fcolor, };
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_apply_surface_vpaint_blend_cb,
- &settings);
- }
-
- /* paint layer */
- MLoopCol *mloopcol = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name);
- /* if output layer is lost from a constructive modifier, re-add it */
- if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
- mloopcol = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
- }
-
- /* wet layer */
- MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name2);
- /* if output layer is lost from a constructive modifier, re-add it */
- if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
- mloopcol_wet = CustomData_add_layer_named(
- &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
- }
-
- /* Save preview results to weight layer to be able to share same drawing methods */
- MLoopCol *mloopcol_preview = NULL;
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL);
- if (!mloopcol_preview) {
- mloopcol_preview = CustomData_add_layer(
- &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
- }
- }
-
- data.ob = ob;
- data.mloop = mloop;
- data.mpoly = mpoly;
- data.mloopcol = mloopcol;
- data.mloopcol_wet = mloopcol_wet;
- data.mloopcol_preview = mloopcol_preview;
-
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (totpoly > 1000);
- BLI_task_parallel_range(
- 0, totpoly,
- &data,
- dynamic_paint_apply_surface_vpaint_cb,
- &settings);
- }
-
- MEM_freeN(fcolor);
-
- /* Mark tessellated CD layers as dirty. */
- //result->dirty |= DM_DIRTY_TESS_CDLAYERS;
- }
- /* vertex group paint */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- int defgrp_index = defgroup_name_index(ob, surface->output_name);
- MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT);
- float *weight = (float *)sData->type_data;
-
- /* viewport preview */
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- /* Save preview results to weight layer to be
- * able to share same drawing methods.
- * Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
- //TODO port this function
- //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
- }
-
- /* apply weights into a vertex group, if doesn't exists add a new layer */
- if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
- dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC,
- NULL, sData->total_points);
- }
- if (defgrp_index != -1 && dvert) {
- int i;
- for (i = 0; i < sData->total_points; i++) {
- MDeformVert *dv = &dvert[i];
- MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index);
-
- /* skip if weight value is 0 and no existing weight is found */
- if ((def_weight != NULL) || (weight[i] != 0.0f)) {
- /* if not found, add a weight for it */
- if (def_weight == NULL) {
- def_weight = defvert_verify_index(dv, defgrp_index);
- }
-
- /* set weight value */
- def_weight->weight = weight[i];
- }
- }
- }
- }
- /* wave simulation */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- MVert *mvert = result->mvert;
-
- DynamicPaintModifierApplyData data = { .surface = surface, .mvert = mvert, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_apply_surface_wave_cb,
- &settings);
- update_normals = true;
- }
-
- /* displace */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- dynamicPaint_applySurfaceDisplace(surface, result);
- update_normals = true;
- }
- }
- }
- }
-
- if (update_normals) {
- //result->dirty |= DM_DIRTY_NORMALS;
- }
- }
- /* make a copy of mesh to use as brush data */
- if (pmd->brush) {
- DynamicPaintRuntime *runtime_data = dynamicPaint_Modifier_runtime_ensure(pmd);
- if (runtime_data->brush_mesh != NULL) {
- BKE_id_free(NULL, runtime_data->brush_mesh);
- }
- runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false);
- }
-
- return result;
+ Mesh *result = BKE_mesh_copy_for_eval(mesh, false);
+
+ if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
+
+ DynamicPaintSurface *surface;
+ bool update_normals = false;
+
+ /* loop through surfaces */
+ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
+ PaintSurfaceData *sData = surface->data;
+
+ if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) {
+ if (!(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
+
+ /* process vertex surface previews */
+ if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+
+ /* vertex color paint */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ MLoop *mloop = result->mloop;
+ const int totloop = result->totloop;
+ MPoly *mpoly = result->mpoly;
+ const int totpoly = result->totpoly;
+
+ /* paint is stored on dry and wet layers, so mix final color first */
+ float(*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points,
+ "Temp paint color");
+
+ DynamicPaintModifierApplyData data = {
+ .surface = surface,
+ .fcolor = fcolor,
+ };
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ &settings);
+ }
+
+ /* paint layer */
+ MLoopCol *mloopcol = CustomData_get_layer_named(
+ &result->ldata, CD_MLOOPCOL, surface->output_name);
+ /* if output layer is lost from a constructive modifier, re-add it */
+ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ mloopcol = CustomData_add_layer_named(
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ }
+
+ /* wet layer */
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(
+ &result->ldata, CD_MLOOPCOL, surface->output_name2);
+ /* if output layer is lost from a constructive modifier, re-add it */
+ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ mloopcol_wet = CustomData_add_layer_named(
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ }
+
+ /* Save preview results to weight layer to be able to share same drawing methods */
+ MLoopCol *mloopcol_preview = NULL;
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol_preview) {
+ mloopcol_preview = CustomData_add_layer(
+ &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
+ }
+ }
+
+ data.ob = ob;
+ data.mloop = mloop;
+ data.mpoly = mpoly;
+ data.mloopcol = mloopcol;
+ data.mloopcol_wet = mloopcol_wet;
+ data.mloopcol_preview = mloopcol_preview;
+
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (totpoly > 1000);
+ BLI_task_parallel_range(
+ 0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb, &settings);
+ }
+
+ MEM_freeN(fcolor);
+
+ /* Mark tessellated CD layers as dirty. */
+ //result->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ }
+ /* vertex group paint */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ int defgrp_index = defgroup_name_index(ob, surface->output_name);
+ MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT);
+ float *weight = (float *)sData->type_data;
+
+ /* viewport preview */
+ if (surface->flags & MOD_DPAINT_PREVIEW) {
+ /* Save preview results to weight layer to be
+ * able to share same drawing methods.
+ * Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
+ //TODO port this function
+ //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
+ }
+
+ /* apply weights into a vertex group, if doesn't exists add a new layer */
+ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
+ dvert = CustomData_add_layer(
+ &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points);
+ }
+ if (defgrp_index != -1 && dvert) {
+ int i;
+ for (i = 0; i < sData->total_points; i++) {
+ MDeformVert *dv = &dvert[i];
+ MDeformWeight *def_weight = defvert_find_index(dv, defgrp_index);
+
+ /* skip if weight value is 0 and no existing weight is found */
+ if ((def_weight != NULL) || (weight[i] != 0.0f)) {
+ /* if not found, add a weight for it */
+ if (def_weight == NULL) {
+ def_weight = defvert_verify_index(dv, defgrp_index);
+ }
+
+ /* set weight value */
+ def_weight->weight = weight[i];
+ }
+ }
+ }
+ }
+ /* wave simulation */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ MVert *mvert = result->mvert;
+
+ DynamicPaintModifierApplyData data = {
+ .surface = surface,
+ .mvert = mvert,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
+ update_normals = true;
+ }
+
+ /* displace */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ dynamicPaint_applySurfaceDisplace(surface, result);
+ update_normals = true;
+ }
+ }
+ }
+ }
+
+ if (update_normals) {
+ //result->dirty |= DM_DIRTY_NORMALS;
+ }
+ }
+ /* make a copy of mesh to use as brush data */
+ if (pmd->brush) {
+ DynamicPaintRuntime *runtime_data = dynamicPaint_Modifier_runtime_ensure(pmd);
+ if (runtime_data->brush_mesh != NULL) {
+ BKE_id_free(NULL, runtime_data->brush_mesh);
+ }
+ runtime_data->brush_mesh = BKE_mesh_copy_for_eval(result, false);
+ }
+
+ return result;
}
/* update cache frame range */
void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
{
- if (surface->pointcache) {
- surface->pointcache->startframe = surface->start_frame;
- surface->pointcache->endframe = surface->end_frame;
- }
+ if (surface->pointcache) {
+ surface->pointcache->startframe = surface->start_frame;
+ surface->pointcache->endframe = surface->end_frame;
+ }
}
static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
{
- DynamicPaintRuntime *runtime = dynamicPaint_Modifier_runtime_ensure(canvas->pmd);
- if (runtime->canvas_mesh != NULL) {
- BKE_id_free(NULL, runtime->canvas_mesh);
- }
+ DynamicPaintRuntime *runtime = dynamicPaint_Modifier_runtime_ensure(canvas->pmd);
+ if (runtime->canvas_mesh != NULL) {
+ BKE_id_free(NULL, runtime->canvas_mesh);
+ }
- runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false);
+ runtime->canvas_mesh = BKE_mesh_copy_for_eval(mesh, false);
}
/*
* Updates derived mesh copy and processes dynamic paint step / caches.
*/
-static void dynamicPaint_frameUpdate(
- DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
- Object *ob, Mesh *mesh)
+static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *mesh)
{
- if (pmd->canvas) {
- DynamicPaintCanvasSettings *canvas = pmd->canvas;
- DynamicPaintSurface *surface = canvas->surfaces.first;
-
- /* update derived mesh copy */
- canvas_copyMesh(canvas, mesh);
-
- /* in case image sequence baking, stop here */
- if (canvas->flags & MOD_DPAINT_BAKING)
- return;
-
- /* loop through surfaces */
- for (; surface; surface = surface->next) {
- int current_frame = (int)scene->r.cfra;
- bool no_surface_data;
-
- /* free bake data if not required anymore */
- surface_freeUnusedData(surface);
-
- /* image sequences are handled by bake operator */
- if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) || !(surface->flags & MOD_DPAINT_ACTIVE))
- continue;
-
- /* make sure surface is valid */
- no_surface_data = surface->data == NULL;
- if (!dynamicPaint_checkSurfaceData(scene, surface))
- continue;
-
- /* limit frame range */
- CLAMP(current_frame, surface->start_frame, surface->end_frame);
-
- if (no_surface_data || current_frame != surface->current_frame ||
- (int)scene->r.cfra == surface->start_frame)
- {
- PointCache *cache = surface->pointcache;
- PTCacheID pid;
- surface->current_frame = current_frame;
-
- /* read point cache */
- BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
- pid.cache->startframe = surface->start_frame;
- pid.cache->endframe = surface->end_frame;
- BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
-
- /* reset non-baked cache at first frame */
- if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
- cache->flag |= PTCACHE_REDO_NEEDED;
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- cache->flag &= ~PTCACHE_REDO_NEEDED;
- }
-
- /* try to read from cache */
- bool can_simulate = ((int)scene->r.cfra == current_frame) && !(cache->flag & PTCACHE_BAKED);
-
- if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
- BKE_ptcache_validate(cache, (int)scene->r.cfra);
- }
- /* if read failed and we're on surface range do recalculate */
- else if (can_simulate) {
- /* calculate surface frame */
- canvas->flags |= MOD_DPAINT_BAKING;
- dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
- canvas->flags &= ~MOD_DPAINT_BAKING;
-
- /* restore canvas mesh if required */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
- surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
- {
- canvas_copyMesh(canvas, mesh);
- }
-
- BKE_ptcache_validate(cache, surface->current_frame);
- BKE_ptcache_write(&pid, surface->current_frame);
- }
- }
- }
- }
+ if (pmd->canvas) {
+ DynamicPaintCanvasSettings *canvas = pmd->canvas;
+ DynamicPaintSurface *surface = canvas->surfaces.first;
+
+ /* update derived mesh copy */
+ canvas_copyMesh(canvas, mesh);
+
+ /* in case image sequence baking, stop here */
+ if (canvas->flags & MOD_DPAINT_BAKING)
+ return;
+
+ /* loop through surfaces */
+ for (; surface; surface = surface->next) {
+ int current_frame = (int)scene->r.cfra;
+ bool no_surface_data;
+
+ /* free bake data if not required anymore */
+ surface_freeUnusedData(surface);
+
+ /* image sequences are handled by bake operator */
+ if ((surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) ||
+ !(surface->flags & MOD_DPAINT_ACTIVE))
+ continue;
+
+ /* make sure surface is valid */
+ no_surface_data = surface->data == NULL;
+ if (!dynamicPaint_checkSurfaceData(scene, surface))
+ continue;
+
+ /* limit frame range */
+ CLAMP(current_frame, surface->start_frame, surface->end_frame);
+
+ if (no_surface_data || current_frame != surface->current_frame ||
+ (int)scene->r.cfra == surface->start_frame) {
+ PointCache *cache = surface->pointcache;
+ PTCacheID pid;
+ surface->current_frame = current_frame;
+
+ /* read point cache */
+ BKE_ptcache_id_from_dynamicpaint(&pid, ob, surface);
+ pid.cache->startframe = surface->start_frame;
+ pid.cache->endframe = surface->end_frame;
+ BKE_ptcache_id_time(&pid, scene, (float)scene->r.cfra, NULL, NULL, NULL);
+
+ /* reset non-baked cache at first frame */
+ if ((int)scene->r.cfra == surface->start_frame && !(cache->flag & PTCACHE_BAKED)) {
+ cache->flag |= PTCACHE_REDO_NEEDED;
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
+
+ /* try to read from cache */
+ bool can_simulate = ((int)scene->r.cfra == current_frame) &&
+ !(cache->flag & PTCACHE_BAKED);
+
+ if (BKE_ptcache_read(&pid, (float)scene->r.cfra, can_simulate)) {
+ BKE_ptcache_validate(cache, (int)scene->r.cfra);
+ }
+ /* if read failed and we're on surface range do recalculate */
+ else if (can_simulate) {
+ /* calculate surface frame */
+ canvas->flags |= MOD_DPAINT_BAKING;
+ dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
+ canvas->flags &= ~MOD_DPAINT_BAKING;
+
+ /* restore canvas mesh if required */
+ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
+ surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next) {
+ canvas_copyMesh(canvas, mesh);
+ }
+
+ BKE_ptcache_validate(cache, surface->current_frame);
+ BKE_ptcache_write(&pid, surface->current_frame);
+ }
+ }
+ }
+ }
}
/* Modifier call. Processes dynamic paint modifier step. */
-Mesh *dynamicPaint_Modifier_do(
- DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
- Object *ob, Mesh *mesh)
+Mesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *mesh)
{
- if (pmd->canvas) {
- Mesh *ret;
+ if (pmd->canvas) {
+ Mesh *ret;
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
- /* Return output mesh */
- ret = dynamicPaint_Modifier_apply(pmd, ob, mesh);
+ /* Return output mesh */
+ ret = dynamicPaint_Modifier_apply(pmd, ob, mesh);
- return ret;
- }
- else {
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
+ return ret;
+ }
+ else {
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
- /* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, mesh);
- }
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, ob, mesh);
+ }
}
-
/***************************** Image Sequence / UV Image Surface Calls ******************************/
/*
* Create a surface for uv image sequence format
*/
-#define JITTER_SAMPLES { \
- 0.0f, 0.0f, \
- -0.2f, -0.4f, \
- 0.2f, 0.4f, \
- 0.4f, -0.2f, \
- -0.4f, 0.3f, \
-}
+#define JITTER_SAMPLES \
+ { \
+ 0.0f, 0.0f, -0.2f, -0.4f, 0.2f, 0.4f, 0.4f, -0.2f, -0.4f, 0.3f, \
+ }
typedef struct DynamicPaintCreateUVSurfaceData {
- const DynamicPaintSurface *surface;
+ const DynamicPaintSurface *surface;
- PaintUVPoint *tempPoints;
- Vec3f *tempWeights;
+ PaintUVPoint *tempPoints;
+ Vec3f *tempWeights;
- const MLoopTri *mlooptri;
- const MLoopUV *mloopuv;
- const MLoop *mloop;
- const int tottri;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ const MLoop *mloop;
+ const int tottri;
- const Bounds2D *faceBB;
- uint32_t *active_points;
+ const Bounds2D *faceBB;
+ uint32_t *active_points;
} DynamicPaintCreateUVSurfaceData;
static void dynamic_paint_create_uv_surface_direct_cb(
- void *__restrict userdata,
- const int ty,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ty, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintCreateUVSurfaceData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- PaintUVPoint *tempPoints = data->tempPoints;
- Vec3f *tempWeights = data->tempWeights;
-
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- const MLoop *mloop = data->mloop;
- const int tottri = data->tottri;
-
- const Bounds2D *faceBB = data->faceBB;
-
- const float jitter5sample[10] = JITTER_SAMPLES;
- const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const int w = surface->image_resolution;
- const int h = w;
-
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
- float point[5][2];
-
- /* Init per pixel settings */
- tPoint->tri_index = -1;
- tPoint->neighbour_pixel = -1;
- tPoint->pixel_index = index;
-
- /* Actual pixel center, used when collision is found */
- point[0][0] = ((float)tx + 0.5f) / w;
- point[0][1] = ((float)ty + 0.5f) / h;
-
- /*
- * A pixel middle sample isn't enough to find very narrow polygons
- * So using 4 samples of each corner too
- */
- point[1][0] = ((float)tx) / w;
- point[1][1] = ((float)ty) / h;
-
- point[2][0] = ((float)tx + 1) / w;
- point[2][1] = ((float)ty) / h;
-
- point[3][0] = ((float)tx) / w;
- point[3][1] = ((float)ty + 1) / h;
-
- point[4][0] = ((float)tx + 1) / w;
- point[4][1] = ((float)ty + 1) / h;
-
-
- /* Loop through samples, starting from middle point */
- for (int sample = 0; sample < 5; sample++) {
- /* Loop through every face in the mesh */
- /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
- for (int i = 0; i < tottri; i++) {
- /* Check uv bb */
- if ((faceBB[i].min[0] > point[sample][0]) ||
- (faceBB[i].min[1] > point[sample][1]) ||
- (faceBB[i].max[0] < point[sample][0]) ||
- (faceBB[i].max[1] < point[sample][1]))
- {
- continue;
- }
-
- const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
- const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
- const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
-
- /* If point is inside the face */
- if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
- float uv[2];
-
- /* Add b-weights per anti-aliasing sample */
- for (int j = 0; j < aa_samples; j++) {
- uv[0] = point[0][0] + jitter5sample[j * 2] / w;
- uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
-
- barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* Set surface point face values */
- tPoint->tri_index = i;
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- }
- }
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+ const int tottri = data->tottri;
+
+ const Bounds2D *faceBB = data->faceBB;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+ float point[5][2];
+
+ /* Init per pixel settings */
+ tPoint->tri_index = -1;
+ tPoint->neighbour_pixel = -1;
+ tPoint->pixel_index = index;
+
+ /* Actual pixel center, used when collision is found */
+ point[0][0] = ((float)tx + 0.5f) / w;
+ point[0][1] = ((float)ty + 0.5f) / h;
+
+ /*
+ * A pixel middle sample isn't enough to find very narrow polygons
+ * So using 4 samples of each corner too
+ */
+ point[1][0] = ((float)tx) / w;
+ point[1][1] = ((float)ty) / h;
+
+ point[2][0] = ((float)tx + 1) / w;
+ point[2][1] = ((float)ty) / h;
+
+ point[3][0] = ((float)tx) / w;
+ point[3][1] = ((float)ty + 1) / h;
+
+ point[4][0] = ((float)tx + 1) / w;
+ point[4][1] = ((float)ty + 1) / h;
+
+ /* Loop through samples, starting from middle point */
+ for (int sample = 0; sample < 5; sample++) {
+ /* Loop through every face in the mesh */
+ /* XXX TODO This is *horrible* with big meshes, should use a 2D BVHTree over UV tris here! */
+ for (int i = 0; i < tottri; i++) {
+ /* Check uv bb */
+ if ((faceBB[i].min[0] > point[sample][0]) || (faceBB[i].min[1] > point[sample][1]) ||
+ (faceBB[i].max[0] < point[sample][0]) || (faceBB[i].max[1] < point[sample][1])) {
+ continue;
+ }
+
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* If point is inside the face */
+ if (isect_point_tri_v2(point[sample], uv1, uv2, uv3) != 0) {
+ float uv[2];
+
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0][0] + jitter5sample[j * 2] / w;
+ uv[1] = point[0][1] + jitter5sample[j * 2 + 1] / h;
+
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* Set surface point face values */
+ tPoint->tri_index = i;
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ sample = 5; /* make sure we exit sample loop as well */
+ break;
+ }
+ }
+ }
+ }
}
static void dynamic_paint_create_uv_surface_neighbor_cb(
- void *__restrict userdata,
- const int ty,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int ty, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintCreateUVSurfaceData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- PaintUVPoint *tempPoints = data->tempPoints;
- Vec3f *tempWeights = data->tempWeights;
-
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
- const MLoop *mloop = data->mloop;
-
- uint32_t *active_points = data->active_points;
-
- const float jitter5sample[10] = JITTER_SAMPLES;
- const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- const int w = surface->image_resolution;
- const int h = w;
-
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
-
- /* If point isn't on canvas mesh */
- if (tPoint->tri_index == -1) {
- float point[2];
-
- /* get loop area */
- const int u_min = (tx > 0) ? -1 : 0;
- const int u_max = (tx < (w - 1)) ? 1 : 0;
- const int v_min = (ty > 0) ? -1 : 0;
- const int v_max = (ty < (h - 1)) ? 1 : 0;
-
- point[0] = ((float)tx + 0.5f) / w;
- point[1] = ((float)ty + 0.5f) / h;
-
- /* search through defined area for neighbor, checking grid directions first */
- for (int ni = 0; ni < 8; ni++) {
- int u = neighStraightX[ni];
- int v = neighStraightY[ni];
-
- if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
- /* if not this pixel itself */
- if (u != 0 || v != 0) {
- const int ind = (tx + u) + w * (ty + v);
-
- /* if neighbor has index */
- if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
- float uv[2];
- const int i = tempPoints[ind].tri_index;
- const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
- const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
- const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
-
- /* tri index */
- /* There is a low possibility of actually having a neighbor point which tri is
- * already set from another neighbor in a separate thread here.
- * Checking for both tri_index and neighbour_pixel above reduces that probability
- * but it remains possible.
- * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
- * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
- */
- tPoint->neighbour_pixel = ind - 1;
- atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
- tPoint->tri_index = i;
-
- /* Now calculate pixel data for this pixel as it was on polygon surface */
- /* Add b-weights per anti-aliasing sample */
- for (int j = 0; j < aa_samples; j++) {
- uv[0] = point[0] + jitter5sample[j * 2] / w;
- uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
- barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
- }
-
- /* save vertex indexes */
- tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
- tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
- tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
-
- break;
- }
- }
- }
- }
- }
-
- /* Increase the final number of active surface points if relevant. */
- if (tPoint->tri_index != -1)
- atomic_add_and_fetch_uint32(active_points, 1);
- }
+ const DynamicPaintCreateUVSurfaceData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ PaintUVPoint *tempPoints = data->tempPoints;
+ Vec3f *tempWeights = data->tempWeights;
+
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+ const MLoop *mloop = data->mloop;
+
+ uint32_t *active_points = data->active_points;
+
+ const float jitter5sample[10] = JITTER_SAMPLES;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ PaintUVPoint *tPoint = &tempPoints[index];
+
+ /* If point isn't on canvas mesh */
+ if (tPoint->tri_index == -1) {
+ float point[2];
+
+ /* get loop area */
+ const int u_min = (tx > 0) ? -1 : 0;
+ const int u_max = (tx < (w - 1)) ? 1 : 0;
+ const int v_min = (ty > 0) ? -1 : 0;
+ const int v_max = (ty < (h - 1)) ? 1 : 0;
+
+ point[0] = ((float)tx + 0.5f) / w;
+ point[1] = ((float)ty + 0.5f) / h;
+
+ /* search through defined area for neighbor, checking grid directions first */
+ for (int ni = 0; ni < 8; ni++) {
+ int u = neighStraightX[ni];
+ int v = neighStraightY[ni];
+
+ if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
+ /* if not this pixel itself */
+ if (u != 0 || v != 0) {
+ const int ind = (tx + u) + w * (ty + v);
+
+ /* if neighbor has index */
+ if (tempPoints[ind].neighbour_pixel == -1 && tempPoints[ind].tri_index != -1) {
+ float uv[2];
+ const int i = tempPoints[ind].tri_index;
+ const float *uv1 = mloopuv[mlooptri[i].tri[0]].uv;
+ const float *uv2 = mloopuv[mlooptri[i].tri[1]].uv;
+ const float *uv3 = mloopuv[mlooptri[i].tri[2]].uv;
+
+ /* tri index */
+ /* There is a low possibility of actually having a neighbor point which tri is
+ * already set from another neighbor in a separate thread here.
+ * Checking for both tri_index and neighbour_pixel above reduces that probability
+ * but it remains possible.
+ * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set
+ * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour).
+ */
+ tPoint->neighbour_pixel = ind - 1;
+ atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1);
+ tPoint->tri_index = i;
+
+ /* Now calculate pixel data for this pixel as it was on polygon surface */
+ /* Add b-weights per anti-aliasing sample */
+ for (int j = 0; j < aa_samples; j++) {
+ uv[0] = point[0] + jitter5sample[j * 2] / w;
+ uv[1] = point[1] + jitter5sample[j * 2 + 1] / h;
+ barycentric_weights_v2(uv1, uv2, uv3, uv, tempWeights[index * aa_samples + j].v);
+ }
+
+ /* save vertex indexes */
+ tPoint->v1 = mloop[mlooptri[i].tri[0]].v;
+ tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
+ tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Increase the final number of active surface points if relevant. */
+ if (tPoint->tri_index != -1)
+ atomic_add_and_fetch_uint32(active_points, 1);
+ }
}
#undef JITTER_SAMPLES
-static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2])
+static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
+ const MLoopUV *mloopuv,
+ int tri_index,
+ const float point[2])
{
- float min_distance = FLT_MAX;
+ float min_distance = FLT_MAX;
- for (int i = 0; i < 3; i++) {
- const float dist_squared = dist_squared_to_line_segment_v2(
- point,
- mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
- mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv
- );
+ for (int i = 0; i < 3; i++) {
+ const float dist_squared = dist_squared_to_line_segment_v2(
+ point,
+ mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv,
+ mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv);
- if (dist_squared < min_distance) {
- min_distance = dist_squared;
- }
- }
+ if (dist_squared < min_distance) {
+ min_distance = dist_squared;
+ }
+ }
- return min_distance;
+ return min_distance;
}
typedef struct DynamicPaintFindIslandBorderData {
- const MeshElemMap *vert_to_looptri_map;
- int w, h, px, py;
+ const MeshElemMap *vert_to_looptri_map;
+ int w, h, px, py;
- int best_index;
- float best_weight;
+ int best_index;
+ float best_weight;
} DynamicPaintFindIslandBorderData;
-static void dynamic_paint_find_island_border(
- const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
- int tri_index, const float pixel[2], int in_edge, int depth);
+static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceData *data,
+ DynamicPaintFindIslandBorderData *bdata,
+ int tri_index,
+ const float pixel[2],
+ int in_edge,
+ int depth);
/* Tries to find the neighboring pixel in given (uv space) direction.
* Result is used by effect system to move paint on the surface.
@@ -2468,936 +2475,956 @@ static void dynamic_paint_find_island_border(
* px, py : origin pixel x and y
* n_index : lookup direction index (use neighX, neighY to get final index)
*/
-static int dynamic_paint_find_neighbour_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)
+static int dynamic_paint_find_neighbour_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)
{
- /* Note: Current method only uses polygon edges to detect neighboring pixels.
- * -> It doesn't always lead to the optimum pixel but is accurate enough
- * and faster/simpler than including possible face tip point links)
- */
-
- /* shift position by given n_index */
- const int x = px + neighX[n_index];
- const int y = py + neighY[n_index];
-
- if (x < 0 || x >= w || y < 0 || y >= h)
- return OUT_OF_TEXTURE;
-
- const PaintUVPoint *tempPoints = data->tempPoints;
- const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
- const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
-
- /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
- if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
- return (x + w * y);
-
- /* Even if shifted point is on another face
- * -> use this point.
- *
- * !! Replace with "is uv faces linked" check !!
- * This should work fine as long as uv island margin is > 1 pixel.
- */
- if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
- return (x + w * y);
- }
-
- /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
- * and we have to find its "real" position.
- *
- * Simple neighboring face finding algorithm:
- * - find closest uv edge to shifted pixel and get the another face that shares that edge
- * - find corresponding position of that new face edge in uv space
- *
- * TODO: Implement something more accurate / optimized?
- */
- {
- DynamicPaintFindIslandBorderData bdata = {
- .vert_to_looptri_map = vert_to_looptri_map,
- .w = w, .h = h, .px = px, .py = py,
- .best_index = NOT_FOUND, .best_weight = 1.0f,
- };
-
- float pixel[2];
-
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
-
- /* Do a small recursive search for the best island edge. */
- dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
-
- return bdata.best_index;
- }
+ /* Note: Current method only uses polygon edges to detect neighboring pixels.
+ * -> It doesn't always lead to the optimum pixel but is accurate enough
+ * and faster/simpler than including possible face tip point links)
+ */
+
+ /* shift position by given n_index */
+ const int x = px + neighX[n_index];
+ const int y = py + neighY[n_index];
+
+ if (x < 0 || x >= w || y < 0 || y >= h)
+ return OUT_OF_TEXTURE;
+
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ const PaintUVPoint *tPoint = &tempPoints[x + w * y]; /* UV neighbor */
+ const PaintUVPoint *cPoint = &tempPoints[px + w * py]; /* Origin point */
+
+ /* Check if shifted point is on same face -> it's a correct neighbor (and if it isn't marked as an "edge pixel") */
+ if ((tPoint->tri_index == cPoint->tri_index) && (tPoint->neighbour_pixel == -1))
+ return (x + w * y);
+
+ /* Even if shifted point is on another face
+ * -> use this point.
+ *
+ * !! Replace with "is uv faces linked" check !!
+ * This should work fine as long as uv island margin is > 1 pixel.
+ */
+ if ((tPoint->tri_index != -1) && (tPoint->neighbour_pixel == -1)) {
+ return (x + w * y);
+ }
+
+ /* If we get here, the actual neighboring pixel is located on a non-linked uv face,
+ * and we have to find its "real" position.
+ *
+ * Simple neighboring face finding algorithm:
+ * - find closest uv edge to shifted pixel and get the another face that shares that edge
+ * - find corresponding position of that new face edge in uv space
+ *
+ * TODO: Implement something more accurate / optimized?
+ */
+ {
+ DynamicPaintFindIslandBorderData bdata = {
+ .vert_to_looptri_map = vert_to_looptri_map,
+ .w = w,
+ .h = h,
+ .px = px,
+ .py = py,
+ .best_index = NOT_FOUND,
+ .best_weight = 1.0f,
+ };
+
+ float pixel[2];
+
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
+
+ /* Do a small recursive search for the best island edge. */
+ dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5);
+
+ return bdata.best_index;
+ }
}
-static void dynamic_paint_find_island_border(
- const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata,
- int tri_index, const float pixel[2], int in_edge, int depth)
+static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceData *data,
+ DynamicPaintFindIslandBorderData *bdata,
+ int tri_index,
+ const float pixel[2],
+ int in_edge,
+ int depth)
{
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const MLoopUV *mloopuv = data->mloopuv;
-
- const unsigned int *loop_idx = mlooptri[tri_index].tri;
-
- /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
- for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
- /* but not the edge we have just recursed through */
- if (edge_idx == in_edge)
- continue;
-
- float uv0[2], uv1[2], uv2[2];
-
- copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
- copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
- copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
+
+ const unsigned int *loop_idx = mlooptri[tri_index].tri;
+
+ /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */
+ for (int edge_idx = 0; edge_idx < 3; edge_idx++) {
+ /* but not the edge we have just recursed through */
+ if (edge_idx == in_edge)
+ continue;
+
+ float uv0[2], uv1[2], uv2[2];
+
+ copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv);
+ copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv);
+ copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv);
- /* Verify the target point is on the opposite side of the edge from the third triangle
- * vertex, to ensure that we always move closer to the goal point. */
- const float sidep = line_point_side_v2(uv0, uv1, pixel);
- const float side2 = line_point_side_v2(uv0, uv1, uv2);
+ /* Verify the target point is on the opposite side of the edge from the third triangle
+ * vertex, to ensure that we always move closer to the goal point. */
+ const float sidep = line_point_side_v2(uv0, uv1, pixel);
+ const float side2 = line_point_side_v2(uv0, uv1, uv2);
- if (side2 == 0.0f)
- continue;
+ if (side2 == 0.0f)
+ continue;
- /* Hack: allow all edges of the original triangle */
- const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0);
+ /* Hack: allow all edges of the original triangle */
+ const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) ||
+ (sidep > 0 && side2 < 0);
- /* Allow exactly on edge for the non-recursive case */
- if (!correct_side && sidep != 0.0f)
- continue;
+ /* Allow exactly on edge for the non-recursive case */
+ if (!correct_side && sidep != 0.0f)
+ continue;
- /* Now find another face that is linked to that edge. */
- const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
- const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
+ /* Now find another face that is linked to that edge. */
+ const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v;
+ const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
- /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
- const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
- bool found_other = false;
- int target_tri = -1;
- int target_edge = -1;
+ bool found_other = false;
+ int target_tri = -1;
+ int target_edge = -1;
- float ouv0[2], ouv1[2];
+ float ouv0[2], ouv1[2];
- for (int i = 0; i < map->count && !found_other; i++) {
- const int lt_index = map->indices[i];
+ for (int i = 0; i < map->count && !found_other; i++) {
+ const int lt_index = map->indices[i];
- if (lt_index == tri_index)
- continue;
-
- const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
+ if (lt_index == tri_index)
+ continue;
+
+ const unsigned int *other_loop_idx = mlooptri[lt_index].tri;
- /* Check edges for match, looping in the same order as the outer loop. */
- for (int j = 0; j < 3; j++) {
- const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
- const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
-
- /* Allow for swapped vertex order */
- if (overt0 == vert0 && overt1 == vert1) {
- found_other = true;
- copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
- copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
- }
- else if (overt0 == vert1 && overt1 == vert0) {
- found_other = true;
- copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
- copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
- }
-
- if (found_other) {
- target_tri = lt_index;
- target_edge = j;
- break;
- }
- }
- }
-
- if (!found_other) {
- if (bdata->best_index < 0)
- bdata->best_index = ON_MESH_EDGE;
-
- continue;
- }
-
- /* If this edge is connected in UV space too, recurse */
- if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
- if (depth > 0 && correct_side) {
- dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
- }
-
- continue;
- }
-
- /* Otherwise try to map to the other side of the edge.
- * First check if there already is a better solution. */
- const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
-
- if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
- continue;
+ /* Check edges for match, looping in the same order as the outer loop. */
+ for (int j = 0; j < 3; j++) {
+ const int overt0 = mloop[other_loop_idx[(j + 0)]].v;
+ const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v;
+
+ /* Allow for swapped vertex order */
+ if (overt0 == vert0 && overt1 == vert1) {
+ found_other = true;
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+ else if (overt0 == vert1 && overt1 == vert0) {
+ found_other = true;
+ copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv);
+ copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv);
+ }
+
+ if (found_other) {
+ target_tri = lt_index;
+ target_edge = j;
+ break;
+ }
+ }
+ }
+
+ if (!found_other) {
+ if (bdata->best_index < 0)
+ bdata->best_index = ON_MESH_EDGE;
+
+ continue;
+ }
+
+ /* If this edge is connected in UV space too, recurse */
+ if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) {
+ if (depth > 0 && correct_side) {
+ dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1);
+ }
+
+ continue;
+ }
+
+ /* Otherwise try to map to the other side of the edge.
+ * First check if there already is a better solution. */
+ const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1);
+
+ if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight)
+ continue;
+
+ /*
+ * Find a point that is relatively at same edge position
+ * on this other face UV
+ */
+ float closest_point[2], dir_vec[2], tgt_pixel[2];
+
+ float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
+ CLAMP(lambda, 0.0f, 1.0f);
- /*
- * Find a point that is relatively at same edge position
- * on this other face UV
- */
- float closest_point[2], dir_vec[2], tgt_pixel[2];
-
- float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1);
- CLAMP(lambda, 0.0f, 1.0f);
-
- sub_v2_v2v2(dir_vec, ouv1, ouv0);
- madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
-
- int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
-
- int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) };
-
- /* If current pixel uv is outside of texture */
- if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
- if (bdata->best_index == NOT_FOUND)
- bdata->best_index = OUT_OF_TEXTURE;
-
- continue;
- }
-
- const PaintUVPoint *tempPoints = data->tempPoints;
- int final_index = final_pixel[0] + w * final_pixel[1];
-
- /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
- if (final_index == (px + w * py))
- continue;
-
- /* If final point is an "edge pixel", use it's "real" neighbor instead */
- if (tempPoints[final_index].neighbour_pixel != -1) {
- final_index = tempPoints[final_index].neighbour_pixel;
-
- /* If we ended up to our origin point */
- if (final_index == (px + w * py))
- continue;
- }
-
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
- /* Check if it's close enough to likely touch the intended triangle. Any triangle
- * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
- const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h };
- const float threshold = SQUARE(0.7f) / (w * h);
-
- if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
- continue;
- }
-
- bdata->best_index = final_index;
- bdata->best_weight = dist_squared;
- }
+ sub_v2_v2v2(dir_vec, ouv1, ouv0);
+ madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda);
+
+ int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py;
+
+ int final_pixel[2] = {(int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h)};
+
+ /* If current pixel uv is outside of texture */
+ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) {
+ if (bdata->best_index == NOT_FOUND)
+ bdata->best_index = OUT_OF_TEXTURE;
+
+ continue;
+ }
+
+ const PaintUVPoint *tempPoints = data->tempPoints;
+ int final_index = final_pixel[0] + w * final_pixel[1];
+
+ /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */
+ if (final_index == (px + w * py))
+ continue;
+
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1) {
+ final_index = tempPoints[final_index].neighbour_pixel;
+
+ /* If we ended up to our origin point */
+ if (final_index == (px + w * py))
+ continue;
+ }
+
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri) {
+ /* Check if it's close enough to likely touch the intended triangle. Any triangle
+ * becomes thinner than a pixel at its vertices, so robustness requires some margin. */
+ const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
+ const float threshold = SQUARE(0.7f) / (w * h);
+
+ if (dist_squared_to_looptri_uv_edges(
+ mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold)
+ continue;
+ }
+
+ bdata->best_index = final_index;
+ bdata->best_weight = dist_squared;
+ }
}
static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor)
{
- const int idx = ed->n_index[index];
+ const int idx = ed->n_index[index];
- for (int i = 0; i < ed->n_num[index]; i++) {
- if (ed->n_target[idx + i] == neighbor) {
- return true;
- }
- }
+ for (int i = 0; i < ed->n_num[index]; i++) {
+ if (ed->n_target[idx + i] == neighbor) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */
static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points)
{
- int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
- int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
-
- if (new_n_num && new_n_index) {
- /* Count symmetrized neigbors */
- int total_targets = 0;
-
- for (int index = 0; index < active_points; index++) {
- total_targets += ed->n_num[index];
- new_n_num[index] = ed->n_num[index];
- }
-
- for (int index = 0; index < active_points; index++) {
- if (ed->flags[index] & ADJ_BORDER_PIXEL) {
- continue;
- }
-
- for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
- const int target = ed->n_target[idx + i];
-
- assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
-
- if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
- new_n_num[target]++;
- total_targets++;
- }
- }
- }
-
- /* Allocate a new target map */
- int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
-
- if (new_n_target) {
- /* Copy existing neighbors to the new map */
- int n_pos = 0;
-
- for (int index = 0; index < active_points; index++) {
- new_n_index[index] = n_pos;
- memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]);
-
- /* Reset count to old, but advance position by new, leaving a gap to fill below. */
- n_pos += new_n_num[index];
- new_n_num[index] = ed->n_num[index];
- }
-
- assert(n_pos == total_targets);
-
- /* Add symmetrized - this loop behavior must exactly match the count pass above */
- for (int index = 0; index < active_points; index++) {
- if (ed->flags[index] & ADJ_BORDER_PIXEL) {
- continue;
- }
-
- for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
- const int target = ed->n_target[idx + i];
-
- if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
- const int num = new_n_num[target]++;
- new_n_target[new_n_index[target] + num] = index;
- }
- }
- }
-
- /* Swap maps */
- MEM_freeN(ed->n_target);
- ed->n_target = new_n_target;
-
- MEM_freeN(ed->n_index);
- ed->n_index = new_n_index;
-
- MEM_freeN(ed->n_num);
- ed->n_num = new_n_num;
-
- ed->total_targets = total_targets;
- return true;
- }
- }
-
- if (new_n_index)
- MEM_freeN(new_n_index);
- if (new_n_num)
- MEM_freeN(new_n_num);
-
- return false;
+ int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index");
+ int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts");
+
+ if (new_n_num && new_n_index) {
+ /* Count symmetrized neigbors */
+ int total_targets = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ total_targets += ed->n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ assert(!(ed->flags[target] & ADJ_BORDER_PIXEL));
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ new_n_num[target]++;
+ total_targets++;
+ }
+ }
+ }
+
+ /* Allocate a new target map */
+ int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets");
+
+ if (new_n_target) {
+ /* Copy existing neighbors to the new map */
+ int n_pos = 0;
+
+ for (int index = 0; index < active_points; index++) {
+ new_n_index[index] = n_pos;
+ memcpy(&new_n_target[n_pos],
+ &ed->n_target[ed->n_index[index]],
+ sizeof(int) * ed->n_num[index]);
+
+ /* Reset count to old, but advance position by new, leaving a gap to fill below. */
+ n_pos += new_n_num[index];
+ new_n_num[index] = ed->n_num[index];
+ }
+
+ assert(n_pos == total_targets);
+
+ /* Add symmetrized - this loop behavior must exactly match the count pass above */
+ for (int index = 0; index < active_points; index++) {
+ if (ed->flags[index] & ADJ_BORDER_PIXEL) {
+ continue;
+ }
+
+ for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) {
+ const int target = ed->n_target[idx + i];
+
+ if (!dynamicPaint_pointHasNeighbor(ed, target, index)) {
+ const int num = new_n_num[target]++;
+ new_n_target[new_n_index[target] + num] = index;
+ }
+ }
+ }
+
+ /* Swap maps */
+ MEM_freeN(ed->n_target);
+ ed->n_target = new_n_target;
+
+ MEM_freeN(ed->n_index);
+ ed->n_index = new_n_index;
+
+ MEM_freeN(ed->n_num);
+ ed->n_num = new_n_num;
+
+ ed->total_targets = total_targets;
+ return true;
+ }
+ }
+
+ if (new_n_index)
+ MEM_freeN(new_n_index);
+ if (new_n_num)
+ MEM_freeN(new_n_num);
+
+ return false;
}
-int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
+int dynamicPaint_createUVSurface(Scene *scene,
+ DynamicPaintSurface *surface,
+ float *progress,
+ short *do_update)
{
- /* Antialias jitter point relative coords */
- const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- uint32_t active_points = 0;
- bool error = false;
-
- PaintSurfaceData *sData;
- DynamicPaintCanvasSettings *canvas = surface->canvas;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(canvas);
-
- PaintUVPoint *tempPoints = NULL;
- Vec3f *tempWeights = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoopUV *mloopuv = NULL;
- const MLoop *mloop = NULL;
-
- Bounds2D *faceBB = NULL;
- int *final_index;
-
- *progress = 0.0f;
- *do_update = true;
-
- if (!mesh)
- return setError(canvas, N_("Canvas mesh not updated"));
- if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
- return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
-
- mloop = mesh->mloop;
- mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- const int tottri = BKE_mesh_runtime_looptri_len(mesh);
-
- /* get uv map */
- if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
- CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
- mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
- }
-
- /* Check for validity */
- if (!mloopuv)
- return setError(canvas, N_("No UV data on canvas"));
- if (surface->image_resolution < 16 || surface->image_resolution > 8192)
- return setError(canvas, N_("Invalid resolution"));
-
- const int w = surface->image_resolution;
- const int h = w;
-
- /*
- * Start generating the surface
- */
- CLOG_INFO(&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, tottri);
-
- /* Init data struct */
- if (surface->data)
- dynamicPaint_freeSurfaceData(surface);
- sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
- if (!surface->data)
- return setError(canvas, N_("Not enough free memory"));
-
- tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
- if (!tempPoints)
- error = true;
-
- final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
- if (!final_index)
- error = true;
-
- tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
- if (!tempWeights)
- error = true;
-
- /*
- * Generate a temporary bounding box array for UV faces to optimize
- * the pixel-inside-a-face search.
- */
- if (!error) {
- faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
- if (!faceBB)
- error = true;
- }
-
- *progress = 0.01f;
- *do_update = true;
-
- if (!error) {
- for (int i = 0; i < tottri; i++) {
- copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
- copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
-
- for (int j = 1; j < 3; j++) {
- minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
- }
- }
-
- *progress = 0.02f;
- *do_update = true;
-
- /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
- DynamicPaintCreateUVSurfaceData data = {
- .surface = surface, .tempPoints = tempPoints, .tempWeights = tempWeights,
- .mlooptri = mlooptri, .mloopuv = mloopuv, .mloop = mloop, .tottri = tottri,
- .faceBB = faceBB,
- };
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (h > 64 || tottri > 1000);
- BLI_task_parallel_range(0, h,
- &data,
- dynamic_paint_create_uv_surface_direct_cb,
- &settings);
- }
-
- *progress = 0.04f;
- *do_update = true;
-
- /*
- * Now loop through every pixel that was left without index
- * and find if they have neighboring pixels that have an index.
- * If so use that polygon as pixel surface.
- * (To avoid seams on uv island edges)
- */
- data.active_points = &active_points;
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (h > 64);
- BLI_task_parallel_range(0, h,
- &data,
- dynamic_paint_create_uv_surface_neighbor_cb,
- &settings);
- }
-
- *progress = 0.06f;
- *do_update = true;
-
- /* Generate surface adjacency data. */
- {
- int cursor = 0;
-
- /* Create a temporary array of final indexes (before unassigned
- * pixels have been dropped) */
- for (int i = 0; i < w * h; i++) {
- if (tempPoints[i].tri_index != -1) {
- final_index[i] = cursor;
- cursor++;
- }
- }
- /* allocate memory */
- sData->total_points = w * h;
- dynamicPaint_initAdjacencyData(surface, true);
-
- if (sData->adj_data) {
- PaintAdjData *ed = sData->adj_data;
- int n_pos = 0;
-
- MeshElemMap *vert_to_looptri_map;
- int *vert_to_looptri_map_mem;
-
- BKE_mesh_vert_looptri_map_create(
- &vert_to_looptri_map, &vert_to_looptri_map_mem,
- mesh->mvert, mesh->totvert, mlooptri, tottri, mloop, mesh->totloop);
-
- int total_border = 0;
-
- for (int ty = 0; ty < h; ty++) {
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
-
- if (tempPoints[index].tri_index != -1) {
- ed->n_index[final_index[index]] = n_pos;
- ed->n_num[final_index[index]] = 0;
-
- if (tempPoints[index].neighbour_pixel != -1) {
- ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
- total_border++;
- }
-
- for (int i = 0; i < 8; i++) {
- /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
- const int n_target = dynamic_paint_find_neighbour_pixel(
- &data, vert_to_looptri_map, w, h, tx, ty, i);
-
- if (n_target >= 0 && n_target != index) {
- if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) {
- ed->n_target[n_pos] = final_index[n_target];
- ed->n_num[final_index[index]]++;
- n_pos++;
- }
- }
- else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
- ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
- }
- }
- }
- }
- }
-
- MEM_freeN(vert_to_looptri_map);
- MEM_freeN(vert_to_looptri_map_mem);
-
- /* Make neighbors symmetric */
- if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
- error = true;
- }
-
- /* Create a list of border pixels */
- ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
-
- if (ed->border) {
- ed->total_border = total_border;
-
- for (int i = 0, next = 0; i < active_points; i++) {
- if (ed->flags[i] & ADJ_BORDER_PIXEL) {
- ed->border[next++] = i;
- }
- }
- }
+ /* Antialias jitter point relative coords */
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ char uvname[MAX_CUSTOMDATA_LAYER_NAME];
+ uint32_t active_points = 0;
+ bool error = false;
+
+ PaintSurfaceData *sData;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(canvas);
+
+ PaintUVPoint *tempPoints = NULL;
+ Vec3f *tempWeights = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoopUV *mloopuv = NULL;
+ const MLoop *mloop = NULL;
+
+ Bounds2D *faceBB = NULL;
+ int *final_index;
+
+ *progress = 0.0f;
+ *do_update = true;
+
+ if (!mesh)
+ return setError(canvas, N_("Canvas mesh not updated"));
+ if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
+
+ mloop = mesh->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
+
+ /* get uv map */
+ if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
+ }
+
+ /* Check for validity */
+ if (!mloopuv)
+ return setError(canvas, N_("No UV data on canvas"));
+ if (surface->image_resolution < 16 || surface->image_resolution > 8192)
+ return setError(canvas, N_("Invalid resolution"));
+
+ const int w = surface->image_resolution;
+ const int h = w;
+
+ /*
+ * Start generating the surface
+ */
+ CLOG_INFO(&LOG, 1, "Preparing UV surface of %ix%i pixels and %i tris.", w, h, tottri);
+
+ /* Init data struct */
+ if (surface->data)
+ dynamicPaint_freeSurfaceData(surface);
+ sData = surface->data = MEM_callocN(sizeof(PaintSurfaceData), "PaintSurfaceData");
+ if (!surface->data)
+ return setError(canvas, N_("Not enough free memory"));
+
+ tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
+ if (!tempPoints)
+ error = true;
+
+ final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
+ if (!final_index)
+ error = true;
+
+ tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
+ if (!tempWeights)
+ error = true;
+
+ /*
+ * Generate a temporary bounding box array for UV faces to optimize
+ * the pixel-inside-a-face search.
+ */
+ if (!error) {
+ faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
+ if (!faceBB)
+ error = true;
+ }
+
+ *progress = 0.01f;
+ *do_update = true;
+
+ if (!error) {
+ for (int i = 0; i < tottri; i++) {
+ copy_v2_v2(faceBB[i].min, mloopuv[mlooptri[i].tri[0]].uv);
+ copy_v2_v2(faceBB[i].max, mloopuv[mlooptri[i].tri[0]].uv);
+
+ for (int j = 1; j < 3; j++) {
+ minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
+ }
+ }
+
+ *progress = 0.02f;
+ *do_update = true;
+
+ /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
+ DynamicPaintCreateUVSurfaceData data = {
+ .surface = surface,
+ .tempPoints = tempPoints,
+ .tempWeights = tempWeights,
+ .mlooptri = mlooptri,
+ .mloopuv = mloopuv,
+ .mloop = mloop,
+ .tottri = tottri,
+ .faceBB = faceBB,
+ };
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (h > 64 || tottri > 1000);
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, &settings);
+ }
+
+ *progress = 0.04f;
+ *do_update = true;
+
+ /*
+ * Now loop through every pixel that was left without index
+ * and find if they have neighboring pixels that have an index.
+ * If so use that polygon as pixel surface.
+ * (To avoid seams on uv island edges)
+ */
+ data.active_points = &active_points;
+ {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (h > 64);
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, &settings);
+ }
+
+ *progress = 0.06f;
+ *do_update = true;
+
+ /* Generate surface adjacency data. */
+ {
+ int cursor = 0;
+
+ /* Create a temporary array of final indexes (before unassigned
+ * pixels have been dropped) */
+ for (int i = 0; i < w * h; i++) {
+ if (tempPoints[i].tri_index != -1) {
+ final_index[i] = cursor;
+ cursor++;
+ }
+ }
+ /* allocate memory */
+ sData->total_points = w * h;
+ dynamicPaint_initAdjacencyData(surface, true);
+
+ if (sData->adj_data) {
+ PaintAdjData *ed = sData->adj_data;
+ int n_pos = 0;
+
+ MeshElemMap *vert_to_looptri_map;
+ int *vert_to_looptri_map_mem;
+
+ BKE_mesh_vert_looptri_map_create(&vert_to_looptri_map,
+ &vert_to_looptri_map_mem,
+ mesh->mvert,
+ mesh->totvert,
+ mlooptri,
+ tottri,
+ mloop,
+ mesh->totloop);
+
+ int total_border = 0;
+
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+
+ if (tempPoints[index].tri_index != -1) {
+ ed->n_index[final_index[index]] = n_pos;
+ ed->n_num[final_index[index]] = 0;
+
+ if (tempPoints[index].neighbour_pixel != -1) {
+ ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL;
+ total_border++;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */
+ const int n_target = dynamic_paint_find_neighbour_pixel(
+ &data, vert_to_looptri_map, w, h, tx, ty, i);
+
+ if (n_target >= 0 && n_target != index) {
+ if (!dynamicPaint_pointHasNeighbor(
+ ed, final_index[index], final_index[n_target])) {
+ ed->n_target[n_pos] = final_index[n_target];
+ ed->n_num[final_index[index]]++;
+ n_pos++;
+ }
+ }
+ else if (n_target == ON_MESH_EDGE || n_target == OUT_OF_TEXTURE) {
+ ed->flags[final_index[index]] |= ADJ_ON_MESH_EDGE;
+ }
+ }
+ }
+ }
+ }
+
+ MEM_freeN(vert_to_looptri_map);
+ MEM_freeN(vert_to_looptri_map_mem);
+
+ /* Make neighbors symmetric */
+ if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) {
+ error = true;
+ }
+
+ /* Create a list of border pixels */
+ ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index");
+
+ if (ed->border) {
+ ed->total_border = total_border;
+
+ for (int i = 0, next = 0; i < active_points; i++) {
+ if (ed->flags[i] & ADJ_BORDER_PIXEL) {
+ ed->border[next++] = i;
+ }
+ }
+ }
#if 0
- /* -----------------------------------------------------------------
- * For debug, write a dump of adjacency data to a file.
- * -----------------------------------------------------------------*/
- FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
- int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
- for (int ty = 0; ty < h; ty++) {
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- if (tempPoints[index].tri_index != -1)
- tmp[final_index[index]] = index;
- }
- }
- for (int ty = 0; ty < h; ty++) {
- for (int tx = 0; tx < w; tx++) {
- const int index = tx + w * ty;
- const int fidx = final_index[index];
-
- if (tempPoints[index].tri_index != -1) {
- int nidx = tempPoints[index].neighbour_pixel;
- fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
- for (int i = 0; i < ed->n_num[fidx]; i++) {
- int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
- fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
- }
- fprintf(dump_file, "\n");
- }
- }
- }
- MEM_freeN(tmp);
- fclose(dump_file);
+ /* -----------------------------------------------------------------
+ * For debug, write a dump of adjacency data to a file.
+ * -----------------------------------------------------------------*/
+ FILE *dump_file = fopen("dynpaint-adj-data.txt", "w");
+ int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp");
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ if (tempPoints[index].tri_index != -1)
+ tmp[final_index[index]] = index;
+ }
+ }
+ for (int ty = 0; ty < h; ty++) {
+ for (int tx = 0; tx < w; tx++) {
+ const int index = tx + w * ty;
+ const int fidx = final_index[index];
+
+ if (tempPoints[index].tri_index != -1) {
+ int nidx = tempPoints[index].neighbour_pixel;
+ fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]);
+ for (int i = 0; i < ed->n_num[fidx]; i++) {
+ int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]];
+ fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w);
+ }
+ fprintf(dump_file, "\n");
+ }
+ }
+ }
+ MEM_freeN(tmp);
+ fclose(dump_file);
#endif
- }
- }
-
- *progress = 0.08f;
- *do_update = true;
-
- /* Create final surface data without inactive points */
- ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
- if (f_data) {
- f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
- f_data->barycentricWeights =
- MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
-
- if (!f_data->uv_p || !f_data->barycentricWeights)
- error = 1;
- }
- else {
- error = 1;
- }
-
- /* in case of allocation error, free everything */
- if (error) {
- if (f_data) {
- if (f_data->uv_p)
- MEM_freeN(f_data->uv_p);
- if (f_data->barycentricWeights)
- MEM_freeN(f_data->barycentricWeights);
- MEM_freeN(f_data);
- }
- sData->total_points = 0;
- }
- else {
- sData->total_points = (int)active_points;
- sData->format_data = f_data;
-
- for (int index = 0, cursor = 0; index < (w * h); index++) {
- if (tempPoints[index].tri_index != -1) {
- memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
- memcpy(&f_data->barycentricWeights[cursor * aa_samples], &tempWeights[index * aa_samples],
- sizeof(*tempWeights) * aa_samples);
- cursor++;
- }
- }
- }
- }
- if (error == 1)
- setError(canvas, N_("Not enough free memory"));
-
- if (faceBB)
- MEM_freeN(faceBB);
- if (tempPoints)
- MEM_freeN(tempPoints);
- if (tempWeights)
- MEM_freeN(tempWeights);
- if (final_index)
- MEM_freeN(final_index);
-
- /* Init surface type data */
- if (!error) {
- dynamicPaint_allocateSurfaceType(surface);
+ }
+ }
+
+ *progress = 0.08f;
+ *do_update = true;
+
+ /* Create final surface data without inactive points */
+ ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData");
+ if (f_data) {
+ f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint");
+ f_data->barycentricWeights = MEM_callocN(
+ active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint");
+
+ if (!f_data->uv_p || !f_data->barycentricWeights)
+ error = 1;
+ }
+ else {
+ error = 1;
+ }
+
+ /* in case of allocation error, free everything */
+ if (error) {
+ if (f_data) {
+ if (f_data->uv_p)
+ MEM_freeN(f_data->uv_p);
+ if (f_data->barycentricWeights)
+ MEM_freeN(f_data->barycentricWeights);
+ MEM_freeN(f_data);
+ }
+ sData->total_points = 0;
+ }
+ else {
+ sData->total_points = (int)active_points;
+ sData->format_data = f_data;
+
+ for (int index = 0, cursor = 0; index < (w * h); index++) {
+ if (tempPoints[index].tri_index != -1) {
+ memcpy(&f_data->uv_p[cursor], &tempPoints[index], sizeof(PaintUVPoint));
+ memcpy(&f_data->barycentricWeights[cursor * aa_samples],
+ &tempWeights[index * aa_samples],
+ sizeof(*tempWeights) * aa_samples);
+ cursor++;
+ }
+ }
+ }
+ }
+ if (error == 1)
+ setError(canvas, N_("Not enough free memory"));
+
+ if (faceBB)
+ MEM_freeN(faceBB);
+ if (tempPoints)
+ MEM_freeN(tempPoints);
+ if (tempWeights)
+ MEM_freeN(tempWeights);
+ if (final_index)
+ MEM_freeN(final_index);
+
+ /* Init surface type data */
+ if (!error) {
+ dynamicPaint_allocateSurfaceType(surface);
#if 0
- /* -----------------------------------------------------------------
- * For debug, output pixel statuses to the color map
- * -----------------------------------------------------------------*/
- for (index = 0; index < sData->total_points; index++) {
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- pPoint->alpha = 1.0f;
-
- /* Every pixel that is assigned as "edge pixel" gets blue color */
- if (uvPoint->neighbour_pixel != -1)
- pPoint->color[2] = 1.0f;
- /* and every pixel that finally got an polygon gets red color */
- /* green color shows pixel face index hash */
- if (uvPoint->tri_index != -1) {
- pPoint->color[0] = 1.0f;
- pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
- }
- }
+ /* -----------------------------------------------------------------
+ * For debug, output pixel statuses to the color map
+ * -----------------------------------------------------------------*/
+ for (index = 0; index < sData->total_points; index++) {
+ ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ pPoint->alpha = 1.0f;
+
+ /* Every pixel that is assigned as "edge pixel" gets blue color */
+ if (uvPoint->neighbour_pixel != -1)
+ pPoint->color[2] = 1.0f;
+ /* and every pixel that finally got an polygon gets red color */
+ /* green color shows pixel face index hash */
+ if (uvPoint->tri_index != -1) {
+ pPoint->color[0] = 1.0f;
+ pPoint->color[1] = (float)(uvPoint->tri_index % 255) / 256.0f;
+ }
+ }
#endif
- dynamicPaint_setInitialColor(scene, surface);
- }
+ dynamicPaint_setInitialColor(scene, surface);
+ }
- *progress = 0.09f;
- *do_update = true;
+ *progress = 0.09f;
+ *do_update = true;
- return (error == 0);
+ return (error == 0);
}
/*
* Outputs an image file from uv surface data.
*/
typedef struct DynamicPaintOutputSurfaceImageData {
- const DynamicPaintSurface *surface;
- ImBuf *ibuf;
+ const DynamicPaintSurface *surface;
+ ImBuf *ibuf;
} DynamicPaintOutputSurfaceImageData;
static void dynamic_paint_output_surface_image_paint_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- /* blend wet and dry layers */
- blendColors(point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
+ /* blend wet and dry layers */
+ blendColors(
+ point->color, point->color[3], point->e_color, point->e_color[3], &ibuf->rect_float[pos]);
- /* Multiply color by alpha if enabled */
- if (surface->flags & MOD_DPAINT_MULALPHA) {
- mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
- }
+ /* Multiply color by alpha if enabled */
+ if (surface->flags & MOD_DPAINT_MULALPHA) {
+ mul_v3_fl(&ibuf->rect_float[pos], ibuf->rect_float[pos + 3]);
+ }
}
static void dynamic_paint_output_surface_image_displace_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- float depth = ((float *)surface->data->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ float depth = ((float *)surface->data->type_data)[index];
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
- if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- depth = (0.5f - depth / 2.0f);
- }
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ depth = (0.5f - depth / 2.0f);
+ }
- CLAMP(depth, 0.0f, 1.0f);
+ CLAMP(depth, 0.0f, 1.0f);
- copy_v3_fl(&ibuf->rect_float[pos], depth);
- ibuf->rect_float[pos + 3] = 1.0f;
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
}
static void dynamic_paint_output_surface_image_wave_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
- float depth = wPoint->height;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintWavePoint *wPoint = &((PaintWavePoint *)surface->data->type_data)[index];
+ float depth = wPoint->height;
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
- depth = (0.5f + depth / 2.0f);
- CLAMP(depth, 0.0f, 1.0f);
+ depth = (0.5f + depth / 2.0f);
+ CLAMP(depth, 0.0f, 1.0f);
- copy_v3_fl(&ibuf->rect_float[pos], depth);
- ibuf->rect_float[pos + 3] = 1.0f;
+ copy_v3_fl(&ibuf->rect_float[pos], depth);
+ ibuf->rect_float[pos + 3] = 1.0f;
}
static void dynamic_paint_output_surface_image_wetmap_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int index, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintOutputSurfaceImageData *data = userdata;
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintPoint *point = &((PaintPoint *)surface->data->type_data)[index];
- ImBuf *ibuf = data->ibuf;
- /* image buffer position */
- const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
+ ImBuf *ibuf = data->ibuf;
+ /* image buffer position */
+ const int pos = ((ImgSeqFormatData *)(surface->data->format_data))->uv_p[index].pixel_index * 4;
- copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
- ibuf->rect_float[pos + 3] = 1.0f;
+ copy_v3_fl(&ibuf->rect_float[pos], (point->wetness > 1.0f) ? 1.0f : point->wetness);
+ ibuf->rect_float[pos + 3] = 1.0f;
}
-void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filename, short output_layer)
+void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,
+ char *filename,
+ short output_layer)
{
- ImBuf *ibuf = NULL;
- PaintSurfaceData *sData = surface->data;
- /* OpenEXR or PNG */
- int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR : R_IMF_IMTYPE_PNG;
- char output_file[FILE_MAX];
-
- if (!sData->type_data) {
- setError(surface->canvas, N_("Image save failed: invalid surface"));
- return;
- }
- /* if selected format is openexr, but current build doesn't support one */
+ ImBuf *ibuf = NULL;
+ PaintSurfaceData *sData = surface->data;
+ /* OpenEXR or PNG */
+ int format = (surface->image_fileformat & MOD_DPAINT_IMGFORMAT_OPENEXR) ? R_IMF_IMTYPE_OPENEXR :
+ R_IMF_IMTYPE_PNG;
+ char output_file[FILE_MAX];
+
+ if (!sData->type_data) {
+ setError(surface->canvas, N_("Image save failed: invalid surface"));
+ return;
+ }
+ /* if selected format is openexr, but current build doesn't support one */
#ifndef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR)
- format = R_IMF_IMTYPE_PNG;
+ if (format == R_IMF_IMTYPE_OPENEXR)
+ format = R_IMF_IMTYPE_PNG;
#endif
- BLI_strncpy(output_file, filename, sizeof(output_file));
- BKE_image_path_ensure_ext_from_imtype(output_file, format);
-
- /* Validate output file path */
- BLI_path_abs(output_file, BKE_main_blendfile_path_from_global());
- BLI_make_existing_file(output_file);
-
- /* Init image buffer */
- ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
- if (ibuf == NULL) {
- setError(surface->canvas, N_("Image save failed: not enough free memory"));
- return;
- }
-
- DynamicPaintOutputSurfaceImageData data = { .surface = surface, .ibuf = ibuf, };
- switch (surface->type) {
- case MOD_DPAINT_SURFACE_T_PAINT:
- switch (output_layer) {
- case 0:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_paint_cb,
- &settings);
- break;
- }
- case 1:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_wetmap_cb,
- &settings);
- break;
- }
- default:
- BLI_assert(0);
- break;
- }
- break;
- case MOD_DPAINT_SURFACE_T_DISPLACE:
- switch (output_layer) {
- case 0:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_displace_cb,
- &settings);
- break;
- }
- case 1:
- break;
- default:
- BLI_assert(0);
- break;
- }
- break;
- case MOD_DPAINT_SURFACE_T_WAVE:
- switch (output_layer) {
- case 0:
- {
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 10000);
- BLI_task_parallel_range(
- 0, sData->total_points,
- &data,
- dynamic_paint_output_surface_image_wave_cb,
- &settings);
- break;
- }
- case 1:
- break;
- default:
- BLI_assert(0);
- break;
- }
- break;
- default:
- BLI_assert(0);
- break;
- }
-
- /* Set output format, png in case exr isn't supported */
+ BLI_strncpy(output_file, filename, sizeof(output_file));
+ BKE_image_path_ensure_ext_from_imtype(output_file, format);
+
+ /* Validate output file path */
+ BLI_path_abs(output_file, BKE_main_blendfile_path_from_global());
+ BLI_make_existing_file(output_file);
+
+ /* Init image buffer */
+ ibuf = IMB_allocImBuf(surface->image_resolution, surface->image_resolution, 32, IB_rectfloat);
+ if (ibuf == NULL) {
+ setError(surface->canvas, N_("Image save failed: not enough free memory"));
+ return;
+ }
+
+ DynamicPaintOutputSurfaceImageData data = {
+ .surface = surface,
+ .ibuf = ibuf,
+ };
+ switch (surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ switch (output_layer) {
+ case 0: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_paint_cb,
+ &settings);
+ break;
+ }
+ case 1: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_wetmap_cb,
+ &settings);
+ break;
+ }
+ default:
+ BLI_assert(0);
+ break;
+ }
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ switch (output_layer) {
+ case 0: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_displace_cb,
+ &settings);
+ break;
+ }
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ switch (output_layer) {
+ case 0: {
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 10000);
+ BLI_task_parallel_range(0,
+ sData->total_points,
+ &data,
+ dynamic_paint_output_surface_image_wave_cb,
+ &settings);
+ break;
+ }
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ /* Set output format, png in case exr isn't supported */
#ifdef WITH_OPENEXR
- if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
- ibuf->ftype = IMB_FTYPE_OPENEXR;
- ibuf->foptions.flag |= OPENEXR_COMPRESS;
- }
- else
+ if (format == R_IMF_IMTYPE_OPENEXR) { /* OpenEXR 32-bit float */
+ ibuf->ftype = IMB_FTYPE_OPENEXR;
+ ibuf->foptions.flag |= OPENEXR_COMPRESS;
+ }
+ else
#endif
- {
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15;
- }
-
- /* Save image */
- IMB_saveiff(ibuf, output_file, IB_rectfloat);
- IMB_freeImBuf(ibuf);
+ {
+ ibuf->ftype = IMB_FTYPE_PNG;
+ ibuf->foptions.quality = 15;
+ }
+
+ /* Save image */
+ IMB_saveiff(ibuf, output_file, IB_rectfloat);
+ IMB_freeImBuf(ibuf);
}
-
/***************************** Ray / Nearest Point Utils ******************************/
-
/* A modified callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_looptri.
* userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
*
* To optimize brush detection speed this doesn't calculate hit coordinates or normal.
*/
-static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void mesh_tris_spherecast_dp(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MLoopTri *mlooptri = data->looptri;
- const MLoop *mloop = data->loop;
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *mlooptri = data->looptri;
+ const MLoop *mloop = data->loop;
- const float *t0, *t1, *t2;
- float dist;
+ const float *t0, *t1, *t2;
+ float dist;
- t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
- t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
- t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
+ t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
+ t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
+ t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
- dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+ dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
- if (dist >= 0 && dist < hit->dist) {
- hit->index = index;
- hit->dist = dist;
- hit->no[0] = 0.0f;
- }
+ if (dist >= 0 && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ hit->no[0] = 0.0f;
+ }
}
/* A modified callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_looptri.
@@ -3405,31 +3432,33 @@ static void mesh_tris_spherecast_dp(void *userdata, int index, const BVHTreeRay
*
* To optimize brush detection speed this doesn't calculate hit normal.
*/
-static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+static void mesh_tris_nearest_point_dp(void *userdata,
+ int index,
+ const float co[3],
+ BVHTreeNearest *nearest)
{
- const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
- const MVert *vert = data->vert;
- const MLoopTri *mlooptri = data->looptri;
- const MLoop *mloop = data->loop;
- float nearest_tmp[3], dist_sq;
-
- const float *t0, *t1, *t2;
- t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
- t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
- t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
-
- closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
- dist_sq = len_squared_v3v3(co, nearest_tmp);
-
- if (dist_sq < nearest->dist_sq) {
- nearest->index = index;
- nearest->dist_sq = dist_sq;
- copy_v3_v3(nearest->co, nearest_tmp);
- nearest->no[0] = 0.0f;
- }
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *mlooptri = data->looptri;
+ const MLoop *mloop = data->loop;
+ float nearest_tmp[3], dist_sq;
+
+ const float *t0, *t1, *t2;
+ t0 = vert[mloop[mlooptri[index].tri[0]].v].co;
+ t1 = vert[mloop[mlooptri[index].tri[1]].v].co;
+ t2 = vert[mloop[mlooptri[index].tri[2]].v].co;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ nearest->no[0] = 0.0f;
+ }
}
-
/***************************** Brush Painting Calls ******************************/
/**
@@ -3442,986 +3471,1030 @@ static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co
* \param timescale: Value used to adjust time dependent
* operations when using substeps
*/
-static void dynamicPaint_mixPaintColors(
- const DynamicPaintSurface *surface, const int index, const int paintFlags,
- const float paintColor[3], const float paintAlpha, const float paintWetness, const float timescale)
+static void dynamicPaint_mixPaintColors(const DynamicPaintSurface *surface,
+ const int index,
+ const int paintFlags,
+ const float paintColor[3],
+ const float paintAlpha,
+ const float paintWetness,
+ const float timescale)
{
- PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
-
- /* Add paint */
- if (!(paintFlags & MOD_DPAINT_ERASE)) {
- float mix[4];
- float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
-
- /* mix brush color with wet layer color */
- blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
- copy_v3_v3(pPoint->e_color, mix);
-
- /* mix wetness and alpha depending on selected alpha mode */
- if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
- /* update values to the brush level unless they're higher already */
- CLAMP_MIN(pPoint->e_color[3], paintAlpha);
- CLAMP_MIN(pPoint->wetness, paintWetness);
- }
- else {
- float wetness = paintWetness;
- CLAMP(wetness, 0.0f, 1.0f);
- pPoint->e_color[3] = mix[3];
- pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
- }
-
- CLAMP_MIN(pPoint->wetness, MIN_WETNESS);
-
- pPoint->state = DPAINT_PAINT_NEW;
- }
- /* Erase paint */
- else {
- float a_ratio, a_highest;
- float wetness;
- float invFact = 1.0f - paintAlpha;
-
- /*
- * Make highest alpha to match erased value
- * but maintain alpha ratio
- */
- if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
- a_highest = max_ff(pPoint->color[3], pPoint->e_color[3]);
- if (a_highest > invFact) {
- a_ratio = invFact / a_highest;
-
- pPoint->e_color[3] *= a_ratio;
- pPoint->color[3] *= a_ratio;
- }
- }
- else {
- pPoint->e_color[3] -= paintAlpha * timescale;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->color[3] -= paintAlpha * timescale;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- }
-
- wetness = (1.0f - paintWetness) * pPoint->e_color[3];
- CLAMP_MAX(pPoint->wetness, wetness);
- }
+ PaintPoint *pPoint = &((PaintPoint *)surface->data->type_data)[index];
+
+ /* Add paint */
+ if (!(paintFlags & MOD_DPAINT_ERASE)) {
+ float mix[4];
+ float temp_alpha = paintAlpha * ((paintFlags & MOD_DPAINT_ABS_ALPHA) ? 1.0f : timescale);
+
+ /* mix brush color with wet layer color */
+ blendColors(pPoint->e_color, pPoint->e_color[3], paintColor, temp_alpha, mix);
+ copy_v3_v3(pPoint->e_color, mix);
+
+ /* mix wetness and alpha depending on selected alpha mode */
+ if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
+ /* update values to the brush level unless they're higher already */
+ CLAMP_MIN(pPoint->e_color[3], paintAlpha);
+ CLAMP_MIN(pPoint->wetness, paintWetness);
+ }
+ else {
+ float wetness = paintWetness;
+ CLAMP(wetness, 0.0f, 1.0f);
+ pPoint->e_color[3] = mix[3];
+ pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
+ }
+
+ CLAMP_MIN(pPoint->wetness, MIN_WETNESS);
+
+ pPoint->state = DPAINT_PAINT_NEW;
+ }
+ /* Erase paint */
+ else {
+ float a_ratio, a_highest;
+ float wetness;
+ float invFact = 1.0f - paintAlpha;
+
+ /*
+ * Make highest alpha to match erased value
+ * but maintain alpha ratio
+ */
+ if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
+ a_highest = max_ff(pPoint->color[3], pPoint->e_color[3]);
+ if (a_highest > invFact) {
+ a_ratio = invFact / a_highest;
+
+ pPoint->e_color[3] *= a_ratio;
+ pPoint->color[3] *= a_ratio;
+ }
+ }
+ else {
+ pPoint->e_color[3] -= paintAlpha * timescale;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->color[3] -= paintAlpha * timescale;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ }
+
+ wetness = (1.0f - paintWetness) * pPoint->e_color[3];
+ CLAMP_MAX(pPoint->wetness, wetness);
+ }
}
/* applies given brush intersection value for wave surface */
-static void dynamicPaint_mixWaveHeight(
- PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
+static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint,
+ const DynamicPaintBrushSettings *brush,
+ float isect_height)
{
- const float isect_change = isect_height - wPoint->brush_isect;
- const float wave_factor = brush->wave_factor;
- bool hit = false;
-
- /* intersection marked regardless of brush type or hit */
- wPoint->brush_isect = isect_height;
- wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
-
- isect_height *= wave_factor;
-
- /* determine hit depending on wave_factor */
- if (wave_factor > 0.0f && wPoint->height > isect_height)
- hit = true;
- else if (wave_factor < 0.0f && wPoint->height < isect_height)
- hit = true;
-
- if (hit) {
- switch (brush->wave_type) {
- case MOD_DPAINT_WAVEB_DEPTH:
- wPoint->height = isect_height;
- wPoint->state = DPAINT_WAVE_OBSTACLE;
- wPoint->velocity = 0.0f;
- break;
- case MOD_DPAINT_WAVEB_FORCE:
- wPoint->velocity = isect_height;
- break;
- case MOD_DPAINT_WAVEB_REFLECT:
- wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
- break;
- case MOD_DPAINT_WAVEB_CHANGE:
- if (isect_change < 0.0f)
- wPoint->height += isect_change * wave_factor;
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
+ const float isect_change = isect_height - wPoint->brush_isect;
+ const float wave_factor = brush->wave_factor;
+ bool hit = false;
+
+ /* intersection marked regardless of brush type or hit */
+ wPoint->brush_isect = isect_height;
+ wPoint->state = DPAINT_WAVE_ISECT_CHANGED;
+
+ isect_height *= wave_factor;
+
+ /* determine hit depending on wave_factor */
+ if (wave_factor > 0.0f && wPoint->height > isect_height)
+ hit = true;
+ else if (wave_factor < 0.0f && wPoint->height < isect_height)
+ hit = true;
+
+ if (hit) {
+ switch (brush->wave_type) {
+ case MOD_DPAINT_WAVEB_DEPTH:
+ wPoint->height = isect_height;
+ wPoint->state = DPAINT_WAVE_OBSTACLE;
+ wPoint->velocity = 0.0f;
+ break;
+ case MOD_DPAINT_WAVEB_FORCE:
+ wPoint->velocity = isect_height;
+ break;
+ case MOD_DPAINT_WAVEB_REFLECT:
+ wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
+ break;
+ case MOD_DPAINT_WAVEB_CHANGE:
+ if (isect_change < 0.0f)
+ wPoint->height += isect_change * wave_factor;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
}
/*
* add brush results to the surface data depending on surface type
*/
-static void dynamicPaint_updatePointData(
- const DynamicPaintSurface *surface, const int index, const DynamicPaintBrushSettings *brush,
- float paint[3], float influence, float depth, float vel_factor, const float timescale)
+static void dynamicPaint_updatePointData(const DynamicPaintSurface *surface,
+ const int index,
+ const DynamicPaintBrushSettings *brush,
+ float paint[3],
+ float influence,
+ float depth,
+ float vel_factor,
+ const float timescale)
{
- PaintSurfaceData *sData = surface->data;
- float strength;
-
- /* apply influence scale */
- influence *= surface->influence_scale;
- depth *= surface->influence_scale;
-
- strength = influence * brush->alpha;
- CLAMP(strength, 0.0f, 1.0f);
-
- /* Sample velocity colorband if required */
- if (brush->flags & (MOD_DPAINT_VELOCITY_ALPHA | MOD_DPAINT_VELOCITY_COLOR | MOD_DPAINT_VELOCITY_DEPTH)) {
- float coba_res[4];
- vel_factor /= brush->max_velocity;
- CLAMP(vel_factor, 0.0f, 1.0f);
-
- if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
- if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
- copy_v3_v3(paint, coba_res);
- }
- if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
- strength *= coba_res[3];
- if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH)
- depth *= coba_res[3];
- }
- }
-
- /* mix paint surface */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- float paintWetness = brush->wetness * strength;
- float paintAlpha = strength;
-
- dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
- }
- /* displace surface */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- float *value = (float *)sData->type_data;
-
- if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
- depth = value[index] + depth;
-
- if (surface->depth_clamp) {
- CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
- }
-
- if (brush->flags & MOD_DPAINT_ERASE) {
- value[index] *= (1.0f - strength);
- CLAMP_MIN(value[index], 0.0f);
- }
- else {
- CLAMP_MIN(value[index], depth);
- }
- }
- /* vertex weight group surface */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
- float *value = (float *)sData->type_data;
-
- if (brush->flags & MOD_DPAINT_ERASE) {
- value[index] *= (1.0f - strength);
- CLAMP_MIN(value[index], 0.0f);
- }
- else {
- CLAMP_MIN(value[index], strength);
- }
- }
- /* wave surface */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- if (brush->wave_clamp) {
- CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
- }
-
- dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
- }
-
- /* doing velocity based painting */
- if (sData->bData->brush_velocity) {
- sData->bData->brush_velocity[index * 4 + 3] *= influence;
- }
+ PaintSurfaceData *sData = surface->data;
+ float strength;
+
+ /* apply influence scale */
+ influence *= surface->influence_scale;
+ depth *= surface->influence_scale;
+
+ strength = influence * brush->alpha;
+ CLAMP(strength, 0.0f, 1.0f);
+
+ /* Sample velocity colorband if required */
+ if (brush->flags &
+ (MOD_DPAINT_VELOCITY_ALPHA | MOD_DPAINT_VELOCITY_COLOR | MOD_DPAINT_VELOCITY_DEPTH)) {
+ float coba_res[4];
+ vel_factor /= brush->max_velocity;
+ CLAMP(vel_factor, 0.0f, 1.0f);
+
+ if (BKE_colorband_evaluate(brush->vel_ramp, vel_factor, coba_res)) {
+ if (brush->flags & MOD_DPAINT_VELOCITY_COLOR) {
+ copy_v3_v3(paint, coba_res);
+ }
+ if (brush->flags & MOD_DPAINT_VELOCITY_ALPHA)
+ strength *= coba_res[3];
+ if (brush->flags & MOD_DPAINT_VELOCITY_DEPTH)
+ depth *= coba_res[3];
+ }
+ }
+
+ /* mix paint surface */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ float paintWetness = brush->wetness * strength;
+ float paintAlpha = strength;
+
+ dynamicPaint_mixPaintColors(
+ surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
+ }
+ /* displace surface */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
+ float *value = (float *)sData->type_data;
+
+ if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
+ depth = value[index] + depth;
+
+ if (surface->depth_clamp) {
+ CLAMP(depth, 0.0f - surface->depth_clamp, surface->depth_clamp);
+ }
+
+ if (brush->flags & MOD_DPAINT_ERASE) {
+ value[index] *= (1.0f - strength);
+ CLAMP_MIN(value[index], 0.0f);
+ }
+ else {
+ CLAMP_MIN(value[index], depth);
+ }
+ }
+ /* vertex weight group surface */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
+ float *value = (float *)sData->type_data;
+
+ if (brush->flags & MOD_DPAINT_ERASE) {
+ value[index] *= (1.0f - strength);
+ CLAMP_MIN(value[index], 0.0f);
+ }
+ else {
+ CLAMP_MIN(value[index], strength);
+ }
+ }
+ /* wave surface */
+ else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ if (brush->wave_clamp) {
+ CLAMP(depth, 0.0f - brush->wave_clamp, brush->wave_clamp);
+ }
+
+ dynamicPaint_mixWaveHeight(&((PaintWavePoint *)sData->type_data)[index], brush, 0.0f - depth);
+ }
+
+ /* doing velocity based painting */
+ if (sData->bData->brush_velocity) {
+ sData->bData->brush_velocity[index * 4 + 3] *= influence;
+ }
}
/* checks whether surface and brush bounds intersect depending on brush type */
-static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBrushSettings *brush, float brush_radius)
+static bool meshBrush_boundsIntersect(Bounds3D *b1,
+ Bounds3D *b2,
+ DynamicPaintBrushSettings *brush,
+ float brush_radius)
{
- if (brush->collision == MOD_DPAINT_COL_VOLUME)
- return boundsIntersect(b1, b2);
- else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
- return boundsIntersectDist(b1, b2, brush_radius);
- return true;
+ if (brush->collision == MOD_DPAINT_COL_VOLUME)
+ return boundsIntersect(b1, b2);
+ else if (brush->collision == MOD_DPAINT_COL_DIST || brush->collision == MOD_DPAINT_COL_VOLDIST)
+ return boundsIntersectDist(b1, b2, brush_radius);
+ return true;
}
/* calculate velocity for mesh vertices */
typedef struct DynamicPaintBrushVelocityData {
- Vec3f *brush_vel;
+ Vec3f *brush_vel;
- const MVert *mvert_p;
- const MVert *mvert_c;
+ const MVert *mvert_p;
+ const MVert *mvert_c;
- float (*obmat)[4];
- float (*prev_obmat)[4];
+ float (*obmat)[4];
+ float (*prev_obmat)[4];
- const float timescale;
+ const float timescale;
} DynamicPaintBrushVelocityData;
-static void dynamic_paint_brush_velocity_compute_cb(
- void *__restrict userdata,
- const int i,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_brush_velocity_compute_cb(void *__restrict userdata,
+ const int i,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintBrushVelocityData *data = userdata;
+ const DynamicPaintBrushVelocityData *data = userdata;
- Vec3f *brush_vel = data->brush_vel;
+ Vec3f *brush_vel = data->brush_vel;
- const MVert *mvert_p = data->mvert_p;
- const MVert *mvert_c = data->mvert_c;
+ const MVert *mvert_p = data->mvert_p;
+ const MVert *mvert_c = data->mvert_c;
- float (*obmat)[4] = data->obmat;
- float (*prev_obmat)[4] = data->prev_obmat;
+ float(*obmat)[4] = data->obmat;
+ float(*prev_obmat)[4] = data->prev_obmat;
- const float timescale = data->timescale;
+ const float timescale = data->timescale;
- float p1[3], p2[3];
+ float p1[3], p2[3];
- copy_v3_v3(p1, mvert_p[i].co);
- mul_m4_v3(prev_obmat, p1);
+ copy_v3_v3(p1, mvert_p[i].co);
+ mul_m4_v3(prev_obmat, p1);
- copy_v3_v3(p2, mvert_c[i].co);
- mul_m4_v3(obmat, p2);
+ copy_v3_v3(p2, mvert_c[i].co);
+ mul_m4_v3(obmat, p2);
- sub_v3_v3v3(brush_vel[i].v, p2, p1);
- mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
+ sub_v3_v3v3(brush_vel[i].v, p2, p1);
+ mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
}
-static void dynamicPaint_brushMeshCalculateVelocity(
- Depsgraph *depsgraph, Scene *scene,
- Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
+static void dynamicPaint_brushMeshCalculateVelocity(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ DynamicPaintBrushSettings *brush,
+ Vec3f **brushVel,
+ float timescale)
{
- float prev_obmat[4][4];
- Mesh *mesh_p, *mesh_c;
- MVert *mvert_p, *mvert_c;
- int numOfVerts_p, numOfVerts_c;
-
- float cur_sfra = scene->r.subframe;
- int cur_fra = scene->r.cfra;
- float prev_sfra = cur_sfra - timescale;
- int prev_fra = cur_fra;
-
- if (prev_sfra < 0.0f) {
- prev_sfra += 1.0f;
- prev_fra = cur_fra - 1;
- }
-
- /* previous frame mesh */
- scene->r.cfra = prev_fra;
- scene->r.subframe = prev_sfra;
-
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false);
- numOfVerts_p = mesh_p->totvert;
- mvert_p = mesh_p->mvert;
- copy_m4_m4(prev_obmat, ob->obmat);
-
- /* current frame mesh */
- scene->r.cfra = cur_fra;
- scene->r.subframe = cur_sfra;
-
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- mesh_c = dynamicPaint_brush_mesh_get(brush);
- numOfVerts_c = mesh_c->totvert;
- mvert_c = mesh_c->mvert;
-
- (*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
- if (!(*brushVel))
- return;
-
- /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
- if (numOfVerts_p != numOfVerts_c)
- mvert_p = mvert_c;
-
- /* calculate speed */
- DynamicPaintBrushVelocityData data = {
- .brush_vel = *brushVel,
- .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
- .timescale = timescale,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (numOfVerts_c > 10000);
- BLI_task_parallel_range(0, numOfVerts_c,
- &data,
- dynamic_paint_brush_velocity_compute_cb,
- &settings);
-
- BKE_id_free(NULL, mesh_p);
+ float prev_obmat[4][4];
+ Mesh *mesh_p, *mesh_c;
+ MVert *mvert_p, *mvert_c;
+ int numOfVerts_p, numOfVerts_c;
+
+ float cur_sfra = scene->r.subframe;
+ int cur_fra = scene->r.cfra;
+ float prev_sfra = cur_sfra - timescale;
+ int prev_fra = cur_fra;
+
+ if (prev_sfra < 0.0f) {
+ prev_sfra += 1.0f;
+ prev_fra = cur_fra - 1;
+ }
+
+ /* previous frame mesh */
+ scene->r.cfra = prev_fra;
+ scene->r.subframe = prev_sfra;
+
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ mesh_p = BKE_mesh_copy_for_eval(dynamicPaint_brush_mesh_get(brush), false);
+ numOfVerts_p = mesh_p->totvert;
+ mvert_p = mesh_p->mvert;
+ copy_m4_m4(prev_obmat, ob->obmat);
+
+ /* current frame mesh */
+ scene->r.cfra = cur_fra;
+ scene->r.subframe = cur_sfra;
+
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ mesh_c = dynamicPaint_brush_mesh_get(brush);
+ numOfVerts_c = mesh_c->totvert;
+ mvert_c = mesh_c->mvert;
+
+ (*brushVel) = (struct Vec3f *)MEM_mallocN(numOfVerts_c * sizeof(Vec3f),
+ "Dynamic Paint brush velocity");
+ if (!(*brushVel))
+ return;
+
+ /* if mesh is constructive -> num of verts has changed, only use current frame derived mesh */
+ if (numOfVerts_p != numOfVerts_c)
+ mvert_p = mvert_c;
+
+ /* calculate speed */
+ DynamicPaintBrushVelocityData data = {
+ .brush_vel = *brushVel,
+ .mvert_p = mvert_p,
+ .mvert_c = mvert_c,
+ .obmat = ob->obmat,
+ .prev_obmat = prev_obmat,
+ .timescale = timescale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (numOfVerts_c > 10000);
+ BLI_task_parallel_range(
+ 0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, &settings);
+
+ BKE_id_free(NULL, mesh_p);
}
/* calculate velocity for object center point */
static void dynamicPaint_brushObjectCalculateVelocity(
- Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
{
- float prev_obmat[4][4];
- float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
-
- float cur_sfra = scene->r.subframe;
- int cur_fra = scene->r.cfra;
- float prev_sfra = cur_sfra - timescale;
- int prev_fra = cur_fra;
-
- if (prev_sfra < 0.0f) {
- prev_sfra += 1.0f;
- prev_fra = cur_fra - 1;
- }
-
- /* previous frame mesh */
- scene->r.cfra = prev_fra;
- scene->r.subframe = prev_sfra;
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- copy_m4_m4(prev_obmat, ob->obmat);
-
- /* current frame mesh */
- scene->r.cfra = cur_fra;
- scene->r.subframe = cur_sfra;
- BKE_object_modifier_update_subframe(
- depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
-
- /* calculate speed */
- mul_m4_v3(prev_obmat, prev_loc);
- mul_m4_v3(ob->obmat, cur_loc);
-
- sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
- mul_v3_fl(brushVel->v, 1.0f / timescale);
+ float prev_obmat[4][4];
+ float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
+
+ float cur_sfra = scene->r.subframe;
+ int cur_fra = scene->r.cfra;
+ float prev_sfra = cur_sfra - timescale;
+ int prev_fra = cur_fra;
+
+ if (prev_sfra < 0.0f) {
+ prev_sfra += 1.0f;
+ prev_fra = cur_fra - 1;
+ }
+
+ /* previous frame mesh */
+ scene->r.cfra = prev_fra;
+ scene->r.subframe = prev_sfra;
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ false,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ copy_m4_m4(prev_obmat, ob->obmat);
+
+ /* current frame mesh */
+ scene->r.cfra = cur_fra;
+ scene->r.subframe = cur_sfra;
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ ob,
+ false,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+
+ /* calculate speed */
+ mul_m4_v3(prev_obmat, prev_loc);
+ mul_m4_v3(ob->obmat, cur_loc);
+
+ sub_v3_v3v3(brushVel->v, cur_loc, prev_loc);
+ mul_v3_fl(brushVel->v, 1.0f / timescale);
}
typedef struct DynamicPaintPaintData {
- const DynamicPaintSurface *surface;
- const DynamicPaintBrushSettings *brush;
- Object *brushOb;
- const Scene *scene;
- const float timescale;
- const int c_index;
-
- Mesh *mesh;
- const MVert *mvert;
- const MLoop *mloop;
- const MLoopTri *mlooptri;
- const float brush_radius;
- const float *avg_brushNor;
- const Vec3f *brushVelocity;
-
- const ParticleSystem *psys;
- const float solidradius;
-
- void *treeData;
-
- float *pointCoord;
+ const DynamicPaintSurface *surface;
+ const DynamicPaintBrushSettings *brush;
+ Object *brushOb;
+ const Scene *scene;
+ const float timescale;
+ const int c_index;
+
+ Mesh *mesh;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const float brush_radius;
+ const float *avg_brushNor;
+ const Vec3f *brushVelocity;
+
+ const ParticleSystem *psys;
+ const float solidradius;
+
+ void *treeData;
+
+ float *pointCoord;
} DynamicPaintPaintData;
/*
* Paint a brush object mesh to the surface
*/
static void dynamic_paint_paint_mesh_cell_point_cb_ex(
- void *__restrict userdata,
- const int id,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int id, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintPaintData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
-
- const DynamicPaintBrushSettings *brush = data->brush;
-
- const float timescale = data->timescale;
- const int c_index = data->c_index;
-
- const MVert *mvert = data->mvert;
- const MLoop *mloop = data->mloop;
- const MLoopTri *mlooptri = data->mlooptri;
- const float brush_radius = data->brush_radius;
- const float *avg_brushNor = data->avg_brushNor;
- const Vec3f *brushVelocity = data->brushVelocity;
-
- BVHTreeFromMesh *treeData = data->treeData;
-
- const int index = grid->t_index[grid->s_pos[c_index] + id];
- const int samples = bData->s_num[index];
- int ss;
- float total_sample = (float)samples;
- float brushStrength = 0.0f; /* brush influence factor */
- float depth = 0.0f; /* brush intersection depth */
- float velocity_val = 0.0f;
-
- float paintColor[3] = {0.0f};
- int numOfHits = 0;
-
- /* for image sequence anti-aliasing, use gaussian factors */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- total_sample = gaussianTotal;
-
- /* Supersampling */
- for (ss = 0; ss < samples; ss++) {
- float ray_start[3], ray_dir[3];
- float sample_factor = 0.0f;
- float sampleStrength = 0.0f;
- BVHTreeRayHit hit;
- BVHTreeNearest nearest;
- short hit_found = 0;
-
- /* volume sample */
- float volume_factor = 0.0f;
- /* proximity sample */
- float proximity_factor = 0.0f;
- float prox_colorband[4] = {0.0f};
- const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
- brush->collision == MOD_DPAINT_COL_VOLDIST);
-
- /* hit data */
- float hitCoord[3];
- int hitTri = -1;
-
- /* Supersampling factor */
- if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
- sample_factor = gaussianFactors[ss];
- else
- sample_factor = 1.0f;
-
- /* Get current sample position in world coordinates */
- copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
- copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
-
- /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
- add_v3_fl(ray_start, 0.001f);
-
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
- nearest.index = -1;
- nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
-
- /* Check volume collision */
- if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
- BLI_bvhtree_ray_cast(treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
- if (hit.index != -1) {
- /* We hit a triangle, now check if collision point normal is facing the point */
-
- /* For optimization sake, hit point normal isn't calculated in ray cast loop */
- const int vtri[3] = {
- mloop[mlooptri[hit.index].tri[0]].v,
- mloop[mlooptri[hit.index].tri[1]].v,
- mloop[mlooptri[hit.index].tri[2]].v,
- };
- float dot;
-
- normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- dot = dot_v3v3(ray_dir, hit.no);
-
- /* If ray and hit face normal are facing same direction
- * hit point is inside a closed mesh. */
- if (dot >= 0.0f) {
- const float dist = hit.dist;
- const int f_index = hit.index;
-
- /* Also cast a ray in opposite direction to make sure
- * point is at least surrounded by two brush faces */
- negate_v3(ray_dir);
- hit.index = -1;
- hit.dist = BVH_RAYCAST_DIST_MAX;
-
- BLI_bvhtree_ray_cast(
- treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
-
- if (hit.index != -1) {
- /* Add factor on supersample filter */
- volume_factor = 1.0f;
- hit_found = HIT_VOLUME;
-
- /* Mark hit info */
- madd_v3_v3v3fl(hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
- depth += dist * sample_factor;
- hitTri = f_index;
- }
- }
- }
- }
-
- /* Check proximity collision */
- if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
- (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
- {
- float proxDist = -1.0f;
- float hitCo[3] = {0.0f, 0.0f, 0.0f};
- int tri = 0;
-
- /* if inverse prox and no hit found, skip this sample */
- if (inner_proximity && !hit_found)
- continue;
-
- /* If pure distance proximity, find the nearest point on the mesh */
- if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
- BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
- if (nearest.index != -1) {
- proxDist = sqrtf(nearest.dist_sq);
- copy_v3_v3(hitCo, nearest.co);
- tri = nearest.index;
- }
- }
- else { /* else cast a ray in defined projection direction */
- float proj_ray[3] = {0.0f};
-
- if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
- copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
- negate_v3(proj_ray);
- }
- else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
- copy_v3_v3(proj_ray, avg_brushNor);
- }
- else { /* MOD_DPAINT_RAY_ZPLUS */
- proj_ray[2] = 1.0f;
- }
- hit.index = -1;
- hit.dist = brush_radius;
-
- /* Do a face normal directional raycast, and use that distance */
- BLI_bvhtree_ray_cast(
- treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
- if (hit.index != -1) {
- proxDist = hit.dist;
- madd_v3_v3v3fl(hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
- tri = hit.index;
- }
- }
-
- /* If a hit was found, calculate required values */
- if (proxDist >= 0.0f && proxDist <= brush_radius) {
- proximity_factor = proxDist / brush_radius;
- CLAMP(proximity_factor, 0.0f, 1.0f);
- if (!inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
-
- hit_found = HIT_PROXIMITY;
-
- /* if no volume hit, use prox point face info */
- if (hitTri == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitTri = tri;
- }
- }
- }
-
- /* mix final sample strength depending on brush settings */
- if (hit_found) {
- /* if "negate volume" enabled, negate all factors within volume*/
- if (brush->collision == MOD_DPAINT_COL_VOLDIST &&
- brush->flags & MOD_DPAINT_NEGATE_VOLUME)
- {
- volume_factor = 1.0f - volume_factor;
- if (inner_proximity)
- proximity_factor = 1.0f - proximity_factor;
- }
-
- /* apply final sample depending on final hit type */
- if (hit_found == HIT_VOLUME) {
- sampleStrength = volume_factor;
- }
- else if (hit_found == HIT_PROXIMITY) {
- /* apply falloff curve to the proximity_factor */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband))
- {
- proximity_factor = prox_colorband[3];
- }
- else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
- proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f : 0.0f;
- }
- /* apply sample */
- sampleStrength = proximity_factor;
- }
-
- sampleStrength *= sample_factor;
- }
- else {
- continue;
- }
-
- /* velocity brush, only do on main sample */
- if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- float weights[3];
- float brushPointVelocity[3];
- float velocity[3];
-
- const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
- const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
- const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
-
- /* calculate barycentric weights for hit point */
- interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
-
- /* simple check based on brush surface velocity,
- * todo: perhaps implement something that handles volume movement as well. */
-
- /* interpolate vertex speed vectors to get hit point velocity */
- interp_v3_v3v3v3(brushPointVelocity,
- brushVelocity[v1].v,
- brushVelocity[v2].v,
- brushVelocity[v3].v, weights);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushPointVelocity);
- }
- velocity_val = normalize_v3(velocity);
-
- /* if brush has smudge enabled store brush velocity */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
- brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- /*
- * Process hit color and alpha
- */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- float sampleColor[3];
- float alpha_factor = 1.0f;
-
- sampleColor[0] = brush->r;
- sampleColor[1] = brush->g;
- sampleColor[2] = brush->b;
-
- /* Sample proximity colorband if required */
- if ((hit_found == HIT_PROXIMITY) &&
- (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
- {
- if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
- sampleColor[0] = prox_colorband[0];
- sampleColor[1] = prox_colorband[1];
- sampleColor[2] = prox_colorband[2];
- }
- }
-
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
- sampleStrength *= alpha_factor;
- numOfHits++;
- }
-
- /* apply sample strength */
- brushStrength += sampleStrength;
- } // end supersampling
-
-
- /* if any sample was inside paint range */
- if (brushStrength > 0.0f || depth > 0.0f) {
- /* apply supersampling results */
- if (samples > 1) {
- brushStrength /= total_sample;
- }
- CLAMP(brushStrength, 0.0f, 1.0f);
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- /* Get final pixel color and alpha */
- paintColor[0] /= numOfHits;
- paintColor[1] /= numOfHits;
- paintColor[2] /= numOfHits;
- }
- /* get final object space depth */
- else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- depth /= bData->bNormal[index].normal_scale * total_sample;
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
- }
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ const MVert *mvert = data->mvert;
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const float brush_radius = data->brush_radius;
+ const float *avg_brushNor = data->avg_brushNor;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ BVHTreeFromMesh *treeData = data->treeData;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ const int samples = bData->s_num[index];
+ int ss;
+ float total_sample = (float)samples;
+ float brushStrength = 0.0f; /* brush influence factor */
+ float depth = 0.0f; /* brush intersection depth */
+ float velocity_val = 0.0f;
+
+ float paintColor[3] = {0.0f};
+ int numOfHits = 0;
+
+ /* for image sequence anti-aliasing, use gaussian factors */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ total_sample = gaussianTotal;
+
+ /* Supersampling */
+ for (ss = 0; ss < samples; ss++) {
+ float ray_start[3], ray_dir[3];
+ float sample_factor = 0.0f;
+ float sampleStrength = 0.0f;
+ BVHTreeRayHit hit;
+ BVHTreeNearest nearest;
+ short hit_found = 0;
+
+ /* volume sample */
+ float volume_factor = 0.0f;
+ /* proximity sample */
+ float proximity_factor = 0.0f;
+ float prox_colorband[4] = {0.0f};
+ const bool inner_proximity = (brush->flags & MOD_DPAINT_INVERSE_PROX &&
+ brush->collision == MOD_DPAINT_COL_VOLDIST);
+
+ /* hit data */
+ float hitCoord[3];
+ int hitTri = -1;
+
+ /* Supersampling factor */
+ if (samples > 1 && surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+ sample_factor = gaussianFactors[ss];
+ else
+ sample_factor = 1.0f;
+
+ /* Get current sample position in world coordinates */
+ copy_v3_v3(ray_start, bData->realCoord[bData->s_pos[index] + ss].v);
+ copy_v3_v3(ray_dir, bData->bNormal[index].invNorm);
+
+ /* a simple hack to minimize chance of ray leaks at identical ray <-> edge locations */
+ add_v3_fl(ray_start, 0.001f);
+
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ nearest.index = -1;
+ nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
+
+ /* Check volume collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_VOLUME, MOD_DPAINT_COL_VOLDIST)) {
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ /* We hit a triangle, now check if collision point normal is facing the point */
+
+ /* For optimization sake, hit point normal isn't calculated in ray cast loop */
+ const int vtri[3] = {
+ mloop[mlooptri[hit.index].tri[0]].v,
+ mloop[mlooptri[hit.index].tri[1]].v,
+ mloop[mlooptri[hit.index].tri[2]].v,
+ };
+ float dot;
+
+ normal_tri_v3(hit.no, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
+ dot = dot_v3v3(ray_dir, hit.no);
+
+ /* If ray and hit face normal are facing same direction
+ * hit point is inside a closed mesh. */
+ if (dot >= 0.0f) {
+ const float dist = hit.dist;
+ const int f_index = hit.index;
+
+ /* Also cast a ray in opposite direction to make sure
+ * point is at least surrounded by two brush faces */
+ negate_v3(ray_dir);
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+
+ if (hit.index != -1) {
+ /* Add factor on supersample filter */
+ volume_factor = 1.0f;
+ hit_found = HIT_VOLUME;
+
+ /* Mark hit info */
+ madd_v3_v3v3fl(
+ hitCoord, ray_start, ray_dir, hit.dist); /* Calculate final hit coordinates */
+ depth += dist * sample_factor;
+ hitTri = f_index;
+ }
+ }
+ }
+ }
+
+ /* Check proximity collision */
+ if (ELEM(brush->collision, MOD_DPAINT_COL_DIST, MOD_DPAINT_COL_VOLDIST) &&
+ (!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX))) {
+ float proxDist = -1.0f;
+ float hitCo[3] = {0.0f, 0.0f, 0.0f};
+ int tri = 0;
+
+ /* if inverse prox and no hit found, skip this sample */
+ if (inner_proximity && !hit_found)
+ continue;
+
+ /* If pure distance proximity, find the nearest point on the mesh */
+ if (!(brush->flags & MOD_DPAINT_PROX_PROJECT)) {
+ BLI_bvhtree_find_nearest(
+ treeData->tree, ray_start, &nearest, mesh_tris_nearest_point_dp, treeData);
+ if (nearest.index != -1) {
+ proxDist = sqrtf(nearest.dist_sq);
+ copy_v3_v3(hitCo, nearest.co);
+ tri = nearest.index;
+ }
+ }
+ else { /* else cast a ray in defined projection direction */
+ float proj_ray[3] = {0.0f};
+
+ if (brush->ray_dir == MOD_DPAINT_RAY_CANVAS) {
+ copy_v3_v3(proj_ray, bData->bNormal[index].invNorm);
+ negate_v3(proj_ray);
+ }
+ else if (brush->ray_dir == MOD_DPAINT_RAY_BRUSH_AVG) {
+ copy_v3_v3(proj_ray, avg_brushNor);
+ }
+ else { /* MOD_DPAINT_RAY_ZPLUS */
+ proj_ray[2] = 1.0f;
+ }
+ hit.index = -1;
+ hit.dist = brush_radius;
+
+ /* Do a face normal directional raycast, and use that distance */
+ BLI_bvhtree_ray_cast(
+ treeData->tree, ray_start, proj_ray, 0.0f, &hit, mesh_tris_spherecast_dp, treeData);
+ if (hit.index != -1) {
+ proxDist = hit.dist;
+ madd_v3_v3v3fl(
+ hitCo, ray_start, proj_ray, hit.dist); /* Calculate final hit coordinates */
+ tri = hit.index;
+ }
+ }
+
+ /* If a hit was found, calculate required values */
+ if (proxDist >= 0.0f && proxDist <= brush_radius) {
+ proximity_factor = proxDist / brush_radius;
+ CLAMP(proximity_factor, 0.0f, 1.0f);
+ if (!inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+
+ hit_found = HIT_PROXIMITY;
+
+ /* if no volume hit, use prox point face info */
+ if (hitTri == -1) {
+ copy_v3_v3(hitCoord, hitCo);
+ hitTri = tri;
+ }
+ }
+ }
+
+ /* mix final sample strength depending on brush settings */
+ if (hit_found) {
+ /* if "negate volume" enabled, negate all factors within volume*/
+ if (brush->collision == MOD_DPAINT_COL_VOLDIST && brush->flags & MOD_DPAINT_NEGATE_VOLUME) {
+ volume_factor = 1.0f - volume_factor;
+ if (inner_proximity)
+ proximity_factor = 1.0f - proximity_factor;
+ }
+
+ /* apply final sample depending on final hit type */
+ if (hit_found == HIT_VOLUME) {
+ sampleStrength = volume_factor;
+ }
+ else if (hit_found == HIT_PROXIMITY) {
+ /* apply falloff curve to the proximity_factor */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ BKE_colorband_evaluate(brush->paint_ramp, (1.0f - proximity_factor), prox_colorband)) {
+ proximity_factor = prox_colorband[3];
+ }
+ else if (brush->proximity_falloff == MOD_DPAINT_PRFALL_CONSTANT) {
+ proximity_factor = (!inner_proximity || brush->flags & MOD_DPAINT_NEGATE_VOLUME) ? 1.0f :
+ 0.0f;
+ }
+ /* apply sample */
+ sampleStrength = proximity_factor;
+ }
+
+ sampleStrength *= sample_factor;
+ }
+ else {
+ continue;
+ }
+
+ /* velocity brush, only do on main sample */
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
+ float weights[3];
+ float brushPointVelocity[3];
+ float velocity[3];
+
+ const int v1 = mloop[mlooptri[hitTri].tri[0]].v;
+ const int v2 = mloop[mlooptri[hitTri].tri[1]].v;
+ const int v3 = mloop[mlooptri[hitTri].tri[2]].v;
+
+ /* calculate barycentric weights for hit point */
+ interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord);
+
+ /* simple check based on brush surface velocity,
+ * todo: perhaps implement something that handles volume movement as well. */
+
+ /* interpolate vertex speed vectors to get hit point velocity */
+ interp_v3_v3v3v3(brushPointVelocity,
+ brushVelocity[v1].v,
+ brushVelocity[v2].v,
+ brushVelocity[v3].v,
+ weights);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushPointVelocity, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushPointVelocity);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* if brush has smudge enabled store brush velocity */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
+ bData->brush_velocity) {
+ copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ /*
+ * Process hit color and alpha
+ */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ float sampleColor[3];
+ float alpha_factor = 1.0f;
+
+ sampleColor[0] = brush->r;
+ sampleColor[1] = brush->g;
+ sampleColor[2] = brush->b;
+
+ /* Sample proximity colorband if required */
+ if ((hit_found == HIT_PROXIMITY) && (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)) {
+ if (!(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
+ sampleColor[0] = prox_colorband[0];
+ sampleColor[1] = prox_colorband[1];
+ sampleColor[2] = prox_colorband[2];
+ }
+ }
+
+ /* Add AA sample */
+ paintColor[0] += sampleColor[0];
+ paintColor[1] += sampleColor[1];
+ paintColor[2] += sampleColor[2];
+ sampleStrength *= alpha_factor;
+ numOfHits++;
+ }
+
+ /* apply sample strength */
+ brushStrength += sampleStrength;
+ } // end supersampling
+
+ /* if any sample was inside paint range */
+ if (brushStrength > 0.0f || depth > 0.0f) {
+ /* apply supersampling results */
+ if (samples > 1) {
+ brushStrength /= total_sample;
+ }
+ CLAMP(brushStrength, 0.0f, 1.0f);
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ /* Get final pixel color and alpha */
+ paintColor[0] /= numOfHits;
+ paintColor[1] /= numOfHits;
+ paintColor[2] /= numOfHits;
+ }
+ /* get final object space depth */
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ depth /= bData->bNormal[index].normal_scale * total_sample;
+ }
+
+ dynamicPaint_updatePointData(
+ surface, index, brush, paintColor, brushStrength, depth, velocity_val, timescale);
+ }
}
-static int dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface,
+static int dynamicPaint_paintMesh(Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
Scene *scene,
float timescale)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Mesh *mesh = NULL;
- Vec3f *brushVelocity = NULL;
- MVert *mvert = NULL;
- const MLoopTri *mlooptri = NULL;
- const MLoop *mloop = NULL;
-
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushMeshCalculateVelocity(depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
-
- Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
- if (brush_mesh == NULL) {
- return 0;
- }
-
- {
- BVHTreeFromMesh treeData = {NULL};
- float avg_brushNor[3] = {0.0f};
- const float brush_radius = brush->paint_distance * surface->radius_scale;
- int numOfVerts;
- int ii;
- Bounds3D mesh_bb = {{0}};
- VolumeGrid *grid = bData->grid;
-
- mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
- mvert = mesh->mvert;
- mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
- mloop = mesh->mloop;
- numOfVerts = mesh->totvert;
-
- /* Transform collider vertices to global space
- * (Faster than transforming per surface point
- * coordinates and normals to object space) */
- for (ii = 0; ii < numOfVerts; ii++) {
- mul_m4_v3(brushOb->obmat, mvert[ii].co);
- boundInsert(&mesh_bb, mvert[ii].co);
-
- /* for proximity project calculate average normal */
- if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
- float nor[3];
- normal_short_to_float_v3(nor, mvert[ii].no);
- mul_mat3_m4_v3(brushOb->obmat, nor);
- normalize_v3(nor);
-
- add_v3_v3(avg_brushNor, nor);
- }
- }
-
- if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
- mul_v3_fl(avg_brushNor, 1.0f / (float)numOfVerts);
- /* instead of null vector use positive z */
- if (UNLIKELY(normalize_v3(avg_brushNor) == 0.0f)) {
- avg_brushNor[2] = 1.0f;
- }
- }
-
- /* check bounding box collision */
- if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
- /* Build a bvh tree from transformed vertices */
- if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
- int c_index;
- int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
- /* loop through space partitioning grid */
- for (c_index = 0; c_index < total_cells; c_index++) {
- /* check grid cell bounding box */
- if (!grid->s_num[c_index] ||
- !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
- {
- continue;
- }
-
- /* loop through cell points and process brush */
- DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .brushOb = brushOb,
- .scene = scene, .timescale = timescale, .c_index = c_index,
- .mesh = mesh, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
- .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
- .treeData = &treeData,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (grid->s_num[c_index] > 250);
- BLI_task_parallel_range(0, grid->s_num[c_index],
- &data,
- dynamic_paint_paint_mesh_cell_point_cb_ex,
- &settings);
- }
- }
- }
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- BKE_id_free(NULL, mesh);
-
- }
-
- /* free brush velocity data */
- if (brushVelocity)
- MEM_freeN(brushVelocity);
-
- return 1;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ Mesh *mesh = NULL;
+ Vec3f *brushVelocity = NULL;
+ MVert *mvert = NULL;
+ const MLoopTri *mlooptri = NULL;
+ const MLoop *mloop = NULL;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushMeshCalculateVelocity(
+ depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
+
+ Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
+ if (brush_mesh == NULL) {
+ return 0;
+ }
+
+ {
+ BVHTreeFromMesh treeData = {NULL};
+ float avg_brushNor[3] = {0.0f};
+ const float brush_radius = brush->paint_distance * surface->radius_scale;
+ int numOfVerts;
+ int ii;
+ Bounds3D mesh_bb = {{0}};
+ VolumeGrid *grid = bData->grid;
+
+ mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
+ mvert = mesh->mvert;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mloop = mesh->mloop;
+ numOfVerts = mesh->totvert;
+
+ /* Transform collider vertices to global space
+ * (Faster than transforming per surface point
+ * coordinates and normals to object space) */
+ for (ii = 0; ii < numOfVerts; ii++) {
+ mul_m4_v3(brushOb->obmat, mvert[ii].co);
+ boundInsert(&mesh_bb, mvert[ii].co);
+
+ /* for proximity project calculate average normal */
+ if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
+ float nor[3];
+ normal_short_to_float_v3(nor, mvert[ii].no);
+ mul_mat3_m4_v3(brushOb->obmat, nor);
+ normalize_v3(nor);
+
+ add_v3_v3(avg_brushNor, nor);
+ }
+ }
+
+ if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
+ mul_v3_fl(avg_brushNor, 1.0f / (float)numOfVerts);
+ /* instead of null vector use positive z */
+ if (UNLIKELY(normalize_v3(avg_brushNor) == 0.0f)) {
+ avg_brushNor[2] = 1.0f;
+ }
+ }
+
+ /* check bounding box collision */
+ if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
+ /* Build a bvh tree from transformed vertices */
+ if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
+ int c_index;
+ int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ /* loop through space partitioning grid */
+ for (c_index = 0; c_index < total_cells; c_index++) {
+ /* check grid cell bounding box */
+ if (!grid->s_num[c_index] ||
+ !meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius)) {
+ continue;
+ }
+
+ /* loop through cell points and process brush */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush,
+ .brushOb = brushOb,
+ .scene = scene,
+ .timescale = timescale,
+ .c_index = c_index,
+ .mesh = mesh,
+ .mvert = mvert,
+ .mloop = mloop,
+ .mlooptri = mlooptri,
+ .brush_radius = brush_radius,
+ .avg_brushNor = avg_brushNor,
+ .brushVelocity = brushVelocity,
+ .treeData = &treeData,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid->s_num[c_index] > 250);
+ BLI_task_parallel_range(0,
+ grid->s_num[c_index],
+ &data,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ &settings);
+ }
+ }
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ BKE_id_free(NULL, mesh);
+ }
+
+ /* free brush velocity data */
+ if (brushVelocity)
+ MEM_freeN(brushVelocity);
+
+ return 1;
}
/*
* Paint a particle system to the surface
*/
static void dynamic_paint_paint_particle_cell_point_cb_ex(
- void *__restrict userdata,
- const int id,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+ void *__restrict userdata, const int id, const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintPaintData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
-
- const DynamicPaintBrushSettings *brush = data->brush;
-
- const ParticleSystem *psys = data->psys;
-
- const float timescale = data->timescale;
- const int c_index = data->c_index;
-
- KDTree_3d *tree = data->treeData;
-
- const float solidradius = data->solidradius;
- const float smooth = brush->particle_smooth * surface->radius_scale;
- const float range = solidradius + smooth;
- const float particle_timestep = 0.04f * psys->part->timetweak;
-
- const int index = grid->t_index[grid->s_pos[c_index] + id];
- float disp_intersect = 0.0f;
- float radius = 0.0f;
- float strength = 0.0f;
- int part_index = -1;
-
- /*
- * With predefined radius, there is no variation between particles.
- * It's enough to just find the nearest one.
- */
- {
- KDTreeNearest_3d nearest;
- float smooth_range, part_solidradius;
-
- /* Find nearest particle and get distance to it */
- BLI_kdtree_3d_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
- /* if outside maximum range, no other particle can influence either */
- if (nearest.dist > range)
- return;
-
- if (brush->flags & MOD_DPAINT_PART_RAD) {
- /* use particles individual size */
- ParticleData *pa = psys->particles + nearest.index;
- part_solidradius = pa->size;
- }
- else {
- part_solidradius = solidradius;
- }
- radius = part_solidradius + smooth;
- if (nearest.dist < radius) {
- /* distances inside solid radius has maximum influence -> dist = 0 */
- smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
- /* do smoothness if enabled */
- if (smooth)
- smooth_range /= smooth;
-
- strength = 1.0f - smooth_range;
- disp_intersect = radius - nearest.dist;
- part_index = nearest.index;
- }
- }
- /* If using random per particle radius and closest particle didn't give max influence */
- if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
- /*
- * If we use per particle radius, we have to sample all particles
- * within max radius range
- */
- KDTreeNearest_3d *nearest;
-
- float smooth_range = smooth * (1.0f - strength), dist;
- /* calculate max range that can have particles with higher influence than the nearest one */
- const float max_range = smooth - strength * smooth + solidradius;
- /* Make gcc happy! */
- dist = max_range;
-
- const int particles = BLI_kdtree_3d_range_search(
- tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
-
- /* Find particle that produces highest influence */
- for (int n = 0; n < particles; n++) {
- ParticleData *pa = &psys->particles[nearest[n].index];
-
- /* skip if out of range */
- if (nearest[n].dist > (pa->size + smooth))
- continue;
-
- /* update hit data */
- const float s_range = nearest[n].dist - pa->size;
- /* skip if higher influence is already found */
- if (smooth_range < s_range)
- continue;
-
- /* update hit data */
- smooth_range = s_range;
- dist = nearest[n].dist;
- part_index = nearest[n].index;
-
- /* If inside solid range and no disp depth required, no need to seek further */
- if ((s_range < 0.0f) && !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- break;
- }
- }
-
- if (nearest)
- MEM_freeN(nearest);
-
- /* now calculate influence for this particle */
- const float rad = radius + smooth;
- if ((rad - dist) > disp_intersect) {
- disp_intersect = radius - dist;
- radius = rad;
- }
-
- /* do smoothness if enabled */
- CLAMP_MIN(smooth_range, 0.0f);
- if (smooth)
- smooth_range /= smooth;
-
- const float str = 1.0f - smooth_range;
- /* if influence is greater, use this one */
- if (str > strength)
- strength = str;
- }
-
- if (strength > 0.001f) {
- float paintColor[4] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
-
- /* apply velocity */
- if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
- float velocity[3];
- ParticleData *pa = psys->particles + part_index;
- mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3(velocity, bData->velocity[index].v);
- }
- velocity_val = normalize_v3(velocity);
-
- /* store brush velocity for smudge */
- if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
- (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity))
- {
- copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- copy_v3_v3(paintColor, &brush->r);
- }
- else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* get displace depth */
- disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
- depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
- }
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+
+ const ParticleSystem *psys = data->psys;
+
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ KDTree_3d *tree = data->treeData;
+
+ const float solidradius = data->solidradius;
+ const float smooth = brush->particle_smooth * surface->radius_scale;
+ const float range = solidradius + smooth;
+ const float particle_timestep = 0.04f * psys->part->timetweak;
+
+ const int index = grid->t_index[grid->s_pos[c_index] + id];
+ float disp_intersect = 0.0f;
+ float radius = 0.0f;
+ float strength = 0.0f;
+ int part_index = -1;
+
+ /*
+ * With predefined radius, there is no variation between particles.
+ * It's enough to just find the nearest one.
+ */
+ {
+ KDTreeNearest_3d nearest;
+ float smooth_range, part_solidradius;
+
+ /* Find nearest particle and get distance to it */
+ BLI_kdtree_3d_find_nearest(tree, bData->realCoord[bData->s_pos[index]].v, &nearest);
+ /* if outside maximum range, no other particle can influence either */
+ if (nearest.dist > range)
+ return;
+
+ if (brush->flags & MOD_DPAINT_PART_RAD) {
+ /* use particles individual size */
+ ParticleData *pa = psys->particles + nearest.index;
+ part_solidradius = pa->size;
+ }
+ else {
+ part_solidradius = solidradius;
+ }
+ radius = part_solidradius + smooth;
+ if (nearest.dist < radius) {
+ /* distances inside solid radius has maximum influence -> dist = 0 */
+ smooth_range = max_ff(0.0f, (nearest.dist - part_solidradius));
+ /* do smoothness if enabled */
+ if (smooth)
+ smooth_range /= smooth;
+
+ strength = 1.0f - smooth_range;
+ disp_intersect = radius - nearest.dist;
+ part_index = nearest.index;
+ }
+ }
+ /* If using random per particle radius and closest particle didn't give max influence */
+ if (brush->flags & MOD_DPAINT_PART_RAD && strength < 1.0f && psys->part->randsize > 0.0f) {
+ /*
+ * If we use per particle radius, we have to sample all particles
+ * within max radius range
+ */
+ KDTreeNearest_3d *nearest;
+
+ float smooth_range = smooth * (1.0f - strength), dist;
+ /* calculate max range that can have particles with higher influence than the nearest one */
+ const float max_range = smooth - strength * smooth + solidradius;
+ /* Make gcc happy! */
+ dist = max_range;
+
+ const int particles = BLI_kdtree_3d_range_search(
+ tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
+
+ /* Find particle that produces highest influence */
+ for (int n = 0; n < particles; n++) {
+ ParticleData *pa = &psys->particles[nearest[n].index];
+
+ /* skip if out of range */
+ if (nearest[n].dist > (pa->size + smooth))
+ continue;
+
+ /* update hit data */
+ const float s_range = nearest[n].dist - pa->size;
+ /* skip if higher influence is already found */
+ if (smooth_range < s_range)
+ continue;
+
+ /* update hit data */
+ smooth_range = s_range;
+ dist = nearest[n].dist;
+ part_index = nearest[n].index;
+
+ /* If inside solid range and no disp depth required, no need to seek further */
+ if ((s_range < 0.0f) &&
+ !ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ break;
+ }
+ }
+
+ if (nearest)
+ MEM_freeN(nearest);
+
+ /* now calculate influence for this particle */
+ const float rad = radius + smooth;
+ if ((rad - dist) > disp_intersect) {
+ disp_intersect = radius - dist;
+ radius = rad;
+ }
+
+ /* do smoothness if enabled */
+ CLAMP_MIN(smooth_range, 0.0f);
+ if (smooth)
+ smooth_range /= smooth;
+
+ const float str = 1.0f - smooth_range;
+ /* if influence is greater, use this one */
+ if (str > strength)
+ strength = str;
+ }
+
+ if (strength > 0.001f) {
+ float paintColor[4] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
+
+ /* apply velocity */
+ if ((brush->flags & MOD_DPAINT_USES_VELOCITY) && (part_index != -1)) {
+ float velocity[3];
+ ParticleData *pa = psys->particles + part_index;
+ mul_v3_v3fl(velocity, pa->state.vel, particle_timestep);
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3(velocity, bData->velocity[index].v);
+ }
+ velocity_val = normalize_v3(velocity);
+
+ /* store brush velocity for smudge */
+ if ((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)) {
+ copy_v3_v3(&bData->brush_velocity[index * 4], velocity);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ copy_v3_v3(paintColor, &brush->r);
+ }
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
+ depth = max_ff(0.0f, (radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+
+ dynamicPaint_updatePointData(
+ surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
+ }
}
static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
@@ -4429,1678 +4502,1767 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
float timescale)
{
- ParticleSettings *part = psys->part;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
-
- KDTree_3d *tree;
- int particlesAdded = 0;
- int invalidParticles = 0;
- int p = 0;
-
- const float solidradius = surface->radius_scale *
- ((brush->flags & MOD_DPAINT_PART_RAD) ? part->size : brush->particle_radius);
- const float smooth = brush->particle_smooth * surface->radius_scale;
-
- const float range = solidradius + smooth;
-
- Bounds3D part_bb = {{0}};
-
- if (psys->totpart < 1)
- return 1;
-
- /*
- * Build a kd-tree to optimize distance search
- */
- tree = BLI_kdtree_3d_new(psys->totpart);
-
- /* loop through particles and insert valid ones to the tree */
- p = 0;
- for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
- /* Proceed only if particle is active */
- if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
- (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) ||
- (pa->flag & PARS_UNEXIST))
- {
- continue;
- }
-
- /* for debug purposes check if any NAN particle proceeds
- * For some reason they get past activity check, this should rule most of them out */
- if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
- invalidParticles++;
- continue;
- }
-
- /* make sure particle is close enough to canvas */
- if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
- continue;
-
- BLI_kdtree_3d_insert(tree, p, pa->state.co);
-
- /* calc particle system bounds */
- boundInsert(&part_bb, pa->state.co);
-
- particlesAdded++;
- }
- if (invalidParticles)
- CLOG_WARN(&LOG, "Invalid particle(s) found!");
-
- /* If no suitable particles were found, exit */
- if (particlesAdded < 1) {
- BLI_kdtree_3d_free(tree);
- return 1;
- }
-
- /* begin thread safe malloc */
- BLI_threaded_malloc_begin();
-
- /* only continue if particle bb is close enough to canvas bb */
- if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
- int c_index;
- int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
-
- /* balance tree */
- BLI_kdtree_3d_balance(tree);
-
- /* loop through space partitioning grid */
- for (c_index = 0; c_index < total_cells; c_index++) {
- /* check cell bounding box */
- if (!grid->s_num[c_index] ||
- !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range))
- {
- continue;
- }
-
- /* loop through cell points */
- DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .psys = psys,
- .solidradius = solidradius, .timescale = timescale, .c_index = c_index,
- .treeData = tree,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (grid->s_num[c_index] > 250);
- BLI_task_parallel_range(0, grid->s_num[c_index],
- &data,
- dynamic_paint_paint_particle_cell_point_cb_ex,
- &settings);
- }
- }
- BLI_threaded_malloc_end();
- BLI_kdtree_3d_free(tree);
-
- return 1;
+ ParticleSettings *part = psys->part;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
+
+ KDTree_3d *tree;
+ int particlesAdded = 0;
+ int invalidParticles = 0;
+ int p = 0;
+
+ const float solidradius = surface->radius_scale * ((brush->flags & MOD_DPAINT_PART_RAD) ?
+ part->size :
+ brush->particle_radius);
+ const float smooth = brush->particle_smooth * surface->radius_scale;
+
+ const float range = solidradius + smooth;
+
+ Bounds3D part_bb = {{0}};
+
+ if (psys->totpart < 1)
+ return 1;
+
+ /*
+ * Build a kd-tree to optimize distance search
+ */
+ tree = BLI_kdtree_3d_new(psys->totpart);
+
+ /* loop through particles and insert valid ones to the tree */
+ p = 0;
+ for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
+ /* Proceed only if particle is active */
+ if ((pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) ||
+ (pa->alive == PARS_DEAD && (part->flag & PART_DIED) == 0) || (pa->flag & PARS_UNEXIST)) {
+ continue;
+ }
+
+ /* for debug purposes check if any NAN particle proceeds
+ * For some reason they get past activity check, this should rule most of them out */
+ if (isnan(pa->state.co[0]) || isnan(pa->state.co[1]) || isnan(pa->state.co[2])) {
+ invalidParticles++;
+ continue;
+ }
+
+ /* make sure particle is close enough to canvas */
+ if (!boundIntersectPoint(&grid->grid_bounds, pa->state.co, range))
+ continue;
+
+ BLI_kdtree_3d_insert(tree, p, pa->state.co);
+
+ /* calc particle system bounds */
+ boundInsert(&part_bb, pa->state.co);
+
+ particlesAdded++;
+ }
+ if (invalidParticles)
+ CLOG_WARN(&LOG, "Invalid particle(s) found!");
+
+ /* If no suitable particles were found, exit */
+ if (particlesAdded < 1) {
+ BLI_kdtree_3d_free(tree);
+ return 1;
+ }
+
+ /* begin thread safe malloc */
+ BLI_threaded_malloc_begin();
+
+ /* only continue if particle bb is close enough to canvas bb */
+ if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
+ int c_index;
+ int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
+
+ /* balance tree */
+ BLI_kdtree_3d_balance(tree);
+
+ /* loop through space partitioning grid */
+ for (c_index = 0; c_index < total_cells; c_index++) {
+ /* check cell bounding box */
+ if (!grid->s_num[c_index] || !boundsIntersectDist(&grid->bounds[c_index], &part_bb, range)) {
+ continue;
+ }
+
+ /* loop through cell points */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush,
+ .psys = psys,
+ .solidradius = solidradius,
+ .timescale = timescale,
+ .c_index = c_index,
+ .treeData = tree,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (grid->s_num[c_index] > 250);
+ BLI_task_parallel_range(0,
+ grid->s_num[c_index],
+ &data,
+ dynamic_paint_paint_particle_cell_point_cb_ex,
+ &settings);
+ }
+ }
+ BLI_threaded_malloc_end();
+ BLI_kdtree_3d_free(tree);
+
+ return 1;
}
/* paint a single point of defined proximity radius to the surface */
-static void dynamic_paint_paint_single_point_cb_ex(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_paint_single_point_cb_ex(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintPaintData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
-
- const DynamicPaintBrushSettings *brush = data->brush;
-
- const float timescale = data->timescale;
-
- const float brush_radius = data->brush_radius;
- const Vec3f *brushVelocity = data->brushVelocity;
-
- float *pointCoord = data->pointCoord;
-
- const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
- float colorband[4] = {0.0f};
- float strength;
-
- if (distance > brush_radius)
- return;
-
- /* Smooth range or color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
- brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP)
- {
- strength = 1.0f - distance / brush_radius;
- CLAMP(strength, 0.0f, 1.0f);
- }
- else {
- strength = 1.0f;
- }
-
- if (strength >= 0.001f) {
- float paintColor[3] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
-
- /* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
- {
- strength = colorband[3];
- }
-
- if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
- float velocity[3];
-
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushVelocity->v);
- }
- velocity_val = len_v3(velocity);
-
- /* store brush velocity for smudge */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT &&
- brush->flags & MOD_DPAINT_DO_SMUDGE && bData->brush_velocity)
- {
- mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
-
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- !(brush->flags & MOD_DPAINT_RAMP_ALPHA))
- {
- paintColor[0] = colorband[0];
- paintColor[1] = colorband[1];
- paintColor[2] = colorband[2];
- }
- else {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
- }
- else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* get displace depth */
- const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
- depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
- }
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
- }
+ const DynamicPaintPaintData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+
+ const DynamicPaintBrushSettings *brush = data->brush;
+
+ const float timescale = data->timescale;
+
+ const float brush_radius = data->brush_radius;
+ const Vec3f *brushVelocity = data->brushVelocity;
+
+ float *pointCoord = data->pointCoord;
+
+ const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
+ float colorband[4] = {0.0f};
+ float strength;
+
+ if (distance > brush_radius)
+ return;
+
+ /* Smooth range or color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_SMOOTH ||
+ brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP) {
+ strength = 1.0f - distance / brush_radius;
+ CLAMP(strength, 0.0f, 1.0f);
+ }
+ else {
+ strength = 1.0f;
+ }
+
+ if (strength >= 0.001f) {
+ float paintColor[3] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
+
+ /* color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband)) {
+ strength = colorband[3];
+ }
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
+ float velocity[3];
+
+ /* substract canvas point velocity */
+ if (bData->velocity) {
+ sub_v3_v3v3(velocity, brushVelocity->v, bData->velocity[index].v);
+ }
+ else {
+ copy_v3_v3(velocity, brushVelocity->v);
+ }
+ velocity_val = len_v3(velocity);
+
+ /* store brush velocity for smudge */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE &&
+ bData->brush_velocity) {
+ mul_v3_v3fl(&bData->brush_velocity[index * 4], velocity, 1.0f / velocity_val);
+ bData->brush_velocity[index * 4 + 3] = velocity_val;
+ }
+ }
+
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ !(brush->flags & MOD_DPAINT_RAMP_ALPHA)) {
+ paintColor[0] = colorband[0];
+ paintColor[1] = colorband[1];
+ paintColor[2] = colorband[2];
+ }
+ else {
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
+ }
+ }
+ else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* get displace depth */
+ const float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) *
+ brush_radius;
+ depth = max_ff(0.0f, (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale);
+ }
+ dynamicPaint_updatePointData(
+ surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
+ }
}
-static int dynamicPaint_paintSinglePoint(
- Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, Scene *scene, float timescale)
+static int dynamicPaint_paintSinglePoint(Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
+ float *pointCoord,
+ DynamicPaintBrushSettings *brush,
+ Object *brushOb,
+ Scene *scene,
+ float timescale)
{
- PaintSurfaceData *sData = surface->data;
- float brush_radius = brush->paint_distance * surface->radius_scale;
- Vec3f brushVel;
-
- if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
-
- const Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
- const MVert *mvert = brush_mesh->mvert;
-
- /*
- * Loop through every surface point
- */
- DynamicPaintPaintData data = {
- .surface = surface,
- .brush = brush, .brushOb = brushOb,
- .scene = scene, .timescale = timescale,
- .mvert = mvert,
- .brush_radius = brush_radius, .brushVelocity = &brushVel,
- .pointCoord = pointCoord,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_paint_single_point_cb_ex,
- &settings);
-
- return 1;
+ PaintSurfaceData *sData = surface->data;
+ float brush_radius = brush->paint_distance * surface->radius_scale;
+ Vec3f brushVel;
+
+ if (brush->flags & MOD_DPAINT_USES_VELOCITY)
+ dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
+
+ const Mesh *brush_mesh = dynamicPaint_brush_mesh_get(brush);
+ const MVert *mvert = brush_mesh->mvert;
+
+ /*
+ * Loop through every surface point
+ */
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush,
+ .brushOb = brushOb,
+ .scene = scene,
+ .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius,
+ .brushVelocity = &brushVel,
+ .pointCoord = pointCoord,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_paint_single_point_cb_ex, &settings);
+
+ return 1;
}
-
/***************************** Dynamic Paint Step / Baking ******************************/
/*
* Calculate current frame distances and directions for adjacency data
*/
-static void dynamic_paint_prepare_adjacency_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_prepare_adjacency_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- PaintSurfaceData *sData = userdata;
- PaintBakeData *bData = sData->bData;
- BakeAdjPoint *bNeighs = bData->bNeighs;
- PaintAdjData *adj_data = sData->adj_data;
- Vec3f *realCoord = bData->realCoord;
-
- const int num_neighs = adj_data->n_num[index];
-
- for (int i = 0; i < num_neighs; i++) {
- const int n_index = adj_data->n_index[index] + i;
- const int t_index = adj_data->n_target[n_index];
-
- /* dir vec */
- sub_v3_v3v3(bNeighs[n_index].dir, realCoord[bData->s_pos[t_index]].v, realCoord[bData->s_pos[index]].v);
- /* dist */
- bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
- }
+ PaintSurfaceData *sData = userdata;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = bData->bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+ Vec3f *realCoord = bData->realCoord;
+
+ const int num_neighs = adj_data->n_num[index];
+
+ for (int i = 0; i < num_neighs; i++) {
+ const int n_index = adj_data->n_index[index] + i;
+ const int t_index = adj_data->n_target[n_index];
+
+ /* dir vec */
+ sub_v3_v3v3(bNeighs[n_index].dir,
+ realCoord[bData->s_pos[t_index]].v,
+ realCoord[bData->s_pos[index]].v);
+ /* dist */
+ bNeighs[n_index].dist = normalize_v3(bNeighs[n_index].dir);
+ }
}
static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- BakeAdjPoint *bNeighs;
- PaintAdjData *adj_data = sData->adj_data;
-
- int index;
-
- if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
- return;
-
- if (bData->bNeighs)
- MEM_freeN(bData->bNeighs);
- bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake");
- if (!bNeighs)
- return;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- sData,
- dynamic_paint_prepare_adjacency_cb,
- &settings);
-
- /* calculate average values (single thread).
- * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
- bData->average_dist = 0.0;
- for (index = 0; index < sData->total_points; index++) {
- int numOfNeighs = adj_data->n_num[index];
-
- for (int i = 0; i < numOfNeighs; i++) {
- bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
- }
- }
- bData->average_dist /= adj_data->total_targets;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+
+ int index;
+
+ if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
+ return;
+
+ if (bData->bNeighs)
+ MEM_freeN(bData->bNeighs);
+ bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs),
+ "PaintEffectBake");
+ if (!bNeighs)
+ return;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
+
+ /* calculate average values (single thread).
+ * Note: tried to put this in threaded callback (using _finalize feature), but gave ~30% slower result! */
+ bData->average_dist = 0.0;
+ for (index = 0; index < sData->total_points; index++) {
+ int numOfNeighs = adj_data->n_num[index];
+
+ for (int i = 0; i < numOfNeighs; i++) {
+ bData->average_dist += (double)bNeighs[adj_data->n_index[index] + i].dist;
+ }
+ }
+ bData->average_dist /= adj_data->total_targets;
}
/* find two adjacency points (closest_id) and influence (closest_d) to move paint towards when affected by a force */
-static void surface_determineForceTargetPoints(
- const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
+static void surface_determineForceTargetPoints(const PaintSurfaceData *sData,
+ const int index,
+ const float force[3],
+ float closest_d[2],
+ int closest_id[2])
{
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- const int numOfNeighs = sData->adj_data->n_num[index];
- int i;
-
- closest_id[0] = closest_id[1] = -1;
- closest_d[0] = closest_d[1] = -1.0f;
-
- /* find closest neigh */
- for (i = 0; i < numOfNeighs; i++) {
- const int n_index = sData->adj_data->n_index[index] + i;
- const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
-
- if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
- closest_d[0] = dir_dot;
- closest_id[0] = n_index;
- }
- }
-
- if (closest_d[0] < 0.0f)
- return;
-
- /* find second closest neigh */
- for (i = 0; i < numOfNeighs; i++) {
- const int n_index = sData->adj_data->n_index[index] + i;
-
- if (n_index == closest_id[0])
- continue;
-
- const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
-
- /* only accept neighbor at "other side" of the first one in relation to force dir
- * so make sure angle between this and closest neigh is greater than first angle. */
- if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
- closest_d[1] = dir_dot;
- closest_id[1] = n_index;
- }
- }
-
- /* if two valid neighs found, calculate how force effect is divided evenly between them
- * (so that d[0] + d[1] = 1.0) */
- if (closest_id[1] != -1) {
- float force_proj[3];
- float tangent[3];
- const float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
- float force_intersect;
- float temp;
-
- /* project force vector on the plane determined by these two neighbor points
- * and calculate relative force angle from it. */
- cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
- normalize_v3(tangent);
- force_intersect = dot_v3v3(force, tangent);
- madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
- normalize_v3(force_proj);
-
- /* get drip factor based on force dir in relation to angle between those neighbors */
- temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
- CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
- closest_d[1] = acosf(temp) / neigh_diff;
- closest_d[0] = 1.0f - closest_d[1];
-
- /* and multiply depending on how deeply force intersects surface */
- temp = fabsf(force_intersect);
- CLAMP(temp, 0.0f, 1.0f);
- mul_v2_fl(closest_d, acosf(temp) / (float)M_PI_2);
- }
- else {
- /* if only single neighbor, still linearize force intersection effect */
- closest_d[0] = 1.0f - acosf(closest_d[0]) / (float)M_PI_2;
- }
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ int i;
+
+ closest_id[0] = closest_id[1] = -1;
+ closest_d[0] = closest_d[1] = -1.0f;
+
+ /* find closest neigh */
+ for (i = 0; i < numOfNeighs; i++) {
+ const int n_index = sData->adj_data->n_index[index] + i;
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+
+ if (dir_dot > closest_d[0] && dir_dot > 0.0f) {
+ closest_d[0] = dir_dot;
+ closest_id[0] = n_index;
+ }
+ }
+
+ if (closest_d[0] < 0.0f)
+ return;
+
+ /* find second closest neigh */
+ for (i = 0; i < numOfNeighs; i++) {
+ const int n_index = sData->adj_data->n_index[index] + i;
+
+ if (n_index == closest_id[0])
+ continue;
+
+ const float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ const float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
+
+ /* only accept neighbor at "other side" of the first one in relation to force dir
+ * so make sure angle between this and closest neigh is greater than first angle. */
+ if (dir_dot > closest_d[1] && closest_dot < closest_d[0] && dir_dot > 0.0f) {
+ closest_d[1] = dir_dot;
+ closest_id[1] = n_index;
+ }
+ }
+
+ /* if two valid neighs found, calculate how force effect is divided evenly between them
+ * (so that d[0] + d[1] = 1.0) */
+ if (closest_id[1] != -1) {
+ float force_proj[3];
+ float tangent[3];
+ const float neigh_diff = acosf(
+ dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
+ float force_intersect;
+ float temp;
+
+ /* project force vector on the plane determined by these two neighbor points
+ * and calculate relative force angle from it. */
+ cross_v3_v3v3(tangent, bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir);
+ normalize_v3(tangent);
+ force_intersect = dot_v3v3(force, tangent);
+ madd_v3_v3v3fl(force_proj, force, tangent, (-1.0f) * force_intersect);
+ normalize_v3(force_proj);
+
+ /* get drip factor based on force dir in relation to angle between those neighbors */
+ temp = dot_v3v3(bNeighs[closest_id[0]].dir, force_proj);
+ CLAMP(temp, -1.0f, 1.0f); /* float precision might cause values > 1.0f that return infinite */
+ closest_d[1] = acosf(temp) / neigh_diff;
+ closest_d[0] = 1.0f - closest_d[1];
+
+ /* and multiply depending on how deeply force intersects surface */
+ temp = fabsf(force_intersect);
+ CLAMP(temp, 0.0f, 1.0f);
+ mul_v2_fl(closest_d, acosf(temp) / (float)M_PI_2);
+ }
+ else {
+ /* if only single neighbor, still linearize force intersection effect */
+ closest_d[0] = 1.0f - acosf(closest_d[0]) / (float)M_PI_2;
+ }
}
-static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrushSettings *brush, float timescale)
+static void dynamicPaint_doSmudge(DynamicPaintSurface *surface,
+ DynamicPaintBrushSettings *brush,
+ float timescale)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int index, steps, step;
- float eff_scale, max_velocity = 0.0f;
-
- if (!sData->adj_data)
- return;
-
- /* find max velocity */
- for (index = 0; index < sData->total_points; index++) {
- float vel = bData->brush_velocity[index * 4 + 3];
- CLAMP_MIN(max_velocity, vel);
- }
-
- steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
- CLAMP(steps, 0, 12);
- eff_scale = brush->smudge_strength / (float)steps * timescale;
-
- for (step = 0; step < steps; step++) {
- for (index = 0; index < sData->total_points; index++) {
- int i;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- continue;
-
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- float smudge_str = bData->brush_velocity[index * 4 + 3];
-
- /* force targets */
- int closest_id[2];
- float closest_d[2];
-
- if (!smudge_str)
- continue;
-
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
-
- /* Apply movement towards those two points */
- for (i = 0; i < 2; i++) {
- int n_index = closest_id[i];
- if (n_index != -1 && closest_d[i] > 0.0f) {
- float dir_dot = closest_d[i], dir_factor;
- float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
-
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f)
- continue;
-
- dir_factor = dir_dot * speed_scale;
- CLAMP_MAX(dir_factor, brush->smudge_strength);
-
- /* mix new color and alpha */
- mixColors(ePoint->color, ePoint->color[3], pPoint->color, pPoint->color[3], dir_factor);
- ePoint->color[3] = ePoint->color[3] * (1.0f - dir_factor) + pPoint->color[3] * dir_factor;
-
- /* smudge "wet layer" */
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint->e_color, pPoint->e_color[3], dir_factor);
- ePoint->e_color[3] = ePoint->e_color[3] * (1.0f - dir_factor) + pPoint->e_color[3] * dir_factor;
- pPoint->wetness *= (1.0f - dir_factor);
- }
- }
- }
- }
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ int index, steps, step;
+ float eff_scale, max_velocity = 0.0f;
+
+ if (!sData->adj_data)
+ return;
+
+ /* find max velocity */
+ for (index = 0; index < sData->total_points; index++) {
+ float vel = bData->brush_velocity[index * 4 + 3];
+ CLAMP_MIN(max_velocity, vel);
+ }
+
+ steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
+ CLAMP(steps, 0, 12);
+ eff_scale = brush->smudge_strength / (float)steps * timescale;
+
+ for (step = 0; step < steps; step++) {
+ for (index = 0; index < sData->total_points; index++) {
+ int i;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ continue;
+
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ float smudge_str = bData->brush_velocity[index * 4 + 3];
+
+ /* force targets */
+ int closest_id[2];
+ float closest_d[2];
+
+ if (!smudge_str)
+ continue;
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(
+ sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (i = 0; i < 2; i++) {
+ int n_index = closest_id[i];
+ if (n_index != -1 && closest_d[i] > 0.0f) {
+ float dir_dot = closest_d[i], dir_factor;
+ float speed_scale = eff_scale * smudge_str / bNeighs[n_index].dist;
+ PaintPoint *ePoint = &(
+ (PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ dir_factor = dir_dot * speed_scale;
+ CLAMP_MAX(dir_factor, brush->smudge_strength);
+
+ /* mix new color and alpha */
+ mixColors(ePoint->color, ePoint->color[3], pPoint->color, pPoint->color[3], dir_factor);
+ ePoint->color[3] = ePoint->color[3] * (1.0f - dir_factor) +
+ pPoint->color[3] * dir_factor;
+
+ /* smudge "wet layer" */
+ mixColors(ePoint->e_color,
+ ePoint->e_color[3],
+ pPoint->e_color,
+ pPoint->e_color[3],
+ dir_factor);
+ ePoint->e_color[3] = ePoint->e_color[3] * (1.0f - dir_factor) +
+ pPoint->e_color[3] * dir_factor;
+ pPoint->wetness *= (1.0f - dir_factor);
+ }
+ }
+ }
+ }
}
typedef struct DynamicPaintEffectData {
- const DynamicPaintSurface *surface;
- Scene *scene;
+ const DynamicPaintSurface *surface;
+ Scene *scene;
- float *force;
- ListBase *effectors;
- const void *prevPoint;
- const float eff_scale;
+ float *force;
+ ListBase *effectors;
+ const void *prevPoint;
+ const float eff_scale;
- uint8_t *point_locks;
+ uint8_t *point_locks;
- const float wave_speed;
- const float wave_scale;
- const float wave_max_slope;
+ const float wave_speed;
+ const float wave_scale;
+ const float wave_max_slope;
- const float dt;
- const float min_dist;
- const float damp_factor;
- const bool reset_wave;
+ const float dt;
+ const float min_dist;
+ const float damp_factor;
+ const bool reset_wave;
} DynamicPaintEffectData;
/*
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
-static void dynamic_paint_prepare_effect_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_prepare_effect_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintBakeData *bData = sData->bData;
- Vec3f *realCoord = bData->realCoord;
-
- Scene *scene = data->scene;
-
- float *force = data->force;
- ListBase *effectors = data->effectors;
-
- float forc[3] = {0};
- float vel[3] = {0};
-
- /* apply force fields */
- if (effectors) {
- EffectedPoint epoint;
- pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
- epoint.vel_to_sec = 1.0f;
- BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
- }
-
- /* if global gravity is enabled, add it too */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
- /* also divide by 10 to about match default grav
- * with default force strength (1.0). */
- madd_v3_v3fl(forc, scene->physics_settings.gravity,
- surface->effector_weights->global_gravity * surface->effector_weights->weight[0] / 10.f);
-
- /* add surface point velocity and acceleration if enabled */
- if (bData->velocity) {
- if (surface->drip_vel)
- madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
-
- /* acceleration */
- if (bData->prev_velocity && surface->drip_acc) {
- float acc[3];
- copy_v3_v3(acc, bData->velocity[index].v);
- sub_v3_v3(acc, bData->prev_velocity[index].v);
- madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
- }
- }
-
- /* force strength, and normalize force vec */
- force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ Vec3f *realCoord = bData->realCoord;
+
+ Scene *scene = data->scene;
+
+ float *force = data->force;
+ ListBase *effectors = data->effectors;
+
+ float forc[3] = {0};
+ float vel[3] = {0};
+
+ /* apply force fields */
+ if (effectors) {
+ EffectedPoint epoint;
+ pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
+ epoint.vel_to_sec = 1.0f;
+ BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ }
+
+ /* if global gravity is enabled, add it too */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ /* also divide by 10 to about match default grav
+ * with default force strength (1.0). */
+ madd_v3_v3fl(forc,
+ scene->physics_settings.gravity,
+ surface->effector_weights->global_gravity * surface->effector_weights->weight[0] /
+ 10.f);
+
+ /* add surface point velocity and acceleration if enabled */
+ if (bData->velocity) {
+ if (surface->drip_vel)
+ madd_v3_v3fl(forc, bData->velocity[index].v, surface->drip_vel * (-1.0f));
+
+ /* acceleration */
+ if (bData->prev_velocity && surface->drip_acc) {
+ float acc[3];
+ copy_v3_v3(acc, bData->velocity[index].v);
+ sub_v3_v3(acc, bData->prev_velocity[index].v);
+ madd_v3_v3fl(forc, acc, surface->drip_acc * (-1.0f));
+ }
+ }
+
+ /* force strength, and normalize force vec */
+ force[index * 4 + 3] = normalize_v3_v3(&force[index * 4], forc);
}
-static int dynamicPaint_prepareEffectStep(
- struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+static int dynamicPaint_prepareEffectStep(struct Depsgraph *depsgraph,
+ DynamicPaintSurface *surface,
+ Scene *scene,
+ Object *ob,
+ float **force,
+ float timescale)
{
- double average_force = 0.0f;
- float shrink_speed = 0.0f, spread_speed = 0.0f;
- float fastest_effect, avg_dist;
- int steps;
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
-
- /* Init force data if required */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights);
-
- /* allocate memory for force data (dir vector + strength) */
- *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
-
- if (*force) {
- DynamicPaintEffectData data = {
- .surface = surface, .scene = scene,
- .force = *force, .effectors = effectors,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_prepare_effect_cb,
- &settings);
-
- /* calculate average values (single thread) */
- for (int index = 0; index < sData->total_points; index++) {
- average_force += (double)(*force)[index * 4 + 3];
- }
- average_force /= sData->total_points;
- }
- BKE_effectors_free(effectors);
- }
-
- /* Get number of required steps using average point distance
- * so that just a few ultra close pixels wont up substeps to max. */
-
- /* adjust number of required substep by fastest active effect */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD)
- spread_speed = surface->spread_speed;
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK)
- shrink_speed = surface->shrink_speed;
-
- fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
- avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
-
- steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
- CLAMP(steps, 1, 20);
-
- return steps;
+ double average_force = 0.0f;
+ float shrink_speed = 0.0f, spread_speed = 0.0f;
+ float fastest_effect, avg_dist;
+ int steps;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+
+ /* Init force data if required */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights);
+
+ /* allocate memory for force data (dir vector + strength) */
+ *force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
+
+ if (*force) {
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .scene = scene,
+ .force = *force,
+ .effectors = effectors,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, &settings);
+
+ /* calculate average values (single thread) */
+ for (int index = 0; index < sData->total_points; index++) {
+ average_force += (double)(*force)[index * 4 + 3];
+ }
+ average_force /= sData->total_points;
+ }
+ BKE_effectors_free(effectors);
+ }
+
+ /* Get number of required steps using average point distance
+ * so that just a few ultra close pixels wont up substeps to max. */
+
+ /* adjust number of required substep by fastest active effect */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD)
+ spread_speed = surface->spread_speed;
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK)
+ shrink_speed = surface->shrink_speed;
+
+ fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
+ avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
+
+ steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
+ CLAMP(steps, 1, 20);
+
+ return steps;
}
/**
* Processes active effect step.
*/
-static void dynamic_paint_effect_spread_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_effect_spread_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- return;
-
- const int numOfNeighs = sData->adj_data->n_num[index];
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const float eff_scale = data->eff_scale;
-
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
-
- /* Loop through neighboring points */
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- float w_factor;
- const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
- const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
- const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f * surface->color_spread_speed;
-
- /* do color mixing */
- if (color_mix)
- mixColors(pPoint->e_color, pPoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], color_mix);
-
- /* Only continue if surrounding point has higher wetness */
- if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
- continue;
-
- w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
- CLAMP(w_factor, 0.0f, 1.0f);
-
- /* mix new wetness and color */
- pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
- pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3],
- pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor);
- }
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float w_factor;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
+ eff_scale / bNeighs[n_idx].dist;
+ const float color_mix = min_fff(pPoint_prev->wetness, pPoint->wetness, 1.0f) * 0.25f *
+ surface->color_spread_speed;
+
+ /* do color mixing */
+ if (color_mix)
+ mixColors(pPoint->e_color,
+ pPoint->e_color[3],
+ pPoint_prev->e_color,
+ pPoint_prev->e_color[3],
+ color_mix);
+
+ /* Only continue if surrounding point has higher wetness */
+ if (pPoint_prev->wetness < pPoint->wetness || pPoint_prev->wetness < MIN_WETNESS)
+ continue;
+
+ w_factor = 1.0f / numOfNeighs * min_ff(pPoint_prev->wetness, 1.0f) * speed_scale;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ /* mix new wetness and color */
+ pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness);
+ pPoint->e_color[3] = mixColors(pPoint->e_color,
+ pPoint->e_color[3],
+ pPoint_prev->e_color,
+ pPoint_prev->e_color[3],
+ w_factor);
+ }
}
-static void dynamic_paint_effect_shrink_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_effect_shrink_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- return;
-
- const int numOfNeighs = sData->adj_data->n_num[index];
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const float eff_scale = data->eff_scale;
- float totalAlpha = 0.0f;
-
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
-
- /* Loop through neighboring points */
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_idx].dist;
- const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
- float a_factor, ea_factor, w_factor;
-
- totalAlpha += pPoint_prev->e_color[3];
-
- /* Check if neighboring point has lower alpha,
- * if so, decrease this point's alpha as well. */
- if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
- continue;
-
- /* decrease factor for dry paint alpha */
- a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs * (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale, 0.0f);
- /* decrease factor for wet paint alpha */
- ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 * (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale, 0.0f);
- /* decrease factor for paint wetness */
- w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 * (pPoint->wetness - pPoint_prev->wetness) * speed_scale, 0.0f);
-
- pPoint->color[3] -= a_factor;
- CLAMP_MIN(pPoint->color[3], 0.0f);
- pPoint->e_color[3] -= ea_factor;
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->wetness -= w_factor;
- CLAMP_MIN(pPoint->wetness, 0.0f);
- }
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const float eff_scale = data->eff_scale;
+ float totalAlpha = 0.0f;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+
+ /* Loop through neighboring points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const float speed_scale = (bNeighs[n_idx].dist < eff_scale) ? 1.0f :
+ eff_scale / bNeighs[n_idx].dist;
+ const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
+ float a_factor, ea_factor, w_factor;
+
+ totalAlpha += pPoint_prev->e_color[3];
+
+ /* Check if neighboring point has lower alpha,
+ * if so, decrease this point's alpha as well. */
+ if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f)
+ continue;
+
+ /* decrease factor for dry paint alpha */
+ a_factor = max_ff((1.0f - pPoint_prev->color[3]) / numOfNeighs *
+ (pPoint->color[3] - pPoint_prev->color[3]) * speed_scale,
+ 0.0f);
+ /* decrease factor for wet paint alpha */
+ ea_factor = max_ff((1.0f - pPoint_prev->e_color[3]) / 8 *
+ (pPoint->e_color[3] - pPoint_prev->e_color[3]) * speed_scale,
+ 0.0f);
+ /* decrease factor for paint wetness */
+ w_factor = max_ff((1.0f - pPoint_prev->wetness) / 8 *
+ (pPoint->wetness - pPoint_prev->wetness) * speed_scale,
+ 0.0f);
+
+ pPoint->color[3] -= a_factor;
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+ pPoint->e_color[3] -= ea_factor;
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ pPoint->wetness -= w_factor;
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+ }
}
-static void dynamic_paint_effect_drip_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_effect_drip_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
-
- if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
- return;
-
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const PaintPoint *prevPoint = data->prevPoint;
- const PaintPoint *pPoint_prev = &prevPoint[index];
- const float *force = data->force;
- const float eff_scale = data->eff_scale;
-
- const int *n_target = sData->adj_data->n_target;
-
- uint8_t *point_locks = data->point_locks;
-
- int closest_id[2];
- float closest_d[2];
-
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0)
- return;
- CLAMP(w_factor, 0.0f, 1.0f);
-
- float ppoint_wetness_diff = 0.0f;
-
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
-
- /* Apply movement towards those two points */
- for (int i = 0; i < 2; i++) {
- const int n_idx = closest_id[i];
- if (n_idx != -1 && closest_d[i] > 0.0f) {
- const float dir_dot = closest_d[i];
-
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f)
- continue;
-
- float dir_factor, a_factor;
- const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
-
- const unsigned int n_trgt = (unsigned int)n_target[n_idx];
-
- /* Sort of spinlock, but only for given ePoint.
- * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
- * much more efficient than a global spin lock. */
- const unsigned int epointlock_idx = n_trgt / 8;
- const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
- while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) & epointlock_bitmask);
-
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
- const float e_wet = ePoint->wetness;
-
- dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
-
- /* mix new wetness */
- ePoint->wetness += dir_factor;
- CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
-
- /* mix new color */
- a_factor = dir_factor / pPoint_prev->wetness;
- CLAMP(a_factor, 0.0f, 1.0f);
- mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor);
- /* dripping is supposed to preserve alpha level */
- if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
- ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
- CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
- }
-
- /* Decrease paint wetness on current point
- * (just store diff here, that way we can only lock current point once at the end to apply it). */
- ppoint_wetness_diff += (ePoint->wetness - e_wet);
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL)
+ return;
+
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const PaintPoint *prevPoint = data->prevPoint;
+ const PaintPoint *pPoint_prev = &prevPoint[index];
+ const float *force = data->force;
+ const float eff_scale = data->eff_scale;
+
+ const int *n_target = sData->adj_data->n_target;
+
+ uint8_t *point_locks = data->point_locks;
+
+ int closest_id[2];
+ float closest_d[2];
+
+ /* adjust drip speed depending on wetness */
+ float w_factor = pPoint_prev->wetness - 0.025f;
+ if (w_factor <= 0)
+ return;
+ CLAMP(w_factor, 0.0f, 1.0f);
+
+ float ppoint_wetness_diff = 0.0f;
+
+ /* get force affect points */
+ surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+
+ /* Apply movement towards those two points */
+ for (int i = 0; i < 2; i++) {
+ const int n_idx = closest_id[i];
+ if (n_idx != -1 && closest_d[i] > 0.0f) {
+ const float dir_dot = closest_d[i];
+
+ /* just skip if angle is too extreme */
+ if (dir_dot <= 0.0f)
+ continue;
+
+ float dir_factor, a_factor;
+ const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist;
+
+ const unsigned int n_trgt = (unsigned int)n_target[n_idx];
+
+ /* Sort of spinlock, but only for given ePoint.
+ * Since the odds a same ePoint is modified at the same time by several threads is very low, this is
+ * much more efficient than a global spin lock. */
+ const unsigned int epointlock_idx = n_trgt / 8;
+ const uint8_t epointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[epointlock_idx], epointlock_bitmask) &
+ epointlock_bitmask)
+ ;
+
+ PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt];
+ const float e_wet = ePoint->wetness;
+
+ dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor);
+
+ /* mix new wetness */
+ ePoint->wetness += dir_factor;
+ CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS);
+
+ /* mix new color */
+ a_factor = dir_factor / pPoint_prev->wetness;
+ CLAMP(a_factor, 0.0f, 1.0f);
+ mixColors(ePoint->e_color,
+ ePoint->e_color[3],
+ pPoint_prev->e_color,
+ pPoint_prev->e_color[3],
+ a_factor);
+ /* dripping is supposed to preserve alpha level */
+ if (pPoint_prev->e_color[3] > ePoint->e_color[3]) {
+ ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3];
+ CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]);
+ }
+
+ /* Decrease paint wetness on current point
+ * (just store diff here, that way we can only lock current point once at the end to apply it). */
+ ppoint_wetness_diff += (ePoint->wetness - e_wet);
#ifndef NDEBUG
- {
- uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
- BLI_assert(ret & epointlock_bitmask);
- }
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[epointlock_idx],
+ ~epointlock_bitmask);
+ BLI_assert(ret & epointlock_bitmask);
+ }
#else
- atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
+ atomic_fetch_and_and_uint8(&point_locks[epointlock_idx], ~epointlock_bitmask);
#endif
- }
- }
+ }
+ }
- {
- const unsigned int ppointlock_idx = index / 8;
- const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
- while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) & ppointlock_bitmask);
+ {
+ const unsigned int ppointlock_idx = index / 8;
+ const uint8_t ppointlock_bitmask = 1 << (index & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[ppointlock_idx], ppointlock_bitmask) &
+ ppointlock_bitmask)
+ ;
- pPoint->wetness -= ppoint_wetness_diff;
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+ pPoint->wetness -= ppoint_wetness_diff;
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
#ifndef NDEBUG
- {
- uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
- BLI_assert(ret & ppointlock_bitmask);
- }
+ {
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+ BLI_assert(ret & ppointlock_bitmask);
+ }
#else
- atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
+ atomic_fetch_and_and_uint8(&point_locks[ppointlock_idx], ~ppointlock_bitmask);
#endif
- }
+ }
}
-static void dynamicPaint_doEffectStep(
- DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
+static void dynamicPaint_doEffectStep(DynamicPaintSurface *surface,
+ float *force,
+ PaintPoint *prevPoint,
+ float timescale,
+ float steps)
{
- PaintSurfaceData *sData = surface->data;
-
- const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
- timescale /= steps;
-
- if (!sData->adj_data)
- return;
-
- /*
- * Spread Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
- const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
-
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_effect_spread_cb,
- &settings);
- }
-
- /*
- * Shrink Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
- const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
-
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_effect_shrink_cb,
- &settings);
- }
-
- /*
- * Drip Effect
- */
- if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
- const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
-
- /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
- const size_t point_locks_size = (sData->total_points / 8) + 1;
- uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
-
- /* Copy current surface to the previous points array to read unmodified values */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint,
- .eff_scale = eff_scale, .force = force,
- .point_locks = point_locks,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_effect_drip_cb,
- &settings);
-
- MEM_freeN(point_locks);
- }
+ PaintSurfaceData *sData = surface->data;
+
+ const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
+ timescale /= steps;
+
+ if (!sData->adj_data)
+ return;
+
+ /*
+ * Spread Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed *
+ timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .eff_scale = eff_scale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, &settings);
+ }
+
+ /*
+ * Shrink Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed *
+ timescale;
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .eff_scale = eff_scale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, &settings);
+ }
+
+ /*
+ * Drip Effect
+ */
+ if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
+ const float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+
+ /* Same as BLI_bitmask, but handled atomicaly as 'ePoint' locks. */
+ const size_t point_locks_size = (sData->total_points / 8) + 1;
+ uint8_t *point_locks = MEM_callocN(sizeof(*point_locks) * point_locks_size, __func__);
+
+ /* Copy current surface to the previous points array to read unmodified values */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .eff_scale = eff_scale,
+ .force = force,
+ .point_locks = point_locks,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, &settings);
+
+ MEM_freeN(point_locks);
+ }
}
-static void dynamic_paint_border_cb(
- void *__restrict userdata,
- const int b_index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_border_cb(void *__restrict userdata,
+ const int b_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
+ const DynamicPaintEffectData *data = userdata;
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
- const int index = sData->adj_data->border[b_index];
+ const int index = sData->adj_data->border[b_index];
- const int numOfNeighs = sData->adj_data->n_num[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
- /* Average neighboring points. Intermediaries use premultiplied alpha. */
- float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- float mix_wetness = 0.0f;
+ /* Average neighboring points. Intermediaries use premultiplied alpha. */
+ float mix_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float mix_e_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float mix_wetness = 0.0f;
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- const int target = n_target[n_idx];
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ const int target = n_target[n_idx];
- PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
+ PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target];
- assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
+ assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL));
- madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
- mix_color[3] += pPoint2->color[3];
+ madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]);
+ mix_color[3] += pPoint2->color[3];
- madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
- mix_e_color[3] += pPoint2->e_color[3];
+ madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]);
+ mix_e_color[3] += pPoint2->e_color[3];
- mix_wetness += pPoint2->wetness;
- }
+ mix_wetness += pPoint2->wetness;
+ }
- const float divisor = 1.0f / numOfNeighs;
+ const float divisor = 1.0f / numOfNeighs;
- if (mix_color[3]) {
- pPoint->color[3] = mix_color[3] * divisor;
- mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
- }
- else {
- pPoint->color[3] = 0.0f;
- }
+ if (mix_color[3]) {
+ pPoint->color[3] = mix_color[3] * divisor;
+ mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]);
+ }
+ else {
+ pPoint->color[3] = 0.0f;
+ }
- if (mix_e_color[3]) {
- pPoint->e_color[3] = mix_e_color[3] * divisor;
- mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
- }
- else {
- pPoint->e_color[3] = 0.0f;
- }
+ if (mix_e_color[3]) {
+ pPoint->e_color[3] = mix_e_color[3] * divisor;
+ mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]);
+ }
+ else {
+ pPoint->e_color[3] = 0.0f;
+ }
- pPoint->wetness = mix_wetness / numOfNeighs;
+ pPoint->wetness = mix_wetness / numOfNeighs;
}
static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface)
{
- PaintSurfaceData *sData = surface->data;
-
- if (!sData->adj_data || !sData->adj_data->border)
- return;
-
- /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
- DynamicPaintEffectData data = {
- .surface = surface,
- };
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->adj_data->total_border > 1000);
- BLI_task_parallel_range(0, sData->adj_data->total_border,
- &data,
- dynamic_paint_border_cb,
- &settings);
+ PaintSurfaceData *sData = surface->data;
+
+ if (!sData->adj_data || !sData->adj_data->border)
+ return;
+
+ /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ };
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->adj_data->total_border > 1000);
+ BLI_task_parallel_range(
+ 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, &settings);
}
-static void dynamic_paint_wave_step_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_wave_step_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintEffectData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- const PaintWavePoint *prevPoint = data->prevPoint;
-
- const float wave_speed = data->wave_speed;
- const float wave_scale = data->wave_scale;
- const float wave_max_slope = data->wave_max_slope;
-
- const float dt = data->dt;
- const float min_dist = data->min_dist;
- const float damp_factor = data->damp_factor;
-
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- const int numOfNeighs = sData->adj_data->n_num[index];
- float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
- int numOfN = 0, numOfRN = 0;
-
- if (wPoint->state > 0)
- return;
-
- const int *n_index = sData->adj_data->n_index;
- const int *n_target = sData->adj_data->n_target;
- const int *adj_flags = sData->adj_data->flags;
-
- /* calculate force from surrounding points */
- for (int i = 0; i < numOfNeighs; i++) {
- const int n_idx = n_index[index] + i;
- float dist = bNeighs[n_idx].dist * wave_scale;
- const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
-
- if (!dist || tPoint->state > 0)
- continue;
-
- CLAMP_MIN(dist, min_dist);
- avg_dist += dist;
- numOfN++;
-
- /* count average height for edge points for open borders */
- if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
- avg_n_height += tPoint->height;
- numOfRN++;
- }
-
- force += (tPoint->height - wPoint->height) / (dist * dist);
- avg_height += tPoint->height;
- }
- avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
-
- if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
- /* if open borders, apply a fake height to keep waves going on */
- avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
- wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
- (avg_dist + dt * wave_speed);
- }
- /* else do wave eq */
- else {
- /* add force towards zero height based on average dist */
- if (avg_dist)
- force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
-
- /* change point velocity */
- wPoint->velocity += force * dt * wave_speed * wave_speed;
- /* damping */
- wPoint->velocity *= damp_factor;
- /* and new height */
- wPoint->height += wPoint->velocity * dt;
-
- /* limit wave slope steepness */
- if (wave_max_slope && avg_dist) {
- const float max_offset = wave_max_slope * avg_dist;
- const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
- if (offset > max_offset)
- wPoint->height += offset - max_offset;
- else if (offset < -max_offset)
- wPoint->height += offset + max_offset;
- }
- }
-
- if (data->reset_wave) {
- /* if there wasn't any brush intersection, clear isect height */
- if (wPoint->state == DPAINT_WAVE_NONE) {
- wPoint->brush_isect = 0.0f;
- }
- wPoint->state = DPAINT_WAVE_NONE;
- }
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const PaintWavePoint *prevPoint = data->prevPoint;
+
+ const float wave_speed = data->wave_speed;
+ const float wave_scale = data->wave_scale;
+ const float wave_max_slope = data->wave_max_slope;
+
+ const float dt = data->dt;
+ const float min_dist = data->min_dist;
+ const float damp_factor = data->damp_factor;
+
+ PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
+ float force = 0.0f, avg_dist = 0.0f, avg_height = 0.0f, avg_n_height = 0.0f;
+ int numOfN = 0, numOfRN = 0;
+
+ if (wPoint->state > 0)
+ return;
+
+ const int *n_index = sData->adj_data->n_index;
+ const int *n_target = sData->adj_data->n_target;
+ const int *adj_flags = sData->adj_data->flags;
+
+ /* calculate force from surrounding points */
+ for (int i = 0; i < numOfNeighs; i++) {
+ const int n_idx = n_index[index] + i;
+ float dist = bNeighs[n_idx].dist * wave_scale;
+ const PaintWavePoint *tPoint = &prevPoint[n_target[n_idx]];
+
+ if (!dist || tPoint->state > 0)
+ continue;
+
+ CLAMP_MIN(dist, min_dist);
+ avg_dist += dist;
+ numOfN++;
+
+ /* count average height for edge points for open borders */
+ if (!(adj_flags[n_target[n_idx]] & ADJ_ON_MESH_EDGE)) {
+ avg_n_height += tPoint->height;
+ numOfRN++;
+ }
+
+ force += (tPoint->height - wPoint->height) / (dist * dist);
+ avg_height += tPoint->height;
+ }
+ avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+
+ if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS && adj_flags[index] & ADJ_ON_MESH_EDGE) {
+ /* if open borders, apply a fake height to keep waves going on */
+ avg_n_height = (numOfRN) ? avg_n_height / numOfRN : 0.0f;
+ wPoint->height = (dt * wave_speed * avg_n_height + wPoint->height * avg_dist) /
+ (avg_dist + dt * wave_speed);
+ }
+ /* else do wave eq */
+ else {
+ /* add force towards zero height based on average dist */
+ if (avg_dist)
+ force += (0.0f - wPoint->height) * surface->wave_spring / (avg_dist * avg_dist) / 2.0f;
+
+ /* change point velocity */
+ wPoint->velocity += force * dt * wave_speed * wave_speed;
+ /* damping */
+ wPoint->velocity *= damp_factor;
+ /* and new height */
+ wPoint->height += wPoint->velocity * dt;
+
+ /* limit wave slope steepness */
+ if (wave_max_slope && avg_dist) {
+ const float max_offset = wave_max_slope * avg_dist;
+ const float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
+ if (offset > max_offset)
+ wPoint->height += offset - max_offset;
+ else if (offset < -max_offset)
+ wPoint->height += offset + max_offset;
+ }
+ }
+
+ if (data->reset_wave) {
+ /* if there wasn't any brush intersection, clear isect height */
+ if (wPoint->state == DPAINT_WAVE_NONE) {
+ wPoint->brush_isect = 0.0f;
+ }
+ wPoint->state = DPAINT_WAVE_NONE;
+ }
}
static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescale)
{
- PaintSurfaceData *sData = surface->data;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int index;
- int steps, ss;
- float dt, min_dist, damp_factor;
- const float wave_speed = surface->wave_speed;
- const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
- double average_dist = 0.0f;
- const float canvas_size = getSurfaceDimension(sData);
- const float wave_scale = CANVAS_REL_SIZE / canvas_size;
-
- /* allocate memory */
- PaintWavePoint *prevPoint = MEM_mallocN(
- sData->total_points * sizeof(PaintWavePoint), __func__);
- if (!prevPoint)
- return;
-
- /* calculate average neigh distance (single thread) */
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
-
- for (i = 0; i < numOfNeighs; i++) {
- average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
- }
- }
- average_dist *= (double)wave_scale / sData->adj_data->total_targets;
-
- /* determine number of required steps */
- steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
- (average_dist / (double)wave_speed / 3));
- CLAMP(steps, 1, 20);
- timescale /= steps;
-
- /* apply simulation values for final timescale */
- dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
- min_dist = wave_speed * dt * 1.5f;
- damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
-
- for (ss = 0; ss < steps; ss++) {
- /* copy previous frame data */
- memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
-
- DynamicPaintEffectData data = {
- .surface = surface, .prevPoint = prevPoint,
- .wave_speed = wave_speed, .wave_scale = wave_scale, .wave_max_slope = wave_max_slope,
- .dt = dt, .min_dist = min_dist, .damp_factor = damp_factor, .reset_wave = (ss == steps - 1),
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data, dynamic_paint_wave_step_cb,
- &settings);
- }
-
- MEM_freeN(prevPoint);
+ PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ int index;
+ int steps, ss;
+ float dt, min_dist, damp_factor;
+ const float wave_speed = surface->wave_speed;
+ const float wave_max_slope = (surface->wave_smoothness >= 0.01f) ?
+ (0.5f / surface->wave_smoothness) :
+ 0.0f;
+ double average_dist = 0.0f;
+ const float canvas_size = getSurfaceDimension(sData);
+ const float wave_scale = CANVAS_REL_SIZE / canvas_size;
+
+ /* allocate memory */
+ PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), __func__);
+ if (!prevPoint)
+ return;
+
+ /* calculate average neigh distance (single thread) */
+ for (index = 0; index < sData->total_points; index++) {
+ int i;
+ int numOfNeighs = sData->adj_data->n_num[index];
+
+ for (i = 0; i < numOfNeighs; i++) {
+ average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
+ }
+ }
+ average_dist *= (double)wave_scale / sData->adj_data->total_targets;
+
+ /* determine number of required steps */
+ steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
+ (average_dist / (double)wave_speed / 3));
+ CLAMP(steps, 1, 20);
+ timescale /= steps;
+
+ /* apply simulation values for final timescale */
+ dt = WAVE_TIME_FAC * timescale * surface->wave_timescale;
+ min_dist = wave_speed * dt * 1.5f;
+ damp_factor = pow((1.0f - surface->wave_damping), timescale * surface->wave_timescale);
+
+ for (ss = 0; ss < steps; ss++) {
+ /* copy previous frame data */
+ memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
+
+ DynamicPaintEffectData data = {
+ .surface = surface,
+ .prevPoint = prevPoint,
+ .wave_speed = wave_speed,
+ .wave_scale = wave_scale,
+ .wave_max_slope = wave_max_slope,
+ .dt = dt,
+ .min_dist = min_dist,
+ .damp_factor = damp_factor,
+ .reset_wave = (ss == steps - 1),
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_wave_step_cb, &settings);
+ }
+
+ MEM_freeN(prevPoint);
}
/* Do dissolve and fading effects */
static bool dynamic_paint_surface_needs_dry_dissolve(DynamicPaintSurface *surface)
{
- return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
- (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
- (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
- (surface->flags & MOD_DPAINT_DISSOLVE)));
+ return (((surface->type == MOD_DPAINT_SURFACE_T_PAINT) &&
+ (surface->flags & (MOD_DPAINT_USE_DRYING | MOD_DPAINT_DISSOLVE))) ||
+ (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WEIGHT) &&
+ (surface->flags & MOD_DPAINT_DISSOLVE)));
}
typedef struct DynamicPaintDissolveDryData {
- const DynamicPaintSurface *surface;
- const float timescale;
+ const DynamicPaintSurface *surface;
+ const float timescale;
} DynamicPaintDissolveDryData;
-static void dynamic_paint_surface_pre_step_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_surface_pre_step_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintDissolveDryData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const float timescale = data->timescale;
-
- /* Do drying dissolve effects */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- /* drying */
- if (surface->flags & MOD_DPAINT_USE_DRYING) {
- if (pPoint->wetness >= MIN_WETNESS) {
- int i;
- float dry_ratio, f_color[4];
- float p_wetness = pPoint->wetness;
-
- value_dissolve(&pPoint->wetness, surface->dry_speed, timescale,
- (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
- CLAMP_MIN(pPoint->wetness, 0.0f);
-
- if (pPoint->wetness < surface->color_dry_threshold) {
- dry_ratio = pPoint->wetness / p_wetness;
-
- /*
- * Slowly "shift" paint from wet layer to dry layer as it drys:
- */
- /* make sure alpha values are within proper range */
- CLAMP(pPoint->color[3], 0.0f, 1.0f);
- CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
-
- /* get current final blended color of these layers */
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- /* reduce wet layer alpha by dry factor */
- pPoint->e_color[3] *= dry_ratio;
-
- /* now calculate new alpha for dry layer that keeps final blended color unchanged */
- pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
- /* for each rgb component, calculate a new dry layer color that keeps the final blend color
- * with these new alpha values. (wet layer color doesn't change)*/
- if (pPoint->color[3]) {
- for (i = 0; i < 3; i++) {
- pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) /
- (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
- }
- }
- }
-
- pPoint->state = DPAINT_PAINT_WET;
- }
- /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
- else if (pPoint->state > 0) {
- float f_color[4];
- blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
- copy_v4_v4(pPoint->color, f_color);
- /* clear wet layer */
- pPoint->wetness = 0.0f;
- pPoint->e_color[3] = 0.0f;
- pPoint->state = DPAINT_PAINT_DRY;
- }
- }
-
- if (surface->flags & MOD_DPAINT_DISSOLVE) {
- value_dissolve(&pPoint->color[3], surface->diss_speed, timescale,
- (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
- CLAMP_MIN(pPoint->color[3], 0.0f);
-
- value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale,
- (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
- CLAMP_MIN(pPoint->e_color[3], 0.0f);
- }
- }
- /* dissolve for float types */
- else if (surface->flags & MOD_DPAINT_DISSOLVE &&
- (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT))
- {
- float *point = &((float *)sData->type_data)[index];
- /* log or linear */
- value_dissolve(point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
- CLAMP_MIN(*point, 0.0f);
- }
+ const DynamicPaintDissolveDryData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const float timescale = data->timescale;
+
+ /* Do drying dissolve effects */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
+ /* drying */
+ if (surface->flags & MOD_DPAINT_USE_DRYING) {
+ if (pPoint->wetness >= MIN_WETNESS) {
+ int i;
+ float dry_ratio, f_color[4];
+ float p_wetness = pPoint->wetness;
+
+ value_dissolve(&pPoint->wetness,
+ surface->dry_speed,
+ timescale,
+ (surface->flags & MOD_DPAINT_DRY_LOG) != 0);
+ CLAMP_MIN(pPoint->wetness, 0.0f);
+
+ if (pPoint->wetness < surface->color_dry_threshold) {
+ dry_ratio = pPoint->wetness / p_wetness;
+
+ /*
+ * Slowly "shift" paint from wet layer to dry layer as it drys:
+ */
+ /* make sure alpha values are within proper range */
+ CLAMP(pPoint->color[3], 0.0f, 1.0f);
+ CLAMP(pPoint->e_color[3], 0.0f, 1.0f);
+
+ /* get current final blended color of these layers */
+ blendColors(
+ pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ /* reduce wet layer alpha by dry factor */
+ pPoint->e_color[3] *= dry_ratio;
+
+ /* now calculate new alpha for dry layer that keeps final blended color unchanged */
+ pPoint->color[3] = (f_color[3] - pPoint->e_color[3]) / (1.0f - pPoint->e_color[3]);
+ /* for each rgb component, calculate a new dry layer color that keeps the final blend color
+ * with these new alpha values. (wet layer color doesn't change)*/
+ if (pPoint->color[3]) {
+ for (i = 0; i < 3; i++) {
+ pPoint->color[i] = (f_color[i] * f_color[3] -
+ pPoint->e_color[i] * pPoint->e_color[3]) /
+ (pPoint->color[3] * (1.0f - pPoint->e_color[3]));
+ }
+ }
+ }
+
+ pPoint->state = DPAINT_PAINT_WET;
+ }
+ /* in case of just dryed paint, just mix it to the dry layer and mark it empty */
+ else if (pPoint->state > 0) {
+ float f_color[4];
+ blendColors(pPoint->color, pPoint->color[3], pPoint->e_color, pPoint->e_color[3], f_color);
+ copy_v4_v4(pPoint->color, f_color);
+ /* clear wet layer */
+ pPoint->wetness = 0.0f;
+ pPoint->e_color[3] = 0.0f;
+ pPoint->state = DPAINT_PAINT_DRY;
+ }
+ }
+
+ if (surface->flags & MOD_DPAINT_DISSOLVE) {
+ value_dissolve(&pPoint->color[3],
+ surface->diss_speed,
+ timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->color[3], 0.0f);
+
+ value_dissolve(&pPoint->e_color[3],
+ surface->diss_speed,
+ timescale,
+ (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(pPoint->e_color[3], 0.0f);
+ }
+ }
+ /* dissolve for float types */
+ else if (surface->flags & MOD_DPAINT_DISSOLVE &&
+ (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
+ surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) {
+ float *point = &((float *)sData->type_data)[index];
+ /* log or linear */
+ value_dissolve(
+ point, surface->diss_speed, timescale, (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0);
+ CLAMP_MIN(*point, 0.0f);
+ }
}
static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *ob)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- MVert *mvert = mesh->mvert;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ MVert *mvert = mesh->mvert;
- int numOfVerts = mesh->totvert;
- int i;
+ int numOfVerts = mesh->totvert;
+ int i;
- if (!bData->prev_verts)
- return true;
+ if (!bData->prev_verts)
+ return true;
- /* matrix comparison */
- if (!equals_m4m4(bData->prev_obmat, ob->obmat))
- return true;
+ /* matrix comparison */
+ if (!equals_m4m4(bData->prev_obmat, ob->obmat))
+ return true;
- /* vertices */
- for (i = 0; i < numOfVerts; i++) {
- if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
- return true;
- }
- }
+ /* vertices */
+ for (i = 0; i < numOfVerts; i++) {
+ if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/* Prepare for surface step by creating PaintBakeNormal data */
typedef struct DynamicPaintGenerateBakeData {
- const DynamicPaintSurface *surface;
- Object *ob;
+ const DynamicPaintSurface *surface;
+ Object *ob;
- const MVert *mvert;
- const Vec3f *canvas_verts;
+ const MVert *mvert;
+ const Vec3f *canvas_verts;
- const bool do_velocity_data;
- const bool new_bdata;
+ const bool do_velocity_data;
+ const bool new_bdata;
} DynamicPaintGenerateBakeData;
-static void dynamic_paint_generate_bake_data_cb(
- void *__restrict userdata,
- const int index,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- const DynamicPaintGenerateBakeData *data = userdata;
-
- const DynamicPaintSurface *surface = data->surface;
- const PaintSurfaceData *sData = surface->data;
- const PaintAdjData *adj_data = sData->adj_data;
- const PaintBakeData *bData = sData->bData;
-
- Object *ob = data->ob;
-
- const MVert *mvert = data->mvert;
- const Vec3f *canvas_verts = data->canvas_verts;
-
- const bool do_velocity_data = data->do_velocity_data;
- const bool new_bdata = data->new_bdata;
-
- float prev_point[3] = {0.0f, 0.0f, 0.0f};
- float temp_nor[3];
-
- if (do_velocity_data && !new_bdata) {
- copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
- }
-
- /*
- * Calculate current 3D-position and normal of each surface point
- */
- if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- float n1[3], n2[3], n3[3];
- const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
-
- bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- bData->s_pos[index] = index * bData->s_num[index];
-
- /* per sample coordinates */
- for (int ss = 0; ss < bData->s_num[index]; ss++) {
- interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[tPoint->v1].v,
- canvas_verts[tPoint->v2].v,
- canvas_verts[tPoint->v3].v,
- f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
- }
-
- /* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
-
- interp_v3_v3v3v3(temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- normalize_v3(temp_nor);
- if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- float scaled_nor[3];
- mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
- bData->bNormal[index].normal_scale = len_v3(scaled_nor);
- }
- mul_mat3_m4_v3(ob->obmat, temp_nor);
- normalize_v3(temp_nor);
- negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
- }
- else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- int ss;
- if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
- bData->s_num[index] = adj_data->n_num[index] + 1;
- bData->s_pos[index] = adj_data->n_index[index] + index;
- }
- else {
- bData->s_num[index] = 1;
- bData->s_pos[index] = index;
- }
-
- /* calculate position for each sample */
- for (ss = 0; ss < bData->s_num[index]; ss++) {
- /* first sample is always point center */
- copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
- if (ss > 0) {
- int t_index = adj_data->n_index[index] + (ss - 1);
- /* get vertex position at 1/3 of each neigh edge */
- mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
- madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
- canvas_verts[adj_data->n_target[t_index]].v, 1.0f / 3.0f);
- }
- }
-
- /* normal */
- normal_short_to_float_v3(temp_nor, mvert[index].no);
- if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- float scaled_nor[3];
- mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
- bData->bNormal[index].normal_scale = len_v3(scaled_nor);
- }
- mul_mat3_m4_v3(ob->obmat, temp_nor);
- normalize_v3(temp_nor);
- negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
- }
-
- /* calculate speed vector */
- if (do_velocity_data && !new_bdata && !bData->clear) {
- sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
- }
+ const DynamicPaintGenerateBakeData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintAdjData *adj_data = sData->adj_data;
+ const PaintBakeData *bData = sData->bData;
+
+ Object *ob = data->ob;
+
+ const MVert *mvert = data->mvert;
+ const Vec3f *canvas_verts = data->canvas_verts;
+
+ const bool do_velocity_data = data->do_velocity_data;
+ const bool new_bdata = data->new_bdata;
+
+ float prev_point[3] = {0.0f, 0.0f, 0.0f};
+ float temp_nor[3];
+
+ if (do_velocity_data && !new_bdata) {
+ copy_v3_v3(prev_point, bData->realCoord[bData->s_pos[index]].v);
+ }
+
+ /*
+ * Calculate current 3D-position and normal of each surface point
+ */
+ if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
+ float n1[3], n2[3], n3[3];
+ const ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
+ const PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
+
+ bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
+ bData->s_pos[index] = index * bData->s_num[index];
+
+ /* per sample coordinates */
+ for (int ss = 0; ss < bData->s_num[index]; ss++) {
+ interp_v3_v3v3v3(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[tPoint->v1].v,
+ canvas_verts[tPoint->v2].v,
+ canvas_verts[tPoint->v3].v,
+ f_data->barycentricWeights[index * bData->s_num[index] + ss].v);
+ }
+
+ /* Calculate current pixel surface normal */
+ normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
+ normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
+ normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
+
+ interp_v3_v3v3v3(
+ temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
+ normalize_v3(temp_nor);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+ else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
+ int ss;
+ if (surface->flags & MOD_DPAINT_ANTIALIAS && adj_data) {
+ bData->s_num[index] = adj_data->n_num[index] + 1;
+ bData->s_pos[index] = adj_data->n_index[index] + index;
+ }
+ else {
+ bData->s_num[index] = 1;
+ bData->s_pos[index] = index;
+ }
+
+ /* calculate position for each sample */
+ for (ss = 0; ss < bData->s_num[index]; ss++) {
+ /* first sample is always point center */
+ copy_v3_v3(bData->realCoord[bData->s_pos[index] + ss].v, canvas_verts[index].v);
+ if (ss > 0) {
+ int t_index = adj_data->n_index[index] + (ss - 1);
+ /* get vertex position at 1/3 of each neigh edge */
+ mul_v3_fl(bData->realCoord[bData->s_pos[index] + ss].v, 2.0f / 3.0f);
+ madd_v3_v3fl(bData->realCoord[bData->s_pos[index] + ss].v,
+ canvas_verts[adj_data->n_target[t_index]].v,
+ 1.0f / 3.0f);
+ }
+ }
+
+ /* normal */
+ normal_short_to_float_v3(temp_nor, mvert[index].no);
+ if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
+ /* Prepare surface normal directional scale to easily convert
+ * brush intersection amount between global and local space */
+ float scaled_nor[3];
+ mul_v3_v3v3(scaled_nor, temp_nor, ob->scale);
+ bData->bNormal[index].normal_scale = len_v3(scaled_nor);
+ }
+ mul_mat3_m4_v3(ob->obmat, temp_nor);
+ normalize_v3(temp_nor);
+ negate_v3_v3(bData->bNormal[index].invNorm, temp_nor);
+ }
+
+ /* calculate speed vector */
+ if (do_velocity_data && !new_bdata && !bData->clear) {
+ sub_v3_v3v3(bData->velocity[index].v, bData->realCoord[bData->s_pos[index]].v, prev_point);
+ }
}
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
+ Depsgraph *depsgraph,
+ Object *ob)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
- int index;
- bool new_bdata = false;
- const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
- (surface_getBrushFlags(surface, depsgraph) & BRUSH_USES_VELOCITY));
- const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
-
- int canvasNumOfVerts = mesh->totvert;
- MVert *mvert = mesh->mvert;
- Vec3f *canvas_verts;
-
- if (bData) {
- const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
-
- /* get previous speed for accelertaion */
- if (do_accel_data && bData->prev_velocity && bData->velocity)
- memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
-
- /* reset speed vectors */
- if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved))
- memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
-
- /* if previous data exists and mesh hasn't moved, no need to recalc */
- if (!surface_moved)
- return 1;
- }
-
- canvas_verts = (struct Vec3f *) MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f), "Dynamic Paint transformed canvas verts");
- if (!canvas_verts)
- return 0;
-
- /* allocate memory if required */
- if (!bData) {
- sData->bData = bData = (struct PaintBakeData *) MEM_callocN(sizeof(struct PaintBakeData), "Dynamic Paint bake data");
- if (!bData) {
- if (canvas_verts)
- MEM_freeN(canvas_verts);
- return 0;
- }
-
- /* Init bdata */
- bData->bNormal = (struct PaintBakeNormal *) MEM_mallocN(sData->total_points * sizeof(struct PaintBakeNormal), "Dynamic Paint step data");
- bData->s_pos = MEM_mallocN(sData->total_points * sizeof(unsigned int), "Dynamic Paint bData s_pos");
- bData->s_num = MEM_mallocN(sData->total_points * sizeof(unsigned int), "Dynamic Paint bData s_num");
- bData->realCoord = (struct Vec3f *) MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f), "Dynamic Paint point coords");
- bData->prev_verts = MEM_mallocN(canvasNumOfVerts * sizeof(MVert), "Dynamic Paint bData prev_verts");
-
- /* if any allocation failed, free everything */
- if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
- if (bData->bNormal)
- MEM_freeN(bData->bNormal);
- if (bData->s_pos)
- MEM_freeN(bData->s_pos);
- if (bData->s_num)
- MEM_freeN(bData->s_num);
- if (bData->realCoord)
- MEM_freeN(bData->realCoord);
- if (canvas_verts)
- MEM_freeN(canvas_verts);
-
- return setError(surface->canvas, N_("Not enough free memory"));
- }
-
- new_bdata = true;
- }
-
- if (do_velocity_data && !bData->velocity) {
- bData->velocity = (struct Vec3f *) MEM_callocN(sData->total_points * sizeof(Vec3f), "Dynamic Paint velocity");
- }
- if (do_accel_data && !bData->prev_velocity) {
- bData->prev_velocity = (struct Vec3f *) MEM_mallocN(sData->total_points * sizeof(Vec3f), "Dynamic Paint prev velocity");
- /* copy previous vel */
- if (bData->prev_velocity && bData->velocity)
- memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
- }
-
- /*
- * Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
- */
- bData->mesh_bounds.valid = false;
- for (index = 0; index < canvasNumOfVerts; index++) {
- copy_v3_v3(canvas_verts[index].v, mvert[index].co);
- mul_m4_v3(ob->obmat, canvas_verts[index].v);
- boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
- }
-
- /*
- * Prepare each surface point for a new step
- */
- DynamicPaintGenerateBakeData data = {
- .surface = surface, .ob = ob,
- .mvert = mvert, .canvas_verts = canvas_verts,
- .do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_generate_bake_data_cb,
- &settings);
-
- MEM_freeN(canvas_verts);
-
- /* generate surface space partitioning grid */
- surfaceGenerateGrid(surface);
- /* calculate current frame adjacency point distances and global dirs */
- dynamicPaint_prepareAdjacencyData(surface, false);
-
- /* Copy current frame vertices to check against in next frame */
- copy_m4_m4(bData->prev_obmat, ob->obmat);
- memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
-
- bData->clear = 0;
-
- return 1;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ Mesh *mesh = dynamicPaint_canvas_mesh_get(surface->canvas);
+ int index;
+ bool new_bdata = false;
+ const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
+ (surface_getBrushFlags(surface, depsgraph) &
+ BRUSH_USES_VELOCITY));
+ const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
+
+ int canvasNumOfVerts = mesh->totvert;
+ MVert *mvert = mesh->mvert;
+ Vec3f *canvas_verts;
+
+ if (bData) {
+ const bool surface_moved = dynamicPaint_surfaceHasMoved(surface, ob);
+
+ /* get previous speed for accelertaion */
+ if (do_accel_data && bData->prev_velocity && bData->velocity)
+ memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
+
+ /* reset speed vectors */
+ if (do_velocity_data && bData->velocity && (bData->clear || !surface_moved))
+ memset(bData->velocity, 0, sData->total_points * sizeof(Vec3f));
+
+ /* if previous data exists and mesh hasn't moved, no need to recalc */
+ if (!surface_moved)
+ return 1;
+ }
+
+ canvas_verts = (struct Vec3f *)MEM_mallocN(canvasNumOfVerts * sizeof(struct Vec3f),
+ "Dynamic Paint transformed canvas verts");
+ if (!canvas_verts)
+ return 0;
+
+ /* allocate memory if required */
+ if (!bData) {
+ sData->bData = bData = (struct PaintBakeData *)MEM_callocN(sizeof(struct PaintBakeData),
+ "Dynamic Paint bake data");
+ if (!bData) {
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
+ return 0;
+ }
+
+ /* Init bdata */
+ bData->bNormal = (struct PaintBakeNormal *)MEM_mallocN(
+ sData->total_points * sizeof(struct PaintBakeNormal), "Dynamic Paint step data");
+ bData->s_pos = MEM_mallocN(sData->total_points * sizeof(unsigned int),
+ "Dynamic Paint bData s_pos");
+ bData->s_num = MEM_mallocN(sData->total_points * sizeof(unsigned int),
+ "Dynamic Paint bData s_num");
+ bData->realCoord = (struct Vec3f *)MEM_mallocN(surface_totalSamples(surface) * sizeof(Vec3f),
+ "Dynamic Paint point coords");
+ bData->prev_verts = MEM_mallocN(canvasNumOfVerts * sizeof(MVert),
+ "Dynamic Paint bData prev_verts");
+
+ /* if any allocation failed, free everything */
+ if (!bData->bNormal || !bData->s_pos || !bData->s_num || !bData->realCoord || !canvas_verts) {
+ if (bData->bNormal)
+ MEM_freeN(bData->bNormal);
+ if (bData->s_pos)
+ MEM_freeN(bData->s_pos);
+ if (bData->s_num)
+ MEM_freeN(bData->s_num);
+ if (bData->realCoord)
+ MEM_freeN(bData->realCoord);
+ if (canvas_verts)
+ MEM_freeN(canvas_verts);
+
+ return setError(surface->canvas, N_("Not enough free memory"));
+ }
+
+ new_bdata = true;
+ }
+
+ if (do_velocity_data && !bData->velocity) {
+ bData->velocity = (struct Vec3f *)MEM_callocN(sData->total_points * sizeof(Vec3f),
+ "Dynamic Paint velocity");
+ }
+ if (do_accel_data && !bData->prev_velocity) {
+ bData->prev_velocity = (struct Vec3f *)MEM_mallocN(sData->total_points * sizeof(Vec3f),
+ "Dynamic Paint prev velocity");
+ /* copy previous vel */
+ if (bData->prev_velocity && bData->velocity)
+ memcpy(bData->prev_velocity, bData->velocity, sData->total_points * sizeof(Vec3f));
+ }
+
+ /*
+ * Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
+ */
+ bData->mesh_bounds.valid = false;
+ for (index = 0; index < canvasNumOfVerts; index++) {
+ copy_v3_v3(canvas_verts[index].v, mvert[index].co);
+ mul_m4_v3(ob->obmat, canvas_verts[index].v);
+ boundInsert(&bData->mesh_bounds, canvas_verts[index].v);
+ }
+
+ /*
+ * Prepare each surface point for a new step
+ */
+ DynamicPaintGenerateBakeData data = {
+ .surface = surface,
+ .ob = ob,
+ .mvert = mvert,
+ .canvas_verts = canvas_verts,
+ .do_velocity_data = do_velocity_data,
+ .new_bdata = new_bdata,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, &settings);
+
+ MEM_freeN(canvas_verts);
+
+ /* generate surface space partitioning grid */
+ surfaceGenerateGrid(surface);
+ /* calculate current frame adjacency point distances and global dirs */
+ dynamicPaint_prepareAdjacencyData(surface, false);
+
+ /* Copy current frame vertices to check against in next frame */
+ copy_m4_m4(bData->prev_obmat, ob->obmat);
+ memcpy(bData->prev_verts, mvert, canvasNumOfVerts * sizeof(MVert));
+
+ bData->clear = 0;
+
+ return 1;
}
/*
* Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
*/
-static int dynamicPaint_doStep(
- Depsgraph *depsgraph, Scene *scene,
- Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
+static int dynamicPaint_doStep(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ DynamicPaintSurface *surface,
+ float timescale,
+ float subframe)
{
- PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
- DynamicPaintCanvasSettings *canvas = surface->canvas;
- const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
- int ret = 1;
-
- if (sData->total_points < 1)
- return 0;
-
- if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
- DynamicPaintDissolveDryData data = { .surface = surface, .timescale = timescale, };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (sData->total_points > 1000);
- BLI_task_parallel_range(0, sData->total_points,
- &data,
- dynamic_paint_surface_pre_step_cb,
- &settings);
- }
-
- /*
- * Loop through surface's target paint objects and do painting
- */
- {
- unsigned int numobjects;
- Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
-
- /* backup current scene frame */
- int scene_frame = scene->r.cfra;
- float scene_subframe = scene->r.subframe;
-
- for (int i = 0; i < numobjects; i++) {
- Object *brushObj = objects[i];
-
- /* check if target has an active dp modifier */
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
- if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
- DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
- /* make sure we're dealing with a brush */
- if (pmd2->brush) {
- DynamicPaintBrushSettings *brush = pmd2->brush;
-
- /* calculate brush speed vectors if required */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
- bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4, "Dynamic Paint brush velocity");
- /* init adjacency data if not already */
- if (!sData->adj_data)
- dynamicPaint_initAdjacencyData(surface, true);
- if (!bData->bNeighs)
- dynamicPaint_prepareAdjacencyData(surface, true);
- }
-
- /* update object data on this subframe */
- if (subframe) {
- scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- }
-
-
- /* Apply brush on the surface depending on it's collision type */
- if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys, for_render))
- {
- /* Paint a particle system */
- dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
- }
- /* Object center distance: */
- if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
- dynamicPaint_paintSinglePoint(depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
- }
- /* Mesh volume/proximity: */
- else if (brushObj != ob) {
- dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
- }
-
- /* reset object to it's original state */
- if (subframe) {
- scene->r.cfra = scene_frame;
- scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
- BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- }
-
- /* process special brush effects, like smudge */
- if (bData->brush_velocity) {
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE)
- dynamicPaint_doSmudge(surface, brush, timescale);
- MEM_freeN(bData->brush_velocity);
- bData->brush_velocity = NULL;
- }
- }
- }
- }
-
- BKE_collision_objects_free(objects);
- }
-
- /* surfaces operations that use adjacency data */
- if (sData->adj_data && bData->bNeighs) {
- /* wave type surface simulation step */
- if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- dynamicPaint_doWaveStep(surface, timescale);
- }
-
- /* paint surface effects */
- if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- int steps = 1, s;
- PaintPoint *prevPoint;
- float *force = NULL;
-
- /* Allocate memory for surface previous points to read unchanged values from */
- prevPoint = MEM_mallocN(sData->total_points * sizeof(struct PaintPoint), "PaintSurfaceDataCopy");
- if (!prevPoint)
- return setError(canvas, N_("Not enough free memory"));
-
- /* Prepare effects and get number of required steps */
- steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
- for (s = 0; s < steps; s++) {
- dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
- }
-
- /* Free temporary effect data */
- if (prevPoint)
- MEM_freeN(prevPoint);
- if (force)
- MEM_freeN(force);
- }
-
- /* paint island border pixels */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- dynamicPaint_doBorderStep(surface);
- }
- }
-
- return ret;
+ PaintSurfaceData *sData = surface->data;
+ PaintBakeData *bData = sData->bData;
+ DynamicPaintCanvasSettings *canvas = surface->canvas;
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ int ret = 1;
+
+ if (sData->total_points < 1)
+ return 0;
+
+ if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
+ DynamicPaintDissolveDryData data = {
+ .surface = surface,
+ .timescale = timescale,
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (sData->total_points > 1000);
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_surface_pre_step_cb, &settings);
+ }
+
+ /*
+ * Loop through surface's target paint objects and do painting
+ */
+ {
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
+
+ /* backup current scene frame */
+ int scene_frame = scene->r.cfra;
+ float scene_subframe = scene->r.subframe;
+
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
+
+ /* check if target has an active dp modifier */
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
+ DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
+ /* make sure we're dealing with a brush */
+ if (pmd2->brush) {
+ DynamicPaintBrushSettings *brush = pmd2->brush;
+
+ /* calculate brush speed vectors if required */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
+ bData->brush_velocity = MEM_callocN(sData->total_points * sizeof(float) * 4,
+ "Dynamic Paint brush velocity");
+ /* init adjacency data if not already */
+ if (!sData->adj_data)
+ dynamicPaint_initAdjacencyData(surface, true);
+ if (!bData->bNeighs)
+ dynamicPaint_prepareAdjacencyData(surface, true);
+ }
+
+ /* update object data on this subframe */
+ if (subframe) {
+ scene_setSubframe(scene, subframe);
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ brushObj,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ }
+
+ /* Apply brush on the surface depending on it's collision type */
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ psys_check_enabled(brushObj, brush->psys, for_render)) {
+ /* Paint a particle system */
+ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
+ }
+ /* Object center distance: */
+ if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
+ dynamicPaint_paintSinglePoint(
+ depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
+ }
+ /* Mesh volume/proximity: */
+ else if (brushObj != ob) {
+ dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
+ }
+
+ /* reset object to it's original state */
+ if (subframe) {
+ scene->r.cfra = scene_frame;
+ scene->r.subframe = scene_subframe;
+ BKE_object_modifier_update_subframe(depsgraph,
+ scene,
+ brushObj,
+ true,
+ SUBFRAME_RECURSION,
+ BKE_scene_frame_get(scene),
+ eModifierType_DynamicPaint);
+ }
+
+ /* process special brush effects, like smudge */
+ if (bData->brush_velocity) {
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE)
+ dynamicPaint_doSmudge(surface, brush, timescale);
+ MEM_freeN(bData->brush_velocity);
+ bData->brush_velocity = NULL;
+ }
+ }
+ }
+ }
+
+ BKE_collision_objects_free(objects);
+ }
+
+ /* surfaces operations that use adjacency data */
+ if (sData->adj_data && bData->bNeighs) {
+ /* wave type surface simulation step */
+ if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
+ dynamicPaint_doWaveStep(surface, timescale);
+ }
+
+ /* paint surface effects */
+ if (surface->effect && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ int steps = 1, s;
+ PaintPoint *prevPoint;
+ float *force = NULL;
+
+ /* Allocate memory for surface previous points to read unchanged values from */
+ prevPoint = MEM_mallocN(sData->total_points * sizeof(struct PaintPoint),
+ "PaintSurfaceDataCopy");
+ if (!prevPoint)
+ return setError(canvas, N_("Not enough free memory"));
+
+ /* Prepare effects and get number of required steps */
+ steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
+ for (s = 0; s < steps; s++) {
+ dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
+ }
+
+ /* Free temporary effect data */
+ if (prevPoint)
+ MEM_freeN(prevPoint);
+ if (force)
+ MEM_freeN(force);
+ }
+
+ /* paint island border pixels */
+ if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
+ dynamicPaint_doBorderStep(surface);
+ }
+ }
+
+ return ret;
}
/*
* Calculate a single frame and included subframes for surface
*/
-int dynamicPaint_calculateFrame(
- DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
- Scene *scene, Object *cObject, int frame)
+int dynamicPaint_calculateFrame(DynamicPaintSurface *surface,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *cObject,
+ int frame)
{
- float timescale = 1.0f;
+ float timescale = 1.0f;
- /* apply previous displace on derivedmesh if incremental surface */
- if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
- dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas));
- }
+ /* apply previous displace on derivedmesh if incremental surface */
+ if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL) {
+ dynamicPaint_applySurfaceDisplace(surface, dynamicPaint_canvas_mesh_get(surface->canvas));
+ }
- /* update bake data */
- dynamicPaint_generateBakeData(surface, depsgraph, cObject);
+ /* update bake data */
+ dynamicPaint_generateBakeData(surface, depsgraph, cObject);
- /* don't do substeps for first frame */
- if (surface->substeps && (frame != surface->start_frame)) {
- int st;
- timescale = 1.0f / (surface->substeps + 1);
+ /* don't do substeps for first frame */
+ if (surface->substeps && (frame != surface->start_frame)) {
+ int st;
+ timescale = 1.0f / (surface->substeps + 1);
- for (st = 1; st <= surface->substeps; st++) {
- float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
- return 0;
- }
- }
+ for (st = 1; st <= surface->substeps; st++) {
+ float subframe = ((float)st) / (surface->substeps + 1);
+ if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
+ return 0;
+ }
+ }
- return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
+ return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
}