diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-10-06 13:25:33 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-10-06 13:25:33 +0300 |
commit | ea606a7847a316a82b365155f666b33e81ff4c2e (patch) | |
tree | d58158c83fd66000fbe9db0c45fa39b6fc02076e /source/blender/editors/sculpt_paint | |
parent | d7d32ad45217736c677edd22906d980d03aeb175 (diff) | |
parent | 3df139c53062a141403ea9d359715ca3635c243c (diff) |
Merge branch 'master' into blender28
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_cursor.c | 18 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_ops.c | 9 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex.c | 101 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex_color_utils.c | 2 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 508 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 11 |
6 files changed, 418 insertions, 231 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 04c7e6e2a62..befb635cfc4 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -42,6 +42,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" +#include "DNA_view3d_types.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -1024,9 +1025,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) ViewContext vc; view3d_set_viewcontext(C, &vc); - float zoomx, zoomy; - get_imapaint_zoom(C, &zoomx, &zoomy); - zoomx = max_ff(zoomx, zoomy); + if (vc.rv3d->rflag & RV3D_NAVIGATING) { + return; + } /* skip everything and draw brush here */ if (brush->flag & BRUSH_CURVE) { @@ -1034,6 +1035,10 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) return; } + float zoomx, zoomy; + get_imapaint_zoom(C, &zoomx, &zoomy); + zoomx = max_ff(zoomx, zoomy); + /* set various defaults */ const float *outline_col = brush->add_col; const float outline_alpha = 0.5f; @@ -1064,11 +1069,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* check if brush is subtracting, use different color then */ /* TODO: no way currently to know state of pen flip or * invert key modifier without starting a stroke */ - if (((ups->draw_inverted == 0) ^ - ((brush->flag & BRUSH_DIR_IN) == 0)) && - ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW, - SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, - SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) + if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) && + BKE_brush_sculpt_has_secondary_color(brush)) { outline_col = brush->sub_col; } diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 4f6b3d100c5..2899cfeedcf 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -264,9 +264,14 @@ static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) if (!ob || !brush) return OPERATOR_CANCELLED; - if (ob->mode & OB_MODE_SCULPT) - BKE_brush_sculpt_reset(brush); /* TODO: other modes */ + if (ob->mode & OB_MODE_SCULPT) { + BKE_brush_sculpt_reset(brush); + } + else { + return OPERATOR_CANCELLED; + } + WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 5d87030bc67..fd88ea2d15f 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -105,6 +105,7 @@ struct NormalAnglePrecalc { static void view_angle_limits_init( struct NormalAnglePrecalc *a, float angle, bool do_mask_normal) { + angle = RAD2DEGF(angle); a->do_mask_normal = do_mask_normal; if (do_mask_normal) { a->angle_inner = angle; @@ -144,8 +145,8 @@ static float view_angle_limits_apply_falloff( static bool vwpaint_use_normal(const VPaint *vp) { - return ((vp->flag & VP_FLAG_PROJECT_BACKFACE) == 0) || - ((vp->flag & VP_FLAG_PROJECT_FLAT) == 0); + return ((vp->paint.brush->flag & BRUSH_FRONTFACE) != 0) || + ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); } @@ -357,7 +358,7 @@ static float calc_vp_alpha_col_dl( if (strength > 0.0f) { float alpha = brush_alpha_pressure * strength; - if ((vp->flag & VP_FLAG_PROJECT_FLAT) == 0) { + if ((vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0) { float dvec[3]; /* transpose ! */ @@ -1390,7 +1391,8 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData"); paint_stroke_set_mode_data(stroke, wpd); view3d_set_viewcontext(C, &wpd->vc); - view_angle_limits_init(&wpd->normal_angle_precalc, vp->normal_angle, (vp->flag & VP_FLAG_PROJECT_FLAT) == 0); + view_angle_limits_init(&wpd->normal_angle_precalc, vp->paint.brush->falloff_angle, + (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); wpd->active.index = vgroup_index.active; wpd->mirror.index = vgroup_index.mirror; @@ -1510,22 +1512,6 @@ static float wpaint_get_active_weight(const MDeformVert *dv, const WeightPaintIn } } -static SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape( - SculptSession *ss, SculptBrushTest *test, char falloff_shape) -{ - sculpt_brush_test_init(ss, test); - SculptBrushTestFn sculpt_brush_test_sq_fn; - if (falloff_shape == VP_FALLOFF_SHAPE_SPHERE) { - sculpt_brush_test_sq_fn = sculpt_brush_test_sphere_sq; - } - else { - /* VP_FALLOFF_SHAPE_TUBE */ - plane_from_point_normal_v3(test->plane, test->location, ss->cache->view_normal); - sculpt_brush_test_sq_fn = sculpt_brush_test_circle_sq; - } - return sculpt_brush_test_sq_fn; -} - static void do_wpaint_brush_blur_task_cb_ex( void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id)) { @@ -1546,7 +1532,9 @@ static void do_wpaint_brush_blur_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -1581,10 +1569,10 @@ static void do_wpaint_brush_blur_task_cb_ex( if (total_hit_loops != 0) { float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; - if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; + if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && - ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) { const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); @@ -1639,7 +1627,9 @@ static void do_wpaint_brush_smear_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -1657,10 +1647,10 @@ static void do_wpaint_brush_smear_task_cb_ex( if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) { float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; - if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; + if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && - ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) { bool do_color = false; @@ -1739,7 +1729,9 @@ static void do_wpaint_brush_draw_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -1758,10 +1750,10 @@ static void do_wpaint_brush_draw_task_cb_ex( if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; - if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; + if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && - ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff(&data->wpd->normal_angle_precalc, angle_cos, &brush_strength))) { const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); @@ -1804,7 +1796,9 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -1813,7 +1807,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; if (angle_cos > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) { const int v_index = ccgdm ? data->me->mloop[vd.grid_indices[vd.g]].v : vd.vert_indices[vd.i]; // const float grid_alpha = ccgdm ? 1.0f / vd.gridsize : 1.0f; @@ -1906,7 +1900,7 @@ static PBVHNode **vwpaint_pbvh_gather_generic( PBVHNode **nodes = NULL; /* Build a list of all nodes that are potentially within the brush's area of influence */ - if (wp->falloff_shape == VP_FALLOFF_SHAPE_SPHERE) { + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { SculptSearchSphereData data = { .ss = ss, .sd = sd, @@ -1923,7 +1917,7 @@ static PBVHNode **vwpaint_pbvh_gather_generic( } else { struct DistRayAABB_Precalc dist_ray_to_aabb_precalc; - dist_squared_ray_to_aabb_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal); + dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal); SculptSearchCircleData data = { .ss = ss, .sd = sd, @@ -2404,7 +2398,8 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f vpd = MEM_callocN(sizeof(*vpd), "VPaintData"); paint_stroke_set_mode_data(stroke, vpd); view3d_set_viewcontext(C, &vpd->vc); - view_angle_limits_init(&vpd->normal_angle_precalc, vp->normal_angle, (vp->flag & VP_FLAG_PROJECT_FLAT) == 0); + view_angle_limits_init(&vpd->normal_angle_precalc, vp->paint.brush->falloff_angle, + (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); vpd->paintcol = vpaint_get_current_col(scene, vp); @@ -2476,7 +2471,7 @@ static void do_vpaint_brush_calc_average_color_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -2545,7 +2540,9 @@ static void do_vpaint_brush_draw_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -2566,10 +2563,10 @@ static void do_vpaint_brush_draw_task_cb_ex( * (ie splash prevention factor), and only paint front facing verts. */ float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; - if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; + if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && - ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) { const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); @@ -2634,7 +2631,9 @@ static void do_vpaint_brush_blur_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -2652,10 +2651,10 @@ static void do_vpaint_brush_blur_task_cb_ex( if (!use_vert_sel || mv->flag & SELECT) { float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; - if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; + if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && - ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) { const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); @@ -2747,7 +2746,9 @@ static void do_vpaint_brush_smear_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = - sculpt_brush_test_init_with_falloff_shape(ss, &test, data->vp->falloff_shape); + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + const float *sculpt_normal_frontface = + sculpt_brush_frontface_normal_from_falloff_shape(ss, data->brush->falloff_shape); /* For each vertex */ PBVHVertexIter vd; @@ -2767,10 +2768,10 @@ static void do_vpaint_brush_smear_task_cb_ex( * (ie splash prevention factor), and only paint front facing verts. */ float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(ss->cache->sculpt_normal_symm, vd.no) : 1.0f; - if (((data->vp->flag & VP_FLAG_PROJECT_BACKFACE) || + dot_vf3vs3(sculpt_normal_frontface, vd.no) : 1.0f; + if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && - ((data->vp->flag & VP_FLAG_PROJECT_FLAT) || + ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff(&data->vpd->normal_angle_precalc, angle_cos, &brush_strength))) { const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c index 3b3e7297aec..a8045232e05 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c @@ -298,7 +298,7 @@ BLI_INLINE uint mcol_colordodge(uint col1, uint col2, int fac) cp[0] = (mfac * cp1[0] + temp * fac) / 255; temp = (cp2[1] == 255) ? 255 : min_ii((cp1[1] * 225) / (255 - cp2[1]), 255); cp[1] = (mfac * cp1[1] + temp * fac) / 255; - temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225 )/ (255 - cp2[2]), 255); + temp = (cp2[2] == 255) ? 255 : min_ii((cp1[2] * 225) / (255 - cp2[2]), 255); cp[2] = (mfac * cp1[2] + temp * fac) / 255; temp = (cp2[3] == 255) ? 255 : min_ii((cp1[3] * 225) / (255 - cp2[3]), 255); cp[3] = (mfac * cp1[3] + temp * fac) / 255; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index aa8e536a430..fb5192b8072 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -524,7 +524,8 @@ void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) test->dist = 0.0f; /* just for initialize */ /* Only for 2D projection. */ - zero_v4(test->plane); + zero_v4(test->plane_view); + zero_v4(test->plane_tool); test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass; @@ -590,7 +591,7 @@ bool sculpt_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3 bool sculpt_brush_test_circle_sq(SculptBrushTest *test, const float co[3]) { float co_proj[3]; - closest_to_plane_normalized_v3(co_proj, test->plane, co); + closest_to_plane_normalized_v3(co_proj, test->plane_view, co); float distsq = len_squared_v3v3(co_proj, test->location); if (distsq <= test->radius_squared) { @@ -634,6 +635,35 @@ bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float loca } } +SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape( + SculptSession *ss, SculptBrushTest *test, char falloff_shape) +{ + sculpt_brush_test_init(ss, test); + SculptBrushTestFn sculpt_brush_test_sq_fn; + if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + sculpt_brush_test_sq_fn = sculpt_brush_test_sphere_sq; + } + else { + /* PAINT_FALLOFF_SHAPE_TUBE */ + plane_from_point_normal_v3(test->plane_view, test->location, ss->cache->view_normal); + sculpt_brush_test_sq_fn = sculpt_brush_test_circle_sq; + } + return sculpt_brush_test_sq_fn; +} + +const float *sculpt_brush_frontface_normal_from_falloff_shape( + SculptSession *ss, char falloff_shape) +{ + if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + return ss->cache->sculpt_normal_symm; + } + else { + /* PAINT_FALLOFF_SHAPE_TUBE */ + return ss->cache->view_normal; + } +} + + static float frontface(const Brush *br, const float sculpt_normal[3], const short no[3], const float fno[3]) { @@ -772,7 +802,6 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) float (*area_cos)[3] = data->area_cos; PBVHVertexIter vd; - SculptBrushTest test; SculptUndoNode *unode = NULL; float private_co[2][3] = {{0.0f}}; @@ -784,7 +813,10 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS); use_original = (unode->co || unode->bm_entry); } - sculpt_brush_test_init(ss, &test); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); /* when the mesh is edited we can't rely on original coords @@ -807,7 +839,7 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri)); - if (sculpt_brush_test_sphere_fast(&test, co)) { + if (sculpt_brush_test_sq_fn(&test, co)) { float no[3]; int flip_index; @@ -841,7 +873,7 @@ static void calc_area_normal_and_center_task_cb(void *userdata, const int n) co = vd.co; } - if (sculpt_brush_test_sphere_fast(&test, co)) { + if (sculpt_brush_test_sq_fn(&test, co)) { float no_buf[3]; const float *no; int flip_index; @@ -959,7 +991,7 @@ void sculpt_pbvh_calc_area_normal( /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { - .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count, }; BLI_mutex_init(&data.mutex); @@ -999,7 +1031,7 @@ static void calc_area_normal_and_center( /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ SculptThreadedTaskData data = { - .sd = NULL, .ob = ob, .nodes = nodes, .totnode = totnode, + .sd = NULL, .ob = ob, .brush = brush, .nodes = nodes, .totnode = totnode, .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count, }; BLI_mutex_init(&data.mutex); @@ -1246,10 +1278,10 @@ bool sculpt_search_circle_cb(PBVHNode *node, void *data_v) BKE_pbvh_node_get_BB(node, bb_min, bb_min); float dummy_co[3], dummy_depth; - const float dist_sq = dist_squared_ray_to_aabb( + const float dist_sq = dist_squared_ray_to_aabb_v3( data->dist_ray_to_aabb_precalc, bb_min, bb_max, dummy_co, &dummy_depth); - return dist_sq < data->radius_squared; + return dist_sq < data->radius_squared || 1; } /* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */ @@ -1268,6 +1300,37 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float } } +static PBVHNode **sculpt_pbvh_gather_generic( + Object *ob, Sculpt *sd, const Brush *brush, bool use_original, float radius_scale, int *r_totnode) +{ + SculptSession *ss = ob->sculpt; + PBVHNode **nodes = NULL; + + /* Build a list of all nodes that are potentially within the brush's area of influence */ + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { + SculptSearchSphereData data = { + .ss = ss, + .sd = sd, + .radius_squared = SQUARE(ss->cache->radius * radius_scale), + .original = use_original, + }; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode); + } + else { + struct DistRayAABB_Precalc dist_ray_to_aabb_precalc; + dist_squared_ray_to_aabb_v3_precalc(&dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal); + SculptSearchCircleData data = { + .ss = ss, + .sd = sd, + .radius_squared = SQUARE(ss->cache->radius * radius_scale), + .original = use_original, + .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc, + }; + BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode); + } + return nodes; +} + /* Calculate primary direction of movement for many brushes */ static void calc_sculpt_normal( Sculpt *sd, Object *ob, @@ -1314,6 +1377,10 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob, (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal); + normalize_v3(cache->sculpt_normal); + } copy_v3_v3(cache->sculpt_normal_symm, cache->sculpt_normal); } else { @@ -1538,18 +1605,26 @@ typedef struct { SculptSession *ss; const float *ray_start, *ray_normal; bool hit; - float dist; + float depth; bool original; - PBVHNode* node; } SculptRaycastData; typedef struct { const float *ray_start, *ray_normal; bool hit; - float dist; + float depth; float detail; } SculptDetailRaycastData; +typedef struct { + SculptSession *ss; + const float *ray_start, *ray_normal; + bool hit; + float depth; + float dist_sq_to_ray; + bool original; +} SculptFindNearestToRayData; + static void do_smooth_brush_mesh_task_cb_ex( void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) { @@ -1561,19 +1636,19 @@ static void do_smooth_brush_mesh_task_cb_ex( float bstrength = data->strength; PBVHVertexIter vd; - SculptBrushTest test; CLAMP(bstrength, 0.0f, 1.0f); - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, - smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), - thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), thread_id); if (smooth_mask) { float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask; val *= fade * bstrength; @@ -1609,18 +1684,19 @@ static void do_smooth_brush_bmesh_task_cb_ex( float bstrength = data->strength; PBVHVertexIter vd; - SculptBrushTest test; CLAMP(bstrength, 0.0f, 1.0f); - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, - thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask, thread_id); if (smooth_mask) { float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask; val *= fade * bstrength; @@ -1656,7 +1732,6 @@ static void do_smooth_brush_multires_task_cb_ex( const bool smooth_mask = data->smooth_mask; float bstrength = data->strength; - SculptBrushTest test; CCGElem **griddata, *gddata; CCGKey key; @@ -1669,7 +1744,9 @@ static void do_smooth_brush_multires_task_cb_ex( int *grid_indices, totgrid, gridsize; int i, x, y; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); CLAMP(bstrength, 0.0f, 1.0f); @@ -1756,10 +1833,11 @@ static void do_smooth_brush_multires_task_cb_ex( fno = CCG_elem_offset_no(&key, gddata, index); mask = CCG_elem_offset_mask(&key, gddata, index); - if (sculpt_brush_test_sphere(&test, co)) { + if (sculpt_brush_test_sq_fn(&test, co)) { const float strength_mask = (smooth_mask ? 0.0f : *mask); const float fade = bstrength * tex_strength( - ss, brush, co, test.dist, NULL, fno, strength_mask, thread_id); + ss, brush, co, sqrtf(test.dist), + NULL, fno, strength_mask, thread_id); float f = 1.0f / 16.0f; if (x == 0 || x == gridsize - 1) @@ -1870,14 +1948,17 @@ static void do_mask_brush_draw_task_cb_ex( const float bstrength = ss->cache->bstrength; PBVHVertexIter vd; - SculptBrushTest test; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { - const float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no, vd.fno, 0.0f, thread_id); + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + const float fade = tex_strength( + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, 0.0f, thread_id); (*vd.mask) += fade * bstrength; CLAMP(*vd.mask, 0, 1); @@ -1927,19 +2008,21 @@ static void do_draw_brush_task_cb_ex( const float *offset = data->offset; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* offset vertex */ const float fade = tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -1977,6 +2060,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false); } +/** + * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' + */ static void do_crease_brush_task_cb_ex( void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id) { @@ -1988,24 +2074,30 @@ static void do_crease_brush_task_cb_ex( const float *offset = data->offset; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { /* offset vertex */ const float fade = tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float val1[3]; float val2[3]; /* first we pinch */ sub_v3_v3v3(val1, test.location, vd.co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(val1, val1, ss->cache->view_normal); + } + mul_v3_fl(val1, fade * flippedbstrength); sculpt_project_v3(spvc, val1, val1); @@ -2073,22 +2165,27 @@ static void do_pinch_brush_task_cb_ex( const Brush *brush = data->brush; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float val[3]; sub_v3_v3v3(val, test.location, vd.co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(val, val, ss->cache->view_normal); + } mul_v3_v3fl(proxy[vd.i], val, fade); if (vd.mvert) @@ -2120,7 +2217,6 @@ static void do_grab_brush_task_cb_ex( const float *grab_delta = data->grab_delta; PBVHVertexIter vd; - SculptBrushTest test; SculptOrigVertData orig_data; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; @@ -2129,16 +2225,18 @@ static void do_grab_brush_task_cb_ex( proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test_sphere(&test, orig_data.co)) { + if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( - ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, orig_data.co, sqrtf(test.dist), + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -2180,19 +2278,21 @@ static void do_nudge_brush_task_cb_ex( const float *cono = data->cono; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -2235,7 +2335,6 @@ static void do_snake_hook_brush_task_cb_ex( const float *grab_delta = data->grab_delta; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; const bool do_rake_rotation = ss->cache->is_rake_rotation_valid; @@ -2245,13 +2344,16 @@ static void do_snake_hook_brush_task_cb_ex( proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -2260,6 +2362,9 @@ static void do_snake_hook_brush_task_cb_ex( float delta_pinch_init[3], delta_pinch[3]; sub_v3_v3v3(delta_pinch, vd.co, test.location); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal); + } /* important to calculate based on the grabbed location (intentionally ignore fade here). */ add_v3_v3(delta_pinch, grab_delta); @@ -2335,7 +2440,6 @@ static void do_thumb_brush_task_cb_ex( const float *cono = data->cono; PBVHVertexIter vd; - SculptBrushTest test; SculptOrigVertData orig_data; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; @@ -2344,16 +2448,18 @@ static void do_thumb_brush_task_cb_ex( proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test_sphere(&test, orig_data.co)) { + if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( - ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, orig_data.co, sqrtf(test.dist), + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -2395,7 +2501,6 @@ static void do_rotate_brush_task_cb_ex( const float angle = data->angle; PBVHVertexIter vd; - SculptBrushTest test; SculptOrigVertData orig_data; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; @@ -2404,17 +2509,19 @@ static void do_rotate_brush_task_cb_ex( proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test_sphere(&test, orig_data.co)) { + if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { float vec[3], rot[3][3]; const float fade = bstrength * tex_strength( - ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, orig_data.co, sqrtf(test.dist), + orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f, thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); @@ -2457,7 +2564,6 @@ static void do_layer_brush_task_cb_ex( const float *offset = data->offset; PBVHVertexIter vd; - SculptBrushTest test; SculptOrigVertData orig_data; float *layer_disp; const float bstrength = ss->cache->bstrength; @@ -2472,15 +2578,18 @@ static void do_layer_brush_task_cb_ex( layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]); BLI_mutex_unlock(&data->mutex); - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_orig_vert_data_update(&orig_data, &vd); - if (sculpt_brush_test_sphere(&test, orig_data.co)) { + if (sculpt_brush_test_sq_fn(&test, orig_data.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float *disp = &layer_disp[vd.i]; float val[3]; @@ -2540,19 +2649,21 @@ static void do_inflate_brush_task_cb_ex( const Brush *brush = data->brush; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); float val[3]; if (vd.fno) @@ -2615,6 +2726,10 @@ static void calc_sculpt_plane( case SCULPT_DISP_DIR_AREA: calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); + normalize_v3(r_area_no); + } break; default: @@ -2700,29 +2815,31 @@ static void do_flatten_brush_task_cb_ex( const float *area_co = data->area_co; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane, area_co, area_no); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere_sq(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { float intr[3]; float val[3]; - closest_to_plane_normalized_v3(intr, test.plane, vd.co); + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); sub_v3_v3v3(val, intr, vd.co); if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2776,24 +2893,26 @@ static void do_clay_brush_task_cb_ex( const float *area_co = data->area_co; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const bool flip = (ss->cache->bstrength < 0); const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane, area_co, area_no); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere_sq(&test, vd.co)) { - if (plane_point_side_flip(vd.co, test.plane, flip)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + if (plane_point_side_flip(vd.co, test.plane_tool, flip)) { float intr[3]; float val[3]; - closest_to_plane_normalized_v3(intr, test.plane, vd.co); + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -2801,8 +2920,8 @@ static void do_clay_brush_task_cb_ex( /* note, the normal from the vertices is ignored, * causes glitch with planes, see: T44390 */ const float fade = bstrength * tex_strength( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2869,16 +2988,16 @@ static void do_clay_strips_brush_task_cb_ex( proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; sculpt_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane, area_co, area_no_sp); + plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_cube(&test, vd.co, mat)) { - if (plane_point_side_flip(vd.co, test.plane, flip)) { + if (plane_point_side_flip(vd.co, test.plane_tool, flip)) { float intr[3]; float val[3]; - closest_to_plane_normalized_v3(intr, test.plane, vd.co); + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); sub_v3_v3v3(val, intr, vd.co); @@ -2886,8 +3005,8 @@ static void do_clay_strips_brush_task_cb_ex( /* note, the normal from the vertices is ignored, * causes glitch with planes, see: T44390 */ const float fade = bstrength * tex_strength( - ss, brush, vd.co, ss->cache->radius * test.dist, - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, ss->cache->radius * test.dist, + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -2970,30 +3089,32 @@ static void do_fill_brush_task_cb_ex( const float *area_co = data->area_co; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane, area_co, area_no); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere_sq(&test, vd.co)) { - if (plane_point_side(vd.co, test.plane)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + if (plane_point_side(vd.co, test.plane_tool)) { float intr[3]; float val[3]; - closest_to_plane_normalized_v3(intr, test.plane, vd.co); + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); sub_v3_v3v3(val, intr, vd.co); if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, sqrtf(test.dist), - vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3049,30 +3170,31 @@ static void do_scrape_brush_task_cb_ex( const float *area_co = data->area_co; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; const float bstrength = ss->cache->bstrength; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane, area_co, area_no); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere_sq(&test, vd.co)) { - if (!plane_point_side(vd.co, test.plane)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + if (!plane_point_side(vd.co, test.plane_tool)) { float intr[3]; float val[3]; - closest_to_plane_normalized_v3(intr, test.plane, vd.co); + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); sub_v3_v3v3(val, intr, vd.co); if (plane_trim(ss->cache, brush, val)) { const float fade = bstrength * tex_strength( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -3127,18 +3249,19 @@ static void do_gravity_task_cb_ex( float *offset = data->offset; PBVHVertexIter vd; - SculptBrushTest test; float (*proxy)[3]; proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - sculpt_brush_test_init(ss, &test); + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = + sculpt_brush_test_init_with_falloff_shape(ss, &test, data->brush->falloff_shape); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sphere_sq(&test, vd.co)) { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = tex_strength( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, - thread_id); + ss, brush, vd.co, sqrtf(test.dist), + vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -3222,22 +3345,12 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *UNUSED(ups)) { SculptSession *ss = ob->sculpt; - SculptSearchSphereData data; - PBVHNode **nodes = NULL; - float radius; - int n, totnode; - /* Build a list of all nodes that are potentially within the - * brush's area of influence */ - data.ss = ss; - data.sd = sd; - - radius = ss->cache->radius * 1.25f; - - data.radius_squared = radius * radius; - data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original; - - BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + int n, totnode; + /* Build a list of all nodes that are potentially within the brush's area of influence */ + const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original; + const float radius_scale = 1.25f; + PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode); /* Only act if some verts are inside the brush area */ if (totnode) { @@ -3269,8 +3382,10 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified BKE_pbvh_bmesh_update_topology( ss->pbvh, mode, ss->cache->location, - (brush->flag & BRUSH_FRONTFACE) ? ss->cache->view_normal : NULL, - ss->cache->radius); + ss->cache->view_normal, + ss->cache->radius, + (brush->flag & BRUSH_FRONTFACE) != 0, + (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE)); } MEM_freeN(nodes); @@ -3293,16 +3408,12 @@ static void do_brush_action_task_cb(void *userdata, const int n) static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups) { SculptSession *ss = ob->sculpt; - SculptSearchSphereData data; - PBVHNode **nodes = NULL; int totnode; /* Build a list of all nodes that are potentially within the brush's area of influence */ - data.ss = ss; - data.sd = sd; - data.radius_squared = ss->cache->radius_squared; - data.original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original; - BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : ss->cache->original; + const float radius_scale = 1.0f; + PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode); /* Only act if some verts are inside the brush area */ if (totnode) { @@ -4120,7 +4231,6 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location); } - invert_m4_m4(imat, ob->obmat); mul_mat3_m4_v3(imat, cache->grab_delta); break; @@ -4130,6 +4240,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru zero_v3(cache->grab_delta); } + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(cache->grab_delta, cache->grab_delta, ss->cache->true_view_normal); + } + copy_v3_v3(cache->old_grab_location, grab_location); if (tool == SCULPT_TOOL_GRAB) @@ -4330,13 +4444,40 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) } if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco, - srd->ray_start, srd->ray_normal, &srd->dist)) + srd->ray_start, srd->ray_normal, &srd->depth)) { srd->hit = 1; - *tmin = srd->dist; + *tmin = srd->depth; + } + } +} + +static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *tmin) +{ + if (BKE_pbvh_node_get_tmin(node) < *tmin) { + SculptFindNearestToRayData *srd = data_v; + float (*origco)[3] = NULL; + bool use_origco = false; + + if (srd->original && srd->ss->cache) { + if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) { + use_origco = true; + } + else { + /* intersect with coordinates from before we started stroke */ + SculptUndoNode *unode = sculpt_undo_get_node(node); + origco = (unode) ? unode->co : NULL; + use_origco = origco ? true : false; + } + } - //for vwpaint testing - srd->node = node; + if (BKE_pbvh_node_find_nearest_to_ray( + srd->ss->pbvh, node, origco, use_origco, + srd->ray_start, srd->ray_normal, + &srd->depth, &srd->dist_sq_to_ray)) + { + srd->hit = 1; + *tmin = srd->dist_sq_to_ray; } } } @@ -4346,10 +4487,10 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin) if (BKE_pbvh_node_get_tmin(node) < *tmin) { SculptDetailRaycastData *srd = data_v; if (BKE_pbvh_bmesh_node_raycast_detail(node, srd->ray_start, srd->ray_normal, - &srd->dist, &srd->detail)) + &srd->depth, &srd->detail)) { srd->hit = 1; - *tmin = srd->dist; + *tmin = srd->depth; } } } @@ -4396,8 +4537,7 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) Object *ob; SculptSession *ss; StrokeCache *cache; - float ray_start[3], ray_end[3], ray_normal[3], dist; - SculptRaycastData srd; + float ray_start[3], ray_end[3], ray_normal[3], depth; bool original; ViewContext vc; @@ -4411,28 +4551,58 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) sculpt_stroke_modifiers_check(C, ob); - dist = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original); + depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original); - srd.original = original; - srd.ss = ob->sculpt; - srd.hit = 0; - srd.ray_start = ray_start; - srd.ray_normal = ray_normal; - srd.dist = dist; - - BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, - ray_start, ray_normal, srd.original); + bool hit = false; + { + SculptRaycastData srd = { + .original = original, + .ss = ob->sculpt, + .hit = 0, + .ray_start = ray_start, + .ray_normal = ray_normal, + .depth = depth, + }; + BKE_pbvh_raycast( + ss->pbvh, sculpt_raycast_cb, &srd, + ray_start, ray_normal, srd.original); + if (srd.hit) { + hit = true; + copy_v3_v3(out, ray_normal); + mul_v3_fl(out, srd.depth); + add_v3_v3(out, ray_start); + } + } - copy_v3_v3(out, ray_normal); - mul_v3_fl(out, srd.dist); - add_v3_v3(out, ray_start); + if (hit == false) { + const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); + if (ELEM(brush->falloff_shape, PAINT_FALLOFF_SHAPE_TUBE)) { + SculptFindNearestToRayData srd = { + .original = original, + .ss = ob->sculpt, + .hit = 0, + .ray_start = ray_start, + .ray_normal = ray_normal, + .depth = FLT_MAX, + .dist_sq_to_ray = FLT_MAX, + }; + BKE_pbvh_find_nearest_to_ray( + ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd, + ray_start, ray_normal, srd.original); + if (srd.hit) { + hit = true; + copy_v3_v3(out, ray_normal); + mul_v3_fl(out, srd.depth); + add_v3_v3(out, ray_start); + } + } + } - //used in vwpaint - if (cache && srd.hit){ + if (cache && hit) { copy_v3_v3(cache->true_location, out); } - return srd.hit; + return hit; } static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) @@ -5475,7 +5645,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) while (BKE_pbvh_bmesh_update_topology( ss->pbvh, PBVH_Collapse | PBVH_Subdivide, - center, NULL, size)) + center, NULL, size, false, false)) { for (i = 0; i < totnodes; i++) BKE_pbvh_node_mark_topology_update(nodes[i]); @@ -5511,7 +5681,7 @@ static void sample_detail(bContext *C, int ss_co[2]) ViewContext vc; Object *ob; Sculpt *sd; - float ray_start[3], ray_end[3], ray_normal[3], dist; + float ray_start[3], ray_end[3], ray_normal[3], depth; SculptDetailRaycastData srd; float mouse[2] = {ss_co[0], ss_co[1]}; view3d_set_viewcontext(C, &vc); @@ -5521,12 +5691,12 @@ static void sample_detail(bContext *C, int ss_co[2]) sculpt_stroke_modifiers_check(C, ob); - dist = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false); + depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false); srd.hit = 0; srd.ray_start = ray_start; srd.ray_normal = ray_normal; - srd.dist = dist; + srd.depth = depth; srd.detail = sd->constant_detail; BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index b9b662f4157..aaea13ce5d0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -182,7 +182,10 @@ typedef struct SculptBrushTest { int mirror_symmetry_pass; /* For circle (not sphere) projection. */ - float plane[4]; + float plane_view[4]; + + /* Some tool code uses a plane for it's calculateions. */ + float plane_tool[4]; /* View3d clipping - only set rv3d for clipping */ struct RegionView3D *clip_rv3d; @@ -213,6 +216,12 @@ bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float loca bool sculpt_brush_test_circle_sq(SculptBrushTest *test, const float co[3]); bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v); bool sculpt_search_circle_cb(PBVHNode *node, void *data_v); + +SculptBrushTestFn sculpt_brush_test_init_with_falloff_shape( + SculptSession *ss, SculptBrushTest *test, char falloff_shape); +const float *sculpt_brush_frontface_normal_from_falloff_shape( + SculptSession *ss, char falloff_shape); + float tex_strength( struct SculptSession *ss, const struct Brush *br, const float point[3], |