Sculpt: More brush engine stuff, got automasking to work with it

* Sculpt now has an API to get brush channel settings.
  If a sculpt cache exists it will use the channels there
  (ss->cache->channels_final), otherwise it pulls them
  from a brush and Sculpt toolsettings. Exampes:

  float f = SCULPT_get_float(ss, "setting", sd, brush);
  itn i = SCULPT_get_int(ss, "setting", sd, brush);

* Improved the UI a bit
This commit is contained in:
Joseph Eagar 2021-09-20 14:10:35 -07:00
parent 645aee0835
commit 76beed9068
10 changed files with 262 additions and 86 deletions

View File

@ -108,7 +108,8 @@ class UnifiedPaintPanel:
return None
@staticmethod
def channel_unified(layout, context, brush, prop_name, icon='NONE', pressure=True, text=None, slider=False, header=False, expand=None):
def channel_unified(layout, context, brush, prop_name, icon='NONE', pressure=True, text=None,
slider=False, header=False, expand=None, toolsettings_only=False):
""" Generalized way of adding brush options to the UI,
along with their pen pressure setting and global toggle, if they exist. """
ch = brush.channels.channels[prop_name]
@ -119,6 +120,9 @@ class UnifiedPaintPanel:
#if ch.ui_expanded:
# layout = layout.box().column() #.column() is a bit more compact
if ch.type == "BITMASK":
layout = layout.box()
row = layout.row(align=True)
typeprop = "float_value"
@ -139,18 +143,35 @@ class UnifiedPaintPanel:
text = text.strip()
path = ""
is_toolset = False
if ch.inherit:
if ch.inherit or toolsettings_only:
sd = context.tool_settings.sculpt
#ensure channel exists in tool settings channel set
sd.channels.ensure(ch)
finalch = sd.channels.channels[prop_name]
is_toolset = True
path = "tool_settings.sculpt.channels.channels[\"%s\"]" % ch.idname
else:
path = "tool_settings.sculpt.brush.channels.channels[\"%s\"]" % ch.idname
if expand is not None:
if ch.type == "BITMASK":
row.label(text=text)
if header:
row.prop_menu_enum(finalch, typeprop)
else:
col = layout.column()
col.emboss = "NONE"
for item in finalch.enum_items:
if item.identifier in finalch.flags_value:
itemicon = "CHECKBOX_HLT"
else:
itemicon = "CHECKBOX_DEHLT"
col.prop_enum(finalch, typeprop, item.identifier, icon=itemicon)
elif expand is not None:
row.prop(finalch, typeprop, icon=icon, text=text, slider=slider, expand=expand)
else:
row.prop(finalch, typeprop, icon=icon, text=text, slider=slider)
@ -166,7 +187,15 @@ class UnifiedPaintPanel:
# # NOTE: We don't draw UnifiedPaintSettings in the header to reduce clutter. D5928#136281
# row.prop(ups, unified_name, text="", icon='BRUSHES_ALL')
if not header and ch.type != "BOOL":
row.prop(ch, "inherit", text="", icon='BRUSHES_ALL')
if ch.type == "BITMASK" and not toolsettings_only and ch == finalch:
row.prop(ch, "inherit_if_unset", text="Combine With Defaults")
if not toolsettings_only:
row.prop(ch, "inherit", text="", icon='BRUSHES_ALL')
if ch.type == "BITMASK":
return
row.prop(ch, "ui_expanded", text="", icon="TRIA_DOWN" if ch.ui_expanded else "TRIA_RIGHT")
if ch.ui_expanded:
@ -1163,6 +1192,18 @@ def brush_settings_advanced(layout, context, brush, popover=False):
use_accumulate = capabilities.has_accumulate
use_frontface = True
UnifiedPaintPanel.channel_unified(
layout.column(),
context,
brush,
"automasking", expand=False)
UnifiedPaintPanel.channel_unified(
layout.column(),
context,
brush,
"automasking_boundary_edges_propagation_steps")
"""
col = layout.column(heading="Auto-Masking", align=True)
# topology automasking
@ -1183,6 +1224,7 @@ def brush_settings_advanced(layout, context, brush, popover=False):
col.prop(brush, "use_automasking_boundary_edges", text="Mesh Boundary")
col.prop(brush, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
col.prop(brush, "automasking_boundary_edges_propagation_steps")
"""
layout.separator()

View File

@ -951,11 +951,26 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
col.separator()
brush = sculpt.brush
UnifiedPaintPanel.channel_unified(
layout.column(),
context,
brush,
"automasking", toolsettings_only=True)
UnifiedPaintPanel.channel_unified(
layout.column(),
context,
brush,
"automasking_boundary_edges_propagation_steps",
toolsettings_only=True)
"""
col = layout.column(heading="Auto-Masking", align=True)
col.prop(sculpt, "use_automasking_topology", text="Topology")
col.prop(sculpt, "use_automasking_face_sets", text="Face Sets")
col.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary")
col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary")
"""
col.separator()
col.operator("sculpt.set_limit_surface")

View File

@ -150,16 +150,18 @@ void BKE_brush_resolve_channels(struct Brush *brush, struct Sculpt *sd);
void BKE_brush_channelset_set_final_int(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
const char *idname,
int value);
int BKE_brush_channelset_get_final_int(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
const char *idname,
BrushMappingData *mapdata);
int BKE_brush_channelset_get_int(BrushChannelSet *chset, char *idname, BrushMappingData *mapdata);
bool BKE_brush_channelset_set_int(BrushChannelSet *chset, char *idname, int val);
int BKE_brush_channelset_get_int(BrushChannelSet *chset,
const char *idname,
BrushMappingData *mapdata);
bool BKE_brush_channelset_set_int(BrushChannelSet *chset, const char *idname, int val);
void BKE_brush_channel_set_int(BrushChannel *ch, int val);
float BKE_brush_channel_get_int(BrushChannel *ch, BrushMappingData *mapdata);
@ -172,18 +174,18 @@ void BKE_brush_channel_set_float(BrushChannel *ch, float val);
/* mapdata may be NULL */
float BKE_brush_channelset_get_float(BrushChannelSet *chset,
char *idname,
const char *idname,
BrushMappingData *mapdata);
bool BKE_brush_channelset_set_float(BrushChannelSet *chset, char *idname, float val);
bool BKE_brush_channelset_set_float(BrushChannelSet *chset, const char *idname, float val);
float BKE_brush_channelset_get_final_float(BrushChannelSet *child,
BrushChannelSet *parent,
char *idname,
const char *idname,
BrushMappingData *mapdata);
void BKE_brush_channelset_set_final_float(BrushChannelSet *child,
BrushChannelSet *parent,
char *idname,
const char *idname,
float value);
void BKE_brush_init_toolsettings(struct Sculpt *sd);

View File

@ -641,7 +641,9 @@ void BKE_brush_resolve_channels(Brush *brush, Sculpt *sd)
BKE_brush_channelset_merge(brush->channels_final, brush->channels, sd->channels);
}
int BKE_brush_channelset_get_int(BrushChannelSet *chset, char *idname, BrushMappingData *mapdata)
int BKE_brush_channelset_get_int(BrushChannelSet *chset,
const char *idname,
BrushMappingData *mapdata)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
@ -709,7 +711,7 @@ void BKE_brush_channel_set_int(BrushChannel *ch, int val)
int BKE_brush_channelset_get_final_int(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
const char *idname,
BrushMappingData *mapdata)
{
BrushChannel *ch = BKE_brush_channelset_lookup(brushset, idname);
@ -733,7 +735,7 @@ int BKE_brush_channelset_get_final_int(BrushChannelSet *brushset,
void BKE_brush_channelset_set_final_int(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
const char *idname,
int value)
{
BrushChannel *ch = BKE_brush_channelset_lookup(brushset, idname);
@ -757,7 +759,7 @@ void BKE_brush_channelset_set_final_int(BrushChannelSet *brushset,
float BKE_brush_channelset_get_final_float(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
const char *idname,
BrushMappingData *mapdata)
{
BrushChannel *ch = BKE_brush_channelset_lookup(brushset, idname);
@ -781,7 +783,7 @@ float BKE_brush_channelset_get_final_float(BrushChannelSet *brushset,
void BKE_brush_channelset_set_final_float(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
const char *idname,
float value)
{
BrushChannel *ch = BKE_brush_channelset_lookup(brushset, idname);
@ -804,7 +806,7 @@ void BKE_brush_channelset_set_final_float(BrushChannelSet *brushset,
}
float BKE_brush_channelset_get_float(BrushChannelSet *chset,
char *idname,
const char *idname,
BrushMappingData *mapdata)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
@ -875,7 +877,7 @@ void BKE_brush_channel_set_float(BrushChannel *ch, float val)
ch->fvalue = val;
}
bool BKE_brush_channelset_set_float(BrushChannelSet *chset, char *idname, float val)
bool BKE_brush_channelset_set_float(BrushChannelSet *chset, const char *idname, float val)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
@ -889,7 +891,7 @@ bool BKE_brush_channelset_set_float(BrushChannelSet *chset, char *idname, float
return true;
}
ATTR_NO_OPT bool BKE_brush_channelset_set_int(BrushChannelSet *chset, char *idname, int val)
ATTR_NO_OPT bool BKE_brush_channelset_set_int(BrushChannelSet *chset, const char *idname, int val)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);

View File

@ -320,7 +320,7 @@ BrushChannelType brush_builtin_channels[] = {
{
.name = "Automasking",
.idname = "automasking",
.flag = BRUSH_CHANNEL_INHERIT_IF_UNSET | BRUSH_CHANNEL_INHERIT,
.flag = BRUSH_CHANNEL_INHERIT_IF_UNSET,
.type = BRUSH_CHANNEL_BITMASK,
.enumdef = {
{BRUSH_AUTOMASKING_BOUNDARY_EDGES, "BOUNDARY_EDGE", ICON_NONE, "Boundary Edges", ""},
@ -444,7 +444,12 @@ BrushChannelType brush_builtin_channels[] = {
MAKE_FLOAT_EX("dyntopo_detail_size", "Detail Size", "Detail Size", 8.0f, 0.1f, 100.0f, 0.001f, 500.0f),
MAKE_FLOAT_EX("dyntopo_constant_detail", "Constaint Detail", "", 3.0f, 0.001f, 1000.0f, 0.0001, FLT_MAX),
MAKE_FLOAT_EX("dyntopo_spacing", "Spacing", "Dyntopo Spacing", 35.0f, 0.01f, 300.0f, 0.001f, 50000.0f),
MAKE_FLOAT_EX("dyntopo_radius_scale", "Radius Scale", "Scale brush radius for dyntopo radius", 1.0f, 0.001f, 3.0f, 0.0001f, 100.0f)
MAKE_FLOAT_EX("dyntopo_radius_scale", "Radius Scale", "Scale brush radius for dyntopo radius", 1.0f, 0.001f, 3.0f, 0.0001f, 100.0f),
MAKE_FLOAT("concave_mask_factor", "Cavity Factor", "", 0.35f, 0.0f, 1.0f),
MAKE_INT_EX("automasking_boundary_edges_propagation_steps", "Propagation Steps",
"Distance where boundary edge automasking is going to protect vertices "
"from the fully masked edge", 1, 1, 20, 1, 3),
};
/* clang-format on */
@ -536,6 +541,8 @@ static BrushSettingsMap brush_settings_map[] = {
DEF(wet_persistence, wet_persistence, FLOAT, FLOAT)
DEF(density, density, FLOAT, FLOAT)
DEF(tip_scale_x, tip_scale_x, FLOAT, FLOAT)
DEF(concave_mask_factor, concave_mask_factor, FLOAT, FLOAT)
DEF(automasking_boundary_edges_propagation_steps, automasking_boundary_edges_propagation_steps, INT, INT)
};
static const int brush_settings_map_len = ARRAY_SIZE(brush_settings_map);
@ -881,7 +888,8 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH("normal_radius_factor");
ADDCH("automasking");
ADDCH("automasking_boundary_edges_propagation_steps");
ADDCH("concave_mask_factor");
ADDCH("dyntopo_disabled");
ADDCH("dyntopo_mode")->flag |= BRUSH_CHANNEL_INHERIT;
ADDCH("dyntopo_detail_range")->flag |= BRUSH_CHANNEL_INHERIT;
@ -1026,6 +1034,8 @@ void BKE_brush_check_toolsettings(Sculpt *sd)
ADDCH("radius");
ADDCH("strength");
ADDCH("automasking_boundary_edges_propagation_steps");
ADDCH("concave_mask_factor");
ADDCH("automasking");
ADDCH("topology_rake_mode");

View File

@ -134,6 +134,40 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
BrushActionFunc action,
UnifiedPaintSettings *ups);
/* Sculpt API to get brush channel data
If ss->cache exists then ss->cache->channels_final
will be used, otherwise brush and tool settings channels
will be used (taking inheritence into account).
*/
ATTR_NO_OPT float SCULPT_get_float(const SculptSession *ss,
const char *idname,
const Sculpt *sd,
const Brush *br)
{
if (ss->cache && ss->cache->channels_final) {
return BKE_brush_channelset_get_float(
ss->cache->channels_final, idname, &ss->cache->input_mapping);
}
else {
return BKE_brush_channelset_get_final_float(br->channels, sd->channels, idname, NULL);
}
}
ATTR_NO_OPT int SCULPT_get_int(const SculptSession *ss,
const char *idname,
const Sculpt *sd,
const Brush *br)
{
if (ss->cache && ss->cache->channels_final) {
return BKE_brush_channelset_get_int(
ss->cache->channels_final, idname, &ss->cache->input_mapping);
}
else {
return BKE_brush_channelset_get_final_int(br->channels, sd->channels, idname, NULL);
}
}
/* Sculpt PBVH abstraction API
*
* This is read-only, for writing use PBVH vertex iterators. There vd.index matches
@ -8835,7 +8869,7 @@ ATTR_NO_OPT static void SCULPT_run_command_list(
BKE_brush_commandlist_start(list, brush, ss->cache->channels_final);
// this does a more high-level check then SCULPT_TOOL_HAS_DYNTOPO;
bool has_dyntopo = SCULPT_stroke_is_dynamic_topology(ss, brush);
bool has_dyntopo = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
bool all_nodes_undo = false;
bool cloth_nodes_undo = false;
@ -9239,7 +9273,9 @@ ATTR_NO_OPT static void SCULPT_run_command_list(
SCULPT_uv_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_TOPOLOGY_RAKE:
bmesh_topology_rake(sd, ob, nodes, totnode, brush2->alpha);
if (ss->bm) {
bmesh_topology_rake(sd, ob, nodes, totnode, brush2->alpha);
}
break;
case SCULPT_TOOL_DYNTOPO:
if (has_dyntopo) {

View File

@ -73,12 +73,15 @@ AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
return NULL;
}
bool SCULPT_is_automasking_mode_enabled(Sculpt *sd, const Brush *br, const eAutomasking_flag mode)
bool SCULPT_is_automasking_mode_enabled(const SculptSession *ss,
const Sculpt *sd,
const Brush *br,
const eAutomasking_flag mode)
{
if (br) {
return br->automasking_flags & mode || sd->automasking_flags & mode;
}
return sd->automasking_flags & mode;
int flag = BKE_brush_channelset_get_int(
ss->cache->channels_final, "automasking", &ss->cache->input_mapping);
return flag & mode;
}
bool SCULPT_is_automasking_enabled(Sculpt *sd, const SculptSession *ss, const Brush *br)
@ -88,34 +91,20 @@ bool SCULPT_is_automasking_enabled(Sculpt *sd, const SculptSession *ss, const Br
return false;
}*/
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_TOPOLOGY)) {
return true;
}
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_FACE_SETS)) {
return true;
}
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
return true;
}
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
return true;
}
if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_CONCAVITY)) {
if (br && br->concave_mask_factor == 0.0f) {
return false;
}
return true;
int flag = SCULPT_get_int(ss, "automasking", sd, br);
if (flag == BRUSH_AUTOMASKING_CONCAVITY) {
return SCULPT_get_float(ss, "concave_mask_factor", sd, br) > 0.0f;
}
return false;
return flag != 0;
}
static int sculpt_automasking_mode_effective_bits(Sculpt *sculpt, const Brush *brush)
static int sculpt_automasking_mode_effective_bits(SculptSession *ss,
Sculpt *sculpt,
const Brush *brush)
{
if (brush) {
return sculpt->automasking_flags | brush->automasking_flags;
}
return sculpt->automasking_flags;
return SCULPT_get_int(ss, "automasking", sculpt, brush);
}
static float sculpt_concavity_factor(AutomaskingCache *automasking, float fac)
@ -130,18 +119,27 @@ static float sculpt_concavity_factor(AutomaskingCache *automasking, float fac)
return fac;
}
static bool SCULPT_automasking_needs_factors_cache(Sculpt *sd, const Brush *brush)
static int automasking_get_propegation(SculptSession *ss)
{
return BKE_brush_channelset_get_int(ss->cache->channels_final,
"automasking_boundary_edges_propagation_steps",
&ss->cache->input_mapping);
}
static bool SCULPT_automasking_needs_factors_cache(SculptSession *ss,
Sculpt *sd,
const Brush *brush)
{
const int automasking_flags = sculpt_automasking_mode_effective_bits(sd, brush);
const int automasking_flags = sculpt_automasking_mode_effective_bits(ss, sd, brush);
if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
return true;
}
if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
return brush && brush->automasking_boundary_edges_propagation_steps != 1;
return brush && automasking_get_propegation(ss) != 1;
}
if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) {
return brush && brush->automasking_boundary_edges_propagation_steps != 1;
return brush && automasking_get_propegation(ss) != 1;
}
return false;
}
@ -157,7 +155,10 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
return mask;
}
do_concave = ss->cache && ss->cache->brush && ss->cache->brush->concave_mask_factor > 0.0f &&
float concave_factor = BKE_brush_channelset_get_float(
ss->cache->channels_final, "concave_mask_factor", &ss->cache->input_mapping);
do_concave = ss->cache && concave_factor > 0.0f &&
(automasking->settings.flags & BRUSH_AUTOMASKING_CONCAVITY);
/* If the cache is initialized with valid info, use the cache. This is used when the
@ -321,8 +322,6 @@ static void sculpt_face_sets_automasking_init(Sculpt *sd,
*(float *)SCULPT_temp_cdata_get(vertex, factorlayer) = 0.0f;
}
}
return;
}
#define EDGE_DISTANCE_INF -1
@ -334,11 +333,6 @@ void SCULPT_boundary_automasking_init(Object *ob,
{
SculptSession *ss = ob->sculpt;
if (!ss->pmap) {
BLI_assert_msg(0, "Boundary Edges masking: pmap missing");
return;
}
const int totvert = SCULPT_vertex_count_get(ss);
int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
@ -346,6 +340,7 @@ void SCULPT_boundary_automasking_init(Object *ob,
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
if (SCULPT_vertex_is_boundary(ss, vertex, SCULPT_BOUNDARY_MESH)) {
@ -397,10 +392,11 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski
Sculpt *sd,
const Brush *brush)
{
automasking->settings.flags = sculpt_automasking_mode_effective_bits(sd, brush);
automasking->settings.flags = sculpt_automasking_mode_effective_bits(ss, sd, brush);
automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss);
automasking->settings.concave_factor = brush ? brush->concave_mask_factor : 0.0f;
automasking->settings.concave_factor = BKE_brush_channelset_get_float(
ss->cache->channels_final, "concave_mask_factor", &ss->cache->input_mapping);
}
float SCULPT_calc_concavity(SculptSession *ss, SculptVertRef vref)
@ -420,7 +416,7 @@ float SCULPT_calc_concavity(SculptSession *ss, SculptVertRef vref)
}
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (!tot) {
if (tot == 0.0f) {
return 0.5f;
}
@ -469,10 +465,11 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, const Brush *brush,
}
AutomaskingCache *automasking = MEM_callocN(sizeof(AutomaskingCache), "automasking cache");
SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush);
SCULPT_boundary_info_ensure(ob);
if (!SCULPT_automasking_needs_factors_cache(sd, brush)) {
if (!SCULPT_automasking_needs_factors_cache(ss, sd, brush)) {
return automasking;
}
@ -502,16 +499,14 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, const Brush *brush,
*f = 1.0f;
}
const int boundary_propagation_steps = brush ?
brush->automasking_boundary_edges_propagation_steps :
1;
const int boundary_propagation_steps = automasking_get_propegation(ss);
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) {
if (SCULPT_is_automasking_mode_enabled(ss, sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) {
SCULPT_vertex_random_access_ensure(ss);
SCULPT_topology_automasking_init(sd, ob, automasking->factorlayer);
}
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
if (SCULPT_is_automasking_mode_enabled(ss, sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_automasking_init(ob,
AUTOMASK_INIT_BOUNDARY_FACE_SETS,
@ -524,17 +519,17 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, const Brush *brush,
return automasking;
}
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) {
if (SCULPT_is_automasking_mode_enabled(ss, sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) {
SCULPT_vertex_random_access_ensure(ss);
sculpt_face_sets_automasking_init(sd, ob, automasking->factorlayer);
}
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
if (SCULPT_is_automasking_mode_enabled(ss, sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
SCULPT_vertex_random_access_ensure(ss);
SCULPT_boundary_automasking_init(
ob, AUTOMASK_INIT_BOUNDARY_EDGES, boundary_propagation_steps, automasking->factorlayer);
}
if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_CONCAVITY)) {
if (SCULPT_is_automasking_mode_enabled(ss, sd, brush, BRUSH_AUTOMASKING_CONCAVITY)) {
SCULPT_vertex_random_access_ensure(ss);
SCULPT_concavity_automasking_init(ob, brush, automasking, automasking->factorlayer);
}

View File

@ -253,6 +253,18 @@ typedef enum SculptCornerType {
SCULPT_CORNER_SHARP = 1 << 3
} SculptCornerType;
/* Sculpt API to get brush channel data
If ss->cache exists then ss->cache->channels_final
will be used, otherwise brush and tool settings channels
will be used (taking inheritence into account).
*/
float SCULPT_get_float(const SculptSession *ss,
const char *idname,
const Sculpt *sd,
const Brush *br);
int SCULPT_get_int(const SculptSession *ss, const char *idname, const Sculpt *sd, const Brush *br);
SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
const SculptVertRef index,
SculptCornerType cornertype);
@ -450,7 +462,10 @@ struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, const Brush *brush, Object *ob);
void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
bool SCULPT_is_automasking_mode_enabled(Sculpt *sd, const Brush *br, const eAutomasking_flag mode);
bool SCULPT_is_automasking_mode_enabled(const SculptSession *ss,
const Sculpt *sd,
const Brush *br,
const eAutomasking_flag mode);
bool SCULPT_is_automasking_enabled(Sculpt *sd, const SculptSession *ss, const Brush *br);
typedef enum eBoundaryAutomaskMode {
@ -1081,6 +1096,7 @@ typedef struct AutomaskingCache {
* initialized in #SCULPT_automasking_cache_init when needed. */
// float *factor;
SculptCustomLayer *factorlayer;
float concave_mask_factor;
} AutomaskingCache;
typedef struct StrokeCache {

View File

@ -1500,13 +1500,13 @@ bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *v
return 0;
}
void RNA_property_enum_items_ex(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const bool use_static,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free)
ATTR_NO_OPT void RNA_property_enum_items_ex(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const bool use_static,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);

View File

@ -45,7 +45,7 @@
#include "DNA_sculpt_brush_types.h"
#include "WM_types.h"
static EnumPropertyItem null_enum[2] = {{0, "null", 0, 0}, {0, NULL, 0, NULL, NULL}};
static EnumPropertyItem null_enum[2] = {{0, "null", ICON_NONE, "null"}, {0, NULL, 0, NULL, NULL}};
#ifdef RNA_RUNTIME
@ -241,6 +241,50 @@ ATTR_NO_OPT const EnumPropertyItem *rna_BrushChannel_enum_value_get_items(struct
return ch->def->rna_enumdef;
}
static int rna_enum_check_separator(CollectionPropertyIterator *UNUSED(iter), void *data)
{
EnumPropertyItem *item = (EnumPropertyItem *)data;
return (item->identifier[0] == 0);
}
static void rna_BrushChannel_enum_items_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
/* EnumPropertyRNA *eprop; */ /* UNUSED */
const EnumPropertyItem *item = NULL;
int totitem;
bool free;
BrushChannel *ch = (BrushChannel *)ptr->data;
if (!ch->def || !ELEM(ch->type, BRUSH_CHANNEL_ENUM, BRUSH_CHANNEL_BITMASK)) {
if (!ch->def) {
printf("%s: channel '%s' had no definition\n", __func__, ch->idname);
}
else {
printf("%s: channel '%s' is not an enum/bitmask\n", __func__, ch->idname);
}
item = null_enum;
rna_iterator_array_begin(
iter, (void *)item, sizeof(EnumPropertyItem), 0, free, rna_enum_check_separator);
return;
}
BKE_brush_channeltype_rna_check(ch->def, lookup_icon_id);
totitem = 0;
while (ch->def->rna_enumdef[totitem].name) {
totitem++;
}
item = ch->def->rna_enumdef;
rna_iterator_array_begin(
iter, (void *)item, sizeof(EnumPropertyItem), totitem, free, rna_enum_check_separator);
}
#endif
static EnumPropertyItem mapping_type_items[] = {
@ -401,6 +445,20 @@ void RNA_def_brush_channel(BlenderRNA *brna)
"rna_BrushChannel_enum_value_set",
"rna_BrushChannel_enum_value_get_items");
prop = RNA_def_property(srna, "enum_items", PROP_COLLECTION, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE | PROP_ANIMATABLE);
RNA_def_property_struct_type(prop, "EnumPropertyItem");
RNA_def_property_collection_funcs(prop,
"rna_BrushChannel_enum_items_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
NULL,
NULL,
NULL,
NULL);
RNA_def_property_ui_text(prop, "Items", "Possible values for the property");
prop = RNA_def_property(srna, "flags_value", PROP_ENUM, PROP_UNIT_NONE);
RNA_def_property_ui_text(prop, "Flags Value", "Flags values");