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:
authorLukas Tönne <lukas.toenne@gmail.com>2016-05-27 17:01:49 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-05-27 17:01:49 +0300
commitd8aaed17eb889c7acab08c89a8efd42fb5f9716d (patch)
tree4a77d67d7623546e3cdfb5cb5be64e9e4c9d65bb /source/blender/blenkernel
parente6777be1d11e8f23fb54b64cf59ad7fe084ce7c8 (diff)
parent3d86a5bc72a63b1ef8b165d68a1806d0abf0a8ac (diff)
Merge branch 'master' into object_nodes
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_action.h9
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_customdata.h4
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h5
-rw-r--r--source/blender/blenkernel/BKE_modifier.h3
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c83
-rw-r--r--source/blender/blenkernel/intern/action.c86
-rw-r--r--source/blender/blenkernel/intern/armature.c175
-rw-r--r--source/blender/blenkernel/intern/armature_update.c6
-rw-r--r--source/blender/blenkernel/intern/camera.c2
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c21
-rw-r--r--source/blender/blenkernel/intern/colortools.c301
-rw-r--r--source/blender/blenkernel/intern/constraint.c62
-rw-r--r--source/blender/blenkernel/intern/customdata.c54
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c4240
-rw-r--r--source/blender/blenkernel/intern/image.c30
-rw-r--r--source/blender/blenkernel/intern/lattice.c1
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c45
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c4
-rw-r--r--source/blender/blenkernel/intern/object.c5
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/blenkernel/intern/scene.c2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c23
24 files changed, 3076 insertions, 2092 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index c164cd542f3..cb282b46bec 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -79,12 +79,15 @@ typedef enum eAction_TransformFlags {
ACT_TRANS_ROT = (1 << 1),
/* scaling */
ACT_TRANS_SCALE = (1 << 2),
-
+
+ /* bbone shape - for all the parameters, provided one is set */
+ ACT_TRANS_BBONE = (1 << 3),
+
/* strictly not a transform, but custom properties are also
* quite often used in modern rigs
*/
- ACT_TRANS_PROP = (1 << 3),
-
+ ACT_TRANS_PROP = (1 << 4),
+
/* all flags */
ACT_TRANS_ONLY = (ACT_TRANS_LOC | ACT_TRANS_ROT | ACT_TRANS_SCALE),
ACT_TRANS_ALL = (ACT_TRANS_ONLY | ACT_TRANS_PROP)
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 6d00110e318..cc082c084ce 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -135,6 +135,7 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
+void equalize_bbone_bezier(float *data, int desired);
void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
/* like EBONE_VISIBLE */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 17ad51a7a16..2cdda34b9b5 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -244,7 +244,7 @@ void CustomData_free_elem(struct CustomData *data, int index, int count);
*/
void CustomData_interp(
const struct CustomData *source, struct CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index);
void CustomData_bmesh_interp_n(
struct CustomData *data, const void **src_blocks, const float *weights,
@@ -358,7 +358,7 @@ void CustomData_file_write_prepare(
struct CustomDataLayer **r_write_layers, struct CustomDataLayer *write_layers_buff, size_t write_layers_size);
/* query info over types */
-void CustomData_file_write_info(int type, const char **structname, int *structnum);
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num);
int CustomData_sizeof(int type);
/* get the name of a layer type */
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 00256176d98..5abb53d4c52 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -82,7 +82,7 @@ void dynamicPaint_resetPreview(struct DynamicPaintCanvasSettings *canvas);
struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings *canvas);
/* image sequence baking */
-int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface);
+int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update);
int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface, struct Scene *scene, struct Object *cObject, int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer);
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index d7dd9ed3ac5..dff79b6cc22 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -114,6 +114,11 @@ void BKE_mesh_vert_loop_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MPoly *mface, const struct MLoop *mloop,
int totvert, int totface, int totloop);
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MVert *mvert, const int totvert,
+ const struct MLoopTri *mlooptri, const int totlooptri,
+ const struct MLoop *mloop, const int totloop);
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 455912ab819..f6c08909d23 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -101,7 +101,8 @@ typedef enum {
eModifierTypeFlag_NoUserAdd = (1 << 8),
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
- eModifierTypeFlag_UsesPreview = (1 << 9)
+ eModifierTypeFlag_UsesPreview = (1 << 9),
+ eModifierTypeFlag_AcceptsLattice = (1 << 10),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 745bb8967f3..195b5e75352 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -3333,17 +3333,18 @@ void DM_calc_loop_tangents_step_0(
bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
/* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
*ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
ract_uv_name[0] = 0;
if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
}
/* Active tangent in render */
*rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
rren_uv_name[0] = 0;
if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
}
/* If active tangent not in tangent_names we take it into account */
@@ -3693,12 +3694,41 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
for (b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_MTFACE) {
+ int type = gattribs->layer[b].type;
+ layer = -1;
+ if (type == CD_AUTO_FROM_NAME) {
+ /* We need to deduct what exact layer is used.
+ *
+ * We do it based on the specified name.
+ */
+ if (gattribs->layer[b].name[0]) {
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ type = CD_TANGENT;
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ type = CD_MCOL;
+ }
+ if (layer == -1) {
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ type = CD_MTFACE;
+ }
+ if (layer == -1) {
+ continue;
+ }
+ }
+ else {
+ /* Fall back to the UV layer, which matches old behavior. */
+ type = CD_MTFACE;
+ }
+ }
+ if (type == CD_MTFACE) {
/* uv coordinates */
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+ }
a = attribs->tottface++;
@@ -3714,11 +3744,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tface[a].gl_index = gattribs->layer[b].glindex;
attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
}
- else if (gattribs->layer[b].type == CD_MCOL) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ else if (type == CD_MCOL) {
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
+ }
a = attribs->totmcol++;
@@ -3734,13 +3766,14 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
}
- else if (gattribs->layer[b].type == CD_TANGENT) {
+ else if (type == CD_TANGENT) {
/* note, even with 'is_editmesh' this uses the derived-meshes loop data */
-
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ if (layer == -1) {
+ if (gattribs->layer[b].name[0])
+ layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+ else
+ layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+ }
a = attribs->tottang++;
@@ -3755,9 +3788,11 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
attribs->tang[a].gl_index = gattribs->layer[b].glindex;
}
- else if (gattribs->layer[b].type == CD_ORCO) {
+ else if (type == CD_ORCO) {
/* original coordinates */
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ if (layer == -1) {
+ layer = CustomData_get_layer_index(vdata, CD_ORCO);
+ }
attribs->totorco = 1;
if (layer != -1) {
@@ -3821,17 +3856,17 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
/* vertex colors */
for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
+ GLfloat col[4];
if (attribs->mcol[b].array) {
const MLoopCol *cp = &attribs->mcol[b].array[loop];
- copy_v4_v4_uchar(col, &cp->r);
+ rgba_uchar_to_float(col, &cp->r);
}
else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ zero_v4(col);
}
- glVertexAttrib4ubv(attribs->mcol[b].gl_index, col);
+ glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
}
/* tangent for normal mapping */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index b969c9ec787..df9b9683687 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -493,6 +493,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
+ chan->scaleIn = chan->scaleOut = 1.0f;
+
chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f;
chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f;
chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f;
@@ -596,7 +598,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
outPose = MEM_callocN(sizeof(bPose), "pose");
BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
-
+
+ /* Rebuild ghash here too, so that name lookups below won't be too bad...
+ * BUT this will have the penalty that the ghash will be built twice
+ * if BKE_pose_rebuild() gets called after this...
+ */
+ if (outPose->chanbase.first != outPose->chanbase.last) {
+ outPose->chanhash = NULL;
+ BKE_pose_channels_hash_make(outPose);
+ }
+
outPose->iksolver = src->iksolver;
outPose->ikdata = NULL;
outPose->ikparam = MEM_dupallocN(src->ikparam);
@@ -608,10 +619,16 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints)
id_us_plus(&pchan->custom->id);
}
- /* warning, O(n2) here, but it's a rarely used feature. */
+ /* warning, O(n2) here, if done without the hash, but these are rarely used features. */
if (pchan->custom_tx) {
pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name);
}
+ if (pchan->bbone_prev) {
+ pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name);
+ }
+ if (pchan->bbone_next) {
+ pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name);
+ }
if (copy_constraints) {
BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb
@@ -726,7 +743,7 @@ void BKE_pose_channels_remove(
Object *ob,
bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
{
- /* First erase any associated pose channel */
+ /* Erase any associated pose channel, along with any references to them */
if (ob->pose) {
bPoseChannel *pchan, *pchan_next;
bConstraint *con;
@@ -735,6 +752,7 @@ void BKE_pose_channels_remove(
pchan_next = pchan->next;
if (filter_fn(pchan->name, user_data)) {
+ /* Bone itself is being removed */
BKE_pose_channel_free(pchan);
if (ob->pose->chanhash) {
BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
@@ -742,6 +760,7 @@ void BKE_pose_channels_remove(
BLI_freelinkN(&ob->pose->chanbase, pchan);
}
else {
+ /* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -765,6 +784,20 @@ void BKE_pose_channels_remove(
cti->flush_constraint_targets(con, &targets, 0);
}
}
+
+ if (pchan->bbone_prev) {
+ if (filter_fn(pchan->bbone_prev->name, user_data))
+ pchan->bbone_prev = NULL;
+ }
+ if (pchan->bbone_next) {
+ if (filter_fn(pchan->bbone_next->name, user_data))
+ pchan->bbone_next = NULL;
+ }
+
+ if (pchan->custom_tx) {
+ if (filter_fn(pchan->custom_tx->name, user_data))
+ pchan->custom_tx = NULL;
+ }
}
}
}
@@ -878,6 +911,15 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
pchan->flag = chan->flag;
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->curveInX = chan->curveInX;
+ pchan->curveInY = chan->curveInY;
+ pchan->curveOutX = chan->curveOutX;
+ pchan->curveOutY = chan->curveOutY;
+ pchan->scaleIn = chan->scaleIn;
+ pchan->scaleOut = chan->scaleOut;
+
con = chan->constraints.first;
for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
pcon->enforce = con->enforce;
@@ -888,7 +930,7 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
- * (unlike copy_pose_channel_data which only).
+ * (unlike copy_pose_channel_data which only does posing-related stuff).
*
* \note use when copying bones in editmode (on returned value from #BKE_pose_channel_verify)
*/
@@ -911,6 +953,11 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->ikstretch = pchan_from->ikstretch;
pchan->ikrotweight = pchan_from->ikrotweight;
pchan->iklinweight = pchan_from->iklinweight;
+
+ /* bbone settings (typically not animated) */
+ pchan->bboneflag = pchan_from->bboneflag;
+ pchan->bbone_next = pchan_from->bbone_next;
+ pchan->bbone_prev = pchan_from->bbone_prev;
/* constraints */
BKE_constraints_copy(&pchan->constraints, &pchan_from->constraints, true);
@@ -1280,6 +1327,18 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
}
}
+ if ((curves) || (flags & ACT_TRANS_BBONE) == 0) {
+ /* bbone shape properties */
+ pPtr = strstr(bPtr, "bbone_");
+ if (pPtr) {
+ flags |= ACT_TRANS_BBONE;
+
+ if (curves)
+ BLI_addtail(curves, BLI_genericNodeN(fcu));
+ continue;
+ }
+ }
+
if ((curves) || (flags & ACT_TRANS_PROP) == 0) {
/* custom properties only */
pPtr = strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */
@@ -1339,8 +1398,13 @@ void BKE_pose_rest(bPose *pose)
unit_qt(pchan->quat);
unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE);
+
+ pchan->roll1 = pchan->roll2 = 0.0f;
+ pchan->curveInX = pchan->curveInY = 0.0f;
+ pchan->curveOutX = pchan->curveOutY = 0.0f;
+ pchan->scaleIn = pchan->scaleOut = 1.0f;
+
+ pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
}
}
@@ -1375,9 +1439,19 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
pchanto->rotmode = pchanfrom->rotmode;
pchanto->flag = pchanfrom->flag;
pchanto->protectflag = pchanfrom->protectflag;
+ pchanto->bboneflag = pchanfrom->bboneflag;
}
}
return true;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 1a3afbb876e..04b4733fd44 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -429,7 +429,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-static void equalize_bezier(float *data, int desired)
+void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -475,7 +475,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1 = 0.0f, roll2;
+ float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
float data[MAX_BBONE_SUBDIV + 1][4], *fp;
int a;
@@ -496,16 +496,21 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
- hlength1 = bone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */
- hlength2 = bone->ease2 * length * 0.390464f;
-
- /* evaluate next and prev bones */
- if (bone->flag & BONE_CONNECTED)
- prev = pchan->parent;
- else
- prev = NULL;
+ /* get "next" and "prev" bones - these are used for handle calculations */
+ if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
+ /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
+ prev = pchan->bbone_prev;
+ next = pchan->bbone_next;
+ }
+ else {
+ /* evaluate next and prev bones */
+ if (bone->flag & BONE_CONNECTED)
+ prev = pchan->parent;
+ else
+ prev = NULL;
- next = pchan->child;
+ next = pchan->child;
+ }
/* find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
@@ -525,10 +530,27 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
float difmat[4][4], result[3][3], imat3[3][3];
/* transform previous point inside this bone space */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ if (rest) {
+ /* in restpose, arm_head == pose_head */
+ h1[0] = h1[1] = h1[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
+ }
+ else {
+ /* Use bone head as absolute position */
+ if (rest)
+ copy_v3_v3(h1, prev->bone->arm_head);
+ else
+ copy_v3_v3(h1, prev->pose_head);
+ }
mul_m4_v3(imat, h1);
if (prev->bone->segments > 1) {
@@ -538,7 +560,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
normalize_v3(h1);
- mul_v3_fl(h1, -hlength1);
+ negate_v3(h1);
if (prev->bone->segments == 1) {
/* find the previous roll to interpolate */
@@ -557,17 +579,34 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
}
}
else {
- h1[0] = 0.0f; h1[1] = hlength1; h1[2] = 0.0f;
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
roll1 = 0.0f;
}
if (next) {
float difmat[4][4], result[3][3], imat3[3][3];
/* transform next point inside this bone space */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
+ if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
+ (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
+ {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
+ if (rest) {
+ /* in restpose, arm_tail == pose_tail */
+ h2[0] = h2[1] = h2[2] = 0.0f;
+ }
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else {
+ /* Use bone tail as absolute position */
+ if (rest)
+ copy_v3_v3(h2, next->bone->arm_tail);
+ else
+ copy_v3_v3(h2, next->pose_tail);
+ }
mul_m4_v3(imat, h2);
/* if next bone is B-bone too, use average handle direction */
@@ -593,14 +632,66 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
roll2 = atan2f(mat3[2][0], mat3[2][2]);
- /* and only now negate handle */
- mul_v3_fl(h2, -hlength2);
}
else {
- h2[0] = 0.0f; h2[1] = -hlength2; h2[2] = 0.0f;
+ h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
roll2 = 0.0;
}
+ {
+ const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
+ const float hlength1 = bone->ease1 * circle_factor;
+ const float hlength2 = bone->ease2 * circle_factor;
+
+ /* and only now negate h2 */
+ mul_v3_fl(h1, hlength1);
+ mul_v3_fl(h2, -hlength2);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ /* add extra rolls */
+ roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone)
+ roll1 += prev->bone->roll2;
+
+ if (!rest)
+ roll1 += prev->roll2;
+ }
+ }
+
+ /* extra curve x / y */
+ /* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
+ * when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
+ * in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
+ */
+ const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
+ const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+
+ h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
+ h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+
+ h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
+ h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ }
+
/* make curve */
if (bone->segments > MAX_BBONE_SUBDIV)
bone->segments = MAX_BBONE_SUBDIV;
@@ -610,20 +701,45 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
/* make transformation matrices for the segments for drawing */
for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
-
+
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
-
+
if (do_scale) {
/* correct for scaling when this matrix is used in scaled space */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
+
+ /* BBone scale... */
+ {
+ const int num_segments = bone->segments;
+
+ const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
+
+ const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
+
+ const float scalefac = scaleFactorIn * scaleFactorOut;
+ float bscalemat[4][4], bscale[3];
+
+ bscale[0] = scalefac;
+ bscale[1] = 1.0f;
+ bscale[2] = scalefac;
+
+ size_to_mat4(bscalemat, bscale);
+
+ /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */
+ /*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
+ mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
+ }
+
}
}
@@ -669,7 +785,6 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
float tmat[4][4];
invert_m4_m4(tmat, b_bone_rest[a].mat);
-
mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
if (use_quaternion)
@@ -683,10 +798,10 @@ static void b_bone_deform(bPoseChanDeform *pdef_info, Bone *bone, float co[3], D
float (*mat)[4] = b_bone[0].mat;
float segment, y;
int a;
-
+
/* need to transform co back to bonespace, only need y */
y = mat[0][1] * co[0] + mat[1][1] * co[1] + mat[2][1] * co[2] + mat[3][1];
-
+
/* now calculate which of the b_bones are deforming this */
segment = bone->length / ((float)bone->segments);
a = (int)(y / segment);
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 34d9962139c..826bb12a912 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -633,7 +633,11 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
- if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
+ bArmature *arm = (bArmature *)ob->data;
+ if (arm->flag & ARM_RESTPOS) {
+ return;
+ }
+ else if (pchan->flag & POSE_IKTREE || pchan->flag & POSE_IKSPLINE) {
/* IK are being solved separately/ */
}
else {
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index bdf3432e6ea..96bac2c2f41 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -76,6 +76,8 @@ void BKE_camera_init(Camera *cam)
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
+ cam->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
+ cam->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
}
void *BKE_camera_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index e6741657f47..af1ad4900b3 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -495,11 +495,12 @@ static void cdDM_drawFacesTex_common(
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
const MPoly *mpoly = cddm->mpoly;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
int i;
int colType, start_element, tot_drawn;
const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
int totpoly;
int next_actualFace;
int mat_index;
@@ -529,15 +530,17 @@ static void cdDM_drawFacesTex_common(
}
}
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index bac59c8c62d..c1f1f0128f5 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BKE_colortools.h"
@@ -53,10 +54,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
-
/* ********************************* color curve ********************* */
/* ***************** operations on full struct ************* */
@@ -1089,31 +1086,170 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
}
/* if view_settings, it also applies this to byte buffers */
+typedef struct ScopesUpdateData {
+ Scopes *scopes;
+ const ImBuf *ibuf;
+ struct ColormanageProcessor *cm_processor;
+ const unsigned char *display_buffer;
+ const int ycc_mode;
+
+ unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
+} ScopesUpdateData;
+
+typedef struct ScopesUpdateDataChunk {
+ unsigned int bin_lum[256];
+ unsigned int bin_r[256];
+ unsigned int bin_g[256];
+ unsigned int bin_b[256];
+ unsigned int bin_a[256];
+ float min[3], max[3];
+} ScopesUpdateDataChunk;
+
+static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
+{
+ const ScopesUpdateData *data = userdata;
+
+ Scopes *scopes = data->scopes;
+ const ImBuf *ibuf = data->ibuf;
+ struct ColormanageProcessor *cm_processor = data->cm_processor;
+ const unsigned char *display_buffer = data->display_buffer;
+ const int ycc_mode = data->ycc_mode;
+
+ ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+ unsigned int *bin_lum = data_chunk->bin_lum;
+ unsigned int *bin_r = data_chunk->bin_r;
+ unsigned int *bin_g = data_chunk->bin_g;
+ unsigned int *bin_b = data_chunk->bin_b;
+ unsigned int *bin_a = data_chunk->bin_a;
+ float *min = data_chunk->min;
+ float *max = data_chunk->max;
+
+ const float *rf = NULL;
+ const unsigned char *rc = NULL;
+ const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
+ const int savedlines = y / rows_per_sample_line;
+ const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
+ const bool is_float = (ibuf->rect_float != NULL);
+
+ if (is_float)
+ rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
+ else {
+ rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
+ }
+
+ for (int x = 0; x < ibuf->x; x++) {
+ float rgba[4], ycc[3], luma;
+
+ if (is_float) {
+ switch (ibuf->channels) {
+ case 4:
+ copy_v4_v4(rgba, rf);
+ IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
+ break;
+ case 3:
+ copy_v3_v3(rgba, rf);
+ IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
+ rgba[3] = 1.0f;
+ break;
+ case 2:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = rf[1];
+ break;
+ case 1:
+ copy_v3_fl(rgba, rf[0]);
+ rgba[3] = 1.0f;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ else {
+ for (int c = 4; c--;)
+ rgba[c] = rc[c] * INV_255;
+ }
+
+ /* we still need luma for histogram */
+ luma = IMB_colormanagement_get_luminance(rgba);
+
+ /* check for min max */
+ if (ycc_mode == -1) {
+ minmax_v3v3_v3(min, max, rgba);
+ }
+ else {
+ rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
+ mul_v3_fl(ycc, INV_255);
+ minmax_v3v3_v3(min, max, ycc);
+ }
+ /* increment count for histo*/
+ bin_lum[get_bin_float(luma)]++;
+ bin_r[get_bin_float(rgba[0])]++;
+ bin_g[get_bin_float(rgba[1])]++;
+ bin_b[get_bin_float(rgba[2])]++;
+ bin_a[get_bin_float(rgba[3])]++;
+
+ /* save sample if needed */
+ if (do_sample_line) {
+ const float fx = (float)x / (float)ibuf->x;
+ const int idx = 2 * (ibuf->x * savedlines + x);
+ save_sample_line(scopes, idx, fx, rgba, ycc);
+ }
+
+ rf += ibuf->channels;
+ rc += ibuf->channels;
+ }
+}
+
+static void scopes_update_finalize(void *userdata, void *userdata_chunk)
+{
+ const ScopesUpdateData *data = userdata;
+ const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
+
+ unsigned int *bin_lum = data->bin_lum;
+ unsigned int *bin_r = data->bin_r;
+ unsigned int *bin_g = data->bin_g;
+ unsigned int *bin_b = data->bin_b;
+ unsigned int *bin_a = data->bin_a;
+ const unsigned int *bin_lum_c = data_chunk->bin_lum;
+ const unsigned int *bin_r_c = data_chunk->bin_r;
+ const unsigned int *bin_g_c = data_chunk->bin_g;
+ const unsigned int *bin_b_c = data_chunk->bin_b;
+ const unsigned int *bin_a_c = data_chunk->bin_a;
+
+ float (*minmax)[2] = data->scopes->minmax;
+ const float *min = data_chunk->min;
+ const float *max = data_chunk->max;
+
+ for (int b = 256; b--;) {
+ bin_lum[b] += bin_lum_c[b];
+ bin_r[b] += bin_r_c[b];
+ bin_g[b] += bin_g_c[b];
+ bin_b[b] += bin_b_c[b];
+ bin_a[b] += bin_a_c[b];
+ }
+
+ for (int c = 3; c--;) {
+ if (min[c] < minmax[c][0])
+ minmax[c][0] = min[c];
+ if (max[c] > minmax[c][1])
+ minmax[c][1] = max[c];
+ }
+}
+
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings)
{
-#ifdef _OPENMP
- const int num_threads = BLI_system_thread_count();
-#endif
- int a, y;
+ int a;
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
- unsigned char *display_buffer;
+ const unsigned char *display_buffer = NULL;
unsigned int bin_lum[256] = {0},
bin_r[256] = {0},
bin_g[256] = {0},
bin_b[256] = {0},
bin_a[256] = {0};
- unsigned int bin_lum_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_r_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_g_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_b_t[BLENDER_MAX_THREADS][256] = {{0}},
- bin_a_t[BLENDER_MAX_THREADS][256] = {{0}};
int ycc_mode = -1;
- const bool is_float = (ibuf->rect_float != NULL);
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
- int rows_per_sample_line;
if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
@@ -1151,7 +1287,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes->sample_lines = ibuf->y;
/* scan the image */
- rows_per_sample_line = ibuf->y / scopes->sample_lines;
for (a = 0; a < 3; a++) {
scopes->minmax[a][0] = 25500.0f;
scopes->minmax[a][1] = -25500.0f;
@@ -1177,129 +1312,21 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
}
else {
- display_buffer = (unsigned char *)IMB_display_buffer_acquire(ibuf,
- view_settings,
- display_settings,
- &cache_handle);
+ display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
+ ibuf, view_settings, display_settings, &cache_handle);
}
/* Keep number of threads in sync with the merge parts below. */
-#pragma omp parallel for private(y) schedule(static) num_threads(num_threads) if (ibuf->y > 256)
- for (y = 0; y < ibuf->y; y++) {
-#ifdef _OPENMP
- const int thread_idx = omp_get_thread_num();
-#else
- const int thread_idx = 0;
-#endif
- const float *rf = NULL;
- const unsigned char *rc = NULL;
- const int savedlines = y / rows_per_sample_line;
- const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
- float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX},
- max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- int x, c;
- if (is_float)
- rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
- else {
- rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
- }
- for (x = 0; x < ibuf->x; x++) {
- float rgba[4], ycc[3], luma;
- if (is_float) {
-
- switch (ibuf->channels) {
- case 4:
- copy_v4_v4(rgba, rf);
- IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
- break;
- case 3:
- copy_v3_v3(rgba, rf);
- IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
- rgba[3] = 1.0f;
- break;
- case 2:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = rf[1];
- break;
- case 1:
- copy_v3_fl(rgba, rf[0]);
- rgba[3] = 1.0f;
- break;
- default:
- BLI_assert(0);
- }
- }
- else {
- for (c = 0; c < 4; c++)
- rgba[c] = rc[c] * INV_255;
- }
-
- /* we still need luma for histogram */
- luma = IMB_colormanagement_get_luminance(rgba);
-
- /* check for min max */
- if (ycc_mode == -1) {
- for (c = 0; c < 3; c++) {
- if (rgba[c] < min[c]) min[c] = rgba[c];
- if (rgba[c] > max[c]) max[c] = rgba[c];
- }
- }
- else {
- rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
- for (c = 0; c < 3; c++) {
- ycc[c] *= INV_255;
- if (ycc[c] < min[c]) min[c] = ycc[c];
- if (ycc[c] > max[c]) max[c] = ycc[c];
- }
- }
- /* increment count for histo*/
- bin_lum_t[thread_idx][get_bin_float(luma)] += 1;
- bin_r_t[thread_idx][get_bin_float(rgba[0])] += 1;
- bin_g_t[thread_idx][get_bin_float(rgba[1])] += 1;
- bin_b_t[thread_idx][get_bin_float(rgba[2])] += 1;
- bin_a_t[thread_idx][get_bin_float(rgba[3])] += 1;
-
- /* save sample if needed */
- if (do_sample_line) {
- const float fx = (float)x / (float)ibuf->x;
- const int idx = 2 * (ibuf->x * savedlines + x);
- save_sample_line(scopes, idx, fx, rgba, ycc);
- }
-
- rf += ibuf->channels;
- rc += ibuf->channels;
- }
-#pragma omp critical
- {
- for (c = 0; c < 3; c++) {
- if (min[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = min[c];
- if (max[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = max[c];
- }
- }
- }
-
-#ifdef _OPENMP
- if (ibuf->y > 256) {
- for (a = 0; a < num_threads; a++) {
- int b;
- for (b = 0; b < 256; b++) {
- bin_lum[b] += bin_lum_t[a][b];
- bin_r[b] += bin_r_t[a][b];
- bin_g[b] += bin_g_t[a][b];
- bin_b[b] += bin_b_t[a][b];
- bin_a[b] += bin_a_t[a][b];
- }
- }
- }
- else
-#endif
- {
- memcpy(bin_lum, bin_lum_t[0], sizeof(bin_lum));
- memcpy(bin_r, bin_r_t[0], sizeof(bin_r));
- memcpy(bin_g, bin_g_t[0], sizeof(bin_g));
- memcpy(bin_b, bin_b_t[0], sizeof(bin_b));
- memcpy(bin_a, bin_a_t[0], sizeof(bin_a));
- }
+ ScopesUpdateData data = {
+ .scopes = scopes, . ibuf = ibuf,
+ .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
+ .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
+ };
+ ScopesUpdateDataChunk data_chunk = {0};
+ INIT_MINMAX(data_chunk.min, data_chunk.max);
+
+ BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
+ scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false);
/* test for nicer distribution even - non standard, leave it out for a while */
#if 0
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 7144e25ba7f..a591d536b43 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -535,7 +535,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
/* generic function to get the appropriate matrix for most target cases */
/* The cases where the target can be object data have not been implemented */
-static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, float headtail)
+static void constraint_target_to_mat4(Object *ob, const char *substring, float mat[4][4], short from, short to, short flag, float headtail)
{
/* Case OBJECT */
if (substring[0] == '\0') {
@@ -573,6 +573,58 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
+ else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
+ /* use point along bbone */
+ Mat4 bbone[MAX_BBONE_SUBDIV];
+ float tempmat[4][4];
+ float loc[3], fac;
+
+ /* get bbone segments */
+ b_bone_spline_setup(pchan, 0, bbone);
+
+ /* figure out which segment(s) the headtail value falls in */
+ fac = (float)pchan->bone->segments * headtail;
+
+ if (fac >= pchan->bone->segments - 1) {
+ /* special case: end segment doesn't get created properly... */
+ float pt[3], sfac;
+ int index;
+
+ /* bbone points are in bonespace, so need to move to posespace first */
+ index = pchan->bone->segments - 1;
+ mul_v3_m4v3(pt, pchan->pose_mat, bbone[index].mat[3]);
+
+ /* interpolate between last segment point and the endpoint */
+ sfac = fac - (float)(pchan->bone->segments - 1); /* fac is just the "leftover" between penultimate and last points */
+ interp_v3_v3v3(loc, pt, pchan->pose_tail, sfac);
+ }
+ else {
+ /* get indices for finding interpolating between points along the bbone */
+ float pt_a[3], pt_b[3], pt[3];
+ int index_a, index_b;
+
+ index_a = floorf(fac);
+ CLAMP(index_a, 0, MAX_BBONE_SUBDIV - 1);
+
+ index_b = ceilf(fac);
+ CLAMP(index_b, 0, MAX_BBONE_SUBDIV - 1);
+
+ /* interpolate between these points */
+ copy_v3_v3(pt_a, bbone[index_a].mat[3]);
+ copy_v3_v3(pt_b, bbone[index_b].mat[3]);
+
+ interp_v3_v3v3(pt, pt_a, pt_b, fac - floorf(fac));
+
+ /* move the point from bone local space to pose space... */
+ mul_v3_m4v3(loc, pchan->pose_mat, pt);
+ }
+
+ /* use interpolated distance for subtarget */
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ copy_v3_v3(tempmat[3], loc);
+
+ mul_m4_m4m4(mat, ob->obmat, tempmat);
+ }
else {
float tempmat[4][4], loc[3];
@@ -634,7 +686,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct)
unit_m4(ct->matrix);
}
@@ -1102,7 +1154,7 @@ static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstrai
bKinematicConstraint *data = con->data;
if (VALID_CONS_TARGET(ct))
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
else if (ct) {
if (data->flag & CONSTRAINT_IK_AUTO) {
Object *ob = cob->ob;
@@ -1985,7 +2037,7 @@ static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTa
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
*/
- constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* only execute target calculation if allowed */
#ifdef WITH_PYTHON
@@ -2097,7 +2149,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT
unit_m4(ct->matrix);
/* get the transform matrix of the target */
- constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail);
+ constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
/* determine where in transform range target is */
/* data->type is mapped as follows for backwards compatibility:
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index b0d0dc08126..de79a30bd60 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1530,13 +1530,11 @@ void CustomData_realloc(CustomData *data, int totelem)
for (i = 0; i < data->totlayer; ++i) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
- int size;
if (layer->flag & CD_FLAG_NOFREE) {
continue;
}
typeInfo = layerType_getInfo(layer->type);
- size = totelem * typeInfo->size;
- layer->data = MEM_reallocN(layer->data, size);
+ layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
@@ -1844,7 +1842,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- const int size = totelem * typeInfo->size;
+ const size_t size = (size_t)totelem * typeInfo->size;
int flag = 0, index = data->totlayer;
void *newlayerdata = NULL;
@@ -2064,7 +2062,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
if (typeInfo->copy) {
- void *dst_data = MEM_mallocN(totelem * typeInfo->size, "CD duplicate ref layer");
+ void *dst_data = MEM_mallocN((size_t)totelem * typeInfo->size, "CD duplicate ref layer");
typeInfo->copy(layer->data, dst_data, totelem);
layer->data = dst_data;
}
@@ -2172,7 +2170,7 @@ void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs,
if (typeInfo->copy)
typeInfo->copy(src_data_ofs, dst_data_ofs, count);
else
- memcpy(dst_data_ofs, src_data_ofs, count * typeInfo->size);
+ memcpy(dst_data_ofs, src_data_ofs, (size_t)count * typeInfo->size);
}
static void CustomData_copy_data_layer(
@@ -2181,16 +2179,14 @@ static void CustomData_copy_data_layer(
int src_index, int dst_index, int count)
{
const LayerTypeInfo *typeInfo;
- int src_offset;
- int dst_offset;
const void *src_data = source->layers[src_i].data;
void *dst_data = dest->layers[dst_i].data;
typeInfo = layerType_getInfo(source->layers[src_i].type);
- src_offset = src_index * typeInfo->size;
- dst_offset = dst_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
+ const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
if (count && !(src_data == NULL && dst_data == NULL)) {
@@ -2201,14 +2197,16 @@ static void CustomData_copy_data_layer(
return;
}
- if (typeInfo->copy)
+ if (typeInfo->copy) {
typeInfo->copy(POINTER_OFFSET(src_data, src_offset),
POINTER_OFFSET(dst_data, dst_offset),
count);
- else
+ }
+ else {
memcpy(POINTER_OFFSET(dst_data, dst_offset),
POINTER_OFFSET(src_data, src_offset),
- count * typeInfo->size);
+ (size_t)count * typeInfo->size);
+ }
}
void CustomData_copy_data_named(const CustomData *source, CustomData *dest,
@@ -2270,7 +2268,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = index * typeInfo->size;
+ size_t offset = (size_t)index * typeInfo->size;
typeInfo->free(POINTER_OFFSET(data->layers[i].data, offset), count, typeInfo->size);
}
@@ -2281,7 +2279,7 @@ void CustomData_free_elem(CustomData *data, int index, int count)
#define SOURCE_BUF_SIZE 100
void CustomData_interp(const CustomData *source, CustomData *dest,
- int *src_indices, float *weights, float *sub_weights,
+ const int *src_indices, const float *weights, const float *sub_weights,
int count, int dest_index)
{
int src_i, dest_i;
@@ -2316,11 +2314,11 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
void *src_data = source->layers[src_i].data;
for (j = 0; j < count; ++j) {
- sources[j] = POINTER_OFFSET(src_data, src_indices[j] * typeInfo->size);
+ sources[j] = POINTER_OFFSET(src_data, (size_t)src_indices[j] * typeInfo->size);
}
typeInfo->interp(sources, weights, sub_weights, count,
- POINTER_OFFSET(dest->layers[dest_i].data, dest_index * typeInfo->size));
+ POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dest_index * typeInfo->size));
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
@@ -2349,7 +2347,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->swap) {
- const int offset = index * typeInfo->size;
+ const size_t offset = (size_t)index * typeInfo->size;
typeInfo->swap(POINTER_OFFSET(data->layers[i].data, offset), corner_indices);
}
@@ -2387,7 +2385,6 @@ void CustomData_swap(struct CustomData *data, const int index_a, const int index
void *CustomData_get(const CustomData *data, int index, int type)
{
- int offset;
int layer_index;
BLI_assert(index >= 0);
@@ -2397,7 +2394,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
if (layer_index == -1) return NULL;
/* get the offset of the desired element */
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index].data, offset);
}
@@ -2405,7 +2402,6 @@ void *CustomData_get(const CustomData *data, int index, int type)
void *CustomData_get_n(const CustomData *data, int type, int index, int n)
{
int layer_index;
- int offset;
BLI_assert(index >= 0 && n >= 0);
@@ -2413,7 +2409,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
layer_index = data->typemap[type];
if (layer_index == -1) return NULL;
- offset = layerType_getInfo(type)->size * index;
+ const size_t offset = (size_t)index * layerType_getInfo(type)->size;
return POINTER_OFFSET(data->layers[layer_index + n].data, offset);
}
@@ -2838,7 +2834,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
typeInfo = layerType_getInfo(data->layers[i].type);
if (typeInfo->free) {
- int offset = data->layers[i].offset;
+ const size_t offset = data->layers[i].offset;
typeInfo->free(POINTER_OFFSET(block, offset), 1, typeInfo->size);
}
}
@@ -3218,7 +3214,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
int src_index, void **dest_block, bool use_default_init)
{
const LayerTypeInfo *typeInfo;
- int dest_i, src_i, src_offset;
+ int dest_i, src_i;
if (*dest_block == NULL)
CustomData_bmesh_alloc_block(dest, dest_block);
@@ -3247,7 +3243,7 @@ void CustomData_to_bmesh_block(const CustomData *source, CustomData *dest,
void *dest_data = POINTER_OFFSET(*dest_block, offset);
typeInfo = layerType_getInfo(dest->layers[dest_i].type);
- src_offset = src_index * typeInfo->size;
+ const size_t src_offset = (size_t)src_index * typeInfo->size;
if (typeInfo->copy)
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
@@ -3294,7 +3290,7 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
int offset = source->layers[src_i].offset;
const void *src_data = POINTER_OFFSET(src_block, offset);
- void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, dst_index * typeInfo->size);
+ void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data, (size_t)dst_index * typeInfo->size);
if (typeInfo->copy)
typeInfo->copy(src_data, dst_data, 1);
@@ -3311,12 +3307,12 @@ void CustomData_from_bmesh_block(const CustomData *source, CustomData *dest,
}
-void CustomData_file_write_info(int type, const char **structname, int *structnum)
+void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- *structname = typeInfo->structname;
- *structnum = typeInfo->structnum;
+ *r_struct_name = typeInfo->structname;
+ *r_struct_num = typeInfo->structnum;
}
/**
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index ff036828ebd..1df4effebf1 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -32,6 +32,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_kdtree.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -64,6 +65,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -79,9 +81,7 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-#ifdef _OPENMP
-# include <omp.h>
-#endif
+#include "atomic_ops.h"
/* could enable at some point but for now there are far too many conversions */
#ifdef __GNUC__
@@ -138,8 +138,8 @@ typedef struct Bounds2D {
} Bounds2D;
typedef struct Bounds3D {
- int valid;
float min[3], max[3];
+ bool valid;
} Bounds3D;
typedef struct VolumeGrid {
@@ -150,6 +150,8 @@ typedef struct VolumeGrid {
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;
} VolumeGrid;
typedef struct Vec3f {
@@ -175,6 +177,7 @@ typedef struct PaintBakeData {
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 */
@@ -190,7 +193,6 @@ typedef struct PaintBakeData {
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 */
@@ -419,7 +421,8 @@ static int surface_totalSamples(DynamicPaintSurface *surface)
return surface->data->total_points;
}
-static void blendColors(const float t_color[3], float t_alpha, const float s_color[3], 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;
@@ -526,7 +529,7 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
return flags;
}
-static int brush_usesMaterial(DynamicPaintBrushSettings *brush, Scene *scene)
+static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
{
return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene)));
}
@@ -573,7 +576,7 @@ 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 = 1;
+ b->valid = true;
return;
}
@@ -600,27 +603,92 @@ static void freeGrid(PaintSurfaceData *data)
bData->grid = NULL;
}
+static void grid_bound_insert_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
+}
+
+static void grid_bound_insert_finalize(void *userdata, void *userdata_chunk)
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+
+ Bounds3D *grid_bound = userdata_chunk;
+
+ boundInsert(&grid->grid_bounds, grid_bound->min);
+ boundInsert(&grid->grid_bounds, grid_bound->max);
+}
+
+static void grid_cell_points_cb_ex(void *userdata, void *userdata_chunk, const int i, const int UNUSED(thread_id))
+{
+ PaintBakeData *bData = userdata;
+ VolumeGrid *grid = bData->grid;
+ int *temp_t_index = grid->temp_t_index;
+ int *s_num = userdata_chunk;
+
+ 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);
+ }
+
+ 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 *userdata, void *userdata_chunk)
+{
+ 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;
+
+ /* 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 *userdata, const int x)
+{
+ 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;
- Bounds3D *grid_bounds;
VolumeGrid *grid;
int grid_cells, axis = 3;
int *temp_t_index = NULL;
int *temp_s_num = NULL;
-#ifdef _OPENMP
- int num_of_threads = omp_get_max_threads();
-#else
- int num_of_threads = 1;
-#endif
-
if (bData->grid)
freeGrid(sData);
- /* allocate separate bounds for each thread */
- grid_bounds = MEM_callocN(sizeof(Bounds3D) * num_of_threads, "Grid Bounds");
bData->grid = MEM_callocN(sizeof(VolumeGrid), "Surface Grid");
grid = bData->grid;
@@ -631,27 +699,16 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
float min_dim;
/* calculate canvas dimensions */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
-#ifdef _OPENMP
- int id = omp_get_thread_num();
- boundInsert(&grid_bounds[id], (bData->realCoord[bData->s_pos[i]].v));
-#else
- boundInsert(&grid_bounds[0], (bData->realCoord[bData->s_pos[i]].v));
-#endif
- }
-
- /* get final dimensions */
- for (i = 0; i < num_of_threads; i++) {
- boundInsert(&grid->grid_bounds, grid_bounds[i].min);
- boundInsert(&grid->grid_bounds, grid_bounds[i].max);
- }
-
- MEM_freeN(grid_bounds);
+ /* Important to init correctly our ref grid_bound... */
+ boundInsert(&grid->grid_bounds, bData->realCoord[bData->s_pos[0]].v);
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, &grid->grid_bounds, sizeof(grid->grid_bounds),
+ grid_bound_insert_cb_ex, grid_bound_insert_finalize, sData->total_points > 1000, false);
/* 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 */
@@ -684,10 +741,11 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
/* 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 * num_of_threads, "Surface Grid Points");
+
+ 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");
- temp_t_index = MEM_callocN(sizeof(int) * sData->total_points, "Temp 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)
@@ -695,33 +753,12 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
if (!error) {
/* calculate number of points withing each cell */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int co[3], j;
- for (j = 0; j < 3; j++) {
- co[j] = (int)floor((bData->realCoord[bData->s_pos[i]].v[j] - grid->grid_bounds.min[j]) / dim[j] * grid->dim[j]);
- CLAMP(co[j], 0, grid->dim[j] - 1);
- }
+ BLI_task_parallel_range_finalize(
+ 0, sData->total_points, bData, grid->s_num, sizeof(*grid->s_num) * grid_cells,
+ grid_cell_points_cb_ex, grid_cell_points_finalize, sData->total_points > 1000, false);
- temp_t_index[i] = co[0] + co[1] * grid->dim[0] + co[2] * grid->dim[0] * grid->dim[1];
-#ifdef _OPENMP
- grid->s_num[temp_t_index[i] + omp_get_thread_num() * grid_cells]++;
-#else
- grid->s_num[temp_t_index[i]]++;
-#endif
- }
-
- /* for first cell only calc s_num */
- for (i = 1; i < num_of_threads; i++) {
- grid->s_num[0] += grid->s_num[i * grid_cells];
- }
-
- /* calculate grid indexes */
+ /* calculate grid indexes (not needed for first cell, which is zero). */
for (i = 1; i < grid_cells; i++) {
- int id;
- for (id = 1; id < num_of_threads; id++) {
- grid->s_num[i] += grid->s_num[i + id * grid_cells];
- }
grid->s_pos[i] = grid->s_pos[i - 1] + grid->s_num[i - 1];
}
@@ -734,35 +771,14 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
}
/* calculate cell bounds */
- {
- int x;
-#pragma omp parallel for schedule(static)
- for (x = 0; x < grid->dim[0]; x++) {
- int y;
- for (y = 0; y < grid->dim[1]; y++) {
- int z;
- for (z = 0; z < grid->dim[2]; z++) {
- int j, b_index = x + y * grid->dim[0] + z * grid->dim[0] * grid->dim[1];
- /* set bounds */
- for (j = 0; j < 3; j++) {
- 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 = 1;
- }
- }
- }
- }
+ BLI_task_parallel_range(0, grid->dim[0], bData, grid_cell_bounds_cb, grid_cells > 1000);
}
if (temp_s_num)
MEM_freeN(temp_s_num);
if (temp_t_index)
MEM_freeN(temp_t_index);
-
- /* free per thread s_num values */
- grid->s_num = MEM_reallocN(grid->s_num, sizeof(int) * grid_cells);
+ grid->temp_t_index = NULL;
if (error || !grid->s_num) {
setError(surface->canvas, N_("Not enough free memory"));
@@ -1040,7 +1056,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
-
+
brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
@@ -1254,7 +1270,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
int *temp_data;
int neigh_points = 0;
- if (!surface_usesAdjData(surface) && !force_init)
+ if (!force_init && !surface_usesAdjData(surface))
return;
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
@@ -1323,7 +1339,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
ad->flags[i] |= ADJ_ON_MESH_EDGE;
}
- /* reset temp data */
+ /* reset temp data */
temp_data[i] = 0;
}
@@ -1357,6 +1373,117 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
MEM_freeN(temp_data);
}
+typedef struct DynamicPaintSetInitColorData {
+ const DynamicPaintSurface *surface;
+
+ const MLoop *mloop;
+ const MLoopUV *mloopuv;
+ const MLoopTri *mlooptri;
+ const MLoopCol *mloopcol;
+ struct ImagePool *pool;
+
+ const bool scene_color_manage;
+} DynamicPaintSetInitColorData;
+
+static void dynamic_paint_set_init_color_tex_to_vcol_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ 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 bool scene_color_manage = data->scene_color_manage;
+
+ float uv[3] = {0.0f};
+
+ 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;
+
+ 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;
+ }
+ }
+}
+
+static void dynamic_paint_set_init_color_tex_to_imseq_cb(void *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ 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 bool scene_color_manage = data->scene_color_manage;
+
+ float uv[9] = {0.0f};
+ float uv_final[3] = {0.0f};
+
+ 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);
+ }
+
+ /* 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);
+
+ /* 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 *userdata, const int i)
+{
+ const DynamicPaintSetInitColorData *data = userdata;
+
+ 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 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);
+ }
+
+ /* interpolate final color */
+ interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
+
+ copy_v4_v4(pPoint[i].color, final_color);
+}
+
static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface *surface)
{
PaintSurfaceData *sData = surface->data;
@@ -1374,7 +1501,6 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
/* Single color */
if (surface->init_color_type == MOD_DPAINT_INITIAL_COLOR) {
/* apply color to every surface point */
-#pragma omp parallel for schedule(static)
for (i = 0; i < sData->total_points; i++) {
copy_v4_v4(pPoint[i].color, surface->init_color);
}
@@ -1404,57 +1530,22 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
struct ImagePool *pool = BKE_image_pool_new();
-#pragma omp parallel for schedule(static) shared(pool)
- for (i = 0; i < tottri; i++) {
- float uv[3] = {0.0f};
- int j;
- for (j = 0; j < 3; j++) {
- TexResult texres = {0};
- unsigned int vert = mloop[mlooptri[i].tri[j]].v;
-
- /* remap to -1.0 to 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);
-
- if (texres.tin > pPoint[vert].color[3]) {
- copy_v3_v3(pPoint[vert].color, &texres.tr);
- pPoint[vert].color[3] = texres.tin;
- }
- }
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv, .pool = pool,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, tottri, &data, dynamic_paint_set_init_color_tex_to_vcol_cb, tottri > 1000);
BKE_image_pool_free(pool);
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float uv[9] = {0.0f};
- float uv_final[3] = {0.0f};
- int j;
- TexResult texres = {0};
-
- /* collect all uvs */
- for (j = 0; 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 to 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);
-
- /* apply color */
- copy_v3_v3(pPoint[i].color, &texres.tr);
- pPoint[i].color[3] = texres.tin;
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopuv = mloopuv,
+ .scene_color_manage = scene_color_manage
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_tex_to_imseq_cb,
+ sData->total_points > 1000);
}
}
/* vertex color layer */
@@ -1468,36 +1559,22 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
if (!col)
return;
-#pragma omp parallel for schedule(static)
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 = dm->getLoopTriArray(dm);
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- int samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
if (!col)
return;
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- int tri_ind = f_data->uv_p[i].tri_index;
- float colors[3][4];
- float final_color[4];
- int j;
-
- /* collect color values */
- for (j = 0; j < 3; j++) {
- rgba_uchar_to_float(colors[j], (const unsigned char *)&col[mlooptri[tri_ind].tri[j]].r);
- }
-
- /* interpolate final color */
- interp_v4_v4v4v4(final_color, UNPACK3(colors), f_data->barycentricWeights[i * samples].v);
-
- copy_v4_v4(pPoint[i].color, final_color);
- }
+ DynamicPaintSetInitColorData data = {
+ .surface = surface,
+ .mlooptri = mlooptri, .mloopcol = col,
+ };
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_set_init_color_vcol_to_imseq_cb,
+ sData->total_points > 1000);
}
}
}
@@ -1570,6 +1647,36 @@ static bool dynamicPaint_checkSurfaceData(const Scene *scene, DynamicPaintSurfac
/***************************** Modifier processing ******************************/
+typedef struct DynamicPaintModifierApplyData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
+
+ MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly;
+
+ float (*fcolor)[4];
+ MLoopCol *mloopcol;
+ MLoopCol *mloopcol_wet;
+ MLoopCol *mloopcol_preview;
+} DynamicPaintModifierApplyData;
+
+static void dynamic_paint_apply_surface_displace_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ 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;
+
+ 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);
+}
/* apply displacing vertex surface to the derived mesh */
static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
@@ -1582,22 +1689,106 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri
/* displace paint */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
MVert *mvert = result->getVertArray(result);
- int i;
- const float *value = (float *)sData->type_data;
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3], val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
- normalize_v3(normal);
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_displace_cb,
+ sData->total_points > 10000);
+ }
+}
+
+static void dynamic_paint_apply_surface_vpaint_blend_cb(void *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ 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]);
+}
+
+static void dynamic_paint_apply_surface_vpaint_cb(void *userdata, const int p_index)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+ Object *ob = data->ob;
+
+ const MLoop *mloop = data->mloop;
+ const MPoly *mpoly = data->mpoly;
- mvert[i].co[0] -= normal[0] * val;
- mvert[i].co[1] -= normal[1] * val;
- mvert[i].co[2] -= normal[2] * val;
+ 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 = FTOCHAR(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 = FTOCHAR(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 *userdata, const int i)
+{
+ const DynamicPaintModifierApplyData *data = userdata;
+
+ 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);
+}
+
/*
* Apply canvas data to the object derived mesh
*/
@@ -1624,127 +1815,57 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
-
- int i;
- PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- MLoopCol *col = NULL;
MLoop *mloop = CDDM_get_loops(result);
- int totloop = result->numLoopData;
+ const int totloop = result->numLoopData;
+ MPoly *mpoly = CDDM_get_polys(result);
+ const int totpoly = result->numPolyData;
/* paint is stored on dry and wet layers, so mix final color first */
- float *fcolor = MEM_callocN(sizeof(float) * sData->total_points * 4, "Temp paint color");
+ float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; 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 * 4]);
- }
-
- /* viewport preview */
- if (surface->flags & MOD_DPAINT_PREVIEW) {
- MPoly *mp = CDDM_get_polys(result);
- int totpoly = result->numPolyData;
-
-#if 0
- /* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev
- * (after a SubSurf mod, eg)... */
- if (!result->getTessFaceDataArray(result, CD_PREVIEW_MCOL)) {
- int numFaces = result->getNumTessFaces(result);
- CustomData_add_layer(&result->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
- }
-#endif
-
- /* Save preview results to weight layer to be
- * able to share same drawing methods */
- col = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
- if (!col) {
- col = CustomData_add_layer(
- &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
- }
-
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totpoly; i++) {
- Material *material = give_current_material(ob, mp[i].mat_nr + 1);
-
- for (int j = 0; j < mp[i].totloop; j++) {
- int l_index = mp[i].loopstart + j;
- int v_index = mloop[l_index].v;
-
- if (surface->preview_id == MOD_DPAINT_SURFACE_PREV_PAINT) {
- float c[3];
- v_index *= 4;
-
- /* Apply material color as base vertex color for preview */
- col[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 *)&col[l_index].r, c);
- }
- else {
- const char c = FTOCHAR(pPoint[v_index].wetness);
- col[l_index].r = c;
- col[l_index].g = c;
- col[l_index].b = c;
- col[l_index].a = 255;
- }
- }
- }
- }
- }
-
-
- /* save layer data to output layer */
+ DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_apply_surface_vpaint_blend_cb,
+ sData->total_points > 1000);
/* paint layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
+ MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 0)) {
- col = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
+ mloopcol = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
- /* apply color */
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totloop; i++) {
- int index = mloop[i].v * 4;
- rgba_float_to_uchar((unsigned char *)&col[i].r, &fcolor[index]);
- }
- }
-
- MEM_freeN(fcolor);
/* wet layer */
- col = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
- if (!col && dynamicPaint_outputLayerExists(surface, ob, 1)) {
- col = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
+ mloopcol_wet = CustomData_add_layer_named(
+ &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
}
- /* apply color */
- if (col) {
-#pragma omp parallel for schedule(static)
- for (i = 0; i < totloop; i++) {
- const char c = FTOCHAR(pPoint[mloop[i].v].wetness);
- col[i].r = c;
- col[i].g = c;
- col[i].b = c;
- col[i].a = 255;
+
+ /* 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->loopData, CD_PREVIEW_MLOOPCOL);
+ if (!mloopcol_preview) {
+ mloopcol_preview = CustomData_add_layer(
+ &result->loopData, 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;
+
+ BLI_task_parallel_range(0, totpoly, &data, dynamic_paint_apply_surface_vpaint_cb,
+ totpoly > 1000);
+
+ MEM_freeN(fcolor);
+
/* Mark tessellated CD layers as dirty. */
result->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
@@ -1789,15 +1910,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* wave simulation */
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
MVert *mvert = result->getVertArray(result);
- int i;
- PaintWavePoint *wPoint = (PaintWavePoint *)sData->type_data;
-
-#pragma omp parallel for schedule(static)
- for (i = 0; i < sData->total_points; i++) {
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
- }
+
+ DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
+ BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb,
+ sData->total_points > 1000);
update_normals = true;
}
@@ -1927,255 +2043,461 @@ static void dynamicPaint_frameUpdate(DynamicPaintModifierData *pmd, Scene *scene
/* Modifier call. Processes dynamic paint modifier step. */
DerivedMesh *dynamicPaint_Modifier_do(DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
{
- /* For now generate looptris in every case */
- DM_ensure_looptri(dm);
+ if (pmd->canvas) {
+ DerivedMesh *ret;
- /* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
- /* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
+
+ return ret;
+ }
+ else {
+ /* For now generate looptris in every case */
+ DM_ensure_looptri(dm);
+
+ /* Update canvas data for a new frame */
+ dynamicPaint_frameUpdate(pmd, scene, ob, dm);
+
+ /* Return output mesh */
+ return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ }
}
/***************************** Image Sequence / UV Image Surface Calls ******************************/
/*
- * Tries to find the neighboring pixel in given (uv space) direction.
- * Result is used by effect system to move paint on the surface.
+ * 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, \
+}
+
+typedef struct DynamicPaintCreateUVSurfaceData {
+ const DynamicPaintSurface *surface;
+
+ PaintUVPoint *tempPoints;
+ Vec3f *tempWeights;
+
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ const MLoop *mloop;
+ const int tottri;
+
+ const Bounds2D *faceBB;
+ uint32_t *active_points;
+} DynamicPaintCreateUVSurfaceData;
+
+static void dynamic_paint_create_uv_surface_direct_cb(void *userdata, const int ty)
+{
+ 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 *userdata, const int ty)
+{
+ 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 */
+ for (int u = u_min; u <= u_max; u++) {
+ for (int v = v_min; v <= v_max; v++) {
+ /* 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.
+ * Cheking 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_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;
+
+ u = u_max + 1; /* make sure we exit outer loop as well */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Increase the final number of active surface points if relevant. */
+ if (tPoint->tri_index != -1)
+ atomic_add_uint32(active_points, 1);
+ }
+}
+
+#undef JITTER_SAMPLES
+
+/* Tries to find the neighboring pixel in given (uv space) direction.
+ * Result is used by effect system to move paint on the surface.
*
- * px, py : origin pixel x and y
- * n_index : lookup direction index (use neighX, neighY to get final index)
+ * px, py : origin pixel x and y
+ * n_index : lookup direction index (use neighX, neighY to get final index)
*/
-static int dynamicPaint_findNeighbourPixel(PaintUVPoint *tempPoints, DerivedMesh *dm,
- const char *uvname, int w, int h, int px, int py, 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)
+ * -> It doesn't always lead to the optimum pixel but is accurate enough
+ * and faster/simpler than including possible face tip point links)
*/
- int x, y;
- PaintUVPoint *tPoint = NULL;
- PaintUVPoint *cPoint = NULL;
-
/* shift position by given n_index */
- x = px + neighX[n_index];
- y = py + neighY[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;
- tPoint = &tempPoints[x + w * y]; /* UV neighbor */
- cPoint = &tempPoints[px + w * py]; /* Origin point */
+ 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")
- */
+ /* 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.
+ /* 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.
+ * !! 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
- * it's "real" position.
+ /* 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
+ * 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?
+ * TODO: Implement something more accurate / optimized?
*/
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const MLoopUV *mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ const MLoop *mloop = data->mloop;
+ const MLoopTri *mlooptri = data->mlooptri;
+ const MLoopUV *mloopuv = data->mloopuv;
/* Get closest edge to that subpixel on UV map */
- {
- float pixel[2];
- /* distances only used for comparison */
- float dist_squared, t_dist_squared;
-
- int i, edge1_index, edge2_index;
- int e1_index, e2_index, target_tri;
- float closest_point[2], lambda, dir_vec[2];
- int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
-
- const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
-
- pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
- pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
-
- /*
- * Find closest edge to that pixel
- */
-
- /* Dist to first edge */
- e1_index = cPoint->v1;
- e2_index = cPoint->v2;
- edge1_index = 0;
- edge2_index = 1;
- dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
-
- /* Dist to second edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v2;
- e2_index = cPoint->v3;
- edge1_index = 1;
- edge2_index = 2;
- dist_squared = t_dist_squared;
- }
- /* Dist to third edge */
- t_dist_squared = dist_squared_to_line_segment_v2(
- pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
- if (t_dist_squared < dist_squared) {
- e1_index = cPoint->v3;
- e2_index = cPoint->v1;
- edge1_index = 2;
- edge2_index = 0;
- dist_squared = t_dist_squared;
- }
+ float pixel[2];
+ /* distances only used for comparison */
+ float dist_squared, t_dist_squared;
+ int edge1_index, edge2_index;
+ int e1_index, e2_index, target_tri;
+ float closest_point[2], lambda, dir_vec[2];
+ int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index;
- /*
- * Now find another face that is linked to that edge
- */
- target_tri = -1;
-
- for (i = 0; i < tottri; i++) {
- const int v0 = mloop[mlooptri[i].tri[0]].v;
- const int v1 = mloop[mlooptri[i].tri[1]].v;
- const int v2 = mloop[mlooptri[i].tri[2]].v;
- /*
- * Check if both edge vertices share this face
- */
- if (ELEM(e1_index, v0, v1, v2) && ELEM(e2_index, v0, v1, v2)) {
- if (i == cPoint->tri_index)
- continue;
+ const float *s_uv1, *s_uv2, *t_uv1, *t_uv2;
- target_tri = i;
+ pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w;
+ pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h;
- /* Get edge UV index */
- target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
- target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
- break;
- }
- }
+ /*
+ * Find closest edge to that pixel
+ */
- /* If none found pixel is on mesh edge */
- if (target_tri == -1)
- return ON_MESH_EDGE;
+ /* Dist to first edge */
+ e1_index = cPoint->v1;
+ e2_index = cPoint->v2;
+ edge1_index = 0;
+ edge2_index = 1;
+ dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv);
+
+ /* Dist to second edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v2;
+ e2_index = cPoint->v3;
+ edge1_index = 1;
+ edge2_index = 2;
+ dist_squared = t_dist_squared;
+ }
- /*
- * If target face is connected in UV space as well, just use original index
- */
- s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
- s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
- t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
- t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+ /* Dist to third edge */
+ t_dist_squared = dist_squared_to_line_segment_v2(
+ pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv);
+ if (t_dist_squared < dist_squared) {
+ e1_index = cPoint->v3;
+ e2_index = cPoint->v1;
+ edge1_index = 2;
+ edge2_index = 0;
+ dist_squared = t_dist_squared;
+ }
- //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+ /*
+ * Now find another face that is linked to that edge
+ */
+ target_tri = -1;
- if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
- (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1]) ) ||
- ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
- (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]) ))
- {
- return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
+ /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */
+ for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) {
+ const int lt_index = vert_to_looptri_map[e1_index].indices[i];
+ const int v0 = mloop[mlooptri[lt_index].tri[0]].v;
+ const int v1 = mloop[mlooptri[lt_index].tri[1]].v;
+ const int v2 = mloop[mlooptri[lt_index].tri[2]].v;
+
+ BLI_assert(ELEM(e1_index, v0, v1, v2));
+
+ if (ELEM(e2_index, v0, v1, v2)) {
+ if (lt_index == cPoint->tri_index)
+ continue;
+
+ target_tri = lt_index;
+
+ /* Get edge UV index */
+ target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2);
+ target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2);
+ break;
}
+ }
+
+ /* If none found pixel is on mesh edge */
+ if (target_tri == -1)
+ return ON_MESH_EDGE;
- /*
- * Find a point that is relatively at same edge position
- * on this other face UV
- */
- lambda = closest_to_line_v2(
- closest_point, pixel,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
- mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
- CLAMP(lambda, 0.0f, 1.0f);
-
- sub_v2_v2v2(
- dir_vec,
- mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
- mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
-
- mul_v2_fl(dir_vec, lambda);
-
- copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
- add_v2_v2(pixel, dir_vec);
- pixel[0] = (pixel[0] * (float)w) - 0.5f;
- pixel[1] = (pixel[1] * (float)h) - 0.5f;
-
- final_pixel[0] = (int)floorf(pixel[0]);
- final_pixel[1] = (int)floorf(pixel[1]);
-
- /* 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)
- return OUT_OF_TEXTURE;
-
- 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))
- return NOT_FOUND;
- /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri)
- return NOT_FOUND;
-
- /* If final point is an "edge pixel", use it's "real" neighbor instead */
- if (tempPoints[final_index].neighbour_pixel != -1)
- final_index = cPoint->neighbour_pixel;
-
- return final_index;
+ /*
+ * If target face is connected in UV space as well, just use original index
+ */
+ s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv;
+ s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv;
+ t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv;
+ t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv;
+
+ //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]);
+
+ if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) &&
+ (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) ||
+ ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
+ (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
+ {
+ return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
}
+
+ /*
+ * Find a point that is relatively at same edge position
+ * on this other face UV
+ */
+ lambda = closest_to_line_v2(
+ closest_point, pixel,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv,
+ mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv);
+ CLAMP(lambda, 0.0f, 1.0f);
+
+ sub_v2_v2v2(
+ dir_vec,
+ mloopuv[mlooptri[target_tri].tri[target_uv2]].uv,
+ mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+
+ mul_v2_fl(dir_vec, lambda);
+
+ copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
+ add_v2_v2(pixel, dir_vec);
+ pixel[0] = (pixel[0] * (float)w) - 0.5f;
+ pixel[1] = (pixel[1] * (float)h) - 0.5f;
+
+ final_pixel[0] = (int)floorf(pixel[0]);
+ final_pixel[1] = (int)floorf(pixel[1]);
+
+ /* 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)
+ return OUT_OF_TEXTURE;
+
+ 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))
+ return NOT_FOUND;
+ /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
+ if (tempPoints[final_index].tri_index != target_tri)
+ return NOT_FOUND;
+
+ /* If final point is an "edge pixel", use it's "real" neighbor instead */
+ if (tempPoints[final_index].neighbour_pixel != -1)
+ final_index = cPoint->neighbour_pixel;
+
+ return final_index;
}
}
-/*
- * Create a surface for uv image sequence format
- */
-int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
+int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update)
{
/* Antialias jitter point relative coords */
- const float jitter5sample[10] = {
- 0.0f, 0.0f,
- -0.2f, -0.4f,
- 0.2f, 0.4f,
- 0.4f, -0.2f,
- -0.4f, 0.3f,
- };
- int ty;
- int w, h;
- int tottri;
+ const int aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
- int active_points = 0;
+ uint32_t active_points = 0;
bool error = false;
PaintSurfaceData *sData;
@@ -2190,7 +2512,9 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
Bounds2D *faceBB = NULL;
int *final_index;
- int aa_samples;
+
+ *progress = 0.0f;
+ *do_update = true;
if (!dm)
return setError(canvas, N_("Canvas mesh not updated"));
@@ -2199,7 +2523,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
mloop = dm->getLoopArray(dm);
mlooptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
+ const int tottri = dm->getNumLoopTri(dm);
/* get uv map */
if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
@@ -2213,7 +2537,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (surface->image_resolution < 16 || surface->image_resolution > 8192)
return setError(canvas, N_("Invalid resolution"));
- w = h = surface->image_resolution;
+ const int w = surface->image_resolution;
+ const int h = w;
/*
* Start generating the surface
@@ -2227,16 +2552,15 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (!surface->data)
return setError(canvas, N_("Not enough free memory"));
- aa_samples = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- tempPoints = (struct PaintUVPoint *) MEM_callocN(w * h * sizeof(struct PaintUVPoint), "Temp PaintUVPoint");
+ tempPoints = MEM_callocN(w * h * sizeof(*tempPoints), "Temp PaintUVPoint");
if (!tempPoints)
error = true;
- final_index = (int *) MEM_callocN(w * h * sizeof(int), "Temp UV Final Indexes");
+ final_index = MEM_callocN(w * h * sizeof(*final_index), "Temp UV Final Indexes");
if (!final_index)
error = true;
- tempWeights = (struct Vec3f *) MEM_mallocN(w * h * aa_samples * sizeof(struct Vec3f), "Temp bWeights");
+ tempWeights = MEM_mallocN(w * h * aa_samples * sizeof(*tempWeights), "Temp bWeights");
if (!tempWeights)
error = true;
@@ -2245,103 +2569,37 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
* the pixel-inside-a-face search.
*/
if (!error) {
- faceBB = (struct Bounds2D *) MEM_mallocN(tottri * sizeof(struct Bounds2D), "MPCanvasFaceBB");
+ faceBB = MEM_mallocN(tottri * sizeof(*faceBB), "MPCanvasFaceBB");
if (!faceBB)
error = true;
}
- if (!error) {
- for (ty = 0; ty < tottri; ty++) {
- int i;
+ *progress = 0.01f;
+ *do_update = true;
- copy_v2_v2(faceBB[ty].min, mloopuv[mlooptri[ty].tri[0]].uv);
- copy_v2_v2(faceBB[ty].max, mloopuv[mlooptri[ty].tri[0]].uv);
+ 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 (i = 1; i < 3; i++) {
- minmax_v2v2_v2(faceBB[ty].min, faceBB[ty].max, mloopuv[mlooptri[ty].tri[i]].uv);
+ for (int j = 1; j < 3; j++) {
+ minmax_v2v2_v2(faceBB[i].min, faceBB[i].max, mloopuv[mlooptri[i].tri[j]].uv);
}
}
- /* Loop through every pixel and check if pixel is uv-mapped on a canvas face. */
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int i, sample;
- 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 (sample = 0; sample < 5; sample++) {
- /* Loop through every face in the mesh */
- for (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];
+ *progress = 0.02f;
+ *do_update = true;
- /* 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;
+ /* 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,
+ };
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_direct_cb, h > 64 || tottri > 1000);
- sample = 5; /* make sure we exit sample loop as well */
- break;
- }
- }
- } /* sample loop */
- }
- }
+ *progress = 0.04f;
+ *do_update = true;
/*
* Now loop through every pixel that was left without index
@@ -2349,84 +2607,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
* If so use that polygon as pixel surface.
* (To avoid seams on uv island edges)
*/
-#pragma omp parallel for schedule(static)
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = (&tempPoints[index]);
-
- /* If point isn't't on canvas mesh */
- if (tPoint->tri_index == -1) {
- int u_min, u_max, v_min, v_max;
- int u, v, ind;
- float point[2];
-
- /* get loop area */
- u_min = (tx > 0) ? -1 : 0;
- u_max = (tx < (w - 1)) ? 1 : 0;
- v_min = (ty > 0) ? -1 : 0;
- 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 */
- for (u = u_min; u <= u_max; u++)
- for (v = v_min; v <= v_max; v++) {
- /* if not this pixel itself */
- if (u != 0 || v != 0) {
- ind = (tx + u) + w * (ty + v);
-
- /* if neighbor has index */
- if (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;
-
- /* 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);
- }
-
- /* Set values */
- tPoint->neighbour_pixel = ind; /* tri index */
+ data.active_points = &active_points;
+ BLI_task_parallel_range(0, h, &data, dynamic_paint_create_uv_surface_neighbor_cb, h > 64);
- /* 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;
-
- u = u_max + 1; /* make sure we exit outer loop as well */
- break;
- }
- }
- }
- }
- }
- }
-
- /*
- * When base loop is over convert found neighbor indexes to real ones
- * Also count the final number of active surface points
- */
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
- PaintUVPoint *tPoint = &tempPoints[index];
-
- if (tPoint->tri_index == -1 && tPoint->neighbour_pixel != -1)
- tPoint->tri_index = tempPoints[tPoint->neighbour_pixel].tri_index;
- if (tPoint->tri_index != -1)
- active_points++;
- }
- }
+ *progress = 0.06f;
+ *do_update = true;
/* Generate surface adjacency data. */
{
@@ -2446,21 +2631,27 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (sData->adj_data) {
PaintAdjData *ed = sData->adj_data;
- unsigned int n_pos = 0;
- for (ty = 0; ty < h; ty++) {
- int tx;
- for (tx = 0; tx < w; tx++) {
- int index = tx + w * ty;
+ 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,
+ dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+
+ 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;
for (int i = 0; i < 8; i++) {
-
- /* Try to find a neighboring pixel in defined direction
- * If not found, -1 is returned */
- int n_target = dynamicPaint_findNeighbourPixel(tempPoints, dm, uvname, w, h, tx, ty, 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) {
ed->n_target[n_pos] = final_index[n_target];
@@ -2474,47 +2665,50 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
}
}
}
+
+ MEM_freeN(vert_to_looptri_map);
+ MEM_freeN(vert_to_looptri_map_mem);
}
}
+ *progress = 0.08f;
+ *do_update = true;
+
/* Create final surface data without inactive points */
- {
- ImgSeqFormatData *f_data = MEM_callocN(sizeof(struct ImgSeqFormatData), "ImgSeqFormatData");
- if (f_data) {
- f_data->uv_p = MEM_callocN(active_points * sizeof(struct PaintUVPoint), "PaintUVPoint");
- f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(struct Vec3f), "PaintUVPoint");
+ 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 {
+ if (!f_data->uv_p || !f_data->barycentricWeights)
error = 1;
- }
+ }
+ else {
+ error = 1;
+ }
- sData->total_points = active_points;
-
- /* 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);
- }
+ /* 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);
}
- else {
- int index, cursor = 0;
- sData->total_points = active_points;
- sData->format_data = f_data;
-
- for (index = 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(Vec3f) * aa_samples);
- cursor++;
- }
+ 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++;
}
}
}
@@ -2539,7 +2733,6 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* -----------------------------------------------------------------
* For debug, output pixel statuses to the color map
* -----------------------------------------------------------------*/
-#pragma omp parallel for schedule(static)
for (index = 0; index < sData->total_points; index++) {
ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
PaintUVPoint *uvPoint = &((PaintUVPoint *)f_data->uv_p)[index];
@@ -2550,29 +2743,116 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
if (uvPoint->neighbour_pixel != -1)
pPoint->color[2] = 1.0f;
/* and every pixel that finally got an polygon gets red color */
- if (uvPoint->tri_index != -1)
- pPoint->color[0] = 1.0f;
/* green color shows pixel face index hash */
- if (uvPoint->tri_index != -1)
+ 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);
}
+ *progress = 0.09f;
+ *do_update = true;
+
return (error == 0);
}
/*
* Outputs an image file from uv surface data.
*/
+typedef struct DynamicPaintOutputSurfaceImageData {
+ const DynamicPaintSurface *surface;
+ ImBuf *ibuf;
+} DynamicPaintOutputSurfaceImageData;
+
+static void dynamic_paint_output_surface_image_paint_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ 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;
+
+ /* 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]);
+ }
+}
+
+static void dynamic_paint_output_surface_image_displace_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ 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;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
+ 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;
+}
+
+static void dynamic_paint_output_surface_image_wave_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ 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;
+
+ if (surface->depth_clamp)
+ depth /= surface->depth_clamp;
+
+ 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;
+}
+
+static void dynamic_paint_output_surface_image_wetmap_cb(void *userdata, const int index)
+{
+ const DynamicPaintOutputSurfaceImageData *data = userdata;
+
+ 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;
+
+ 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)
{
- int index;
ImBuf *ibuf = NULL;
PaintSurfaceData *sData = surface->data;
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_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];
@@ -2600,74 +2880,66 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
return;
}
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int pos = f_data->uv_p[index].pixel_index * 4; /* image buffer position */
-
- /* Set values of preferred type */
- if (output_layer == 1) {
- /* wetmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
- float value = (point->wetness > 1.0f) ? 1.0f : point->wetness;
-
- copy_v3_fl(&ibuf->rect_float[pos], value);
- ibuf->rect_float[pos + 3] = 1.0f;
- }
- }
- else if (output_layer == 0) {
- /* Paintmap */
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- PaintPoint *point = &((PaintPoint *)sData->type_data)[index];
-
- /* 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]);
- }
+ DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf};
+ switch(surface->type) {
+ case MOD_DPAINT_SURFACE_T_PAINT:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_paint_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wetmap_cb, sData->total_points > 10000);
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* displace */
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- float depth = ((float *)sData->type_data)[index];
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
-
- if (surface->disp_type == MOD_DPAINT_DISP_DISPLACE) {
- 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;
+ break;
+ case MOD_DPAINT_SURFACE_T_DISPLACE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_displace_cb, sData->total_points > 10000);
+ break;
+ case 1:
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
- /* waves */
- else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- float depth = wPoint->height;
- if (surface->depth_clamp)
- depth /= surface->depth_clamp;
- 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;
+ break;
+ case MOD_DPAINT_SURFACE_T_WAVE:
+ switch (output_layer) {
+ case 0:
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_output_surface_image_wave_cb, sData->total_points > 10000);
+ 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 */
- ibuf->ftype = IMB_FTYPE_PNG;
- ibuf->foptions.quality = 15;
-
#ifdef WITH_OPENEXR
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);
@@ -2733,7 +3005,7 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
* Get material diffuse color and alpha (including linked textures) in given coordinates
*/
static void dynamicPaint_doMaterialTex(
- BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
+ const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
const float volume_co[3], const float surface_co[3],
int triIndex, DerivedMesh *orcoDm)
{
@@ -2834,15 +3106,15 @@ static void mesh_tris_nearest_point_dp(void *userdata, int index, const float co
* operations when using substeps
*/
static void dynamicPaint_mixPaintColors(
- DynamicPaintSurface *surface, int index, int paintFlags,
- const float paintColor[3], float *paintAlpha, float *paintWetness, float *timescale)
+ 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));
+ 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);
@@ -2851,11 +3123,11 @@ static void dynamicPaint_mixPaintColors(
/* mix wetness and alpha depending on selected alpha mode */
if (paintFlags & MOD_DPAINT_ABS_ALPHA) {
/* update values to the brush level unless theyre higher already */
- CLAMP_MIN(pPoint->e_color[3], *paintAlpha);
- CLAMP_MIN(pPoint->wetness, *paintWetness);
+ CLAMP_MIN(pPoint->e_color[3], paintAlpha);
+ CLAMP_MIN(pPoint->wetness, paintWetness);
}
else {
- float wetness = (*paintWetness);
+ float wetness = paintWetness;
CLAMP(wetness, 0.0f, 1.0f);
pPoint->e_color[3] = mix[3];
pPoint->wetness = pPoint->wetness * (1.0f - wetness) + wetness;
@@ -2869,7 +3141,7 @@ static void dynamicPaint_mixPaintColors(
else {
float a_ratio, a_highest;
float wetness;
- float invFact = 1.0f - (*paintAlpha);
+ float invFact = 1.0f - paintAlpha;
/*
* Make highest alpha to match erased value
@@ -2885,48 +3157,57 @@ static void dynamicPaint_mixPaintColors(
}
}
else {
- pPoint->e_color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->e_color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->e_color[3], 0.0f);
- pPoint->color[3] -= (*paintAlpha) * (*timescale);
+ pPoint->color[3] -= paintAlpha * timescale;
CLAMP_MIN(pPoint->color[3], 0.0f);
}
- wetness = (1.0f - (*paintWetness)) * pPoint->e_color[3];
+ 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, DynamicPaintBrushSettings *brush, float isect_height)
+static void dynamicPaint_mixWaveHeight(
+ PaintWavePoint *wPoint, const DynamicPaintBrushSettings *brush, float isect_height)
{
- float isect_change = isect_height - wPoint->brush_isect;
+ 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 *= brush->wave_factor;
+ isect_height *= wave_factor;
/* determine hit depending on wave_factor */
- if (brush->wave_factor > 0.0f && wPoint->height > isect_height)
+ if (wave_factor > 0.0f && wPoint->height > isect_height)
hit = true;
- else if (brush->wave_factor < 0.0f && wPoint->height < isect_height)
+ else if (wave_factor < 0.0f && wPoint->height < isect_height)
hit = true;
if (hit) {
- if (brush->wave_type == MOD_DPAINT_WAVEB_DEPTH) {
- wPoint->height = isect_height;
- wPoint->state = DPAINT_WAVE_OBSTACLE;
- wPoint->velocity = 0.0f;
- }
- else if (brush->wave_type == MOD_DPAINT_WAVEB_FORCE)
- wPoint->velocity = isect_height;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_REFLECT)
- wPoint->state = DPAINT_WAVE_REFLECT_ONLY;
- else if (brush->wave_type == MOD_DPAINT_WAVEB_CHANGE) {
- if (isect_change < 0.0f)
- wPoint->height += isect_change * brush->wave_factor;
+ 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;
}
}
}
@@ -2935,8 +3216,8 @@ static void dynamicPaint_mixWaveHeight(PaintWavePoint *wPoint, DynamicPaintBrush
* add brush results to the surface data depending on surface type
*/
static void dynamicPaint_updatePointData(
- DynamicPaintSurface *surface, unsigned int index, DynamicPaintBrushSettings *brush,
- float paint[3], float influence, float depth, float vel_factor, float timescale)
+ 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;
@@ -2970,7 +3251,7 @@ static void dynamicPaint_updatePointData(
float paintWetness = brush->wetness * strength;
float paintAlpha = strength;
- dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, &paintAlpha, &paintWetness, &timescale);
+ dynamicPaint_mixPaintColors(surface, index, brush->flags, paint, paintAlpha, paintWetness, timescale);
}
/* displace surface */
else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
@@ -3029,10 +3310,47 @@ static bool meshBrush_boundsIntersect(Bounds3D *b1, Bounds3D *b2, DynamicPaintBr
}
/* calculate velocity for mesh vertices */
+typedef struct DynamicPaintBrushVelocityData {
+ Vec3f *brush_vel;
+
+ const MVert *mvert_p;
+ const MVert *mvert_c;
+
+ float (*obmat)[4];
+ float (*prev_obmat)[4];
+
+ const float timescale;
+} DynamicPaintBrushVelocityData;
+
+static void dynamic_paint_brush_velocity_compute_cb(void *userdata, const int i)
+{
+ const DynamicPaintBrushVelocityData *data = userdata;
+
+ Vec3f *brush_vel = data->brush_vel;
+
+ 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;
+
+ const float timescale = data->timescale;
+
+ float p1[3], p2[3];
+
+ 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);
+
+ sub_v3_v3v3(brush_vel[i].v, p2, p1);
+ mul_v3_fl(brush_vel[i].v, 1.0f / timescale);
+}
+
static void dynamicPaint_brushMeshCalculateVelocity(
Scene *scene, Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
- int i;
float prev_obmat[4][4];
DerivedMesh *dm_p, *dm_c;
MVert *mvert_p, *mvert_c;
@@ -3073,25 +3391,17 @@ static void dynamicPaint_brushMeshCalculateVelocity(
if (!(*brushVel))
return;
- /* if mesh is constructive -> num of verts has changed,
- * only use current frame derived mesh */
+ /* 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 */
-#pragma omp parallel for schedule(static)
- for (i = 0; i < numOfVerts_c; i++) {
- float p1[3], p2[3];
-
- 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(ob->obmat, p2);
-
- sub_v3_v3v3((*brushVel)[i].v, p2, p1);
- mul_v3_fl((*brushVel)[i].v, 1.0f / timescale);
- }
+ DynamicPaintBrushVelocityData data = {
+ .brush_vel = *brushVel,
+ .mvert_p = mvert_p, .mvert_c = mvert_c, .obmat = ob->obmat, .prev_obmat = prev_obmat,
+ .timescale = timescale,
+ };
+ BLI_task_parallel_range(0, numOfVerts_c, &data, dynamic_paint_brush_velocity_compute_cb, numOfVerts_c > 10000);
dm_p->release(dm_p);
}
@@ -3133,9 +3443,366 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
mul_v3_fl(brushVel->v, 1.0f / timescale);
}
+typedef struct DynamicPaintPaintData {
+ const DynamicPaintSurface *surface;
+ const DynamicPaintBrushSettings *brush;
+ Object *brushOb;
+ const BrushMaterials *bMats;
+ const Scene *scene;
+ const float timescale;
+ const int c_index;
+
+ DerivedMesh *dm;
+ 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 *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+{
+ 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;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
+
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
+
+ DerivedMesh *dm = data->dm;
+ 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 &&
+ do_colorband(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[4];
+ 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_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, 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;
+
+ /* Get material+textures color on hit point if required */
+ if (brush_usesMaterial(brush, scene)) {
+ dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index] + ss].v,
+ hitCoord, hitTri, dm);
+ }
+
+ /* 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(DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
@@ -3160,7 +3827,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
{
BVHTreeFromMesh treeData = {NULL};
float avg_brushNor[3] = {0.0f};
- float brush_radius = brush->paint_distance * surface->radius_scale;
+ const float brush_radius = brush->paint_distance * surface->radius_scale;
int numOfVerts;
int ii;
Bounds3D mesh_bb = {0};
@@ -3207,8 +3874,6 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
/* loop through space partitioning grid */
for (c_index = 0; c_index < total_cells; c_index++) {
- int id;
-
/* check grid cell bounding box */
if (!grid->s_num[c_index] ||
!meshBrush_boundsIntersect(&grid->bounds[c_index], &mesh_bb, brush, brush_radius))
@@ -3217,335 +3882,203 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
}
/* loop through cell points and process brush */
-#pragma omp parallel for schedule(static)
- for (id = 0; id < grid->s_num[c_index]; id++) {
- int index = grid->t_index[grid->s_pos[c_index] + id];
- int ss, samples = bData->s_num[index];
- 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};
- int 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 (brush->collision == MOD_DPAINT_COL_VOLUME || brush->collision == 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) {
- float dist = hit.dist;
- 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;
- }
- }
- }
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale, .c_index = c_index,
+ .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
+ .treeData = &treeData
+ };
+ BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
+ dynamic_paint_paint_mesh_cell_point_cb_ex,
+ grid->s_num[c_index] > 250, true);
+ }
+ }
+ }
+ /* free bvh tree */
+ free_bvhtree_from_mesh(&treeData);
+ dm->release(dm);
- /* Check proximity collision */
- if ((brush->collision == MOD_DPAINT_COL_DIST || brush->collision == 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;
- }
- }
+ /* free brush velocity data */
+ if (brushVelocity)
+ MEM_freeN(brushVelocity);
- /* 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;
+ return 1;
+}
- hit_found = HIT_PROXIMITY;
+/*
+ * Paint a particle system to the surface
+ */
+static void dynamic_paint_paint_particle_cell_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int id, const int UNUSED(threadid))
+{
+ const DynamicPaintPaintData *data = userdata;
- /* if no volume hit, use prox point face info */
- if (hitTri == -1) {
- copy_v3_v3(hitCoord, hitCo);
- hitTri = tri;
- }
- }
- }
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
+ VolumeGrid *grid = bData->grid;
- /* 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;
- }
+ const DynamicPaintBrushSettings *brush = data->brush;
- /* 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 &&
- do_colorband(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;
- }
+ const ParticleSystem *psys = data->psys;
- sampleStrength *= sample_factor;
- }
- else {
- continue;
- }
+ const float timescale = data->timescale;
+ const int c_index = data->c_index;
- /* velocity brush, only do on main sample */
- if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) {
- int v1, v2, v3;
- float weights[4];
- float brushPointVelocity[3];
- float velocity[3];
-
- v1 = mloop[mlooptri[hitTri].tri[0]].v;
- v2 = mloop[mlooptri[hitTri].tri[1]].v;
- v3 = mloop[mlooptri[hitTri].tri[2]].v;
-
- /* calculate barycentric weights for hit point */
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, 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 = len_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);
- mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
+ KDTree *tree = data->treeData;
- /*
- * 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;
-
- /* Get material+textures color on hit point if required */
- if (brush_usesMaterial(brush, scene)) {
- dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index] + ss].v,
- hitCoord, hitTri, dm);
- }
+ 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;
- /* 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];
- }
- }
+ 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;
- /* Add AA sample */
- paintColor[0] += sampleColor[0];
- paintColor[1] += sampleColor[1];
- paintColor[2] += sampleColor[2];
- sampleStrength *= alpha_factor;
- numOfHits++;
- }
+ /*
+ * With predefined radius, there is no variation between particles.
+ * It's enough to just find the nearest one.
+ */
+ {
+ KDTreeNearest nearest;
+ float smooth_range, part_solidradius;
- /* apply sample strength */
- brushStrength += sampleStrength;
- } // end supersampling
+ /* Find nearest particle and get distance to it */
+ BLI_kdtree_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 *nearest;
- /* 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);
+ 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;
- 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 (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- depth /= bData->bNormal[index].normal_scale * total_sample;
- }
+ const int particles = BLI_kdtree_range_search(
+ tree, bData->realCoord[bData->s_pos[index]].v, &nearest, max_range);
- dynamicPaint_updatePointData(surface, index, brush, paintColor,
- brushStrength, depth, velocity_val, timescale);
- }
- }
- }
+ /* 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;
}
}
- /* free bvh tree */
- free_bvhtree_from_mesh(&treeData);
- dm->release(dm);
+ 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;
}
- /* free brush velocity data */
- if (brushVelocity)
- MEM_freeN(brushVelocity);
+ if (strength > 0.001f) {
+ float paintColor[4] = {0.0f};
+ float depth = 0.0f;
+ float velocity_val = 0.0f;
- return 1;
+ /* 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);
+ }
}
-/*
- * Paint a particle system to the surface
- */
static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
ParticleSystem *psys,
DynamicPaintBrushSettings *brush,
@@ -3554,19 +4087,18 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
ParticleSettings *part = psys->part;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- VolumeGrid *grid = bData->grid;
+ VolumeGrid *grid = bData->grid;
KDTree *tree;
int particlesAdded = 0;
int invalidParticles = 0;
int p = 0;
- float solidradius = surface->radius_scale *
- ((brush->flags & MOD_DPAINT_PART_RAD) ? psys->part->size : brush->particle_radius);
- float smooth = brush->particle_smooth * surface->radius_scale;
+ 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;
- float range = solidradius + smooth;
- float particle_timestep = 0.04f * part->timetweak;
+ const float range = solidradius + smooth;
Bounds3D part_bb = {0};
@@ -3623,14 +4155,12 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
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_balance(tree);
/* loop through space partitioning grid */
for (c_index = 0; c_index < total_cells; c_index++) {
- int id;
-
/* check cell bounding box */
if (!grid->s_num[c_index] ||
!boundsIntersectDist(&grid->bounds[c_index], &part_bb, range))
@@ -3639,297 +4169,199 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
}
/* loop through cell points */
-#pragma omp parallel for schedule(static)
- for (id = 0; id < grid->s_num[c_index]; id++) {
- int index = grid->t_index[grid->s_pos[c_index] + id];
- float disp_intersect = 0.0f;
- float radius = 0.0f;
- float strength = 0.0f;
- float velocity_val = 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 nearest;
- float smooth_range, part_solidradius;
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .psys = psys,
+ .solidradius = solidradius, .timescale = timescale, .c_index = c_index,
+ .treeData = tree,
+ };
+ BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0,
+ dynamic_paint_paint_particle_cell_point_cb_ex,
+ grid->s_num[c_index] > 250, true);
+ }
+ }
+ BLI_end_threaded_malloc();
+ BLI_kdtree_free(tree);
- /* Find nearest particle and get distance to it */
- BLI_kdtree_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)
- continue;
+ return 1;
+}
- 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 = (nearest.dist - part_solidradius);
- if (smooth_range < 0.0f) smooth_range = 0.0f;
- /* 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 *nearest;
-
- int n, particles;
- float smooth_range = smooth * (1.0f - strength), dist;
- /* calculate max range that can have particles with higher influence than the nearest one */
- float max_range = smooth - strength * smooth + solidradius;
- /* Make gcc happy! */
- dist = max_range;
-
- particles = BLI_kdtree_range_search(tree, bData->realCoord[bData->s_pos[index]].v,
- &nearest, max_range);
-
- /* Find particle that produces highest influence */
- for (n = 0; n < particles; n++) {
- ParticleData *pa = psys->particles + nearest[n].index;
- float s_range;
-
- /* skip if out of range */
- if (nearest[n].dist > (pa->size + smooth))
- continue;
-
- /* update hit data */
- 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) &&
- (surface->type != MOD_DPAINT_SURFACE_T_DISPLACE) &&
- (surface->type != MOD_DPAINT_SURFACE_T_WAVE))
- {
- break;
- }
- }
+/* paint a single point of defined proximity radius to the surface */
+static void dynamic_paint_paint_single_point_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int index, const int UNUSED(threadid))
+{
+ const DynamicPaintPaintData *data = userdata;
- if (nearest) MEM_freeN(nearest);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const PaintBakeData *bData = sData->bData;
- /* now calculate influence for this particle */
- {
- float rad = radius + smooth, str;
- if ((rad - dist) > disp_intersect) {
- disp_intersect = radius - dist;
- radius = rad;
- }
+ const DynamicPaintBrushSettings *brush = data->brush;
+ Object *brushOb = data->brushOb;
+ const BrushMaterials *bMats = data->bMats;
- /* do smoothness if enabled */
- if (smooth_range < 0.0f)
- smooth_range = 0.0f;
- if (smooth)
- smooth_range /= smooth;
- str = 1.0f - smooth_range;
- /* if influence is greater, use this one */
- if (str > strength)
- strength = str;
- }
- }
+ const Scene *scene = data->scene;
+ const float timescale = data->timescale;
- if (strength > 0.001f) {
- float paintColor[4] = {0.0f};
- float depth = 0.0f;
+ const MVert *mvert = data->mvert;
+ const float brush_radius = data->brush_radius;
+ const Vec3f *brushVelocity = data->brushVelocity;
- /* 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);
+ float *pointCoord = data->pointCoord;
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3(velocity, bData->velocity[index].v);
- }
- velocity_val = len_v3(velocity);
+ const float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
+ float colorband[4] = {0.0f};
+ float strength;
- /* 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);
- mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
+ if (distance > brush_radius)
+ return;
- if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- copy_v3_v3(paintColor, &brush->r);
- }
- else if ((surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) ||
- (surface->type == MOD_DPAINT_SURFACE_T_WAVE))
- {
- /* get displace depth */
- disp_intersect = (1.0f - sqrtf(disp_intersect / radius)) * radius;
- depth = (radius - disp_intersect) / bData->bNormal[index].normal_scale;
- if (depth < 0.0f) depth = 0.0f;
- }
-
- dynamicPaint_updatePointData(surface, index, brush, paintColor,
- strength, depth, velocity_val, timescale);
+ /* 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;
+
+ /* material */
+ if (brush_usesMaterial(brush, scene)) {
+ float alpha_factor = 1.0f;
+ float hit_coord[3];
+ /* use dummy coord of first vertex */
+ mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
+
+ dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
+ bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
+ }
+
+ /* color ramp */
+ if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
+ do_colorband(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 {
+ if (!brush_usesMaterial(brush, scene)) {
+ 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);
}
- BLI_end_threaded_malloc();
- BLI_kdtree_free(tree);
-
- return 1;
}
-/* paint a single point of defined proximity radius to the surface */
static int dynamicPaint_paintSinglePoint(
DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
{
- int index;
- float brush_radius = brush->paint_distance * surface->radius_scale;
PaintSurfaceData *sData = surface->data;
- PaintBakeData *bData = sData->bData;
+ float brush_radius = brush->paint_distance * surface->radius_scale;
Vec3f brushVel;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
dynamicPaint_brushObjectCalculateVelocity(scene, brushOb, &brushVel, timescale);
+ const MVert *mvert = brush->dm->getVertArray(brush->dm);
+
/*
* Loop through every surface point
*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float distance = len_v3v3(pointCoord, bData->realCoord[bData->s_pos[index]].v);
- float colorband[4] = {0.0f};
- float strength;
-
- if (distance > brush_radius)
- continue;
+ DynamicPaintPaintData data = {
+ .surface = surface,
+ .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .scene = scene, .timescale = timescale,
+ .mvert = mvert,
+ .brush_radius = brush_radius, .brushVelocity = &brushVel,
+ .pointCoord = pointCoord,
+ };
+ BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0,
+ dynamic_paint_paint_single_point_cb_ex,
+ sData->total_points > 1000, true);
- /* 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;
- }
+ return 1;
+}
- if (strength >= 0.001f) {
- float paintColor[3] = {0.0f};
- float depth = 0.0f;
- float velocity_val = 0.0f;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- MVert *mvert = brush->dm->getVertArray(brush->dm);
- /* use dummy coord of first vertex */
- copy_v3_v3(hit_coord, mvert[0].co);
- mul_m4_v3(brushOb->obmat, hit_coord);
-
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
- }
+/***************************** Dynamic Paint Step / Baking ******************************/
- /* color ramp */
- if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
- do_colorband(brush->paint_ramp, (1.0f - strength), colorband))
- {
- strength = colorband[3];
- }
+/*
+ * Calculate current frame distances and directions for adjacency data
+ */
- if (brush->flags & MOD_DPAINT_USES_VELOCITY) {
- float velocity[3];
+static void dynamic_paint_prepare_adjacency_cb(void *userdata, const int index)
+{
+ PaintSurfaceData *sData = userdata;
+ PaintBakeData *bData = sData->bData;
+ BakeAdjPoint *bNeighs = bData->bNeighs;
+ PaintAdjData *adj_data = sData->adj_data;
+ Vec3f *realCoord = bData->realCoord;
- /* substract canvas point velocity */
- if (bData->velocity) {
- sub_v3_v3v3(velocity, brushVel.v, bData->velocity[index].v);
- }
- else {
- copy_v3_v3(velocity, brushVel.v);
- }
- velocity_val = len_v3(velocity);
+ const int num_neighs = adj_data->n_num[index];
- /* 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);
- mul_v3_fl(&bData->brush_velocity[index * 4], 1.0f / velocity_val);
- bData->brush_velocity[index * 4 + 3] = velocity_val;
- }
- }
+ 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];
- 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 {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
- }
- }
- else if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- /* get displace depth */
- float disp_intersect = (1.0f - sqrtf((brush_radius - distance) / brush_radius)) * brush_radius;
- depth = (brush_radius - disp_intersect) / bData->bNormal[index].normal_scale;
- CLAMP_MIN(depth, 0.0f);
- }
- dynamicPaint_updatePointData(surface, index, brush, paintColor, strength, depth, velocity_val, timescale);
- }
+ /* 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);
}
-
- return 1;
}
-
-/***************************** Dynamic Paint Step / Baking ******************************/
-
-/*
- * Calculate current frame distances and directions for adjacency data
- */
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;
- Vec3f *realCoord = bData->realCoord;
+
int index;
if ((!surface_usesAdjDistance(surface) && !force_init) || !sData->adj_data)
@@ -3937,48 +4369,32 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons
if (bData->bNeighs)
MEM_freeN(bData->bNeighs);
- bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(struct BakeAdjPoint), "PaintEffectBake");
+ bNeighs = bData->bNeighs = MEM_mallocN(sData->adj_data->total_targets * sizeof(*bNeighs), "PaintEffectBake");
if (!bNeighs)
return;
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = adj_data->n_num[index];
+ BLI_task_parallel_range(
+ 0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, sData->total_points > 1000);
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = adj_data->n_index[index] + i;
- 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 = len_v3(bNeighs[n_index].dir);
- /* normalize dir */
- if (bNeighs[n_index].dist)
- mul_v3_fl(bNeighs[n_index].dir, 1.0f / bNeighs[n_index].dist);
- }
- }
-
- /* calculate average values (single thread) */
- bData->average_dist = 0.0f;
+ /* 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 i;
int numOfNeighs = adj_data->n_num[index];
- for (i = 0; i < numOfNeighs; i++) {
+ 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;
+ 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(
- PaintSurfaceData *sData, int index, float force[3], float closest_d[2], int closest_id[2])
+ const PaintSurfaceData *sData, const int index, const float force[3], float closest_d[2], int closest_id[2])
{
BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- int numOfNeighs = sData->adj_data->n_num[index];
+ const int numOfNeighs = sData->adj_data->n_num[index];
int i;
closest_id[0] = closest_id[1] = -1;
@@ -3986,8 +4402,8 @@ static void surface_determineForceTargetPoints(
/* find closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
+ 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;
@@ -4000,26 +4416,28 @@ static void surface_determineForceTargetPoints(
/* find second closest neigh */
for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dir_dot = dot_v3v3(bNeighs[n_index].dir, force);
- float closest_dot = dot_v3v3(bNeighs[n_index].dir, bNeighs[closest_id[0]].dir);
+ 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;
+ 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 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];
- float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
+ const float neigh_diff = acosf(dot_v3v3(bNeighs[closest_id[0]].dir, bNeighs[closest_id[1]].dir));
float force_intersect;
float temp;
@@ -4081,7 +4499,7 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
if (!smudge_str)
continue;
-
+
/* get force affect points */
surface_determineForceTargetPoints(sData, index, &bData->brush_velocity[index * 4], closest_d, closest_id);
@@ -4114,10 +4532,80 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
}
}
+typedef struct DynamicPaintEffectData {
+ const DynamicPaintSurface *surface;
+ Scene *scene;
+
+ float *force;
+ EffectorContext *effectors;
+ const void *prevPoint;
+ const float eff_scale;
+
+ uint8_t *point_locks;
+
+ 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;
+} DynamicPaintEffectData;
+
/*
* Prepare data required by effects for current frame.
* Returns number of steps required
*/
+static void dynamic_paint_prepare_effect_cb(void *userdata, const int index)
+{
+ 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;
+ EffectorContext *effectors = data->effectors;
+ float *force = data->force;
+
+ 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;
+ pdDoEffectors(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(
DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
@@ -4127,63 +4615,24 @@ static int dynamicPaint_prepareEffectStep(
int steps;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- Vec3f *realCoord = bData->realCoord;
- int index;
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- float vel[3] = {0};
- EffectorContext *effectors;
-
- effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
+ EffectorContext *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
if (*force) {
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float forc[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;
- pdDoEffectors(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 */
- (*force)[index * 4 + 3] = len_v3(forc);
- /* normalize and copy */
- if ((*force)[index * 4 + 3])
- mul_v3_fl(forc, 1.0f / (*force)[index * 4 + 3]);
- copy_v3_v3(&((*force)[index * 4]), forc);
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .scene = scene,
+ .force = *force, .effectors = effectors,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_prepare_effect_cb, sData->total_points > 1000);
/* calculate average values (single thread) */
- for (index = 0; index < sData->total_points; index++) {
+ for (int index = 0; index < sData->total_points; index++) {
average_force += (*force)[index * 4 + 3];
}
average_force /= sData->total_points;
@@ -4203,7 +4652,7 @@ static int dynamicPaint_prepareEffectStep(
fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData);
- steps = (int)ceil(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
+ steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
CLAMP(steps, 1, 20);
return steps;
@@ -4212,13 +4661,185 @@ static int dynamicPaint_prepareEffectStep(
/**
* Processes active effect step.
*/
+static void dynamic_paint_effect_spread_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ 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 = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->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 *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+
+ 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 *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
+
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ 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);
+
+ /* 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 eficient than a global spin lock. */
+ const unsigned int pointlock_idx = n_trgt / 8;
+ const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */
+ while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_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 */
+ pPoint->wetness -= (ePoint->wetness - e_wet);
+ CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
+
+#ifndef NDEBUG
+ uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+ BLI_assert(ret & pointlock_bitmask);
+#else
+ atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask);
+#endif
+ }
+ }
+}
+
static void dynamicPaint_doEffectStep(
DynamicPaintSurface *surface, float *force, PaintPoint *prevPoint, float timescale, float steps)
{
PaintSurfaceData *sData = surface->data;
- BakeAdjPoint *bNeighs = sData->bData->bNeighs;
- float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
- int index;
+
+ const float distance_scale = getSurfaceDimension(sData) / CANVAS_REL_SIZE;
timescale /= steps;
if (!sData->adj_data)
@@ -4228,159 +4849,149 @@ static void dynamicPaint_doEffectStep(
* Spread Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SPREAD) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->spread_speed * timescale;
+ 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));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- /* Only reads values from the surface copy (prevPoint[]),
- * so this one is thread safe */
-
- /* Loop through neighboring points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float w_factor;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
- float color_mix = (MIN3(ePoint->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], ePoint->e_color, ePoint->e_color[3], color_mix);
-
- /* Only continue if surrounding point has higher wetness */
- if (ePoint->wetness < pPoint->wetness || ePoint->wetness < MIN_WETNESS)
- continue;
-
- w_factor = 1.0f / numOfNeighs * MIN2(ePoint->wetness, 1.0f) * speed_scale;
- CLAMP(w_factor, 0.0f, 1.0f);
-
- /* mix new wetness and color */
- pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * ePoint->wetness;
- pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3], ePoint->e_color, ePoint->e_color[3],
- w_factor);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_spread_cb, sData->total_points > 1000);
}
/*
* Shrink Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_SHRINK) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * surface->shrink_speed * timescale;
+ 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));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- int i;
- int numOfNeighs = sData->adj_data->n_num[index];
- float totalAlpha = 0.0f;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
-
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float speed_scale = (bNeighs[n_index].dist < eff_scale) ? 1.0f : eff_scale / bNeighs[n_index].dist;
- PaintPoint *ePoint = &prevPoint[sData->adj_data->n_target[n_index]];
- float a_factor, ea_factor, w_factor;
-
- totalAlpha += ePoint->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 = (1.0f - ePoint->color[3]) / numOfNeighs * (pPoint->color[3] - ePoint->color[3]) * speed_scale;
- CLAMP_MIN(a_factor, 0.0f);
- /* decrease factor for wet paint alpha */
- ea_factor = (1.0f - ePoint->e_color[3]) / 8 * (pPoint->e_color[3] - ePoint->e_color[3]) * speed_scale;
- CLAMP_MIN(ea_factor, 0.0f);
- /* decrease factor for paint wetness */
- w_factor = (1.0f - ePoint->wetness) / 8 * (pPoint->wetness - ePoint->wetness) * speed_scale;
- CLAMP_MIN(w_factor, 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);
- }
- }
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_shrink_cb, sData->total_points > 1000);
}
/*
* Drip Effect
*/
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP && force) {
- float eff_scale = distance_scale * EFF_MOVEMENT_PER_FRAME * timescale / 2.0f;
+ 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));
- for (index = 0; index < sData->total_points; index++) {
- int i;
- PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
- PaintPoint *pPoint_prev = &prevPoint[index];
+ DynamicPaintEffectData data = {
+ .surface = surface, .prevPoint = prevPoint,
+ .eff_scale = eff_scale, .force = force,
+ .point_locks = point_locks,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_effect_drip_cb, sData->total_points > 1000);
- int closest_id[2];
- float closest_d[2];
+ MEM_freeN(point_locks);
+ }
+}
- /* adjust drip speed depending on wetness */
- float w_factor = pPoint_prev->wetness - 0.025f;
- if (w_factor <= 0)
- continue;
- CLAMP(w_factor, 0.0f, 1.0f);
+static void dynamic_paint_wave_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintEffectData *data = userdata;
- /* get force affect points */
- surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id);
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ BakeAdjPoint *bNeighs = sData->bData->bNeighs;
+ const PaintWavePoint *prevPoint = data->prevPoint;
- /* 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, a_factor;
- float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_index].dist;
- PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[sData->adj_data->n_target[n_index]];
- float e_wet = ePoint->wetness;
+ const float wave_speed = data->wave_speed;
+ const float wave_scale = data->wave_scale;
+ const float wave_max_slope = data->wave_max_slope;
- /* just skip if angle is too extreme */
- if (dir_dot <= 0.0f)
- continue;
+ const float dt = data->dt;
+ const float min_dist = data->min_dist;
+ const float damp_factor = data->damp_factor;
- dir_factor = dir_dot * MIN2(speed_scale, 1.0f) * w_factor;
- CLAMP_MAX(dir_factor, 0.5f);
-
- /* 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]);
- }
+ 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;
- /* decrease paint wetness on current point */
- pPoint->wetness -= (ePoint->wetness - e_wet);
- CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS);
- }
- }
+ 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 wasnt 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)
@@ -4390,11 +5001,11 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int index;
int steps, ss;
float dt, min_dist, damp_factor;
- float wave_speed = surface->wave_speed;
- float wave_max_slope = (surface->wave_smoothness >= 0.01f) ? (0.5f / surface->wave_smoothness) : 0.0f;
+ 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);
- float wave_scale = CANVAS_REL_SIZE / canvas_size;
+ const float wave_scale = CANVAS_REL_SIZE / canvas_size;
/* allocate memory */
PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation");
@@ -4426,172 +5037,114 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
/* copy previous frame data */
memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(PaintWavePoint));
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- 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;
- int i;
+ 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),
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_wave_step_cb, sData->total_points > 1000);
+ }
- if (wPoint->state > 0)
- continue;
+ MEM_freeN(prevPoint);
+}
- /* calculate force from surrounding points */
- for (i = 0; i < numOfNeighs; i++) {
- int n_index = sData->adj_data->n_index[index] + i;
- float dist = bNeighs[n_index].dist * wave_scale;
- PaintWavePoint *tPoint = &prevPoint[sData->adj_data->n_target[n_index]];
+/* 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)));
+}
- 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 (!(sData->adj_data->flags[sData->adj_data->n_target[n_index]] & ADJ_ON_MESH_EDGE)) {
- avg_n_height += tPoint->height;
- numOfRN++;
- }
+typedef struct DynamicPaintDissolveDryData {
+ const DynamicPaintSurface *surface;
+ const float timescale;
+} DynamicPaintDissolveDryData;
- force += (tPoint->height - wPoint->height) / (dist * dist);
- avg_height += tPoint->height;
- }
- avg_dist = (numOfN) ? avg_dist / numOfN : 0.0f;
+static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index)
+{
+ const DynamicPaintDissolveDryData *data = userdata;
- if (surface->flags & MOD_DPAINT_WAVE_OPEN_BORDERS &&
- sData->adj_data->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) {
- float max_offset = wave_max_slope * avg_dist;
- float offset = (numOfN) ? (avg_height / numOfN - wPoint->height) : 0.0f;
- if (offset > max_offset)
- wPoint->height += offset - max_offset;
- if (offset < -max_offset)
- wPoint->height += offset + max_offset;
- }
- }
- }
- }
+ const DynamicPaintSurface *surface = data->surface;
+ const PaintSurfaceData *sData = surface->data;
+ const float timescale = data->timescale;
- /* reset state */
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- PaintWavePoint *wPoint = &((PaintWavePoint *)sData->type_data)[index];
- /* if there wasnt any brush intersection, clear isect height */
- if (wPoint->state == DPAINT_WAVE_NONE) {
- wPoint->brush_isect = 0.0f;
- }
- wPoint->state = DPAINT_WAVE_NONE;
- }
+ /* 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);
- MEM_freeN(prevPoint);
-}
+ if (pPoint->wetness < surface->color_dry_threshold) {
+ dry_ratio = pPoint->wetness / p_wetness;
-/* Do dissolve and fading effects */
-static void dynamicPaint_surfacePreStep(DynamicPaintSurface *surface, float timescale)
-{
- PaintSurfaceData *sData = surface->data;
- int index;
+ /*
+ * 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);
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- /* 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 doesnt 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]));
- }
+ /* 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 doesnt 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);
+ 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;
}
}
- /* 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);
+ 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)
@@ -4603,7 +5156,6 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o
int numOfVerts = dm->getNumVerts(dm);
int i;
- bool ret = false;
if (!bData->prev_verts)
return true;
@@ -4613,24 +5165,140 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o
return true;
/* vertices */
-#pragma omp parallel for schedule(static)
for (i = 0; i < numOfVerts; i++) {
if (!equals_v3v3(bData->prev_verts[i].co, mvert[i].co)) {
- ret = true;
+ return true;
}
}
- return ret;
+ return false;
}
/* Prepare for surface step by creating PaintBakeNormal data */
+typedef struct DynamicPaintGenerateBakeData {
+ const DynamicPaintSurface *surface;
+ Object *ob;
+
+ const MVert *mvert;
+ const Vec3f *canvas_verts;
+
+ const bool do_velocity_data;
+ const bool new_bdata;
+} DynamicPaintGenerateBakeData;
+
+static void dynamic_paint_generate_bake_data_cb(void *userdata, const int index)
+{
+ 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->size);
+ 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->size);
+ 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, const Scene *scene, Object *ob)
{
PaintSurfaceData *sData = surface->data;
- PaintAdjData *adj_data = sData->adj_data;
PaintBakeData *bData = sData->bData;
DerivedMesh *dm = surface->canvas->dm;
- int index, new_bdata = 0;
+ int index;
+ bool new_bdata = false;
const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
(surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
@@ -4691,7 +5359,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
return setError(surface->canvas, N_("Not enough free memory"));
}
- new_bdata = 1;
+ new_bdata = true;
}
if (do_velocity_data && !bData->velocity) {
@@ -4707,7 +5375,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Make a transformed copy of canvas derived mesh vertices to avoid recalculation.
*/
- bData->mesh_bounds.valid = 0;
+ 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);
@@ -4717,105 +5385,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
/*
* Prepare each surface point for a new step
*/
-#pragma omp parallel for schedule(static)
- for (index = 0; index < sData->total_points; index++) {
- float prev_point[3] = {0.0f, 0.0f, 0.0f};
- 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];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
- int ss;
-
- bData->s_num[index] = (surface->flags & MOD_DPAINT_ANTIALIAS) ? 5 : 1;
- bData->s_pos[index] = index * bData->s_num[index];
-
- /* per sample coordinates */
- for (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(bData->bNormal[index].invNorm,
- n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
- 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(bData->bNormal[index].invNorm, mvert[index].no);
- mul_mat3_m4_v3(ob->obmat, bData->bNormal[index].invNorm);
- normalize_v3(bData->bNormal[index].invNorm);
- negate_v3(bData->bNormal[index].invNorm);
- }
-
- /* Prepare surface normal directional scale to easily convert
- * brush intersection amount between global and local space */
- if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE ||
- surface->type == MOD_DPAINT_SURFACE_T_WAVE)
- {
- float temp_nor[3];
- if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- normal_short_to_float_v3(temp_nor, mvert[index].no);
- normalize_v3(temp_nor);
- }
- else {
- float n1[3], n2[3], n3[3];
- ImgSeqFormatData *f_data = (ImgSeqFormatData *)sData->format_data;
- PaintUVPoint *tPoint = &((PaintUVPoint *)f_data->uv_p)[index];
-
- 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);
- }
-
- mul_v3_v3(temp_nor, ob->size);
- bData->bNormal[index].normal_scale = len_v3(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);
- }
- }
+ DynamicPaintGenerateBakeData data = {
+ .surface = surface, .ob = ob,
+ .mvert = mvert, .canvas_verts = canvas_verts,
+ .do_velocity_data = do_velocity_data, .new_bdata = new_bdata,
+ };
+ BLI_task_parallel_range(
+ 0, sData->total_points, &data, dynamic_paint_generate_bake_data_cb, sData->total_points > 1000);
MEM_freeN(canvas_verts);
@@ -4842,10 +5418,16 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
int ret = 1;
+
if (sData->total_points < 1)
return 0;
- dynamicPaint_surfacePreStep(surface, timescale);
+ if (dynamic_paint_surface_needs_dry_dissolve(surface)) {
+ DynamicPaintDissolveDryData data = {.surface = surface, .timescale = timescale};
+ BLI_task_parallel_range(0, sData->total_points, &data,
+ dynamic_paint_surface_pre_step_cb, sData->total_points > 1000);
+ }
+
/*
* Loop through surface's target paint objects and do painting
*/
@@ -5007,8 +5589,8 @@ int dynamicPaint_calculateFrame(DynamicPaintSurface *surface, Scene *scene, Obje
dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
-
+ dynamicPaint_generateBakeData(surface, scene, cObject);
+
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
int st;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 45007b327ff..911bf21b731 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -1748,6 +1748,7 @@ typedef struct StampData {
char scene[STAMP_NAME_SIZE];
char strip[STAMP_NAME_SIZE];
char rendertime[STAMP_NAME_SIZE];
+ char memory[STAMP_NAME_SIZE];
} StampData;
#undef STAMP_NAME_SIZE
@@ -1869,6 +1870,13 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
else {
stamp_data->rendertime[0] = '\0';
}
+
+ if (stats && (scene->r.stamp & R_STAMP_MEMORY)) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), do_prefix ? "Peak Memory %.2fM" : "%.2fM", stats->mem_peak);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
}
@@ -1943,6 +1951,12 @@ static void stampdata_from_template(StampData *stamp_data,
else {
stamp_data->rendertime[0] = '\0';
}
+ if (scene->r.stamp & R_STAMP_MEMORY) {
+ BLI_snprintf(stamp_data->memory, sizeof(stamp_data->memory), "Peak Memory %s", stamp_data_template->memory);
+ }
+ else {
+ stamp_data->memory[0] = '\0';
+ }
}
void BKE_image_stamp_buf(
@@ -2056,6 +2070,21 @@ void BKE_image_stamp_buf(
}
/* Top left corner, below File, Date, Rendertime */
+ if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
+ y -= h;
+
+ /* and space for background. */
+ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display,
+ 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y);
+
+ BLF_position(mono, x, y + y_ofs, 0.0);
+ BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+
+ /* the extra pixel for background. */
+ y -= BUFF_MARGIN_Y * 2;
+ }
+
+ /* Top left corner, below File, Date, Memory, Rendertime */
BLF_enable(mono, BLF_WORD_WRAP);
if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
y -= h;
@@ -2219,6 +2248,7 @@ void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCall
CALL(scene, "Scene");
CALL(strip, "Strip");
CALL(rendertime, "RenderTime");
+ CALL(memory, "Memory");
#undef CALL
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 57c02ec6329..b350e932281 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -1082,6 +1082,7 @@ void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
md->scene = scene;
+ if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index c8bb2e0e758..a472b6e5bc1 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -262,6 +262,51 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, int **r_mem,
}
/**
+ * Generates a map where the key is the edge and the value is a list of looptris that use that edge.
+ * The lists are allocated from one memory pool.
+ */
+void BKE_mesh_vert_looptri_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const MVert *UNUSED(mvert), const int totvert,
+ const MLoopTri *mlooptri, const int totlooptri,
+ const MLoop *mloop, const int UNUSED(totloop))
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
+ int *index_step;
+ const MLoopTri *mlt;
+ int i;
+
+ /* count face users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ map[mloop[mlt->tri[j]].v].count++;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign looptri-edge users */
+ for (i = 0, mlt = mlooptri; i < totlooptri; mlt++, i++) {
+ for (int j = 3; j--;) {
+ MeshElemMap *map_ele = &map[mloop[mlt->tri[j]].v];
+ map_ele->indices[map_ele->count++] = i;
+ }
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the vertex and the value is a list of edges that use that vertex as an endpoint.
* The lists are allocated from one memory pool.
*/
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 49dd0b104ab..ba890b005d8 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -284,7 +284,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
bool fix_normal = true;
for (j = 0; j < 3; j++) {
- if (!finite(mv->co[j])) {
+ if (!isfinite(mv->co[j])) {
PRINT_ERR("\tVertex %u: has invalid coordinate\n", i);
if (do_fixes) {
@@ -765,7 +765,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
for (j = 0, dw = dv->dw; j < dv->totweight; j++, dw++) {
/* note, greater than max defgroups is accounted for in our code, but not < 0 */
- if (!finite(dw->weight)) {
+ if (!isfinite(dw->weight)) {
PRINT_ERR("\tVertex deform %u, group %d has weight: %f\n", i, dw->def_nr, dw->weight);
if (do_fixes) {
dw->weight = 0.0f;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 1ba4852623c..65ee153e00b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -244,6 +244,11 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type)
mti = modifierType_getInfo(modifier_type);
+
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
+ return false;
+ }
+
if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
(ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh))))
{
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 8901b274db9..af30c1af66b 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -4225,8 +4225,8 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
/* can happen with bad pointcache or physics calculation
* since this becomes geometry, nan's and inf's crash raytrace code.
* better not allow this. */
- if ((!finite(bb->vec[0])) || (!finite(bb->vec[1])) || (!finite(bb->vec[2])) ||
- (!finite(bb->vel[0])) || (!finite(bb->vel[1])) || (!finite(bb->vel[2])) )
+ if ((!isfinite(bb->vec[0])) || (!isfinite(bb->vec[1])) || (!isfinite(bb->vec[2])) ||
+ (!isfinite(bb->vel[0])) || (!isfinite(bb->vel[1])) || (!isfinite(bb->vel[2])) )
{
zero_v3(bb->vec);
zero_v3(bb->vel);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 27abbb62762..d307ba1811b 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -545,7 +545,7 @@ void BKE_scene_init(Scene *sce)
sce->r.bake.im_format.compress = 15;
sce->r.scemode = R_DOCOMP | R_DOSEQ | R_EXTENSION;
- sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME;
+ sce->r.stamp = R_STAMP_TIME | R_STAMP_FRAME | R_STAMP_DATE | R_STAMP_CAMERA | R_STAMP_SCENE | R_STAMP_FILENAME | R_STAMP_RENDERTIME | R_STAMP_MEMORY;
sce->r.stamp_font_id = 12;
sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8f;
sce->r.fg_stamp[3] = 1.0f;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a84b8352417..5fd418fadfc 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -3370,13 +3370,14 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
int colType;
- const MLoopCol *mloopcol;
+ const MLoopCol *mloopcol = NULL;
MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
DMFlagMat *faceFlags = ccgdm->faceFlags;
DMDrawOption draw_option;
int i, totpoly;
bool flush;
- bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
unsigned int next_actualFace;
unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
int mat_index;
@@ -3395,15 +3396,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
+ if (use_colors) {
+ colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
+ if (!mloopcol) {
+ colType = CD_PREVIEW_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
+ if (!mloopcol) {
+ colType = CD_MLOOPCOL;
+ mloopcol = dm->getLoopDataArray(dm, colType);
+ }
}
GPU_vertex_setup(dm);