Sculpt: fix broken jitter and smooth
stabilize brush settings.
This commit is contained in:
parent
a1202d3ce1
commit
f91161a707
|
@ -320,6 +320,12 @@ class UnifiedPaintPanel:
|
|||
|
||||
@staticmethod
|
||||
def get_channel_value(context, brush, prop_name, toolsettings_only=False):
|
||||
if context.mode != "SCULPT":
|
||||
if prop_name in channel_name_map:
|
||||
prop_name = channel_name_map[prop_name]
|
||||
|
||||
return getattr(brush, prop_name)
|
||||
|
||||
ch = brush.channels[prop_name]
|
||||
|
||||
if ch.inherit or toolsettings_only:
|
||||
|
@ -864,7 +870,7 @@ class StrokePanel(BrushPanel):
|
|||
col.prop(brush, "dash_ratio", text="Dash Ratio")
|
||||
col.prop(brush, "dash_samples", text="Dash Length")
|
||||
|
||||
if (mode == 'SCULPT' and brush.sculpt_capabilities.has_jitter) or mode != 'SCULPT':
|
||||
if mode != 'SCULPT':
|
||||
col.separator()
|
||||
row = col.row(align=True)
|
||||
if brush.jitter_unit == 'BRUSH':
|
||||
|
@ -873,6 +879,26 @@ class StrokePanel(BrushPanel):
|
|||
row.prop(brush, "jitter_absolute")
|
||||
row.prop(brush, "use_pressure_jitter", toggle=True, text="")
|
||||
col.row().prop(brush, "jitter_unit", expand=True)
|
||||
elif mode == 'SCULPT' and brush.sculpt_capabilities.has_jitter:
|
||||
col.separator()
|
||||
row = col.row(align=True)
|
||||
if UnifiedPaintPanel.get_channel_value(context, brush, "jitter_unit") == 'BRUSH':
|
||||
UnifiedPaintPanel.channel_unified(row,
|
||||
context,
|
||||
brush,
|
||||
"jitter", slider=True)
|
||||
else:
|
||||
UnifiedPaintPanel.channel_unified(row,
|
||||
context,
|
||||
brush,
|
||||
"jitter_absolute")
|
||||
|
||||
#row.prop(brush, "use_pressure_jitter", toggle=True, text="")
|
||||
UnifiedPaintPanel.channel_unified(col.row(),
|
||||
context,
|
||||
brush,
|
||||
"jitter_unit", expand=True)
|
||||
#col.row().prop(brush, "jitter_unit", expand=True)
|
||||
|
||||
col.separator()
|
||||
col.prop(settings, "input_samples")
|
||||
|
@ -896,20 +922,41 @@ class SmoothStrokePanel(BrushPanel):
|
|||
settings = self.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
self.layout.prop(brush, "use_smooth_stroke", text="")
|
||||
if context.mode == "SCULPT":
|
||||
self.layout.prop(brush.channels["use_smooth_stroke"], "value", text="")
|
||||
else:
|
||||
self.layout.prop(brush, "use_smooth_stroke", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
ui_editing = context.tool_settings.unified_paint_settings.brush_editor_mode
|
||||
|
||||
settings = self.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
if ui_editing:
|
||||
UnifiedPaintPanel.channel_unified(self.layout,
|
||||
context,
|
||||
brush,
|
||||
"use_smooth_stroke", ui_editing=True, text="Stabilize Stroke")
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
col = layout.column()
|
||||
col.active = brush.use_smooth_stroke
|
||||
col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
|
||||
col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
|
||||
|
||||
col.active = UnifiedPaintPanel.get_channel_value(context, brush, "use_smooth_stroke")
|
||||
|
||||
#col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
|
||||
#col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
|
||||
UnifiedPaintPanel.channel_unified(col,
|
||||
context,
|
||||
brush,
|
||||
"smooth_stroke_radius", text="Radius", ui_editing=ui_editing, slider=True)
|
||||
UnifiedPaintPanel.channel_unified(col,
|
||||
context,
|
||||
brush,
|
||||
"smooth_stroke_factor", text="Factor", ui_editing=ui_editing, slider=True)
|
||||
|
||||
|
||||
class FalloffPanel(BrushPanel):
|
||||
|
|
|
@ -288,8 +288,15 @@ MAKE_FLOAT(normal_weight, "Normal Weight", "", 0.0f, 0.0f, 1.0f)
|
|||
MAKE_FLOAT(weight, "Weight", "", 0.5f, 0.0f, 1.0f)
|
||||
MAKE_FLOAT(jitter, "Jitter", "Jitter the position of the brush while painting", 0.0f, 0.0f, 1.0f)
|
||||
MAKE_INT(jitter_absolute, "Absolute Jitter", "", 0, 0.0f, 1000.0f)
|
||||
MAKE_FLOAT(smooth_stroke_radius, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues", 75.0f, 10.0f, 200.0f)
|
||||
MAKE_FLOAT(smooth_stroke_factor, "Smooth Stroke Factor", "", 0.9f, 0.5f, 0.99f)
|
||||
MAKE_ENUM_EX(jitter_unit, "Jitter Unit", "Jitter in screen space or relative to brush size", 0, 0, {
|
||||
{BRUSH_ABSOLUTE_JITTER, "VIEW", "NONE", "View", "Jittering happens in screen space, in pixels"},
|
||||
{0, "BRUSH", "NONE", "Brush", "Jittering happens relative to the brush size"},
|
||||
{-1}
|
||||
})
|
||||
|
||||
MAKE_BOOL_EX(use_smooth_stroke, "Smooth Stroke", "Brush lags behind mouse and follows a smoother path", false, 0)
|
||||
MAKE_FLOAT_EX_EX(smooth_stroke_radius, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues", 75.0f, 10.0f, 200.0f, 10.0f, 200.0f, false, false, 0)
|
||||
MAKE_FLOAT_EX_EX(smooth_stroke_factor, "Smooth Stroke Factor", "", 0.9f, 0.5f, 0.99f, 0.5f, 0.99f, false, false, 0)
|
||||
MAKE_FLOAT_EX(rate, "Rate", "", 0.1f, 0.0001f, 10000.0f, 0.01f, 1.0f, false)
|
||||
MAKE_FLOAT(flow, "Flow", "Amount of paint that is applied per stroke sample", 1.0f, 0.0f, 1.0f)
|
||||
MAKE_FLOAT(wet_mix, "Wet Mix", "Amount of paint that is picked from the surface into the brush color", 0.0f, 0.0f, 1.0f)
|
||||
|
|
|
@ -248,6 +248,10 @@ static bool check_builtin_init()
|
|||
// BKE_brush_channeltype_rna_check(brush_builtin_channels + i);
|
||||
//}
|
||||
|
||||
SUBTYPE_SET(smooth_stroke_radius, BRUSH_CHANNEL_PIXEL);
|
||||
|
||||
SUBTYPE_SET(jitter_absolute, BRUSH_CHANNEL_PIXEL);
|
||||
|
||||
SUBTYPE_SET(radius, BRUSH_CHANNEL_PIXEL);
|
||||
SUBTYPE_SET(spacing, BRUSH_CHANNEL_PERCENT);
|
||||
SUBTYPE_SET(autosmooth_spacing, BRUSH_CHANNEL_PERCENT);
|
||||
|
@ -286,6 +290,12 @@ static bool check_builtin_init()
|
|||
|
||||
SETCAT(spacing, "Stroke");
|
||||
SETCAT(use_space_attenuation, "Stroke");
|
||||
SETCAT(use_smooth_stroke, "Stroke");
|
||||
SETCAT(smooth_stroke_factor, "Stroke");
|
||||
SETCAT(smooth_stroke_radius, "Stroke");
|
||||
SETCAT(jitter_absolute, "Stroke");
|
||||
SETCAT(jitter_unit, "Stroke");
|
||||
SETCAT(jitter, "Stroke");
|
||||
|
||||
SETCAT(autosmooth, "Smoothing");
|
||||
SETCAT(autosmooth_projection, "Smoothing");
|
||||
|
@ -416,7 +426,7 @@ static BrushSettingsMap brush_settings_map[] = {
|
|||
DEF(weight, weight, FLOAT, FLOAT)
|
||||
DEF(multiplane_scrape_angle, multiplane_scrape_angle, FLOAT, FLOAT)
|
||||
DEF(jitter, jitter, FLOAT, FLOAT)
|
||||
DEF(jitter_absolute, JITTER_ABSOLITE, INT, INT)
|
||||
DEF(jitter_absolute, jitter_absolute, INT, INT)
|
||||
DEF(smooth_stroke_radius, smooth_stroke_radius, INT, FLOAT)
|
||||
DEF(smooth_stroke_factor, smooth_stroke_factor, FLOAT, FLOAT)
|
||||
DEF(rate, rate, FLOAT, FLOAT)
|
||||
|
@ -502,6 +512,7 @@ typedef struct BrushFlagMap {
|
|||
char *channel_name;
|
||||
int flag;
|
||||
int member_size;
|
||||
int bitmask_bit;
|
||||
} BrushFlagMap;
|
||||
|
||||
/* clang-format off */
|
||||
|
@ -510,7 +521,10 @@ typedef struct BrushFlagMap {
|
|||
#endif
|
||||
|
||||
#define DEF(member, channel, flag)\
|
||||
{offsetof(Brush, member), #channel, flag, sizeof(((Brush){0}).member)},
|
||||
{offsetof(Brush, member), #channel, flag, sizeof(((Brush){0}).member), 0},
|
||||
|
||||
#define DEFBIT(member, channel, flag, bit)\
|
||||
{offsetof(Brush, member), #channel, flag, sizeof(((Brush){0}).member), bit},
|
||||
|
||||
/* This lookup table is like brush_settings_map except it converts
|
||||
individual bitflags instead of whole struct members.*/
|
||||
|
@ -539,6 +553,8 @@ BrushFlagMap brush_flags_map[] = {
|
|||
DEF(flag2, use_surface_falloff, BRUSH_USE_SURFACE_FALLOFF)
|
||||
DEF(flag2, use_grab_active_vertex, BRUSH_GRAB_ACTIVE_VERTEX)
|
||||
DEF(flag, accumulate, BRUSH_ACCUMULATE)
|
||||
DEF(flag, use_smooth_stroke, BRUSH_SMOOTH_STROKE)
|
||||
DEFBIT(flag, jitter_unit, BRUSH_ABSOLUTE_JITTER, BRUSH_ABSOLUTE_JITTER)
|
||||
};
|
||||
|
||||
int brush_flags_map_len = ARRAY_SIZE(brush_flags_map);
|
||||
|
@ -637,6 +653,38 @@ void *get_channel_value_pointer(BrushChannel *ch, int *r_data_size)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int brushflag_from_channel(BrushFlagMap *mf, int flag, int val)
|
||||
{
|
||||
if (mf->bitmask_bit == 0) {
|
||||
return val ? flag | mf->flag : flag & ~mf->flag;
|
||||
}
|
||||
|
||||
if (val & mf->bitmask_bit) {
|
||||
flag |= mf->flag;
|
||||
}
|
||||
else {
|
||||
flag &= ~mf->flag;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
static int brushflag_to_channel(BrushFlagMap *mf, int chvalue, int val)
|
||||
{
|
||||
if (mf->bitmask_bit == 0) {
|
||||
return val & mf->flag ? 1 : 0;
|
||||
}
|
||||
|
||||
if (val & mf->flag) {
|
||||
chvalue |= mf->bitmask_bit;
|
||||
}
|
||||
else {
|
||||
chvalue &= ~mf->bitmask_bit;
|
||||
}
|
||||
|
||||
return chvalue;
|
||||
}
|
||||
|
||||
static void brush_flags_from_channels(BrushChannelSet *chset, Brush *brush)
|
||||
{
|
||||
for (int i = 0; i < brush_flags_map_len; i++) {
|
||||
|
@ -653,42 +701,22 @@ static void brush_flags_from_channels(BrushChannelSet *chset, Brush *brush)
|
|||
switch (mf->member_size) {
|
||||
case 1: {
|
||||
char *f = (char *)ptr;
|
||||
if (ch->ivalue) {
|
||||
*f |= mf->flag;
|
||||
}
|
||||
else {
|
||||
*f &= ~mf->flag;
|
||||
}
|
||||
*f = (char)brushflag_from_channel(mf, *f, ch->ivalue);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
ushort *f = (ushort *)ptr;
|
||||
if (ch->ivalue) {
|
||||
*f |= mf->flag;
|
||||
}
|
||||
else {
|
||||
*f &= ~mf->flag;
|
||||
}
|
||||
*f = (ushort)brushflag_from_channel(mf, *f, ch->ivalue);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint *f = (uint *)ptr;
|
||||
if (ch->ivalue) {
|
||||
*f |= mf->flag;
|
||||
}
|
||||
else {
|
||||
*f &= ~mf->flag;
|
||||
}
|
||||
*f = (uint)brushflag_from_channel(mf, *f, ch->ivalue);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
uint64_t *f = (uint64_t *)ptr;
|
||||
if (ch->ivalue) {
|
||||
*f |= mf->flag;
|
||||
}
|
||||
else {
|
||||
*f &= ~mf->flag;
|
||||
}
|
||||
*f = (uint64_t)brushflag_from_channel(mf, *f, ch->ivalue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -711,22 +739,22 @@ static void brush_flags_to_channels(BrushChannelSet *chset, Brush *brush)
|
|||
switch (mf->member_size) {
|
||||
case 1: {
|
||||
char *f = (char *)ptr;
|
||||
ch->ivalue = (*f & mf->flag) ? 1 : 0;
|
||||
ch->ivalue = brushflag_to_channel(mf, ch->ivalue, *f);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
ushort *f = (ushort *)ptr;
|
||||
ch->ivalue = (*f & mf->flag) ? 1 : 0;
|
||||
ch->ivalue = brushflag_to_channel(mf, ch->ivalue, *f);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint *f = (uint *)ptr;
|
||||
ch->ivalue = (*f & mf->flag) ? 1 : 0;
|
||||
ch->ivalue = brushflag_to_channel(mf, ch->ivalue, *f);
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
uint64_t *f = (uint64_t *)ptr;
|
||||
ch->ivalue = (*f & mf->flag) ? 1 : 0;
|
||||
ch->ivalue = brushflag_to_channel(mf, ch->ivalue, *f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1053,6 +1081,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
ADDCH(original_plane);
|
||||
ADDCH(jitter);
|
||||
ADDCH(jitter_absolute);
|
||||
ADDCH(jitter_unit);
|
||||
ADDCH(use_weighted_smooth);
|
||||
ADDCH(preserve_faceset_boundary);
|
||||
ADDCH(hard_edge_mode);
|
||||
|
@ -1068,6 +1097,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
|
||||
ADDCH(direction);
|
||||
ADDCH(dash_ratio);
|
||||
ADDCH(use_smooth_stroke);
|
||||
ADDCH(smooth_stroke_factor);
|
||||
ADDCH(smooth_stroke_radius);
|
||||
ADDCH(smooth_deform_type);
|
||||
|
|
|
@ -11892,6 +11892,17 @@ static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float
|
|||
|
||||
static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
|
||||
{
|
||||
if (BKE_paintmode_get_active_from_context(C) == PAINT_MODE_SCULPT) {
|
||||
/* load brush settings into old Brush fields so the
|
||||
paint API can get at then */
|
||||
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
||||
if (brush && brush->channels) {
|
||||
BKE_brush_channelset_compat_load(brush->channels, brush, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't start the stroke until mouse goes over the mesh.
|
||||
* NOTE: mouse will only be null when re-executing the saved stroke.
|
||||
* We have exception for 'exec' strokes since they may not set 'mouse',
|
||||
|
|
Loading…
Reference in New Issue