diff options
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 8089a65960c..1a7394e03af 100644 --- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py +++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py @@ -4,15 +4,10 @@ # <pep8 compliant> -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 @@ -101,17 +96,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 64517560256..b2a7334a13e 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -50,7 +50,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 187f793eefe..e11e6c1850b 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -135,18 +135,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..f5652384177 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 AttributeDomain 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_size(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_size(domain)), 4096, indices, [&](const int i) { + return selection[i]; + }); + } + return IndexMask(component.attribute_domain_size(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; -} |