diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d_toolbar.py | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_paint.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/paint.c | 4 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_cursor.c | 46 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 84 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 13 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 8 |
8 files changed, 161 insertions, 7 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index c39f2ea051d..d96f8b04058 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -380,6 +380,11 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): row = col.row() row.prop(brush, "use_automasking_topology") + if brush.sculpt_tool == 'GRAB': + col.separator() + row = col.row() + row.prop(brush, "grab_active_vertex") + # topology_rake_factor if ( capabilities.has_topology_rake and diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 10c3f42bba7..ed4bcee3541 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -269,6 +269,10 @@ typedef struct SculptSession { float pivot_pos[3]; + /* Dynamic mesh preview */ + int *preview_vert_index_list; + int preview_vert_index_count; + union { struct { struct SculptVertexPaintGeomMap gmap; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index b386a0d4483..5980aa456e2 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1060,6 +1060,10 @@ void BKE_sculptsession_free(Object *ob) MEM_freeN(ss->deform_imats); } + if (ss->preview_vert_index_list) { + MEM_freeN(ss->preview_vert_index_list); + } + BKE_sculptsession_free_vwpaint_data(ob->sculpt); MEM_freeN(ss); diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index a000da57383..62e44bf04c5 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1180,6 +1180,20 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr, } } +static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss) +{ + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f); + GPU_depth_test(true); + GPU_line_width(1.0f); + if (ss->preview_vert_index_count > 0) { + immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count); + for (int i = 0; i < ss->preview_vert_index_count; i++) { + immVertex3fv(gpuattr, sculpt_vertex_co_get(ss, ss->preview_vert_index_list[i])); + } + immEnd(); + } +} + static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) { Scene *scene = CTX_data_scene(C); @@ -1348,6 +1362,17 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) imm_draw_circle_wire_3d(pos, 0, 0, rds, 40); GPU_matrix_pop(); + /* Update and draw dynamic mesh preview lines */ + GPU_matrix_push(); + GPU_matrix_mul(vc.obact->obmat); + if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag2 & BRUSH_GRAB_ACTIVE_VERTEX) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) { + sculpt_geometry_preview_lines_update(C, ss, rds); + sculpt_geometry_preview_lines_draw(pos, ss); + } + } + GPU_matrix_pop(); + GPU_matrix_pop_projection(); wmWindowViewport(win); @@ -1370,6 +1395,27 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) add_v3_v3(cursor_location, ss->cache->grab_delta); } cursor_draw_point_with_symmetry(pos, ar, cursor_location, sd, vc.obact, ss->cache->radius); + + /* Draw cached dynamic mesh preview lines */ + if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag2 & BRUSH_GRAB_ACTIVE_VERTEX) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) { + GPU_matrix_push_projection(); + ED_view3d_draw_setup_view(CTX_wm_window(C), + CTX_data_depsgraph_pointer(C), + CTX_data_scene(C), + ar, + CTX_wm_view3d(C), + NULL, + NULL, + NULL); + GPU_matrix_push(); + GPU_matrix_mul(vc.obact->obmat); + sculpt_geometry_preview_lines_draw(pos, ss); + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + } + } + wmWindowViewport(win); } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 792a75746d3..688adc56ef5 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -31,6 +31,7 @@ #include "BLI_gsqueue.h" #include "BLI_stack.h" #include "BLI_task.h" +#include "BLI_stack.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -99,7 +100,7 @@ /* Do not use these functions while working with PBVH_GRIDS data in SculptSession */ -static float *sculpt_vertex_co_get(SculptSession *ss, int index) +float *sculpt_vertex_co_get(SculptSession *ss, int index) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: @@ -5902,7 +5903,13 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru float grab_location[3], imat[4][4], delta[3], loc[3]; if (cache->first_time) { - copy_v3_v3(cache->orig_grab_location, cache->true_location); + if (tool == SCULPT_TOOL_GRAB && brush->flag2 & BRUSH_GRAB_ACTIVE_VERTEX) { + copy_v3_v3(cache->orig_grab_location, + sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); + } + else { + copy_v3_v3(cache->orig_grab_location, cache->true_location); + } } else if (tool == SCULPT_TOOL_SNAKE_HOOK) { add_v3_v3(cache->true_location, cache->grab_delta); @@ -5955,7 +5962,12 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru copy_v3_v3(cache->old_grab_location, grab_location); if (tool == SCULPT_TOOL_GRAB) { - copy_v3_v3(cache->anchored_location, cache->true_location); + if (brush->flag2 & BRUSH_GRAB_ACTIVE_VERTEX) { + copy_v3_v3(cache->anchored_location, cache->orig_grab_location); + } + else { + copy_v3_v3(cache->anchored_location, cache->true_location); + } } else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) { copy_v3_v3(cache->anchored_location, cache->true_location); @@ -8995,6 +9007,72 @@ static void SCULPT_OT_mask_expand(wmOperatorType *ot) 2000); } +void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + + ss->preview_vert_index_count = 0; + int totpoints = 0; + + /* This function is called from the cursor drawing code, so the PBVH may not be build yet */ + if (!ss->pbvh) { + return; + } + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true); + + if (!ss->pmap) { + return; + } + + float brush_co[3]; + copy_v3_v3(brush_co, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss))); + + char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char), + "visited vertices"); + + if (ss->preview_vert_index_list == NULL) { + ss->preview_vert_index_list = MEM_callocN(4 * sizeof(int) * sculpt_vertex_count_get(ss), + "preview lines"); + } + + BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator), + "Not visited vertices stack"); + VertexTopologyIterator mevit; + mevit.v = sculpt_active_vertex_get(ss); + BLI_stack_push(not_visited_vertices, &mevit); + + while (!BLI_stack_is_empty(not_visited_vertices)) { + VertexTopologyIterator c_mevit; + BLI_stack_pop(not_visited_vertices, &c_mevit); + SculptVertexNeighborIter ni; + sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni) + { + VertexTopologyIterator new_entry; + new_entry.v = ni.index; + new_entry.it = c_mevit.it + 1; + ss->preview_vert_index_list[totpoints] = c_mevit.v; + totpoints++; + ss->preview_vert_index_list[totpoints] = new_entry.v; + totpoints++; + if (visited_vertices[(int)ni.index] == 0) { + visited_vertices[(int)ni.index] = 1; + if (len_squared_v3v3(brush_co, sculpt_vertex_co_get(ss, new_entry.v)) < radius * radius) { + BLI_stack_push(not_visited_vertices, &new_entry); + } + } + } + sculpt_vertex_neighbors_iter_end(ni) + } + + BLI_stack_free(not_visited_vertices); + + MEM_freeN(visited_vertices); + + ss->preview_vert_index_count = totpoints; +} + void ED_operatortypes_sculpt(void) { WM_operatortype_append(SCULPT_OT_brush_stroke); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 3be8e0f7bb7..5995eadea59 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -57,6 +57,10 @@ bool sculpt_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mouse[2], bool use_sampled_normal); +void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius); + +/* Sculpt PBVH abstraction API */ +float *sculpt_vertex_co_get(struct SculptSession *ss, int index); /* Dynamic topology */ void sculpt_pbvh_clear(Object *ob); diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 56e255b132a..5901163c3a9 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -244,6 +244,8 @@ typedef struct Brush { int size; /** General purpose flag. */ int flag; + int flag2; + char _pad[4]; /** Pressure influence for mask. */ int mask_pressure; /** Jitter the position of the brush. */ @@ -280,7 +282,7 @@ typedef struct Brush { /** Source for fill tool color gradient application. */ char gradient_fill_mode; - char _pad; + char _pad0; /** Projection shape (sphere, circle). */ char falloff_shape; float falloff_angle; @@ -289,7 +291,6 @@ typedef struct Brush { char sculpt_tool; /** Active sculpt tool. */ char uv_sculpt_tool; - /** Active vertex paint. */ char vertexpaint_tool; /** Active weight paint. */ char weightpaint_tool; @@ -299,7 +300,7 @@ typedef struct Brush { char mask_tool; /** Active grease pencil tool. */ char gpencil_tool; - char _pad0[1]; + char _pad1[1]; float autosmooth_factor; @@ -318,7 +319,7 @@ typedef struct Brush { int curve_preset; int automasking_flags; - char _pad1[4]; + char _pad2[4]; int elastic_deform_type; float elastic_deform_compressibility; @@ -431,6 +432,10 @@ typedef enum eBrushFlags { BRUSH_CURVE = (1u << 31), } eBrushFlags; +typedef enum eBrushFlags2 { + BRUSH_GRAB_ACTIVE_VERTEX = (1 << 0), +} eBrushFlags2; + typedef enum { BRUSH_MASK_PRESSURE_RAMP = (1 << 1), BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2), diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 3aa96749512..a78a6fb264b 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1984,6 +1984,14 @@ static void rna_def_brush(BlenderRNA *brna) prop, "Spacing distance", "Calculate the brush spacing using view or scene distance"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "grab_active_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_GRAB_ACTIVE_VERTEX); + RNA_def_property_ui_text( + prop, + "Grab Active Vertex", + "Apply the maximum grab strength to the active vertex instead of the cursor location"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); |