diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 58 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex.c | 4 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 1365 |
4 files changed, 779 insertions, 652 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b5748d7bc88..0689e8e63d7 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -43,11 +43,13 @@ struct ARegion; struct VPaint; /* paint_stroke.c */ +typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]); typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event); typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr); typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke); -struct PaintStroke *paint_stroke_new(struct bContext *C, StrokeTestStart test_start, +struct PaintStroke *paint_stroke_new(struct bContext *C, + StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeDone done); int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event); int paint_stroke_exec(struct bContext *C, struct wmOperator *op); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 6e256bee7f2..c2d22089442 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -73,6 +73,7 @@ typedef struct PaintStroke { passes over the mesh */ int stroke_started; + StrokeGetLocation get_location; StrokeTestStart test_start; StrokeUpdateStep update_step; StrokeDone done; @@ -118,12 +119,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *customdata) static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2]) { PointerRNA itemptr; - float cur_depth, pressure = 1; - float center[3]; + float pressure = 1; + float center[3] = {0, 0, 0}; PaintStroke *stroke = op->customdata; - cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]); - view3d_unproject(&stroke->mats, center, mouse[0], mouse[1], cur_depth); + /* XXX: can remove the if statement once all modes have this */ + if(stroke->get_location) + stroke->get_location(C, stroke, center, mouse); /* Tablet */ if(event->custom == EVT_DATA_TABLET) { @@ -208,15 +210,19 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const /**** Public API ****/ -PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start, - StrokeUpdateStep update_step, StrokeDone done) +PaintStroke *paint_stroke_new(bContext *C, + StrokeGetLocation get_location, + StrokeTestStart test_start, + StrokeUpdateStep update_step, + StrokeDone done) { PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke"); stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C))); view3d_set_viewcontext(C, &stroke->vc); - view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats); + view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats); + stroke->get_location = get_location; stroke->test_start = test_start; stroke->update_step = update_step; stroke->done = done; @@ -226,12 +232,9 @@ PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start, int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) { - ARegion *ar = CTX_wm_region(C); PaintStroke *stroke = op->customdata; float mouse[2]; - - if(event->type == TIMER && (event->customdata != stroke->timer)) - return OPERATOR_RUNNING_MODAL; + int first= 0; if(!stroke->stroke_started) { stroke->last_mouse_position[0] = event->x; @@ -246,26 +249,27 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate); } - ED_region_tag_redraw(ar); + first= 1; + //ED_region_tag_redraw(ar); } - if(stroke->stroke_started) { - if(paint_smooth_stroke(stroke, mouse, event)) { - if(paint_space_stroke_enabled(stroke->brush)) { - if(!paint_space_stroke(C, op, event, mouse)) - ED_region_tag_redraw(ar); + /* TODO: fix hardcoded event here */ + if(first || event->type == MOUSEMOVE || (event->type == TIMER && (event->customdata == stroke->timer))) { + if(stroke->stroke_started) { + if(paint_smooth_stroke(stroke, mouse, event)) { + if(paint_space_stroke_enabled(stroke->brush)) { + if(!paint_space_stroke(C, op, event, mouse)) + ;//ED_region_tag_redraw(ar); + } + else + paint_brush_stroke_add_step(C, op, event, mouse); } else - paint_brush_stroke_add_step(C, op, event, mouse); + ;//ED_region_tag_redraw(ar); } - else - ED_region_tag_redraw(ar); } - - /* TODO: fix hardcoded event here */ - if(event->type == LEFTMOUSE && event->val == KM_RELEASE) { - /* Exit stroke, free data */ - + else if(event->type == LEFTMOUSE && event->val == KM_RELEASE) { + /* exit stroke, free data */ if(stroke->smooth_stroke_cursor) WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor); @@ -276,8 +280,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) MEM_freeN(stroke); return OPERATOR_FINISHED; } - else - return OPERATOR_RUNNING_MODAL; + + return OPERATOR_RUNNING_MODAL; } int paint_stroke_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 408f4862b6f..582a0c149b4 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1610,7 +1610,7 @@ static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke) static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) { - op->customdata = paint_stroke_new(C, wpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, wpaint_stroke_update_step, wpaint_stroke_done); @@ -1909,7 +1909,7 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event) { - op->customdata = paint_stroke_new(C, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, vpaint_stroke_update_step, vpaint_stroke_done); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c4c7f436f12..e29f0d56ba2 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -35,6 +35,8 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" +#include "BLI_ghash.h" +#include "BLI_pbvh.h" #include "DNA_armature_types.h" #include "DNA_brush_types.h" @@ -52,6 +54,7 @@ #include "DNA_color_types.h" #include "BKE_brush.h" +#include "BKE_cdderivedmesh.h" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" @@ -131,7 +134,6 @@ typedef struct StrokeCache { int flag; float clip_tolerance[3]; float initial_mouse[2]; - float depth; /* Variants */ float radius; @@ -140,6 +142,7 @@ typedef struct StrokeCache { float flip; float pressure; float mouse[2]; + float bstrength; /* The rest is temporary storage that isn't saved as a property */ @@ -147,11 +150,17 @@ typedef struct StrokeCache { bglMats *mats; + /* Clean this up! */ + ViewContext *vc; + Brush *brush; + short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */ float (*face_norms)[3]; /* Copy of the mesh faces' normals */ float rotation; /* Texture rotation (radians) for anchored and rake modes */ int pixel_radius, previous_pixel_radius; ListBase grab_active_verts[8]; /* The same list of verts is used throught grab stroke */ + PBVHNode **grab_active_nodes[8]; + int grab_active_totnode[8]; float grab_delta[3], grab_delta_symmetry[3]; float old_grab_location[3]; int symmetry; /* Symmetry index between 0 and 7 */ @@ -159,20 +168,6 @@ typedef struct StrokeCache { int last_rake[2]; /* Last location of updating rake rotation */ } StrokeCache; -typedef struct RectNode { - struct RectNode *next, *prev; - rcti r; -} RectNode; - -/* Used to store to 2D screen coordinates of each vertex in the mesh. */ -typedef struct ProjVert { - short co[2]; - - /* Used to mark whether a vertex is inside a rough bounding box - containing the brush. */ - char inside; -} ProjVert; - /* ===== OPENGL ===== * * Simple functions to get data from the GL @@ -189,7 +184,7 @@ static void projectf(bglMats *mats, const float v[3], float p[2]) p[1]= uy; } -static void project(bglMats *mats, const float v[3], short p[2]) +/*XXX: static void project(bglMats *mats, const float v[3], short p[2]) { float f[2]; projectf(mats, v, f); @@ -197,6 +192,127 @@ static void project(bglMats *mats, const float v[3], short p[2]) p[0]= f[0]; p[1]= f[1]; } +*/ + +/*** BVH Tree ***/ + +/* Get a screen-space rectangle of the modified area */ +int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, + Object *ob, rcti *rect) +{ + float bb_min[3], bb_max[3], pmat[4][4]; + int i, j, k; + + view3d_get_object_project_mat(rv3d, ob, pmat); + + BLI_pbvh_redraw_bounding_box(ob->sculpt->tree, bb_min, bb_max); + + rect->xmin = rect->ymin = INT_MAX; + rect->xmax = rect->ymax = INT_MIN; + + if(bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2]) + return 0; + + for(i = 0; i < 2; ++i) { + for(j = 0; j < 2; ++j) { + for(k = 0; k < 2; ++k) { + float vec[3], proj[2]; + vec[0] = i ? bb_min[0] : bb_max[0]; + vec[1] = j ? bb_min[1] : bb_max[1]; + vec[2] = k ? bb_min[2] : bb_max[2]; + view3d_project_float(ar, vec, proj, pmat); + rect->xmin = MIN2(rect->xmin, proj[0]); + rect->xmax = MAX2(rect->xmax, proj[0]); + rect->ymin = MIN2(rect->ymin, proj[1]); + rect->ymax = MAX2(rect->ymax, proj[1]); + } + } + } + + return rect->xmin < rect->xmax && rect->ymin < rect->ymax; +} + +void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar, + RegionView3D *rv3d, Object *ob) +{ + BoundBox *bb = MEM_callocN(sizeof(BoundBox), "sculpt boundbox"); + bglMats mats; + int i; + rcti rect; + + view3d_get_transformation(ar, rv3d, ob, &mats); + sculpt_get_redraw_rect(ar, rv3d,ob, &rect); + +#if 1 + /* use some extra space just in case */ + rect.xmin -= 2; + rect.xmax += 2; + rect.ymin -= 2; + rect.ymax += 2; +#else + /* it was doing this before, allows to redraw a smaller + part of the screen but also gives artifaces .. */ + rect.xmin += 2; + rect.xmax -= 2; + rect.ymin += 2; + rect.ymax -= 2; +#endif + + view3d_calculate_clipping(bb, planes, &mats, &rect); + + for(i = 0; i < 16; ++i) + ((float*)planes)[i] = -((float*)planes)[i]; + + MEM_freeN(bb); + + /* clear redraw flag from nodes */ + BLI_pbvh_update(ob->sculpt->tree, PBVH_UpdateRedraw, NULL, NULL); +} + +/*** Looping Over Nodes in a BVH Node ***/ + +typedef struct SculptVertexData { + float radius_squared; + float location[3]; + + MVert *mvert; + int *verts; + int i, index, totvert; + + float *co; + short *no; + float dist; +} SculptVertexData; + +static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss, PBVHNode *node, SculptVertexData *vd) +{ + vd->radius_squared= ss->cache->radius*ss->cache->radius; + VecCopyf(vd->location, ss->cache->location); + + vd->mvert= ss->mvert; + vd->i= 0; + BLI_pbvh_node_get_verts(node, &vd->verts, &vd->totvert); +} + +static int sculpt_node_verts_next(SculptVertexData *vd) +{ + while(vd->i < vd->totvert) { + float delta[3], dsq; + + vd->index= vd->verts[vd->i++]; + vd->co= vd->mvert[vd->index].co; + vd->no= vd->mvert[vd->index].no; + VECSUB(delta, vd->co, vd->location); + dsq = INPR(delta, delta); + + if(dsq < vd->radius_squared) { + vd->dist = sqrt(dsq); + return 1; + } + } + + return 0; +} /* ===== Sculpting ===== * @@ -236,6 +352,168 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache) } } +/* Uses symm to selectively flip any axis of a coordinate. */ +static void flip_coord(float out[3], float in[3], const char symm) +{ + if(symm & SCULPT_SYMM_X) + out[0]= -in[0]; + else + out[0]= in[0]; + if(symm & SCULPT_SYMM_Y) + out[1]= -in[1]; + else + out[1]= in[1]; + if(symm & SCULPT_SYMM_Z) + out[2]= -in[2]; + else + out[2]= in[2]; +} + +/* Get a pixel from the texcache at (px, py) */ +static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py) +{ + unsigned *p; + p = ss->texcache + py * ss->texcache_side + px; + return ((unsigned char*)(p))[0]; +} + +static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v) +{ + int x, y, x2, y2; + const int tc_max = ss->texcache_side - 1; + float urat, vrat, uopp; + + if(u < 0) u = 0; + else if(u >= ss->texcache_side) u = tc_max; + if(v < 0) v = 0; + else if(v >= ss->texcache_side) v = tc_max; + + x = floor(u); + y = floor(v); + x2 = x + 1; + y2 = y + 1; + + if(x2 > ss->texcache_side) x2 = tc_max; + if(y2 > ss->texcache_side) y2 = tc_max; + + urat = u - x; + vrat = v - y; + uopp = 1 - urat; + + return ((get_texcache_pixel(ss, x, y) * uopp + + get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) + + (get_texcache_pixel(ss, x, y2) * uopp + + get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0; +} + +/* Return a multiplier for brush strength on a particular vertex. */ +static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len) +{ + MTex *tex = NULL; + float avg= 1; + + if(br->texact >= 0) + tex = br->mtex[br->texact]; + + if(!tex) { + avg= 1; + } + else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) { + float jnk; + + /* Get strength by feeding the vertex + location directly into a texture */ + externtex(tex, point, &avg, + &jnk, &jnk, &jnk, &jnk); + } + else if(ss->texcache) { + const float bsize= ss->cache->pixel_radius * 2; + const float rot= tex->rot + ss->cache->rotation; + int px, py; + float flip[3], point_2d[2]; + + /* If the active area is being applied for symmetry, flip it + across the symmetry axis in order to project it. This insures + that the brush texture will be oriented correctly. */ + VecCopyf(flip, point); + flip_coord(flip, flip, ss->cache->symmetry); + projectf(ss->cache->mats, flip, point_2d); + + /* For Tile and Drag modes, get the 2D screen coordinates of the + and scale them up or down to the texture size. */ + if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) { + const int sx= (const int)tex->size[0]; + const int sy= (const int)tex->size[1]; + + float fx= point_2d[0]; + float fy= point_2d[1]; + + float angle= atan2(fy, fx) - rot; + float flen= sqrtf(fx*fx + fy*fy); + + if(rot<0.001 && rot>-0.001) { + px= point_2d[0]; + py= point_2d[1]; + } else { + px= flen * cos(angle) + 2000; + py= flen * sin(angle) + 2000; + } + if(sx != 1) + px %= sx-1; + if(sy != 1) + py %= sy-1; + avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy); + } + else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) { + float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize; + float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize; + + float angle= atan2(fy, fx) - rot; + float flen= sqrtf(fx*fx + fy*fy); + + fx = flen * cos(angle) + 0.5; + fy = flen * sin(angle) + 0.5; + + avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side); + } + } + + avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */ + + return avg; +} + +typedef struct { + Sculpt *sd; + SculptSession *ss; + float radius_squared; + ListBase *active_verts; + float area_normal[3]; +} SculptSearchSphereData; + +/* Test AABB against sphere */ +static int sculpt_search_sphere_cb(PBVHNode *node, + float bb_min[3], float bb_max[3], void *data_v) +{ + SculptSearchSphereData *data = data_v; + float *center = data->ss->cache->location, nearest[3]; + float t[3]; + int i; + + for(i = 0; i < 3; ++i) { + if(bb_min[i] > center[i]) + nearest[i] = bb_min[i]; + else if(bb_max[i] < center[i]) + nearest[i] = bb_max[i]; + else + nearest[i] = center[i]; + } + + VecSubf(t, center, nearest); + + return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared; +} + /* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float val[3]) { @@ -265,26 +543,41 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons } } -/* Currently only for the draw brush; finds average normal for all active - vertices */ -static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const ListBase* active_verts) +/* For draw/layer/flatten; finds average normal for all active vertices */ +static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3], PBVHNode **nodes, int totnode) { Brush *brush = paint_brush(&sd->paint); StrokeCache *cache = ss->cache; - ActiveData *node = active_verts->first; const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */ - float out_flip[3]; - float *out_dir = cache->view_normal_symmetry; - - out[0]=out[1]=out[2] = out_flip[0]=out_flip[1]=out_flip[2] = 0; + float out[3] = {0.0f, 0.0f, 0.0f}; + float out_flip[3] = {0.0f, 0.0f, 0.0f}; + float out_dir[3]; + int n; + + VecCopyf(out_dir, cache->view_normal_symmetry); + + /* threaded loop over nodes */ + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; + float nout[3] = {0.0f, 0.0f, 0.0f}; + float nout_flip[3] = {0.0f, 0.0f, 0.0f}; + + sculpt_node_verts_init(sd, ss, nodes[n], &vd); - if(brush->flag & BRUSH_ANCHORED) { - for(; node; node = node->next) - add_norm_if(out_dir, out, out_flip, cache->orig_norms[node->Index]); - } - else { - for(; node; node = node->next) - add_norm_if(out_dir, out, out_flip, ss->mvert[node->Index].no); + if(brush->flag & BRUSH_ANCHORED) { + while(sculpt_node_verts_next(&vd)) + add_norm_if(out_dir, nout, nout_flip, cache->orig_norms[vd.index]); + } + else { + while(sculpt_node_verts_next(&vd)) + add_norm_if(out_dir, nout, nout_flip, ss->mvert[vd.index].no); + } + + /* we sum per node and add together later for threads */ + #pragma omp critical + VecAddf(out, out, nout); + VecAddf(out_flip, out_flip, nout_flip); } if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) { @@ -293,46 +586,48 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const Normalize(out); - if(out_dir) { - out[0] = out_dir[0] * view + out[0] * (10-view); - out[1] = out_dir[1] * view + out[1] * (10-view); - out[2] = out_dir[2] * view + out[2] * (10-view); - } + out[0] = out_dir[0] * view + out[0] * (10-view); + out[1] = out_dir[1] * view + out[1] * (10-view); + out[2] = out_dir[2] * view + out[2] * (10-view); Normalize(out); + VecCopyf(area_normal, out); } -static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_verts) +static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) { - float area_normal[3]; - ActiveData *node= active_verts->first; - float* buffer; - - calc_area_normal(sd, ss, area_normal, active_verts); - - buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; - - while(node){ - float *co= ss->mvert[node->Index].co; + Brush *brush = paint_brush(&sd->paint); + float offset[3], area_normal[3]; + float bstrength= ss->cache->bstrength; + int n; + + /* area normal */ + calc_area_normal(sd, ss, area_normal, nodes, totnode); + + /* offset with as much as possible factored in already */ + offset[0]= area_normal[0]*ss->cache->radius*ss->cache->scale[0]*bstrength; + offset[1]= area_normal[1]*ss->cache->radius*ss->cache->scale[1]*bstrength; + offset[2]= area_normal[2]*ss->cache->radius*ss->cache->scale[2]*bstrength; + + /* threaded loop over nodes */ + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; + + sculpt_node_verts_init(sd, ss, nodes[n], &vd); - const float val[3]= {co[0]+area_normal[0]*ss->cache->radius*node->Fade*ss->cache->scale[0], - co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1], - co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]}; + while(sculpt_node_verts_next(&vd)) { + /* offset vertex */ + const float fade = tex_strength(ss, brush, vd.co, vd.dist); + const float val[3]= {vd.co[0] + offset[0]*fade, + vd.co[1] + offset[1]*fade, + vd.co[2] + offset[2]*fade}; - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(sd, ss, &buffer[cur->element*3], val); - cur = cur->next; - } + sculpt_clip(sd, ss, vd.co, val); } - sculpt_clip(sd, ss, co, val); - - node= node->next; + BLI_pbvh_node_mark_update(nodes[n]); } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } /* For the smooth brush, uses the neighboring vertices around vert to calculate @@ -379,69 +674,67 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert) VecCopyf(avg, ss->mvert[vert].co); } -static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts) +static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) { - ActiveData *node= active_verts->first; - float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; - int i; - - for(i = 0; i < 2; ++i) { - while(node){ - float *co= ss->mvert[node->Index].co; - float avg[3], val[3]; - - neighbor_average(ss, avg, node->Index); - val[0] = co[0]+(avg[0]-co[0])*node->Fade; - val[1] = co[1]+(avg[1]-co[1])*node->Fade; - val[2] = co[2]+(avg[2]-co[2])*node->Fade; + Brush *brush = paint_brush(&sd->paint); + float bstrength= ss->cache->bstrength; + int iteration, n; + + for(iteration = 0; iteration < 2; ++iteration) { + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; - sculpt_clip(s, ss, co, val); - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(s, ss, &buffer[cur->element*3], val); - cur = cur->next; - } + sculpt_node_verts_init(sd, ss, nodes[n], &vd); + + while(sculpt_node_verts_next(&vd)) { + const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength; + float avg[3], val[3]; + + neighbor_average(ss, avg, vd.index); + val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade; + val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade; + val[2] = vd.co[2]+(avg[2]-vd.co[2])*fade; + + sculpt_clip(sd, ss, vd.co, val); } - node= node->next; + + BLI_pbvh_node_mark_update(nodes[n]); } } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } -static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts) +static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) { - ActiveData *node= active_verts->first; - float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; + Brush *brush = paint_brush(&sd->paint); + float bstrength= ss->cache->bstrength; + int n; - while(node) { - float *co= ss->mvert[node->Index].co; - const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade, - co[1]+(ss->cache->location[1]-co[1])*node->Fade, - co[2]+(ss->cache->location[2]-co[2])*node->Fade}; - - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(s, ss, &buffer[cur->element*3], val); - cur = cur->next; - } + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; + + sculpt_node_verts_init(sd, ss, nodes[n], &vd); + + while(sculpt_node_verts_next(&vd)) { + const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength; + const float val[3]= {vd.co[0]+(vd.location[0]-vd.co[0])*fade, + vd.co[1]+(vd.location[1]-vd.co[1])*fade, + vd.co[2]+(vd.location[2]-vd.co[2])*fade}; + + sculpt_clip(sd, ss, vd.co, val); } - sculpt_clip(s, ss, co, val); - node= node->next; + BLI_pbvh_node_mark_update(nodes[n]); } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } -static void do_grab_brush(Sculpt *sd, SculptSession *ss) +static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) { ActiveData *node= ss->cache->grab_active_verts[ss->cache->symmetry].first; float add[3]; float grab_delta[3]; - float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; + int n; VecCopyf(grab_delta, ss->cache->grab_delta_symmetry); @@ -452,122 +745,120 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss) VecMulf(add, node->Fade); VecAddf(add, add, co); - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(sd, ss, &buffer[cur->element*3], add); - cur = cur->next; - } - } - sculpt_clip(sd, ss, co, add); node= node->next; } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); - + + for(n=0; n<totnode; n++) + BLI_pbvh_node_mark_update(nodes[n]); } -static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts) +static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) { + Brush *brush = paint_brush(&sd->paint); + float bstrength= ss->cache->bstrength; float area_normal[3]; - ActiveData *node= active_verts->first; - float *buffer; float lim= ss->cache->radius / 4; + int n; if(ss->cache->flip) lim = -lim; - calc_area_normal(sd, ss, area_normal, active_verts); + calc_area_normal(sd, ss, area_normal, nodes, totnode); - buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; - while(node){ - float *disp= &ss->layer_disps[node->Index]; - float *co= ss->mvert[node->Index].co; - float val[3]; + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; - *disp+= node->Fade; - - /* Don't let the displacement go past the limit */ - if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim)) - *disp = lim; - - val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0]; - val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1]; - val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2]; - - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(sd, ss, &buffer[cur->element*3], val); - cur = cur->next; - } - } + sculpt_node_verts_init(sd, ss, nodes[n], &vd); - sculpt_clip(sd, ss, co, val); + while(sculpt_node_verts_next(&vd)) { + const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength; + float *disp= &ss->layer_disps[vd.index]; + float val[3]; + + *disp+= fade; + + /* Don't let the displacement go past the limit */ + if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim)) + *disp = lim; + + val[0] = ss->mesh_co_orig[vd.index][0]+area_normal[0] * *disp*ss->cache->scale[0]; + val[1] = ss->mesh_co_orig[vd.index][1]+area_normal[1] * *disp*ss->cache->scale[1]; + val[2] = ss->mesh_co_orig[vd.index][2]+area_normal[2] * *disp*ss->cache->scale[2]; - node= node->next; + sculpt_clip(sd, ss, vd.co, val); + } + + BLI_pbvh_node_mark_update(nodes[n]); } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } -static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts) +static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) { - ActiveData *node= active_verts->first; - float add[3]; - float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; + Brush *brush = paint_brush(&sd->paint); + float bstrength= ss->cache->bstrength; + int n; - while(node) { - float *co= ss->mvert[node->Index].co; - short *no= ss->mvert[node->Index].no; - - add[0]= no[0]/ 32767.0f; - add[1]= no[1]/ 32767.0f; - add[2]= no[2]/ 32767.0f; - VecMulf(add, node->Fade * ss->cache->radius); - add[0]*= ss->cache->scale[0]; - add[1]*= ss->cache->scale[1]; - add[2]*= ss->cache->scale[2]; - VecAddf(add, add, co); + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(s, ss, &buffer[cur->element*3], add); - cur = cur->next; - } - } + sculpt_node_verts_init(sd, ss, nodes[n], &vd); - sculpt_clip(s, ss, co, add); + while(sculpt_node_verts_next(&vd)) { + const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength; + float add[3]; + + add[0]= vd.no[0]/32767.0f; + add[1]= vd.no[1]/32767.0f; + add[2]= vd.no[2]/32767.0f; + VecMulf(add, fade * ss->cache->radius); + add[0]*= ss->cache->scale[0]; + add[1]*= ss->cache->scale[1]; + add[2]*= ss->cache->scale[2]; + VecAddf(add, add, vd.co); + + sculpt_clip(sd, ss, vd.co, add); + } - node= node->next; + BLI_pbvh_node_mark_update(nodes[n]); } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } -static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3]) +static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float co[3]) { - ActiveData *outer[FLATTEN_SAMPLE_SIZE]; - int i; + float outer_dist[FLATTEN_SAMPLE_SIZE]; + int outer_index[FLATTEN_SAMPLE_SIZE]; + int i, n; - for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) - outer[i] = node; + for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) { + outer_index[i] = 0; + outer_dist[i]= -1.0f; + } - for(; node; node = node->next) { - for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) { - if(node->dist > outer[i]->dist) { - outer[i] = node; - break; + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; + + sculpt_node_verts_init(sd, ss, nodes[n], &vd); + + while(sculpt_node_verts_next(&vd)) { + for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) { + if(vd.dist > outer_dist[i]) { + outer_index[i] = vd.index; + break; + } } } + + BLI_pbvh_node_mark_update(nodes[n]); } co[0] = co[1] = co[2] = 0.0f; for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) - VecAddf(co, co, ss->mvert[outer[i]->Index].co); + VecAddf(co, co, ss->mvert[outer_index[i]].co); VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE); } @@ -599,16 +890,17 @@ static int plane_point_side(float co[3], float plane_normal[3], float plane_cent return d <= 0.0f; } -static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts, int clay) +static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, int clay) { - ActiveData *node= active_verts->first; /* area_normal and cntr define the plane towards which vertices are squashed */ + Brush *brush = paint_brush(&sd->paint); + float bstrength= ss->cache->bstrength; float area_normal[3]; float cntr[3], cntr2[3], bstr = 0; - int flip = 0; - float *buffer; - calc_area_normal(sd, ss, area_normal, active_verts); - calc_flatten_center(ss, node, cntr); + int n, flip = 0; + + calc_area_normal(sd, ss, area_normal, nodes, totnode); + calc_flatten_center(sd, ss, nodes, totnode, cntr); if(clay) { bstr= brush_strength(sd, ss->cache); @@ -619,287 +911,152 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase flip = bstr < 0; } - buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; - - while(node){ - float *co= ss->mvert[node->Index].co; - float intr[3], val[3]; + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptVertexData vd; - if(!clay || plane_point_side(co, area_normal, cntr2, flip)) { - /* Find the intersection between squash-plane and vertex (along the area normal) */ - point_plane_project(intr, co, area_normal, cntr); + sculpt_node_verts_init(sd, ss, nodes[n], &vd); - VecSubf(val, intr, co); + while(sculpt_node_verts_next(&vd)) { + float intr[3], val[3]; + + if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) { + const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength; - if(clay) { - if(bstr > FLT_EPSILON) - VecMulf(val, node->Fade / bstr); - else - VecMulf(val, node->Fade); - /* Clay displacement */ - val[0]+=area_normal[0] * ss->cache->scale[0]*node->Fade; - val[1]+=area_normal[1] * ss->cache->scale[1]*node->Fade; - val[2]+=area_normal[2] * ss->cache->scale[2]*node->Fade; - } - else - VecMulf(val, fabs(node->Fade)); + /* Find the intersection between squash-plane and vertex (along the area normal) */ + point_plane_project(intr, vd.co, area_normal, cntr); - VecAddf(val, val, co); + VecSubf(val, intr, vd.co); - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[node->Index]; - while( cur != 0 && cur->element != -1 ) { - sculpt_clip(sd, ss, &buffer[cur->element*3], val); - cur = cur->next; + if(clay) { + if(bstr > FLT_EPSILON) + VecMulf(val, fade / bstr); + else + VecMulf(val, fade); + /* Clay displacement */ + val[0]+=area_normal[0] * ss->cache->scale[0]*fade; + val[1]+=area_normal[1] * ss->cache->scale[1]*fade; + val[2]+=area_normal[2] * ss->cache->scale[2]*fade; } - } - sculpt_clip(sd, ss, co, val); - - } - - node= node->next; - } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); -} - -/* Uses symm to selectively flip any axis of a coordinate. */ -static void flip_coord(float out[3], float in[3], const char symm) -{ - if(symm & SCULPT_SYMM_X) - out[0]= -in[0]; - else - out[0]= in[0]; - if(symm & SCULPT_SYMM_Y) - out[1]= -in[1]; - else - out[1]= in[1]; - if(symm & SCULPT_SYMM_Z) - out[2]= -in[2]; - else - out[2]= in[2]; -} - -/* Get a pixel from the texcache at (px, py) */ -static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py) -{ - unsigned *p; - p = ss->texcache + py * ss->texcache_side + px; - return ((unsigned char*)(p))[0]; -} - -static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v) -{ - int x, y, x2, y2; - const int tc_max = ss->texcache_side - 1; - float urat, vrat, uopp; - - if(u < 0) u = 0; - else if(u >= ss->texcache_side) u = tc_max; - if(v < 0) v = 0; - else if(v >= ss->texcache_side) v = tc_max; - - x = floor(u); - y = floor(v); - x2 = x + 1; - y2 = y + 1; - - if(x2 > ss->texcache_side) x2 = tc_max; - if(y2 > ss->texcache_side) y2 = tc_max; - - urat = u - x; - vrat = v - y; - uopp = 1 - urat; - - return ((get_texcache_pixel(ss, x, y) * uopp + - get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) + - (get_texcache_pixel(ss, x, y2) * uopp + - get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0; -} - -/* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len) -{ - Brush *br = paint_brush(&sd->paint); - MTex *tex = NULL; - float avg= 1; - - if(br->texact >= 0) - tex = br->mtex[br->texact]; - - if(!tex) { - avg= 1; - } - else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) { - float jnk; - - /* Get strength by feeding the vertex - location directly into a texture */ - externtex(tex, point, &avg, - &jnk, &jnk, &jnk, &jnk); - } - else if(ss->texcache) { - const float bsize= ss->cache->pixel_radius * 2; - const float rot= tex->rot + ss->cache->rotation; - int px, py; - float flip[3], point_2d[2]; + else + VecMulf(val, fabs(fade)); - /* If the active area is being applied for symmetry, flip it - across the symmetry axis in order to project it. This insures - that the brush texture will be oriented correctly. */ - VecCopyf(flip, point); - flip_coord(flip, flip, ss->cache->symmetry); - projectf(ss->cache->mats, flip, point_2d); + VecAddf(val, val, vd.co); - /* For Tile and Drag modes, get the 2D screen coordinates of the - and scale them up or down to the texture size. */ - if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) { - const int sx= (const int)tex->size[0]; - const int sy= (const int)tex->size[1]; - - float fx= point_2d[0]; - float fy= point_2d[1]; - - float angle= atan2(fy, fx) - rot; - float flen= sqrtf(fx*fx + fy*fy); - - if(rot<0.001 && rot>-0.001) { - px= point_2d[0]; - py= point_2d[1]; - } else { - px= flen * cos(angle) + 2000; - py= flen * sin(angle) + 2000; + sculpt_clip(sd, ss, vd.co, val); } - if(sx != 1) - px %= sx-1; - if(sy != 1) - py %= sy-1; - avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy); } - else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) { - float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize; - float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize; - float angle= atan2(fy, fx) - rot; - float flen= sqrtf(fx*fx + fy*fy); - - fx = flen * cos(angle) + 0.5; - fy = flen * sin(angle) + 0.5; - - avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side); - } + BLI_pbvh_node_mark_update(nodes[n]); } - - avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */ - - return avg; } -/* Mark area around the brush as damaged. projverts are marked if they are - inside the area and the damaged rectangle in 2D screen coordinates is - added to damaged_rects. */ -static void sculpt_add_damaged_rect(SculptSession *ss) +static void sculpt_brush_hit_cb(PBVHNode *node, void *data_v) { - short p[2]; - RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode"); - const float radius = MAX2(ss->cache->pixel_radius, ss->cache->previous_pixel_radius); - unsigned i; + SculptSearchSphereData *data = data_v; + int i, totvert, *verts; - /* Find center */ - project(ss->cache->mats, ss->cache->location, p); - rn->r.xmin= p[0] - radius; - rn->r.ymin= p[1] - radius; - rn->r.xmax= p[0] + radius; - rn->r.ymax= p[1] + radius; + BLI_pbvh_node_get_verts(node, &verts, &totvert); - BLI_addtail(&ss->damaged_rects, rn); + /* XXX: for now grab brush still uses an active vert list, + will be fixed later */ - /* Update insides */ - for(i=0; i<ss->totvert; ++i) { - if(!ss->projverts[i].inside) { - if(ss->projverts[i].co[0] > rn->r.xmin && ss->projverts[i].co[1] > rn->r.ymin && - ss->projverts[i].co[0] < rn->r.xmax && ss->projverts[i].co[1] < rn->r.ymax) { - ss->projverts[i].inside= 1; - } + for(i = 0; i < totvert; ++i) { + int v = verts[i]; + float delta[3], dsq; + + VecSubf(delta, data->ss->mvert[v].co, + data->ss->cache->location); + dsq = Inpf(delta, delta); + + if(dsq < data->radius_squared) { + ActiveData *adata = + (ActiveData*)MEM_mallocN(sizeof(ActiveData), + "ActiveData"); + adata->Index = v; + adata->dist = sqrt(dsq); + BLI_addtail(data->active_verts, adata); } - // XXX: remember to fix this! - // temporary pass - ss->projverts[i].inside = 1; } + + BLI_pbvh_node_mark_update(node); } static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache) { Brush *brush = paint_brush(&sd->paint); - float av_dist; - ListBase active_verts={0,0}; - ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry]; - ActiveData *adata= 0; - float *vert; - Mesh *me= NULL; /*XXX: get_mesh(OBACT); */ - const float bstrength= brush_strength(sd, cache); - KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */ - Brush *b = brush; - int i; + //KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */ + PBVHNode **nodes= NULL; + int totnode; + SculptSearchSphereData data; - sculpt_add_damaged_rect(ss); + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cache->radius * ss->cache->radius; /* Build a list of all vertices that are potentially within the brush's - area of influence. Only do this once for the grab brush. */ - if((b->sculpt_tool != SCULPT_TOOL_GRAB) || cache->first_time) { - for(i=0; i<ss->totvert; ++i) { - /* Projverts.inside provides a rough bounding box */ - if(ss->multires || ss->projverts[i].inside) { - //vert= ss->vertexcosnos ? &ss->vertexcosnos[i*6] : a->verts[i].co; - vert= ss->mvert[i].co; - av_dist= VecLenf(ss->cache->location, vert); - if(av_dist < cache->radius) { - adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData"); - - adata->Index = i; - /* Fade is used to store the final strength at which the brush - should modify a particular vertex. */ - adata->Fade= tex_strength(sd, ss, vert, av_dist) * bstrength; - adata->dist = av_dist; - - if(b->sculpt_tool == SCULPT_TOOL_GRAB && cache->first_time) - BLI_addtail(grab_active_verts, adata); - else - BLI_addtail(&active_verts, adata); - } - } + area of influence */ + if(brush->sculpt_tool == SCULPT_TOOL_GRAB) { + if(cache->first_time) { + const float bstrength= brush_strength(sd, cache); + ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry]; + ActiveData *adata; + + data.active_verts = grab_active_verts; + BLI_pbvh_search_callback(ss->tree, sculpt_search_sphere_cb, &data, + sculpt_brush_hit_cb, &data); + + BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data, + &nodes, &totnode); + + ss->cache->grab_active_nodes[ss->cache->symmetry]= nodes; + ss->cache->grab_active_totnode[ss->cache->symmetry]= totnode; + + /* Update brush strength for each vertex */ + for(adata = data.active_verts->first; adata; adata = adata->next) + adata->Fade = tex_strength(ss, brush, ss->mvert[adata->Index].co, adata->dist) * bstrength; + } + else { + nodes= ss->cache->grab_active_nodes[ss->cache->symmetry]; + totnode= ss->cache->grab_active_totnode[ss->cache->symmetry]; } } + else { + BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data, + &nodes, &totnode); + } /* Only act if some verts are inside the brush area */ - if(active_verts.first || (b->sculpt_tool == SCULPT_TOOL_GRAB && grab_active_verts->first)) { + if(totnode) { /* Apply one type of brush action */ - switch(b->sculpt_tool){ + switch(brush->sculpt_tool){ case SCULPT_TOOL_DRAW: - do_draw_brush(sd, ss, &active_verts); + do_draw_brush(sd, ss, nodes, totnode); break; case SCULPT_TOOL_SMOOTH: - do_smooth_brush(sd, ss, &active_verts); + do_smooth_brush(sd, ss, nodes, totnode); break; case SCULPT_TOOL_PINCH: - do_pinch_brush(sd, ss, &active_verts); + do_pinch_brush(sd, ss, nodes, totnode); break; case SCULPT_TOOL_INFLATE: - do_inflate_brush(sd, ss, &active_verts); + do_inflate_brush(sd, ss, nodes, totnode); break; case SCULPT_TOOL_GRAB: - do_grab_brush(sd, ss); + do_grab_brush(sd, ss, nodes, totnode); break; case SCULPT_TOOL_LAYER: - do_layer_brush(sd, ss, &active_verts); + do_layer_brush(sd, ss, nodes, totnode); break; case SCULPT_TOOL_FLATTEN: - do_flatten_clay_brush(sd, ss, &active_verts, 0); + do_flatten_clay_brush(sd, ss, nodes, totnode, 0); break; case SCULPT_TOOL_CLAY: - do_flatten_clay_brush(sd, ss, &active_verts, 1); + do_flatten_clay_brush(sd, ss, nodes, totnode, 1); + break; } +#if 0 /* Copy the modified vertices from mesh to the active key */ if(keyblock && !ss->multires) { float *co= keyblock->data; @@ -919,9 +1076,14 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache) BLI_freelistN(&active_verts); else { if(b->sculpt_tool != SCULPT_TOOL_GRAB) - addlisttolist(&ss->damaged_verts, &active_verts); + addlisttolist(&ss->modified_verts, &active_verts); } - } +#endif + + if(brush->sculpt_tool != SCULPT_TOOL_GRAB) + if(nodes) + MEM_freeN(nodes); + } } /* Flip all the editdata across the axis/axes specified by symm. Used to @@ -943,6 +1105,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss) VecCopyf(cache->location, cache->true_location); VecCopyf(cache->grab_delta_symmetry, cache->grab_delta); cache->symmetry = 0; + cache->bstrength = brush_strength(sd, cache); do_brush_action(sd, ss, cache); for(i = 1; i <= symm; ++i) { @@ -955,110 +1118,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss) cache->first_time = 0; } -static void add_face_normal(vec3f *norm, MVert *mvert, const MFace* face, float *fn) -{ - vec3f c= {mvert[face->v1].co[0],mvert[face->v1].co[1],mvert[face->v1].co[2]}; - vec3f b= {mvert[face->v2].co[0],mvert[face->v2].co[1],mvert[face->v2].co[2]}; - vec3f a= {mvert[face->v3].co[0],mvert[face->v3].co[1],mvert[face->v3].co[2]}; - vec3f s1, s2; - float final[3]; - - VecSubf(&s1.x,&a.x,&b.x); - VecSubf(&s2.x,&c.x,&b.x); - - final[0] = s1.y * s2.z - s1.z * s2.y; - final[1] = s1.z * s2.x - s1.x * s2.z; - final[2] = s1.x * s2.y - s1.y * s2.x; - - if(fn) - VecCopyf(fn, final); - - norm->x+= final[0]; - norm->y+= final[1]; - norm->z+= final[2]; -} - -static void update_damaged_vert(SculptSession *ss, ListBase *lb) -{ - ActiveData *vert; - - float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->normals ):0; - for(vert= lb->first; vert; vert= vert->next) { - vec3f norm= {0,0,0}; - IndexNode *face= ss->fmap[vert->Index].first; - - while(face){ - float *fn = NULL; - if(ss->face_normals) - fn = &ss->face_normals[face->index*3]; - add_face_normal(&norm, ss->mvert, &ss->mface[face->index], fn); - face= face->next; - } - Normalize(&norm.x); - - ss->mvert[vert->Index].no[0]=norm.x*32767; - ss->mvert[vert->Index].no[1]=norm.y*32767; - ss->mvert[vert->Index].no[2]=norm.z*32767; - - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[vert->Index]; - while( cur != 0 && cur->element != -1 ) { - int i = ss->drawobject->faceRemap[cur->element/3]; - if( ss->mface[i].flag & ME_SMOOTH ) { - VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no); - } - else { - float norm[3]; - if( ss->mface[i].v4 ) - CalcNormFloat4(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, ss->mvert[ss->mface[i].v4].co, norm); - else - CalcNormFloat(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, norm); - VECCOPY(&buffer[(cur->element-cur->element%3)*3],norm); - VECCOPY(&buffer[(cur->element-cur->element%3+1)*3],norm); - VECCOPY(&buffer[(cur->element-cur->element%3+2)*3],norm); - - /* maybe this was a quad - need to update the other triangle of the quad */ - if( ss->drawobject->faceRemap[cur->element/3-1] == i ) { - VECCOPY(&buffer[(cur->element-cur->element%3-3)*3],norm); - VECCOPY(&buffer[(cur->element-cur->element%3-2)*3],norm); - VECCOPY(&buffer[(cur->element-cur->element%3-1)*3],norm); - } - if( ss->drawobject->faceRemap[cur->element/3+1] == i ) { - VECCOPY(&buffer[(cur->element-cur->element%3+3)*3],norm); - VECCOPY(&buffer[(cur->element-cur->element%3+4)*3],norm); - VECCOPY(&buffer[(cur->element-cur->element%3+5)*3],norm); - } - } - - //VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no); - cur = cur->next; - } - } - } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->normals ); -} - -static void calc_damaged_verts(SculptSession *ss) -{ - int i; - - for(i=0; i<8; ++i) - update_damaged_vert(ss, &ss->cache->grab_active_verts[i]); - update_damaged_vert(ss, &ss->damaged_verts); - BLI_freelistN(&ss->damaged_verts); - ss->damaged_verts.first = ss->damaged_verts.last = NULL; -} - -#if 0 -static void projverts_clear_inside(SculptSession *ss) -{ - int i; - for(i = 0; i < ss->totvert; ++i) - ss->projverts[i].inside = 0; -} -#endif - static void sculpt_update_tex(Sculpt *sd, SculptSession *ss) { Brush *brush = paint_brush(&sd->paint); @@ -1076,20 +1135,6 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss) } } -static void sculptmode_update_all_projverts(SculptSession *ss) -{ - unsigned i; - - if(!ss->projverts) - ss->projverts = MEM_mallocN(sizeof(ProjVert)*ss->totvert,"ProjVerts"); - - for(i=0; i<ss->totvert; ++i) { - project(ss->cache->mats, ss->vertexcosnos ? &ss->vertexcosnos[i * 6] : ss->mvert[i].co, - ss->projverts[i].co); - ss->projverts[i].inside= 0; - } -} - /* Checks whether full update mode (slower) needs to be used to work with modifiers */ char sculpt_modifiers_active(Object *ob) { @@ -1130,12 +1175,12 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob) static void sculpt_update_mesh_elements(bContext *C) { Object *ob = CTX_data_active_object(C); + DerivedMesh *dm = + mesh_get_derived_final(CTX_data_scene(C), ob, + CTX_wm_view3d(C)->customdata_mask); SculptSession *ss = ob->sculpt; - int oldtotvert = ss->totvert; - DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH); if((ss->multires = sculpt_multires_active(ob))) { - //DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH); ss->totvert = dm->getNumVerts(dm); ss->totface = dm->getNumFaces(dm); ss->mvert = dm->getVertDataArray(dm, CD_MVERT); @@ -1148,24 +1193,12 @@ static void sculpt_update_mesh_elements(bContext *C) ss->totface = me->totface; ss->mvert = me->mvert; ss->mface = me->mface; - ss->face_normals = NULL; - } - if( GPU_buffer_legacy( dm ) ) { - ss->drawobject = 0; - } - else { - ss->drawobject = dm->drawObject; + if(!ss->face_normals) + ss->face_normals = MEM_callocN(sizeof(float) * 3 * me->totface, "sculpt face normals"); } - if(ss->totvert != oldtotvert) { - if(ss->projverts) MEM_freeN(ss->projverts); - ss->projverts = NULL; - - if(ss->fmap) MEM_freeN(ss->fmap); - if(ss->fmap_mem) MEM_freeN(ss->fmap_mem); - create_vert_face_map(&ss->fmap, &ss->fmap_mem, ss->mface, ss->totvert, ss->totface); - ss->fmap_size = ss->totvert; - } + ss->tree = dm->getPBVH(dm); + ss->fmap = dm->getFaceMap(dm); } static int sculpt_mode_poll(bContext *C) @@ -1251,15 +1284,13 @@ static void SCULPT_OT_radial_control(wmOperatorType *ot) /**** Operator for applying a stroke (various attributes including mouse path) using the current brush. ****/ -static float unproject_brush_radius(SculptSession *ss, float offset) +static float unproject_brush_radius(ViewContext *vc, float center[3], float offset) { - float brush_edge[3]; - - /* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */ - view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset, - ss->cache->initial_mouse[1], ss->cache->depth); + float delta[3]; - return VecLenf(ss->cache->true_location, brush_edge); + initgrabz(vc->rv3d, center[0], center[1], center[2]); + window_to_3d_delta(vc->ar, delta, offset, 0); + return VecLength(delta); } static void sculpt_cache_free(StrokeCache *cache) @@ -1271,8 +1302,11 @@ static void sculpt_cache_free(StrokeCache *cache) MEM_freeN(cache->face_norms); if(cache->mats) MEM_freeN(cache->mats); - for(i = 0; i < 8; ++i) + for(i = 0; i < 8; ++i) { BLI_freelistN(&cache->grab_active_verts[i]); + if(cache->grab_active_nodes[i]) + MEM_freeN(cache->grab_active_nodes[i]); + } MEM_freeN(cache); } @@ -1290,15 +1324,17 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte cache->flag = RNA_int_get(op->ptr, "flag"); RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance); RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse); - cache->depth = RNA_float_get(op->ptr, "depth"); cache->mouse[0] = cache->initial_mouse[0]; cache->mouse[1] = cache->initial_mouse[1]; /* Truly temporary data that isn't stored in properties */ + cache->vc = vc; + cache->brush = brush; + cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats"); - view3d_get_transformation(vc, vc->obact, cache->mats); + view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats); sculpt_update_mesh_elements(C); @@ -1338,14 +1374,14 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte } } - view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); - cache->initial_radius = unproject_brush_radius(ss, brush->size); + //view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); + cache->initial_radius = unproject_brush_radius(vc, cache->true_location, brush->size); cache->rotation = 0; cache->first_time = 1; } /* Initialize the stroke cache variants from operator properties */ -static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerRNA *ptr) +static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr) { StrokeCache *cache = ss->cache; Brush *brush = paint_brush(&sd->paint); @@ -1375,7 +1411,8 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR dx = cache->mouse[0] - cache->initial_mouse[0]; dy = cache->mouse[1] - cache->initial_mouse[1]; cache->pixel_radius = sqrt(dx*dx + dy*dy); - cache->radius = unproject_brush_radius(ss, cache->pixel_radius); + cache->radius = unproject_brush_radius(paint_stroke_view_context(stroke), + cache->true_location, cache->pixel_radius); cache->rotation = atan2(dy, dx); } else if(brush->flag & BRUSH_RAKE) { @@ -1398,13 +1435,103 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR /* Find the grab delta */ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) { - view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth); + // XXX: view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth); + initgrabz(cache->vc->rv3d, cache->true_location[0], cache->true_location[1], cache->true_location[2]); + window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]); + if(!cache->first_time) VecSubf(cache->grab_delta, grab_location, cache->old_grab_location); VecCopyf(cache->old_grab_location, grab_location); } } +/* XXX: Code largely copied from bvhutils.c, should be unified */ +/* Returns 1 if a better intersection has been found */ +static int ray_face_intersection(float ray_start[3], float ray_normal[3], + float *t0, float *t1, float *t2, float *t3, + float *fdist) +{ + int hit = 0; + + do + { + float dist = FLT_MAX; + + if(!RayIntersectsTriangle(ray_start, ray_normal, t0, t1, t2, + &dist, NULL)) + dist = FLT_MAX; + + if(dist >= 0 && dist < *fdist) { + hit = 1; + *fdist = dist; + } + + t1 = t2; + t2 = t3; + t3 = NULL; + + } while(t2); + + return hit; +} + +typedef struct { + SculptSession *ss; + float *ray_start, *ray_normal; + int hit; + float dist; +} SculptRaycastData; + +void sculpt_raycast_cb(PBVHNode *node, void *data_v) +{ + SculptRaycastData *srd = data_v; + MVert *vert = srd->ss->mvert; + int i, totface, *faces; + + BLI_pbvh_node_get_faces(node, &faces, &totface); + + for(i = 0; i < totface; ++i) { + MFace *f = srd->ss->mface + faces[i]; + if(ray_face_intersection(srd->ray_start, srd->ray_normal, + vert[f->v1].co, + vert[f->v2].co, + vert[f->v3].co, + f->v4 ? vert[f->v4].co : NULL, + &srd->dist)) { + srd->hit = faces[i]; + } + } +} + +/* Do a raycast in the tree to find the 3d brush location + (This allows us to ignore the GL depth buffer) + Returns 0 if the ray doesn't hit the mesh, non-zero otherwise + */ +int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]) +{ + ViewContext *vc = paint_stroke_view_context(stroke); + float ray_start[3], ray_normal[3]; + float mval[2] = {mouse[0] - vc->ar->winrct.xmin, + mouse[1] - vc->ar->winrct.ymin}; + SculptRaycastData srd; + + viewray(vc->ar, vc->v3d, mval, ray_start, ray_normal); + + srd.ss = vc->obact->sculpt; + srd.ray_start = ray_start; + srd.ray_normal = ray_normal; + srd.dist = FLT_MAX; + srd.hit = -1; + BLI_pbvh_raycast(vc->obact->sculpt->tree, sculpt_raycast_cb, &srd, + ray_start, ray_normal); + + VecCopyf(out, ray_normal); + VecMulf(out, srd.dist); + VecAddf(out, out, ray_start); + + return srd.hit != -1; +} + /* Initialize stroke operator properties */ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss) { @@ -1442,9 +1569,6 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE mouse[1] = event->y; RNA_float_set_array(op->ptr, "initial_mouse", mouse); - /* Initial screen depth under the mouse */ - RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y)); - sculpt_update_cache_invariants(sd, ss, C, op); } @@ -1467,30 +1591,16 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) { StrokeCache *cache = ss->cache; Brush *brush = paint_brush(&sd->paint); - float *buffer= NULL; int i; /* Restore the mesh before continuing with anchored stroke */ if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) { - - if(ss->drawobject) - buffer= (float *)GPU_buffer_lock(ss->drawobject->normals); - for(i = 0; i < ss->totvert; ++i) { VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]); ss->mvert[i].no[0] = cache->orig_norms[i][0]; ss->mvert[i].no[1] = cache->orig_norms[i][1]; ss->mvert[i].no[2] = cache->orig_norms[i][2]; - if( buffer != 0 ) { - IndexLink *cur = &ss->drawobject->indices[i]; - while( cur != 0 && cur->element != -1 ) { - VECCOPY(&buffer[cur->element*3],cache->orig_norms[i]); - cur = cur->next; - } - } } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->normals ); if(ss->face_normals) { float *fn = ss->face_normals; @@ -1503,20 +1613,14 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) } } -static void sculpt_post_stroke_free(SculptSession *ss) -{ - BLI_freelistN(&ss->damaged_rects); - BLI_freelistN(&ss->damaged_verts); -} - static void sculpt_flush_update(bContext *C) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; ARegion *ar = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires; - - calc_damaged_verts(ss); + rcti r; + int redraw = 0; if(mmd) { if(mmd->undo_verts && mmd->undo_verts != ss->mvert) @@ -1527,23 +1631,35 @@ static void sculpt_flush_update(bContext *C) multires_mark_as_modified(ob); } - ED_region_tag_redraw(ar); + BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL, NULL); + redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r); + + if(redraw) { + r.xmin += ar->winrct.xmin + 1; + r.xmax += ar->winrct.xmin - 1; + r.ymin += ar->winrct.ymin + 1; + r.ymax += ar->winrct.ymin - 1; + + ss->partial_redraw = 1; + ED_region_tag_redraw_partial(ar, &r); + } } static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event) { - ViewContext vc; - float cur_depth; - - view3d_set_viewcontext(C, &vc); - cur_depth = read_cached_depth(&vc, event->x, event->y); + float mouse[2] = {event->x, event->y}, location[3]; + int over_mesh; - /* Don't start the stroke until a valid depth is found */ - if(cur_depth < 1.0 - FLT_EPSILON) { - SculptSession *ss = CTX_data_active_object(C)->sculpt; + over_mesh = sculpt_stroke_get_location(C, op->customdata, location, mouse); + + /* Don't start the stroke until mouse goes over the mesh */ + if(over_mesh) { + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C)); sculpt_brush_stroke_init_properties(C, op, event, ss); - sculptmode_update_all_projverts(ss); return 1; } @@ -1556,13 +1672,12 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; - sculpt_update_cache_variants(sd, ss, itemptr); + sculpt_update_cache_variants(sd, ss, stroke, itemptr); sculpt_restore_mesh(sd, ss); do_symmetrical_brush_actions(sd, ss); /* Cleanup */ sculpt_flush_update(C); - sculpt_post_stroke_free(ss); } static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) @@ -1571,9 +1686,8 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) /* Finished */ if(ss->cache) { - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - request_depth_update(paint_stroke_view_context(stroke)->rv3d); sculpt_cache_free(ss->cache); ss->cache = NULL; sculpt_undo_push(C, sd); @@ -1584,7 +1698,8 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even { sculpt_brush_stroke_init(C); - op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, + op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, + sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done); @@ -1601,12 +1716,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; - op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done); + op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start, + sculpt_stroke_update_step, sculpt_stroke_done); sculpt_brush_stroke_init(C); sculpt_update_cache_invariants(sd, ss, C, op); - sculptmode_update_all_projverts(ss); paint_stroke_exec(C, op); @@ -1649,9 +1764,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* The initial 2D location of the mouse */ RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX); - - /* The initial screen depth of the mouse */ - RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX); } /**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/ @@ -1688,6 +1800,13 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) /**** Toggle operator for turning sculpt mode on or off ****/ +static void sculpt_init_session(bContext *C, Object *ob) +{ + ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); + + sculpt_update_mesh_elements(C); +} + static int sculpt_toggle_mode(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); @@ -1713,7 +1832,8 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op) /* Create sculpt mode session data */ if(ob->sculpt) free_sculptsession(&ob->sculpt); - ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); + + sculpt_init_session(C, ob); paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); @@ -1745,3 +1865,4 @@ void ED_operatortypes_sculpt() WM_operatortype_append(SCULPT_OT_sculptmode_toggle); WM_operatortype_append(SCULPT_OT_set_persistent_base); } + |