Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-06-23 19:32:53 +0300
committerHans Goudey <h.goudey@me.com>2022-06-23 19:33:11 +0300
commit2eba15d3e862fdf112edda6b26b7e1535f0fdb07 (patch)
treeb67e797668e14ea9c6a50bcca1aea41b7bdda730
parent5c6ffd07e0de8f4917927da69a68db9af205973d (diff)
Fix T98975: Broken vertex paint mode operators
All of the operators in vertex paint mode didn't work properly with the new color attribute system. They only worked on byte color type attributes on the face corner domain. Since there are four possible combinations of domains and types now, it mostly ended up being simpler to convert the code to C++ and use the geometry component API for retrieving attributes, interpolating between domains, etc. The code changes ended up being fairly large, but the result should be simpler now. Differential Revision: https://developer.blender.org/D15261
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py23
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h8
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc393
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c75
5 files changed, 227 insertions, 273 deletions
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index a3c0b73fc0e..fc14879cf18 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -2,15 +2,10 @@
# Copyright Campbell Barton.
-def get_vcolor_layer_data(me):
- for lay in me.vertex_colors:
- if lay.active:
- return lay.data
-
- lay = me.vertex_colors.new()
- lay.active = True
- return lay.data
-
+def ensure_active_color_attribute(me):
+ if me.attributes.active_color:
+ return me.attributes.active_color
+ return me.color_attributes.new("Color", 'BYTE_COLOR', 'FACE_CORNER')
def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only, normalize):
from mathutils import Vector
@@ -99,17 +94,21 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
else:
tone_range = 1.0 / tone_range
- active_col_layer = get_vcolor_layer_data(me)
- if not active_col_layer:
+ active_color_attribute = ensure_active_color_attribute(me)
+ if not active_color_attribute:
return {'CANCELLED'}
+ point_domain = active_color_attribute.domain == 'POINT'
+
+ attribute_data = active_color_attribute.data
+
use_paint_mask = me.use_paint_mask
for i, p in enumerate(me.polygons):
if not use_paint_mask or p.select:
for loop_index in p.loop_indices:
loop = me.loops[loop_index]
v = loop.vertex_index
- col = active_col_layer[loop_index].color
+ col = attribute_data[v if point_domain else loop_index].color
tone = vert_tone[v]
tone = (tone - min_tone) * tone_range
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 8879161d2af..34247b4ef75 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -53,7 +53,6 @@ set(SRC
paint_utils.c
paint_vertex.cc
paint_vertex_color_ops.cc
- paint_vertex_color_utils.c
paint_vertex_proj.c
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 3f4e660b229..ea17114efa5 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -134,18 +134,10 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_color(struct Scene *scene, struct VPaint *vp, bool secondary);
-/* paint_vertex_color_utils.c */
-
/**
* \note weight-paint has an equivalent function: #ED_wpaint_blend_tool
*/
unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i);
-/**
- * Apply callback to each vertex of the active vertex color layer.
- */
-bool ED_vpaint_color_transform(struct Object *ob,
- VPaintTransform_Callback vpaint_tx_fn,
- const void *user_data);
/* paint_vertex_weight_utils.c */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
index 6a47aceb2b0..bd015784ad7 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
@@ -12,11 +12,15 @@
#include "DNA_scene_types.h"
#include "BLI_array.hh"
+#include "BLI_index_mask_ops.hh"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
+#include "BLI_vector.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "DEG_depsgraph.h"
@@ -32,6 +36,10 @@
#include "paint_intern.h" /* own include */
using blender::Array;
+using blender::ColorGeometry4f;
+using blender::GMutableSpan;
+using blender::IndexMask;
+using blender::Vector;
/* -------------------------------------------------------------------- */
/** \name Internal Utility Functions
@@ -62,34 +70,57 @@ static void tag_object_after_update(Object *object)
static bool vertex_paint_from_weight(Object *ob)
{
- Mesh *me;
- const MPoly *mp;
- int vgroup_active;
+ using namespace blender;
+ Mesh *me;
if (((me = BKE_mesh_from_object(ob)) == nullptr ||
(ED_mesh_color_ensure(me, nullptr)) == false)) {
return false;
}
- /* TODO: respect selection. */
- /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway. */
- mp = me->mpoly;
- vgroup_active = me->vertex_group_active_index - 1;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
- uint j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- const float weight = BKE_defvert_find_weight(&me->dvert[vidx], vgroup_active);
- const uchar grayscale = weight * 255;
- lcol->r = grayscale;
- lcol->b = grayscale;
- lcol->g = grayscale;
- lcol++;
- j++;
- } while (j < mp->totloop);
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ const int active_vertex_group_index = me->vertex_group_active_index - 1;
+ const bDeformGroup *deform_group = static_cast<const bDeformGroup *>(
+ BLI_findlink(&me->vertex_group_names, active_vertex_group_index));
+ if (deform_group == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ MeshComponent component;
+ component.replace(me, GeometryOwnershipType::Editable);
+
+ bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write(
+ active_color_layer->name);
+ if (!color_attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ /* Retrieve the vertex group with the domain and type of the existing color
+ * attribute, in order to let the attribute API handle both conversions. */
+ const GVArray vertex_group = component.attribute_get_for_read(
+ deform_group->name,
+ ATTR_DOMAIN_POINT,
+ bke::cpp_type_to_custom_data_type(color_attribute.varray.type()));
+ if (!vertex_group) {
+ BLI_assert_unreachable();
+ return false;
}
+ GVArray_GSpan interpolated{component.attribute_try_adapt_domain(
+ vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)};
+
+ color_attribute.varray.set_all(interpolated.data());
+
+ if (color_attribute.tag_modified_fn) {
+ color_attribute.tag_modified_fn();
+ }
tag_object_after_update(ob);
return true;
@@ -128,99 +159,81 @@ void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
/** \name Smooth Vertex Colors Operator
* \{ */
-static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
+static IndexMask get_selected_indices(const Mesh &mesh,
+ const eAttrDomain domain,
+ Vector<int64_t> &indices)
{
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const MPoly *mp;
- bool has_shared = false;
+ using namespace blender;
+ Span<MVert> verts(mesh.mvert, mesh.totvert);
+ Span<MPoly> faces(mesh.mpoly, mesh.totpoly);
+
+ MeshComponent component;
+ component.replace(&const_cast<Mesh &>(mesh), GeometryOwnershipType::ReadOnly);
+
+ if (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) {
+ const VArray<bool> selection = component.attribute_try_adapt_domain(
+ VArray<bool>::ForFunc(faces.size(),
+ [&](const int i) { return faces[i].flag & ME_FACE_SEL; }),
+ ATTR_DOMAIN_FACE,
+ domain);
+
+ return index_mask_ops::find_indices_based_on_predicate(
+ IndexMask(component.attribute_domain_num(domain)), 4096, indices, [&](const int i) {
+ return selection[i];
+ });
+ }
+ if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) {
+ const VArray<bool> selection = component.attribute_try_adapt_domain(
+ VArray<bool>::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }),
+ ATTR_DOMAIN_POINT,
+ domain);
+
+ return index_mask_ops::find_indices_based_on_predicate(
+ IndexMask(component.attribute_domain_num(domain)), 4096, indices, [&](const int i) {
+ return selection[i];
+ });
+ }
+ return IndexMask(component.attribute_domain_num(domain));
+}
- if (me->mloopcol == nullptr || me->totvert == 0 || me->totpoly == 0) {
+static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask selection)
+{
+ using namespace blender;
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
return;
}
- int(*scol)[4] = static_cast<int(*)[4]>(MEM_callocN(sizeof(int) * me->totvert * 5, "scol"));
-
- int i;
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
- scol[ml->v][0] += lcol->r;
- scol[ml->v][1] += lcol->g;
- scol[ml->v][2] += lcol->b;
- scol[ml->v][3] += 1;
- has_shared = 1;
- }
- }
+ MeshComponent component;
+ component.replace(&mesh, GeometryOwnershipType::Editable);
+
+ if (component.attribute_get_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
+ return;
}
- if (has_shared) {
- for (i = 0; i < me->totvert; i++) {
- if (scol[i][3] != 0) {
- scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
- scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
- scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
- }
- }
+ GVArray color_attribute_point = component.attribute_try_get_for_read(active_color_layer->name,
+ ATTR_DOMAIN_POINT);
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
- if (mlooptag[mp->loopstart + j]) {
- lcol->r = scol[ml->v][0];
- lcol->g = scol[ml->v][1];
- lcol->b = scol[ml->v][2];
- }
- }
- }
- }
- }
+ GVArray color_attribute_corner = component.attribute_try_adapt_domain(
+ color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER);
- MEM_freeN(scol);
+ color_attribute_corner.materialize(selection, active_color_layer->data);
}
static bool vertex_color_smooth(Object *ob)
{
Mesh *me;
- const MPoly *mp;
- int i, j;
-
if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
(ED_mesh_color_ensure(me, nullptr) == false)) {
return false;
}
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- Array<bool> loop_tag(me->totloop, false);
-
- /* simply tag loops of selected faces */
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- const MLoop *ml = me->mloop + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- j = 0;
- do {
- if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
- loop_tag[mp->loopstart + j] = true;
- }
- ml++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
+ Vector<int64_t> indices;
+ const IndexMask selection = get_selected_indices(*me, ATTR_DOMAIN_CORNER, indices);
- vertex_color_smooth_looptag(me, loop_tag.data());
+ face_corner_color_equalize_vertices(*me, selection);
tag_object_after_update(ob);
@@ -258,22 +271,52 @@ void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
/** \name Vertex Color Transformation Operators
* \{ */
-struct VPaintTx_BrightContrastData {
- /* pre-calculated */
- float gain;
- float offset;
-};
-
-static void vpaint_tx_brightness_contrast(const float col[3],
- const void *user_data,
- float r_col[3])
+template<typename TransformFn>
+static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
{
- const VPaintTx_BrightContrastData *data = static_cast<const VPaintTx_BrightContrastData *>(
- user_data);
+ using namespace blender;
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * col[i] + data->offset;
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ MeshComponent component;
+ component.replace(&mesh, GeometryOwnershipType::Editable);
+
+ bke::WriteAttributeLookup color_attribute = component.attribute_try_get_for_write(
+ active_color_layer->name);
+ if (!color_attribute) {
+ BLI_assert_unreachable();
+ return false;
}
+
+ Vector<int64_t> indices;
+ const IndexMask selection = get_selected_indices(mesh, color_attribute.domain, indices);
+
+ attribute_math::convert_to_static_type(color_attribute.varray.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ if constexpr (std::is_same_v<T, ColorGeometry4f>) {
+ ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4f>(i);
+ transform_fn(color);
+ color_attribute.varray.set_by_copy(i, &color);
+ }
+ else if constexpr (std::is_same_v<T, ColorGeometry4b>) {
+ ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4b>(i).decode();
+ transform_fn(color);
+ ColorGeometry4b color_encoded = color.encode();
+ color_attribute.varray.set_by_copy(i, &color_encoded);
+ }
+ }
+ });
+ });
+
+ DEG_id_tag_update(&mesh.id, 0);
+
+ return true;
}
static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
@@ -303,15 +346,20 @@ static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
}
}
- VPaintTx_BrightContrastData user_data{};
- user_data.gain = gain;
- user_data.offset = offset;
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_CANCELLED;
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = gain * color[i] + offset;
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
@@ -337,45 +385,39 @@ void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
RNA_def_property_ui_range(prop, min, max, 1, 1);
}
-struct VPaintTx_HueSatData {
- float hue;
- float sat;
- float val;
-};
-
-static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
+static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
{
- const VPaintTx_HueSatData *data = static_cast<const VPaintTx_HueSatData *>(user_data);
- float hsv[3];
- rgb_to_hsv_v(col, hsv);
+ Object *obact = CTX_data_active_object(C);
- hsv[0] += (data->hue - 0.5f);
- if (hsv[0] > 1.0f) {
- hsv[0] -= 1.0f;
- }
- else if (hsv[0] < 0.0f) {
- hsv[0] += 1.0f;
+ const float hue = RNA_float_get(op->ptr, "h");
+ const float sat = RNA_float_get(op->ptr, "s");
+ const float val = RNA_float_get(op->ptr, "v");
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return OPERATOR_CANCELLED;
}
- hsv[1] *= data->sat;
- hsv[2] *= data->val;
- hsv_to_rgb_v(hsv, r_col);
-}
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ float hsv[3];
+ rgb_to_hsv_v(color, hsv);
-static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
+ hsv[0] += (hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= sat;
+ hsv[2] *= val;
- VPaintTx_HueSatData user_data{};
- user_data.hue = RNA_float_get(op->ptr, "h");
- user_data.sat = RNA_float_get(op->ptr, "s");
- user_data.val = RNA_float_get(op->ptr, "v");
+ hsv_to_rgb_v(hsv, color);
+ });
- if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
@@ -398,22 +440,24 @@ void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
}
-static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
-{
- for (int i = 0; i < 3; i++) {
- r_col[i] = 1.0f - col[i];
- }
-}
-
static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obact = CTX_data_active_object(C);
- if (ED_vpaint_color_transform(obact, vpaint_tx_invert, nullptr)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_CANCELLED;
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = 1.0f - color[i];
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
@@ -431,32 +475,27 @@ void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-struct VPaintTx_LevelsData {
- float gain;
- float offset;
-};
-
-static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
-{
- const VPaintTx_LevelsData *data = static_cast<const VPaintTx_LevelsData *>(user_data);
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * (col[i] + data->offset);
- }
-}
-
static int vertex_color_levels_exec(bContext *C, wmOperator *op)
{
Object *obact = CTX_data_active_object(C);
- VPaintTx_LevelsData user_data{};
- user_data.gain = RNA_float_get(op->ptr, "gain");
- user_data.offset = RNA_float_get(op->ptr, "offset");
+ const float gain = RNA_float_get(op->ptr, "gain");
+ const float offset = RNA_float_get(op->ptr, "offset");
- if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_CANCELLED;
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = gain * (color[i] + offset);
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
}
void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
deleted file mode 100644
index cd099f71ccd..00000000000
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edsculpt
- *
- * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
- */
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_color.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-
-#include "BKE_context.h"
-#include "BKE_mesh.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_mesh.h"
-
-#include "paint_intern.h" /* own include */
-
-#define EPS_SATURATION 0.0005f
-
-bool ED_vpaint_color_transform(struct Object *ob,
- VPaintTransform_Callback vpaint_tx_fn,
- const void *user_data)
-{
- Mesh *me;
- const MPoly *mp;
- int i, j;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
- return false;
- }
-
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- float col_mix[3];
- rgb_uchar_to_float(col_mix, &lcol->r);
-
- vpaint_tx_fn(col_mix, user_data, col_mix);
-
- rgb_float_to_uchar(&lcol->r, col_mix);
- }
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- DEG_id_tag_update(&me->id, 0);
-
- return true;
-}