diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/intern/brush.c | 9 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_defaults.c | 8 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_cursor.c | 82 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 348 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 6 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 17 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 22 |
7 files changed, 489 insertions, 3 deletions
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index eebed72103f..794876ec444 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -938,6 +938,14 @@ void BKE_brush_sculpt_reset(Brush *br) br->curve_preset = BRUSH_CURVE_SPHERE; br->spacing = 6; break; + case SCULPT_TOOL_MULTIPLANE_SCRAPE: + br->flag2 |= BRUSH_MULTIPLANE_SCRAPE_DYNAMIC | BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW; + br->alpha = 0.7f; + br->normal_radius_factor = 0.70f; + br->multiplane_scrape_angle = 60; + br->curve_preset = BRUSH_CURVE_SMOOTH; + br->spacing = 5; + break; case SCULPT_TOOL_CREASE: br->flag |= BRUSH_DIR_IN; br->alpha = 0.25; @@ -1010,6 +1018,7 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_FLATTEN: case SCULPT_TOOL_FILL: case SCULPT_TOOL_SCRAPE: + case SCULPT_TOOL_MULTIPLANE_SCRAPE: br->add_col[0] = 1.0f; br->add_col[1] = 0.39f; br->add_col[2] = 0.39f; diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 05758b446ad..45ec6eef813 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -509,6 +509,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) brush->sculpt_tool = SCULPT_TOOL_POSE; } + brush_name = "Multiplane Scrape"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_MULTIPLANE_SCRAPE; + } + brush_name = "Simplify"; brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); if (!brush) { diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index b9af33e7ad6..ac738f326a3 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1214,6 +1214,70 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession } } +static void sculpt_multiplane_scrape_preview_draw(const uint gpuattr, + SculptSession *ss, + float *outline_col, + float outline_alpha) +{ + float local_mat_inv[4][4]; + invert_m4_m4(local_mat_inv, ss->cache->stroke_local_mat); + GPU_matrix_mul(local_mat_inv); + float angle = ss->cache->multiplane_scrape_sampled_angle; + if (ss->cache->pen_flip || ss->cache->invert) { + angle = -angle; + } + + float offset = ss->cache->radius * 0.25f; + + float p[3] = {0.0f, 0.0f, ss->cache->radius}; + float y_axis[3] = {0.0f, 1.0f, 0.0f}; + float p_l[3]; + float p_r[3]; + float area_center[3] = {0.0f, 0.0f, 0.0f}; + rotate_v3_v3v3fl(p_r, p, y_axis, DEG2RADF((angle + 180) * 0.5f)); + rotate_v3_v3v3fl(p_l, p, y_axis, DEG2RADF(-(angle + 180) * 0.5f)); + + immBegin(GPU_PRIM_LINES, 14); + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]); + + immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]); + immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]); + immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]); + + immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + + immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]); + immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]); + + immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]); + immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]); + + immEnd(); + + immUniformColor3fvAlpha(outline_col, outline_alpha * 0.1f); + immBegin(GPU_PRIM_TRIS, 12); + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + immVertex3f(gpuattr, p_r[0], p_r[1] + offset, p_r[2]); + immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]); + immVertex3f(gpuattr, p_r[0], p_r[1] - offset, p_r[2]); + + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + immVertex3f(gpuattr, p_l[0], p_l[1] + offset, p_l[2]); + immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] + offset, area_center[2]); + immVertex3f(gpuattr, area_center[0], area_center[1] - offset, area_center[2]); + immVertex3f(gpuattr, p_l[0], p_l[1] - offset, p_l[2]); + + immEnd(); +} + static bool paint_use_2d_cursor(ePaintMode mode) { if (mode >= PAINT_MODE_TEXTURE_3D) { @@ -1516,6 +1580,24 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) } } + if (brush->sculpt_tool == SCULPT_TOOL_MULTIPLANE_SCRAPE && + brush->flag2 & BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW && !ss->cache->first_time) { + 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_multiplane_scrape_preview_draw(pos, ss, outline_col, outline_alpha); + 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 fcc2a7a08b3..6cda6ccac06 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1771,6 +1771,10 @@ static float brush_strength(const Sculpt *sd, return 0.125f * alpha * flip * pressure * overlap * feather; } + case SCULPT_TOOL_MULTIPLANE_SCRAPE: + overlap = (1.0f + overlap) / 2.0f; + return alpha * flip * pressure * overlap * feather; + case SCULPT_TOOL_FILL: case SCULPT_TOOL_SCRAPE: case SCULPT_TOOL_FLATTEN: @@ -4843,6 +4847,341 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); } +/* -------------------------------------------------------------------- */ + +/** \name Sculpt Multiplane Scrape Brush + * \{ */ + +typedef struct MultiplaneScrapeSampleData { + float area_cos[2][3]; + float area_nos[2][3]; + int area_count[2]; +} MultiplaneScrapeSampleData; + +static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + MultiplaneScrapeSampleData *mssd = tls->userdata_chunk; + float(*mat)[4] = data->mat; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = sculpt_brush_test_init_with_falloff_shape( + ss, &test, brush->falloff_shape); + + /* Apply the brush normal radius to the test before sampling */ + float test_radius = sqrtf(test.radius_squared); + test_radius *= brush->normal_radius_factor; + test.radius_squared = test_radius * test_radius; + + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + float local_co[3]; + float normal[3]; + if (vd.no) { + normal_short_to_float_v3(normal, vd.no); + } + else { + copy_v3_v3(normal, vd.fno); + } + mul_v3_m4v3(local_co, mat, vd.co); + /* Use the brush falloff to weight the sampled normals */ + const float fade = tex_strength(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + tls->thread_id); + + /* Sample the normal and area of the +X and -X axis individually */ + if (local_co[0] > 0.0f) { + madd_v3_v3fl(mssd->area_nos[0], normal, fade); + add_v3_v3(mssd->area_cos[0], vd.co); + mssd->area_count[0]++; + } + else { + madd_v3_v3fl(mssd->area_nos[1], normal, fade); + add_v3_v3(mssd->area_cos[1], vd.co); + mssd->area_count[1]++; + } + } + BKE_pbvh_vertex_iter_end; + } +} + +static void calc_multiplane_scrape_surface_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + MultiplaneScrapeSampleData *join = chunk_join; + MultiplaneScrapeSampleData *mssd = chunk; + + add_v3_v3(join->area_cos[0], mssd->area_cos[0]); + add_v3_v3(join->area_cos[1], mssd->area_cos[1]); + + add_v3_v3(join->area_nos[0], mssd->area_nos[0]); + add_v3_v3(join->area_nos[1], mssd->area_nos[1]); + + join->area_count[0] += mssd->area_count[0]; + join->area_count[1] += mssd->area_count[1]; +} + +static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*mat)[4] = data->mat; + float(*scrape_planes)[4] = data->multiplane_scrape_planes; + + float angle = data->multiplane_scrape_angle; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = fabsf(ss->cache->bstrength); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + 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_sq_fn(&test, vd.co)) { + float local_co[3]; + bool deform = false; + + mul_v3_m4v3(local_co, mat, vd.co); + + if (local_co[0] > 0.0f) { + deform = !plane_point_side(vd.co, scrape_planes[0]); + } + else { + deform = !plane_point_side(vd.co, scrape_planes[1]); + } + + if (angle < 0.0f) { + deform = true; + } + + if (deform) { + float intr[3]; + float val[3]; + + if (local_co[0] > 0.0f) { + closest_to_plane_normalized_v3(intr, scrape_planes[0], vd.co); + } + else { + closest_to_plane_normalized_v3(intr, scrape_planes[1], vd.co); + } + + sub_v3_v3v3(val, intr, vd.co); + if (plane_trim(ss->cache, brush, val)) { + /* Deform the local space along the Y axis to avoid artifacts on curved strokes */ + /* This produces a not round brush tip */ + local_co[1] *= 2.0f; + const float fade = bstrength * tex_strength(ss, + brush, + vd.co, + len_v3(local_co), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + tls->thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const bool flip = (ss->cache->bstrength < 0.0f); + const float radius = flip ? -ss->cache->radius : ss->cache->radius; + const float offset = get_offset(sd, ss); + const float displace = -radius * offset; + + float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */ + float area_no[3]; /* geometry normal */ + float area_co[3]; + + float temp[3]; + float mat[4][4]; + + calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co); + + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + calc_area_normal(sd, ob, nodes, totnode, area_no); + } + else { + copy_v3_v3(area_no, area_no_sp); + } + + /* delay the first daub because grab delta is not setup */ + if (ss->cache->first_time) { + return; + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + /* Init brush local space matrix */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0; + copy_v3_v3(mat[3], ss->cache->location); + mat[3][3] = 1; + normalize_m4(mat); + invert_m4(mat); + + float angle = brush->multiplane_scrape_angle; + + /* Update matrix for the cursor preview */ + if (ss->cache->mirror_symmetry_pass == 0) { + copy_m4_m4(ss->cache->stroke_local_mat, mat); + } + + /* Dynamic mode */ + + if (brush->flag2 & BRUSH_MULTIPLANE_SCRAPE_DYNAMIC) { + /* Sample the individual normal and area center of the two areas at both sides of the cursor */ + SculptThreadedTaskData sample_data = { + .sd = NULL, + .ob = ob, + .brush = brush, + .nodes = nodes, + .totnode = totnode, + .mat = mat, + }; + + MultiplaneScrapeSampleData mssd = {{{0}}}; + + PBVHParallelSettings sample_settings; + BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce; + sample_settings.userdata_chunk = &mssd; + sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData); + + BKE_pbvh_parallel_range( + 0, totnode, &sample_data, calc_multiplane_scrape_surface_task_cb, &sample_settings); + + float sampled_plane_normals[2][3]; + float sampled_plane_co[2][3]; + float sampled_cv[2][3]; + float mid_co[3]; + + /* Use the area center of both planes to detect if we are sculpting along a concave or convex + * edge */ + mul_v3_v3fl(sampled_plane_co[0], mssd.area_cos[0], 1.0f / (float)mssd.area_count[0]); + mul_v3_v3fl(sampled_plane_co[1], mssd.area_cos[1], 1.0f / (float)mssd.area_count[1]); + mid_v3_v3v3(mid_co, sampled_plane_co[0], sampled_plane_co[1]); + + /* Calculate the scrape planes angle based on the sampled normals */ + mul_v3_v3fl(sampled_plane_normals[0], mssd.area_nos[0], 1.0f / (float)mssd.area_count[0]); + mul_v3_v3fl(sampled_plane_normals[1], mssd.area_nos[1], 1.0f / (float)mssd.area_count[1]); + normalize_v3(sampled_plane_normals[0]); + normalize_v3(sampled_plane_normals[1]); + + float sampled_angle = angle_v3v3(sampled_plane_normals[0], sampled_plane_normals[1]); + copy_v3_v3(sampled_cv[0], area_no); + sub_v3_v3v3(sampled_cv[1], ss->cache->location, mid_co); + + sampled_angle += DEG2RADF(brush->multiplane_scrape_angle) * ss->cache->pressure; + + /* Invert the angle if we are sculpting along a concave edge */ + if (dot_v3v3(sampled_cv[0], sampled_cv[1]) < 0.0f) { + sampled_angle = -sampled_angle; + } + + /* In dynamic mode, set the angle to 0 when inverting the brush, so you can trim plane surfaces + * without changing the brush */ + if (flip) { + sampled_angle = 0.0f; + } + else { + copy_v3_v3(area_co, ss->cache->location); + } + + angle = RAD2DEGF(sampled_angle); + } + else { + + /* Standard mode: Scrape with the brush property fixed angle */ + copy_v3_v3(area_co, ss->cache->location); + if (flip) { + angle = -angle; + } + } + + /* Set the angle for the cursor preview */ + ss->cache->multiplane_scrape_sampled_angle = angle; + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .mat = mat, + .multiplane_scrape_angle = angle, + }; + + /* Calculate the final left and right scrape planes */ + float plane_no[3]; + float plane_no_rot[3]; + float y_axis[3] = {0.0f, 1.0f, 0.0f}; + float mat_inv[4][4]; + invert_m4_m4(mat_inv, mat); + + mul_v3_mat3_m4v3(plane_no, mat, area_no); + rotate_v3_v3v3fl(plane_no_rot, plane_no, y_axis, DEG2RADF(-angle * 0.5f)); + mul_v3_mat3_m4v3(plane_no, mat_inv, plane_no_rot); + normalize_v3(plane_no); + plane_from_point_normal_v3(data.multiplane_scrape_planes[1], area_co, plane_no); + + mul_v3_mat3_m4v3(plane_no, mat, area_no); + rotate_v3_v3v3fl(plane_no_rot, plane_no, y_axis, DEG2RADF(angle * 0.5f)); + mul_v3_mat3_m4v3(plane_no, mat_inv, plane_no_rot); + normalize_v3(plane_no); + plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no); + + PBVHParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); + BKE_pbvh_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings); +} + /** \} */ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, @@ -5468,6 +5807,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_CLAY_STRIPS: do_clay_strips_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_MULTIPLANE_SCRAPE: + do_multiplane_scrape_brush(sd, ob, nodes, totnode); + break; case SCULPT_TOOL_FILL: do_fill_brush(sd, ob, nodes, totnode); break; @@ -5997,6 +6339,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Elastic Deform Brush"; case SCULPT_TOOL_POSE: return "Pose Brush"; + case SCULPT_TOOL_MULTIPLANE_SCRAPE: + return "Multiplane Scrape Brush"; } return "Sculpting"; @@ -6260,6 +6604,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru SCULPT_TOOL_ELASTIC_DEFORM, SCULPT_TOOL_NUDGE, SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_MULTIPLANE_SCRAPE, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_POSE, SCULPT_TOOL_THUMB) || @@ -6295,6 +6640,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru add_v3_v3(cache->grab_delta, delta); break; case SCULPT_TOOL_CLAY_STRIPS: + case SCULPT_TOOL_MULTIPLANE_SCRAPE: case SCULPT_TOOL_NUDGE: case SCULPT_TOOL_SNAKE_HOOK: if (brush->flag & BRUSH_ANCHORED) { @@ -7759,7 +8105,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) break; case PBVH_FACES: /* Mesh Symmetrize */ - ED_sculpt_undo_geometry_begin(ob); + ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); Mesh *mesh = ob->data; Mesh *mesh_mirror; MirrorModifierData mmd = {0}; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 93e4a777569..0b25ab31ce0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -206,6 +206,9 @@ typedef struct SculptThreadedTaskData { float *pose_factor; float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4]; + float multiplane_scrape_angle; + float multiplane_scrape_planes[2][4]; + float max_distance_squared; float nearest_vertex_search_co[3]; @@ -392,6 +395,9 @@ typedef struct StrokeCache { float *automask; + float stroke_local_mat[4][4]; + float multiplane_scrape_sampled_angle; + rcti previous_r; /* previous redraw rectangle */ rcti current_r; /* current redraw rectangle */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 67bca60e7e1..c55ab81a733 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -247,7 +247,9 @@ typedef struct Brush { int size; /** General purpose flags. */ int flag; + int flag2; int sampling_flag; + /** Pressure influence for mask. */ int mask_pressure; /** Jitter the position of the brush. */ @@ -288,7 +290,8 @@ typedef struct Brush { /** Source for fill tool color gradient application. */ char gradient_fill_mode; - char _pad[5]; + char _pad0; + /** Projection shape (sphere, circle). */ char falloff_shape; float falloff_angle; @@ -307,7 +310,7 @@ typedef struct Brush { char mask_tool; /** Active grease pencil tool. */ char gpencil_tool; - char _pad0[1]; + char _pad1[5]; float autosmooth_factor; @@ -332,6 +335,9 @@ typedef struct Brush { /* pose */ float pose_offset; + /* multiplane scrape */ + float multiplane_scrape_angle; + /* overlay */ int texture_overlay_alpha; int mask_overlay_alpha; @@ -445,6 +451,12 @@ typedef enum eBrushSamplingFlags { BRUSH_PAINT_ANTIALIASING = (1 << 0), } eBrushSamplingFlags; +/* Brush.flag2 */ +typedef enum eBrushFlags2 { + BRUSH_MULTIPLANE_SCRAPE_DYNAMIC = (1 << 0), + BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW = (1 << 1), +} eBrushFlags2; + typedef enum { BRUSH_MASK_PRESSURE_RAMP = (1 << 1), BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2), @@ -488,6 +500,7 @@ typedef enum eBrushSculptTool { SCULPT_TOOL_DRAW_SHARP = 20, SCULPT_TOOL_ELASTIC_DEFORM = 21, SCULPT_TOOL_POSE = 22, + SCULPT_TOOL_MULTIPLANE_SCRAPE = 23, } eBrushSculptTool; /* Brush.uv_sculpt_tool */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 3f269299461..86b1ed92349 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -68,6 +68,7 @@ static const EnumPropertyItem sculpt_stroke_method_items[] = { {0, NULL, 0, NULL, NULL}, }; +/* clang-format off */ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""}, {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""}, @@ -82,6 +83,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""}, {SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""}, {SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""}, + {SCULPT_TOOL_MULTIPLANE_SCRAPE, "MULTIPLANE_SCRAPE", ICON_BRUSH_SCRAPE, "Multiplane Scrape", ""}, {SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""}, {0, "", 0, NULL, NULL}, {SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""}, @@ -96,6 +98,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, {0, NULL, 0, NULL, NULL}, }; +/* clang-format on */ const EnumPropertyItem rna_enum_brush_uv_sculpt_tool_items[] = { {UV_SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", "Grab UVs"}, @@ -1878,6 +1881,12 @@ static void rna_def_brush(BlenderRNA *brna) prop, "Pose Origin Offset", "Offset of the pose origin in relation to the brush radius"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "multiplane_scrape_angle", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "multiplane_scrape_angle"); + RNA_def_property_range(prop, 0.0f, 160.0f); + RNA_def_property_ui_text(prop, "Plane Angle", "Angle between the planes of the crease"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor"); RNA_def_property_float_default(prop, 0); @@ -2026,6 +2035,19 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "use_paint_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "sampling_flag", BRUSH_PAINT_ANTIALIASING); RNA_def_property_ui_text(prop, "Antialasing", "Smooths the edges of the strokes"); + + prop = RNA_def_property(srna, "use_multiplane_scrape_dynamic", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_MULTIPLANE_SCRAPE_DYNAMIC); + RNA_def_property_ui_text(prop, + "Dynamic Mode", + "The angle between the planes changes during the stroke to fit the " + "surface under the cursor"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "show_multiplane_scrape_planes_preview", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW); + RNA_def_property_ui_text( + prop, "Show Cursor Preview", "Preview the scrape planes in the cursor during the stroke"); RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE); |