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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2534
1 files changed, 1393 insertions, 1141 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 07511e1924e..40ff662a2c2 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -38,6 +38,8 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -97,25 +99,6 @@
#include <stdlib.h>
#include <string.h>
-#ifdef _OPENMP
-#include <omp.h>
-#endif
-
-#if defined(__APPLE__) && defined _OPENMP
-#include <sys/sysctl.h>
-
-#include "BLI_threads.h"
-
-/* Query how many cores not counting HT aka physical cores we've got. */
-static int system_physical_thread_count(void)
-{
- int pcount;
- size_t pcount_len = sizeof(pcount);
- sysctlbyname("hw.physicalcpu", &pcount, &pcount_len, NULL, 0);
- return pcount;
-}
-#endif /* __APPLE__ */
-
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
@@ -159,10 +142,10 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
/**
* Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
*/
-static int sculpt_brush_needs_normal(const Brush *brush)
+static int sculpt_brush_needs_normal(const Brush *brush, float normal_weight)
{
return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
- (brush->normal_weight > 0)) ||
+ (normal_weight > 0.0f)) ||
ELEM(brush->sculpt_tool,
SCULPT_TOOL_BLOB,
@@ -175,9 +158,21 @@ static int sculpt_brush_needs_normal(const Brush *brush)
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
}
-
/** \} */
+static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
+{
+ return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
+}
+
+/* Factor of brush to have rake point following behind
+ * (could be configurable but this is reasonable default). */
+#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
+
+struct SculptRakeData {
+ float follow_dist;
+ float follow_co[3];
+};
typedef enum StrokeFlags {
CLIP_X = 1,
@@ -198,11 +193,6 @@ typedef struct StrokeCache {
float clip_tolerance[3];
float initial_mouse[2];
- /* Pre-allocated temporary storage used during smoothing */
- int num_threads, init_num_threads;
- float (**tmpgrid_co)[3], (**tmprow_co)[3];
- float **tmpgrid_mask, **tmprow_mask;
-
/* Variants */
float radius;
float radius_squared;
@@ -214,6 +204,7 @@ typedef struct StrokeCache {
float pressure;
float mouse[2];
float bstrength;
+ float normal_weight; /* from brush (with optional override) */
/* The rest is temporary storage that isn't saved as a property */
@@ -230,6 +221,11 @@ typedef struct StrokeCache {
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
+ /* screen-space rotation defined by mouse motion */
+ float rake_rotation[4], rake_rotation_symmetry[4];
+ bool is_rake_rotation_valid;
+ struct SculptRakeData rake_data;
+
int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
* 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
@@ -350,6 +346,67 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
}
}
+static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3])
+{
+ float rake_dist = len_v3v3(srd->follow_co, co);
+ if (rake_dist > srd->follow_dist) {
+ interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
+ }
+}
+
+
+static void sculpt_rake_rotate(
+ const SculptSession *ss, const float sculpt_co[3], const float v_co[3], float factor, float r_delta[3])
+{
+ float vec_rot[3];
+
+#if 0
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
+#else
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ mul_fac_qt_fl(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
+
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+
+}
+
+/**
+ * Align the grab delta to the brush normal.
+ *
+ * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
+ */
+static void sculpt_project_v3_normal_align(SculptSession *ss, const float normal_weight, float grab_delta[3])
+{
+ /* signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+
+ /* this scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
+
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+}
+
+
/** \name SculptProjectVector
*
* Fast-path for #project_plane_v3_v3v3
@@ -419,57 +476,106 @@ static bool sculpt_stroke_is_dynamic_topology(
/*** paint mesh ***/
-static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
+/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
+typedef struct SculptThreadedTaskData {
+ Sculpt *sd;
+ Object *ob;
+ Brush *brush;
+ PBVHNode **nodes;
+ int totnode;
+
+ /* Data specific to some callbacks. */
+ /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
+ * what it is, and memory overhead is ridiculous anyway... */
+ float flippedbstrength;
+ float angle;
+ float strength;
+ bool smooth_mask;
+ bool has_bm_orco;
+
+ SculptProjectVector *spvc;
+ float *offset;
+ float *grab_delta;
+ float *cono;
+ float *area_no;
+ float *area_no_sp;
+ float *area_co;
+ float (*mat)[4];
+ float (*vertCos)[3];
+
+ /* 0=towards view, 1=flipped */
+ float (*area_cos)[3];
+ float (*area_nos)[3];
+ int *count;
+
+ ThreadMutex mutex;
+} SculptThreadedTaskData;
+
+static void paint_mesh_restore_co_task_cb(void *userdata, const int n)
{
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
- PBVHNode **nodes;
- int n, totnode;
+ SculptUndoNode *unode;
+ SculptUndoType type = (data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ if (ss->bm) {
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], type);
+ }
+ else {
+ unode = sculpt_undo_get_node(data->nodes[n]);
+ }
- /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
- * entries might be inserted by sculpt_undo_push_node() into the
- * GHash used internally by BM_log_original_vert_co() by a
- * different thread. [#33787] */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- SculptUndoNode *unode;
- SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
- SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ if (unode) {
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
- if (ss->bm) {
- unode = sculpt_undo_push_node(ob, nodes[n], type);
- }
- else {
- unode = sculpt_undo_get_node(nodes[n]);
- }
- if (unode) {
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_unode_init(&orig_data, data->ob, unode);
- sculpt_orig_vert_data_unode_init(&orig_data, ob, unode);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
- if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
- copy_v3_v3(vd.co, orig_data.co);
- if (vd.no) copy_v3_v3_short(vd.no, orig_data.no);
- else normal_short_to_float_v3(vd.fno, orig_data.no);
- }
- else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
- *vd.mask = orig_data.mask;
- }
- if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
+ copy_v3_v3(vd.co, orig_data.co);
+ if (vd.no)
+ copy_v3_v3_short(vd.no, orig_data.no);
+ else
+ normal_short_to_float_v3(vd.fno, orig_data.no);
+ }
+ else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
+ *vd.mask = orig_data.mask;
}
- BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_update(nodes[n]);
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(data->nodes[n]);
}
+}
+
+static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new entries might be inserted by
+ * sculpt_undo_push_node() into the GHash used internally by BM_log_original_vert_co() by a different thread.
+ * See T33787. */
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
+
+ BLI_task_parallel_range(
+ 0, totnode, &data, paint_mesh_restore_co_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT));
if (nodes)
MEM_freeN(nodes);
@@ -548,6 +654,7 @@ typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
+ int mirror_symmetry_pass;
/* View3d clipping - only set rv3d for clipping */
RegionView3D *clip_rv3d;
@@ -561,6 +668,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
+ test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
if (rv3d->rflag & RV3D_CLIPPING) {
test->clip_rv3d = rv3d;
@@ -573,7 +681,12 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const float co[3])
{
RegionView3D *rv3d = test->clip_rv3d;
- return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
+ if (!rv3d) {
+ return false;
+ }
+ float symm_co[3];
+ flip_v3_v3(symm_co, co, test->mirror_symmetry_pass);
+ return ED_view3d_clipping_test(rv3d, symm_co, true);
}
static bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
@@ -776,131 +889,163 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
-static void calc_area_center(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_co[3])
+static void calc_area_normal_and_center_task_cb(void *userdata, const int n)
{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- int n;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ float (*area_nos)[3] = data->area_nos;
+ float (*area_cos)[3] = data->area_cos;
- /* 0=towards view, 1=flipped */
- float area_co[2][3] = {{0.0f}};
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
- int count[2] = {0};
+ float private_co[2][3] = {{0.0f}};
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_co[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(
- nodes[n],
- &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no[3];
- int flip_index;
-
- cross_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && data->has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ if (area_cos)
add_v3_v3(private_co[flip_index], co);
- private_count[flip_index] += 1;
- }
+ if (area_nos)
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
}
}
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
}
else {
- co = vd.co;
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
}
+ }
+ else {
+ co = vd.co;
+ }
- if (sculpt_brush_test_fast(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
no = no_buf;
}
else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
+ no = vd.fno;
}
+ }
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ if (area_cos)
add_v3_v3(private_co[flip_index], co);
- private_count[flip_index] += 1;
- }
+ if (area_nos)
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
+ }
-#pragma omp critical
- {
- /* for flatten center */
- add_v3_v3(area_co[0], private_co[0]);
- add_v3_v3(area_co[1], private_co[1]);
+ BLI_mutex_lock(&data->mutex);
- /* weights */
- count[0] += private_count[0];
- count[1] += private_count[1];
- }
+ /* for flatten center */
+ if (area_cos) {
+ add_v3_v3(area_cos[0], private_co[0]);
+ add_v3_v3(area_cos[1], private_co[1]);
+ }
+
+ /* for area normal */
+ if (area_nos) {
+ add_v3_v3(area_nos[0], private_no[0]);
+ add_v3_v3(area_nos[1], private_no[1]);
}
+ /* weights */
+ data->count[0] += private_count[0];
+ data->count[1] += private_count[1];
+
+ BLI_mutex_unlock(&data->mutex);
+}
+
+static void calc_area_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_cos[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = NULL, .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
+
+ BLI_task_parallel_range(
+ 0, totnode, &data, calc_area_normal_and_center_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+
+ BLI_mutex_end(&data.mutex);
+
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
break;
}
}
@@ -921,119 +1066,25 @@ static void calc_area_normal(
int n;
/* 0=towards view, 1=flipped */
- float area_no[2][3] = {{0.0f}};
+ float area_nos[2][3] = {{0.0f}};
int count[2] = {0};
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(
- nodes[n],
- &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no[3];
- int flip_index;
-
- normal_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
-
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
- }
- else {
- co = vd.co;
- }
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
-
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
- }
- else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
- }
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
-#pragma omp critical
- {
- /* for area normal */
- add_v3_v3(area_no[0], private_no[0]);
- add_v3_v3(area_no[1], private_no[1]);
+ BLI_task_parallel_range(
+ 0, totnode, &data, calc_area_normal_and_center_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
- /* weights */
- count[0] += private_count[0];
- count[1] += private_count[1];
- }
- }
+ BLI_mutex_end(&data.mutex);
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_no); n++) {
- if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
break;
}
}
@@ -1052,128 +1103,27 @@ static void calc_area_normal_and_center(
int n;
/* 0=towards view, 1=flipped */
- float area_co[2][3] = {{0.0f}};
- float area_no[2][3] = {{0.0f}};
+ float area_cos[2][3] = {{0.0f}};
+ float area_nos[2][3] = {{0.0f}};
int count[2] = {0};
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(
- nodes[n],
- &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no[3];
- int flip_index;
-
- normal_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_co[flip_index], co);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
-
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
- }
- else {
- co = vd.co;
- }
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
-
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
- }
- else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
- }
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_co[flip_index], co);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- /* for flatten center */
- add_v3_v3(area_co[0], private_co[0]);
- add_v3_v3(area_co[1], private_co[1]);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
- /* for area normal */
- add_v3_v3(area_no[0], private_no[0]);
- add_v3_v3(area_no[1], private_no[1]);
+ BLI_task_parallel_range(
+ 0, totnode, &data, calc_area_normal_and_center_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
- /* weights */
- count[0] += private_count[0];
- count[1] += private_count[1];
- }
- }
+ BLI_mutex_end(&data.mutex);
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
break;
}
}
@@ -1182,8 +1132,8 @@ static void calc_area_normal_and_center(
}
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_no); n++) {
- if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
break;
}
}
@@ -1291,14 +1241,14 @@ static float tex_strength(SculptSession *ss, Brush *br,
const float len,
const short vno[3],
const float fno[3],
- const float mask)
+ const float mask,
+ const int thread_id)
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
MTex *mtex = &br->mtex;
float avg = 1;
float rgba[4];
- int thread_num;
if (!mtex->tex) {
avg = 1;
@@ -1341,12 +1291,7 @@ static float tex_strength(SculptSession *ss, Brush *br,
x += br->mtex.ofs[0];
y += br->mtex.ofs[1];
-#ifdef _OPENMP
- thread_num = omp_get_thread_num();
-#else
- thread_num = 0;
-#endif
- avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_num);
+ avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id);
avg += br->texture_sample_bias;
}
@@ -1678,36 +1623,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
}
}
-static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+/* Note: uses after-struct allocated mem to store actual cache... */
+typedef struct SculptDoBrushSmoothGridDataChunk {
+ size_t tmpgrid_size;
+} SculptDoBrushSmoothGridDataChunk;
+
+static void do_smooth_brush_mesh_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
PBVHVertexIter vd;
SculptBrushTest test;
-
+
CLAMP(bstrength, 0.0f, 1.0f);
sculpt_brush_test_init(ss, &test);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno,
- smooth_mask ? 0 : (vd.mask ? *vd.mask : 0.0f));
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ thread_id);
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
- CLAMP(*vd.mask, 0, 1);
+ CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
neighbor_average(ss, avg, vd.vert_indices[vd.i]);
sub_v3_v3v3(val, avg, vd.co);
- mul_v3_fl(val, fade);
- add_v3_v3(val, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
sculpt_clip(sd, ss, vd.co, val);
}
@@ -1719,36 +1676,42 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
BKE_pbvh_vertex_iter_end;
}
-static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+static void do_smooth_brush_bmesh_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
PBVHVertexIter vd;
SculptBrushTest test;
-
+
CLAMP(bstrength, 0.0f, 1.0f);
sculpt_brush_test_init(ss, &test);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno,
- smooth_mask ? 0 : *vd.mask);
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask,
+ thread_id);
if (smooth_mask) {
float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
- CLAMP(*vd.mask, 0, 1);
+ CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
bmesh_neighbor_average(avg, vd.bm_vert);
sub_v3_v3v3(val, avg, vd.co);
- mul_v3_fl(val, fade);
- add_v3_v3(val, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
sculpt_clip(sd, ss, vd.co, val);
}
@@ -1760,74 +1723,78 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
BKE_pbvh_vertex_iter_end;
}
-static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
- float bstrength, int smooth_mask)
+static void do_smooth_brush_multires_task_cb_ex(
+ void *userdata, void *userdata_chunk, const int n, const int thread_id)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptDoBrushSmoothGridDataChunk *data_chunk = userdata_chunk;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
SculptBrushTest test;
- CCGElem **griddata, *data;
+ CCGElem **griddata, *gddata;
CCGKey key;
- float (*tmpgrid_co)[3], (*tmprow_co)[3];
- float *tmpgrid_mask, *tmprow_mask;
- int v1, v2, v3, v4;
- int thread_num;
+
+ float (*tmpgrid_co)[3] = NULL;
+ float tmprow_co[2][3];
+ float *tmpgrid_mask = NULL;
+ float tmprow_mask[2];
+
BLI_bitmap * const *grid_hidden;
- int *grid_indices, totgrid, gridsize, i, x, y;
+ int *grid_indices, totgrid, gridsize;
+ int i, x, y;
sculpt_brush_test_init(ss, &test);
CLAMP(bstrength, 0.0f, 1.0f);
- BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata);
+ BKE_pbvh_node_get_grids(ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
BKE_pbvh_get_grid_key(ss->pbvh, &key);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
-#ifdef _OPENMP
- thread_num = omp_get_thread_num();
-#else
- thread_num = 0;
-#endif
- tmpgrid_co = ss->cache->tmpgrid_co[thread_num];
- tmprow_co = ss->cache->tmprow_co[thread_num];
- tmpgrid_mask = ss->cache->tmpgrid_mask[thread_num];
- tmprow_mask = ss->cache->tmprow_mask[thread_num];
+ if (smooth_mask)
+ tmpgrid_mask = (void *)(data_chunk + 1);
+ else
+ tmpgrid_co = (void *)(data_chunk + 1);
- for (i = 0; i < totgrid; ++i) {
+ for (i = 0; i < totgrid; i++) {
int gi = grid_indices[i];
const BLI_bitmap *gh = grid_hidden[gi];
- data = griddata[gi];
+ gddata = griddata[gi];
if (smooth_mask)
- memset(tmpgrid_mask, 0, sizeof(float) * gridsize * gridsize);
+ memset(tmpgrid_mask, 0, data_chunk->tmpgrid_size);
else
- memset(tmpgrid_co, 0, sizeof(float) * 3 * gridsize * gridsize);
+ memset(tmpgrid_co, 0, data_chunk->tmpgrid_size);
for (y = 0; y < gridsize - 1; y++) {
- v1 = y * gridsize;
+ const int v = y * gridsize;
if (smooth_mask) {
- tmprow_mask[0] = (*CCG_elem_offset_mask(&key, data, v1) +
- *CCG_elem_offset_mask(&key, data, v1 + gridsize));
+ tmprow_mask[0] = (*CCG_elem_offset_mask(&key, gddata, v) +
+ *CCG_elem_offset_mask(&key, gddata, v + gridsize));
}
else {
add_v3_v3v3(tmprow_co[0],
- CCG_elem_offset_co(&key, data, v1),
- CCG_elem_offset_co(&key, data, v1 + gridsize));
+ CCG_elem_offset_co(&key, gddata, v),
+ CCG_elem_offset_co(&key, gddata, v + gridsize));
}
for (x = 0; x < gridsize - 1; x++) {
- v1 = x + y * gridsize;
- v2 = v1 + 1;
- v3 = v1 + gridsize;
- v4 = v3 + 1;
+ const int v1 = x + y * gridsize;
+ const int v2 = v1 + 1;
+ const int v3 = v1 + gridsize;
+ const int v4 = v3 + 1;
if (smooth_mask) {
float tmp;
- tmprow_mask[x + 1] = (*CCG_elem_offset_mask(&key, data, v2) +
- *CCG_elem_offset_mask(&key, data, v4));
- tmp = tmprow_mask[x + 1] + tmprow_mask[x];
+ tmprow_mask[(x + 1) % 2] = (*CCG_elem_offset_mask(&key, gddata, v2) +
+ *CCG_elem_offset_mask(&key, gddata, v4));
+ tmp = tmprow_mask[(x + 1) % 2] + tmprow_mask[x % 2];
tmpgrid_mask[v1] += tmp;
tmpgrid_mask[v2] += tmp;
@@ -1837,10 +1804,10 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
else {
float tmp[3];
- add_v3_v3v3(tmprow_co[x + 1],
- CCG_elem_offset_co(&key, data, v2),
- CCG_elem_offset_co(&key, data, v4));
- add_v3_v3v3(tmp, tmprow_co[x + 1], tmprow_co[x]);
+ add_v3_v3v3(tmprow_co[(x + 1) % 2],
+ CCG_elem_offset_co(&key, gddata, v2),
+ CCG_elem_offset_co(&key, gddata, v4));
+ add_v3_v3v3(tmp, tmprow_co[(x + 1) % 2], tmprow_co[x % 2]);
add_v3_v3(tmpgrid_co[v1], tmp);
add_v3_v3(tmpgrid_co[v2], tmp);
@@ -1851,49 +1818,44 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
}
/* blend with existing coordinates */
- for (y = 0; y < gridsize; ++y) {
- for (x = 0; x < gridsize; ++x) {
+ for (y = 0; y < gridsize; y++) {
+ for (x = 0; x < gridsize; x++) {
float *co;
const float *fno;
float *mask;
- int index;
+ const int index = y * gridsize + x;
if (gh) {
- if (BLI_BITMAP_TEST(gh, y * gridsize + x))
+ if (BLI_BITMAP_TEST(gh, index))
continue;
}
- index = x + y * gridsize;
- co = CCG_elem_offset_co(&key, data, index);
- fno = CCG_elem_offset_no(&key, data, index);
- mask = CCG_elem_offset_mask(&key, data, index);
+ co = CCG_elem_offset_co(&key, gddata, index);
+ fno = CCG_elem_offset_no(&key, gddata, index);
+ mask = CCG_elem_offset_mask(&key, gddata, index);
if (sculpt_brush_test(&test, co)) {
- const float strength_mask = (smooth_mask ? 0 : *mask);
- const float fade = bstrength * tex_strength(ss, brush, co, test.dist,
- NULL, fno, strength_mask);
- float n = 1.0f / 16.0f;
-
+ const float strength_mask = (smooth_mask ? 0.0f : *mask);
+ const float fade = bstrength * tex_strength(
+ ss, brush, co, test.dist, NULL, fno, strength_mask, thread_id);
+ float f = 1.0f / 16.0f;
+
if (x == 0 || x == gridsize - 1)
- n *= 2;
-
+ f *= 2.0f;
+
if (y == 0 || y == gridsize - 1)
- n *= 2;
-
+ f *= 2.0f;
+
if (smooth_mask) {
- *mask += ((tmpgrid_mask[x + y * gridsize] * n) - *mask) * fade;
+ *mask += ((tmpgrid_mask[index] * f) - *mask) * fade;
}
else {
- float *avg, val[3];
-
- avg = tmpgrid_co[x + y * gridsize];
-
- mul_v3_fl(avg, n);
+ float *avg = tmpgrid_co[index];
+ float val[3];
+ mul_v3_fl(avg, f);
sub_v3_v3v3(val, avg, co);
- mul_v3_fl(val, fade);
-
- add_v3_v3(val, co);
+ madd_v3_v3v3fl(val, co, val, fade);
sculpt_clip(sd, ss, co, val);
}
@@ -1903,17 +1865,19 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
}
}
-static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
- float bstrength, int smooth_mask)
+static void smooth(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength, const bool smooth_mask)
{
SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
const int max_iterations = 4;
const float fract = 1.0f / max_iterations;
PBVHType type = BKE_pbvh_type(ss->pbvh);
- int iteration, n, count;
+ int iteration, count;
float last;
- CLAMP(bstrength, 0, 1);
+ CLAMP(bstrength, 0.0f, 1.0f);
count = (int)(bstrength * max_iterations);
last = max_iterations * (bstrength - count * fract);
@@ -1924,23 +1888,44 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
}
for (iteration = 0; iteration <= count; ++iteration) {
- float strength = (iteration != count) ? 1.0f : last;
+ const float strength = (iteration != count) ? 1.0f : last;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- switch (type) {
- case PBVH_GRIDS:
- do_multires_smooth_brush(sd, ss, nodes[n], strength,
- smooth_mask);
- break;
- case PBVH_FACES:
- do_mesh_smooth_brush(sd, ss, nodes[n], strength,
- smooth_mask);
- break;
- case PBVH_BMESH:
- do_bmesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask);
- break;
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .smooth_mask = smooth_mask, .strength = strength,
+ };
+
+ switch (type) {
+ case PBVH_GRIDS:
+ {
+ int gridsize;
+ size_t size;
+ SculptDoBrushSmoothGridDataChunk *data_chunk;
+
+ BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL);
+ size = (size_t)gridsize;
+ size = sizeof(float) * size * size * (smooth_mask ? 1 : 3);
+ data_chunk = MEM_mallocN(sizeof(*data_chunk) + size, __func__);
+ data_chunk->tmpgrid_size = size;
+ size += sizeof(*data_chunk);
+
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, data_chunk, size, do_smooth_brush_multires_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+
+ MEM_freeN(data_chunk);
+ break;
}
+ case PBVH_FACES:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_smooth_brush_mesh_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ break;
+ case PBVH_BMESH:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_smooth_brush_bmesh_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ break;
}
if (ss->multires)
@@ -1954,38 +1939,48 @@ static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
}
-static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void do_mask_brush_draw_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
- /* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
+ PBVHVertexIter vd;
+ SculptBrushTest test;
- sculpt_brush_test_init(ss, &test);
+ sculpt_brush_test_init(ss, &test);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- float fade = tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, 0);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no, vd.fno, 0.0f, thread_id);
- (*vd.mask) += fade * bstrength;
- CLAMP(*vd.mask, 0, 1);
+ (*vd.mask) += fade * bstrength;
+ CLAMP(*vd.mask, 0, 1);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
+ BKE_pbvh_vertex_iter_end;
}
}
+static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
+
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_mask_brush_draw_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
+
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
@@ -2001,13 +1996,44 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
+static void do_draw_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
float offset[3];
- float bstrength = ss->cache->bstrength;
- int n;
+ const float bstrength = ss->cache->bstrength;
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
@@ -2015,31 +2041,59 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .offset = offset,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_draw_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_crease_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- /* offset vertex */
- float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no,
- vd.fno, vd.mask ? *vd.mask : 0.0f);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
- mul_v3_v3fl(proxy[vd.i], offset, fade);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* first we pinch */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* then we draw */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2051,7 +2105,6 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float bstrength = ss->cache->bstrength;
float flippedbstrength, crease_correction;
float brush_alpha;
- int n;
SculptProjectVector spvc;
@@ -2076,422 +2129,532 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .spvc = &spvc, .offset = offset, .flippedbstrength = flippedbstrength,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_crease_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_pinch_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- /* offset vertex */
- const float fade = tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
- float val1[3];
- float val2[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- /* first we pinch */
- sub_v3_v3v3(val1, test.location, vd.co);
- mul_v3_fl(val1, fade * flippedbstrength);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_project_v3(&spvc, val1, val1);
+ sculpt_brush_test_init(ss, &test);
- /* then we draw */
- mul_v3_v3fl(val2, offset, fade);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float val[3];
- add_v3_v3v3(proxy[vd.i], val1, val2);
+ sub_v3_v3v3(val, test.location, vd.co);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_pinch_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_grab_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, vd.no,
- vd.fno, vd.mask ? *vd.mask : 0.0f);
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- sub_v3_v3v3(val, test.location, vd.co);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float grab_delta[3];
- int n;
- float len;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- len = len_v3(grab_delta);
-
- if (brush->normal_weight > 0) {
- mul_v3_fl(ss->cache->sculpt_normal_symm, len * brush->normal_weight);
- mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
- add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
}
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_grab_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+static void do_nudge_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *cono = data->cono;
- sculpt_brush_test_init(ss, &test);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- if (sculpt_brush_test(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(ss, brush,
- orig_data.co,
- test.dist,
- orig_data.no,
- NULL, vd.mask ? *vd.mask : 0.0f);
+ sculpt_brush_test_init(ss, &test);
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float grab_delta[3];
float tmp[3], cono[3];
- int n;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .cono = cono,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_nudge_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_snake_hook_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ?
+ (2.0f * (0.5f - brush->crease_pinch_factor) * (len_v3(grab_delta) / ss->cache->radius)) : 0.0f;
- mul_v3_v3fl(proxy[vd.i], cono, fade);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* negative pinch will inflate, helps maintain volume */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+
+ /* important to calculate based on the grabbed location (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* when reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness */
+ if (pinch > 0.0f) {
+ /* square to have even less impact for close vertices */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
}
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
+ const float bstrength = ss->cache->bstrength;
float grab_delta[3];
- int n;
- float len;
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ SculptProjectVector spvc;
- len = len_v3(grab_delta);
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
if (bstrength < 0)
negate_v3(grab_delta);
- if (brush->normal_weight > 0) {
- mul_v3_fl(ss->cache->sculpt_normal_symm, len * brush->normal_weight);
- mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
- add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
}
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ /* optionally pinch while painting */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .spvc = &spvc, .grab_delta = grab_delta,
+ };
- sculpt_brush_test_init(ss, &test);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_snake_hook_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+static void do_thumb_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float grab_delta[3];
float tmp[3], cono[3];
- int n;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .cono = cono,
+ };
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_thumb_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+static void do_rotate_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float angle = data->angle;
- sculpt_brush_test_init(ss, &test);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (sculpt_brush_test(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(ss, brush,
- orig_data.co,
- test.dist,
- orig_data.no,
- NULL, vd.mask ? *vd.mask : 0.0f);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- mul_v3_v3fl(proxy[vd.i], cono, fade);
+ sculpt_brush_test_init(ss, &test);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ float vec[3], rot[3][3];
+ const float fade = bstrength * tex_strength(
+ ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
+
static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
- float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .angle = angle,
+ };
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_rotate_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+static void do_layer_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const float *offset = data->offset;
- sculpt_brush_test_init(ss, &test);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float *layer_disp;
+ const float bstrength = ss->cache->bstrength;
+ const float lim = (bstrength < 0) ? -data->brush->height : data->brush->height;
+ /* XXX: layer brush needs conversion to proxy but its more complicated */
+ /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (sculpt_brush_test(&test, orig_data.co)) {
- float vec[3], rot[3][3];
- const float fade = bstrength * tex_strength(ss, brush,
- orig_data.co,
- test.dist,
- orig_data.no,
- NULL, vd.mask ? *vd.mask : 0.0f);
+ /* Why does this have to be thread-protected? */
+ BLI_mutex_lock(&data->mutex);
+ layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
+ BLI_mutex_unlock(&data->mutex);
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
+ sculpt_brush_test_init(ss, &test);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float *disp = &layer_disp[vd.i];
+ float val[3];
+
+ *disp += fade;
+
+ /* Don't let the displacement go past the limit */
+ if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim))
+ *disp = lim;
+
+ mul_v3_v3fl(val, offset, *disp);
+
+ if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ int index = vd.vert_indices[vd.i];
+
+ /* persistent base */
+ add_v3_v3(val, ss->layer_co[index]);
}
+ else {
+ add_v3_v3(val, orig_data.co);
+ }
+
+ sculpt_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float offset[3];
- float lim = brush->height;
- int n;
-
- if (bstrength < 0)
- lim = -lim;
mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float *layer_disp;
- /* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
-
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .offset = offset,
+ };
+ BLI_mutex_init(&data.mutex);
-#pragma omp critical
- {
- layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]);
- }
-
- sculpt_brush_test_init(ss, &test);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_layer_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BLI_mutex_end(&data.mutex);
+}
- if (sculpt_brush_test(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
- float *disp = &layer_disp[vd.i];
- float val[3];
+static void do_inflate_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
- *disp += fade;
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- /* Don't let the displacement go past the limit */
- if ((lim < 0 && *disp < lim) || (lim >= 0 && *disp > lim))
- *disp = lim;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- mul_v3_v3fl(val, offset, *disp);
+ sculpt_brush_test_init(ss, &test);
- if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- int index = vd.vert_indices[vd.i];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float val[3];
- /* persistent base */
- add_v3_v3(val, ss->layer_co[index]);
- }
- else {
- add_v3_v3(val, orig_data.co);
- }
+ if (vd.fno)
+ copy_v3_v3(val, vd.fno);
+ else
+ normal_short_to_float_v3(val, vd.no);
- sculpt_clip(sd, ss, vd.co, val);
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
-
- sculpt_brush_test_init(ss, &test);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
- float val[3];
-
- if (vd.fno) copy_v3_v3(val, vd.fno);
- else normal_short_to_float_v3(val, vd.no);
-
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_inflate_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
}
static void calc_sculpt_plane(
@@ -2619,23 +2782,61 @@ static float get_offset(Sculpt *sd, SculptSession *ss)
return rv;
}
+static void do_flatten_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, area_no, area_co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float area_no[3];
float area_co[3];
float offset = get_offset(sd, ss);
-
float displace;
-
- int n;
-
float temp[3];
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
@@ -2646,19 +2847,39 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_flatten_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_clay_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
float intr[3];
float val[3];
@@ -2667,8 +2888,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2677,8 +2901,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2686,30 +2910,18 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- float radius = ss->cache->radius;
- float offset = get_offset(sd, ss);
-
+ const bool flip = (ss->cache->bstrength < 0);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+
+ float offset = get_offset(sd, ss);
float displace;
float area_no[3];
float area_co[3];
-
- int n;
-
float temp[3];
- bool flip;
-
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
- flip = bstrength < 0;
-
- if (flip) {
- bstrength = -bstrength;
- radius = -radius;
- }
-
displace = radius * (0.25f + offset);
mul_v3_v3v3(temp, area_no, ss->cache->scale);
@@ -2718,43 +2930,63 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* add_v3_v3v3(p, ss->cache->location, area_no); */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_clay_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_clay_strips_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ float (*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
- point_plane_project(intr, vd.co, area_no, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- /* note, the normal from the vertices is ignored,
- * causes glitch with planes, see: T44390 */
- const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_cube(&test, vd.co, mat)) {
+ if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
+ float intr[3];
+ float val[3];
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ point_plane_project(intr, vd.co, area_no_sp, area_co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, ss->cache->radius * test.dist,
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2762,25 +2994,20 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- float radius = ss->cache->radius;
- float offset = get_offset(sd, ss);
-
- float displace;
+ const bool flip = (ss->cache->bstrength < 0);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = get_offset(sd, ss);
+ const float displace = radius * (0.25f + offset);;
float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
float area_no[3]; /* geometry normal */
float area_co[3];
- int n;
-
float temp[3];
float mat[4][4];
float scale[4][4];
float tmat[4][4];
- bool flip;
-
calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
@@ -2792,15 +3019,6 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
if (ss->cache->first_time)
return;
- flip = bstrength < 0;
-
- if (flip) {
- bstrength = -bstrength;
- radius = -radius;
- }
-
- displace = radius * (0.25f + offset);
-
mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
@@ -2821,44 +3039,59 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
mul_m4_m4m4(tmat, mat, scale);
invert_m4_m4(mat, tmat);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no_sp = area_no_sp, .area_co = area_co, .mat = mat,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_clay_strips_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_fill_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- point_plane_project(intr, vd.co, area_no_sp, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- /* note, the normal from the vertices is ignored,
- * causes glitch with planes, see: T44390 */
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- ss->cache->radius * test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (plane_point_side(vd.co, area_no, area_co)) {
+ float intr[3];
+ float val[3];
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ point_plane_project(intr, vd.co, area_no, area_co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2866,7 +3099,6 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float area_no[3];
@@ -2875,8 +3107,6 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float displace;
- int n;
-
float temp[3];
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
@@ -2887,42 +3117,59 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_fill_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_scrape_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side(vd.co, area_no, area_co)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- point_plane_project(intr, vd.co, area_no, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (!plane_point_side(vd.co, area_no, area_co)) {
+ float intr[3];
+ float val[3];
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ point_plane_project(intr, vd.co, area_no, area_co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2930,7 +3177,6 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float area_no[3];
@@ -2939,8 +3185,6 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float displace;
- int n;
-
float temp[3];
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
@@ -2951,42 +3195,45 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_scrape_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_gravity_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ float *offset = data->offset;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (!plane_point_side(vd.co, area_no, area_co)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
- point_plane_project(intr, vd.co, area_no, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ const float fade = tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength)
@@ -2995,7 +3242,6 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
Brush *brush = BKE_paint_brush(&sd->paint);
float offset[3]/*, area_no[3]*/;
- int n;
float gravity_vector[3];
mul_v3_v3fl(gravity_vector, ss->cache->gravity_direction, -ss->cache->radius_squared);
@@ -3005,29 +3251,14 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
-
- sculpt_brush_test_init(ss, &test);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- const float fade = tex_strength(ss, brush, vd.co, sqrtf(test.dist), vd.no,
- vd.fno, vd.mask ? *vd.mask : 0.0f);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .offset = offset,
+ };
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_gravity_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
}
@@ -3137,12 +3368,21 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
}
}
+static void do_brush_action_task_cb(void *userdata, const int n)
+{
+ SculptThreadedTaskData *data = userdata;
+
+ sculpt_undo_push_node(data->ob, data->nodes[n],
+ data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+}
+
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
SculptSearchSphereData data;
PBVHNode **nodes = NULL;
- int n, totnode;
+ int totnode;
/* Build a list of all nodes that are potentially within the brush's area of influence */
data.ss = ss;
@@ -3155,15 +3395,15 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (totnode) {
float location[3];
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- sculpt_undo_push_node(ob, nodes[n],
- brush->sculpt_tool == SCULPT_TOOL_MASK ?
- SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(nodes[n]);
- }
+ SculptThreadedTaskData task_data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
+
+ BLI_task_parallel_range(
+ 0, totnode, &task_data, do_brush_action_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
- if (sculpt_brush_needs_normal(brush))
+ if (sculpt_brush_needs_normal(brush, ss->cache->normal_weight))
update_sculpt_normal(sd, ob, nodes, totnode);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
@@ -3273,64 +3513,76 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
copy_v3_v3(me->mvert[index].co, newco);
}
-static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
+static void sculpt_combine_proxies_task_cb(void *userdata, const int n)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- PBVHNode **nodes;
- int totnode, n;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Object *ob = data->ob;
- BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ /* these brushes start from original coordinates */
+ const bool use_orco = ELEM(data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
- /* first line is tools that don't support proxies */
- if (ss->cache->supports_gravity ||
- (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
+ PBVHVertexIter vd;
+ PBVHProxyNode *proxies;
+ int proxy_count;
+ float (*orco)[3] = NULL;
+
+ if (use_orco && !ss->bm)
+ orco = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co;
+
+ BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- /* these brushes start from original coordinates */
- const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ float val[3];
+ int p;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- PBVHProxyNode *proxies;
- int proxy_count;
- float (*orco)[3] = NULL;
+ if (use_orco) {
+ if (ss->bm) {
+ copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
+ }
+ else {
+ copy_v3_v3(val, orco[vd.i]);
+ }
+ }
+ else {
+ copy_v3_v3(val, vd.co);
+ }
- if (use_orco && !ss->bm)
- orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co;
+ for (p = 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
- BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+ sculpt_clip(sd, ss, vd.co, val);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- float val[3];
- int p;
+ if (ss->modifiers_active)
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+ }
+ BKE_pbvh_vertex_iter_end;
- if (use_orco) {
- if (ss->bm) {
- copy_v3_v3(val,
- BM_log_original_vert_co(ss->bm_log,
- vd.bm_vert));
- }
- else
- copy_v3_v3(val, orco[vd.i]);
- }
- else
- copy_v3_v3(val, vd.co);
+ BKE_pbvh_node_free_proxies(data->nodes[n]);
+}
- for (p = 0; p < proxy_count; p++)
- add_v3_v3(val, proxies[p].co[vd.i]);
+static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ PBVHNode **nodes;
+ int totnode;
- sculpt_clip(sd, ss, vd.co, val);
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
- if (ss->modifiers_active)
- sculpt_flush_pbvhvert_deform(ob, &vd);
- }
- BKE_pbvh_vertex_iter_end;
+ /* first line is tools that don't support proxies */
+ if (ss->cache->supports_gravity ||
+ (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
+ {
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
- BKE_pbvh_node_free_proxies(nodes[n]);
- }
+ BLI_task_parallel_range(
+ 0, totnode, &data, sculpt_combine_proxies_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
}
if (nodes)
@@ -3356,6 +3608,27 @@ static void sculpt_update_keyblock(Object *ob)
}
}
+static void sculpt_flush_stroke_deform_task_cb(void *userdata, const int n)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Object *ob = data->ob;
+ float (*vertCos)[3] = data->vertCos;
+
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+
+ if (vertCos) {
+ int index = vd.vert_indices[vd.i];
+ copy_v3_v3(vertCos[index], ss->orig_cos[index]);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
/* flush displacement from deformed PBVH to original layer */
static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
{
@@ -3366,7 +3639,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
- int n, totnode;
+ int totnode;
Mesh *me = (Mesh *)ob->data;
PBVHNode **nodes;
float (*vertCos)[3] = NULL;
@@ -3378,26 +3651,19 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
* to deal with this we copy old coordinates over new ones
* and then update coordinates for all vertices from BVH
*/
- memcpy(vertCos, ss->orig_cos, 3 * sizeof(float) * me->totvert);
+ memcpy(vertCos, ss->orig_cos, sizeof(*vertCos) * me->totvert);
}
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .vertCos = vertCos,
+ };
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_flush_pbvhvert_deform(ob, &vd);
-
- if (vertCos) {
- int index = vd.vert_indices[vd.i];
- copy_v3_v3(vertCos[index], ss->orig_cos[index]);
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range(
+ 0, totnode, &data, sculpt_flush_stroke_deform_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
if (vertCos) {
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -3458,6 +3724,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
flip_v3_v3(cache->gravity_direction, cache->true_gravity_direction, symm);
mul_m4_v3(cache->symm_rot_mat, cache->gravity_direction);
}
+
+ if (cache->is_rake_rotation_valid) {
+ flip_qt_qt(cache->rake_rotation_symmetry, cache->rake_rotation, symm);
+ }
}
typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
@@ -3714,83 +3984,6 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
}
}
-static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
-{
- StrokeCache *cache = ss->cache;
-
-#ifdef _OPENMP
-
-#if defined(__APPLE__)
- cache->init_num_threads = BLI_system_thread_count();
-#else
- cache->init_num_threads = omp_get_max_threads();
-#endif
- /* If using OpenMP then create a number of threads two times the
- * number of processor cores.
- * Justification: Empirically I've found that two threads per
- * processor gives higher throughput. */
- if (sd->flags & SCULPT_USE_OPENMP) {
-#if defined(__APPLE__)
- cache->num_threads = system_physical_thread_count();
-#else
- cache->num_threads = 2 * omp_get_num_procs();
-#endif
- }
- else {
- cache->num_threads = 1;
- }
- omp_set_num_threads(cache->num_threads);
-#else
- (void)sd;
- cache->num_threads = 1;
-#endif
- if (ss->multires) {
- int i, gridsize, array_mem_size;
- BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
- &gridsize, NULL);
-
- array_mem_size = cache->num_threads * sizeof(void *);
-
- cache->tmpgrid_co = MEM_mallocN(array_mem_size, "tmpgrid_co array");
- cache->tmprow_co = MEM_mallocN(array_mem_size, "tmprow_co array");
- cache->tmpgrid_mask = MEM_mallocN(array_mem_size, "tmpgrid_mask array");
- cache->tmprow_mask = MEM_mallocN(array_mem_size, "tmprow_mask array");
-
- for (i = 0; i < cache->num_threads; i++) {
- const size_t row_size = sizeof(float) * gridsize;
- const size_t co_row_size = 3 * row_size;
-
- cache->tmprow_co[i] = MEM_mallocN(co_row_size, "tmprow_co");
- cache->tmpgrid_co[i] = MEM_mallocN(co_row_size * gridsize, "tmpgrid_co");
- cache->tmprow_mask[i] = MEM_mallocN(row_size, "tmprow_mask");
- cache->tmpgrid_mask[i] = MEM_mallocN(row_size * gridsize, "tmpgrid_mask");
- }
- }
-}
-
-static void sculpt_omp_done(SculptSession *ss)
-{
-#ifdef _OPENMP
- omp_set_num_threads(ss->cache->init_num_threads);
-#endif
-
- if (ss->multires) {
- int i;
-
- for (i = 0; i < ss->cache->num_threads; i++) {
- MEM_freeN(ss->cache->tmpgrid_co[i]);
- MEM_freeN(ss->cache->tmprow_co[i]);
- MEM_freeN(ss->cache->tmpgrid_mask[i]);
- MEM_freeN(ss->cache->tmprow_mask[i]);
- }
-
- MEM_freeN(ss->cache->tmpgrid_co);
- MEM_freeN(ss->cache->tmprow_co);
- MEM_freeN(ss->cache->tmpgrid_mask);
- MEM_freeN(ss->cache->tmprow_mask);
- }
-}
-
/* Initialize the stroke cache invariants from operator properties */
static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
{
@@ -3837,6 +4030,15 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
mode = RNA_enum_get(op->ptr, "mode");
cache->invert = mode == BRUSH_STROKE_INVERT;
cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
+ cache->normal_weight = brush->normal_weight;
+
+ /* interpret invert as following normal, for grab brushes */
+ if (SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool)) {
+ if (cache->invert) {
+ cache->invert = false;
+ cache->normal_weight = (cache->normal_weight == 0.0f);
+ }
+ }
/* not very nice, but with current events system implementation
* we can't handle brush appearance inversion hotkey separately (sergey) */
@@ -3951,8 +4153,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
cache->dial = BLI_dial_initialize(cache->initial_mouse, PIXEL_INPUT_THRESHHOLD);
#undef PIXEL_INPUT_THRESHHOLD
-
- sculpt_omp_start(sd, ss);
}
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
@@ -4030,6 +4230,54 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
ups->anchored_size = ups->pixel_radius;
}
+
+
+ /* handle 'rake' */
+ cache->is_rake_rotation_valid = false;
+
+ if (cache->first_time) {
+ copy_v3_v3(cache->rake_data.follow_co, grab_location);
+ }
+
+ if (sculpt_brush_needs_rake_rotation(brush)) {
+ cache->rake_data.follow_dist = cache->radius * SCULPT_RAKE_BRUSH_FACTOR;
+
+ if (!is_zero_v3(cache->grab_delta)) {
+ const float eps = 0.00001f;
+
+ float v1[3], v2[3];
+
+ copy_v3_v3(v1, cache->rake_data.follow_co);
+ copy_v3_v3(v2, cache->rake_data.follow_co);
+ sub_v3_v3(v2, cache->grab_delta);
+
+ sub_v3_v3(v1, grab_location);
+ sub_v3_v3(v2, grab_location);
+
+ if ((normalize_v3(v2) > eps) &&
+ (normalize_v3(v1) > eps) &&
+ (len_squared_v3v3(v1, v2) > eps))
+ {
+ const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
+ const float rake_fade = (rake_dist_sq > SQUARE(cache->rake_data.follow_dist)) ?
+ 1.0f : sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
+
+ float axis[3], angle;
+ float tquat[4];
+
+ rotation_between_vecs_to_quat(tquat, v1, v2);
+
+ /* use axis-angle to scale rotation since the factor may be above 1 */
+ quat_to_axis_angle(axis, &angle, tquat);
+ normalize_v3(axis);
+
+ angle *= brush->rake_factor * rake_fade;
+ axis_angle_normalized_to_quat(cache->rake_rotation, axis, angle);
+ cache->is_rake_rotation_valid = true;
+ }
+ }
+ sculpt_rake_data_update(&cache->rake_data, grab_location);
+ }
}
}
@@ -4494,8 +4742,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- sculpt_omp_done(ss);
-
/* Finished */
if (ss->cache) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -4522,7 +4768,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_cache_free(ss->cache);
ss->cache = NULL;
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
@@ -4602,8 +4848,11 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ const Brush *brush = BKE_paint_brush(&sd->paint);
- if (ss->cache) {
+ /* XXX Canceling strokes that way does not work with dynamic topology, user will have to do real undo for now.
+ * See T46456. */
+ if (ss->cache && !sculpt_stroke_is_dynamic_topology(ss, brush)) {
paint_mesh_restore_co(sd, ob);
}
@@ -4677,7 +4926,7 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
static void sculpt_dynamic_topology_triangulate(BMesh *bm)
{
if (bm->totloop != bm->totface * 3) {
- BM_mesh_triangulate(bm, MOD_TRIANGULATE_QUAD_FIXED, MOD_TRIANGULATE_NGON_EARCLIP, false, NULL, NULL);
+ BM_mesh_triangulate(bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, false, NULL, NULL, NULL);
}
}
@@ -4846,7 +5095,7 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
sculpt_dynamic_topology_enable(C);
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
}
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
return OPERATOR_FINISHED;
}
@@ -5008,7 +5257,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
/* Redraw */
sculpt_pbvh_clear(ob);
@@ -5149,6 +5398,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
paint_cursor_start(C, sculpt_poll_view3d);
}
+ if (ob->derivedFinal) /* VBO no longer valid */
+ GPU_drawobject_free(ob->derivedFinal);
+
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
return OPERATOR_FINISHED;
@@ -5216,7 +5468,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
MEM_freeN(nodes);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
/* force rebuild of pbvh for better BB placement */
sculpt_pbvh_clear(ob);