diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 380 |
1 files changed, 227 insertions, 153 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index a94cb9dd971..8b7be205b12 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -30,6 +30,11 @@ * */ +/** \file blender/editors/sculpt_paint/sculpt.c + * \ingroup edsculpt + */ + + #include "MEM_guardedalloc.h" #include "BLI_math.h" @@ -59,6 +64,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_lattice.h" /* for armature_deform_verts */ +#include "BKE_node.h" #include "BIF_glutil.h" @@ -259,6 +265,8 @@ typedef struct StrokeCache { int alt_smooth; float plane_trim_squared; + + rcti previous_r; /* previous redraw rectangle */ } StrokeCache; /*** BVH Tree ***/ @@ -551,8 +559,8 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis, //distsq = len_squared_v3v3(mirror, cache->traced_location); distsq = len_squared_v3v3(mirror, cache->true_location); - if (distsq <= 4*(cache->radius_squared)) - return (2*(cache->radius) - sqrt(distsq)) / (2*(cache->radius)); + if (distsq <= 4.0f*(cache->radius_squared)) + return (2.0f*(cache->radius) - sqrtf(distsq)) / (2.0f*(cache->radius)); else return 0; } @@ -745,12 +753,12 @@ static float tex_strength(SculptSession *ss, Brush *br, float *point, const floa /* 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.001 || rotation < -0.001) { - const float angle = atan2(y, x) + rotation; + if (rotation > 0.001f || rotation < -0.001f) { + const float angle = atan2f(y, x) + rotation; const float flen = sqrtf(x*x + y*y); - x = flen * cos(angle); - y = flen * sin(angle); + x = flen * cosf(angle); + y = flen * sinf(angle); } x *= br->mtex.size[0]; @@ -812,7 +820,7 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float va if(sd->flags & (SCULPT_LOCK_X << i)) continue; - if((ss->cache->flag & (CLIP_X << i)) && (fabs(co[i]) <= ss->cache->clip_tolerance[i])) + if((ss->cache->flag & (CLIP_X << i)) && (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) co[i]= 0.0f; else co[i]= val[i]; @@ -828,8 +836,9 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], floa } } -static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode) +static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; int n; float out_flip[3] = {0.0f, 0.0f, 0.0f}; @@ -846,7 +855,7 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNod float private_an[3] = {0.0f, 0.0f, 0.0f}; float private_out_flip[3] = {0.0f, 0.0f, 0.0f}; - unode = sculpt_undo_push_node(ss, nodes[n]); + unode = sculpt_undo_push_node(ob, nodes[n]); sculpt_brush_test_init(ss, &test); if(ss->cache->original) { @@ -892,8 +901,9 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNod /* This initializes the faces to be moved for this sculpt for draw/layer/flatten; then it finds average normal for all active vertices - note that this is called once for each mirroring direction */ -static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode) +static void calc_sculpt_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); if (ss->cache->mirror_symmetry_pass == 0 && @@ -924,7 +934,7 @@ static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHN break; case SCULPT_DISP_DIR_AREA: - calc_area_normal(sd, ss, an, nodes, totnode); + calc_area_normal(sd, ob, an, nodes, totnode); default: break; @@ -1127,8 +1137,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no } } -static void smooth(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float bstrength) +static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength) { + SculptSession *ss = ob->sculpt; const int max_iterations = 4; const float fract = 1.0f/max_iterations; int iteration, n, count; @@ -1150,23 +1161,25 @@ static void smooth(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, } if(ss->multires) - multires_stitch_grids(ss->ob); + multires_stitch_grids(ob); } } -static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { - smooth(sd, ss, nodes, totnode, ss->cache->bstrength); + SculptSession *ss = ob->sculpt; + smooth(sd, ob, nodes, totnode, ss->cache->bstrength); } -static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float offset[3], area_normal[3]; float bstrength= ss->cache->bstrength; int n; - calc_sculpt_normal(sd, ss, area_normal, nodes, totnode); + calc_sculpt_normal(sd, ob, area_normal, nodes, totnode); /* offset with as much as possible factored in already */ mul_v3_v3fl(offset, area_normal, ss->cache->radius); @@ -1200,15 +1213,16 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t } } -static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float offset[3], area_normal[3]; float bstrength= ss->cache->bstrength; float flippedbstrength, crease_correction; int n; - calc_sculpt_normal(sd, ss, area_normal, nodes, totnode); + calc_sculpt_normal(sd, ob, area_normal, nodes, totnode); /* offset with as much as possible factored in already */ mul_v3_v3fl(offset, area_normal, ss->cache->radius); @@ -1263,8 +1277,9 @@ static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int } } -static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength= ss->cache->bstrength; int n; @@ -1295,8 +1310,9 @@ static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int } } -static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush= paint_brush(&sd->paint); float bstrength= ss->cache->bstrength; float grab_delta[3], an[3]; @@ -1307,7 +1323,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t int cache= 1; /* grab brush requires to test on original data */ SWAP(int, ss->cache->original, cache); - calc_sculpt_normal(sd, ss, an, nodes, totnode); + calc_sculpt_normal(sd, ob, an, nodes, totnode); SWAP(int, ss->cache->original, cache); } @@ -1330,7 +1346,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t short (*origno)[3]; float (*proxy)[3]; - unode= sculpt_undo_push_node(ss, nodes[n]); + unode= sculpt_undo_push_node(ob, nodes[n]); origco= unode->co; origno= unode->no; @@ -1352,8 +1368,9 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t } } -static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; float grab_delta[3]; @@ -1363,7 +1380,7 @@ static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - calc_sculpt_normal(sd, ss, an, nodes, totnode); + calc_sculpt_normal(sd, ob, an, nodes, totnode); cross_v3_v3v3(tmp, an, grab_delta); cross_v3_v3v3(cono, tmp, an); @@ -1392,8 +1409,9 @@ static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int } } -static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; float grab_delta[3], an[3]; @@ -1401,7 +1419,7 @@ static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, float len; if (brush->normal_weight > 0 || brush->flag & BRUSH_FRONTFACE) - calc_sculpt_normal(sd, ss, an, nodes, totnode); + calc_sculpt_normal(sd, ob, an, nodes, totnode); copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); @@ -1440,8 +1458,9 @@ static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, } } -static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; float grab_delta[3]; @@ -1451,7 +1470,7 @@ static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - calc_sculpt_normal(sd, ss, an, nodes, totnode); + calc_sculpt_normal(sd, ob, an, nodes, totnode); cross_v3_v3v3(tmp, an, grab_delta); cross_v3_v3v3(cono, tmp, an); @@ -1465,7 +1484,7 @@ static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int short (*origno)[3]; float (*proxy)[3]; - unode= sculpt_undo_push_node(ss, nodes[n]); + unode= sculpt_undo_push_node(ob, nodes[n]); origco= unode->co; origno= unode->no; @@ -1487,8 +1506,9 @@ static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int } } -static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush= paint_brush(&sd->paint); float bstrength= ss->cache->bstrength; float an[3]; @@ -1497,7 +1517,7 @@ static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 }; float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; - calc_sculpt_normal(sd, ss, an, nodes, totnode); + calc_sculpt_normal(sd, ob, an, nodes, totnode); axis_angle_to_mat3(m, an, angle); @@ -1510,7 +1530,7 @@ static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int short (*origno)[3]; float (*proxy)[3]; - unode= sculpt_undo_push_node(ss, nodes[n]); + unode= sculpt_undo_push_node(ob, nodes[n]); origco= unode->co; origno= unode->no; @@ -1534,8 +1554,9 @@ static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int } } -static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength= ss->cache->bstrength; float area_normal[3], offset[3]; @@ -1545,7 +1566,7 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int if(bstrength < 0) lim = -lim; - calc_sculpt_normal(sd, ss, area_normal, nodes, totnode); + calc_sculpt_normal(sd, ob, area_normal, nodes, totnode); mul_v3_v3v3(offset, ss->cache->scale, area_normal); @@ -1559,7 +1580,7 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int //proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; - unode= sculpt_undo_push_node(ss, nodes[n]); + unode= sculpt_undo_push_node(ob, nodes[n]); origco=unode->co; if(!unode->layer_disp) { @@ -1605,8 +1626,9 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int } } -static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength= ss->cache->bstrength; int n; @@ -1640,8 +1662,9 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in } } -static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float fc[3]) +static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float fc[3]) { + SculptSession *ss = ob->sculpt; int n; float count = 0; @@ -1658,7 +1681,7 @@ static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, float private_fc[3] = {0.0f, 0.0f, 0.0f}; int private_count = 0; - unode = sculpt_undo_push_node(ss, nodes[n]); + unode = sculpt_undo_push_node(ob, nodes[n]); sculpt_brush_test_init(ss, &test); if(ss->cache->original) { @@ -1692,8 +1715,9 @@ static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, /* this calculates flatten center and area normal together, amortizing the memory bandwidth and loop overhead to calculate both at the same time */ -static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3]) +static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3]) { + SculptSession *ss = ob->sculpt; int n; // an @@ -1720,7 +1744,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, P float private_fc[3] = {0.0f, 0.0f, 0.0f}; int private_count = 0; - unode = sculpt_undo_push_node(ss, nodes[n]); + unode = sculpt_undo_push_node(ob, nodes[n]); sculpt_brush_test_init(ss, &test); if(ss->cache->original) { @@ -1788,8 +1812,9 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, P } } -static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3]) +static void calc_sculpt_plane(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float an[3], float fc[3]) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); if (ss->cache->mirror_symmetry_pass == 0 && @@ -1820,7 +1845,7 @@ static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, i break; case SCULPT_DISP_DIR_AREA: - calc_area_normal_and_flatten_center(sd, ss, nodes, totnode, an, fc); + calc_area_normal_and_flatten_center(sd, ob, nodes, totnode, an, fc); default: break; @@ -1829,7 +1854,7 @@ static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, i // fc /* flatten center has not been calculated yet if we are not using the area normal */ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) - calc_flatten_center(sd, ss, nodes, totnode, fc); + calc_flatten_center(sd, ob, nodes, totnode, fc); // an copy_v3_v3(ss->cache->last_area_normal, an); @@ -1905,8 +1930,9 @@ static float get_offset(Sculpt *sd, SculptSession *ss) return rv; } -static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; @@ -1923,7 +1949,7 @@ static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in float temp[3]; - calc_sculpt_plane(sd, ss, nodes, totnode, an, fc); + calc_sculpt_plane(sd, ob, nodes, totnode, an, fc); displace = radius*offset; @@ -1964,8 +1990,9 @@ static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in } } -static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; @@ -1984,7 +2011,7 @@ static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t int flip; - calc_sculpt_plane(sd, ss, nodes, totnode, an, fc); + calc_sculpt_plane(sd, ob, nodes, totnode, an, fc); flip = bstrength < 0; @@ -2037,8 +2064,9 @@ static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t } } -static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_clay_tubes_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; @@ -2060,10 +2088,10 @@ static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int flip; - calc_sculpt_plane(sd, ss, nodes, totnode, sn, fc); + calc_sculpt_plane(sd, ob, nodes, totnode, sn, fc); if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) - calc_area_normal(sd, ss, an, nodes, totnode); + calc_area_normal(sd, ob, an, nodes, totnode); else copy_v3_v3(an, sn); @@ -2127,8 +2155,9 @@ static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, } } -static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); float bstrength = ss->cache->bstrength; @@ -2144,7 +2173,7 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t float temp[3]; - calc_sculpt_plane(sd, ss, nodes, totnode, an, fc); + calc_sculpt_plane(sd, ob, nodes, totnode, an, fc); displace = radius*offset; @@ -2187,8 +2216,9 @@ static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t } } -static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) +static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); rctf mr; float xrad, yrad; @@ -2205,7 +2235,7 @@ static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int float temp[3]; - calc_sculpt_plane(sd, ss, nodes, totnode, an, fc); + calc_sculpt_plane(sd, ob, nodes, totnode, an, fc); displace = -radius*offset; @@ -2291,15 +2321,16 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) for (a= 0; a < me->totvert; a++, mvert++) VECCOPY(mvert->co, vertCos[a]); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } /* apply new coords on active key block */ vertcos_to_key(ob, kb, vertCos); } -static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush) +static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) { + SculptSession *ss = ob->sculpt; SculptSearchSphereData data; PBVHNode **nodes = NULL; int n, totnode; @@ -2315,71 +2346,71 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush) if (totnode) { #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n= 0; n < totnode; n++) { - sculpt_undo_push_node(ss, nodes[n]); + sculpt_undo_push_node(ob, nodes[n]); BLI_pbvh_node_mark_update(nodes[n]); } /* Apply one type of brush action */ switch(brush->sculpt_tool){ case SCULPT_TOOL_DRAW: - do_draw_brush(sd, ss, nodes, totnode); + do_draw_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SMOOTH: - do_smooth_brush(sd, ss, nodes, totnode); + do_smooth_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CREASE: - do_crease_brush(sd, ss, nodes, totnode); + do_crease_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_BLOB: - do_crease_brush(sd, ss, nodes, totnode); + do_crease_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_PINCH: - do_pinch_brush(sd, ss, nodes, totnode); + do_pinch_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_INFLATE: - do_inflate_brush(sd, ss, nodes, totnode); + do_inflate_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_GRAB: - do_grab_brush(sd, ss, nodes, totnode); + do_grab_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_ROTATE: - do_rotate_brush(sd, ss, nodes, totnode); + do_rotate_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SNAKE_HOOK: - do_snake_hook_brush(sd, ss, nodes, totnode); + do_snake_hook_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_NUDGE: - do_nudge_brush(sd, ss, nodes, totnode); + do_nudge_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_THUMB: - do_thumb_brush(sd, ss, nodes, totnode); + do_thumb_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_LAYER: - do_layer_brush(sd, ss, nodes, totnode); + do_layer_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_FLATTEN: - do_flatten_brush(sd, ss, nodes, totnode); + do_flatten_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY: - do_clay_brush(sd, ss, nodes, totnode); + do_clay_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY_TUBES: - do_clay_tubes_brush(sd, ss, nodes, totnode); + do_clay_tubes_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_FILL: - do_fill_brush(sd, ss, nodes, totnode); + do_fill_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SCRAPE: - do_scrape_brush(sd, ss, nodes, totnode); + do_scrape_brush(sd, ob, nodes, totnode); break; } if (brush->sculpt_tool != SCULPT_TOOL_SMOOTH && brush->autosmooth_factor > 0) { if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) { - smooth(sd, ss, nodes, totnode, brush->autosmooth_factor*(1-ss->cache->pressure)); + smooth(sd, ob, nodes, totnode, brush->autosmooth_factor*(1-ss->cache->pressure)); } else { - smooth(sd, ss, nodes, totnode, brush->autosmooth_factor); + smooth(sd, ob, nodes, totnode, brush->autosmooth_factor); } } @@ -2388,9 +2419,9 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush) } /* flush displacement from deformed PBVH vertex to original mesh */ -static void sculpt_flush_pbvhvert_deform(SculptSession *ss, PBVHVertexIter *vd) +static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) { - Object *ob= ss->ob; + SculptSession *ss = ob->sculpt; Mesh *me= ob->data; float disp[3], newco[3]; int index= vd->vert_indices[vd->i]; @@ -2406,8 +2437,9 @@ static void sculpt_flush_pbvhvert_deform(SculptSession *ss, PBVHVertexIter *vd) copy_v3_v3(me->mvert[index].co, newco); } -static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss) +static void sculpt_combine_proxies(Sculpt *sd, Object *ob) { + SculptSession *ss = ob->sculpt; Brush *brush= paint_brush(&sd->paint); PBVHNode** nodes; int totnode, n; @@ -2427,7 +2459,7 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss) float (*orco)[3]; if(use_orco) - orco= sculpt_undo_push_node(ss, nodes[n])->co; + orco= sculpt_undo_push_node(ob, nodes[n])->co; BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count); @@ -2446,7 +2478,7 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss) sculpt_clip(sd, ss, vd.co, val); if(ss->modifiers_active) - sculpt_flush_pbvhvert_deform(ss, &vd); + sculpt_flush_pbvhvert_deform(ob, &vd); } BLI_pbvh_vertex_iter_end; @@ -2459,8 +2491,9 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss) } /* copy the modified vertices from bvh to the active key */ -static void sculpt_update_keyblock(SculptSession *ss) +static void sculpt_update_keyblock(Object *ob) { + SculptSession *ss = ob->sculpt; float (*vertCos)[3]; /* Keyblock update happens after hadning deformation caused by modifiers, @@ -2469,7 +2502,7 @@ static void sculpt_update_keyblock(SculptSession *ss) else vertCos = BLI_pbvh_get_vertCos(ss->pbvh); if (vertCos) { - sculpt_vertcos_to_key(ss->ob, ss->kb, vertCos); + sculpt_vertcos_to_key(ob, ss->kb, vertCos); if(vertCos != ss->orig_cos) MEM_freeN(vertCos); @@ -2477,40 +2510,53 @@ static void sculpt_update_keyblock(SculptSession *ss) } /* flush displacement from deformed PBVH to original layer */ -static void sculpt_flush_stroke_deform(Sculpt *sd, SculptSession *ss) +static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) { - if(!ss->kb) { - Object *ob= ss->ob; + SculptSession *ss = ob->sculpt; + Brush *brush= paint_brush(&sd->paint); + + if(ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) { + /* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't + propagate needed deformation to original base */ + + int n, totnode; Mesh *me= (Mesh*)ob->data; - Brush *brush= paint_brush(&sd->paint); + PBVHNode** nodes; + float (*vertCos)[3]= NULL; - if(ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) { - /* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't - propagate needed deformation to original base */ + if(ss->kb) + vertCos= MEM_callocN(sizeof(*vertCos)*me->totvert, "flushStrokeDeofrm keyVerts"); - int n, totnode; - PBVHNode** nodes; + BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - BLI_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; - #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) { + sculpt_flush_pbvhvert_deform(ob, &vd); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - sculpt_flush_pbvhvert_deform(ss, &vd); + if(vertCos) { + int index= vd.vert_indices[vd.i]; + copy_v3_v3(vertCos[index], ss->orig_cos[index]); } - BLI_pbvh_vertex_iter_end; } + BLI_pbvh_vertex_iter_end; + } - MEM_freeN(nodes); + if(vertCos) { + sculpt_vertcos_to_key(ob, ss->kb, vertCos); + MEM_freeN(vertCos); } + MEM_freeN(nodes); + /* Modifiers could depend on mesh normals, so we should update them/ Note, then if sculpting happens on locked key, normals should be re-calculated after applying coords from keyblock on base mesh */ - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); - } else sculpt_update_keyblock(ss); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); + } else if (ss->kb) + sculpt_update_keyblock(ob); } //static int max_overlap_count(Sculpt *sd) @@ -2564,33 +2610,36 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry); } -static void do_radial_symmetry(Sculpt *sd, SculptSession *ss, Brush *brush, const char symm, const int axis, const float feather) +static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, const char symm, const int axis, const float feather) { + SculptSession *ss = ob->sculpt; int i; for(i = 1; i < sd->radial_symm[axis-'X']; ++i) { 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, ss, brush); + do_brush_action(sd, ob, brush); } } /* noise texture gives different values for the same input coord; this can tear a multires mesh during sculpting so do a stitch in this case */ -static void sculpt_fix_noise_tear(Sculpt *sd, SculptSession *ss) +static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); MTex *mtex = &brush->mtex; if(ss->multires && mtex->tex && mtex->tex->type == TEX_NOISE) - multires_stitch_grids(ss->ob); + multires_stitch_grids(ob); } -static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss) +static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob) { Brush *brush = paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; const char symm = sd->flags & 7; int i; @@ -2608,21 +2657,21 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss) cache->radial_symmetry_pass= 0; calc_brushdata_symm(sd, cache, i, 0, 0, feather); - do_brush_action(sd, ss, brush); + do_brush_action(sd, ob, brush); - do_radial_symmetry(sd, ss, brush, i, 'X', feather); - do_radial_symmetry(sd, ss, brush, i, 'Y', feather); - do_radial_symmetry(sd, ss, brush, i, 'Z', feather); + 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); } } - sculpt_combine_proxies(sd, ss); + sculpt_combine_proxies(sd, ob); /* hack to fix noise texture tearing mesh */ - sculpt_fix_noise_tear(sd, ss); + sculpt_fix_noise_tear(sd, ob); if (ss->modifiers_active) - sculpt_flush_stroke_deform(sd, ss); + sculpt_flush_stroke_deform(sd, ob); cache->first_time= 0; } @@ -2662,8 +2711,6 @@ void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap) SculptSession *ss = ob->sculpt; MultiresModifierData *mmd= sculpt_multires_active(scene, ob); - ss->ob= ob; - ss->modifiers_active= sculpt_modifiers_active(scene, ob); if((ob->shapeflag & OB_SHAPE_LOCK) && !mmd) ss->kb= ob_get_keyblock(ob); @@ -2909,7 +2956,7 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio ss->cache->initial_mouse[1] = 0; } - mode = RNA_int_get(op->ptr, "mode"); + mode = RNA_enum_get(op->ptr, "mode"); cache->invert = mode == BRUSH_STROKE_INVERT; cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH; @@ -2987,8 +3034,9 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio cache->vertex_rotation= 0; } -static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brush) +static void sculpt_update_brush_delta(Sculpt *sd, Object *ob, Brush *brush) { + SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; int tool = brush->sculpt_tool; @@ -3020,19 +3068,19 @@ static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brus case SCULPT_TOOL_GRAB: case SCULPT_TOOL_THUMB: sub_v3_v3v3(delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ss->ob->obmat); + invert_m4_m4(imat, ob->obmat); mul_mat3_m4_v3(imat, delta); add_v3_v3(cache->grab_delta, delta); break; case SCULPT_TOOL_CLAY_TUBES: case SCULPT_TOOL_NUDGE: sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ss->ob->obmat); + invert_m4_m4(imat, ob->obmat); mul_mat3_m4_v3(imat, cache->grab_delta); break; case SCULPT_TOOL_SNAKE_HOOK: sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); - invert_m4_m4(imat, ss->ob->obmat); + invert_m4_m4(imat, ob->obmat); mul_mat3_m4_v3(imat, cache->grab_delta); break; } @@ -3060,8 +3108,9 @@ static void sculpt_update_brush_delta(Sculpt *sd, SculptSession *ss, Brush *brus } /* Initialize the stroke cache variants from operator properties */ -static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr) +static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, struct PaintStroke *stroke, PointerRNA *ptr) { + SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; Brush *brush = paint_brush(&sd->paint); @@ -3126,7 +3175,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession (brush->flag & BRUSH_RANDOM_ROTATION) && !(brush->flag & BRUSH_RAKE)) { - cache->special_rotation = 2*M_PI*BLI_frand(); + cache->special_rotation = 2.0f*(float)M_PI*BLI_frand(); } } @@ -3144,8 +3193,8 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession float halfway[2]; float out[3]; - halfway[0] = dx*0.5 + cache->initial_mouse[0]; - halfway[1] = dy*0.5 + cache->initial_mouse[1]; + halfway[0] = (float)dx * 0.5f + cache->initial_mouse[0]; + halfway[1] = (float)dy * 0.5f + cache->initial_mouse[1]; if (sculpt_stroke_get_location(C, stroke, out, halfway)) { copy_v3_v3(sd->anchored_location, out); @@ -3187,7 +3236,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession } } - sculpt_update_brush_delta(sd, ss, brush); + sculpt_update_brush_delta(sd, ob, brush); if(brush->sculpt_tool == SCULPT_TOOL_ROTATE) { dx = cache->mouse[0] - cache->initial_mouse[0]; @@ -3204,13 +3253,15 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession sd->special_rotation = cache->special_rotation; } -static void sculpt_stroke_modifiers_check(bContext *C, SculptSession *ss) +static void sculpt_stroke_modifiers_check(bContext *C, Object *ob) { + SculptSession *ss = ob->sculpt; + if(ss->modifiers_active) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Brush *brush = paint_brush(&sd->paint); - sculpt_update_mesh_elements(CTX_data_scene(C), ss->ob, brush->sculpt_tool == SCULPT_TOOL_SMOOTH); + sculpt_update_mesh_elements(CTX_data_scene(C), ob, brush->sculpt_tool == SCULPT_TOOL_SMOOTH); } } @@ -3248,7 +3299,8 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float* tmin) int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]) { ViewContext *vc = paint_stroke_view_context(stroke); - SculptSession *ss= vc->obact->sculpt; + Object *ob = vc->obact; + SculptSession *ss= ob->sculpt; StrokeCache *cache= ss->cache; float ray_start[3], ray_end[3], ray_normal[3], dist; float obimat[4][4]; @@ -3258,11 +3310,11 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou mval[0] = mouse[0] - vc->ar->winrct.xmin; mval[1] = mouse[1] - vc->ar->winrct.ymin; - sculpt_stroke_modifiers_check(C, ss); + sculpt_stroke_modifiers_check(C, ob); viewline(vc->ar, vc->v3d, mval, ray_start, ray_end); - invert_m4_m4(obimat, ss->ob->obmat); + invert_m4_m4(obimat, ob->obmat); mul_m4_v3(obimat, ray_start); mul_m4_v3(obimat, ray_end); @@ -3285,6 +3337,21 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou return srd.hit; } +static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss) +{ + Brush *brush = paint_brush(&sd->paint); + MTex *mtex= &brush->mtex; + + /* init mtex nodes */ + if(mtex->tex && mtex->tex->nodetree) + ntreeBeginExecTree(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 + changes are made to the texture. */ + sculpt_update_tex(sd, ss); +} + static int sculpt_brush_stroke_init(bContext *C, ReportList *reports) { Scene *scene= CTX_data_scene(C); @@ -3299,11 +3366,7 @@ static int sculpt_brush_stroke_init(bContext *C, ReportList *reports) } view3d_operator_needs_opengl(C); - - /* TODO: Shouldn't really have to do this at the start of every - stroke, but sculpt would need some sort of notification when - changes are made to the texture. */ - sculpt_update_tex(sd, ss); + sculpt_brush_init_tex(sd, ss); sculpt_update_mesh_elements(scene, ob, brush->sculpt_tool == SCULPT_TOOL_SMOOTH); @@ -3381,19 +3444,19 @@ static void sculpt_flush_update(bContext *C) BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) { - //rcti tmp; - r.xmin += ar->winrct.xmin + 1 + off; r.xmax += ar->winrct.xmin - 1 - off; r.ymin += ar->winrct.ymin + 1 + off; r.ymax += ar->winrct.ymin - 1 - off; - //tmp = r; + if (ss->cache) { + rcti tmp = r; - //if (!BLI_rcti_is_empty(&ss->previous_r)) - // BLI_union_rcti(&r, &ss->previous_r); + if (!BLI_rcti_is_empty(&ss->cache->previous_r)) + BLI_union_rcti(&r, &ss->cache->previous_r); - //ss->previous_r= tmp; + ss->cache->previous_r= tmp; + } ss->partial_redraw = 1; ED_region_tag_redraw_partial(ar, &r); @@ -3450,17 +3513,27 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - SculptSession *ss = CTX_data_active_object(C)->sculpt; - - sculpt_stroke_modifiers_check(C, ss); - sculpt_update_cache_variants(C, sd, ss, stroke, itemptr); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + 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, ss); + do_symmetrical_brush_actions(sd, ob); /* Cleanup */ sculpt_flush_update(C); } +static void sculpt_brush_exit_tex(Sculpt *sd) +{ + Brush *brush= paint_brush(&sd->paint); + MTex *mtex= &brush->mtex; + + if(mtex->tex && mtex->tex->nodetree) + ntreeEndExecTree(mtex->tex->nodetree); +} + static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused) { Object *ob= CTX_data_active_object(C); @@ -3479,7 +3552,7 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused) Brush *brush= paint_brush(&sd->paint); brush->flag &= ~BRUSH_INVERTED; - sculpt_stroke_modifiers_check(C, ss); + sculpt_stroke_modifiers_check(C, ob); /* Alt-Smooth */ if (ss->cache->alt_smooth) { @@ -3500,7 +3573,7 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused) /* optimization: if there is locked key and active modifiers present in */ /* the stack, keyblock is updating at each step. otherwise we could update */ /* keyblock only when stroke is finished */ - if(ss->kb && !ss->modifiers_active) sculpt_update_keyblock(ss); + if(ss->kb && !ss->modifiers_active) sculpt_update_keyblock(ob); ss->partial_redraw = 0; @@ -3510,6 +3583,8 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused) WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); } + + sculpt_brush_exit_tex(sd); } static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) @@ -3523,7 +3598,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even stroke = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, - sculpt_stroke_done); + sculpt_stroke_done, event->type); op->customdata = stroke; @@ -3553,7 +3628,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start, - sculpt_stroke_update_step, sculpt_stroke_done); + sculpt_stroke_update_step, sculpt_stroke_done, 0); sculpt_update_cache_invariants(C, sd, ss, op, NULL); @@ -3636,7 +3711,6 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) static void sculpt_init_session(Scene *scene, Object *ob) { ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - ob->sculpt->ob = ob; sculpt_update_mesh_elements(scene, ob, 0); } |