Fix T99644: Anchored brush mode fails for negative brushes

The stroke code now supports raycasting the original mesh.
This fixes anchored mode not working for negative brushes,
which might move the mesh out of the initial mouse cursor
position.
This commit is contained in:
Joseph Eagar 2022-07-16 17:27:25 -07:00
parent 9a14887905
commit cd1e4ae448
Notes: blender-bot 2023-02-14 09:48:25 +01:00
Referenced by issue #99644, Draw Sharp brush stops on anchored during the stroke
6 changed files with 39 additions and 15 deletions

View File

@ -147,7 +147,10 @@ struct SculptCurvesBrushStrokeData {
PaintStroke *stroke;
};
static bool stroke_get_location(bContext *C, float out[3], const float mouse[2])
static bool stroke_get_location(bContext *C,
float out[3],
const float mouse[2],
bool UNUSED(force_original))
{
out[0] = mouse[0];
out[1] = mouse[1];

View File

@ -46,7 +46,10 @@ typedef struct CoNo {
/* paint_stroke.c */
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeGetLocation)(struct bContext *C,
float location[3],
const float mouse[2],
bool force_original);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
typedef void (*StrokeUpdateStep)(struct bContext *C,
struct wmOperator *op,

View File

@ -122,6 +122,8 @@ typedef struct PaintStroke {
StrokeUpdateStep update_step;
StrokeRedraw redraw;
StrokeDone done;
bool original; /* Raycast original mesh at start of stroke */
} PaintStroke;
/*** Cursors ***/
@ -245,6 +247,11 @@ static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode)
return false;
}
static bool paint_tool_raycast_original(Brush *brush, ePaintMode mode)
{
return brush->flag & BRUSH_ANCHORED;
}
static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode)
{
if (brush->flag & BRUSH_ANCHORED) {
@ -394,7 +401,7 @@ static bool paint_brush_update(bContext *C,
halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
if (stroke->get_location) {
if (stroke->get_location(C, r_location, halfway)) {
if (stroke->get_location(C, r_location, halfway, stroke->original)) {
hit = true;
location_sampled = true;
location_success = true;
@ -468,7 +475,7 @@ static bool paint_brush_update(bContext *C,
if (!location_sampled) {
if (stroke->get_location) {
if (stroke->get_location(C, r_location, mouse)) {
if (stroke->get_location(C, r_location, mouse, stroke->original)) {
location_success = true;
*r_location_is_set = true;
}
@ -554,7 +561,8 @@ static void paint_brush_stroke_add_step(
if (paint_stroke_use_scene_spacing(brush, mode)) {
float world_space_position[3];
if (SCULPT_stroke_get_location(C, world_space_position, stroke->last_mouse_position)) {
if (SCULPT_stroke_get_location(
C, world_space_position, stroke->last_mouse_position, stroke->original)) {
copy_v3_v3(stroke->last_world_space_position, world_space_position);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
@ -816,7 +824,7 @@ static int paint_space_stroke(bContext *C,
if (use_scene_spacing) {
float world_space_position[3];
bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse);
bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position);
if (hit && stroke->stroke_over_mesh) {
sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position);
@ -907,6 +915,8 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->ups = ups;
stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
stroke->original = paint_tool_raycast_original(br, BKE_paintmode_get_active_from_context(C));
get_imapaint_zoom(C, &zoomx, &zoomy);
stroke->zoom_2d = max_ff(zoomx, zoomy);
@ -1202,8 +1212,10 @@ static void paint_line_strokes_spacing(bContext *C,
copy_v2_v2(stroke->last_mouse_position, old_pos);
if (use_scene_spacing) {
bool hit_old = SCULPT_stroke_get_location(C, world_space_position_old, old_pos);
bool hit_new = SCULPT_stroke_get_location(C, world_space_position_new, new_pos);
bool hit_old = SCULPT_stroke_get_location(
C, world_space_position_old, old_pos, stroke->original);
bool hit_new = SCULPT_stroke_get_location(
C, world_space_position_new, new_pos, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position_old);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position_new);
if (hit_old && hit_new && stroke->stroke_over_mesh) {
@ -1347,7 +1359,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (paint_stroke_use_scene_spacing(br, BKE_paintmode_get_active_from_context(C))) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
C, stroke->last_world_space_position, data + 2 * j);
C, stroke->last_world_space_position, data + 2 * j, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
@ -1479,7 +1491,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
if (paint_stroke_use_scene_spacing(br, mode)) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
C, stroke->last_world_space_position, sample_average.mouse);
C, stroke->last_world_space_position, sample_average.mouse, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);

View File

@ -4952,7 +4952,10 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
bool SCULPT_stroke_get_location(bContext *C,
float out[3],
const float mval[2],
bool force_original)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
@ -4968,7 +4971,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mval[2])
ss = ob->sculpt;
cache = ss->cache;
original = (cache) ? cache->original : false;
original = force_original || ((cache) ? cache->original : false);
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
@ -5284,7 +5287,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2])
{
float co_dummy[3];
return SCULPT_stroke_get_location(C, co_dummy, mval);
return SCULPT_stroke_get_location(C, co_dummy, mval, false);
}
bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)

View File

@ -845,7 +845,10 @@ void SCULPT_tag_update_overlays(bContext *C);
* (This allows us to ignore the GL depth buffer)
* Returns 0 if the ray doesn't hit the mesh, non-zero otherwise.
*/
bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]);
bool SCULPT_stroke_get_location(struct bContext *C,
float out[3],
const float mouse[2],
bool force_original);
/**
* Gets the normal, location and active vertex location of the geometry under the cursor. This also
* updates the active vertex and cursor related data of the SculptSession using the mouse position

View File

@ -426,7 +426,7 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
RNA_float_get(op->ptr, "mouse_x"),
RNA_float_get(op->ptr, "mouse_y"),
};
if (SCULPT_stroke_get_location(C, stroke_location, mval)) {
if (SCULPT_stroke_get_location(C, stroke_location, mval, false)) {
copy_v3_v3(ss->pivot_pos, stroke_location);
}
}