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.c985
1 files changed, 804 insertions, 181 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 8325b47beab..54ae2ebf588 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -65,6 +65,7 @@
#include "BKE_report.h"
#include "BKE_lattice.h" /* for armature_deform_verts */
#include "BKE_node.h"
+#include "BKE_object.h"
#include "BKE_subsurf.h"
#include "BIF_glutil.h"
@@ -86,6 +87,8 @@
#include "GPU_buffers.h"
+#include "bmesh.h"
+
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -98,8 +101,13 @@ void ED_sculpt_force_update(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- if (ob && (ob->mode & OB_MODE_SCULPT))
+ if (ob && (ob->mode & OB_MODE_SCULPT)) {
multires_force_update(ob);
+
+ /* Set reorder=false so that saving the file doesn't reorder
+ * the BMesh's elements */
+ sculptsession_bm_to_me(ob, FALSE);
+ }
}
float *ED_sculpt_get_last_stroke(struct Object *ob)
@@ -172,7 +180,8 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
Mesh *me = (Mesh *)ob->data;
MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
- if (mmd) return 0;
+ if (mmd || ob->sculpt->bm)
+ return 0;
/* non-locked shape keys could be handled in the same way as deformed mesh */
if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
@@ -281,12 +290,130 @@ typedef struct StrokeCache {
rcti previous_r; /* previous redraw rectangle */
} StrokeCache;
+/************** Access to original unmodified vertex data *************/
+
+typedef struct {
+ BMLog *bm_log;
+
+ SculptUndoNode *unode;
+ float (*coords)[3];
+ short (*normals)[3];
+ float *vmasks;
+
+ /* Original coordinate, normal, and mask */
+ const float *co;
+ float mask;
+ short no[3];
+} SculptOrigVertData;
+
+
+/* Initialize a SculptOrigVertData for accessing original vertex data;
+ * handles BMesh, mesh, and multires */
+static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data,
+ Object *ob,
+ SculptUndoNode *unode)
+{
+ SculptSession *ss = ob->sculpt;
+ BMesh *bm = ss->bm;
+
+ memset(data, 0, sizeof(*data));
+ data->unode = unode;
+
+ if (bm) {
+ data->bm_log = ss->bm_log;
+ }
+ else {
+ data->coords = data->unode->co;
+ data->normals = data->unode->no;
+ data->vmasks = data->unode->mask;
+ }
+}
+
+/* Initialize a SculptOrigVertData for accessing original vertex data;
+ * handles BMesh, mesh, and multires */
+static void sculpt_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node)
+{
+ SculptUndoNode *unode;
+ unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+ sculpt_orig_vert_data_unode_init(data, ob, unode);
+
+}
+
+/* Update a SculptOrigVertData for a particular vertex from the PBVH
+ * iterator */
+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];
+ }
+ else {
+ orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
+ }
+
+ if (orig_data->normals) {
+ copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]);
+ }
+ else {
+ /* TODO: log doesn't store normals yet */
+ normal_float_to_short_v3(orig_data->no, iter->bm_vert->no);
+ }
+ }
+ else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
+ if (orig_data->vmasks) {
+ orig_data->mask = orig_data->vmasks[iter->i];
+ }
+ else {
+ orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+ }
+ }
+}
+
+/**********************************************************************/
+
+/* Returns true if the stroke will use dynamic topology, false
+ otherwise.
+
+ 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)
+{
+ return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
+
+ (!ss->cache || (!ss->cache->alt_smooth)) &&
+
+ /* Requires mesh restore, which doesn't work with
+ * dynamic-topology */
+ !(brush->flag & BRUSH_ANCHORED) &&
+ !(brush->flag & BRUSH_RESTORE_MESH) &&
+
+ (!ELEM6(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)));
+}
/*** paint mesh ***/
-static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss)
+static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
+ const Brush *brush = paint_brush(&sd->paint);
int i;
PBVHNode **nodes;
@@ -296,31 +423,38 @@ static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss)
(void)sd; /* quied unused warning */
#endif
- BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
SculptUndoNode *unode;
-
- unode = sculpt_undo_get_node(nodes[n]);
+ SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
+ SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+
+ unode = sculpt_undo_push_node(ob, nodes[n], type);
if (unode) {
PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ sculpt_orig_vert_data_unode_init(&orig_data, ob, unode);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (unode->type == SCULPT_UNDO_COORDS) {
- copy_v3_v3(vd.co, unode->co[vd.i]);
- if (vd.no) copy_v3_v3_short(vd.no, unode->no[vd.i]);
- else normal_short_to_float_v3(vd.fno, unode->no[vd.i]);
+ 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 (unode->type == SCULPT_UNDO_MASK) {
- *vd.mask = unode->mask[vd.i];
+ else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
+ *vd.mask = orig_data.mask;
}
if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
- BLI_pbvh_node_mark_update(nodes[n]);
+ BKE_pbvh_node_mark_update(nodes[n]);
}
}
@@ -347,7 +481,7 @@ static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
if (!pbvh)
return 0;
- BLI_pbvh_redraw_BB(pbvh, bb_min, bb_max);
+ BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max);
/* convert 3D bounding box to screen space */
if (!paint_convert_bb_to_rect(rect,
@@ -387,7 +521,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
/* clear redraw flag from nodes */
if (pbvh)
- BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
+ BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
}
/************************ Brush Testing *******************/
@@ -405,7 +539,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
test->dist = 0.0f; /* just for initialize */
}
-static int sculpt_brush_test(SculptBrushTest *test, float co[3])
+static int sculpt_brush_test(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
@@ -418,7 +552,7 @@ static int sculpt_brush_test(SculptBrushTest *test, float co[3])
}
}
-static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
+static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
@@ -734,7 +868,8 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
}
/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(SculptSession *ss, Brush *br, float point[3],
+static float tex_strength(SculptSession *ss, Brush *br,
+ const float point[3],
const float len,
const float sculpt_normal[3],
const short vno[3],
@@ -871,9 +1006,9 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
int i;
if (data->original)
- BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
+ BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
else
- BLI_pbvh_node_get_BB(node, bb_min, bb_max);
+ BKE_pbvh_node_get_BB(node, bb_min, bb_max);
for (i = 0; i < 3; ++i) {
if (bb_min[i] > center[i])
@@ -926,6 +1061,11 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
original = (paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
TRUE : ss->cache->original);
+ /* In general the original coords are not available with dynamic
+ * topology */
+ if (ss->bm)
+ original = FALSE;
+
(void)sd; /* unused w/o openmp */
zero_v3(an);
@@ -942,7 +1082,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
sculpt_brush_test_init(ss, &test);
if (original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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];
@@ -951,10 +1091,10 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, vd.co)) {
if (vd.no) {
@@ -968,7 +1108,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
#pragma omp critical
@@ -1210,6 +1350,71 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
return vmask[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);
+
+ zero_v3(avg);
+
+ /* Don't modify corner vertices */
+ if (vfcount > 1) {
+ BMIter liter;
+ BMLoop *l;
+ 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};
+
+ 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);
+ total++;
+ }
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
+
+ copy_v3_v3(avg, v->co);
+}
+
+/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
+static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+{
+ BMIter liter;
+ BMLoop *l;
+ float avg = 0;
+ 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};
+
+ for (i = 0; i < 3; i++) {
+ BMVert *v2 = adj_v[i];
+ float *vmask = CustomData_bmesh_get(&bm->vdata,
+ v2->head.data,
+ CD_PAINT_MASK);
+ avg += (*vmask);
+ total++;
+ }
+ }
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ float *vmask = CustomData_bmesh_get(&bm->vdata,
+ v->head.data,
+ CD_PAINT_MASK);
+ return (*vmask);
+ }
+}
+
static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
{
Brush *brush = paint_brush(&sd->paint);
@@ -1220,7 +1425,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1248,7 +1453,48 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ 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)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
+ ss->cache->view_normal, 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;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0, 1);
+ }
+ 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);
+
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
}
static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
@@ -1269,9 +1515,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
CLAMP(bstrength, 0.0f, 1.0f);
- BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
+ BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
NULL, &gridsize, &griddata, &gridadj);
- BLI_pbvh_get_grid_key(ss->pbvh, &key);
+ BKE_pbvh_get_grid_key(ss->pbvh, &key);
thread_num = 0;
#ifdef _OPENMP
@@ -1405,7 +1651,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
SculptSession *ss = ob->sculpt;
const int max_iterations = 4;
const float fract = 1.0f / max_iterations;
- PBVHType type = BLI_pbvh_type(ss->pbvh);
+ PBVHType type = BKE_pbvh_type(ss->pbvh);
int iteration, n, count;
float last;
@@ -1433,6 +1679,9 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
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;
}
}
@@ -1462,7 +1711,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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,
@@ -1474,7 +1723,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
if (vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
}
@@ -1514,11 +1763,11 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
@@ -1532,7 +1781,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1570,11 +1819,11 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
@@ -1597,7 +1846,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1614,11 +1863,11 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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,
@@ -1633,7 +1882,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1659,26 +1908,27 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode *unode;
SculptBrushTest test;
- float (*origco)[3];
- short (*origno)[3];
+ SculptOrigVertData orig_data;
float (*proxy)[3];
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- origno = unode->no;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
- ss->cache->sculpt_normal_symm, origno[vd.i],
- NULL, vd.mask ? *vd.mask : 0.0f);
+ 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,
+ ss->cache->sculpt_normal_symm,
+ orig_data.no,
+ NULL, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -1686,7 +1936,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1710,11 +1960,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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,
@@ -1727,7 +1977,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1759,11 +2009,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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,
@@ -1776,7 +2026,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1797,26 +2047,27 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode *unode;
SculptBrushTest test;
- float (*origco)[3];
- short (*origno)[3];
+ SculptOrigVertData orig_data;
float (*proxy)[3];
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- origno = unode->no;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
+ 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,
ss->cache->sculpt_normal_symm,
- origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f);
+ orig_data.no,
+ NULL, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1824,7 +2075,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1850,36 +2101,37 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- SculptUndoNode *unode;
SculptBrushTest test;
- float (*origco)[3];
- short (*origno)[3];
+ SculptOrigVertData orig_data;
float (*proxy)[3];
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- origno = unode->no;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
- const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
+ 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,
ss->cache->sculpt_normal_symm,
- origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f);
+ orig_data.no,
+ NULL, vd.mask ? *vd.mask : 0.0f);
- mul_v3_m4v3(proxy[vd.i], m, origco[vd.i]);
- sub_v3_v3(proxy[vd.i], origco[vd.i]);
+ mul_v3_m4v3(proxy[vd.i], m, orig_data.co);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
mul_v3_fl(proxy[vd.i], fade);
if (vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1901,25 +2153,25 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
- SculptUndoNode *unode;
- float (*origco)[3], *layer_disp;
+ SculptOrigVertData orig_data;
+ float *layer_disp;
/* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
+ /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- origco = unode->co;
- if (!unode->layer_disp) {
- #pragma omp critical
- unode->layer_disp = MEM_callocN(sizeof(float) * unode->totvert, "layer disp");
- }
-
- layer_disp = unode->layer_disp;
+ sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ #pragma omp critical
+ {
+ layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]);
+ }
+
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (sculpt_brush_test(&test, origco[vd.i])) {
+ 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,
ss->cache->sculpt_normal_symm,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -1941,7 +2193,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
add_v3_v3(val, ss->layer_co[index]);
}
else {
- add_v3_v3(val, origco[vd.i]);
+ add_v3_v3(val, orig_data.co);
}
sculpt_clip(sd, ss, vd.co, val);
@@ -1950,7 +2202,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -1967,11 +2219,11 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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,
@@ -1989,7 +2241,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2016,24 +2268,24 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
sculpt_brush_test_init(ss, &test);
if (ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
add_v3_v3(private_fc, unode->co[vd.i]);
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, vd.co)) {
add_v3_v3(private_fc, vd.co);
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
#pragma omp critical
@@ -2082,8 +2334,8 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
sculpt_brush_test_init(ss, &test);
- if (ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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 */
@@ -2097,10 +2349,10 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, vd.co)) {
/* for area normal */
@@ -2119,7 +2371,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
private_count++;
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
#pragma omp critical
@@ -2301,11 +2553,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq(&test, vd.co)) {
float intr[3];
@@ -2326,7 +2578,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2373,11 +2625,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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)) {
@@ -2401,7 +2653,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2475,11 +2727,11 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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)) {
@@ -2503,7 +2755,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2539,11 +2791,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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)) {
@@ -2567,7 +2819,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2603,11 +2855,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
SculptBrushTest test;
float (*proxy)[3];
- proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ 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)) {
@@ -2631,7 +2883,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
}
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
}
@@ -2688,6 +2940,65 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
BKE_key_convert_from_vertcos(ob, kb, vertCos);
}
+/* Note: we do the topology update before any brush actions to avoid
+ * issues with the proxies. The size of the proxy can't change, so
+ * topology must be updated first. */
+static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
+{
+ SculptSession *ss = ob->sculpt;
+ SculptSearchSphereData data;
+ PBVHNode **nodes = NULL;
+ float radius;
+ int n, totnode;
+
+ /* Build a list of all nodes that are potentially within the
+ * brush's area of influence */
+ data.ss = ss;
+ data.sd = sd;
+
+ radius = ss->cache->radius * 1.25f;
+
+ data.radius_squared = radius * radius;
+ data.original = ELEM4(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER);
+
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+
+ /* Only act if some verts are inside the brush area */
+ if (totnode) {
+ PBVHTopologyUpdateMode mode = PBVH_Subdivide;
+
+ if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) ||
+ (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY))
+ {
+ mode |= PBVH_Collapse;
+ }
+
+ 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]);
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BKE_pbvh_node_mark_topology_update(nodes[n]);
+ BKE_pbvh_bmesh_node_save_orig(nodes[n]);
+ }
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
+ ss->cache->location,
+ ss->cache->radius);
+ }
+
+ MEM_freeN(nodes);
+ }
+}
+
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
@@ -2704,7 +3015,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_LAYER);
- BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
if (totnode) {
@@ -2713,7 +3024,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
sculpt_undo_push_node(ob, nodes[n],
brush->sculpt_tool == SCULPT_TOOL_MASK ?
SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BLI_pbvh_node_mark_update(nodes[n]);
+ BKE_pbvh_node_mark_update(nodes[n]);
}
if (brush_needs_sculpt_normal(brush))
@@ -2821,7 +3132,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
PBVHNode **nodes;
int totnode, n;
- BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
/* these brushes start from original coordinates */
@@ -2835,18 +3146,25 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
int proxy_count;
float (*orco)[3];
- if (use_orco)
+ if (use_orco && !ss->bm)
orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co;
- BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+ BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
float val[3];
int p;
- if (use_orco)
- copy_v3_v3(val, orco[vd.i]);
+ 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);
@@ -2858,9 +3176,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
if (ss->modifiers_active)
sculpt_flush_pbvhvert_deform(ob, &vd);
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
- BLI_pbvh_node_free_proxies(nodes[n]);
+ BKE_pbvh_node_free_proxies(nodes[n]);
}
}
@@ -2877,7 +3195,7 @@ static void sculpt_update_keyblock(Object *ob)
/* Keyblock update happens after handling deformation caused by modifiers,
* so ss->orig_cos would be updated with new stroke */
if (ss->orig_cos) vertCos = ss->orig_cos;
- else vertCos = BLI_pbvh_get_vertCos(ss->pbvh);
+ else vertCos = BKE_pbvh_get_vertCos(ss->pbvh);
if (vertCos) {
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -2905,13 +3223,13 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
if (ss->kb)
vertCos = MEM_callocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
- BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
sculpt_flush_pbvhvert_deform(ob, &vd);
@@ -2920,7 +3238,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
copy_v3_v3(vertCos[index], ss->orig_cos[index]);
}
}
- BLI_pbvh_vertex_iter_end;
+ BKE_pbvh_vertex_iter_end;
}
if (vertCos) {
@@ -2978,7 +3296,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
}
+typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush);
+
static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
+ BrushActionFunc action,
const char symm, const int axis,
const float feather)
{
@@ -2989,7 +3310,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
ss->cache->radial_symmetry_pass = i;
calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
- do_brush_action(sd, ob, brush);
+ action(sd, ob, brush);
}
}
@@ -3006,7 +3327,8 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
multires_stitch_grids(ob);
}
-static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
+static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
+ BrushActionFunc action)
{
Brush *brush = paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
@@ -3017,7 +3339,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
float feather = calc_symmetry_feather(sd, ss->cache);
cache->bstrength = brush_strength(sd, cache, feather);
-
cache->symmetry = symm;
/* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
@@ -3027,23 +3348,13 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
cache->radial_symmetry_pass = 0;
calc_brushdata_symm(sd, cache, i, 0, 0, feather);
- do_brush_action(sd, ob, brush);
+ action(sd, ob, brush);
- do_radial_symmetry(sd, ob, brush, i, 'X', feather);
- do_radial_symmetry(sd, ob, brush, i, 'Y', feather);
- do_radial_symmetry(sd, ob, brush, i, 'Z', feather);
+ do_radial_symmetry(sd, ob, brush, action, i, 'X', feather);
+ do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather);
+ do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather);
}
}
-
- sculpt_combine_proxies(sd, ob);
-
- /* hack to fix noise texture tearing mesh */
- sculpt_fix_noise_tear(sd, ob);
-
- if (ss->modifiers_active)
- sculpt_flush_stroke_deform(sd, ob);
-
- cache->first_time = 0;
}
static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
@@ -3142,7 +3453,7 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->orig_cos = (ss->kb) ? BKE_key_convert_to_vertcos(ob, ss->kb) : mesh_getVertexCos(me, NULL);
crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
- BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
for (a = 0; a < me->totvert; ++a) {
invert_m3(ss->deform_imats[a]);
@@ -3152,12 +3463,12 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
else free_sculptsession_deformMats(ss);
/* if pbvh is deformed, key block is already applied to it */
- if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) {
+ if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) {
float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb);
if (vertCos) {
/* apply shape keys coordinates to PBVH */
- BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
MEM_freeN(vertCos);
}
}
@@ -3220,6 +3531,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Rotate Brush";
case SCULPT_TOOL_MASK:
return "Mask Brush";
+ case SCULPT_TOOL_SIMPLIFY:
+ return "Simplify Brush";
}
return "Sculpting";
@@ -3291,7 +3604,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
if (ss->multires) {
int i, gridsize, array_mem_size;
- BLI_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
+ BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
&gridsize, NULL, NULL);
array_mem_size = cache->num_threads * sizeof(void *);
@@ -3406,8 +3719,9 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
/* Initialize layer brush displacements and persistent coords */
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- /* not supported yet for multires */
- if (!ss->multires && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ /* not supported yet for multires or dynamic topology */
+ if (!ss->multires && !ss->bm && !ss->layer_co &&
+ (brush->flag & BRUSH_PERSISTENT)) {
if (!ss->layer_co)
ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
@@ -3721,17 +4035,26 @@ typedef struct {
static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{
- if (BLI_pbvh_node_get_tmin(node) < *tmin) {
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
SculptRaycastData *srd = data_v;
float (*origco)[3] = NULL;
+ int use_origco = FALSE;
if (srd->original && srd->ss->cache) {
- /* intersect with coordinates from before we started stroke */
- SculptUndoNode *unode = sculpt_undo_get_node(node);
- origco = (unode) ? unode->co : NULL;
+ if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+ use_origco = TRUE;
+ }
+ else {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode = sculpt_undo_get_node(node);
+ origco = (unode) ? unode->co : NULL;
+ use_origco = origco ? TRUE : FALSE;
+ }
}
- if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) {
+ if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco,
+ srd->ray_start, srd->ray_normal, &srd->dist))
+ {
srd->hit = 1;
*tmin = srd->dist;
}
@@ -3780,7 +4103,7 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
srd.dist = dist;
srd.hit = 0;
srd.original = (cache) ? cache->original : 0;
- BLI_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
+ BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
ray_start, ray_normal, srd.original);
copy_v3_v3(out, ray_normal);
@@ -3829,8 +4152,9 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
return 1;
}
-static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
+static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
Brush *brush = paint_brush(&sd->paint);
/* Restore the mesh before continuing with anchored stroke */
@@ -3839,7 +4163,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
(brush->flag & BRUSH_RESTORE_MESH))
{
- paint_mesh_restore_co(sd, ss);
+ paint_mesh_restore_co(sd, ob);
}
}
@@ -3862,7 +4186,7 @@ static void sculpt_flush_update(bContext *C)
else {
rcti r;
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
if (ss->cache)
ss->cache->previous_r = r;
@@ -3917,11 +4241,33 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ const Brush *brush = paint_brush(&sd->paint);
sculpt_stroke_modifiers_check(C, ob);
sculpt_update_cache_variants(C, sd, ob, stroke, itemptr);
- sculpt_restore_mesh(sd, ss);
- do_symmetrical_brush_actions(sd, ob);
+ sculpt_restore_mesh(sd, ob);
+
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
+ (ss->cache->radius /
+ (float)ss->cache->pixel_radius) *
+ (float)sd->detail_size);
+
+ if (sculpt_stroke_dynamic_topology(ss, brush)) {
+ do_symmetrical_brush_actions(sd, ob, sculpt_topology_update);
+ }
+
+ if (paint_brush(&sd->paint)->sculpt_tool != SCULPT_TOOL_SIMPLIFY)
+ do_symmetrical_brush_actions(sd, ob, do_brush_action);
+
+ sculpt_combine_proxies(sd, ob);
+
+ /* hack to fix noise texture tearing mesh */
+ sculpt_fix_noise_tear(sd, ob);
+
+ if (ss->modifiers_active)
+ sculpt_flush_stroke_deform(sd, ob);
+
+ ss->cache->first_time = FALSE;
/* Cleanup */
sculpt_flush_update(C);
@@ -3980,7 +4326,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_undo_push_end();
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+ BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)
+ BKE_pbvh_bmesh_after_stroke(ss->pbvh);
/* optimization: if there is locked key and active modifiers present in */
/* the stack, keyblock is updating at each step. otherwise we could update */
@@ -4055,7 +4404,7 @@ static int sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
if (ss->cache) {
- paint_mesh_restore_co(sd, ss);
+ paint_mesh_restore_co(sd, ob);
}
paint_stroke_cancel(C, op);
@@ -4137,6 +4486,266 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/************************** Dynamic Topology **************************/
+
+static void sculpt_dynamic_topology_triangulate(BMesh *bm)
+{
+ BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "triangulate faces=%af");
+}
+
+void sculpt_pbvh_clear(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ DerivedMesh *dm = ob->derivedFinal;
+
+ /* Clear out any existing DM and PBVH */
+ if (ss->pbvh)
+ BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ if (dm)
+ dm->getPBVH(NULL, dm);
+ BKE_object_free_display(ob);
+}
+
+void sculpt_update_after_dynamic_topology_toggle(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Sculpt *sd = scene->toolsettings->sculpt;
+
+ /* Create the PBVH */
+ sculpt_update_mesh_elements(scene, sd, ob, FALSE, FALSE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+}
+
+void sculpt_dynamic_topology_enable(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ sculpt_pbvh_clear(ob);
+
+ ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags &
+ SCULPT_DYNTOPO_SMOOTH_SHADING);
+
+ /* Create triangles-only BMesh */
+ ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+
+ BM_mesh_bm_from_me(ss->bm, me, TRUE, ob->shapenr);
+ sculpt_dynamic_topology_triangulate(ss->bm);
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ BM_mesh_normals_update(ss->bm, TRUE);
+
+ /* Enable dynamic topology */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Enable logging for undo/redo */
+ ss->bm_log = BM_log_create(ss->bm);
+
+ /* Refresh */
+ sculpt_update_after_dynamic_topology_toggle(C);
+}
+
+/* Free the sculpt BMesh and BMLog
+ *
+ * If 'unode' is given, the BMesh's data is copied out to the unode
+ * before the BMesh is deleted so that it can be restored from */
+void sculpt_dynamic_topology_disable(bContext *C,
+ SculptUndoNode *unode)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ sculpt_pbvh_clear(ob);
+
+ if (unode) {
+ /* Free all existing custom data */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* Copy over stored custom data */
+ me->totvert = unode->bm_enter_totvert;
+ me->totloop = unode->bm_enter_totloop;
+ me->totpoly = unode->bm_enter_totpoly;
+ me->totedge = unode->bm_enter_totedge;
+ me->totface = 0;
+ CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totvert);
+ CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totedge);
+ CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totloop);
+ CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH,
+ CD_DUPLICATE, unode->bm_enter_totpoly);
+
+ mesh_update_customdata_pointers(me, FALSE);
+ } else {
+ sculptsession_bm_to_me(ob, TRUE);
+ }
+
+ BM_mesh_free(ss->bm);
+
+ /* Clear data */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ ss->bm = NULL;
+ BM_log_free(ss->bm_log);
+ ss->bm_log = NULL;
+
+ /* Refresh */
+ sculpt_update_after_dynamic_topology_toggle(C);
+}
+
+static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->bm) {
+ sculpt_undo_push_begin("Dynamic topology disable");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
+ sculpt_dynamic_topology_disable(C, NULL);
+ }
+ else {
+ sculpt_undo_push_begin("Dynamic topology enable");
+ sculpt_dynamic_topology_enable(C);
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ }
+ sculpt_undo_push_end();
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op,
+ wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+ const char *msg = "Dynamic-topology sculpting will not preserve"
+ "vertex colors, UVs, or other customdata";
+
+ if (!ss->bm) {
+ int i;
+
+ for (i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE,
+ CD_MLOOP, CD_MPOLY, CD_PAINT_MASK,
+ CD_ORIGINDEX) &&
+ (CustomData_has_layer(&me->vdata, i) ||
+ CustomData_has_layer(&me->edata, i) ||
+ CustomData_has_layer(&me->fdata, i))) {
+ /* The mesh has customdata that will be lost, let the
+ * user confirm this is OK */
+ return WM_operator_confirm_message(C, op, msg);
+ }
+ }
+ }
+
+ return sculpt_dynamic_topology_toggle_exec(C, op);
+}
+
+static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Dynamic Topology Toggle";
+ ot->idname = "SCULPT_OT_dynamic_topology_toggle";
+ ot->description = "Dynamic topology alters the mesh topology while sculpting";
+
+ /* api callbacks */
+ ot->invoke = sculpt_dynamic_topology_toggle_invoke;
+ ot->exec = sculpt_dynamic_topology_toggle_exec;
+ ot->poll = sculpt_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ sculpt_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_and_dynamic_topology_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return sculpt_mode_poll(C) && ob->sculpt->bm;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Optimize";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
+
+ /* api callbacks */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies) */
+ sculpt_undo_push_begin("Dynamic topology symmetrize");
+ sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+ /* Symmetrize and re-triangulate */
+ BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS,
+ "symmetrize input=%avef direction=%i",
+ sd->symmetrize_direction);
+ sculpt_dynamic_topology_triangulate(ss->bm);
+
+ /* Finish undo */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ sculpt_undo_push_end();
+
+ /* Redraw */
+ sculpt_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+
+ /* api callbacks */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+}
+
/**** Toggle operator for turning sculpt mode on or off ****/
static void sculpt_init_session(Scene *scene, Object *ob)
@@ -4222,6 +4831,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
+ Mesh *me = ob->data;
MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
int flush_recalc = 0;
@@ -4234,9 +4844,16 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
if (mmd)
multires_force_update(ob);
- if (flush_recalc)
+ if (flush_recalc || (ob->sculpt && ob->sculpt->bm))
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state */
+ sculpt_dynamic_topology_toggle_exec(C, NULL);
+ }
+
/* Leave sculptmode */
ob->mode &= ~OB_MODE_SCULPT;
@@ -4257,6 +4874,9 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
ts->sculpt->flags |= SCULPT_SYMM_X;
}
+ if (!ts->sculpt->detail_size)
+ ts->sculpt->detail_size = 30;
+
/* Create sculpt mode session data */
if (ob->sculpt)
free_sculptsession(ob);
@@ -4271,7 +4891,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
}
BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
-
+
paint_cursor_start(C, sculpt_poll);
}
@@ -4299,4 +4919,7 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_brush_stroke);
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
}