68 {
int(FilterType::Fill),
"FILL", 0,
"Fill",
"Fill with a specific color"},
69 {
int(FilterType::Hue),
"HUE", 0,
"Hue",
"Change hue"},
70 {
int(FilterType::Saturation),
"SATURATION", 0,
"Saturation",
"Change saturation"},
71 {
int(FilterType::Value),
"VALUE", 0,
"Value",
"Change value"},
72 {
int(FilterType::Brightness),
"BRIGHTNESS", 0,
"Brightness",
"Change brightness"},
73 {
int(FilterType::Contrast),
"CONTRAST", 0,
"Contrast",
"Change contrast"},
74 {
int(FilterType::Smooth),
"SMOOTH", 0,
"Smooth",
"Smooth colors"},
75 {
int(FilterType::Red),
"RED", 0,
"Red",
"Change red channel"},
76 {
int(FilterType::Green),
"GREEN", 0,
"Green",
"Change green channel"},
77 {
int(FilterType::Blue),
"BLUE", 0,
"Blue",
"Change blue channel"},
78 {0,
nullptr, 0,
nullptr,
nullptr},
93 for (
float &factor : factors) {
94 factor = std::clamp(factor,
min, max);
105 const float filter_strength,
106 const float *filter_fill_color,
128 for (
const int i :
verts.index_range()) {
129 new_colors[i][3] = orig_colors[i][3];
133 case FilterType::Fill: {
135 for (
const int i :
verts.index_range()) {
136 float fill_color_rgba[4];
137 copy_v3_v3(fill_color_rgba, filter_fill_color);
138 fill_color_rgba[3] = 1.0f;
144 case FilterType::Hue: {
145 for (
const int i :
verts.index_range()) {
148 const float hue = hsv_color[0];
149 hsv_color[0] =
fmod((hsv_color[0] +
fabs(factors[i])) - hue, 1);
154 case FilterType::Saturation: {
155 for (
const int i :
verts.index_range()) {
159 if (hsv_color[1] > 0.001f) {
160 hsv_color[1] = std::clamp(hsv_color[1] + factors[i] * hsv_color[1], 0.0f, 1.0f);
169 case FilterType::Value: {
170 for (
const int i :
verts.index_range()) {
173 hsv_color[2] = std::clamp(hsv_color[2] + factors[i], 0.0f, 1.0f);
178 case FilterType::Red: {
179 for (
const int i :
verts.index_range()) {
181 new_colors[i][0] = std::clamp(orig_colors[i][0] + factors[i], 0.0f, 1.0f);
185 case FilterType::Green: {
186 for (
const int i :
verts.index_range()) {
188 new_colors[i][1] = std::clamp(orig_colors[i][1] + factors[i], 0.0f, 1.0f);
192 case FilterType::Blue: {
193 for (
const int i :
verts.index_range()) {
195 new_colors[i][2] = std::clamp(orig_colors[i][2] + factors[i], 0.0f, 1.0f);
199 case FilterType::Brightness: {
201 for (
const int i :
verts.index_range()) {
202 const float brightness = factors[i];
203 const float contrast = 0;
204 float delta = contrast / 2.0f;
205 const float gain = 1.0f - delta * 2.0f;
207 const float offset = gain * (brightness + delta);
208 for (
int component = 0; component < 3; component++) {
209 new_colors[i][component] = std::clamp(
210 gain * orig_colors[i][component] + offset, 0.0f, 1.0f);
215 case FilterType::Contrast: {
217 for (
const int i :
verts.index_range()) {
218 const float brightness = 0;
219 const float contrast = factors[i];
220 float delta = contrast / 2.0f;
221 float gain = 1.0f - delta * 2.0f;
225 gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
226 offset = gain * (brightness - delta);
230 offset = gain * (brightness + delta);
232 for (
int component = 0; component < 3; component++) {
233 new_colors[i][component] = std::clamp(
234 gain * orig_colors[i][component] + offset, 0.0f, 1.0f);
239 case FilterType::Smooth: {
244 for (
const int i :
verts.index_range()) {
248 color_attribute.
span,
262 color_attribute.
span,
267 for (
const int i :
verts.index_range()) {
268 const int vert =
verts[i];
270 if (factors[i] < 0.0f) {
271 interp_v4_v4v4(average_colors[i], average_colors[i], colors[i], 0.5f);
274 bool copy_alpha = colors[i][3] == average_colors[i][3];
276 if (factors[i] < 0.0f) {
277 float delta_color[4];
281 sub_v4_v4(delta_color, average_colors[i]);
290 new_colors[i] =
math::clamp(new_colors[i], 0.0f, 1.0f);
294 new_colors[i][3] = average_colors[i][3];
301 for (
const int i :
verts.index_range()) {
308 color_attribute.
span);
319 const Span<int> corner_verts = mesh.corner_verts();
329 node_mask.foreach_index(
GrainSize(1), [&](
const int i) {
330 for (
const int vert : nodes[i].verts()) {
332 faces, corner_verts, vert_to_face_map, colors, color_attribute.
domain, vert);
341 for ([[maybe_unused]]
const int iteration :
IndexRange(2)) {
342 node_mask.foreach_index(
GrainSize(1), [&](
const int i) {
350 tls.averaged_colors.resize(
verts.size());
353 pre_smoothed_color.
as_span(), vert_neighbors, averaged_colors);
355 for (
const int i :
verts.index_range()) {
357 pre_smoothed_color[
verts[i]], averaged_colors[i], 0.5f);
378 if (filter_strength < 0.0 && ss.filter_cache->pre_smoothed_color.is_empty()) {
385 const Span<int> corner_verts = mesh.corner_verts();
435 const float len = (
event->prev_press_xy[0] -
event->xy[0]) * 0.001f;
459 float mval_fl[2] = {
float(mval[0]),
float(mval[1])};
462 if (use_automasking) {
536 const char *ui_name =
nullptr;
556 ot->
name =
"Filter Color";
557 ot->
idname =
"SCULPT_OT_color_filter";
558 ot->
description =
"Applies a filter to modify the active color attribute";
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
#define SCULPT_FACE_SET_NONE
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
void BKE_sculpt_color_layer_create_if_needed(Object *object)
A BVH for high poly meshes.
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t)
MINLINE void sub_v4_v4(float r[4], const float a[4])
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
#define BLT_I18NCONTEXT_ID_MESH
@ V3D_SHADING_VERTEX_COLOR
void ED_image_paint_brush_type_update_sticky_shading_color(bContext *C, Object *ob)
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
Read Guarded memory(de)allocation.
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
constexpr Span< T > as_span() const
void resize(const int64_t new_size)
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name)
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 fabs(const float2 a)
pbvh::Tree * pbvh_get(Object &object)
std::unique_ptr< Cache > cache_init(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
bool is_enabled(const Sculpt &sd, const Object &object, const Brush *br)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
bke::GSpanAttributeWriter active_color_attribute_for_write(Mesh &mesh)
static std::string sculpt_color_filter_get_name(wmOperatorType *, PointerRNA *ptr)
static const float fill_filter_default_color[4]
static void color_filter_task(const Depsgraph &depsgraph, Object &ob, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const MeshAttributeData &attribute_data, const FilterType mode, const float filter_strength, const float *filter_fill_color, const bke::pbvh::MeshNode &node, LocalData &tls, bke::GSpanAttributeWriter &color_attribute)
static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static BLI_NOINLINE void clamp_factors(const MutableSpan< float > factors, const float min, const float max)
float4 color_vert_get(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, int vert)
void color_vert_set(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, bke::AttrDomain color_domain, int vert, const float4 &color, GMutableSpan color_attribute)
static int sculpt_color_filter_init(bContext *C, wmOperator *op)
void SCULPT_OT_color_filter(wmOperatorType *ot)
static int sculpt_color_filter_exec(bContext *C, wmOperator *op)
bke::GAttributeReader active_color_attribute(const Mesh &mesh)
static void sculpt_color_presmooth_init(const Mesh &mesh, Object &object)
static void sculpt_color_filter_end(bContext *C, Object &ob)
static void sculpt_color_filter_apply(bContext *C, wmOperator *op, Object &ob)
static void sculpt_color_filter_ui(bContext *, wmOperator *op)
static EnumPropertyItem prop_color_filter_types[]
static int sculpt_color_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
void cache_init(bContext *C, Object &ob, const Sculpt &sd, undo::Type undo_type, const float mval_fl[2], float area_normal_radius, float start_strength)
void register_operator_props(wmOperatorType *ot)
void neighbor_color_average(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const GSpan color_attribute, const bke::AttrDomain color_domain, const Span< Vector< int > > vert_neighbors, const MutableSpan< float4 > smooth_colors)
void neighbor_data_average_mesh(const Span< T > src, const Span< Vector< int > > vert_neighbors, const MutableSpan< T > dst)
void push_end(Object &ob)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
void flush_update_step(bContext *C, UpdateType update_type)
void scale_factors(MutableSpan< float > factors, float strength)
Span< float4 > orig_color_data_get_mesh(const Object &object, const bke::pbvh::MeshNode &node)
void calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, MutableSpan< Vector< int > > result)
T clamp(const T &a, const T &min, const T &max)
T interpolate(const T &a, const T &b, const FactorT &t)
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
bool RNA_property_enum_name_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
bool SCULPT_mode_poll(bContext *C)
bool SCULPT_handles_colors_report(const Object &object, ReportList *reports)
struct SculptSession * sculpt
blender::ed::sculpt_paint::filter::Cache * filter_cache
VArraySpan< bool > hide_vert
Vector< float4 > new_colors
Vector< float4 > average_colors
Vector< Vector< int > > vert_neighbors
float start_filter_strength
std::unique_ptr< auto_mask::Cache > automasking
Array< float4 > pre_smoothed_color
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
std::string(* get_name)(wmOperatorType *ot, PointerRNA *ptr)
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
void(* ui)(bContext *C, wmOperator *op)
struct ReportList * reports
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)