diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc | 393 |
1 files changed, 216 insertions, 177 deletions
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) |