Refactor: Sculpt: Use newer structure for color filter factors
Part of #118145.
This commit is contained in:
@@ -46,127 +46,130 @@
|
||||
|
||||
namespace blender::ed::sculpt_paint::color {
|
||||
|
||||
enum eSculptColorFilterTypes {
|
||||
COLOR_FILTER_FILL,
|
||||
COLOR_FILTER_HUE,
|
||||
COLOR_FILTER_SATURATION,
|
||||
COLOR_FILTER_VALUE,
|
||||
COLOR_FILTER_BRIGHTNESS,
|
||||
COLOR_FILTER_CONTRAST,
|
||||
COLOR_FILTER_RED,
|
||||
COLOR_FILTER_GREEN,
|
||||
COLOR_FILTER_BLUE,
|
||||
COLOR_FILTER_SMOOTH,
|
||||
enum class FilterType {
|
||||
Fill = 0,
|
||||
Hue,
|
||||
Saturation,
|
||||
Value,
|
||||
Brightness,
|
||||
Contrast,
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
Smooth,
|
||||
};
|
||||
|
||||
static const float fill_filter_default_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
static EnumPropertyItem prop_color_filter_types[] = {
|
||||
{COLOR_FILTER_FILL, "FILL", 0, "Fill", "Fill with a specific color"},
|
||||
{COLOR_FILTER_HUE, "HUE", 0, "Hue", "Change hue"},
|
||||
{COLOR_FILTER_SATURATION, "SATURATION", 0, "Saturation", "Change saturation"},
|
||||
{COLOR_FILTER_VALUE, "VALUE", 0, "Value", "Change value"},
|
||||
|
||||
{COLOR_FILTER_BRIGHTNESS, "BRIGHTNESS", 0, "Brightness", "Change brightness"},
|
||||
{COLOR_FILTER_CONTRAST, "CONTRAST", 0, "Contrast", "Change contrast"},
|
||||
|
||||
{COLOR_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth colors"},
|
||||
|
||||
{COLOR_FILTER_RED, "RED", 0, "Red", "Change red channel"},
|
||||
{COLOR_FILTER_GREEN, "GREEN", 0, "Green", "Change green channel"},
|
||||
{COLOR_FILTER_BLUE, "BLUE", 0, "Blue", "Change blue channel"},
|
||||
{int(FilterType::Fill), "FILL", 0, "Fill", "Fill with a specific color"},
|
||||
{int(FilterType::Hue), "HUE", 0, "Hue", "Change hue"},
|
||||
{int(FilterType::Saturation), "SATURATION", 0, "Saturation", "Change saturation"},
|
||||
{int(FilterType::Value), "VALUE", 0, "Value", "Change value"},
|
||||
{int(FilterType::Brightness), "BRIGHTNESS", 0, "Brightness", "Change brightness"},
|
||||
{int(FilterType::Contrast), "CONTRAST", 0, "Contrast", "Change contrast"},
|
||||
{int(FilterType::Smooth), "SMOOTH", 0, "Smooth", "Smooth colors"},
|
||||
{int(FilterType::Red), "RED", 0, "Red", "Change red channel"},
|
||||
{int(FilterType::Green), "GREEN", 0, "Green", "Change green channel"},
|
||||
{int(FilterType::Blue), "BLUE", 0, "Blue", "Change blue channel"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float4> new_colors;
|
||||
};
|
||||
|
||||
static void color_filter_task(Object &ob,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const Span<bool> hide_vert,
|
||||
const Span<float> mask,
|
||||
const int mode,
|
||||
const FilterType mode,
|
||||
const float filter_strength,
|
||||
const float *filter_fill_color,
|
||||
bke::pbvh::Node *node,
|
||||
const bke::pbvh::Node &node,
|
||||
LocalData &tls,
|
||||
bke::GSpanAttributeWriter &color_attribute)
|
||||
{
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
|
||||
const Span<float4> orig_colors = orig_color_data_get_mesh(ob, *node);
|
||||
const Span<float4> orig_colors = orig_color_data_get_mesh(ob, node);
|
||||
|
||||
auto_mask::NodeData automask_data = auto_mask::node_begin(
|
||||
ob, ss.filter_cache->automasking.get(), *node);
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(*node);
|
||||
tls.factors.resize(verts.size());
|
||||
const MutableSpan<float> factors = tls.factors;
|
||||
fill_factor_from_hide_and_mask(mesh, verts, factors);
|
||||
auto_mask::calc_vert_factors(ob, *ss.filter_cache->automasking, node, verts, factors);
|
||||
scale_factors(factors, filter_strength);
|
||||
|
||||
tls.new_colors.resize(verts.size());
|
||||
const MutableSpan<float4> new_colors = tls.new_colors;
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
if (!hide_vert.is_empty() && hide_vert[vert]) {
|
||||
continue;
|
||||
}
|
||||
auto_mask::node_update(automask_data, i);
|
||||
|
||||
float3 orig_color;
|
||||
float4 final_color;
|
||||
float3 hsv_color;
|
||||
int hue;
|
||||
float brightness, contrast, gain, delta, offset;
|
||||
float fade = mask.is_empty() ? 1.0f : 1.0f - mask[vert];
|
||||
fade *= filter_strength;
|
||||
fade *= auto_mask::factor_get(
|
||||
ss.filter_cache->automasking.get(), ss, PBVHVertRef{vert}, &automask_data);
|
||||
if (fade == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
float fade = factors[i];
|
||||
|
||||
copy_v3_v3(orig_color, orig_colors[i]);
|
||||
final_color[3] = orig_colors[i][3]; /* Copy alpha */
|
||||
new_colors[i][3] = orig_colors[i][3]; /* Copy alpha */
|
||||
|
||||
switch (mode) {
|
||||
case COLOR_FILTER_FILL: {
|
||||
case FilterType::Fill: {
|
||||
float fill_color_rgba[4];
|
||||
copy_v3_v3(fill_color_rgba, filter_fill_color);
|
||||
fill_color_rgba[3] = 1.0f;
|
||||
fade = clamp_f(fade, 0.0f, 1.0f);
|
||||
mul_v4_fl(fill_color_rgba, fade);
|
||||
blend_color_mix_float(final_color, orig_colors[i], fill_color_rgba);
|
||||
blend_color_mix_float(new_colors[i], orig_colors[i], fill_color_rgba);
|
||||
break;
|
||||
}
|
||||
case COLOR_FILTER_HUE:
|
||||
case FilterType::Hue: {
|
||||
rgb_to_hsv_v(orig_color, hsv_color);
|
||||
hue = hsv_color[0];
|
||||
hsv_color[0] = fmod((hsv_color[0] + fabs(fade)) - hue, 1);
|
||||
hsv_to_rgb_v(hsv_color, final_color);
|
||||
hsv_to_rgb_v(hsv_color, new_colors[i]);
|
||||
break;
|
||||
case COLOR_FILTER_SATURATION:
|
||||
}
|
||||
case FilterType::Saturation: {
|
||||
rgb_to_hsv_v(orig_color, hsv_color);
|
||||
|
||||
if (hsv_color[1] > 0.001f) {
|
||||
hsv_color[1] = clamp_f(hsv_color[1] + fade * hsv_color[1], 0.0f, 1.0f);
|
||||
hsv_to_rgb_v(hsv_color, final_color);
|
||||
hsv_to_rgb_v(hsv_color, new_colors[i]);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(final_color, orig_color);
|
||||
copy_v3_v3(new_colors[i], orig_color);
|
||||
}
|
||||
break;
|
||||
case COLOR_FILTER_VALUE:
|
||||
}
|
||||
case FilterType::Value: {
|
||||
rgb_to_hsv_v(orig_color, hsv_color);
|
||||
hsv_color[2] = clamp_f(hsv_color[2] + fade, 0.0f, 1.0f);
|
||||
hsv_to_rgb_v(hsv_color, final_color);
|
||||
hsv_to_rgb_v(hsv_color, new_colors[i]);
|
||||
break;
|
||||
case COLOR_FILTER_RED:
|
||||
}
|
||||
case FilterType::Red: {
|
||||
orig_color[0] = clamp_f(orig_color[0] + fade, 0.0f, 1.0f);
|
||||
copy_v3_v3(final_color, orig_color);
|
||||
copy_v3_v3(new_colors[i], orig_color);
|
||||
break;
|
||||
case COLOR_FILTER_GREEN:
|
||||
}
|
||||
case FilterType::Green: {
|
||||
orig_color[1] = clamp_f(orig_color[1] + fade, 0.0f, 1.0f);
|
||||
copy_v3_v3(final_color, orig_color);
|
||||
copy_v3_v3(new_colors[i], orig_color);
|
||||
break;
|
||||
case COLOR_FILTER_BLUE:
|
||||
}
|
||||
case FilterType::Blue: {
|
||||
orig_color[2] = clamp_f(orig_color[2] + fade, 0.0f, 1.0f);
|
||||
copy_v3_v3(final_color, orig_color);
|
||||
copy_v3_v3(new_colors[i], orig_color);
|
||||
break;
|
||||
case COLOR_FILTER_BRIGHTNESS:
|
||||
}
|
||||
case FilterType::Brightness: {
|
||||
fade = clamp_f(fade, -1.0f, 1.0f);
|
||||
brightness = fade;
|
||||
contrast = 0;
|
||||
@@ -174,11 +177,12 @@ static void color_filter_task(Object &ob,
|
||||
gain = 1.0f - delta * 2.0f;
|
||||
delta *= -1;
|
||||
offset = gain * (brightness + delta);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f);
|
||||
for (int component = 0; component < 3; component++) {
|
||||
new_colors[i][component] = clamp_f(gain * orig_color[component] + offset, 0.0f, 1.0f);
|
||||
}
|
||||
break;
|
||||
case COLOR_FILTER_CONTRAST:
|
||||
}
|
||||
case FilterType::Contrast: {
|
||||
fade = clamp_f(fade, -1.0f, 1.0f);
|
||||
brightness = 0;
|
||||
contrast = fade;
|
||||
@@ -192,11 +196,12 @@ static void color_filter_task(Object &ob,
|
||||
delta *= -1;
|
||||
offset = gain * (brightness + delta);
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final_color[i] = clamp_f(gain * orig_color[i] + offset, 0.0f, 1.0f);
|
||||
for (int component = 0; component < 3; component++) {
|
||||
new_colors[i][component] = clamp_f(gain * orig_color[component] + offset, 0.0f, 1.0f);
|
||||
}
|
||||
break;
|
||||
case COLOR_FILTER_SMOOTH: {
|
||||
}
|
||||
case FilterType::Smooth: {
|
||||
fade = clamp_f(fade, -1.0f, 1.0f);
|
||||
float4 smooth_color = smooth::neighbor_color_average(ss,
|
||||
faces,
|
||||
@@ -226,32 +231,33 @@ static void color_filter_task(Object &ob,
|
||||
copy_v4_v4(delta_color, ss.filter_cache->pre_smoothed_color[vert]);
|
||||
sub_v4_v4(delta_color, smooth_color);
|
||||
|
||||
copy_v4_v4(final_color, col);
|
||||
madd_v4_v4fl(final_color, delta_color, fade);
|
||||
copy_v4_v4(new_colors[i], col);
|
||||
madd_v4_v4fl(new_colors[i], delta_color, fade);
|
||||
}
|
||||
else {
|
||||
blend_color_interpolate_float(final_color, col, smooth_color, fade);
|
||||
blend_color_interpolate_float(new_colors[i], col, smooth_color, fade);
|
||||
}
|
||||
|
||||
final_color = math::clamp(final_color, 0.0f, 1.0f);
|
||||
new_colors[i] = math::clamp(new_colors[i], 0.0f, 1.0f);
|
||||
|
||||
/* Prevent accumulated numeric error from corrupting alpha. */
|
||||
if (copy_alpha) {
|
||||
final_color[3] = smooth_color[3];
|
||||
new_colors[i][3] = smooth_color[3];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
color_vert_set(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
color_attribute.domain,
|
||||
vert,
|
||||
final_color,
|
||||
verts[i],
|
||||
new_colors[i],
|
||||
color_attribute.span);
|
||||
}
|
||||
BKE_pbvh_node_mark_update_color(node);
|
||||
}
|
||||
|
||||
static void sculpt_color_presmooth_init(const Mesh &mesh, SculptSession &ss)
|
||||
@@ -274,7 +280,7 @@ static void sculpt_color_presmooth_init(const Mesh &mesh, SculptSession &ss)
|
||||
for (const int vert : verts) {
|
||||
pre_smoothed_color[vert] = color_vert_get(
|
||||
faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, vert);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -301,8 +307,8 @@ static void sculpt_color_presmooth_init(const Mesh &mesh, SculptSession &ss)
|
||||
for (const int i : verts.index_range()) {
|
||||
pre_smoothed_color[verts[i]] = math::interpolate(
|
||||
pre_smoothed_color[verts[i]], averaged_colors[i], 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -311,7 +317,7 @@ static void sculpt_color_filter_apply(bContext *C, wmOperator *op, Object &ob)
|
||||
{
|
||||
SculptSession &ss = *ob.sculpt;
|
||||
|
||||
const int mode = RNA_enum_get(op->ptr, "type");
|
||||
const FilterType mode = FilterType(RNA_enum_get(op->ptr, "type"));
|
||||
float filter_strength = RNA_float_get(op->ptr, "strength");
|
||||
float fill_color[3];
|
||||
|
||||
@@ -329,21 +335,20 @@ static void sculpt_color_filter_apply(bContext *C, wmOperator *op, Object &ob)
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const GroupedSpan<int> vert_to_face_map = ss.vert_to_face_map;
|
||||
bke::GSpanAttributeWriter color_attribute = active_color_attribute_for_write(mesh);
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
|
||||
const VArraySpan mask = *attributes.lookup<float>(".sculpt_mask", bke::AttrDomain::Point);
|
||||
|
||||
threading::EnumerableThreadSpecific<LocalData> all_tls;
|
||||
threading::parallel_for(nodes.index_range(), 1, [&](const IndexRange range) {
|
||||
LocalData &tls = all_tls.local();
|
||||
for (const int i : range) {
|
||||
color_filter_task(ob,
|
||||
faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_vert,
|
||||
mask,
|
||||
mode,
|
||||
filter_strength,
|
||||
fill_color,
|
||||
nodes[i],
|
||||
*nodes[i],
|
||||
tls,
|
||||
color_attribute);
|
||||
BKE_pbvh_node_mark_update_color(nodes[i]);
|
||||
}
|
||||
@@ -491,7 +496,7 @@ static void sculpt_color_filter_ui(bContext * /*C*/, wmOperator *op)
|
||||
|
||||
uiItemR(layout, op->ptr, "strength", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
||||
if (RNA_enum_get(op->ptr, "type") == COLOR_FILTER_FILL) {
|
||||
if (FilterType(RNA_enum_get(op->ptr, "type")) == FilterType::Fill) {
|
||||
uiItemR(layout, op->ptr, "fill_color", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
}
|
||||
@@ -516,7 +521,8 @@ void SCULPT_OT_color_filter(wmOperatorType *ot)
|
||||
/* rna */
|
||||
filter::register_operator_props(ot);
|
||||
|
||||
RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_FILL, "Filter Type", "");
|
||||
RNA_def_enum(
|
||||
ot->srna, "type", prop_color_filter_types, int(FilterType::Fill), "Filter Type", "");
|
||||
|
||||
PropertyRNA *prop = RNA_def_float_color(ot->srna,
|
||||
"fill_color",
|
||||
|
||||
Reference in New Issue
Block a user