diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 5ce16e8b906..8580aefcfbc 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -270,6 +270,7 @@ typedef struct SculptSession { /* Dynamic mesh preview */ int *preview_vert_index_list; int preview_vert_index_count; + float pose_origin[3]; /* Transform operator */ float pivot_pos[3]; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index c8c857d721b..a41ff09e514 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1093,17 +1093,15 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush) return true; } -static void cursor_draw_point_screen_space(const uint gpuattr, - const ARegion *ar, - const float true_location[3], - const float obmat[4][4]) +static void cursor_draw_point_screen_space( + const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size) { float translation_vertex_cursor[3], location[3]; copy_v3_v3(location, true_location); mul_m4_v3(obmat, location); ED_view3d_project(ar, location, translation_vertex_cursor); imm_draw_circle_fill_3d( - gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], 3, 10); + gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10); } static void cursor_draw_tiling_preview(const uint gpuattr, @@ -1145,7 +1143,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr, for (dim = 0; dim < 3; dim++) { location[dim] = cur[dim] * step[dim] + orgLoc[dim]; } - cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat); + cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3); } } } @@ -1166,7 +1164,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, /* Axis Symmetry */ flip_v3_v3(location, true_location, (char)i); - cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat); + cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3); /* Tiling */ cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius); @@ -1181,7 +1179,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, mul_m4_v3(symm_rot_mat, location); cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius); - cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat); + cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3); } } } @@ -1215,6 +1213,7 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) { + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -1338,8 +1337,14 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) if (!ups->stroke_active) { SculptCursorGeometryInfo gi; float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin}; + int prev_active_vertex_index = ss->active_vertex_index; + bool update_previews = false; if (sculpt_cursor_geometry_info_update(C, &gi, mouse, true) && !alpha_overlay_active) { + if (prev_active_vertex_index != ss->active_vertex_index) { + update_previews = true; + } + float rds; if (!BKE_brush_use_locked_size(scene, brush)) { rds = paint_calc_object_space_radius(&vc, gi.location, BKE_brush_size_get(scene, brush)); @@ -1355,6 +1360,16 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds); } + /* Draw pose brush origin */ + if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) { + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); + if (update_previews) { + BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false); + sculpt_pose_calc_pose_data(sd, vc.obact, ss, gi.location, rds, ss->pose_origin, NULL); + } + cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5); + } + /* Draw 3D brush cursor */ GPU_matrix_push_projection(); ED_view3d_draw_setup_view(CTX_wm_window(C), @@ -1378,6 +1393,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) GPU_matrix_push(); GPU_matrix_mul(cursor_trans); GPU_matrix_mul(cursor_rot); + immUniformColor3fvAlpha(outline_col, outline_alpha); imm_draw_circle_wire_3d(pos, 0, 0, rds, 40); GPU_matrix_pop(); @@ -1390,6 +1406,17 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) sculpt_geometry_preview_lines_draw(pos, ss); } } + + /* Draw pose brush line preview */ + if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) { + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); + GPU_line_width(2.0f); + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, ss->pose_origin); + immVertex3fv(pos, gi.location); + immEnd(); + } + GPU_matrix_pop(); GPU_matrix_pop_projection(); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 351e4c0482b..d912f04479d 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -3610,13 +3610,26 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3], return false; } -static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br) +/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush + * + * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't + * be calculated. */ +void sculpt_pose_calc_pose_data(Sculpt *sd, + Object *ob, + SculptSession *ss, + float initial_location[3], + float radius, + float *r_pose_origin, + float *r_pose_factor) { + const bool calc_pose_factor = (r_pose_factor != NULL); + sculpt_vertex_random_access_init(ss); - ss->cache->pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor"); + float pose_origin[3]; + float pose_initial_co[3]; - copy_v3_v3(ss->cache->pose_initial_co, ss->cache->location); + copy_v3_v3(pose_initial_co, initial_location); char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char), "Visited vertices"); @@ -3624,13 +3637,14 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br "not visited vertices stack"); float tot_co = 0; - zero_v3(ss->cache->pose_origin); + zero_v3(pose_origin); VertexTopologyIterator mevit; /* Add active vertex and symmetric vertices to the stack. */ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; for (char i = 0; i <= symm; ++i) { + mevit.v = -1; if (is_symmetry_iteration_valid(i, symm)) { float location[3]; flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), (char)i); @@ -3638,8 +3652,9 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br mevit.v = sculpt_active_vertex_get(ss); } else { - mevit.v = sculpt_nearest_vertex_get( - sd, ob, location, ss->cache->radius * ss->cache->radius, false); + if (calc_pose_factor) { + mevit.v = sculpt_nearest_vertex_get(sd, ob, location, radius * radius, false); + } } if (mevit.v != -1) { mevit.it = 1; @@ -3660,19 +3675,19 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br VertexTopologyIterator new_entry; new_entry.v = ni.index; new_entry.it = c_mevit.it + 1; - ss->cache->pose_factor[new_entry.v] = 1.0f; + if (calc_pose_factor) { + r_pose_factor[new_entry.v] = 1.0f; + } visited_vertices[(int)ni.index] = 1; - if (sculpt_pose_brush_is_vertex_inside_brush_radius(sculpt_vertex_co_get(ss, new_entry.v), - ss->cache->pose_initial_co, - ss->cache->radius, - symm)) { + if (sculpt_pose_brush_is_vertex_inside_brush_radius( + sculpt_vertex_co_get(ss, new_entry.v), pose_initial_co, radius, symm)) { BLI_stack_push(not_visited_vertices, &new_entry); } else { if (check_vertex_pivot_symmetry( - sculpt_vertex_co_get(ss, new_entry.v), ss->cache->pose_initial_co, symm)) { + sculpt_vertex_co_get(ss, new_entry.v), pose_initial_co, symm)) { tot_co++; - add_v3_v3(ss->cache->pose_origin, sculpt_vertex_co_get(ss, new_entry.v)); + add_v3_v3(pose_origin, sculpt_vertex_co_get(ss, new_entry.v)); } } } @@ -3681,15 +3696,26 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br } BLI_stack_free(not_visited_vertices); - MEM_freeN(visited_vertices); if (tot_co > 0) { - mul_v3_fl(ss->cache->pose_origin, 1.0f / (float)tot_co); + mul_v3_fl(pose_origin, 1.0f / (float)tot_co); } + copy_v3_v3(r_pose_origin, pose_origin); +} + +static void sculpt_pose_brush_init( + Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius) +{ + float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor"); + + sculpt_pose_calc_pose_data( + sd, ob, ss, initial_location, radius, ss->cache->pose_origin, pose_factor); + + copy_v3_v3(ss->cache->pose_initial_co, initial_location); + ss->cache->pose_factor = pose_factor; /* Smooth the pose brush factor for cleaner deformation */ - PBVHNode **nodes; PBVH *pbvh = ob->sculpt->pbvh; int totnode; @@ -5078,7 +5104,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) { if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) { - sculpt_pose_brush_init(sd, ob, ss, brush); + sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); } } @@ -5676,6 +5702,9 @@ void sculpt_cache_free(StrokeCache *cache) if (cache->dial) { MEM_freeN(cache->dial); } + if (cache->pose_factor) { + MEM_freeN(cache->pose_factor); + } MEM_freeN(cache); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index b814e87fcb0..ba7c2e601ff 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -58,6 +58,13 @@ bool sculpt_cursor_geometry_info_update(bContext *C, const float mouse[2], bool use_sampled_normal); void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius); +void sculpt_pose_calc_pose_data(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + float initial_location[3], + float radius, + float *r_pose_origin, + float *r_pose_factor); /* Sculpt PBVH abstraction API */ float *sculpt_vertex_co_get(struct SculptSession *ss, int index);