Sculpt: Add a curve brush channel type

* Added a new curve brush channel type
* Added a BKE_brush_curve_strength_ex method
  that just takes preset and curve as arguments,
  instead of pulling them from Brush.
* Autosmooth and topology rake now have their
  own falloff curves.
This commit is contained in:
Joseph Eagar 2021-09-23 16:11:29 -07:00
parent 99c0ee0558
commit ccb3ca41cd
12 changed files with 389 additions and 59 deletions

View File

@ -31,6 +31,22 @@ channel_name_map = {
};
expand_channels = {"direction"}
def template_curve(layout, base, propname, full_path):
layout.template_curve_mapping(base, propname, brush=True)
path = full_path
col = layout.column(align=True)
row = col.row(align=True)
shapes = ['SMOOTH', 'ROUND', 'ROOT', 'SHARP', 'LINE', 'MAX']
icons = ['SMOOTHCURVE', 'SPHERECURVE', 'ROOTCURVE', 'SHARPCURVE', 'LINCURVE', 'NOCURVE']
for i, shape in enumerate(shapes):
props = row.operator("brush.curve_preset_load", icon=icons[i], text="")
props.shape = shape
props.path = path
class UnifiedPaintPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@ -144,7 +160,7 @@ class UnifiedPaintPanel:
typeprop = "color3_value"
elif ch.type == "VEC4":
typeprop = "color4_value"
if text is None:
s = prop_name.lower().replace("_", " ").split(" ");
text = ''
@ -181,7 +197,13 @@ class UnifiedPaintPanel:
row.prop(ch, "show_in_workspace", text="", icon="HIDE_OFF")
#row.prop(ch, "ui_order", text="")
if ch.type == "BITMASK":
if ch.type == "CURVE":
row.prop(finalch.curve, "curve_preset")
if finalch.curve.curve_preset == "CUSTOM":
path2 = path + ".curve.curve"
template_curve(layout, finalch.curve, "curve", path2)
elif ch.type == "BITMASK":
row.label(text=text)
if header:
@ -201,7 +223,7 @@ class UnifiedPaintPanel:
else:
row.prop(finalch, typeprop, icon=icon, text=text, slider=slider)
pressure = pressure and ch.type not in ["BOOL", "ENUM", "BITMASK"]
pressure = pressure and ch.type not in ["BOOL", "ENUM", "BITMASK", "CURVE"]
if pressure:
row.prop(finalch.mappings["PRESSURE"], "enabled", text="", icon="STYLUS_PRESSURE")
@ -213,14 +235,14 @@ class UnifiedPaintPanel:
#if unified_name and not header:
# # 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":
if not header:
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" or ch.type == "BOOL":
if ch.type in ["BITMASK", "BOOL", "CURVE"]:
return
if not ui_editing and not show_reorder:
@ -792,12 +814,18 @@ def brush_settings(layout, context, brush, popover=False):
"auto_smooth_radius_factor",
slider=True
)
UnifiedPaintPanel.channel_unified(
box,
context,
brush,
"autosmooth_falloff_curve"
)
elif brush.sculpt_tool == "SMOOTH":
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"auto_smooth_projection",
"projection",
slider=True
)
@ -847,7 +875,21 @@ def brush_settings(layout, context, brush, popover=False):
slider=True
)
box.prop(brush, "use_curvature_rake")
UnifiedPaintPanel.channel_unified(
box,
context,
brush,
"topology_rake_mode",
expand=True
)
UnifiedPaintPanel.channel_unified(
box,
context,
brush,
"topology_rake_falloff_curve"
)
#box.prop(brush, "use_curvature_rake")
box.prop(brush, "ignore_falloff_for_topology_rake")
if context.sculpt_object.use_dynamic_topology_sculpting:

View File

@ -38,6 +38,7 @@ struct ToolSettings;
struct UnifiedPaintSettings;
struct DynTopoSettings;
struct Sculpt;
struct CurveMapping;
// enum eCurveMappingPreset;
@ -166,6 +167,10 @@ bool BKE_brush_hard_edge_mode_get(const struct Scene *scene, const struct Brush
void BKE_brush_hard_edge_mode_set(struct Scene *scene, struct Brush *brush, bool val);
float BKE_brush_fset_slide_get(const struct Scene *scene, const struct Brush *brush);
float BKE_brush_curve_strength_ex(int curve_preset,
const struct CurveMapping *curve,
float p,
const float len);
#ifdef __cplusplus
}

View File

@ -65,6 +65,8 @@ struct Sculpt;
BKE_brush_channelset_get_float(chset, MAKE_BUILTIN_CH_NAME(channel), mapdata)
#define BRUSHSET_GET_INT(chset, channel, mapdata) \
BKE_brush_channelset_get_int(chset, MAKE_BUILTIN_CH_NAME(channel), mapdata)
#define BRUSHSET_ENSURE_BUILTIN(chset, channel) \
BKE_brush_channelset_ensure_builtin(chset, MAKE_BUILTIN_CH_NAME(channel))
//#define DEBUG_CURVE_MAPPING_ALLOC
#ifdef DEBUG_CURVE_MAPPING_ALLOC
@ -109,6 +111,7 @@ typedef struct BrushChannelType {
int ivalue;
float fvalue;
float vector[4];
int curve_preset;
BrushEnumDef enumdef[MAX_BRUSH_ENUM_DEF]; // for enum/bitmask types
EnumPropertyItem *rna_enumdef;
@ -165,8 +168,8 @@ BrushChannel *BKE_brush_channelset_lookup(BrushChannelSet *chset, const char *id
bool BKE_brush_channelset_has(BrushChannelSet *chset, const char *idname);
void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname);
bool BKE_brush_channelset_ensure_builtin(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_channelset_merge(BrushChannelSet *dst,
BrushChannelSet *child,
@ -217,6 +220,11 @@ void BKE_brush_channelset_set_final_float(BrushChannelSet *child,
void BKE_brush_channel_set_vector(BrushChannel *ch, float vec[4]);
int BKE_brush_channel_get_vector_size(BrushChannel *ch);
float BKE_brush_channel_curve_evaluate(BrushChannel *ch, float val, const float maxval);
CurveMapping *BKE_brush_channel_curvemapping_get(BrushCurve *curve, bool force_create);
bool BKE_brush_channel_curve_ensure_write(BrushCurve *curve);
void BKE_brush_channel_curve_assign(BrushChannel *ch, BrushCurve *curve);
/* returns size of vector */
int BKE_brush_channel_get_vector(BrushChannel *ch, float out[4], BrushMappingData *mapdata);

View File

@ -2675,8 +2675,10 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
}
}
/* Uses the brush curve control to find a strength value */
ATTR_NO_OPT float BKE_brush_curve_strength(const Brush *br, float p, const float len)
ATTR_NO_OPT float BKE_brush_curve_strength_ex(int curve_preset,
const CurveMapping *curve,
float p,
const float len)
{
float strength = 1.0f;
@ -2687,9 +2689,9 @@ ATTR_NO_OPT float BKE_brush_curve_strength(const Brush *br, float p, const float
p = p / len;
p = 1.0f - p;
switch (br->curve_preset) {
switch (curve_preset) {
case BRUSH_CURVE_CUSTOM:
strength = BKE_curvemapping_evaluateF(br->curve, 0, 1.0f - p);
strength = BKE_curvemapping_evaluateF(curve, 0, 1.0f - p);
break;
case BRUSH_CURVE_SHARP:
strength = p * p;
@ -2723,6 +2725,12 @@ ATTR_NO_OPT float BKE_brush_curve_strength(const Brush *br, float p, const float
return strength;
}
/* Uses the brush curve control to find a strength value */
ATTR_NO_OPT float BKE_brush_curve_strength(const Brush *br, float p, const float len)
{
return BKE_brush_curve_strength_ex(br->curve_preset, br->curve, p, len);
}
/* Uses the brush curve control to find a strength value between 0 and 1 */
float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len)
{

View File

@ -58,6 +58,9 @@ places in rna_engine_codebase are relevent:
# ifdef MAKE_FLAGS_EX
# undef MAKE_FLAGS_EX
# endif
# ifdef MAKE_CURVE
# undef MAKE_CURVE
# endif
# ifdef MAKE_BUILTIN_CH_DEF
# undef MAKE_BUILTIN_CH_DEF
@ -90,7 +93,7 @@ places in rna_engine_codebase are relevent:
# define MAKE_FLAGS(idname1, name1, tooltip1, value1, enumdef1) MAKE_BUILTIN_CH_DEF(idname1);
# define MAKE_FLAGS_EX(idname1, name1, tooltip1, value1, enumdef1, flag1) \
MAKE_BUILTIN_CH_DEF(idname1);
# define MAKE_CURVE(idname1, name1, tooltip1, preset1) MAKE_BUILTIN_CH_DEF(idname1);
#else
#endif
@ -317,6 +320,10 @@ MAKE_ENUM(deform_target, "Deformation Target", "How the deformation of the brush
{-1}
}))
MAKE_CURVE(autosmooth_falloff_curve, "Falloff", "Custom curve for autosmooth", BRUSH_CURVE_SMOOTH)
MAKE_CURVE(topology_rake_falloff_curve, "Falloff", "Custom curve for topolgoy rake", BRUSH_CURVE_SMOOTH)
MAKE_CURVE(falloff_curve, "Falloff", "Falloff curve", BRUSH_CURVE_SMOOTH)
/* clang-format on */
#if defined(BRUSH_CHANNEL_DEFINE_TYPES) || defined(BRUSH_CHANNEL_DEFINE_EXTERNAL)
# ifdef MAKE_FLOAT
@ -366,4 +373,8 @@ MAKE_ENUM(deform_target, "Deformation Target", "How the deformation of the brush
# ifdef MAKE_BUILTIN_CH_DEF
# undef MAKE_BUILTIN_CH_DEF
# endif
# ifdef MAKE_CURVE
# undef MAKE_CURVE
# endif
#endif

View File

@ -95,6 +95,39 @@ bool BKE_brush_mapping_ensure_write(BrushMapping *mp)
return false;
}
void BKE_brush_channel_curve_assign(BrushChannel *ch, BrushCurve *curve)
{
RELEASE_OR_FREE_CURVE(ch->curve.curve);
if (curve->curve) {
if (IS_CACHE_CURVE(curve->curve)) {
ch->curve.curve = curve->curve;
CURVE_ADDREF(curve->curve);
}
else {
ch->curve.curve = BKE_curvemapping_copy(curve->curve);
}
}
else {
ch->curve.curve = NULL;
}
ch->curve.preset = curve->preset;
}
// returns true if curve was duplicated
bool BKE_brush_channel_curve_ensure_write(BrushCurve *curve)
{
BKE_brush_channel_curvemapping_get(curve, true);
if (IS_CACHE_CURVE(curve->curve)) {
curve->curve = BKE_curvemapping_copy(curve->curve);
return true;
}
return false;
}
ATTR_NO_OPT static bool check_corrupted_curve(BrushMapping *dst)
{
CurveMapping *curve = dst->curve;
@ -178,6 +211,10 @@ ATTR_NO_OPT void BKE_brush_channeltype_rna_check(BrushChannelType *def,
ATTR_NO_OPT void BKE_brush_channel_free_data(BrushChannel *ch)
{
if (ch->curve.curve) {
RELEASE_OR_FREE_CURVE(ch->curve.curve);
}
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMapping *mp = ch->mappings + i;
@ -193,6 +230,15 @@ ATTR_NO_OPT void BKE_brush_channel_free(BrushChannel *ch)
ATTR_NO_OPT void BKE_brush_channel_copy_data(BrushChannel *dst, BrushChannel *src)
{
if (src->type == BRUSH_CHANNEL_CURVE) {
if (dst->curve.curve && IS_CACHE_CURVE(dst->curve.curve)) {
RELEASE_CACHE_CURVE(dst->curve.curve);
}
else if (dst->curve.curve) {
BKE_curvemapping_free(dst->curve.curve);
}
}
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMapping *mp = dst->mappings + i;
@ -215,6 +261,19 @@ ATTR_NO_OPT void BKE_brush_channel_copy_data(BrushChannel *dst, BrushChannel *sr
*dst = *src;
if (src->curve.curve) {
if (!IS_CACHE_CURVE(src->curve.curve)) {
// dst->curve = GET_CACHE_CURVE(src->curve);
// hrm, let's not modify src->curve, GET_CACHE_CURVE might free it
dst->curve.curve = BKE_curvemapping_cache_get(
BKE_curvemapping_cache_global(), src->curve.curve, false);
}
else {
CURVE_ADDREF(dst->curve.curve);
}
}
dst->next = next;
dst->prev = prev;
@ -244,6 +303,7 @@ ATTR_NO_OPT void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def)
ch->flag = def->flag;
ch->curve.preset = def->curve_preset;
ch->fvalue = def->fvalue;
ch->ivalue = def->ivalue;
@ -302,6 +362,31 @@ ATTR_NO_OPT void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def)
}
}
CurveMapping *BKE_brush_channel_curvemapping_get(BrushCurve *curve, bool force_create)
{
if ((force_create || curve->preset == BRUSH_CURVE_CUSTOM) && !curve->curve) {
CurveMapping *cumap = curve->curve = MEM_callocN(sizeof(CurveMapping), "channel CurveMapping");
BKE_curvemapping_set_defaults(cumap, 1, 0.0f, 0.0f, 1.0f, 1.0f);
BKE_curvemap_reset(cumap->cm,
&(struct rctf){.xmin = 0, .ymin = 0.0, .xmax = 1.0, .ymax = 1.0},
CURVE_PRESET_LINE,
1);
BKE_curvemapping_init(cumap);
}
return curve->curve;
}
float BKE_brush_channel_curve_evaluate(BrushChannel *ch, float val, const float maxval)
{
BKE_brush_channel_curvemapping_get(&ch->curve, false);
return BKE_brush_curve_strength_ex(ch->curve.preset, ch->curve.curve, val, maxval);
}
BrushChannelSet *BKE_brush_channelset_create()
{
BrushChannelSet *chset = (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet),
@ -482,13 +567,14 @@ ATTR_NO_OPT BrushChannelType *BKE_brush_builtin_channel_def_find(const char *nam
return NULL;
}
ATTR_NO_OPT void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname)
ATTR_NO_OPT BrushChannel *BKE_brush_channelset_add_builtin(BrushChannelSet *chset,
const char *idname)
{
BrushChannelType *def = BKE_brush_builtin_channel_def_find(idname);
if (!def) {
printf("%s: Could not find brush %s\n", __func__, idname);
return;
return NULL;
}
namestack_push(__func__);
@ -499,20 +585,25 @@ ATTR_NO_OPT void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const
BKE_brush_channelset_add(chset, ch);
namestack_pop(NULL);
return ch;
}
bool BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname)
BrushChannel *BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname)
{
namestack_push(__func__);
if (!BKE_brush_channelset_has(chset, idname)) {
BKE_brush_channelset_add_builtin(chset, idname);
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
if (ch) {
namestack_pop(NULL);
return true;
return ch;
}
ch = BKE_brush_channelset_add_builtin(chset, idname);
namestack_pop(NULL);
return false;
return ch;
}
ATTR_NO_OPT void BKE_brush_channelset_ensure_existing(BrushChannelSet *chset,
@ -1216,14 +1307,14 @@ BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool)
ADDCH("strength");
ADDCH("fset_slide");
ADDCH("boundary_smooth");
ADDCH("autosmooth_projection");
ADDCH("projection");
break;
case SCULPT_TOOL_TOPOLOGY_RAKE:
ADDCH("radius");
ADDCH("strength");
// ADDCH("fset_slide");
// ADDCH("boundary_smooth");
ADDCH("autosmooth_projection");
ADDCH("projection");
ADDCH("topology_rake_mode");
break;
case SCULPT_TOOL_DYNTOPO:
@ -1235,7 +1326,10 @@ BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool)
return command;
}
static void float_set_uninherit(BrushChannelSet *chset, const char *channel, float val)
#define float_set_uninherit(chset, channel, val) \
_float_set_uninherit(chset, MAKE_BUILTIN_CH_NAME(channel), val)
static void _float_set_uninherit(BrushChannelSet *chset, const char *channel, float val)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, channel);
@ -1289,10 +1383,22 @@ ATTR_NO_OPT static void bke_builtin_commandlist_create_paint(Brush *brush,
float autosmooth = BRUSHSET_GET_FLOAT(chset, autosmooth, mapdata);
if (autosmooth > 0.0f) {
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true), SCULPT_TOOL_SMOOTH);
float_set_uninherit(cmd->params, "strength", autosmooth);
float_set_uninherit(cmd->params, "radius", radius * autosmooth_scale);
float_set_uninherit(cmd->params, "projection", autosmooth_projection);
float_set_uninherit(cmd->params, "spacing", autosmooth_spacing);
BrushChannel *ch = BRUSHSET_ENSURE_BUILTIN(cmd->params, falloff_curve);
BrushChannel *ch2 = BRUSHSET_LOOKUP(chset, autosmooth_falloff_curve);
if (ch2) {
BKE_brush_channel_curve_assign(ch, &ch2->curve);
ch->flag &= ~BRUSH_CHANNEL_INHERIT;
}
else {
ch->flag |= BRUSH_CHANNEL_INHERIT;
}
float_set_uninherit(cmd->params, strength, autosmooth);
float_set_uninherit(cmd->params, radius, radius * autosmooth_scale);
float_set_uninherit(cmd->params, projection, autosmooth_projection);
float_set_uninherit(cmd->params, spacing, autosmooth_spacing);
}
float vcol_boundary = BKE_brush_channelset_get_float(chset, "vcol_boundary_factor", mapdata);
@ -1301,9 +1407,10 @@ ATTR_NO_OPT static void bke_builtin_commandlist_create_paint(Brush *brush,
if (vcol_boundary > 0.0f) {
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true),
SCULPT_TOOL_VCOL_BOUNDARY);
float_set_uninherit(cmd->params, "radius", radius * GETF("vcol_boundary_radius_scale"));
float_set_uninherit(cmd->params, "spacing", GETF("vcol_boundary_spacing"));
float_set_uninherit(cmd->params, "strength", vcol_boundary);
float_set_uninherit(cmd->params, radius, radius * GETF("vcol_boundary_radius_scale"));
float_set_uninherit(cmd->params, spacing, GETF("vcol_boundary_spacing"));
float_set_uninherit(cmd->params, strength, vcol_boundary);
}
#undef GETF
@ -1319,6 +1426,7 @@ ATTR_NO_OPT void BKE_builtin_commandlist_create(Brush *brush,
BrushMappingData *mapdata)
{
BrushCommand *cmd;
BrushChannel *ch;
/* add main tool */
if (ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
@ -1340,6 +1448,17 @@ ATTR_NO_OPT void BKE_builtin_commandlist_create(Brush *brush,
float autosmooth_projection = BKE_brush_channelset_get_float(
chset, "autosmooth_projection", NULL);
bool is_cloth = tool = SCULPT_TOOL_CLOTH;
is_cloth = is_cloth ||
(ELEM(tool, SCULPT_TOOL_BOUNDARY, SCULPT_TOOL_POSE) &&
BRUSHSET_GET_INT(chset, deform_target, mapdata) == BRUSH_DEFORM_TARGET_CLOTH_SIM);
float cloth_radius_mul = 1.0f;
if (is_cloth && (ch = BRUSHSET_LOOKUP(chset, cloth_sim_limit))) {
autosmooth_scale *= ch->fvalue;
cloth_radius_mul = ch->fvalue;
}
float autosmooth_spacing;
if (BKE_brush_channelset_get_int(chset, "autosmooth_use_spacing", mapdata)) {
@ -1352,14 +1471,27 @@ ATTR_NO_OPT void BKE_builtin_commandlist_create(Brush *brush,
float autosmooth = BKE_brush_channelset_get_float(chset, "autosmooth", mapdata);
if (!no_autosmooth && autosmooth > 0.0f) {
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true), SCULPT_TOOL_SMOOTH);
float_set_uninherit(cmd->params, "strength", autosmooth);
float_set_uninherit(cmd->params, "radius", radius * autosmooth_scale);
float_set_uninherit(cmd->params, "projection", autosmooth_projection);
float_set_uninherit(cmd->params, "spacing", autosmooth_spacing);
BrushChannel *ch = BRUSHSET_ENSURE_BUILTIN(cmd->params, falloff_curve);
BrushChannel *ch2 = BRUSHSET_LOOKUP(chset, autosmooth_falloff_curve);
if (ch2) {
BKE_brush_channel_curve_assign(ch, &ch2->curve);
ch->flag &= ~BRUSH_CHANNEL_INHERIT;
}
else {
ch->flag |= BRUSH_CHANNEL_INHERIT;
}
float_set_uninherit(cmd->params, strength, autosmooth);
float_set_uninherit(cmd->params, radius, radius * autosmooth_scale);
float_set_uninherit(cmd->params, projection, autosmooth_projection);
float_set_uninherit(cmd->params, spacing, autosmooth_spacing);
}
float topology_rake_scale = BKE_brush_channelset_get_float(
chset, "topology_rake_radius_scale", mapdata);
chset, "topology_rake_radius_scale", mapdata) *
cloth_radius_mul;
float topology_rake_projection = BKE_brush_channelset_get_float(
chset, "topology_rake_projection", mapdata);
@ -1379,10 +1511,21 @@ ATTR_NO_OPT void BKE_builtin_commandlist_create(Brush *brush,
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl, chset, true),
SCULPT_TOOL_TOPOLOGY_RAKE);
float_set_uninherit(cmd->params, "strength", topology_rake);
float_set_uninherit(cmd->params, "radius", radius * topology_rake_scale);
float_set_uninherit(cmd->params, "projection", topology_rake_projection);
float_set_uninherit(cmd->params, "spacing", topology_rake_spacing);
BrushChannel *ch = BRUSHSET_ENSURE_BUILTIN(cmd->params, falloff_curve);
BrushChannel *ch2 = BRUSHSET_LOOKUP(chset, topology_rake_falloff_curve);
if (ch2) {
BKE_brush_channel_curve_assign(ch, &ch2->curve);
ch->flag &= ~BRUSH_CHANNEL_INHERIT;
}
else {
ch->flag |= BRUSH_CHANNEL_INHERIT;
}
float_set_uninherit(cmd->params, strength, topology_rake);
float_set_uninherit(cmd->params, radius, radius * topology_rake_scale);
float_set_uninherit(cmd->params, projection, topology_rake_projection);
float_set_uninherit(cmd->params, spacing, topology_rake_spacing);
}
/* build dyntopo command */
@ -1395,8 +1538,8 @@ ATTR_NO_OPT void BKE_builtin_commandlist_create(Brush *brush,
radius2 *= radius;
float_set_uninherit(cmd->params, "spacing", spacing);
float_set_uninherit(cmd->params, "radius", radius2);
float_set_uninherit(cmd->params, spacing, spacing);
float_set_uninherit(cmd->params, radius, radius2);
}
BKE_brush_commandset_inherit_all_mappings(cmd->params);
@ -1417,6 +1560,12 @@ ATTR_NO_OPT void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannel
BLI_ghash_insert(chset->namemap, ch->idname, ch);
BLO_read_data_address(reader, &ch->curve.curve);
if (ch->curve.curve) {
BKE_curvemapping_blend_read(reader, ch->curve.curve);
BKE_curvemapping_init(ch->curve.curve);
}
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMapping *mp = ch->mappings + i;
@ -1467,6 +1616,10 @@ ATTR_NO_OPT void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet
BrushChannel *ch;
for (ch = chset->channels.first; ch; ch = ch->next) {
if (ch->curve.curve) {
BKE_curvemapping_blend_write(writer, ch->curve.curve);
}
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BKE_brush_mapping_ensure_write(ch->mappings + i);
BKE_curvemapping_blend_write(writer, ch->mappings[i].curve);

View File

@ -151,6 +151,15 @@ MAKE_FLOAT_EX_EX(idname1, name1, tooltip1, value1, min1, max1, smin1, smax1, pre
#define MAKE_FLAGS(idname1, name1, tooltip1, value1, enumdef1) MAKE_FLAGS_EX(idname1, name1, tooltip1, value1, enumdef1, 0)
#define MAKE_ENUM(idname1, name1, tooltip1, value1, enumdef1) MAKE_ENUM_EX(idname1, name1, tooltip1, value1, enumdef1, 0)
#define MAKE_CURVE(idname1, name1, tooltip1, preset1)\
{\
.idname = #idname1,\
.name = name1,\
.tooltip = tooltip1,\
.type = BRUSH_CHANNEL_CURVE,\
.curve_preset = preset1,\
},
/*
This is where all the builtin brush channels are defined.
That includes per-brush enums and bitflags!
@ -632,6 +641,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(autosmooth_spacing);
ADDCH(autosmooth_use_spacing);
ADDCH(autosmooth_projection);
ADDCH(autosmooth_falloff_curve);
ADDCH(vcol_boundary_exponent);
ADDCH(vcol_boundary_factor);
@ -644,6 +654,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(topology_rake_use_spacing);
ADDCH(topology_rake_spacing);
ADDCH(topology_rake_projection);
ADDCH(topology_rake_falloff_curve);
ADDCH(hardness);
ADDCH(tip_roundness);
@ -975,6 +986,19 @@ void BKE_brush_check_toolsettings(Sculpt *sd)
ADDCH(automasking);
ADDCH(topology_rake_mode);
ADDCH(autosmooth);
ADDCH(autosmooth_projection);
ADDCH(autosmooth_radius_scale);
ADDCH(autosmooth_spacing);
ADDCH(autosmooth_falloff_curve);
ADDCH(topology_rake_radius_scale);
ADDCH(topology_rake_projection);
ADDCH(topology_rake_use_spacing);
ADDCH(topology_rake_spacing);
ADDCH(topology_rake);
ADDCH(topology_rake_falloff_curve);
ADDCH(vcol_boundary_exponent);
ADDCH(vcol_boundary_factor);
ADDCH(vcol_boundary_radius_scale);

View File

@ -9096,6 +9096,13 @@ ATTR_NO_OPT static void SCULPT_run_command_list(
for (int step = 0; step < list->totcommand; step++) {
BrushCommand *cmd = list->commands + step;
float radius = BRUSHSET_GET_FLOAT(cmd->params_final, radius, NULL);
radius = paint_calc_object_space_radius(ss->cache->vc, ss->cache->true_location, radius);
ss->cache->radius = radius;
ss->cache->radius_squared = radius * radius;
radius_scale = 1.0f;
BKE_brush_channelset_free(cmd->params_mapped);
cmd->params_mapped = BKE_brush_channelset_copy(cmd->params_final);
BKE_brush_channelset_apply_mapping(cmd->params_mapped, &ss->cache->input_mapping);
@ -9120,6 +9127,12 @@ ATTR_NO_OPT static void SCULPT_run_command_list(
*brush2 = *brush;
BrushChannel *ch = BRUSHSET_LOOKUP(cmd->params_final, falloff_curve);
if (ch) {
brush2->curve_preset = ch->curve.preset;
brush2->curve = ch->curve.curve;
}
// 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);

View File

@ -1150,8 +1150,12 @@ ATTR_NO_OPT static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
if (modified && weighted) {
BKE_pbvh_node_mark_update_tri_area(data->nodes[n]);
if (modified) {
if (weighted) {
BKE_pbvh_node_mark_update_tri_area(data->nodes[n]);
}
BKE_pbvh_node_mark_update(data->nodes[n]);
}
}
#endif

View File

@ -40,6 +40,11 @@ typedef struct BrushMapping {
int flag, type;
} BrushMapping;
typedef struct BrushCurve {
CurveMapping *curve;
int preset, _pad[1]; // see eBrushCurvePreset, this differs from the one in BrushMappingDef
} BrushCurve;
typedef struct BrushChannel {
struct BrushChannel *next, *prev;
@ -51,6 +56,8 @@ typedef struct BrushChannel {
float fvalue;
int ivalue;
float vector[4];
BrushCurve curve;
BrushMapping mappings[5]; // should always be BRUSH_MAPPING_MAX
short type, ui_order;
@ -109,5 +116,6 @@ enum {
BRUSH_CHANNEL_BITMASK = 1 << 3,
BRUSH_CHANNEL_BOOL = 1 << 4,
BRUSH_CHANNEL_VEC3 = 1 << 5,
BRUSH_CHANNEL_VEC4 = 1 << 6
BRUSH_CHANNEL_VEC4 = 1 << 6,
BRUSH_CHANNEL_CURVE = 1 << 7
};

View File

@ -2088,6 +2088,20 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
}
const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{BRUSH_CURVE_SMOOTHER, "SMOOTHER", ICON_SMOOTHCURVE, "Smoother", ""},
{BRUSH_CURVE_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{BRUSH_CURVE_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{BRUSH_CURVE_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{BRUSH_CURVE_LIN, "LIN", ICON_LINCURVE, "Linear", ""},
{BRUSH_CURVE_POW4, "POW4", ICON_SHARPCURVE, "Sharper", ""},
{BRUSH_CURVE_INVSQUARE, "INVSQUARE", ICON_INVERSESQUARECURVE, "Inverse Square", ""},
{BRUSH_CURVE_CONSTANT, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, NULL, 0, NULL, NULL},
};
static void rna_def_brush(BlenderRNA *brna)
{
StructRNA *srna;
@ -2250,20 +2264,6 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{BRUSH_CURVE_SMOOTHER, "SMOOTHER", ICON_SMOOTHCURVE, "Smoother", ""},
{BRUSH_CURVE_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{BRUSH_CURVE_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{BRUSH_CURVE_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{BRUSH_CURVE_LIN, "LIN", ICON_LINCURVE, "Linear", ""},
{BRUSH_CURVE_POW4, "POW4", ICON_SHARPCURVE, "Sharper", ""},
{BRUSH_CURVE_INVSQUARE, "INVSQUARE", ICON_INVERSESQUARECURVE, "Inverse Square", ""},
{BRUSH_CURVE_CONSTANT, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem brush_deformation_target_items[] = {
{BRUSH_DEFORM_TARGET_GEOMETRY,
"GEOMETRY",

View File

@ -147,6 +147,16 @@ PointerRNA rna_BrushMapping_curve_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, mapping->curve);
}
PointerRNA rna_BrushCurve_curve_get(PointerRNA *ptr)
{
BrushCurve *curve = (BrushCurve *)ptr->data;
// make sure we can write to curve
BKE_brush_channel_curve_ensure_write(curve);
return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, curve->curve);
}
int rna_BrushChannel_mappings_begin(CollectionPropertyIterator *iter, struct PointerRNA *ptr)
{
BrushChannel *ch = ptr->data;
@ -345,8 +355,47 @@ EnumPropertyItem channel_types[] = {{BRUSH_CHANNEL_FLOAT, "FLOAT", ICON_NONE, "F
{BRUSH_CHANNEL_BOOL, "BOOL", ICON_NONE, "Boolean"},
{BRUSH_CHANNEL_VEC3, "VEC3", ICON_NONE, "Color3"},
{BRUSH_CHANNEL_VEC4, "VEC4", ICON_NONE, "Color4"},
{BRUSH_CHANNEL_CURVE, "CURVE", ICON_NONE, "Curve"},
{0, NULL, 0, NULL, NULL}};
// getting weird link errors here
// extern const EnumPropertyItem brush_curve_preset_items[];
static const EnumPropertyItem brush_curve_preset_items[] = {
{BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""},
{BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{BRUSH_CURVE_SMOOTHER, "SMOOTHER", ICON_SMOOTHCURVE, "Smoother", ""},
{BRUSH_CURVE_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{BRUSH_CURVE_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
{BRUSH_CURVE_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{BRUSH_CURVE_LIN, "LIN", ICON_LINCURVE, "Linear", ""},
{BRUSH_CURVE_POW4, "POW4", ICON_SHARPCURVE, "Sharper", ""},
{BRUSH_CURVE_INVSQUARE, "INVSQUARE", ICON_INVERSESQUARECURVE, "Inverse Square", ""},
{BRUSH_CURVE_CONSTANT, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, NULL, 0, NULL, NULL},
};
void RNA_def_brush_curve(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "BrushCurve", NULL);
RNA_def_struct_sdna(srna, "BrushCurve");
RNA_def_struct_ui_text(srna, "Brush Curve", "Brush Curve");
prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, "BrushCurve", "preset");
RNA_def_property_enum_items(prop, brush_curve_preset_items);
RNA_def_property_ui_text(prop, "Curve Preset", "");
prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_pointer_funcs(prop, "rna_BrushCurve_curve_get", NULL, NULL, NULL);
}
void RNA_def_brush_channel(BlenderRNA *brna)
{
StructRNA *srna;
@ -521,6 +570,10 @@ void RNA_def_brush_channel(BlenderRNA *brna)
"rna_BrushChannel_enum_value_get_items");
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BrushCurve");
RNA_def_property_ui_text(prop, "Curve", "Curve");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
// PROP_ENUM_FLAG
}
@ -560,6 +613,7 @@ void RNA_def_brush_channelset(BlenderRNA *brna)
void RNA_def_brush_engine(BlenderRNA *brna)
{
RNA_def_brush_curve(brna);
RNA_def_brush_mapping(brna);
RNA_def_brush_channel(brna);
RNA_def_brush_channelset(brna);