Sculpt: brush input mappings improvements

Cleaned up brush channel input mappings:

* BrushMapping now stores .min/.max
* BrushMappingDef .min/max now sets BrushMapping min/max
  instead of changing the curve preset bounds.
* Fixed how BKE_brush_channel_eval_mappings evaluates
  the mappings stack.  Mappings now blend directly
  with channel value instead of accumulating a multiplier
  that's applied at the end.
* Consequently, BrushMapping->blendmode now defaults to MA_BLEND_MULT.
* Exposed BrushMapping->blendmode in RNA and UI.
  Note that it doesn't support every MA_BLEND_ type,
  it provides its own EnumPropertyItem list of
  supported blendmodes.
* Added a random input method, BRUSH_MAPPING_RANDOM.
* Fixed BRUSH_MAPPING_ANGLE being given data in the wrong
  range (all channels should be 0..1, not -pi..pi).

Other changes:
* Improved the uv smooth brush.  It's still hidden behind an
  experimental pref.
* Added a SCULPT_temp_customlayer_has function to check if a temporary
  customdata attribute layer exists.
* Fixed a bunch of broken sliders in the paint_toolsystem_common.py.
This commit is contained in:
Joseph Eagar 2021-10-16 01:16:21 -07:00
parent 673e1fbac5
commit 07be162dd5
12 changed files with 344 additions and 95 deletions

View File

@ -114,7 +114,6 @@ class DynamicPaintPanelGen:
}
def callback():
print("creating panel")
DynamicPaintPanelGen.createPanel(group)
pass
@ -353,11 +352,14 @@ class UnifiedPaintPanel:
@staticmethod
def channel_unified(layout, context, brush, prop_name, icon='NONE', pressure=None, text=None,
def channel_unified(layout, context, brush, prop_name, icon='NONE', pressure=None, text=None, baselayout=None,
slider=False, header=False, show_reorder=False, expand=None, toolsettings_only=False, ui_editing=None):
""" Generalized way of adding brush options to the UI,
along with their pen pressure setting and global toggle"""
if baselayout is None:
baselayout = layout
if slider is None:
slider = False
@ -527,6 +529,8 @@ class UnifiedPaintPanel:
row.prop(ch, "ui_expanded", text="", icon="TRIA_DOWN" if ch.ui_expanded else "TRIA_RIGHT")
if ch.ui_expanded:
layout = baselayout.column()
for i, mp in enumerate(ch.mappings):
mp0 = mp
if mp.inherit:
@ -563,6 +567,12 @@ class UnifiedPaintPanel:
props.shape = shape
props.path = path2
col.prop(mp, "factor")
col.prop(mp, "blendmode")
row = col.row()
row.prop(mp, "min")
row.prop(mp, "max")
#row2.prop(mp, "curve")
return row
@ -1341,12 +1351,12 @@ def brush_settings(layout, context, brush, popover=False):
# Per sculpt tool options.
def doprop(col, prop, slider=None):
def doprop(col, prop, slider=None, text=None, baselayout=None):
UnifiedPaintPanel.channel_unified(col,
context,
brush,
prop,
slider=slider)
slider=slider, text=text, baselayout=baselayout)
if sculpt_tool == "VCOL_BOUNDARY":
row = layout.row()
@ -1480,17 +1490,18 @@ def brush_settings(layout, context, brush, popover=False):
elif sculpt_tool == 'SCRAPE':
row = layout.row(align=True)
doprop(row, "area_radius_factor")
doprop(row, "use_pressure_area_radius", text="")
doprop(row, "area_radius_factor", baselayout=layout)
#doprop(row, "use_pressure_area_radius", text="",
#baselayout=layout)
row = layout.row()
doprop(row, "invert_to_scrape_fill", text="Invert to Fill")
doprop(row, "invert_to_scrape_fill", text="Invert to Fill", baselayout=layout)
elif sculpt_tool == 'FILL':
row = layout.row(align=True)
doprop(row, "area_radius_factor")
doprop(row, "use_pressure_area_radius", text="")
doprop(row, "area_radius_factor", baselayout=layout)
#doprop(row, "use_pressure_area_radius", text="")
row = layout.row()
doprop(row, "invert_to_scrape_fill", text="Invert to Scrape")
doprop(row, "invert_to_scrape_fill", text="Invert to Scrape", baselayout=layout)
elif sculpt_tool == 'GRAB':
doprop(layout, "use_grab_active_vertex")
@ -1499,33 +1510,31 @@ def brush_settings(layout, context, brush, popover=False):
elif sculpt_tool == 'PAINT':
row = layout.row(align=True)
doprop(row, "flow")
doprop(row, "invert_flow_pressure", text="")
doprop(row, "use_flow_pressure", text="")
doprop(row, "flow", baselayout=layout)
row.prop(brush.channels["flow"].mappings["PRESSURE"], "invert", text="")
row = layout.row(align=True)
row.prop(brush, "wet_mix")
row.prop(brush, "invert_wet_mix_pressure", text="")
row.prop(brush, "use_wet_mix_pressure", text="")
doprop(row, "wet_mix", baselayout=layout)
row.prop(brush.channels["wet_mix"].mappings["PRESSURE"], "invert", text="")
row = layout.row(align=True)
doprop(row, "wet_persistence")
doprop(row, "invert_wet_persistence_pressure", text="")
doprop(row, "use_wet_persistence_pressure", text="")
doprop(row, "wet_persistence", baselayout=layout)
row.prop(brush.channels["wet_persistence"].mappings["PRESSURE"], "invert", text="")
row = layout.row(align=True)
doprop(row, "wet_paint_radius_factor")
doprop(row, "wet_paint_radius_factor", baselayout=layout)
row = layout.row(align=True)
doprop(row, "density")
doprop(row, "invert_density_pressure", text="")
doprop(row, "use_density_pressure", text="")
doprop(row, "density", baselayout=layout)
row.prop(brush.channels["density"].mappings["PRESSURE"], "invert", text="")
row = layout.row()
doprop(row, "tip_roundness")
doprop(row, "tip_roundness", baselayout=layout)
row = layout.row()
doprop(row, "tip_scale_x")
doprop(row, "tip_scale_x", baselayout=layout)
doprop(layout.column(), "hue_offset", baselayout=layout)
elif sculpt_tool == 'SMEAR':
col = layout.column()
@ -1602,7 +1611,7 @@ def brush_settings(layout, context, brush, popover=False):
doprop(col, "smear_deform_type")
elif sculpt_tool == 'MASK':
doprop(layout.row(), "mask_tool", expand=True)
doprop(layout.row(), "mask_tool", expand=True, baselayout=layout)
# End sculpt_tool interface.
@ -1813,6 +1822,7 @@ class ReorderBrushChannel(Operator):
return {'FINISHED'}
classes.append(ReorderBrushChannel)
def brush_settings_channels(layout, context, brush, ui_editing=False, popover=False, show_reorder=None, filterkey="show_in_workspace",
parent="VIEW3D_PT_tools_brush_settings_channels", prefix="VIEW3D_PT_brush_category_"):

View File

@ -105,15 +105,16 @@ typedef struct BrushMappingDef {
float min, max;
int blendmode;
float factor; // if 0, will default to 1.0
bool no_default;
} BrushMappingDef;
typedef struct BrushMappingPreset {
// must match order of BRUSH_MAPPING_XXX enums
struct BrushMappingDef pressure, xtilt, ytilt, angle, speed;
struct BrushMappingDef pressure, xtilt, ytilt, angle, speed, random;
} BrushMappingPreset;
typedef struct BrushMappingData {
float pressure, xtilt, ytilt, angle, speed;
float pressure, xtilt, ytilt, angle, speed, random;
} BrushMappingData;
#define MAX_BRUSH_ENUM_DEF 32
@ -227,6 +228,7 @@ bool BKE_brush_channelset_has(BrushChannelSet *chset, const char *idname);
BrushChannel *BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname);
BrushChannel *BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname);
void BKE_brush_mapping_reset(BrushChannel *ch, int tool, int mapping);
void BKE_brush_channelset_merge(BrushChannelSet *dst,
BrushChannelSet *child,

View File

@ -302,6 +302,10 @@ 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)
MAKE_FLOAT(wet_persistence, "Wet Persistence", "Amount of wet paint that stays in the brush after applying paint to the surface", 0.0f, 0.0f, 1.0f)
MAKE_FLOAT_EX(hue_offset, "Hue", "Offset Applied To Hue", 0.5f, -3.0f, 3.0f, 0.0f, 1.0f, false)
MAKE_FLOAT(wet_paint_radius_factor, "Wet Paint Radius",
"Ratio between the brush radius and the radius that is going to be "
"used to sample the color to blend in wet paint", 0.5f, 0.0f, 2.0f)
MAKE_FLOAT(density, "Density", "Amount of random elements that are going to be affected by the brush", 1.0f, 0.0f, 1.0f)
MAKE_FLOAT(tip_scale_x, "Tip Scale X", "Scale of the brush tip in the X axis", 1.0f, 0.0f, 1.0f)
MAKE_FLOAT(dash_ratio, "Dash Ratio", "Ratio of samples in a cycle that the brush is enabled", 1.0f, 0.0f, 1.0f)

View File

@ -416,14 +416,14 @@ void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def)
BrushMappingDef *mdef = (&def->mappings.pressure) + i;
if (mdef->min != mdef->max) {
min = mdef->min;
max = mdef->max;
}
else {
if (!mdef->no_default) {
min = 0.0f;
max = 1.0f;
}
else {
min = mdef->min;
max = mdef->max;
}
if (mdef->inv) {
mp->flag |= BRUSH_MAPPING_INVERT;
@ -431,20 +431,22 @@ void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def)
int slope = CURVEMAP_SLOPE_POSITIVE;
BKE_curvemapping_set_defaults(curve, 1, 0, min, 1, max);
BKE_curvemapping_set_defaults(curve, 1, 0, 0.0f, 1, 1.0f);
for (int j = 0; j < 1; j++) {
BKE_curvemap_reset(&curve->cm[j],
&(struct rctf){.xmin = 0, .ymin = min, .xmax = 1, .ymax = max},
&(struct rctf){.xmin = 0.0f, .ymin = 0.0f, .xmax = 1.0f, .ymax = 1.0f},
mdef->curve,
slope);
}
BKE_curvemapping_init(curve);
mp->min = min;
mp->max = max;
mp->curve = GET_CACHE_CURVE(curve); // frees curve and returns cached copy
mp->blendmode = mdef->blendmode;
mp->blendmode = !mdef->no_default ? MA_RAMP_MULT : mdef->blendmode;
mp->factor = mdef->factor == 0.0f ? 1.0f : mdef->factor;
if (mdef->enabled) {
@ -923,7 +925,7 @@ static bool channel_has_mappings(BrushChannel *ch)
return false;
}
// idx is used by vector channels
/* idx is used by vector channels */
double BKE_brush_channel_eval_mappings(BrushChannel *ch,
BrushMappingData *mapdata,
double f,
@ -935,7 +937,7 @@ double BKE_brush_channel_eval_mappings(BrushChannel *ch,
}
if (mapdata) {
double factor = 1.0f;
double factor = f; // 1.0f;
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMapping *mp = ch->mappings + i;
@ -951,7 +953,10 @@ double BKE_brush_channel_eval_mappings(BrushChannel *ch,
}
double f2 = (float)BKE_curvemapping_evaluateF(mp->curve, 0, inputf);
f2 = mp->min + (mp->max - mp->min) * f2;
/* make sure to update blend_items in rna_brush_engine.c
when adding new mode implementations */
switch (mp->blendmode) {
case MA_RAMP_BLEND:
break;
@ -959,7 +964,7 @@ double BKE_brush_channel_eval_mappings(BrushChannel *ch,
f2 *= factor;
break;
case MA_RAMP_DIV:
f2 = factor / (0.00001f + f2);
f2 = factor / (f2 == 0.0f ? 0.0001f : f2);
break;
case MA_RAMP_ADD:
f2 += factor;
@ -980,7 +985,9 @@ double BKE_brush_channel_eval_mappings(BrushChannel *ch,
factor += (f2 - factor) * mp->factor;
}
f *= factor;
f = factor;
CLAMP(f, ch->def->min, ch->def->max);
// f *= factor;
}
return f;
@ -1767,6 +1774,10 @@ void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *chset)
CurveMapping *curve = mp->curve;
if (mp->min == mp->max == 0.0f) {
mp->max = 1.0f;
}
if (curve) {
BKE_curvemapping_blend_read(reader, curve);
BKE_curvemapping_init(curve);
@ -1833,6 +1844,8 @@ const char *BKE_brush_mapping_type_to_str(BrushMappingType mapping)
return "X Tilt";
case BRUSH_MAPPING_YTILT:
return "Y Tilt";
case BRUSH_MAPPING_RANDOM:
return "Random";
case BRUSH_MAPPING_MAX:
return "Error";
}
@ -1853,6 +1866,8 @@ const char *BKE_brush_mapping_type_to_typename(BrushMappingType mapping)
return "XTILT";
case BRUSH_MAPPING_YTILT:
return "YTILT";
case BRUSH_MAPPING_RANDOM:
return "RANDOM";
case BRUSH_MAPPING_MAX:
return "Error";
}
@ -1876,6 +1891,9 @@ void BKE_brush_mapping_copy_data(BrushMapping *dst, BrushMapping *src)
}
dst->blendmode = src->blendmode;
dst->min = src->min;
dst->max = src->max;
dst->factor = src->factor;
dst->flag = src->flag;
dst->input_channel = src->input_channel;

View File

@ -94,7 +94,8 @@ To enable converting to/from old data:
.type = BRUSH_CHANNEL_TYPE_FLOAT,\
.subtype = BRUSH_CHANNEL_FACTOR,\
.mappings = {\
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0f, .min = 0.0f, .max = 1.0f, .enabled = pressure_enabled, .inv = pressure_inv},\
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0f, .no_default=true, .blendmode = MA_RAMP_MULT, \
.min = 0.0f, .max = 1.0f, .enabled = pressure_enabled, .inv = pressure_inv},\
}\
},
#define MAKE_FLOAT_EX(idname1, name1, tooltip1, value1, min1, max1, smin1, smax1, pressure_enabled)\
@ -237,6 +238,8 @@ static BrushChannelType *_get_def(const char *idname)
static bool do_builtin_init = true;
static bool check_builtin_init()
{
BrushChannelType *def;
if (!do_builtin_init || !BLI_thread_is_main()) {
return false;
}
@ -259,11 +262,23 @@ static bool check_builtin_init()
SUBTYPE_SET(autosmooth_radius_scale, BRUSH_CHANNEL_PERCENT);
SUBTYPE_SET(topology_rake_radius_scale, BRUSH_CHANNEL_PERCENT);
def = GETDEF(hue_offset);
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMappingDef *mdef = (&def->mappings.pressure) + i;
mdef->no_default = true;
mdef->curve = CURVE_PRESET_LINE;
mdef->min = i == 0 ? 0.0f : -1.0f; /* have pressure use minimum of 0.0f */
mdef->max = 1.0f;
mdef->factor = 0.5f;
mdef->blendmode = MA_RAMP_ADD;
}
SETCAT(concave_mask_factor, "Automasking");
SETCAT(automasking, "Automasking");
SETCAT(automasking_boundary_edges_propagation_steps, "Automasking");
BrushChannelType *def = GETDEF(concave_mask_factor);
def = GETDEF(concave_mask_factor);
def->mappings.pressure.inv = true;
// don't group strength/radius/direction in subpanels
@ -349,9 +364,11 @@ static bool check_builtin_init()
SETCAT(secondary_color, "Color");
SETCAT(blend, "Color");
SETCAT(wet_mix, "Color");
SETCAT(hue_offset, "Color");
SETCAT(wet_persistence, "Color");
SETCAT(density, "Color");
SETCAT(flow, "Color");
SETCAT(wet_paint_radius_factor, "Color");
SETCAT(vcol_boundary_spacing, "Color Boundary Hardening");
SETCAT(vcol_boundary_radius_scale, "Color Boundary Hardening");
@ -435,6 +452,7 @@ static BrushSettingsMap brush_settings_map[] = {
DEF(flow, flow, FLOAT, FLOAT)
DEF(hardness, hardness, FLOAT, FLOAT)
DEF(wet_mix, wet_mix, FLOAT, FLOAT)
DEF(wet_paint_radius_factor, wet_paint_radius_factor, FLOAT, FLOAT)
DEF(wet_persistence, wet_persistence, FLOAT, FLOAT)
DEF(density, density, FLOAT, FLOAT)
DEF(tip_scale_x, tip_scale_x, FLOAT, FLOAT)
@ -919,6 +937,7 @@ void BKE_brush_channelset_compat_load(BrushChannelSet *chset, Brush *brush, bool
}
}
/* todo: move into BKE_brush_reset_mapping*/
void reset_clay_mappings(BrushChannelSet *chset, bool strips)
{
BrushMapping *mp = BRUSHSET_LOOKUP(chset, radius)->mappings + BRUSH_MAPPING_PRESSURE;
@ -1136,6 +1155,8 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(color);
ADDCH(secondary_color);
ADDCH(wet_mix);
ADDCH(hue_offset);
ADDCH(wet_paint_radius_factor);
ADDCH(wet_persistence);
ADDCH(density);
ADDCH(tip_scale_x);
@ -1470,6 +1491,8 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWWRK(secondary_color);
SHOWWRK(wet_mix);
SHOWWRK(hue_offset);
SHOWWRK(wet_paint_radius_factor);
SHOWWRK(wet_persistence);
SHOWWRK(density);
SHOWWRK(tip_scale_x);
@ -1518,6 +1541,35 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
#undef SHOWPROPS
namestack_pop();
}
void BKE_brush_mapping_reset(BrushChannel *ch, int tool, int mapping)
{
BrushMapping *mp = ch->mappings + mapping;
BrushMappingDef *mdef = (&ch->def->mappings.pressure) + mapping;
BKE_brush_mapping_ensure_write(mp);
CurveMapping *curve = mp->curve;
BKE_curvemapping_set_defaults(curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemap_reset(
curve->cm, &(struct rctf){.xmin = 0, .ymin = 0.0, .xmax = 1.0, .ymax = 1.0}, mdef->curve, 1);
BKE_curvemapping_init(curve);
if (STREQ(ch->idname, "hue_offset") && mapping == BRUSH_MAPPING_PRESSURE) {
CurveMap *cuma = curve->cm;
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 1.0f;
cuma->curve[1].y = 1.0f;
BKE_curvemap_insert(cuma, 0.65f, 0.0f);
cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
}
BKE_curvemapping_changed(curve, true);
}
void BKE_brush_builtin_create(Brush *brush, int tool)
{
namestack_push(__func__);
@ -1622,13 +1674,17 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
GETCH(dyntopo_disabled)->ivalue = 1;
GETCH(slide_deform_type)->ivalue = BRUSH_SLIDE_DEFORM_DRAG;
break;
case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_PAINT: {
BRUSHSET_SET_BOOL(chset, dyntopo_disabled, true);
BRUSHSET_SET_FLOAT(chset, hardness, 0.4f);
BRUSHSET_SET_FLOAT(chset, spacing, 10.0f);
BRUSHSET_SET_FLOAT(chset, strength, 0.6f);
BRUSHSET_LOOKUP(chset, strength)->flag &= ~BRUSH_MAPPING_INHERIT;
BrushChannel *ch = BRUSHSET_LOOKUP(chset, hue_offset);
BKE_brush_mapping_reset(ch, SCULPT_TOOL_PAINT, BRUSH_MAPPING_PRESSURE);
break;
}
case SCULPT_TOOL_CLAY:
GETCH(radius)->mappings[BRUSH_MAPPING_PRESSURE].flag |= BRUSH_MAPPING_ENABLED;
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag |= BRUSH_MAPPING_ENABLED;

View File

@ -1893,6 +1893,40 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 37)) {
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (!brush->channels) {
continue;
}
BrushChannel *ch;
ch = BRUSHSET_LOOKUP(brush->channels, hue_offset);
if (ch) {
BKE_brush_mapping_reset(ch, brush->sculpt_tool, BRUSH_MAPPING_PRESSURE);
}
ch = (BrushChannel *)brush->channels->channels.first;
for (; ch; ch = ch->next) {
if (!ch->mappings[BRUSH_MAPPING_RANDOM].factor) {
ch->mappings[BRUSH_MAPPING_RANDOM].factor = 1.0f;
}
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
if (ch->mappings[i].blendmode == MA_RAMP_BLEND) {
ch->mappings[i].blendmode = MA_RAMP_MULT;
}
if (ch->mappings[i].min == ch->mappings[i].max) {
ch->mappings[i].min = 0.0f;
ch->mappings[i].max = 1.0f;
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -853,9 +853,48 @@ bool SCULPT_temp_customlayer_ensure(SculptSession *ss,
return ret;
}
/* TODO: thoroughly test this function */
bool SCULPT_temp_customlayer_has(SculptSession *ss,
AttributeDomain domain,
int proptype,
const char *name)
{
CustomData *vdata = NULL, *pdata = NULL, *data = NULL;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH:
vdata = &ss->bm->vdata;
pdata = &ss->bm->pdata;
break;
case PBVH_FACES:
pdata = ss->pdata;
vdata = ss->vdata;
break;
case PBVH_GRIDS:
pdata = ss->pdata;
break;
}
switch (domain) {
case ATTR_DOMAIN_POINT:
data = vdata;
break;
case ATTR_DOMAIN_FACE:
data = pdata;
break;
default:
return false;
}
if (data) {
return CustomData_get_named_layer_index(data, proptype, name) >= 0;
}
return false;
}
bool SCULPT_temp_customlayer_release(SculptSession *ss, SculptCustomLayer *scl)
{
int proptype = scl->proptype;
AttributeDomain domain = scl->domain;
if (scl->released) {
@ -1694,8 +1733,6 @@ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(const SculptSessi
bool SCULPT_vertex_has_unique_face_set(const SculptSession *ss, SculptVertRef vertex)
{
MSculptVert *mv = SCULPT_vertex_get_mdyntopo(ss, vertex);
return !SCULPT_vertex_is_boundary(ss, vertex, SCULPT_BOUNDARY_FACE_SET);
}
@ -1906,8 +1943,6 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
if (ok) {
for (int j = 0; j < 2; j += 1) {
int e = 0;
if (f_adj_v[j] != index) {
sculpt_vertex_neighbor_add(
iter, BKE_pbvh_make_vref(f_adj_v[j]), BKE_pbvh_make_eref(j ? e2 : e1), f_adj_v[j]);
@ -2085,7 +2120,6 @@ static bool neighbor_cache_begin(const SculptSession *ss)
}
ncache->totvert = totvert;
NeighborCache *old = ss->cache->ncache;
atomic_cas_ptr((void **)&ss->cache->ncache, NULL, ncache);
@ -2413,7 +2447,6 @@ SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
const SculptVertRef vertex,
SculptCornerType cornertype)
{
bool check_facesets = cornertype & SCULPT_CORNER_FACE_SET;
SculptCornerType ret = 0;
MSculptVert *mv = NULL;
@ -2473,7 +2506,6 @@ SculptBoundaryType SCULPT_vertex_is_boundary(const SculptSession *ss,
const SculptVertRef vertex,
SculptBoundaryType boundary_types)
{
bool check_facesets = boundary_types & SCULPT_BOUNDARY_FACE_SET;
MSculptVert *mv = NULL;
switch (BKE_pbvh_type(ss->pbvh)) {
@ -3195,7 +3227,6 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
}
PBVHVertexIter vd;
SculptOrigVertData orig_data;
bool modified = false;
@ -4044,7 +4075,6 @@ static float brush_strength(const Sculpt *sd,
const float feather,
const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
const Brush *brush = cache->brush; // BKE_paint_brush((Paint *)&sd->paint);
/* Primary strength input; square it to make lower values more sensitive. */
@ -5479,11 +5509,8 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
const float *offset = data->offset;
PBVHVertexIter vd;
SculptOrigVertData orig_data;
float(*proxy)[3];
// SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
SculptBrushTest test;
@ -5499,13 +5526,13 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
normalize_v3(noffset);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
// SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
SCULPT_vertex_check_origdata(ss, vd.vertex);
MSculptVert *mv = SCULPT_vertex_get_mdyntopo(ss, vd.vertex);
if (!sculpt_brush_test_sq_fn(&test, mv->origco)) {
continue;
}
/* Offset vertex. */
const float fade = SCULPT_brush_strength_factor(ss,
brush,
@ -5538,7 +5565,6 @@ static void do_draw_sharp_brush_task_cb_ex_plane(void *__restrict userdata,
const float *offset = data->offset;
PBVHVertexIter vd;
SculptOrigVertData orig_data;
float(*proxy)[3];
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@ -5662,8 +5688,6 @@ static void sculpt_stroke_cache_snap_context_init(bContext *C, Object *ob)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
cache->snap_context = ED_transform_snap_object_context_create(scene, 0);
cache->depsgraph = depsgraph;
@ -6491,7 +6515,6 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
const bool use_geodesic_dists = brush->flag2 & BRUSH_USE_SURFACE_FALLOFF;
int i = 0;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
@ -7304,7 +7327,6 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.vertex,
thread_id);
const int vi = vd.index;
float *disp_factor;
if (use_persistent_base) {
@ -9687,9 +9709,6 @@ static void get_nodes_undo(Sculpt *sd,
BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
}
Brush *oldbrush = ss->cache->brush;
Brush _dummy = *brush, *brush2 = &_dummy;
if (ss->cache->original) {
SculptThreadedTaskData task_data = {
.sd = sd,
@ -9743,8 +9762,6 @@ static void SCULPT_run_command(
brush2->curve = ch->curve.curve;
}
const bool use_original = sculpt_tool_needs_original(cmd->tool) ? true : ss->cache->original;
// Load parameters into brush2 for compatibility with old code
// Make sure to remove all pen pressure/tilt old code
BKE_brush_channelset_compat_load(cmd->params_mapped, brush2, false);
@ -9999,8 +10016,8 @@ static void SCULPT_run_commandlist(
BRUSHSET_SET_FLOAT(ss->cache->channels_final, projection, projection);
}
int totnode;
PBVHNode **nodes;
int totnode = 0;
PBVHNode **nodes = NULL;
float start_radius = ss->cache->radius;
@ -11369,6 +11386,8 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
// printf("pressure: %f\n", cache->pressure);
}
cache->input_mapping.random = BLI_thread_frand(0);
cache->x_tilt = RNA_float_get(ptr, "x_tilt");
cache->y_tilt = RNA_float_get(ptr, "y_tilt");
cache->input_mapping.xtilt = cache->x_tilt;
@ -11391,7 +11410,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
direction[3] = 0.0f;
mul_v4_m4v4(direction, cache->projection_mat, direction);
cache->input_mapping.angle = atan2(direction[1], direction[0]);
cache->input_mapping.angle = (atan2(direction[1], direction[0]) / (float)M_PI) * 0.5 + 0.5;
// cache->vc
}
@ -12624,8 +12643,6 @@ static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
SculptCustomLayer *scl_co, *scl_no, *scl_disp;
SculptLayerParams params = {.permanent = true, .simple_array = false};
SCULPT_ensure_persistent_layers(ss);
scl_co = ss->custom_layers[SCULPT_SCL_PERS_CO];
@ -14593,7 +14610,6 @@ int SCULPT_vertex_valence_get(const struct SculptSession *ss, SculptVertRef vert
{
SculptVertexNeighborIter ni;
int tot = 0;
int mval = -1;
#if 0
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {

View File

@ -1171,6 +1171,7 @@ typedef struct UVSmoothVert {
BMLoop *ls[MAXUVLOOPS];
struct UVSmoothVert *neighbors[MAXUVNEIGHBORS];
int totloop, totneighbor;
float brushfade;
} UVSmoothVert;
typedef struct UVSmoothTri {
@ -1205,6 +1206,7 @@ typedef struct UVSolver {
double totarea2d;
double strength;
int cd_sculpt_vert;
} UVSolver;
/*that that currently this tool is *not* threaded*/
@ -1255,7 +1257,16 @@ void *uvsolver_calc_loop_key(UVSolver *solver, BMLoop *l)
intptr_t x = (intptr_t)(uv->uv[0] * 16384.0);
intptr_t y = (intptr_t)(uv->uv[1] * 16384.0);
intptr_t key = y * 16384LL + x;
intptr_t key;
MSculptVert *mv = BKE_PBVH_SCULPTVERT(solver->cd_sculpt_vert, l->v);
if ((mv->flag & SCULPTVERT_SEAM_BOUNDARY) ||
(l->e->head.hflag | l->prev->e->head.hflag) & BM_ELEM_SEAM) {
key = y * 16384LL + x;
}
else {
key = (intptr_t)l->v;
}
return POINTER_FROM_INT(key);
}
@ -1272,10 +1283,26 @@ static UVSmoothVert *uvsolver_get_vert(UVSolver *solver, BMLoop *l)
v = BLI_mempool_alloc(solver->verts);
memset(v, 0, sizeof(*v));
MSculptVert *mv = BKE_PBVH_SCULPTVERT(solver->cd_sculpt_vert, l->v);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(solver->cd_sculpt_vert, l->prev->v);
MSculptVert *mv3 = BKE_PBVH_SCULPTVERT(solver->cd_sculpt_vert, l->next->v);
v->boundary = mv->flag & SCULPTVERT_SEAM_BOUNDARY;
if ((mv->flag | mv2->flag | mv3->flag) & SCULPTVERT_SHARP_CORNER) {
v->pinned = true;
}
// copy_v2_v2(v->uv, uv->uv);
v->uv[0] = (double)uv->uv[0];
v->uv[1] = (double)uv->uv[1];
if (isnan(v->uv[0]) || !isfinite(v->uv[0])) {
v->uv[0] = 0.0f;
}
if (isnan(v->uv[1]) || !isfinite(v->uv[1])) {
v->uv[1] = 0.0f;
}
copy_v3_v3(v->co, l->v->co);
v->v = l->v;
@ -1509,9 +1536,12 @@ BLI_INLINE float uvsolver_vert_weight(UVSmoothVert *sv)
{
double w = 1.0;
if (sv->pinned || sv->boundary) {
if (sv->pinned || sv->boundary || sv->brushfade == 0.0f) {
w = 100000.0;
}
else {
return 1.0 / sv->brushfade;
}
return w;
}
@ -1642,7 +1672,7 @@ static float uvsolver_solve_step(UVSolver *solver)
sv->uv[j] = orig;
totw += 1.0 / uvsolver_vert_weight(sv);
totw += uvsolver_vert_weight(sv);
}
}
@ -1651,14 +1681,23 @@ static float uvsolver_solve_step(UVSolver *solver)
}
r1 *= -solver->strength * 0.75 * con->k / totg;
// totw = 1.0 / totw;
if (totw == 0.0) {
continue;
}
totw = 1.0 / totw;
for (int i = 0; i < con->totvert; i++) {
UVSmoothVert *sv = con->vs[i];
double w = 1.0 / (uvsolver_vert_weight(sv) * totw);
double w = uvsolver_vert_weight(sv) * totw * sv->brushfade;
w = MIN2(w, 1.0);
for (int j = 0; j < 2; j++) {
sv->uv[j] += r1 * con->gs[i][j] * w;
double off = r1 * con->gs[i][j] * w;
CLAMP(off, -0.1, 0.1);
sv->uv[j] += off;
}
}
}
@ -1815,7 +1854,7 @@ static void sculpt_uv_brush_cb(void *__restrict userdata,
void SCULPT_uv_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
Brush *brush = ss->cache ? ss->cache->brush : BKE_paint_brush(&sd->paint);
float offset[3];
const float bstrength = ss->cache->bstrength;
@ -1835,6 +1874,7 @@ void SCULPT_uv_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
BKE_curvemapping_init(brush->curve);
UVSolver *solver = uvsolver_new(cd_uv);
solver->cd_sculpt_vert = ss->cd_sculpt_vert;
solver->strength = ss->cache->bstrength;
/* Threaded loop over nodes. */
@ -1855,6 +1895,31 @@ void SCULPT_uv_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
uvsolver_solve_begin(solver);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
BLI_mempool_iter iter;
BLI_mempool_iternew(solver->verts, &iter);
UVSmoothVert *sv = BLI_mempool_iterstep(&iter);
for (; sv; sv = BLI_mempool_iterstep(&iter)) {
if (!sculpt_brush_test_sq_fn(&test, sv->v->co)) {
sv->brushfade = 0.0f;
continue;
}
sv->brushfade = SCULPT_brush_strength_factor(ss,
brush,
sv->v->co,
sqrtf(test.dist),
NULL,
sv->v->no,
0.0f,
(SculptVertRef){.i = (intptr_t)sv->v},
0);
}
for (int i = 0; i < 5; i++) {
uvsolver_solve_step(solver);
}

View File

@ -1014,6 +1014,7 @@ typedef struct SculptThreadedTaskData {
bool any_vertex_sampled;
float *wet_mix_sampled_color;
float hue_offset;
float *prev_mask;
float *new_mask;
@ -1933,6 +1934,10 @@ bool SCULPT_temp_customlayer_get(SculptSession *ss,
SculptCustomLayer *scl,
SculptLayerParams *params);
bool SCULPT_temp_customlayer_release(SculptSession *ss, SculptCustomLayer *scl);
bool SCULPT_temp_customlayer_has(SculptSession *ss,
AttributeDomain domain,
int proptype,
const char *name);
bool SCULPT_dyntopo_automasking_init(const SculptSession *ss,
Sculpt *sd,

View File

@ -119,6 +119,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
const Brush *brush = data->brush;
const float bstrength = fabsf(ss->cache->bstrength);
float hue_offset = data->hue_offset;
const SculptCustomLayer *buffer_scl = data->scl;
const SculptCustomLayer *stroke_id_scl = data->scl2;
@ -139,6 +140,18 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
IMB_colormanagement_srgb_to_scene_linear_v3(brush_color);
if (hue_offset != 0.5f) {
hue_offset = (hue_offset * 2.0 - 1.0) * 0.5f;
float hsv[3];
rgb_to_hsv_v(brush_color, hsv);
hsv[0] += hue_offset;
hsv[0] -= floorf(hsv[0]);
hsv_to_rgb_v(hsv, brush_color);
}
/* get un-pressure-mapped alpha */
float alpha = BKE_brush_channelset_get_final_float(
BKE_paint_brush(&data->sd->paint)->channels, data->sd->channels, "strength", NULL);
@ -349,6 +362,7 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.sd = sd,
.ob = ob,
.nodes = nodes,
.hue_offset = SCULPT_get_float(ss, hue_offset, sd, brush),
.brush = brush,
.brush_color = brush_color,
};
@ -407,6 +421,7 @@ void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.nodes = nodes,
.wet_mix_sampled_color = wet_color,
.mat = mat,
.hue_offset = SCULPT_get_float(ss, hue_offset, sd, brush),
.scl = &buffer_scl,
.scl2 = &stroke_id_scl,
.brush_color = brush_color,
@ -530,6 +545,7 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptCustomLayer prev_scl;
SculptLayerParams params = {.permanent = false, .simple_array = false};
SCULPT_temp_customlayer_ensure(
ss, ATTR_DOMAIN_POINT, CD_PROP_COLOR, "_sculpt_smear_previous", &params);
SCULPT_temp_customlayer_get(
@ -537,19 +553,6 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SCULPT_vertex_random_access_ensure(ss);
const int totvert = SCULPT_vertex_count_get(ss);
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
if (!ss->cache->prev_colors) {
ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
for (int i = 0; i < totvert; i++) {
SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i);
copy_v4_v4(ss->cache->prev_colors[i], SCULPT_vertex_color_get(ss, vertex));
}
}
}
BKE_curvemapping_init(brush->curve);
SculptThreadedTaskData data = {

View File

@ -38,6 +38,8 @@ typedef struct BrushMapping {
short blendmode;
short input_channel;
int flag, type;
float min, max;
} BrushMapping;
typedef struct BrushCurve {
@ -59,7 +61,7 @@ typedef struct BrushChannel {
float vector[4];
BrushCurve curve;
BrushMapping mappings[5]; // should always be BRUSH_MAPPING_MAX
BrushMapping mappings[6]; // should always be BRUSH_MAPPING_MAX
short type, ui_order;
int flag;
@ -88,7 +90,8 @@ typedef enum {
BRUSH_MAPPING_YTILT = 2,
BRUSH_MAPPING_ANGLE = 3,
BRUSH_MAPPING_SPEED = 4,
BRUSH_MAPPING_MAX = 5 // see BrushChannel.mappings
BRUSH_MAPPING_RANDOM = 5,
BRUSH_MAPPING_MAX = 6 // see BrushChannel.mappings
} BrushMappingType;
#ifndef __GNUC__

View File

@ -646,6 +646,7 @@ static EnumPropertyItem mapping_type_items[] = {
{BRUSH_MAPPING_YTILT, "YTILT", ICON_NONE, "Y Tilt"},
{BRUSH_MAPPING_ANGLE, "ANGLE", ICON_NONE, "Angle"},
{BRUSH_MAPPING_SPEED, "SPEED", ICON_NONE, "Speed"},
{BRUSH_MAPPING_RANDOM, "RANDOM", ICON_NONE, "Random"},
{0, NULL, 0, NULL, NULL},
};
@ -658,6 +659,25 @@ void RNA_def_brush_mapping(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "BrushMapping");
RNA_def_struct_ui_text(srna, "Brush Mapping", "Brush Mapping");
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "BrushMapping", "factor");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Factor", "Mapping factor");
prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, "BrushMapping", "min");
RNA_def_property_range(prop, -100000, 100000);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.001, 3);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Min", "");
prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, "BrushMapping", "max");
RNA_def_property_range(prop, -100000, 100000);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.001, 3);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Max", "");
prop = RNA_def_property(srna, "inherit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, "BrushMapping", "flag", BRUSH_MAPPING_INHERIT);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
@ -690,6 +710,19 @@ void RNA_def_brush_mapping(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Enabled", "Input Mapping Is Enabled");
static EnumPropertyItem blend_items[] = {
{MA_RAMP_BLEND, "MIX", ICON_NONE, "Mix", ""},
{MA_RAMP_MULT, "MULTIPLY", ICON_NONE, "Multiply", ""},
{MA_RAMP_DIV, "DIVIDE", ICON_NONE, "Divide", ""},
{MA_RAMP_ADD, "ADD", ICON_NONE, "Add", ""},
{MA_RAMP_SUB, "SUBTRACT", ICON_NONE, "Subtract", ""},
{MA_RAMP_DIFF, "DIFFERENCE", ICON_NONE, "Difference", ""},
{0, NULL, 0, NULL, NULL}};
prop = RNA_def_property(srna, "blendmode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, blend_items);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Blend Mode", "Input mapping blend mode");
prop = RNA_def_property(srna, "ui_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, "BrushMapping", "flag", BRUSH_MAPPING_UI_EXPANDED);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);