From c8aedd75d7b549bd2e4073a548efa34360be6614 Mon Sep 17 00:00:00 2001 From: Joseph Eagar Date: Fri, 7 Jan 2022 12:03:40 -0800 Subject: [PATCH] Sculpt-dev: New normal automasking modes Two new automasking modes: "Brush Normal" and "View Normal." Brush Normal compares vertex normals to the initial sculpt normal, while View Normal of course compares with the view vector. Each of these modes have an angular limit and a falloff. There's also an "original normal" option, which needs a better name; "original normal" is actually already taken, but "automasking original normal" is a lot of characters. Not sure what to do here. --- .../startup/bl_ui/properties_paint_common.py | 46 ++++++++- .../startup/bl_ui/space_toolsystem_common.py | 12 ++- .../startup/bl_ui/space_toolsystem_toolbar.py | 97 +++++++++++++++++++ .../startup/bl_ui/space_view3d_toolbar.py | 45 ++++++++- .../blenkernel/intern/brush_channel_define.h | 10 ++ .../blenkernel/intern/brush_engine_presets.c | 20 +++- .../draw/intern/draw_cache_impl_mesh.c | 52 ++++++++-- source/blender/editors/sculpt_paint/sculpt.c | 10 ++ .../editors/sculpt_paint/sculpt_automasking.c | 83 ++++++++++++++++ .../editors/sculpt_paint/sculpt_intern.h | 8 +- source/blender/makesdna/DNA_brush_enums.h | 4 +- .../blender/makesdna/DNA_sculpt_brush_types.h | 3 +- .../makesrna/intern/rna_brush_engine.c | 3 + 13 files changed, 374 insertions(+), 19 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 9364aafb4ed..c6bad232953 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -2105,11 +2105,51 @@ def brush_settings_advanced(layout, context, brush, popover=False): context, brush, "automasking_boundary_edges_propagation_steps") - UnifiedPaintPanel.channel_unified(layout.column(), + + flags = UnifiedPaintPanel.get_channel_value(context, brush, "automasking") + + if "CONCAVITY" in flags: + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "concave_mask_factor", + slider=True) + + enable_orig_normal = False + + if "BRUSH_NORMAL" in flags: + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "normal_mask_limit", + slider=True) + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "normal_mask_falloff", + slider=True) + enable_orig_normal = True + + if "VIEW_NORMAL" in flags: + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "view_normal_mask_limit", + slider=True) + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "view_normal_mask_falloff", + slider=True) + enable_orig_normal = True + + sub = layout.row() + sub.enabled = enable_orig_normdal + + UnifiedPaintPanel.channel_unified(sub, context, brush, - "concave_mask_factor", - slider=True) + "automasking_use_original_normal") """ col = layout.column(heading="Auto-Masking", align=True) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index c4dabb5b5bc..f63beee3f03 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -120,6 +120,8 @@ ToolDef = namedtuple( "draw_cursor", # Various options, see: `bpy.types.WorkSpaceTool.setup` options argument. "options", + #get_enabled(ctx, idname) whether tool should be grayed out + "get_enabled" ) ) del namedtuple @@ -143,6 +145,7 @@ def from_dict(kw_args): "operator": None, "draw_settings": None, "draw_cursor": None, + "get_enabled": None } kw.update(kw_args) @@ -725,9 +728,14 @@ class ToolSelectPanelHelper: icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) sub = ui_gen.send(False) + sub2 = sub + + if item.get_enabled is not None: + sub2 = sub.row(align=False) + sub2.enabled = item.get_enabled(context, item.idname) if use_menu: - sub.operator_menu_hold( + sub2.operator_menu_hold( "wm.tool_set_by_id", text=item.label if show_text else "", depress=is_active, @@ -735,7 +743,7 @@ class ToolSelectPanelHelper: icon_value=icon_value, ).name = item.idname else: - sub.operator( + sub2.operator( "wm.tool_set_by_id", text=item.label if show_text else "", depress=is_active, diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index da185b53544..6edd0cb5a6d 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1211,6 +1211,83 @@ class _defs_particle: attr="tool",) +def generate_from_enum_ex(_context, *, + idname_prefix, + icon_prefix, + type, + attr, + cursor='DEFAULT', + tooldef_keywords={}, + exclude_filter={}, + combine_map={}): + """ + combine_map combines items, takes the form of a dict: + + combine_map = { + "PARENT KEY" : ( + "CHILD KEY" + ) + } + + """ + + combinekeys = {} + parentmap = {} + + for k, v in combine_map.items(): + combinekeys[k] = [] + + for child in v: + parentmap[child] = k + + tool_defs = [] + + #build combine key owners first + for enum in type.bl_rna.properties[attr].enum_items_static: + name = enum.name + idname = enum.identifier + if idname in exclude_filter: + continue + + if idname in combinekeys: + combinekeys[idname].append(ToolDef.from_dict(dict(idname=idname_prefix + name, + label=name, + icon=icon_prefix + idname.lower(), + cursor=cursor, + data_block=idname, + **tooldef_keywords,))) + + for enum in type.bl_rna.properties[attr].enum_items_static: + name = enum.name + idname = enum.identifier + if idname in exclude_filter: + continue + + if idname in combinekeys: + tool_defs.append(combinekeys[idname]) + elif idname in parentmap: + parentkey = parentmap[idname] + + combinekeys[parentkey].append(ToolDef.from_dict(dict(idname=idname_prefix + name, + label=name, + icon=icon_prefix + idname.lower(), + cursor=cursor, + data_block=idname, + **tooldef_keywords,))) + else: + tool_defs.append(ToolDef.from_dict(dict(idname=idname_prefix + name, + label=name, + icon=icon_prefix + idname.lower(), + cursor=cursor, + data_block=idname, + **tooldef_keywords,))) + + # finalize combined keys + for k, v in combinekeys.items(): + tool_defs[tool_defs.index(v)] = tuple(v) + + return tuple(tool_defs) + class _defs_sculpt: @staticmethod @@ -1229,12 +1306,32 @@ class _defs_sculpt: "SMOOTH" : ("ENHANCE_DETAILS",) } + def get_enabled(context, idname): + if "multires" in idname.lower() or idname.lower() == "builtin_brush.displacement heal": + print("IDNAME", idname) + have_multires = False; + ob = context.object + + for mod in ob.modifiers: + ok = mod.type == "MULTIRES" + ok = ok and mod.sculpt_levels > 0 + ok = ok and mod.show_viewport + + if ok: + have_multires = True + break + + return have_multires + + return True + return generate_from_enum_ex(context, idname_prefix="builtin_brush.", icon_prefix="brush.sculpt.", type=bpy.types.Brush, attr="sculpt_tool", exclude_filter=exclude_filter, + tooldef_keywords={"get_enabled" : get_enabled}, combine_map=combine_map) @ToolDef.from_fn diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 2fbad9ba285..c5f0c055b9a 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1361,11 +1361,50 @@ class VIEW3D_PT_sculpt_automasking(Panel, View3DPaintPanel): brush, "automasking_boundary_edges_propagation_steps", ui_editing=False) - UnifiedPaintPanel.channel_unified(layout.column(), + + if "CONCAVITY" in sculpt.channels["automasking"].value: + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "concave_mask_factor", + ui_editing=False, slider=True, show_mappings=True) + + enable_orig_normal = False + + if "BRUSH_NORMAL" in sculpt.channels["automasking"].value: + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "normal_mask_limit", + ui_editing=False, slider=True, show_mappings=True) + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "normal_mask_falloff", + ui_editing=False, slider=True, show_mappings=True) + enable_orig_normal = True + + if "VIEW_NORMAL" in sculpt.channels["automasking"].value: + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "view_normal_mask_limit", + ui_editing=False, slider=True, show_mappings=True) + UnifiedPaintPanel.channel_unified(layout.column(), + context, + brush, + "view_normal_mask_falloff", + ui_editing=False, slider=True, show_mappings=True) + enable_orig_normal = True + + sub = layout.row() + sub.enabled = enable_orig_normal + + UnifiedPaintPanel.channel_unified(sub, context, brush, - "concave_mask_factor", - ui_editing=False, slider=True, show_mappings=True) + "automasking_use_original_normal", + ui_editing=False, show_mappings=False) class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel): diff --git a/source/blender/blenkernel/intern/brush_channel_define.h b/source/blender/blenkernel/intern/brush_channel_define.h index 9a56991e1c8..6c9021d1ef3 100644 --- a/source/blender/blenkernel/intern/brush_channel_define.h +++ b/source/blender/blenkernel/intern/brush_channel_define.h @@ -270,9 +270,19 @@ MAKE_ENUM(blend,"Blending Mode","Brush blending mode",IMB_BLEND_MIX,{\ {BRUSH_AUTOMASKING_INVERT_CONCAVITY, "INVERT_CONCAVITY", "NONE", "Invert Cavity", "Invert Cavity Map"}, {BRUSH_AUTOMASKING_FACE_SETS, "FACE_SETS", "NONE", "Face Sets", ""}, {BRUSH_AUTOMASKING_TOPOLOGY, "TOPOLOGY", "NONE", "Topology", ""}, + {BRUSH_AUTOMASKING_BRUSH_NORMAL, "BRUSH_NORMAL", "NONE", "Brush Normal", "Mask using normal at center of brush"}, + {BRUSH_AUTOMASKING_VIEW_NORMAL, "VIEW_NORMAL", "NONE", "View Normal", "Mask using view normal"}, {-1}, }) + MAKE_FLOAT(normal_mask_limit, "Brush Normal Limit", "", M_PI*0.5f, 0.0001f, M_PI) + MAKE_FLOAT(normal_mask_falloff, "Brush Normal Falloff", "", 0.1, 0.0, 1.0) + + MAKE_FLOAT(view_normal_mask_limit, "View Limit", "", M_PI*0.5f, 0.0001f, M_PI) + MAKE_FLOAT(view_normal_mask_falloff, "View Falloff", "", 0.1, 0.0, 1.0) + + MAKE_BOOL_EX(automasking_use_original_normal, "Original Normal", "Use original normal for automasking", true, BRUSH_CHANNEL_NO_MAPPINGS) + MAKE_BOOL_EX(dyntopo_disabled,"Disable Dyntopo","",false,BRUSH_CHANNEL_NO_MAPPINGS) MAKE_FLAGS_EX(dyntopo_mode,"Dyntopo Operators","",DYNTOPO_COLLAPSE | DYNTOPO_CLEANUP | DYNTOPO_SUBDIVIDE,BRUSH_CHANNEL_INHERIT,{\ {DYNTOPO_COLLAPSE, "COLLAPSE", "NONE", "Collapse", ""}, diff --git a/source/blender/blenkernel/intern/brush_engine_presets.c b/source/blender/blenkernel/intern/brush_engine_presets.c index 5dd202194f0..0c463470edc 100644 --- a/source/blender/blenkernel/intern/brush_engine_presets.c +++ b/source/blender/blenkernel/intern/brush_engine_presets.c @@ -264,7 +264,9 @@ static bool check_builtin_init() //} SUBTYPE_SET(smooth_stroke_radius, BRUSH_CHANNEL_PIXEL); - + SUBTYPE_SET(normal_mask_limit, BRUSH_CHANNEL_ANGLE); + SUBTYPE_SET(view_normal_mask_limit, BRUSH_CHANNEL_ANGLE); + SUBTYPE_SET(jitter_absolute, BRUSH_CHANNEL_PIXEL); SUBTYPE_SET(radius, BRUSH_CHANNEL_PIXEL); @@ -306,6 +308,11 @@ static bool check_builtin_init() SETCAT(concave_mask_factor, "Automasking"); SETCAT(automasking, "Automasking"); SETCAT(automasking_boundary_edges_propagation_steps, "Automasking"); + SETCAT(normal_mask_limit, "Automasking"); + SETCAT(view_normal_mask_limit, "Automasking"); + SETCAT(normal_mask_falloff, "Automasking"); + SETCAT(view_normal_mask_falloff, "Automasking"); + SETCAT(automasking_use_original_normal, "Automasking"); def = GETDEF(concave_mask_factor); def->mappings.pressure.inv = true; @@ -1144,6 +1151,11 @@ void BKE_brush_builtin_patch(Brush *brush, int tool) ADDCH(automasking); ADDCH(automasking_boundary_edges_propagation_steps); ADDCH(concave_mask_factor); + ADDCH(normal_mask_limit); + ADDCH(automasking_use_original_normal); + ADDCH(view_normal_mask_limit); + ADDCH(normal_mask_falloff); + ADDCH(view_normal_mask_falloff); ADDCH(dyntopo_disabled); ADDCH(dyntopo_disable_smooth); @@ -2045,6 +2057,12 @@ void BKE_brush_check_toolsettings(Sculpt *sd) ADDCH(automasking_boundary_edges_propagation_steps); ADDCH(concave_mask_factor); ADDCH(automasking); + ADDCH(normal_mask_limit); + ADDCH(automasking_use_original_normal); + ADDCH(view_normal_mask_limit); + ADDCH(normal_mask_falloff); + ADDCH(view_normal_mask_falloff); + ADDCH(topology_rake_mode); ADDCH(plane_offset); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 6981c771173..8bde4e081d6 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -574,12 +574,34 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, if (layer == -1) { layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name); - type = CD_PROP_COLOR; + if (layer != -1) { + type = CD_PROP_COLOR; + domain = ATTR_DOMAIN_POINT; + } + } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_ldata, CD_PROP_COLOR, name); + if (layer != -1) { + type = CD_PROP_COLOR; + domain = ATTR_DOMAIN_CORNER; + } + } + + if (layer == -1) { + layer = CustomData_get_named_layer(cd_vdata, CD_MLOOPCOL, name); + if (layer != -1) { + type = CD_MLOOPCOL; + domain = ATTR_DOMAIN_POINT; + } } if (layer == -1) { layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name); - type = CD_MCOL; + if (layer != -1) { + type = CD_MLOOPCOL; + domain = ATTR_DOMAIN_CORNER; + } } #if 0 /* Tangents are always from UV's - this will never happen. */ @@ -656,7 +678,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, break; } - case CD_MCOL: + /* note that attr->type will always be CD_PROP_COLOR event for + CD_MLOOPCOL layers, see node_shader_gpu_vertex_color in + node_shader_vertex_color.cc + */ case CD_MLOOPCOL: case CD_PROP_COLOR: { const AttributeRef *render = &me->attr_color_render; @@ -667,15 +692,28 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me, if (layer == -1 && name[0] != '\0') { layer = CustomData_get_named_layer_index(cd_ldata, type, name); + domain = layer != -1 ? ATTR_DOMAIN_CORNER : domain; - if (layer != -1) { - domain = ATTR_DOMAIN_CORNER; - } - else { + if (layer == -1) { layer = CustomData_get_named_layer_index(cd_vdata, type, name); + domain = layer != -1 ? ATTR_DOMAIN_POINT : domain; + } + + if (layer == -1) { + layer = CustomData_get_named_layer_index(cd_ldata, CD_MLOOPCOL, name); + + if (layer != -1) { + domain = ATTR_DOMAIN_CORNER; + type = CD_MLOOPCOL; + } + } + + if (layer == -1) { + layer = CustomData_get_named_layer_index(cd_vdata, CD_MLOOPCOL, name); if (layer != -1) { domain = ATTR_DOMAIN_POINT; + type = CD_MLOOPCOL; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index a972c4ff3c6..bba49f3f95a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -56,6 +56,7 @@ #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_view3d_types.h" #include "BKE_attribute.h" #include "BKE_brush.h" @@ -2944,6 +2945,8 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(SCULPT_get_tool(ss, brush)) && (ss->cache->normal_weight > 0.0f)) || + SCULPT_automasking_needs_normal(ss, brush) || + ELEM(SCULPT_get_tool(ss, brush), SCULPT_TOOL_BLOB, SCULPT_TOOL_CREASE, @@ -8436,6 +8439,13 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f Brush *brush = BKE_paint_brush(&sd->paint); Object *ob = CTX_data_active_object(C); + if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d) { + v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR; + } + } + if (brush && brush->channels) { int tool = RNA_enum_get(op->ptr, "tool_override"); BrushChannelSet *channels = brush->channels; diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c index 693a7c81bb1..39dd0b5cb3a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c @@ -142,6 +142,50 @@ static bool SCULPT_automasking_needs_factors_cache(SculptSession *ss, return false; } +bool SCULPT_automasking_needs_normal(const SculptSession *ss, const Brush *brush) +{ + int flags = SCULPT_get_int(ss, automasking, NULL, brush); + + return flags & (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL); +} + +static float sculpt_automasking_normal_calc(AutomaskingCache *automasking, + SculptSession *ss, + SculptVertRef vert, + float normal[3], + float limit, + float falloff) +{ + float normal_v[3]; + + if (automasking->settings.original_normal) { + SCULPT_vertex_check_origdata(ss, vert); + copy_v3_v3(normal_v, SCULPT_vertex_origno_get(ss, vert)); + } + else { + SCULPT_vertex_normal_get(ss, vert, normal_v); + } + + float angle = saacos(dot_v3v3(normal, normal_v)) / M_PI; + falloff *= 0.5; + + /* note that limit is pre-divided by M_PI */ + + if (angle > limit - falloff && angle < limit + falloff) { + float t = 1.0f - (angle - (limit - falloff)) / (2.0 * falloff); + + /* smoothstep */ + t = t * t * (3.0 - 2.0 * t); + + return t; + } + else if (angle > limit) { + return 0.0f; + } + + return 1.0f; +} + float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, SculptVertRef vert) @@ -195,6 +239,32 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, } } + if (ss->cache && (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) { + float normal[3]; + + copy_v3_v3(normal, ss->cache->initial_normal); + + mask *= sculpt_automasking_normal_calc(automasking, + ss, + vert, + normal, + automasking->settings.normal_limit, + automasking->settings.normal_falloff); + } + + if (ss->cache && (automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) { + float normal[3]; + + copy_v3_v3(normal, ss->cache->view_normal); + + mask *= sculpt_automasking_normal_calc(automasking, + ss, + vert, + normal, + automasking->settings.view_normal_limit, + automasking->settings.view_normal_falloff); + } + return mask; } @@ -394,6 +464,19 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss); automasking->settings.concave_factor = SCULPT_get_float(ss, concave_mask_factor, sd, brush); + + /* pre-divide by M_PI */ + automasking->settings.normal_limit = SCULPT_get_float(ss, normal_mask_limit, sd, brush) / M_PI; + automasking->settings.normal_falloff = SCULPT_get_float(ss, normal_mask_falloff, sd, brush); + + automasking->settings.view_normal_limit = SCULPT_get_float( + ss, view_normal_mask_limit, sd, brush) / + M_PI; + automasking->settings.view_normal_falloff = SCULPT_get_float( + ss, view_normal_mask_falloff, sd, brush); + + automasking->settings.original_normal = SCULPT_get_bool( + ss, automasking_use_original_normal, sd, brush); } void SCULPT_automasking_step_update(AutomaskingCache *automasking, diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 0d41e5fea7c..8633ac43777 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -577,8 +577,9 @@ void SCULPT_pbvh_clear(Object *ob); float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, SculptSession *ss, SculptVertRef vert); +bool SCULPT_automasking_needs_normal(const SculptSession *ss, const Brush *brush); -/* Returns the automasking cache depending on the active tool. Used for code that can run both for + /* Returns the automasking cache depending on the active tool. Used for code that can run both for * brushes and filter. */ struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss); @@ -1297,6 +1298,9 @@ typedef struct AutomaskingSettings { int initial_face_set; int current_face_set; // used by faceset draw tool float concave_factor; + float normal_limit, normal_falloff; + float view_normal_limit, view_normal_falloff; + bool original_normal; } AutomaskingSettings; typedef struct AutomaskingCache { @@ -1995,6 +1999,8 @@ void SCULPT_ensure_persistent_layers(SculptSession *ss, struct Object *ob); // these tools don't support dynamic pbvh splitting during the stroke #define DYNTOPO_HAS_DYNAMIC_SPLIT(tool) true +#define SCULPT_TOOL_NEEDS_COLOR(tool) ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR) + /*get current symmetry pass index inclusive of both mirror and radial symmetry*/ int SCULPT_get_symmetry_pass(const SculptSession *ss); diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index 37722f72a3f..fec5758cb05 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -344,7 +344,9 @@ typedef enum eAutomasking_flag { BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2), BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3), BRUSH_AUTOMASKING_CONCAVITY = (1 << 4), - BRUSH_AUTOMASKING_INVERT_CONCAVITY = (1 << 5) + BRUSH_AUTOMASKING_INVERT_CONCAVITY = (1 << 5), + BRUSH_AUTOMASKING_BRUSH_NORMAL = (1<<6), + BRUSH_AUTOMASKING_VIEW_NORMAL = (1 << 7), } eAutomasking_flag; typedef enum ePaintBrush_flag { diff --git a/source/blender/makesdna/DNA_sculpt_brush_types.h b/source/blender/makesdna/DNA_sculpt_brush_types.h index 30d0d25c9ea..98f5a951484 100644 --- a/source/blender/makesdna/DNA_sculpt_brush_types.h +++ b/source/blender/makesdna/DNA_sculpt_brush_types.h @@ -156,6 +156,7 @@ enum { BRUSH_CHANNEL_COLOR, BRUSH_CHANNEL_FACTOR, BRUSH_CHANNEL_PERCENT, - BRUSH_CHANNEL_PIXEL + BRUSH_CHANNEL_PIXEL, + BRUSH_CHANNEL_ANGLE }; /* clang-format on */ diff --git a/source/blender/makesrna/intern/rna_brush_engine.c b/source/blender/makesrna/intern/rna_brush_engine.c index e637d77cd16..b6004d3e376 100644 --- a/source/blender/makesrna/intern/rna_brush_engine.c +++ b/source/blender/makesrna/intern/rna_brush_engine.c @@ -125,6 +125,9 @@ struct StructRNA *rna_BrushChannel_refine(PointerRNA *ptr) case BRUSH_CHANNEL_PIXEL: subtype = PROP_PIXEL; break; + case BRUSH_CHANNEL_ANGLE: + subtype = PROP_ANGLE; + break; default: subtype = PROP_NONE; break;