Sculpt: more brush engine stuff; do not test.

Pushing this commit early due to computer
weirdness
This commit is contained in:
2021-09-19 01:02:00 -07:00
parent 1ca57bc5f4
commit 87feba04dd
27 changed files with 2203 additions and 353 deletions

View File

@@ -19,6 +19,15 @@
# <pep8 compliant>
from bpy.types import Menu
channel_name_map = {
"size" : "RADIUS",
"autosmooth_fset_slide":"FSET_SLIDE",
"auto_smooth_factor": "AUTOSMOOTH",
"auto_smooth_projection": "SMOOTH_PROJECTION",
"auto_smooth_radius_factor": "AUTOSMOOTH_RADIUS_SCALE",
"boundary_smooth_factor": "BOUNDARY_SMOOTH",
};
class UnifiedPaintPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@@ -105,11 +114,15 @@ class UnifiedPaintPanel:
l1 = layout
if ch.ui_expanded:
layout = layout.box().column() #.column() is a bit more compact
#if ch.ui_expanded:
# layout = layout.box().column() #.column() is a bit more compact
row = layout.row(align=True)
typeprop = "float_value"
if ch.type == "INT":
typeprop = "int_value"
if text is None:
s = prop_name.lower().replace("_", " ").split(" ");
text = ''
@@ -124,7 +137,7 @@ class UnifiedPaintPanel:
finalch = sd.channels.channels[prop_name]
row.prop(finalch, "value", icon=icon, text=text, slider=slider)
row.prop(finalch, typeprop, icon=icon, text=text, slider=slider)
if pressure:
row.prop(finalch.mappings["PRESSURE"], "enabled", text="", icon="STYLUS_PRESSURE")
@@ -154,6 +167,15 @@ class UnifiedPaintPanel:
if mp.ui_expanded:
layout.template_curve_mapping(mp, "curve", brush=True)
col = layout.column(align=True)
row = col.row(align=True)
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
#row2.prop(mp, "curve")
return row
@@ -173,6 +195,16 @@ class UnifiedPaintPanel:
):
""" Generalized way of adding brush options to the UI,
along with their pen pressure setting and global toggle, if they exist. """
if prop_name in channel_name_map:
prop_name = channel_name_map[prop_name]
else:
prop_name = prop_name.upper()
if prop_name in brush.channels.channels:
# def channel_unified(layout, context, brush, prop_name, icon='NONE', pressure=True, text=None, slider=False, header=False):
return UnifiedPaintPanel.channel_unified(layout, context, brush, prop_name, icon=icon, text=text, slider=slider, header=header)
row = layout.row(align=True)
ups = context.tool_settings.unified_paint_settings
prop_owner = brush
@@ -1017,7 +1049,21 @@ def brush_shared_settings(layout, context, brush, popover=False):
size_prop = "size"
if size_mode and (size_owner.use_locked_size == 'SCENE'):
size_prop = "unprojected_radius"
if size or size_mode:
if size:
UnifiedPaintPanel.channel_unified(
layout,
context,
brush,
"RADIUS" if size_prop == "size" else size_prop.upper(),
text="Radius",
slider=True,
)
if size_mode:
layout.row().prop(size_owner, "use_locked_size", expand=True)
layout.separator()
elif size or size_mode:
if size:
UnifiedPaintPanel.prop_unified(
layout,
@@ -1033,7 +1079,7 @@ def brush_shared_settings(layout, context, brush, popover=False):
layout.row().prop(size_owner, "use_locked_size", expand=True)
layout.separator()
if 0 and strength:
if strength:
UnifiedPaintPanel.channel_unified(
layout,
context,

View File

@@ -110,8 +110,13 @@ const float *BKE_brush_color_get(const struct Scene *scene, const struct Brush *
const float *BKE_brush_secondary_color_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]);
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int size);
int BKE_brush_size_get(const struct Scene *scene,
const struct Brush *brush,
bool use_brush_channel);
void BKE_brush_size_set(struct Scene *scene,
struct Brush *brush,
int size,
bool use_brush_channel);
float BKE_brush_unprojected_radius_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_unprojected_radius_set(struct Scene *scene,

View File

@@ -44,17 +44,21 @@ is controller via BrushChannel->flag.
This should completely replace UnifiedPaintSettings.
*/
struct BrushChannel;
#include "BLO_read_write.h"
#include "DNA_sculpt_brush_types.h"
struct BrushChannel;
struct BlendWriter;
struct BlendDataReader;
struct Brush;
typedef struct BrushMappingDef {
int curve;
bool enabled;
bool inv;
float min, max;
int blendmode;
float factor; // if 0, will default to 1.0
} BrushMappingDef;
typedef struct BrushMappingPreset {
@@ -62,6 +66,10 @@ typedef struct BrushMappingPreset {
struct BrushMappingDef pressure, xtilt, ytilt, angle, speed;
} BrushMappingPreset;
typedef struct BrushMappingData {
float pressure, xtilt, ytilt, angle, speed;
} BrushMappingData;
#define MAX_BRUSH_ENUM_DEF 32
typedef struct BrushEnumDef {
@@ -69,7 +77,7 @@ typedef struct BrushEnumDef {
} BrushEnumDef;
typedef struct BrushChannelType {
char name[32], idname[32];
char name[32], idname[32], tooltip[512];
float min, max, soft_min, soft_max;
BrushMappingPreset mappings;
@@ -83,7 +91,6 @@ typedef struct BrushCommand {
int tool;
struct BrushChannelSet *params;
struct BrushChannelSet *params_final;
int totparam;
} BrushCommand;
typedef struct BrushCommandList {
@@ -117,22 +124,70 @@ void BKE_brush_channelset_merge(BrushChannelSet *dst,
BrushChannelSet *parent);
void BKE_brush_resolve_channels(struct Brush *brush, struct Sculpt *sd);
int BKE_brush_channel_get_int(BrushChannelSet *chset, char *idname);
float BKE_brush_channel_get_float(BrushChannelSet *chset, char *idname);
float BKE_brush_channel_set_float(BrushChannelSet *chset, char *idname, float val);
int BKE_brush_channelset_get_int(BrushChannelSet *chset, char *idname);
// mapdata is optional, can be NULL
float BKE_brush_channel_get_final_float(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
BrushMappingData *mapdata);
void BKE_brush_channel_set_final_float(BrushChannelSet *brushset,
BrushChannelSet *toolset,
char *idname,
float value);
/* mapdata may be NULL */
float BKE_brush_channel_get_float(BrushChannel *ch, BrushMappingData *mapdata);
void BKE_brush_channel_set_float(BrushChannel *ch, float val);
/* mapdata may be NULL */
float BKE_brush_channelset_get_float(BrushChannelSet *chset,
char *idname,
BrushMappingData *mapdata);
bool BKE_brush_channelset_set_float(BrushChannelSet *chset, char *idname, float val);
float BKE_brush_channelset_get_final_float(BrushChannelSet *child,
BrushChannelSet *parent,
char *idname,
BrushMappingData *mapdata);
void BKE_brush_channelset_set_final_float(BrushChannelSet *child,
BrushChannelSet *parent,
char *idname,
float value);
void BKE_brush_init_toolsettings(struct Sculpt *sd);
void BKE_brush_builtin_create(struct Brush *brush, int tool);
BrushCommandList *BKE_brush_commandlist_create();
void BKE_brush_commandlist_free(BrushCommandList *cl);
BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl);
BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl,
BrushChannelSet *chset_template,
bool auto_inherit);
BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool);
void BKE_builtin_commandlist_create(BrushChannelSet *chset, BrushCommandList *cl, int tool);
void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *cset);
void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet *cset);
void BKE_builtin_commandlist_create(struct Brush *brush,
BrushChannelSet *chset,
BrushCommandList *cl,
int tool,
BrushMappingData *map_data); // map_data may be NULL
void BKE_brush_channelset_read(struct BlendDataReader *reader, BrushChannelSet *cset);
void BKE_brush_channelset_write(struct BlendWriter *writer, BrushChannelSet *cset);
void BKE_brush_mapping_copy_data(BrushMapping *dst, BrushMapping *src);
const char *BKE_brush_mapping_type_to_str(BrushMappingType mapping);
const char *BKE_brush_mapping_type_to_typename(BrushMappingType mapping);
void BKE_brush_channelset_flag_clear(BrushChannelSet *chset, const char *channel, int flag);
void BKE_brush_channelset_flag_set(BrushChannelSet *chset, const char *channel, int flag);
/* adds missing channels to exising .channels in brush.
* if channels do not exist use BKE_brush_builtin_create.
*/
void BKE_brush_builtin_patch(struct Brush *brush, int tool);
void BKE_brush_channelset_compat_load(BrushChannelSet *chset,
struct Brush *brush,
bool to_channels);
#ifdef __cplusplus
}
#endif

View File

@@ -23,7 +23,9 @@
* \ingroup bke
*/
#include "BKE_brush_engine.h"
#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"

View File

@@ -290,6 +290,7 @@ set(SRC
intern/world.c
intern/writeavi.c
intern/brush_engine.c
intern/brush_engine_presets.c
BKE_DerivedMesh.h
BKE_action.h

View File

@@ -143,6 +143,10 @@ static void brush_free_data(ID *id)
MEM_SAFE_FREE(brush->gradient);
BKE_previewimg_free(&(brush->preview));
if (brush->channels) {
BKE_brush_channelset_free(brush->channels);
}
}
static void brush_make_local(Main *bmain, ID *id, const int flags)
@@ -312,6 +316,7 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
if (brush->channels) {
BLO_read_data_address(reader, &brush->channels);
BKE_brush_channelset_read(reader, brush->channels);
BKE_brush_builtin_patch(brush, brush->sculpt_tool);
}
else {
BKE_brush_builtin_create(brush, brush->sculpt_tool);
@@ -1792,6 +1797,16 @@ void BKE_brush_sculpt_reset(Brush *br)
* settings used by a brush: */
// BKE_brush_debug_print_state(br);
BKE_brush_builtin_create(br, br->sculpt_tool);
for (int i = 0; i < br->channels->totchannel; i++) {
BrushChannel *ch = br->channels->channels + i;
BrushChannelType *def = ch->def;
BKE_brush_channel_free(ch);
BKE_brush_channel_init(ch, def);
}
brush_defaults(br);
BKE_brush_curve_preset(br, CURVE_PRESET_SMOOTH);
BKE_brush_default_input_curves_set(br);
@@ -1805,7 +1820,7 @@ void BKE_brush_sculpt_reset(Brush *br)
bool disable_dyntopo = false;
// basic face set setup for all organic brushes
// XXX basic face set setup for all organic brushes
br->autosmooth_fset_slide = 1.0f;
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT;
@@ -2245,7 +2260,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
/* leave the coordinates relative to the screen */
/* use unadjusted size for tiled mode */
invradius = 1.0f / BKE_brush_size_get(scene, br);
invradius = 1.0f / BKE_brush_size_get(scene, br, false);
x = point_2d[0];
y = point_2d[1];
@@ -2358,7 +2373,7 @@ float BKE_brush_sample_masktex(
/* leave the coordinates relative to the screen */
/* use unadjusted size for tiled mode */
invradius = 1.0f / BKE_brush_size_get(scene, br);
invradius = 1.0f / BKE_brush_size_get(scene, br, false);
x = point_2d[0];
y = point_2d[1];
@@ -2448,8 +2463,19 @@ void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float c
}
}
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
void BKE_brush_size_set(Scene *scene, Brush *brush, int size, bool use_brush_channels)
{
if (use_brush_channels) {
if (scene->toolsettings->sculpt && scene->toolsettings->sculpt->channels) {
BKE_brush_channelset_set_final_float(
brush->channels, scene->toolsettings->sculpt->channels, "RADIUS", (float)size);
return;
}
else {
BKE_brush_channelset_set_float(brush->channels, "RADIUS", (float)size);
}
}
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
/* make sure range is sane */
@@ -2463,8 +2489,18 @@ void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
}
}
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
int BKE_brush_size_get(const Scene *scene, const Brush *brush, bool use_brush_channel)
{
if (use_brush_channel) {
if (scene->toolsettings->sculpt) {
return (int)BKE_brush_channelset_get_final_float(
brush->channels, scene->toolsettings->sculpt->channels, "RADIUS", NULL);
}
else {
return (int)BKE_brush_channelset_get_float(brush->channels, "RADIUS", NULL);
}
}
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
int size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
@@ -2607,7 +2643,7 @@ void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2],
spread = 1.0;
}
else {
diameter = 2 * BKE_brush_size_get(scene, brush);
diameter = 2 * BKE_brush_size_get(scene, brush, false);
spread = brush->jitter;
}
/* find random position within a circle of diameter 1 */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_rect.h"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
#include "DNA_color_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_sculpt_brush_types.h"
#include "BKE_brush.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_brush_engine.h"
#include "BKE_curveprofile.h"
#include "BLO_read_write.h"
/*
Instructions to add a built-in channel:
1. Add to brush_builtin_channels
2. Add to BKE_brush_builtin_patch to insert it in old brushes (without converting data)
To enable converting to/from old data:
3. If not a boolean mapping to a bitflag: Add to brush_settings_map
4. If a boolean mapping to a bitflag: Add to brush_flags_map_len.
*/
#define ICON_NONE -1
/* clang-format off */
#define MAKE_FLOAT_EX_OPEN(idname1, name1, tooltip1, value1, min1, max1, smin1, smax1) \
{.name = name1, \
.idname = idname1, \
.fvalue = value1,\
.tooltip = tooltip1, \
.min = min1,\
.max = max1,\
.soft_min = smin1,\
.soft_max = smax1,\
.type = BRUSH_CHANNEL_FLOAT
#define MAKE_FLOAT_EX(idname, name, tooltip, value, min, max, smin, smax) \
MAKE_FLOAT_EX_OPEN(idname, name, tooltip, value, min, max, smin, smax) }
#define MAKE_FLOAT(idname, name, tooltip, value, min, max) MAKE_FLOAT_EX(idname, name, tooltip, value, min, max, min, max)
#define MAKE_INT_EX_OPEN(idname1, name1, tooltip1, value1, min1, max1, smin1, smax1) \
{.name = name1, \
.idname = idname1, \
.tooltip = tooltip1, \
.min = min1,\
.max = max1,\
.ivalue = value1,\
.soft_min = smin1,\
.soft_max = smax1,\
.type = BRUSH_CHANNEL_INT
#define MAKE_INT_EX(idname, name, tooltip, value, min, max, smin, smax) \
MAKE_INT_EX_OPEN(idname, name, tooltip, value, min, max, smin, smax) }
#define MAKE_INT(idname, name, tooltip, value, min, max) MAKE_INT_EX(idname, name, tooltip, value, min, max, min, max)
#define MAKE_BOOL_EX_OPEN(idname1, name1, tooltip1, value1)\
{.name = name1, \
.idname = idname1, \
.tooltip = tooltip1, \
.ivalue = value1,\
.type = BRUSH_CHANNEL_BOOL
#define MAKE_BOOL(idname, name, tooltip, value)\
MAKE_BOOL_EX_OPEN(idname, name, tooltip, value) }
/* clang-format on */
/* clang-format off */
BrushChannelType brush_builtin_channels[] = {
{
.name = "Radius",
.idname = "RADIUS",
.min = 0.001f,
.type = BRUSH_CHANNEL_FLOAT,
.max = 2048.0f,
.fvalue = 50.0f,
.soft_min = 0.1f,
.soft_max = 1024.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0f, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Strength",
.idname = "STRENGTH",
.min = -1.0f,
.type = BRUSH_CHANNEL_FLOAT,
.max = 4.0f,
.fvalue = 0.5f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0f, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Alpha",
.idname = "ALPHA",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0f,
.max = 1.0f,
.fvalue = 1.0f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0f, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Spacing",
.idname = "SPACING",
.min = 1.0f,
.type = BRUSH_CHANNEL_INT,
.max = 500.0f,
.fvalue = 10.0f,
.soft_min = 1.0f,
.soft_max = 500.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Autosmooth",
.idname = "AUTOSMOOTH",
.type = BRUSH_CHANNEL_FLOAT,
.min = -1.0f,
.max = 4.0f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false, .inv = true},
}
},
{
.name = "Topology Rake",
.idname = "TOPOLOGY_RAKE",
.type = BRUSH_CHANNEL_FLOAT,
.min = -1.0f,
.max = 4.0f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Autosmooth Radius Scale",
.idname = "AUTOSMOOTH_RADIUS_SCALE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 25.0f,
.fvalue = 1.0f,
.soft_min = 0.1f,
.soft_max = 4.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Rake Radius Scale",
.idname = "TOPOLOGY_RAKE_RADIUS_SCALE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 25.0f,
.fvalue = 1.0f,
.soft_min = 0.1f,
.soft_max = 4.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Face Set Slide",
.idname = "FSET_SLIDE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.fvalue = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Boundary Smooth",
.idname = "BOUNDARY_SMOOTH",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Projection",
.idname = "PROJECTION",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Use Spacing",
.idname = "TOPOLOGY_RAKE_USE_SPACING",
.type = BRUSH_CHANNEL_BOOL,
.ivalue = 0
},
{
.name = "Use Spacing",
.idname = "AUTOSMOOTH_USE_SPACING",
.type = BRUSH_CHANNEL_BOOL,
.ivalue = 0
},
{
.name = "Projection",
.idname = "AUTOSMOOTH_PROJECTION",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Projection",
.idname = "TOPOLOGY_RAKE_PROJECTION",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.fvalue = 0.975f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Spacing",
.idname = "TOPOLOGY_RAKE_SPACING",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.fvalue = 13.0f,
.soft_min = 0.1f,
.soft_max = 100.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Spacing",
.idname = "AUTOSMOOTH_SPACING",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.fvalue = 13.0f,
.soft_min = 0.1f,
.soft_max = 100.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_LINE, .factor = 1.0, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Topology Rake Mode",
.idname = "TOPOLOGY_RAKE_MODE",
.type = BRUSH_CHANNEL_ENUM,
.enumdef = {.items = {
{0, "BRUSH_DIRECTION", ICON_NONE, "Stroke", "Stroke Direction"},
{1, "CURVATURE", ICON_NONE, "Curvature", "Follow mesh curvature"},
{-1, 0}
}}
},
{
.name = "Automasking",
.idname = "AUTOMASKING",
.flag = BRUSH_CHANNEL_INHERIT_IF_UNSET | BRUSH_CHANNEL_INHERIT,
.type = BRUSH_CHANNEL_BITMASK,
.enumdef = {.items = {
{BRUSH_AUTOMASKING_BOUNDARY_EDGES, "BOUNDARY_EDGE", ICON_NONE, "Boundary Edges", ""},
{BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS, "BOUNDARY_FACE_SETS", ICON_NONE, "Boundary Face Sets", ""},
{BRUSH_AUTOMASKING_CONCAVITY, "CONCAVITY", ICON_NONE, "Concave", ""},
{BRUSH_AUTOMASKING_INVERT_CONCAVITY, "INVERT_CONCAVITY", ICON_NONE, "Invert Concave", "Invert Concave Map"},
{BRUSH_AUTOMASKING_FACE_SETS, "FACE_SETS", ICON_NONE, "Face Sets", ""},
{BRUSH_AUTOMASKING_TOPOLOGY, "TOPOLOGY", ICON_NONE, "Topology", ""}
}}
},
{
.name = "Disable Dyntopo",
.idname = "DYNTOPO_DISABLED",
.type = BRUSH_CHANNEL_BOOL,
.flag = BRUSH_CHANNEL_NO_MAPPINGS,
.ivalue = 0
},
{
.name = "Detail Range",
.idname = "DYNTOPO_DETAIL_RANGE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.001,
.max = 0.99,
.flag = BRUSH_CHANNEL_INHERIT,
.ivalue = 0
},
{
.name = "Operations",
.idname = "DYNTOPO_OPS",
.type = BRUSH_CHANNEL_BITMASK,
.flag = BRUSH_CHANNEL_INHERIT,
.ivalue = DYNTOPO_COLLAPSE | DYNTOPO_CLEANUP | DYNTOPO_SUBDIVIDE,
.enumdef = {
{DYNTOPO_COLLAPSE, "COLLAPSE", ICON_NONE, "Collapse", ""},
{DYNTOPO_SUBDIVIDE, "SUBDIVIDE", ICON_NONE, "Subdivide", ""},
{DYNTOPO_CLEANUP, "CLEANUP", ICON_NONE, "Cleanup", ""},
{DYNTOPO_LOCAL_COLLAPSE, "LOCAL_COLLAPSE", ICON_NONE, "Local Collapse", ""},
{DYNTOPO_LOCAL_SUBDIVIDE, "LOCAL_SUBDIVIDE", ICON_NONE, "Local Subdivide", ""},
{-1, NULL, -1, NULL, NULL}
}
},
{
.name = "Slide Deform Type",
.idname = "SLIDE_DEFORM_TYPE",
.ivalue = BRUSH_SLIDE_DEFORM_DRAG,
.type = BRUSH_CHANNEL_ENUM,
.enumdef = {
{BRUSH_SLIDE_DEFORM_DRAG, "DRAG", ICON_NONE, "Drag", ""},
{BRUSH_SLIDE_DEFORM_PINCH, "PINCH", ICON_NONE, "Pinch", ""},
{BRUSH_SLIDE_DEFORM_EXPAND, "EXPAND", ICON_NONE, "Expand", ""},
{-1, NULL, -1, NULL}
}
},
{
.name = "Normal Radius",
.idname = "NORMAL_RADIUS_FACTOR",
.tooltip = "Ratio between the brush radius and the radius that is going to be "
"used to sample the normal",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0f,
.max = 2.0f,
.soft_min = 0.0f,
.soft_max = 2.0f,
},
{
.name = "Hardness",
.idname = "HARDNESS",
.tooltip = "Brush hardness",
.type = BRUSH_CHANNEL_FLOAT,
.fvalue = 0.0f,
.min = 0.0f,
.max = 1.0f,
.soft_min = 0.0f,
.soft_max = 1.0f
},
{
.name = "Tip Roundness",
.idname = "TIP_ROUNDNESS",
.tooltip = "",
.type = BRUSH_CHANNEL_FLOAT,
.fvalue = 0.0f,
.min = 0.0f,
.max = 1.0f,
.soft_min = 0.0f,
.soft_max = 1.0f
},
{
.name = "Accumulate",
.idname = "ACCUMULATE",
.type = BRUSH_CHANNEL_BOOL,
.ivalue = 0
},
MAKE_FLOAT("NORMAL_WEIGHT", "Normal Weight", "", 0.0f, 0.0f, 1.0f),
MAKE_FLOAT("RAKE_FACTOR", "Rake Factor", "How much grab will follow cursor rotation", 0.0f, 0.0f, 10.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", 10.0f, 10.0f, 200.0f),
MAKE_FLOAT("SMOOTH_STROKE_FACTOR", "Smooth Stroke Factor", "", 0.5f, 0.5f, 0.99f),
MAKE_FLOAT_EX("RATE", "Rate", "", 0.5, 0.0001f, 10000.0f, 0.01f, 1.0f),
MAKE_FLOAT("FLOW", "Flow", "Amount of paint that is applied per stroke sample", 0.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("DENSITY", "Density", "Amount of random elements that are going to be affected by the brush", 0.0f, 0.0f, 1.0f),
MAKE_FLOAT("TIP_SCALE_X", "Tip Scale X", "Scale of the brush tip in the X axis", 0.0f, 0.0f, 1.0f),
MAKE_FLOAT("DASH_RATIO", "Dash Ratio", "Ratio of samples in a cycle that the brush is enabled", 0.0f, 0.0f, 1.0f),
MAKE_FLOAT_EX("PLANE_OFFSET", "Plane Offset", "Adjust plane on which the brush acts towards or away from the object surface", 0.0f, -2.0f, 2.0f, -0.5f, 0.5f),
MAKE_BOOL("ORIGINAL_NORMAL", "Original Normal", "When locked keep using normal of surface where stroke was initiated", false),
MAKE_BOOL("ORIGINAL_PLANE", "Original Plane", "When locked keep using the plane origin of surface where stroke was initiated", false)
};
/* clang-format on */
const int brush_builtin_channel_len = ARRAY_SIZE(brush_builtin_channels);

View File

@@ -124,6 +124,37 @@ void BKE_curvemapping_free(CurveMapping *cumap)
}
}
static void *my_dupalloc_id(void *mem, const char *tag)
{
size_t size = MEM_allocN_len(mem);
void *ret = MEM_mallocN(size, tag);
memcpy(ret, mem, size);
return ret;
};
void BKE_curvemapping_copy_data_tag_ex(CurveMapping *target,
const CurveMapping *cumap,
const char *tag)
{
int a;
*target = *cumap;
for (a = 0; a < CM_TOT; a++) {
if (cumap->cm[a].curve) {
target->cm[a].curve = my_dupalloc_id(cumap->cm[a].curve, tag);
}
if (cumap->cm[a].table) {
target->cm[a].table = my_dupalloc_id(cumap->cm[a].table, tag);
}
if (cumap->cm[a].premultable) {
target->cm[a].premultable = my_dupalloc_id(cumap->cm[a].premultable, tag);
}
}
}
void BKE_curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
{
int a;
@@ -305,6 +336,15 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
case CURVE_PRESET_BELL:
cuma->totpoint = 3;
break;
case CURVE_PRESET_POW2:
cuma->totpoint = 5;
break;
case CURVE_PRESET_POW3:
cuma->totpoint = 6;
break;
case CURVE_PRESET_POW15:
cuma->totpoint = 6;
break;
}
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
@@ -401,8 +441,60 @@ void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope
cuma->curve[2].x = 1.0f;
cuma->curve[2].y = 0.025f;
break;
}
case CURVE_PRESET_POW2:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 0.25f;
cuma->curve[1].y = 0.0625f;
cuma->curve[2].x = 0.5;
cuma->curve[2].y = 0.25;
cuma->curve[3].x = 0.75f;
cuma->curve[3].y = 0.5625f;
cuma->curve[4].x = 1.0f;
cuma->curve[4].y = 1.0f;
case CURVE_PRESET_POW3:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 0.135f;
cuma->curve[1].y = 0.002f;
cuma->curve[2].x = 0.318;
cuma->curve[2].y = 0.032;
cuma->curve[3].x = 0.528;
cuma->curve[3].y = 0.147f;
cuma->curve[4].x = 0.757f;
cuma->curve[4].y = 0.433f;
cuma->curve[5].x = 1.0f;
cuma->curve[5].y = 1.0f;
case CURVE_PRESET_POW15:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 0.135f;
cuma->curve[1].y = 0.002f;
cuma->curve[2].x = 0.318;
cuma->curve[2].y = 0.032;
cuma->curve[3].x = 0.528;
cuma->curve[3].y = 0.147f;
cuma->curve[4].x = 0.757f;
cuma->curve[4].y = 0.433f;
cuma->curve[5].x = 1.0f;
cuma->curve[5].y = 1.0f;
}
//[[0,0], [0.134,0.002], [0.318,0.032], [0.528,0.147], [0.757,0.433], [1,1]
/* mirror curve in x direction to have positive slope
* rather than default negative slope */
if (slope == CURVEMAP_SLOPE_POSITIVE) {

View File

@@ -1060,10 +1060,15 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &sce->toolsettings->sculpt->channels);
BKE_brush_channelset_read(reader, sce->toolsettings->sculpt->channels);
}
else {
else if (sce->toolsettings->sculpt) {
sce->toolsettings->sculpt->channels = BKE_brush_channelset_create();
}
if (sce->toolsettings->sculpt) {
// make sure radius exists in the toolsettings brush channel set
BKE_brush_channelset_ensure_builtin(sce->toolsettings->sculpt->channels, "RADIUS");
}
/* relink grease pencil interpolation curves */
BLO_read_data_address(reader, &sce->toolsettings->gp_interpolate.custom_ipo);
if (sce->toolsettings->gp_interpolate.custom_ipo) {

View File

@@ -49,6 +49,7 @@
#include "BKE_animsys.h"
#include "BKE_asset.h"
#include "BKE_brush.h"
#include "BKE_brush_engine.h"
#include "BKE_collection.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
@@ -1239,6 +1240,9 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (br->autosmooth_fset_slide == 0.0f) {
Brush defbrush = *br;
// don't free data inside of pointers copied from br
defbrush.channels = NULL;
defbrush.curve = NULL;
defbrush.pressure_size_curve = defbrush.pressure_strength_curve = NULL;
BKE_brush_sculpt_reset(&defbrush);
@@ -1258,6 +1262,10 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (br->autosmooth_projection == 0.0f) {
br->autosmooth_projection = defbrush.autosmooth_projection;
}
if (defbrush.channels) {
BKE_brush_channelset_free(defbrush.channels);
}
}
if (br->sculpt_tool == SCULPT_TOOL_VCOL_BOUNDARY) {

View File

@@ -253,6 +253,8 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
bool init;
TexSnapshot *target;
bool use_brush_channels = paint_use_channels(vc->C);
MTex *mtex = (primary) ? &br->mtex : &br->mask_mtex;
ePaintOverlayControlFlags overlay_flags = BKE_paint_get_overlay_flags();
uchar *buffer = NULL;
@@ -273,12 +275,12 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
struct ImagePool *pool = NULL;
/* Stencil is rotated later. */
const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
const float radius = BKE_brush_size_get(vc->scene, br, use_brush_channels) * zoom;
make_tex_snap(target, vc, zoom);
if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
int s = BKE_brush_size_get(vc->scene, br);
int s = BKE_brush_size_get(vc->scene, br, use_brush_channels);
int r = 1;
for (s >>= 1; s > 0; s >>= 1) {
@@ -420,13 +422,14 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
cursor_snap.curve_preset != br->curve_preset;
init = (cursor_snap.overlay_texture != 0);
bool use_brush_channels = paint_use_channels(vc->C);
if (refresh) {
int s, r;
cursor_snap.zoom = zoom;
s = BKE_brush_size_get(vc->scene, br);
s = BKE_brush_size_get(vc->scene, br, use_brush_channels);
r = 1;
for (s >>= 1; s > 0; s >>= 1) {
@@ -565,6 +568,8 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
}
}
bool use_brush_channels = paint_use_channels(vc->C);
if (!(mtex->tex) ||
!((mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) ||
(valid && ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED)))) {
@@ -598,7 +603,7 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups,
quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
}
else {
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
const int radius = BKE_brush_size_get(vc->scene, brush, use_brush_channels) * zoom;
quad.xmin = x - radius;
quad.ymin = y - radius;
quad.xmax = x + radius;
@@ -691,6 +696,8 @@ static bool paint_draw_cursor_overlay(
rctf quad;
/* Check for overlay mode. */
bool use_brush_channels = paint_use_channels(vc->C);
if (!(brush->overlay_flags & BRUSH_OVERLAY_CURSOR)) {
return false;
}
@@ -710,7 +717,7 @@ static bool paint_draw_cursor_overlay(
quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size;
}
else {
const int radius = BKE_brush_size_get(vc->scene, brush) * zoom;
const int radius = BKE_brush_size_get(vc->scene, brush, use_brush_channels) * zoom;
center[0] = x;
center[1] = y;
@@ -1003,6 +1010,8 @@ static void paint_cursor_update_unprojected_radius(UnifiedPaintSettings *ups,
{
float unprojected_radius, projected_radius;
bool use_brush_channels = paint_use_channels(vc->C);
/* Update the brush's cached 3D radius. */
if (!BKE_brush_use_locked_size(vc->scene, brush)) {
/* Get 2D brush radius. */
@@ -1014,7 +1023,7 @@ static void paint_cursor_update_unprojected_radius(UnifiedPaintSettings *ups,
projected_radius = 8;
}
else {
projected_radius = BKE_brush_size_get(vc->scene, brush);
projected_radius = BKE_brush_size_get(vc->scene, brush, use_brush_channels);
}
}
@@ -1301,10 +1310,13 @@ static bool paint_cursor_context_init(bContext *C,
pcontext->translation[0] = (float)x;
pcontext->translation[1] = (float)y;
bool use_brush_channels = paint_use_channels(pcontext->C);
float zoomx, zoomy;
get_imapaint_zoom(C, &zoomx, &zoomy);
pcontext->zoomx = max_ff(zoomx, zoomy);
pcontext->final_radius = (BKE_brush_size_get(pcontext->scene, pcontext->brush) * zoomx);
pcontext->final_radius =
(BKE_brush_size_get(pcontext->scene, pcontext->brush, use_brush_channels) * zoomx);
/* There is currently no way to check if the direction is inverted before starting the stroke,
* so this does not reflect the state of the brush in the UI. */
@@ -1339,6 +1351,8 @@ static bool paint_cursor_context_init(bContext *C,
static void paint_cursor_update_pixel_radius(PaintCursorContext *pcontext)
{
bool use_brush_channels = paint_use_channels(pcontext->C);
if (pcontext->is_cursor_over_mesh) {
Brush *brush = BKE_paint_brush(pcontext->paint);
pcontext->pixel_radius = project_brush_radius(
@@ -1347,7 +1361,7 @@ static void paint_cursor_update_pixel_radius(PaintCursorContext *pcontext)
pcontext->location);
if (pcontext->pixel_radius == 0) {
pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush);
pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush, use_brush_channels);
}
copy_v3_v3(pcontext->scene_space_location, pcontext->location);
@@ -1357,7 +1371,7 @@ static void paint_cursor_update_pixel_radius(PaintCursorContext *pcontext)
Sculpt *sd = CTX_data_tool_settings(pcontext->C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush);
pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush, use_brush_channels);
}
}
@@ -1396,7 +1410,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
paint_cursor_update_pixel_radius(pcontext);
if (BKE_brush_use_locked_size(scene, brush)) {
BKE_brush_size_set(scene, brush, pcontext->pixel_radius);
BKE_brush_size_set(scene, brush, pcontext->pixel_radius, !!ss);
}
if (pcontext->is_cursor_over_mesh) {
@@ -1562,9 +1576,13 @@ static void sculpt_cursor_draw_3D_face_set_preview(PaintCursorContext *pcontext)
static void paint_cursor_update_object_space_radius(PaintCursorContext *pcontext)
{
bool use_brush_channels = paint_use_channels(pcontext->C);
if (!BKE_brush_use_locked_size(pcontext->scene, pcontext->brush)) {
pcontext->radius = paint_calc_object_space_radius(
&pcontext->vc, pcontext->location, BKE_brush_size_get(pcontext->scene, pcontext->brush));
&pcontext->vc,
pcontext->location,
BKE_brush_size_get(pcontext->scene, pcontext->brush, use_brush_channels));
}
else {
pcontext->radius = BKE_brush_unprojected_radius_get(pcontext->scene, pcontext->brush);

View File

@@ -598,6 +598,9 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
ToolSettings *toolsettings = scene->toolsettings;
PaintOperation *pop = paint_stroke_mode_data(stroke);
Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
Object *ob = CTX_data_active_object(C);
bool is_sculpt = ob && ob->mode == OB_MODE_SCULPT;
toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
@@ -614,7 +617,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
paint_stroke_flipped(stroke),
1.0,
0.0,
BKE_brush_size_get(scene, brush));
BKE_brush_size_get(scene, brush, is_sculpt));
/* two redraws, one for GPU update, one for notification */
paint_proj_redraw(C, pop->custom_paint, false);
paint_proj_redraw(C, pop->custom_paint, true);
@@ -639,7 +642,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
paint_stroke_flipped(stroke),
1.0,
0.0,
BKE_brush_size_get(scene, brush));
BKE_brush_size_get(scene, brush, is_sculpt));
/* two redraws, one for GPU update, one for notification */
paint_proj_redraw(C, pop->custom_paint, false);
paint_proj_redraw(C, pop->custom_paint, true);

View File

@@ -4461,7 +4461,10 @@ static void project_paint_begin(const bContext *C,
/* At the moment this is just ps->arena_mt[0], but use this to show were not multi-threading. */
MemArena *arena;
const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
Object *ob = CTX_data_active_object(C);
bool use_brush_channels = paint_use_channels(C);
const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush, use_brush_channels);
bool reset_threads = false;
@@ -5908,8 +5911,11 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
ProjStrokeHandle *ps_handle;
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
ePaintMode paintmode = BKE_paintmode_get_active_from_context(C);
char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
bool use_brush_channels = paint_use_channels(C);
ps_handle = MEM_callocN(sizeof(ProjStrokeHandle), "ProjStrokeHandle");
ps_handle->scene = scene;
ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
@@ -5921,7 +5927,7 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
return ps_handle;
}
ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush);
ps_handle->orig_brush_size = BKE_brush_size_get(scene, ps_handle->brush, use_brush_channels);
Mesh *mesh = BKE_mesh_from_object(ob);
ps_handle->symmetry_flags = mesh->symmetry;
@@ -5963,8 +5969,8 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
}
/* Don't allow brush size below 2 */
if (BKE_brush_size_get(scene, ps_handle->brush) < 2) {
BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize);
if (BKE_brush_size_get(scene, ps_handle->brush, use_brush_channels) < 2) {
BKE_brush_size_set(scene, ps_handle->brush, 2 * U.pixelsize, paintmode == PAINT_MODE_SCULPT);
}
/* allocate and initialize spatial data structures */
@@ -6036,7 +6042,7 @@ void paint_proj_stroke_done(void *ps_handle_p)
PROJ_PAINT_STATE_SHARED_CLEAR(ps_handle->ps_views[i]);
}
BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size);
BKE_brush_size_set(scene, ps_handle->brush, ps_handle->orig_brush_size, false);
paint_brush_exit_tex(ps_handle->brush);
@@ -6068,6 +6074,8 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
bool use_brush_channels = paint_use_channels(C);
if (!ED_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
ED_paint_data_warning(op->reports, uvs, mat, tex, true);
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -6119,9 +6127,9 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ps.is_texbrush = false;
ps.is_maskbrush = false;
ps.do_masking = false;
orig_brush_size = BKE_brush_size_get(scene, ps.brush);
orig_brush_size = BKE_brush_size_get(scene, ps.brush, use_brush_channels);
/* cover the whole image */
BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize);
BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize, use_brush_channels);
/* so pixels are initialized with minimal info */
ps.tool = PAINT_TOOL_DRAW;
@@ -6132,7 +6140,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
project_paint_begin(C, &ps, false, 0);
if (ps.me_eval == NULL) {
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
BKE_brush_size_set(scene, ps.brush, orig_brush_size, use_brush_channels);
BKE_report(op->reports, RPT_ERROR, "Could not get valid evaluated mesh");
return OPERATOR_CANCELLED;
}
@@ -6157,7 +6165,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ED_image_undo_push_end();
scene->toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
BKE_brush_size_set(scene, ps.brush, orig_brush_size);
BKE_brush_size_set(scene, ps.brush, orig_brush_size, false);
return OPERATOR_FINISHED;
}

View File

@@ -170,13 +170,13 @@ void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
void paint_cursor_delete_textures(void);
/**
* used by various actions that have their own spacing that
* is coarser then the brush spacing. e.g. sculpt dyntopo.
*
* \param state: pointer to a float used for internal state, should be initialized to zero at start of stroke
* \return false if the action should be skipped.
*
*/
* used by various actions that have their own spacing that
* is coarser then the brush spacing. e.g. sculpt dyntopo.
*
* \param state: pointer to a float used for internal state, should be initialized to zero at start
* of stroke \return false if the action should be skipped.
*
*/
bool paint_stroke_apply_subspacing(struct PaintStroke *stroke,
const float spacing,
const enum ePaintMode mode,
@@ -455,5 +455,7 @@ enum eBlurKernelType;
BlurKernel *paint_new_blur_kernel(struct Brush *br, bool proj);
void paint_delete_blur_kernel(BlurKernel *);
#define paint_use_channels(C) (BKE_paintmode_get_active_from_context(C) == PAINT_MODE_SCULPT)
/* paint curve defines */
#define PAINT_CURVE_NUM_SEGMENTS 40

View File

@@ -143,10 +143,14 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
// Object *ob = CTX_data_active_object(C);
float scalar = RNA_float_get(op->ptr, "scalar");
bool use_brush_channels = paint_use_channels(C);
Object *ob = CTX_data_active_object(C);
if (brush) {
/* pixel radius */
{
const int old_size = (!is_gpencil) ? BKE_brush_size_get(scene, brush) : brush->size;
const int old_size = (!is_gpencil) ? BKE_brush_size_get(scene, brush, use_brush_channels) :
brush->size;
int size = (int)(scalar * old_size);
if (abs(old_size - size) < U.pixelsize) {
@@ -164,7 +168,7 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
BKE_brush_size_set(scene, brush, size);
BKE_brush_size_set(scene, brush, size, use_brush_channels);
}
/* unprojected radius */

View File

@@ -301,8 +301,8 @@ static bool paint_brush_update(bContext *C,
ups->stroke_active = true;
ups->size_pressure_value = stroke->cached_size_pressure;
ups->pixel_radius = BKE_brush_size_get(scene, brush);
ups->initial_pixel_radius = BKE_brush_size_get(scene, brush);
ups->pixel_radius = BKE_brush_size_get(scene, brush, mode == PAINT_MODE_SCULPT);
ups->initial_pixel_radius = BKE_brush_size_get(scene, brush, mode == PAINT_MODE_SCULPT);
if (BKE_brush_use_size_pressure(brush) && paint_supports_dynamic_size(brush, mode)) {
ups->pixel_radius *= stroke->cached_size_pressure;
@@ -637,7 +637,8 @@ static float paint_space_stroke_spacing(bContext *C,
BKE_curvemapping_init(brush->pressure_size_curve);
final_size_pressure = BKE_curvemapping_evaluateF(brush->pressure_size_curve, 0, size_pressure);
}
float size = BKE_brush_size_get(scene, stroke->brush) * final_size_pressure;
float size = BKE_brush_size_get(scene, stroke->brush, mode == PAINT_MODE_SCULPT) *
final_size_pressure;
if (paint_stroke_use_scene_spacing(brush, mode)) {
if (!BKE_brush_use_locked_size(scene, brush)) {
float last_object_space_position[3];
@@ -729,7 +730,7 @@ static float paint_space_get_final_size_intern(
bContext *C, const Scene *scene, PaintStroke *stroke, float pressure, float dpressure)
{
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
float size = BKE_brush_size_get(scene, stroke->brush) * pressure;
float size = BKE_brush_size_get(scene, stroke->brush, mode == PAINT_MODE_SCULPT) * pressure;
if (paint_stroke_use_scene_spacing(stroke->brush, mode)) {
if (!BKE_brush_use_locked_size(scene, stroke->brush)) {
@@ -1059,7 +1060,7 @@ static bool sculpt_is_grab_tool(Brush *br)
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ARRAY,
SCULPT_TOOL_ARRAY,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK);
}

View File

@@ -1486,7 +1486,7 @@ static void vwpaint_update_cache_invariants(
StrokeCache *cache;
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
const Brush *brush = vp->paint.brush;
Brush *brush = vp->paint.brush;
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
float mat[3][3];
@@ -1571,7 +1571,7 @@ static void vwpaint_update_cache_variants(bContext *C, VPaint *vp, Object *ob, P
/* Truly temporary data that isn't stored in properties */
if (cache->first_time) {
cache->initial_radius = paint_calc_object_space_radius(
cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
cache->vc, cache->true_location, BKE_brush_size_get(scene, brush, true));
BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
}
@@ -1758,7 +1758,7 @@ static void get_brush_alpha_data(const Scene *scene,
float *r_brush_alpha_value,
float *r_brush_alpha_pressure)
{
*r_brush_size_pressure = BKE_brush_size_get(scene, brush) *
*r_brush_size_pressure = BKE_brush_size_get(scene, brush, true) *
(BKE_brush_use_size_pressure(brush) ? ss->cache->pressure : 1.0f);
*r_brush_alpha_value = BKE_brush_alpha_get(scene, brush);
*r_brush_alpha_pressure = (BKE_brush_use_alpha_pressure(brush) ? ss->cache->pressure : 1.0f);

View File

@@ -56,6 +56,7 @@
#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_brush_engine.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -123,6 +124,15 @@
static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss,
const SculptVertRef index);
typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
void sculpt_combine_proxies(Sculpt *sd, Object *ob);
static void SCULPT_run_command_list(
Sculpt *sd, Object *ob, Brush *brush, BrushCommandList *list, UnifiedPaintSettings *ups);
static void do_symmetrical_brush_actions(Sculpt *sd,
Object *ob,
BrushActionFunc action,
UnifiedPaintSettings *ups);
/* Sculpt PBVH abstraction API
*
@@ -3567,6 +3577,7 @@ static float brush_strength(const Sculpt *sd,
}
float pressure = BKE_brush_use_alpha_pressure(brush) ? cache->pressure : 1.0f;
if (brush->pressure_strength_curve) {
}
BKE_curvemapping_init(brush->pressure_strength_curve);
@@ -8375,6 +8386,26 @@ static void do_brush_action_task_cb(void *__restrict userdata,
void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
if (ELEM(brush->sculpt_tool,
SCULPT_TOOL_DRAW,
SCULPT_TOOL_DRAW_SHARP,
SCULPT_TOOL_CLAY_STRIPS,
SCULPT_TOOL_CLAY,
SCULPT_TOOL_CREASE,
SCULPT_TOOL_CLOTH)) {
// SCULPT_run_command_list
BrushCommandList *list = BKE_brush_commandlist_create();
BKE_builtin_commandlist_create(
brush, ss->cache->channels_final, list, brush->sculpt_tool, &ss->cache->input_mapping);
SCULPT_run_command_list(sd, ob, brush, list, ups);
BKE_brush_commandlist_free(list);
return;
}
int totnode;
PBVHNode **nodes;
@@ -8779,6 +8810,460 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
ups->last_stroke_valid = true;
}
void BKE_brush_commandlist_start(BrushCommandList *list,
Brush *brush,
BrushChannelSet *chset_final);
ATTR_NO_OPT static void SCULPT_run_command_list(
Sculpt *sd, Object *ob, Brush *brush, BrushCommandList *list, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
int totnode;
PBVHNode **nodes;
float start_radius = ss->cache->radius;
float radius_scale = 1.0f;
float radius_max = 0.0f;
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 all_nodes_undo = false;
bool cloth_nodes_undo = false;
// get maximum radius
for (int i = 0; i < list->totcommand; i++) {
BrushCommand *cmd = list->commands + i;
Brush brush2 = *brush;
brush2.sculpt_tool = cmd->tool;
// Load parameters into brush2 for compatibility with old code
BKE_brush_channelset_compat_load(cmd->params_final, &brush2, false);
/* With these options enabled not all required nodes are inside the original brush radius, so
* the brush can produce artifacts in some situations. */
if (cmd->tool == SCULPT_TOOL_DRAW &&
BKE_brush_channelset_get_int(cmd->params_final, "ORIGINAL_NORMAL")) {
radius_scale = MAX2(radius_scale, 2.0f);
}
if (SCULPT_tool_needs_all_pbvh_nodes(&brush2)) {
all_nodes_undo = true;
}
else if (cmd->tool == SCULPT_TOOL_CLOTH) {
cloth_nodes_undo = true;
}
if (!SCULPT_TOOL_HAS_DYNTOPO(cmd->tool)) {
has_dyntopo = false;
}
float radius = BKE_brush_channelset_get_float(
ss->cache->channels_final, "RADIUS", &ss->cache->input_mapping);
radius_max = max_ff(radius_max, radius);
}
float ratio = radius_max / BKE_brush_channelset_get_float(
ss->cache->channels_final, "RADIUS", &ss->cache->input_mapping);
ss->cache->radius = start_radius * ratio;
ss->cache->radius_squared = start_radius * start_radius * ratio * ratio;
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR) &&
!ELEM(type, PBVH_BMESH, PBVH_FACES)) {
return;
}
if (brush->sculpt_tool == SCULPT_TOOL_ARRAY && type != PBVH_FACES) {
return;
}
/* Build a list of all nodes that are potentially within the brush's area of influence */
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
if (all_nodes_undo) {
/* These brushes need to update all nodes as they are not constrained by the brush radius */
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
}
else if (cloth_nodes_undo) {
//
float initial_radius = ss->cache->initial_radius;
float old_radius = ss->cache->radius;
float radius = ss->cache->initial_radius;
radius = max_ff(radius, ss->cache->radius);
radius *= radius_scale;
ss->cache->initial_radius = radius;
ss->cache->radius = radius;
ss->cache->radius_squared = radius * radius;
nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode);
ss->cache->initial_radius = initial_radius;
ss->cache->radius = old_radius;
ss->cache->radius_squared = old_radius * old_radius;
}
else {
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
/* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
* vertices and uses regular coords undo. */
/* It also assigns the paint_face_set here as it needs to be done regardless of the stroke type
* and the number of nodes under the brush influence. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS &&
SCULPT_stroke_is_first_brush_step(ss->cache) && !ss->cache->alt_smooth) {
// faceset undo node is created below for pbvh_bmesh
if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
}
if (ss->cache->invert) {
/* When inverting the brush, pick the paint face mask ID from the mesh. */
ss->cache->paint_face_set = SCULPT_active_face_set_get(ss);
}
else {
/* By default create a new Face Sets. */
ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
}
}
/* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with
* zero radius, thus we have no pbvh nodes on the first brush step. */
if (totnode ||
((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) {
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob);
}
}
}
/* Only act if some verts are inside the brush area. */
if (totnode == 0) {
ss->cache->radius = start_radius;
ss->cache->radius_squared = start_radius * start_radius;
return;
}
float location[3];
// dyntopo can't push undo nodes inside a thread
if (ss->bm) {
if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
for (int i = 0; i < totnode; i++) {
int other = brush->vcol_boundary_factor > 0.0f ? SCULPT_UNDO_COORDS : -1;
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COLOR, other);
BKE_pbvh_node_mark_update_color(nodes[i]);
}
}
else if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
for (int i = 0; i < totnode; i++) {
if (ss->cache->alt_smooth) {
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_FACE_SETS, SCULPT_UNDO_COORDS);
}
else {
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_FACE_SETS, -1);
}
BKE_pbvh_node_mark_update(nodes[i]);
}
}
else {
for (int i = 0; i < totnode; i++) {
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COORDS, -1);
BKE_pbvh_node_mark_update(nodes[i]);
}
}
}
else {
SculptThreadedTaskData task_data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
}
Brush *oldbrush = ss->cache->brush;
Brush _dummy = *brush, *brush2 = &_dummy;
for (int step = 0; step < list->totcommand; step++) {
BrushCommand *cmd = list->commands + step;
*brush2 = *brush;
ss->cache->brush = brush2;
// Load parameters into brush2 for compatibility with old code
BKE_brush_channelset_compat_load(cmd->params_final, brush2, false);
brush2->sculpt_tool = cmd->tool;
/*Search PBVH*/
if (step > 0) {
MEM_SAFE_FREE(nodes);
if (SCULPT_tool_needs_all_pbvh_nodes(brush)) {
/* These brushes need to update all nodes as they are not constrained by the brush radius
*/
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
}
else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode);
}
else {
/* With these options enabled not all required nodes are inside the original brush radius,
* so the brush can produce artifacts in some situations. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) {
radius_scale = MAX2(radius_scale, 2.0f);
}
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
}
if (sculpt_brush_needs_normal(ss, brush2)) {
update_sculpt_normal(sd, ob, nodes, totnode);
}
if (brush2->mtex.brush_map_mode == MTEX_MAP_MODE_AREA) {
update_brush_local_mat(sd, ob);
}
if (brush2->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) {
SCULPT_pose_brush_init(sd, ob, ss, brush2);
}
if (brush2->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) {
if (!ss->cache->cloth_sim) {
ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
ss, 1.0f, 1.0f, 0.0f, false, true);
SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim);
}
SCULPT_cloth_brush_store_simulation_state(ss, ss->cache->cloth_sim);
SCULPT_cloth_brush_ensure_nodes_constraints(
sd, ob, nodes, totnode, ss->cache->cloth_sim, ss->cache->location, FLT_MAX);
}
bool invert = ss->cache->pen_flip || ss->cache->invert || brush2->flag & BRUSH_DIR_IN;
SCULPT_replay_log_append(sd, ss, ob);
/* Apply one type of brush action. */
switch (brush2->sculpt_tool) {
case SCULPT_TOOL_DRAW:
do_draw_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
if (brush2->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
SCULPT_do_smooth_brush(sd, ob, nodes, totnode, brush2->autosmooth_projection);
}
else if (brush2->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE) {
SCULPT_do_surface_smooth_brush(sd, ob, nodes, totnode);
}
else if (brush2->smooth_deform_type == BRUSH_SMOOTH_DEFORM_DIRECTIONAL) {
SCULPT_do_directional_smooth_brush(sd, ob, nodes, totnode);
}
else if (brush2->smooth_deform_type == BRUSH_SMOOTH_DEFORM_UNIFORM_WEIGHTS) {
SCULPT_do_uniform_weights_smooth_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_CREASE:
do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BLOB:
do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
do_pinch_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
do_inflate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
do_grab_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ROTATE:
do_rotate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SNAKE_HOOK:
do_snake_hook_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_NUDGE:
do_nudge_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_THUMB:
do_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
do_layer_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
do_flatten_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
do_clay_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_STRIPS:
do_clay_strips_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_TWIST:
do_twist_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_THUMB:
do_clay_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
if (invert && brush2->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
do_scrape_brush(sd, ob, nodes, totnode);
}
else {
do_fill_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_SCRAPE:
if (invert && brush2->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
do_fill_brush(sd, ob, nodes, totnode);
}
else {
do_scrape_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_MASK:
do_mask_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_POSE:
SCULPT_do_pose_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_SHARP:
do_draw_sharp_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ELASTIC_DEFORM:
do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SLIDE_RELAX:
do_slide_relax_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BOUNDARY:
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLOTH:
SCULPT_do_cloth_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_FACE_SETS:
SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_ERASER:
do_displacement_eraser_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
do_displacement_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMEAR:
SCULPT_do_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FAIRING:
do_fairing_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SCENE_PROJECT:
do_scene_project_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SYMMETRIZE:
SCULPT_do_symmetrize_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ARRAY:
SCULPT_do_array_brush(sd, ob, nodes, totnode);
case SCULPT_TOOL_VCOL_BOUNDARY:
SCULPT_smooth_vcol_boundary(sd, ob, nodes, totnode, ss->cache->bstrength);
break;
case SCULPT_TOOL_UV_SMOOTH:
SCULPT_uv_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_TOPOLOGY_RAKE:
bmesh_topology_rake(sd, ob, nodes, totnode, brush2->alpha);
break;
case SCULPT_TOOL_DYNTOPO:
if (has_dyntopo) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
break;
}
if (ss->needs_pbvh_rebuild) {
bContext *C = ss->cache->vc->C;
/* The mesh was modified, rebuild the PBVH. */
BKE_particlesystem_reset_all(ob);
BKE_ptcache_object_reset(CTX_data_scene(C), ob, PTCACHE_RESET_OUTDATED);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
BKE_scene_graph_update_tagged(CTX_data_ensure_evaluated_depsgraph(C), CTX_data_main(C));
SCULPT_pbvh_clear(ob);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
if (brush->sculpt_tool == SCULPT_TOOL_ARRAY) {
SCULPT_tag_update_overlays(C);
}
ss->needs_pbvh_rebuild = false;
}
sculpt_combine_proxies(sd, ob);
}
/*
paint_stroke_apply_subspacing(
ss->cache->stroke,
spacing,
PAINT_MODE_SCULPT,
&ss->cache->last_smooth_t[SCULPT_get_symmetry_pass(ss)]);
*/
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
if (ss->cache->supports_gravity && !ELEM(brush->sculpt_tool,
SCULPT_TOOL_CLOTH,
SCULPT_TOOL_DRAW_FACE_SETS,
SCULPT_TOOL_BOUNDARY)) {
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
if (brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) {
if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
SCULPT_cloth_sim_activate_nodes(ss->cache->cloth_sim, nodes, totnode);
SCULPT_cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode);
}
}
ss->cache->brush = oldbrush;
ss->cache->radius = start_radius;
ss->cache->radius_squared = start_radius * start_radius;
MEM_SAFE_FREE(nodes);
}
/* Flush displacement from deformed PBVH vertex to original mesh. */
static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
{
@@ -9082,8 +9567,6 @@ void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,
}
}
typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
static void do_tiled(
Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action)
{
@@ -9214,7 +9697,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
{
Brush *brush = BKE_paint_brush(&sd->paint);
const int radius = BKE_brush_size_get(scene, brush);
const int radius = BKE_brush_size_get(scene, brush, true);
MEM_SAFE_FREE(ss->texcache);
@@ -9390,6 +9873,10 @@ void SCULPT_cache_free(SculptSession *ss, StrokeCache *cache)
ss, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, ss->cache->prefairing_co);
}
if (ss->cache->channels_final) {
BKE_brush_channelset_free(ss->cache->channels_final);
}
MEM_SAFE_FREE(ss->cache->fairing_mask);
MEM_SAFE_FREE(ss->cache->fairing_fade);
MEM_SAFE_FREE(ss->cache->prefairing_co);
@@ -9542,7 +10029,7 @@ static void sculpt_update_cache_invariants(
else {
Paint *p = &sd->paint;
Brush *br;
int size = BKE_brush_size_get(scene, brush);
int size = BKE_brush_size_get(scene, brush, true);
BLI_strncpy(cache->saved_active_brush_name,
brush->id.name + 2,
@@ -9552,8 +10039,8 @@ static void sculpt_update_cache_invariants(
if (br) {
BKE_paint_brush_set(p, br);
brush = br;
cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
BKE_brush_size_set(scene, brush, size);
cache->saved_smooth_size = BKE_brush_size_get(scene, brush, true);
BKE_brush_size_set(scene, brush, size, paint_use_channels(C));
BKE_curvemapping_init(brush->curve);
}
}
@@ -9921,16 +10408,41 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
* events. We should avoid this after events system re-design. */
if (paint_supports_dynamic_size(brush, PAINT_MODE_SCULPT) || cache->first_time) {
cache->pressure = RNA_float_get(ptr, "pressure");
cache->input_mapping.pressure = cache->pressure;
}
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;
cache->input_mapping.ytilt = cache->y_tilt;
{
float direction[4];
copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
float tmp[3];
mul_v3_v3fl(
tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
sub_v3_v3(direction, tmp);
normalize_v3(direction);
/* If the active area is being applied for symmetry, flip it
* across the symmetry axis and rotate it back to the original
* position in order to project it. This insures that the
* brush texture will be oriented correctly. */
direction[3] = 0.0f;
mul_v4_m4v4(direction, cache->projection_mat, direction);
cache->input_mapping.angle = atan2(direction[1], direction[0]);
// cache->vc
}
/* Truly temporary data that isn't stored in properties. */
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
if (!BKE_brush_use_locked_size(scene, brush)) {
cache->initial_radius = paint_calc_object_space_radius(
cache->vc, cache->true_location, BKE_brush_size_get(scene, brush));
cache->vc, cache->true_location, BKE_brush_size_get(scene, brush, true));
BKE_brush_unprojected_radius_set(scene, brush, cache->initial_radius);
}
else {
@@ -10280,7 +10792,8 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
ss->v3d = vc.v3d;
if (!BKE_brush_use_locked_size(scene, brush)) {
radius = paint_calc_object_space_radius(&vc, out->location, BKE_brush_size_get(scene, brush));
radius = paint_calc_object_space_radius(
&vc, out->location, BKE_brush_size_get(scene, brush, true));
}
else {
radius = BKE_brush_unprojected_radius_get(scene, brush);
@@ -10699,12 +11212,31 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
extern void BKE_brush_channelset_to_unified_settings(BrushChannelSet * chset,
UnifiedPaintSettings * ups);
if (ss->cache->channels_final) {
BKE_brush_channelset_free(ss->cache->channels_final);
}
if (brush->channels && sd->channels) {
ss->cache->channels_final = BKE_brush_channelset_create();
BKE_brush_channelset_merge(ss->cache->channels_final, brush->channels, sd->channels);
}
else if (brush->channels) {
ss->cache->channels_final = BKE_brush_channelset_copy(brush->channels);
}
// load settings into brush and unified paint settings
BKE_brush_channelset_compat_load(ss->cache->channels_final, brush, false);
BKE_brush_channelset_to_unified_settings(ss->cache->channels_final, ups);
ss->cache->stroke_distance = stroke->stroke_distance;
ss->cache->stroke_distance_t = stroke->stroke_distance_t;
ss->cache->stroke = stroke;
@@ -10873,7 +11405,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* Do nothing. */
}
else {
BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size, true);
brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
if (brush) {
BKE_paint_brush_set(&sd->paint, brush);

View File

@@ -37,6 +37,7 @@
#include "ED_view3d.h"
#include "BKE_attribute.h"
#include "BKE_brush_engine.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
@@ -47,6 +48,7 @@ struct KeyBlock;
struct Object;
struct SculptUndoNode;
struct bContext;
struct BrushChannelSet;
enum ePaintSymmetryFlags;
@@ -1082,6 +1084,8 @@ typedef struct AutomaskingCache {
} AutomaskingCache;
typedef struct StrokeCache {
BrushMappingData input_mapping;
/* Invariants */
float initial_radius;
float scale[3];
@@ -1089,6 +1093,8 @@ typedef struct StrokeCache {
float clip_tolerance[3];
float initial_mouse[2];
struct BrushChannelSet *channels_final;
/* Variants */
float radius;
float radius_squared;
@@ -1135,7 +1141,7 @@ typedef struct StrokeCache {
/* Clean this up! */
struct ViewContext *vc;
const struct Brush *brush;
struct Brush *brush;
float special_rotation;
float grab_delta[3], grab_delta_symmetry[3];

View File

@@ -485,16 +485,6 @@ void vec_transform(float r_dir2[3], float no[3], int bits)
}
}
volatile int blehrand = 0;
static int blehrand_get()
{
int i = blehrand;
i = (i * 124325 + 231423322) & 524287;
blehrand = i;
return i;
}
/* For bmesh: Average surrounding verts based on an orthogonality measure.
* Naturally converges to a quad-like structure. */
void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,

View File

@@ -329,7 +329,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
ED_space_image_get_size(sima, &width, &height);
ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
radius = BKE_brush_size_get(scene, brush) / (width * zoomx);
radius = BKE_brush_size_get(scene, brush, true) / (width * zoomx);
aspectRatio = width / (float)height;
/* We will compare squares to save some computation */
@@ -696,7 +696,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
alpha = BKE_brush_alpha_get(scene, brush);
radius = BKE_brush_size_get(scene, brush);
radius = BKE_brush_size_get(scene, brush, true);
sima = CTX_wm_space_image(C);
ED_space_image_get_size(sima, &width, &height);
ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);

View File

@@ -117,6 +117,9 @@ typedef enum eCurveMappingPreset {
CURVE_PRESET_ROOT = 6,
CURVE_PRESET_GAUSS = 7,
CURVE_PRESET_BELL = 8,
CURVE_PRESET_POW2 = 9,
CURVE_PRESET_POW3 = 10,
CURVE_PRESET_POW15 = 11
} eCurveMappingPreset;
/** #CurveMapping.tone */

View File

@@ -24,6 +24,8 @@
*/
#pragma once
#include "DNA_color_types.h"
typedef struct BrushMapping {
char name[64];
CurveMapping curve;
@@ -86,4 +88,7 @@ enum {
BRUSH_CHANNEL_INT = 1 << 1,
BRUSH_CHANNEL_ENUM = 1 << 2,
BRUSH_CHANNEL_BITMASK = 1 << 3,
BRUSH_CHANNEL_BOOL = 1 << 4,
BRUSH_CHANNEL_VEC3 = 1 << 5,
BRUSH_CHANNEL_VEC4 = 1 << 6
};

View File

@@ -3457,7 +3457,7 @@ int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
return eprop->defaultvalue;
}
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
ATTR_NO_OPT void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
IDProperty *idprop;

View File

@@ -43,6 +43,8 @@
#include "DNA_sculpt_brush_types.h"
#include "WM_types.h"
static EnumPropertyItem null_enum[1] = {{0, "null", 0, 0}, {-1, NULL, -1, -1}};
#ifdef RNA_RUNTIME
int rna_BrushChannelSet_channels_begin(CollectionPropertyIterator *iter, struct PointerRNA *ptr)
@@ -100,6 +102,38 @@ void rna_BrushChannel_value_range(
}
}
int rna_BrushChannel_get_ivalue(PointerRNA *rna)
{
BrushChannel *ch = rna->data;
return ch->ivalue;
}
void rna_BrushChannel_set_ivalue(PointerRNA *rna, int value)
{
BrushChannel *ch = rna->data;
ch->ivalue = value;
}
void rna_BrushChannel_ivalue_range(
PointerRNA *rna, int *min, int *max, int *soft_min, int *soft_max)
{
BrushChannel *ch = rna->data;
if (ch->def) {
*min = (int)ch->def->min;
*max = (int)ch->def->max;
*soft_min = (int)ch->def->soft_min;
*soft_max = (int)ch->def->soft_max;
}
else {
*min = 0;
*max = 65535;
*soft_min = 0;
*soft_max = 1024;
}
}
PointerRNA rna_BrushMapping_curve_get(PointerRNA *ptr)
{
BrushMapping *mapping = (BrushMapping *)ptr->data;
@@ -152,6 +186,36 @@ int rna_BrushChannel_mappings_length(PointerRNA *ptr)
return BRUSH_MAPPING_MAX;
}
int rna_BrushChannel_enum_value_get(PointerRNA *ptr)
{
BrushChannel *ch = (BrushChannel *)ptr->data;
return ch->ivalue;
}
int rna_BrushChannel_enum_value_set(PointerRNA *ptr, int val)
{
BrushChannel *ch = (BrushChannel *)ptr->data;
ch->ivalue = val;
return 1;
}
ATTR_NO_OPT const EnumPropertyItem *rna_BrushChannel_enum_value_get_items(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
bool *r_free)
{
BrushChannel *ch = (BrushChannel *)ptr->data;
if (!ch->def || !ELEM(ch->type, BRUSH_CHANNEL_ENUM, BRUSH_CHANNEL_BITMASK)) {
return null_enum;
}
return ch->def->enumdef.items;
}
#endif
static EnumPropertyItem mapping_type_items[] = {
@@ -202,6 +266,9 @@ EnumPropertyItem channel_types[] = {{BRUSH_CHANNEL_FLOAT, "FLOAT", ICON_NONE, "F
{BRUSH_CHANNEL_INT, "INT", ICON_NONE, "Int"},
{BRUSH_CHANNEL_ENUM, "ENUM", ICON_NONE, "Enum"},
{BRUSH_CHANNEL_BITMASK, "BITMASK", ICON_NONE, "Bitmask"},
{BRUSH_CHANNEL_BOOL, "BOOL", ICON_NONE, "Boolean"},
{BRUSH_CHANNEL_VEC3, "VEC3", ICON_NONE, "Color3"},
{BRUSH_CHANNEL_VEC4, "VEC4", ICON_NONE, "Color4"},
{-1, NULL, -1, NULL}};
void RNA_def_brush_channel(BlenderRNA *brna)
@@ -230,7 +297,41 @@ void RNA_def_brush_channel(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE | PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Type", "Value Type");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
prop = RNA_def_property(srna, "bool_value", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, "BrushChannel", "ivalue", 1);
RNA_def_property_ui_text(prop, "Value", "Current value");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
prop = RNA_def_property(srna, "int_value", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, "BrushChannel", "ivalue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Value", "Current value");
RNA_def_property_int_funcs(prop,
"rna_BrushChannel_get_ivalue",
"rna_BrushChannel_set_ivalue",
"rna_BrushChannel_ivalue_range");
prop = RNA_def_property(srna, "float_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, "BrushChannel", "fvalue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Value", "Current value");
RNA_def_property_float_funcs(prop,
"rna_BrushChannel_get_value",
"rna_BrushChannel_set_value",
"rna_BrushChannel_value_range");
// XXX hack warning: these next two are duplicates of above
// to get different subtypes
prop = RNA_def_property(srna, "factor_value", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "BrushChannel", "fvalue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Value", "Current value");
RNA_def_property_float_funcs(prop,
"rna_BrushChannel_get_value",
"rna_BrushChannel_set_value",
"rna_BrushChannel_value_range");
prop = RNA_def_property(srna, "percent_value", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_sdna(prop, "BrushChannel", "fvalue");
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Value", "Current value");
@@ -252,7 +353,7 @@ void RNA_def_brush_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "inherit_if_unset", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, "BrushChannel", "flag", BRUSH_CHANNEL_INHERIT_IF_UNSET);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Inherit If Unset", "Combine with default settings");
RNA_def_property_ui_text(prop, "Combine", "Combine with default settings");
prop = RNA_def_property(srna, "mappings", PROP_COLLECTION, PROP_NONE);
// RNA_def_property_collection_sdna(prop, "BrushChannel", "mappings", NULL);
@@ -266,6 +367,27 @@ void RNA_def_brush_channel(BlenderRNA *brna)
"rna_BrushChannel_mappings_lookupstring",
"rna_BrushChannel_mappings_assignint");
RNA_def_property_struct_type(prop, "BrushMapping");
prop = RNA_def_property(srna, "enum_value", PROP_ENUM, PROP_UNIT_NONE);
RNA_def_property_ui_text(prop, "Enum Value", "Enum values (for enums");
RNA_def_property_enum_items(prop, null_enum);
RNA_def_property_enum_funcs(prop,
"rna_BrushChannel_enum_value_get",
"rna_BrushChannel_enum_value_set",
"rna_BrushChannel_enum_value_get_items");
prop = RNA_def_property(srna, "flags_value", PROP_ENUM, PROP_UNIT_NONE);
RNA_def_property_ui_text(prop, "Flags Value", "Flags values");
RNA_def_property_enum_bitflag_sdna(prop, "BrushChannel", "ivalue");
RNA_def_property_enum_items(prop, null_enum);
RNA_def_property_enum_funcs(prop,
"rna_BrushChannel_enum_value_get",
"rna_BrushChannel_enum_value_set",
"rna_BrushChannel_enum_value_get_items");
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
// PROP_ENUM_FLAG
}
void RNA_def_brush_channelset(BlenderRNA *brna)

View File

@@ -353,7 +353,7 @@ void pyrna_write_set(bool val)
{
rna_disallow_writes = !val;
}
#else /* USE_PEDANTIC_WRITE */
#else /* USE_PEDANTIC_WRITE */
bool pyrna_write_check(void)
{
return true;
@@ -775,7 +775,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
ret = pyrna_prop_CreatePyObject(ptr, prop); /* Owned by the mathutils PyObject. */
}
}
#else /* USE_MATHUTILS */
#else /* USE_MATHUTILS */
(void)ptr;
(void)prop;
#endif /* USE_MATHUTILS */
@@ -1297,7 +1297,7 @@ static int pyrna_prop_to_enum_bitfield(
return ret;
}
static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
ATTR_NO_OPT static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
{
PyObject *item, *ret = NULL;
@@ -1372,7 +1372,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
return ret;
}
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
ATTR_NO_OPT PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
{
PyObject *ret;
const int type = RNA_property_type(prop);
@@ -1410,7 +1410,7 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
else {
ret = PyUnicode_FromStringAndSize(buf, buf_len);
}
#else /* USE_STRING_COERCE */
#else /* USE_STRING_COERCE */
if (subtype == PROP_BYTESTRING) {
ret = PyBytes_FromStringAndSize(buf, buf_len);
}
@@ -1537,7 +1537,7 @@ static PyObject *pyrna_func_to_py(const PointerRNA *ptr, FunctionRNA *func)
return (PyObject *)pyfunc;
}
static int pyrna_py_to_prop(
ATTR_NO_OPT static int pyrna_py_to_prop(
PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix)
{
/* XXX hard limits should be checked here. */
@@ -1723,7 +1723,7 @@ static int pyrna_py_to_prop(
else {
param = PyUnicode_AsUTF8(value);
}
#else /* USE_STRING_COERCE */
#else /* USE_STRING_COERCE */
param = PyUnicode_AsUTF8(value);
#endif /* USE_STRING_COERCE */
@@ -6507,7 +6507,7 @@ PyTypeObject pyrna_struct_Type = {
/* delete references to contained objects */
(inquiry)pyrna_struct_clear, /* inquiry tp_clear; */
#else
NULL, /* traverseproc tp_traverse; */
NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */