diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 1332 |
1 files changed, 964 insertions, 368 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index e2ed7776b7e..51500ab8e1c 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -40,10 +40,11 @@ #include "BLI_utildefines.h" #include "BLI_dynstr.h" #include "BLI_ghash.h" -#include "BLI_pbvh.h" #include "BLI_threads.h" #include "BLI_rand.h" +#include "BLF_translation.h" + #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_node_types.h" @@ -51,11 +52,13 @@ #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "BKE_pbvh.h" #include "BKE_brush.h" #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#include "BKE_image.h" #include "BKE_key.h" #include "BKE_library.h" #include "BKE_mesh.h" @@ -65,6 +68,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 +90,8 @@ #include "GPU_buffers.h" +#include "bmesh.h" + #include <math.h> #include <stdlib.h> #include <string.h> @@ -98,8 +104,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) @@ -129,6 +140,11 @@ MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) Mesh *me = (Mesh *)ob->data; ModifierData *md; + if (ob->sculpt && ob->sculpt->bm) { + /* can't combine multires and dynamic topology */ + return NULL; + } + if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) { /* multires can't work without displacement layer */ return NULL; @@ -172,7 +188,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) @@ -228,7 +245,6 @@ typedef struct StrokeCache { float pressure; float mouse[2]; float bstrength; - float tex_mouse[2]; /* The rest is temporary storage that isn't saved as a property */ @@ -242,8 +258,8 @@ typedef struct StrokeCache { Brush *brush; float (*face_norms)[3]; /* Copy of the mesh faces' normals */ - float special_rotation; /* Texture rotation (radians) for anchored and rake modes */ - int pixel_radius, previous_pixel_radius; + + float special_rotation; float grab_delta[3], grab_delta_symmetry[3]; float old_grab_location[3], orig_grab_location[3]; @@ -267,8 +283,8 @@ typedef struct StrokeCache { int radial_symmetry_pass; float symm_rot_mat[4][4]; float symm_rot_mat_inv[4][4]; - float last_rake[2]; /* Last location of updating rake rotation */ int original; + float anchored_location[3]; float vertex_rotation; @@ -281,12 +297,129 @@ 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 +429,47 @@ 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) + /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new + * entries might be inserted by sculpt_undo_push_node() into the + * GHash used internally by BM_log_original_vert_co() by a + * different thread. [#33787] */ + #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP && !ss->bm) 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); + + if (ss->bm) { + unode = sculpt_undo_push_node(ob, nodes[n], type); + } + else { + unode = sculpt_undo_get_node(nodes[n]); + } if (unode) { PBVHVertexIter vd; + SculptOrigVertData orig_data; - 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 +496,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 +536,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 *******************/ @@ -396,20 +545,42 @@ typedef struct SculptBrushTest { float radius_squared; float location[3]; float dist; + + /* View3d clipping - only set rv3d for clipping */ + RegionView3D *clip_rv3d; } SculptBrushTest; static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) { + RegionView3D *rv3d = ss->cache->vc->rv3d; + test->radius_squared = ss->cache->radius_squared; copy_v3_v3(test->location, ss->cache->location); test->dist = 0.0f; /* just for initialize */ + + + if (rv3d->rflag & RV3D_CLIPPING) { + test->clip_rv3d = rv3d; + } + else { + test->clip_rv3d = NULL; + } } -static int sculpt_brush_test(SculptBrushTest *test, float co[3]) +BLI_INLINE bool sculpt_brush_test_clipping(SculptBrushTest *test, const float co[3]) +{ + RegionView3D *rv3d = test->clip_rv3d; + return (rv3d && (ED_view3d_clipping_test(rv3d, co, true))); +} + +static int sculpt_brush_test(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); if (distsq <= test->radius_squared) { + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } test->dist = sqrt(distsq); return 1; } @@ -418,11 +589,14 @@ 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); if (distsq <= test->radius_squared) { + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } test->dist = distsq; return 1; } @@ -433,6 +607,9 @@ static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3]) static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3]) { + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } return len_squared_v3v3(co, test->location) <= test->radius_squared; } @@ -441,6 +618,10 @@ static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float loca float side = M_SQRT1_2; float local_co[3]; + if (sculpt_brush_test_clipping(test, co)) { + return 0; + } + mul_v3_m4v3(local_co, local, co); local_co[0] = fabs(local_co[0]); @@ -510,7 +691,6 @@ static int sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float locat /* ===== Sculpting ===== * */ - static float overlapped_curve(Brush *br, float x) { @@ -734,32 +914,30 @@ 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], const float fno[3], const float mask) { + const Scene *scene = ss->cache->vc->scene; MTex *mtex = &br->mtex; float avg = 1; + float rgba[4]; if (!mtex->tex) { avg = 1; } else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) { - float jnk; - /* Get strength by feeding the vertex * location directly into a texture */ - externtex(mtex, point, &avg, - &jnk, &jnk, &jnk, &jnk, 0); + avg = BKE_brush_sample_tex_3D(scene, br, point, rgba, 0, ss->tex_pool); } else if (ss->texcache) { - float rotation = -mtex->rot; float symm_point[3], point_2d[2]; float x = 0.0f, y = 0.0f; /* Quite warnings */ - float radius = 1.0f; /* Quite warnings */ /* if the active area is being applied for symmetry, flip it * across the symmetry axis and rotate it back to the original @@ -773,77 +951,33 @@ static float tex_strength(SculptSession *ss, Brush *br, float point[3], ED_view3d_project_float_v2_m4(ss->cache->vc->ar, symm_point, point_2d, ss->cache->projection_mat); - if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { - /* keep coordinates relative to mouse */ - - rotation += ss->cache->special_rotation; - - point_2d[0] -= ss->cache->tex_mouse[0]; - point_2d[1] -= ss->cache->tex_mouse[1]; - - /* use pressure adjusted size for fixed mode */ - radius = ss->cache->pixel_radius; - - x = point_2d[0] + ss->cache->vc->ar->winrct.xmin; - y = point_2d[1] + ss->cache->vc->ar->winrct.ymin; - } - else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { - /* leave the coordinates relative to the screen */ - - /* use unadjusted size for tiled mode */ - radius = BKE_brush_size_get(ss->cache->vc->scene, br); - - x = point_2d[0]; - y = point_2d[1]; - } - else if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) { + /* still no symmetry supported for other paint modes. + * Sculpt does it DIY */ + if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) { /* Similar to fixed mode, but projects from brush angle * rather than view direction */ - /* Rotation is handled by the brush_local_mat */ - rotation = 0; - mul_m4_v3(ss->cache->brush_local_mat, symm_point); x = symm_point[0]; y = symm_point[1]; - } - if (mtex->brush_map_mode != MTEX_MAP_MODE_AREA) { - x /= ss->cache->vc->ar->winx; - y /= ss->cache->vc->ar->winy; + x *= br->mtex.size[0]; + y *= br->mtex.size[1]; - if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { - x -= 0.5f; - y -= 0.5f; - } - - x *= ss->cache->vc->ar->winx / radius; - y *= ss->cache->vc->ar->winy / radius; - } + x += br->mtex.ofs[0]; + y += br->mtex.ofs[1]; - /* it is probably worth optimizing for those cases where - * the texture is not rotated by skipping the calls to - * atan2, sqrtf, sin, and cos. */ - if (rotation > 0.001f || rotation < -0.001f) { - const float angle = atan2f(y, x) + rotation; - const float flen = sqrtf(x * x + y * y); + avg = paint_get_tex_pixel(br, x, y, ss->tex_pool); - x = flen * cosf(angle); - y = flen * sinf(angle); + avg += br->texture_sample_bias; + } + else { + const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f}; + avg = BKE_brush_sample_tex_3D(scene, br, point_3d, rgba, 0, ss->tex_pool); } - - x *= br->mtex.size[0]; - y *= br->mtex.size[1]; - - x += br->mtex.ofs[0]; - y += br->mtex.ofs[1]; - - avg = paint_get_tex_pixel(br, x, y); } - avg += br->texture_sample_bias; - /* Falloff curve */ avg *= BKE_brush_curve_strength(br, len, ss->cache->radius); @@ -871,9 +1005,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 +1060,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 +1081,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 +1090,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 +1107,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 @@ -1049,11 +1188,12 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3]) { Object *ob = vc->obact; float loc[3], mval_f[2] = {0.0f, 1.0f}; + float zfac; mul_v3_m4v3(loc, ob->imat, center); - initgrabz(vc->rv3d, loc[0], loc[1], loc[2]); + zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL); - ED_view3d_win_to_delta(vc->ar, mval_f, y); + ED_view3d_win_to_delta(vc->ar, mval_f, y, zfac); normalize_v3(y); add_v3_v3(y, ob->loc); @@ -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,25 +1908,26 @@ 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], + 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; } } @@ -2015,25 +2267,25 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to 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])) { 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 */ @@ -2833,20 +3144,27 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) PBVHVertexIter vd; PBVHProxyNode *proxies; int proxy_count; - float (*orco)[3]; + float (*orco)[3] = NULL; - 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) @@ -3056,11 +3367,17 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) ss->texcache = NULL; } + if (ss->tex_pool) { + BKE_image_pool_free(ss->tex_pool); + ss->tex_pool = NULL; + } + /* Need to allocate a bigger buffer for bigger brush size */ ss->texcache_side = 2 * radius; if (!ss->texcache || ss->texcache_side > ss->texcache_actual) { ss->texcache = BKE_brush_gen_texture_cache(brush, radius); ss->texcache_actual = ss->texcache_side; + ss->tex_pool = BKE_image_pool_new(); } } @@ -3142,22 +3459,24 @@ 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]); } } } - else free_sculptsession_deformMats(ss); + 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 +3539,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 +3612,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 *); @@ -3336,30 +3657,32 @@ static void sculpt_omp_done(SculptSession *ss) static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; Brush *brush = paint_brush(&sd->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); + float rot[3][3], scale[3], loc[3]; int i; int mode; ss->cache = cache; /* Set scaling adjustment */ - ss->cache->scale[0] = 1.0f / ob->size[0]; - ss->cache->scale[1] = 1.0f / ob->size[1]; - ss->cache->scale[2] = 1.0f / ob->size[2]; + cache->scale[0] = 1.0f / ob->size[0]; + cache->scale[1] = 1.0f / ob->size[1]; + cache->scale[2] = 1.0f / ob->size[2]; - ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim; + cache->plane_trim_squared = brush->plane_trim * brush->plane_trim; - ss->cache->flag = 0; + cache->flag = 0; sculpt_init_mirror_clipping(ob, ss); /* Initial mouse location */ if (mouse) - copy_v2_v2(ss->cache->initial_mouse, mouse); + copy_v2_v2(cache->initial_mouse, mouse); else - zero_v2(ss->cache->initial_mouse); + zero_v2(cache->initial_mouse); mode = RNA_enum_get(op->ptr, "mode"); cache->invert = mode == BRUSH_STROKE_INVERT; @@ -3371,7 +3694,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio else brush->flag &= ~BRUSH_INVERTED; /* Alt-Smooth */ - if (ss->cache->alt_smooth) { + if (cache->alt_smooth) { if (brush->sculpt_tool == SCULPT_TOOL_MASK) { cache->saved_mask_brush_tool = brush->mask_tool; brush->mask_tool = BRUSH_MASK_SMOOTH; @@ -3392,7 +3715,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio } copy_v2_v2(cache->mouse, cache->initial_mouse); - copy_v2_v2(cache->tex_mouse, cache->initial_mouse); + copy_v2_v2(ups->tex_mouse, cache->initial_mouse); /* Truly temporary data that isn't stored in properties */ @@ -3403,16 +3726,25 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio /* cache projection matrix */ ED_view3d_ob_project_mat_get(cache->vc->rv3d, ob, cache->projection_mat); + mat4_to_loc_rot_size(loc, rot, scale, ob->obmat); + /* transposing an orthonormal matrix inverts */ + transpose_m3(rot); ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal); + /* This takes care of rotated mesh. Instead of rotating every normal, we inverse rotate view normal. */ + mul_m3_v3(rot, 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"); - if (ss->deform_cos) memcpy(ss->layer_co, ss->deform_cos, ss->totvert); + if (ss->deform_cos) { + memcpy(ss->layer_co, ss->deform_cos, ss->totvert); + } else { for (i = 0; i < ss->totvert; ++i) { copy_v3_v3(ss->layer_co[i], ss->mvert[i].co); @@ -3443,8 +3775,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio } } - cache->special_rotation = (brush->flag & BRUSH_RAKE) ? sd->last_angle : 0; - cache->first_time = 1; cache->vertex_rotation = 0; @@ -3452,13 +3782,13 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio sculpt_omp_start(sd, ss); } -static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush) +static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush) { SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; float mouse[2] = { - cache->mouse[0] - cache->vc->ar->winrct.xmin, - cache->mouse[1] - cache->vc->ar->winrct.ymin + cache->mouse[0], + cache->mouse[1] }; int tool = brush->sculpt_tool; @@ -3478,8 +3808,6 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush) /* compute 3d coordinate at same z from original location + mouse */ mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location); - initgrabz(cache->vc->rv3d, loc[0], loc[1], loc[2]); - ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location); /* compute delta to move verts by */ @@ -3517,17 +3845,17 @@ static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush) copy_v3_v3(cache->old_grab_location, grab_location); if (tool == SCULPT_TOOL_GRAB) - copy_v3_v3(sd->anchored_location, cache->true_location); + copy_v3_v3(cache->anchored_location, cache->true_location); else if (tool == SCULPT_TOOL_THUMB) - copy_v3_v3(sd->anchored_location, cache->orig_grab_location); + copy_v3_v3(cache->anchored_location, cache->orig_grab_location); if (ELEM(tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB)) { /* location stays the same for finding vertices in brush radius */ copy_v3_v3(cache->true_location, cache->orig_grab_location); - sd->draw_anchored = 1; - copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse); - sd->anchored_size = cache->pixel_radius; + ups->draw_anchored = 1; + copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse); + ups->anchored_size = ups->pixel_radius; } } } @@ -3538,6 +3866,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; Brush *brush = paint_brush(&sd->paint); @@ -3561,17 +3890,11 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, * brush coord/pressure/etc. * It's more an events design issue, which doesn't split coordinate/pressure/angle * changing events. We should avoid this after events system re-design */ - if (paint_space_stroke_enabled(brush) || cache->first_time) + if (paint_supports_dynamic_size(brush, PAINT_SCULPT) || cache->first_time) { cache->pressure = RNA_float_get(ptr, "pressure"); + } /* Truly temporary data that isn't stored in properties */ - - sd->draw_pressure = 1; - sd->pressure_value = cache->pressure; - - cache->previous_pixel_radius = cache->pixel_radius; - cache->pixel_radius = BKE_brush_size_get(scene, brush); - if (cache->first_time) { if (!BKE_brush_use_locked_size(scene, brush)) { cache->initial_radius = paint_calc_object_space_radius(cache->vc, @@ -3584,89 +3907,37 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, } } - if (BKE_brush_use_size_pressure(scene, brush)) { - cache->pixel_radius *= cache->pressure; + if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, PAINT_SCULPT)) { cache->radius = cache->initial_radius * cache->pressure; } - else + else { cache->radius = cache->initial_radius; + } cache->radius_squared = cache->radius * cache->radius; - if (!(brush->flag & BRUSH_ANCHORED || - ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, - SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) - { - copy_v2_v2(cache->tex_mouse, cache->mouse); - - if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) && - (brush->flag & BRUSH_RANDOM_ROTATION) && - !(brush->flag & BRUSH_RAKE)) - { - cache->special_rotation = 2.0f * (float)M_PI * BLI_frand(); - } - } - if (brush->flag & BRUSH_ANCHORED) { - int hit = 0; - - const float dx = cache->mouse[0] - cache->initial_mouse[0]; - const float dy = cache->mouse[1] - cache->initial_mouse[1]; - - sd->anchored_size = cache->pixel_radius = sqrt(dx * dx + dy * dy); - - cache->special_rotation = atan2(dx, dy) + M_PI; - if (brush->flag & BRUSH_EDGE_TO_EDGE) { float halfway[2]; float out[3]; - - halfway[0] = dx * 0.5f + cache->initial_mouse[0]; - halfway[1] = dy * 0.5f + cache->initial_mouse[1]; + halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]); + halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]); if (sculpt_stroke_get_location(C, out, halfway)) { - copy_v3_v3(sd->anchored_location, out); - copy_v2_v2(sd->anchored_initial_mouse, halfway); - copy_v2_v2(cache->tex_mouse, halfway); - copy_v3_v3(cache->true_location, sd->anchored_location); - sd->anchored_size /= 2.0f; - cache->pixel_radius /= 2.0f; - hit = 1; + copy_v3_v3(cache->anchored_location, out); + copy_v3_v3(cache->true_location, cache->anchored_location); } } - if (!hit) - copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse); - cache->radius = paint_calc_object_space_radius(paint_stroke_view_context(stroke), cache->true_location, - cache->pixel_radius); + ups->pixel_radius); cache->radius_squared = cache->radius * cache->radius; - copy_v3_v3(sd->anchored_location, cache->true_location); - - sd->draw_anchored = 1; - } - else if (brush->flag & BRUSH_RAKE) { - const float u = 0.5f; - const float v = 1 - u; - const float r = 20; - - const float dx = cache->last_rake[0] - cache->mouse[0]; - const float dy = cache->last_rake[1] - cache->mouse[1]; - - if (cache->first_time) { - copy_v2_v2(cache->last_rake, cache->mouse); - } - else if (dx * dx + dy * dy >= r * r) { - cache->special_rotation = atan2(dx, dy); - - cache->last_rake[0] = u * cache->last_rake[0] + v * cache->mouse[0]; - cache->last_rake[1] = u * cache->last_rake[1] + v * cache->mouse[1]; - } + copy_v3_v3(cache->anchored_location, cache->true_location); } - sculpt_update_brush_delta(sd, ob, brush); + sculpt_update_brush_delta(ups, ob, brush); if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) { const float dx = cache->mouse[0] - cache->initial_mouse[0]; @@ -3674,16 +3945,16 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, cache->vertex_rotation = -atan2f(dx, dy) * cache->bstrength; - sd->draw_anchored = 1; - copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse); - copy_v3_v3(sd->anchored_location, cache->true_location); - sd->anchored_size = cache->pixel_radius; + ups->draw_anchored = 1; + copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse); + copy_v3_v3(cache->anchored_location, cache->true_location); + ups->anchored_size = ups->pixel_radius; } - sd->special_rotation = cache->special_rotation; + cache->special_rotation = ups->brush_rotation; } -/* Returns true iff any of the smoothing modes are active (currently +/* Returns true if any of the smoothing modes are active (currently * one of smooth brush, autosmooth, mask smooth, or shift-key * smooth) */ static int sculpt_any_smooth_mode(const Brush *brush, @@ -3721,17 +3992,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; } @@ -3750,7 +4030,6 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) StrokeCache *cache; float ray_start[3], ray_end[3], ray_normal[3], dist; float obimat[4][4]; - float mval[2]; SculptRaycastData srd; view3d_set_viewcontext(C, &vc); @@ -3761,11 +4040,8 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) sculpt_stroke_modifiers_check(C, ob); - mval[0] = mouse[0] - vc.ar->winrct.xmin; - mval[1] = mouse[1] - vc.ar->winrct.ymin; - /* TODO: what if the segment is totally clipped? (return == 0) */ - ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mval, ray_start, ray_end); + ED_view3d_win_to_segment_clip(vc.ar, vc.v3d, mouse, ray_start, ray_end); invert_m4_m4(obimat, ob->obmat); mul_m4_v3(obimat, ray_start); @@ -3780,7 +4056,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); @@ -3797,7 +4073,7 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession /* init mtex nodes */ if (mtex->tex && mtex->tex->nodetree) - ntreeTexBeginExecTree(mtex->tex->nodetree, 1); /* has internal flag to detect it only does it once */ + ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */ /* TODO: Shouldn't really have to do this at the start of every * stroke, but sculpt would need some sort of notification when @@ -3829,8 +4105,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 +4116,18 @@ 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); + } +} + +/* Copy the PBVH bounding box into the object's bounding box */ +static void sculpt_update_object_bounding_box(Object *ob) +{ + if (ob->bb) { + float bb_min[3], bb_max[3]; + + BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max); + BKE_boundbox_init_from_minmax(ob->bb, bb_min, bb_max); } } @@ -3862,7 +4150,12 @@ 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); + /* Update the object's bounding box too so that the object + * doesn't get incorrectly clipped during drawing in + * draw_mesh_object(). [#33790] */ + sculpt_update_object_bounding_box(ob); + if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) { if (ss->cache) ss->cache->previous_r = r; @@ -3914,14 +4207,37 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; 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)ups->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); @@ -3933,11 +4249,12 @@ static void sculpt_brush_exit_tex(Sculpt *sd) MTex *mtex = &brush->mtex; if (mtex->tex && mtex->tex->nodetree) - ntreeTexEndExecTree(mtex->tex->nodetree->execdata, 1); + ntreeTexEndExecTree(mtex->tex->nodetree->execdata); } static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) { + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -3945,9 +4262,8 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_omp_done(ss); /* reset values used to draw brush after completing the stroke */ - sd->draw_anchored = 0; - sd->draw_pressure = 0; - sd->special_rotation = 0; + ups->draw_anchored = 0; + ups->draw_pressure = 0; /* Finished */ if (ss->cache) { @@ -3980,7 +4296,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 */ @@ -3999,7 +4318,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_brush_exit_tex(sd); } -static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { struct PaintStroke *stroke; int ignore_background_click; @@ -4016,8 +4335,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even op->customdata = stroke; /* For tablet rotation */ - ignore_background_click = RNA_boolean_get(op->ptr, - "ignore_background_click"); + ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) { paint_stroke_data_free(op); @@ -4055,7 +4373,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); @@ -4096,8 +4414,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* properties */ - RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, - "Stroke", ""); + RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Sculpt Stroke Mode", @@ -4137,6 +4454,265 @@ 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) +{ + BM_mesh_triangulate(bm, false, false, NULL, NULL); +} + +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); + BM_mesh_normals_update(ss->bm, false); + 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); + + BKE_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, const wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + const char *msg = TIP_("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"; + ot->description = "Symmetrize the topology modifications"; + + /* 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 +4798,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 +4811,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; @@ -4246,6 +4830,12 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) /* Enter sculptmode */ ob->mode |= OB_MODE_SCULPT; + /* Remove dynamic-topology flag; this will be enabled if the + * file was saved with dynamic topology on, but we don't + * automatically re-enter dynamic-topology mode when loading a + * file. */ + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + if (flush_recalc) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -4257,6 +4847,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 +4864,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 +4892,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); } |