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.c1247
1 files changed, 690 insertions, 557 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c0925eeca39..ede90b6e1f1 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -56,6 +56,7 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@@ -115,6 +116,13 @@ static int system_physical_thread_count(void)
}
#endif /* __APPLE__ */
+/** \name Tool Capabilities
+ *
+ * Avoid duplicate checks, internal logic only,
+ * share logic with #rna_def_sculpt_capabilities where possible.
+ *
+ * \{ */
+
/* Check if there are any active modifiers in stack (used for flushing updates at enter/exit sculpt mode) */
static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
{
@@ -132,6 +140,43 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
return 0;
}
+static bool sculpt_tool_needs_original(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER);
+}
+
+static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
+{
+ return ELEM(sculpt_tool,
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_LAYER);
+}
+
+/**
+ * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
+ */
+static int sculpt_brush_needs_normal(const Brush *brush)
+{
+ return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
+ (brush->normal_weight > 0)) ||
+
+ ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_BLOB,
+ SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW,
+ SCULPT_TOOL_LAYER,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB) ||
+
+ (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
+}
+
+/** \} */
typedef enum StrokeFlags {
@@ -181,8 +226,6 @@ typedef struct StrokeCache {
ViewContext *vc;
Brush *brush;
- float (*face_norms)[3]; /* Copy of the mesh faces' normals */
-
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
@@ -284,30 +327,70 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
PBVHVertexIter *iter)
{
if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
- if (orig_data->coords) {
- orig_data->co = orig_data->coords[iter->i];
+ if (orig_data->bm_log) {
+ BM_log_original_vert_data(
+ orig_data->bm_log, iter->bm_vert,
+ &orig_data->co, &orig_data->no);
}
else {
- orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
- }
-
- if (orig_data->normals) {
+ orig_data->co = orig_data->coords[iter->i];
orig_data->no = orig_data->normals[iter->i];
}
- else {
- orig_data->no = BM_log_original_vert_no(orig_data->bm_log, iter->bm_vert);
- }
}
else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
- if (orig_data->vmasks) {
- orig_data->mask = orig_data->vmasks[iter->i];
+ if (orig_data->bm_log) {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
}
else {
- orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ orig_data->mask = orig_data->vmasks[iter->i];
}
}
}
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ *
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+/**
+ * \param plane Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(
+ SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(
+ const SculptProjectVector *spvc, const float vec[3],
+ float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+/** \} */
+
+
/**********************************************************************/
/* Returns true if the stroke will use dynamic topology, false
@@ -316,8 +399,8 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
- const Brush *brush)
+static bool sculpt_stroke_is_dynamic_topology(
+ const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -327,20 +410,8 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
* dynamic-topology */
!(brush->flag & BRUSH_ANCHORED) &&
!(brush->flag & BRUSH_DRAG_DOT) &&
-
- (!ELEM(brush->sculpt_tool,
- /* These brushes, as currently coded, cannot
- * support dynamic topology */
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER,
-
- /* These brushes could handle dynamic topology,
- * but user feedback indicates it's better not
- * to */
- SCULPT_TOOL_SMOOTH,
- SCULPT_TOOL_MASK)));
+
+ SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
/*** paint mesh ***/
@@ -348,17 +419,11 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
SculptSession *ss = ob->sculpt;
- StrokeCache *cache = ss->cache;
const Brush *brush = BKE_paint_brush(&sd->paint);
- int i;
PBVHNode **nodes;
int n, totnode;
-#ifndef _OPENMP
- (void)sd; /* quied unused warning */
-#endif
-
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
/* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
@@ -403,12 +468,6 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
}
}
- if (ss->face_normals) {
- for (i = 0; i < ss->totpoly; i++) {
- copy_v3_v3(ss->face_normals[i], cache->face_norms[i]);
- }
- }
-
if (nodes)
MEM_freeN(nodes);
}
@@ -508,7 +567,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
}
}
-BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3])
+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)));
@@ -546,7 +605,7 @@ static bool sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
}
}
-static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
+static bool sculpt_brush_test_fast(const SculptBrushTest *test, const float co[3])
{
if (sculpt_brush_test_clipping(test, co)) {
return 0;
@@ -554,7 +613,7 @@ static bool sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
-static bool sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
+static bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float local[4][4])
{
float side = M_SQRT1_2;
float local_co[3];
@@ -607,7 +666,7 @@ static float frontface(Brush *br, const float sculpt_normal[3],
#if 0
-static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
+static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], const float area_no[3])
{
if (sculpt_brush_test_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
@@ -615,7 +674,7 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
sub_v3_v3v3(t1, location, co);
sub_v3_v3v3(t2, x2, location);
- cross_v3_v3v3(t3, an, t1);
+ cross_v3_v3v3(t3, area_no, t1);
dist = len_v3(t3) / len_v3(t2);
@@ -701,18 +760,447 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
}
}
+/** \name Calculate Normal and Center
+ *
+ * Calculate geometry surrounding the brush center.
+ * (optionally using original coordinates).
+ *
+ * Functions are:
+ * - #calc_area_center
+ * - #calc_area_normal
+ * - #calc_area_normal_and_center
+ *
+ * \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])
+{
+ 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_co[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}};
+ 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);
+ add_v3_v3(private_co[flip_index], co);
+ 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);
+ 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]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+}
+
+
+static void calc_area_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[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_no[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;
+ }
+
+#pragma omp critical
+ {
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/* this calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time */
+static void calc_area_normal_and_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], 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_co[2][3] = {{0.0f}};
+ float area_no[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]);
+
+ /* for area normal */
+ add_v3_v3(area_no[0], private_no[0]);
+ add_v3_v3(area_no[1], private_no[1]);
+
+ /* weights */
+ count[0] += private_count[0];
+ count[1] += private_count[1];
+ }
+ }
+
+ /* for flatten center */
+ for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ if (count[n] != 0) {
+ mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ break;
+ }
+ }
+ if (n == 2) {
+ zero_v3(r_area_co);
+ }
+
+ /* for area normal */
+ for (n = 0; n < ARRAY_SIZE(area_no); n++) {
+ if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ break;
+ }
+ }
+}
+
+/** \} */
+
+
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups)
+static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
+ const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
const float root_alpha = BKE_brush_alpha_get(scene, brush);
float alpha = root_alpha * root_alpha;
- float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
+ float dir = (brush->flag & BRUSH_DIR_IN) ? -1 : 1;
float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
@@ -926,132 +1414,34 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
-static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
-{
- if ((dot_v3v3(view_vec, fno)) > 0) {
- add_v3_v3(out, fno);
- }
- else {
- add_v3_v3(out_flip, fno); /* out_flip is used when out is {0,0,0} */
- }
-}
-
-static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode)
-{
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
- int n;
- bool original;
-
- /* Grab brush requires to test on original data (see r33888 and
- * bug #25371) */
- original = (BKE_paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
- true : ss->cache->original);
-
- /* In general the original coords are not available with dynamic
- * topology
- *
- * Mask tool could not use undo nodes to get coordinates from
- * since the coordinates are not stored in those odes.
- * And mask tool is not gonna to modify vertex coordinates,
- * so we don't actually need to use modified coords.
- */
- if (ss->bm || brush->sculpt_tool == SCULPT_TOOL_MASK)
- original = false;
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(an);
-
-#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_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (original) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
- }
- else {
- add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
- }
- }
-
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-}
-
/* Calculate primary direction of movement for many brushes */
-static void calc_sculpt_normal(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3])
+static void calc_sculpt_normal(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
const SculptSession *ss = ob->sculpt;
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, r_area_no);
break;
default:
@@ -1152,27 +1542,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
-/* Test whether the StrokeCache.sculpt_normal needs update in
- * do_brush_action() */
-static int brush_needs_sculpt_normal(const Brush *brush)
-{
- return ((ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_SNAKE_HOOK) &&
- (brush->normal_weight > 0)) ||
-
- ELEM(brush->sculpt_tool,
- SCULPT_TOOL_BLOB,
- SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW,
- SCULPT_TOOL_LAYER,
- SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB) ||
-
- (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
-}
-
/* For the smooth brush, uses the neighboring vertices around vert to calculate
* a smoothed location for vert. Skips corner vertices (used by only one
* polygon.) */
@@ -1182,20 +1551,19 @@ static void neighbor_average(SculptSession *ss, float avg[3], unsigned vert)
const MVert *mvert = ss->mvert;
float (*deform_co)[3] = ss->deform_cos;
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vert_map->count > 1) {
int i, total = 0;
+ zero_v3(avg);
+
for (i = 0; i < vert_map->count; i++) {
const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] :
mvert[f_adj_v[j]].co);
@@ -1226,12 +1594,11 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
for (i = 0; i < ss->pmap[vert].count; i++) {
const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- unsigned f_adj_v[3];
+ unsigned f_adj_v[2];
if (poly_get_adj_loops_from_vert(f_adj_v, p, ss->mloop, vert) != -1) {
int j;
-
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
avg += vmask[f_adj_v[j]];
total++;
}
@@ -1247,22 +1614,24 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
/* Same logic as neighbor_average(), but for bmesh rather than mesh */
static void bmesh_neighbor_average(float avg[3], BMVert *v)
{
- const int vfcount = BM_vert_face_count(v);
+ /* logic for 3 or more is identical */
+ const int vfcount = BM_vert_face_count_ex(v, 3);
- zero_v3(avg);
-
/* Don't modify corner vertices */
if (vfcount > 1) {
BMIter liter;
BMLoop *l;
int i, total = 0;
+ zero_v3(avg);
+
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) {
- add_v3_v3(avg, adj_v[i]->co);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (vfcount != 2 || BM_vert_face_count_ex(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
total++;
}
}
@@ -1278,7 +1647,7 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
}
/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
-static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
{
BMIter liter;
BMLoop *l;
@@ -1286,13 +1655,12 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
int i, total = 0;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+ /* skip this vertex */
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
- for (i = 0; i < 3; i++) {
- BMVert *v2 = adj_v[i];
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v2->head.data,
- CD_PAINT_MASK);
+ for (i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
avg += (*vmask);
total++;
}
@@ -1302,9 +1670,7 @@ static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
return avg / (float)total;
}
else {
- float *vmask = CustomData_bmesh_get(&bm->vdata,
- v->head.data,
- CD_PAINT_MASK);
+ const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
return (*vmask);
}
}
@@ -1367,7 +1733,7 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
vd.no, vd.fno,
smooth_mask ? 0 : *vd.mask);
if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.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);
@@ -1398,12 +1764,11 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
SculptBrushTest test;
CCGElem **griddata, *data;
CCGKey key;
- DMGridAdjacency *gridadj, *adj;
float (*tmpgrid_co)[3], (*tmprow_co)[3];
float *tmpgrid_mask, *tmprow_mask;
int v1, v2, v3, v4;
int thread_num;
- BLI_bitmap **grid_hidden;
+ BLI_bitmap * const *grid_hidden;
int *grid_indices, totgrid, gridsize, i, x, y;
sculpt_brush_test_init(ss, &test);
@@ -1411,7 +1776,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
CLAMP(bstrength, 0.0f, 1.0f);
BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata, &gridadj);
+ NULL, &gridsize, &griddata);
BKE_pbvh_get_grid_key(ss->pbvh, &key);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -1428,9 +1793,8 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
for (i = 0; i < totgrid; ++i) {
int gi = grid_indices[i];
- BLI_bitmap *gh = grid_hidden[gi];
+ const BLI_bitmap *gh = grid_hidden[gi];
data = griddata[gi];
- adj = &gridadj[gi];
if (smooth_mask)
memset(tmpgrid_mask, 0, sizeof(float) * gridsize * gridsize);
@@ -1496,18 +1860,6 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
continue;
}
- if (x == 0 && adj->index[0] == -1)
- continue;
-
- if (x == gridsize - 1 && adj->index[2] == -1)
- continue;
-
- if (y == 0 && adj->index[3] == -1)
- continue;
-
- if (y == gridsize - 1 && adj->index[1] == -1)
- continue;
-
index = x + y * gridsize;
co = CCG_elem_offset_co(&key, data, index);
fno = CCG_elem_offset_no(&key, data, index);
@@ -1698,6 +2050,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float brush_alpha;
int n;
+ SculptProjectVector spvc;
+
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
@@ -1714,6 +2068,10 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single point.
+ * Without this we get a 'flat' surface surrounding the pinch */
+ 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++) {
@@ -1738,6 +2096,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
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);
@@ -2131,233 +2491,10 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
-static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- int count = 0;
- int count_flip = 0;
-
- float fc_flip[3] = {0.0, 0.0, 0.0};
-
- (void)sd; /* unused w/o openmp */
-
- zero_v3(fc);
-
-#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_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flip += private_count_flip;
- }
- }
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flip != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flip);
- else
- zero_v3(fc);
-}
-
-/* this calculates flatten center and area normal together,
- * amortizing the memory bandwidth and loop overhead to calculate both at the same time */
-static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float an[3], float fc[3])
-{
- SculptSession *ss = ob->sculpt;
- int n;
-
- /* for area normal */
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
- float fc_flip[3] = {0.0f, 0.0f, 0.0f};
-
- /* for flatten center */
- int count = 0;
- int count_flipped = 0;
-
- (void)sd; /* unused w/o openmp */
-
- /* for area normal */
- zero_v3(an);
-
- /* for flatten center */
- zero_v3(fc);
-
-#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_an[3] = {0.0f, 0.0f, 0.0f};
- float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
- float private_fc[3] = {0.0f, 0.0f, 0.0f};
- float private_fc_flip[3] = {0.0f, 0.0f, 0.0f};
- int private_count = 0;
- int private_count_flip = 0;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- if (ss->cache->original && unode->co) {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
- /* for area normal */
- float fno[3];
-
- normal_short_to_float_v3(fno, unode->no[vd.i]);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, unode->co[vd.i]);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, unode->co[vd.i]);
- private_count_flip++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_fast(&test, vd.co)) {
- /* for area normal */
- if (vd.no) {
- float fno[3];
-
- normal_short_to_float_v3(fno, vd.no);
-
- if (dot_v3v3(ss->cache->view_normal, fno) > 0) {
- add_v3_v3(private_an, fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- else {
- if (dot_v3v3(ss->cache->view_normal, vd.fno) > 0) {
- add_v3_v3(private_an, vd.fno);
- add_v3_v3(private_fc, vd.co);
- private_count++;
- }
- else {
- add_v3_v3(private_out_flip, vd.fno);
- add_v3_v3(private_fc_flip, vd.co);
- private_count_flip++;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- /* for area normal */
- add_v3_v3(an, private_an);
- add_v3_v3(out_flip, private_out_flip);
-
- /* for flatten center */
- add_v3_v3(fc, private_fc);
- add_v3_v3(fc_flip, private_fc_flip);
- count += private_count;
- count_flipped += private_count_flip;
- }
- }
-
- /* for area normal */
- if (is_zero_v3(an))
- copy_v3_v3(an, out_flip);
-
- normalize_v3(an);
-
- /* for flatten center */
- if (count != 0)
- mul_v3_fl(fc, 1.0f / count);
- else if (count_flipped != 0)
- mul_v3_v3fl(fc, fc_flip, 1.0f / count_flipped);
- else
- zero_v3(fc);
-}
-
-static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_no[3], float r_area_co[3])
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2368,29 +2505,23 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(an, ss->cache->true_view_normal);
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
break;
case SCULPT_DISP_DIR_X:
- an[1] = 0.0;
- an[2] = 0.0;
- an[0] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 1, 0, 0);
break;
case SCULPT_DISP_DIR_Y:
- an[0] = 0.0;
- an[2] = 0.0;
- an[1] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 1, 0);
break;
case SCULPT_DISP_DIR_Z:
- an[0] = 0.0;
- an[1] = 0.0;
- an[2] = 1.0;
+ ARRAY_SET_ITEMS(r_area_no, 0, 0, 1);
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc);
+ calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
break;
default:
@@ -2400,50 +2531,54 @@ static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
/* for flatten center */
/* flatten center has not been calculated yet if we are not using the area normal */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
- calc_flatten_center(sd, ob, nodes, totnode, fc);
+ calc_area_center(sd, ob, nodes, totnode, r_area_co);
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, an);
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, fc);
+ copy_v3_v3(ss->cache->last_center, r_area_co);
}
else {
/* for area normal */
- copy_v3_v3(an, ss->cache->sculpt_normal);
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
/* for flatten center */
- copy_v3_v3(fc, ss->cache->last_center);
+ copy_v3_v3(r_area_co, ss->cache->last_center);
/* for area normal */
- flip_v3(an, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
/* for flatten center */
- flip_v3(fc, ss->cache->mirror_symmetry_pass);
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
/* for area normal */
- mul_m4_v3(ss->cache->symm_rot_mat, an);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
/* for flatten center */
- mul_m4_v3(ss->cache->symm_rot_mat, fc);
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
}
}
/* Projects a point onto a plane along the plane's normal */
-static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
+static void point_plane_project(
+ float intr[3],
+ const float co[3], const float plane_normal[3], const float plane_center[3])
{
sub_v3_v3v3(intr, co, plane_center);
mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
sub_v3_v3v3(intr, co, intr);
}
-static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
+static int plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
+static bool plane_point_side_flip(
+ const float co[3], const float plane_normal[3], const float plane_center[3],
+ const bool flip)
{
float delta[3];
float d;
@@ -2456,7 +2591,7 @@ static int plane_point_side_flip(float co[3], float plane_normal[3], float plane
return d <= 0.0f;
}
-static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
+static int plane_point_side(const float co[3], const float plane_normal[3], const float plane_center[3])
{
float delta[3];
@@ -2485,8 +2620,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
@@ -2496,13 +2631,13 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ 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++) {
@@ -2520,7 +2655,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2550,16 +2685,16 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float displace;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
int n;
float temp[3];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
flip = bstrength < 0;
@@ -2570,11 +2705,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
- /* add_v3_v3v3(p, ss->cache->location, an); */
+ /* 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++) {
@@ -2589,15 +2724,17 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
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, an, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
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, sqrtf(test.dist),
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -2624,9 +2761,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float displace;
- float sn[3];
- float an[3];
- float fc[3];
+ 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;
@@ -2635,14 +2772,14 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
float scale[4][4];
float tmat[4][4];
- int flip;
+ bool flip;
- calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc);
+ 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))
- calc_area_normal(sd, ob, an, nodes, totnode);
+ calc_area_normal(sd, ob, nodes, totnode, area_no);
else
- copy_v3_v3(an, sn);
+ copy_v3_v3(area_no, area_no_sp);
/* delay the first daub because grab delta is not setup */
if (ss->cache->first_time)
@@ -2657,16 +2794,16 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
displace = radius * (0.25f + offset);
- mul_v3_v3v3(temp, sn, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ add_v3_v3(area_co, temp);
/* init mat */
- cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry);
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
mat[0][3] = 0;
- cross_v3_v3v3(mat[1], an, mat[0]);
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
mat[1][3] = 0;
- copy_v3_v3(mat[2], an);
+ copy_v3_v3(mat[2], area_no);
mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location);
mat[3][3] = 1;
@@ -2690,15 +2827,17 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
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, sn, fc, flip)) {
+ if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, sn, fc);
+ point_plane_project(intr, vd.co, area_no_sp, area_co);
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);
@@ -2723,8 +2862,8 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2733,13 +2872,13 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ 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++) {
@@ -2754,11 +2893,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
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, an, fc)) {
+ if (plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2787,8 +2926,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
- float an[3];
- float fc[3];
+ float area_no[3];
+ float area_co[3];
float offset = get_offset(sd, ss);
float displace;
@@ -2797,13 +2936,13 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float temp[3];
- calc_sculpt_plane(sd, ob, nodes, totnode, an, fc);
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
displace = -radius * offset;
- mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
mul_v3_fl(temp, displace);
- add_v3_v3(fc, temp);
+ 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++) {
@@ -2818,11 +2957,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
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, an, fc)) {
+ if (!plane_point_side(vd.co, area_no, area_co)) {
float intr[3];
float val[3];
- point_plane_project(intr, vd.co, an, fc);
+ point_plane_project(intr, vd.co, area_no, area_co);
sub_v3_v3v3(val, intr, vd.co);
@@ -2848,7 +2987,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3]/*, an[3]*/;
+ float offset[3]/*, area_no[3]*/;
int n;
float gravity_vector[3];
@@ -2945,11 +3084,7 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
radius = ss->cache->radius * 1.25f;
data.radius_squared = radius * radius;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
@@ -2980,9 +3115,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
- ss->cache->location,
- ss->cache->radius);
+ BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, mode,
+ ss->cache->location,
+ (brush->flag & BRUSH_FRONTFACE) ? ss->cache->view_normal : NULL,
+ ss->cache->radius);
}
MEM_freeN(nodes);
@@ -3004,11 +3141,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius_squared;
- data.original = ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
@@ -3023,7 +3156,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_node_mark_update(nodes[n]);
}
- if (brush_needs_sculpt_normal(brush))
+ if (sculpt_brush_needs_normal(brush))
update_sculpt_normal(sd, ob, nodes, totnode);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
@@ -3143,8 +3276,8 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
/* first line is tools that don't support proxies */
- if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER) ||
- ss->cache->supports_gravity)
+ if (ss->cache->supports_gravity ||
+ (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
{
/* these brushes start from original coordinates */
const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
@@ -3222,7 +3355,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
+ if (sculpt_tool_is_proxy_used(brush->sculpt_tool)) {
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
@@ -3483,8 +3616,6 @@ static const char *sculpt_tool_name(Sculpt *sd)
static void sculpt_cache_free(StrokeCache *cache)
{
- if (cache->face_norms)
- MEM_freeN(cache->face_norms);
if (cache->dial)
MEM_freeN(cache->dial);
MEM_freeN(cache);
@@ -3556,7 +3687,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
if (ss->multires) {
int i, gridsize, array_mem_size;
BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
- &gridsize, NULL, NULL);
+ &gridsize, NULL);
array_mem_size = cache->num_threads * sizeof(void *);
@@ -3744,21 +3875,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- if (ss->face_normals) {
- cache->face_norms = MEM_mallocN(sizeof(float) * 3 * ss->totpoly, "Sculpt face norms");
- for (i = 0; i < ss->totpoly; ++i) {
- copy_v3_v3(cache->face_norms[i], ss->face_normals[i]);
- }
- }
-
cache->original = 1;
}
- if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB,
- SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN))
- {
+ if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = 1;
}
@@ -4250,6 +4370,9 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
}
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f);
+ }
else {
BKE_pbvh_bmesh_detail_size_set(
ss->pbvh,
@@ -4258,7 +4381,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
(float)(sd->detail_size * U.pixelsize) / 0.4f);
}
- if (sculpt_stroke_dynamic_topology(ss, brush)) {
+ if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
@@ -4650,7 +4773,7 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
- if (!GPU_vertex_buffer_support()) {
+ if (!G.background && !GPU_vertex_buffer_support()) {
return OPERATOR_CANCELLED;
}
@@ -4745,7 +4868,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
if (mti->type == eModifierTypeType_Constructive) {
@@ -4837,6 +4960,9 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
sd->symmetrize_direction, 0.00001f);
sculpt_dynamic_topology_triangulate(ss->bm);
+ /* bisect operator flags edges (keep tags clean for edge queue) */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
sculpt_undo_push_end();
@@ -4911,7 +5037,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
/* Leave sculptmode */
ob->mode &= ~mode_flag;
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
paint_cursor_delete_textures();
}
@@ -4940,16 +5066,16 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
- if (!ts->sculpt->detail_size) {
+ if (!ts->sculpt->detail_size)
ts->sculpt->detail_size = 12;
- }
-
+ if (!ts->sculpt->detail_percent)
+ ts->sculpt->detail_percent = 25;
if (ts->sculpt->constant_detail == 0.0f)
ts->sculpt->constant_detail = 30.0f;
/* Create sculpt mode session data */
if (ob->sculpt)
- BKE_free_sculptsession(ob);
+ BKE_sculptsession_free(ob);
sculpt_init_session(scene, ob);
@@ -5032,7 +5158,10 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
- while (BKE_pbvh_bmesh_update_topology(ss->pbvh, PBVH_Collapse | PBVH_Subdivide, bb_min, size)) {
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide,
+ bb_min, NULL, size))
+ {
for (i = 0; i < totnodes; i++)
BKE_pbvh_node_mark_topology_update(nodes[i]);
}
@@ -5176,6 +5305,10 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail");
}
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0);
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
else {
set_brush_rc_props(&props_ptr, "sculpt", "detail_size", NULL, 0);
RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");