diff --git a/source/blender/blenlib/BLI_color_mix.hh b/source/blender/blenlib/BLI_color_mix.hh index f7c8897ffe7..652b5c6f0e1 100644 --- a/source/blender/blenlib/BLI_color_mix.hh +++ b/source/blender/blenlib/BLI_color_mix.hh @@ -87,6 +87,17 @@ struct FloatTraits { } }; +template struct TraitsType { + using type = void; +}; +template<> struct TraitsType { + using type = FloatTraits; +}; +template<> struct TraitsType { + using type = ByteTraits; +}; +template using Traits = typename TraitsType::type; + static float get_luminance(ColorPaint4f c) { return IMB_colormanagement_get_luminance(&c.r); diff --git a/source/blender/editors/sculpt_paint/paint_intern.hh b/source/blender/editors/sculpt_paint/paint_intern.hh index 872d2076fb8..1221060cd38 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.hh +++ b/source/blender/editors/sculpt_paint/paint_intern.hh @@ -136,8 +136,6 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot); void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot); void PAINT_OT_vertex_paint(wmOperatorType *ot); -unsigned int vpaint_get_current_color(Scene *scene, VPaint *vp, bool secondary); - /** * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index 303458214b0..7a92dc8909d 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -77,11 +77,6 @@ using namespace blender::color; /** \name Internal Utilities * \{ */ -static uint color2uint(ColorPaint4b c) -{ - return *(reinterpret_cast(&c)); -} - static bool isZero(ColorPaint4f c) { return c.r == 0.0f && c.g == 0.0f && c.b == 0.0f && c.a == 0.0f; @@ -92,7 +87,7 @@ static bool isZero(ColorPaint4b c) return c.r == 0 && c.g == 0 && c.b == 0 && c.a == 0; } -template static ColorPaint4f toFloat(const Color &c) +template static ColorPaint4f toFloat(const Color &c) { if constexpr (std::is_same_v) { return c.decode(); @@ -102,7 +97,7 @@ template static ColorPaint4f toFloat(const Color } } -template static Color fromFloat(const ColorPaint4f &c) +template static Color fromFloat(const ColorPaint4f &c) { if constexpr (std::is_same_v) { return c.encode(); @@ -135,26 +130,6 @@ struct NormalAnglePrecalc { float angle_range; }; -/* Returns number of elements. */ -static int get_vcol_elements(Mesh *me, size_t *r_elem_size) -{ - const std::optional meta_data = *me->attributes().lookup_meta_data( - me->active_color_attribute); - - if (r_elem_size) { - *r_elem_size = meta_data->data_type == CD_PROP_COLOR ? sizeof(float[4]) : 4ULL; - } - - switch (meta_data->domain) { - case ATTR_DOMAIN_POINT: - return me->totvert; - case ATTR_DOMAIN_CORNER: - return me->totloop; - default: - return 0; - } -} - static void view_angle_limits_init(NormalAnglePrecalc *a, float angle, bool do_mask_normal) { angle = RAD2DEGF(angle); @@ -328,8 +303,7 @@ bool weight_paint_poll_ignore_tool(bContext *C) return weight_paint_poll_ex(C, false); } -template -static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary) +static ColorPaint4f vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary) { const Brush *brush = BKE_paint_brush_for_read(&vp->paint); float color[4]; @@ -339,15 +313,7 @@ static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary) color[3] = 1.0f; /* alpha isn't used, could even be removed to speedup paint a little */ - return fromFloat(ColorPaint4f(color)); -} - -uint vpaint_get_current_color(Scene *scene, VPaint *vp, bool secondary) -{ - ColorPaint4b col = vpaint_get_current_col( - scene, vp, secondary); - - return color2uint(col); + return ColorPaint4f(color); } /* wpaint has 'wpaint_blend' */ @@ -1213,7 +1179,7 @@ static void vwpaint_init_stroke(Depsgraph *depsgraph, Object *ob) * vwpaint_update_cache_invariants and vwpaint_update_cache_variants. */ if (!ss->cache) { - ss->cache = (StrokeCache *)MEM_callocN(sizeof(StrokeCache), "stroke cache"); + ss->cache = MEM_new(__func__); } } @@ -1226,18 +1192,16 @@ static void vertex_paint_init_stroke(Scene *scene, Depsgraph *depsgraph, Object /* Allocate scratch array for previous colors if needed. */ if (!brush_use_accumulate(ts->vpaint)) { - if (!ss->cache->prev_colors_vpaint) { - Mesh *me = BKE_object_get_original_mesh(ob); - size_t elem_size; - int elem_num; - - elem_num = get_vcol_elements(me, &elem_size); - - ss->cache->prev_colors_vpaint = (uint *)MEM_callocN(elem_num * elem_size, __func__); + if (ss->cache->prev_colors_vpaint.is_empty()) { + const Mesh *mesh = BKE_object_get_original_mesh(ob); + const GVArray attribute = *mesh->attributes().lookup(mesh->active_color_attribute); + ss->cache->prev_colors_vpaint = GArray(attribute.type(), attribute.size()); + attribute.type().value_initialize_n(ss->cache->prev_colors_vpaint.data(), + ss->cache->prev_colors_vpaint.size()); } } else { - MEM_SAFE_FREE(ss->cache->prev_colors_vpaint); + ss->cache->prev_colors_vpaint = {}; } } @@ -1618,7 +1582,7 @@ static void vwpaint_update_cache_invariants( /* VW paint needs to allocate stroke cache before update is called. */ if (!ss->cache) { - cache = (StrokeCache *)MEM_callocN(sizeof(StrokeCache), "stroke cache"); + cache = MEM_new(__func__); ss->cache = cache; } else { @@ -2826,17 +2790,30 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot) * - revise whether op->customdata should be added in object, in set_vpaint. */ -struct VPaintDataBase { +template +static void to_static_color_type(const eCustomDataType type, const Func &func) +{ + switch (type) { + case CD_PROP_COLOR: + func(ColorGeometry4f()); + break; + case CD_PROP_BYTE_COLOR: + func(ColorGeometry4b()); + break; + default: + BLI_assert_unreachable(); + break; + } +} + +struct VPaintData { ViewContext vc; eAttrDomain domain; eCustomDataType type; -}; -template -struct VPaintData : public VPaintDataBase { NormalAnglePrecalc normal_angle_precalc; - Color paintcol; + ColorPaint4f paintcol; VertProjHandle *vp_handle; CoNo *vertexcosnos; @@ -2845,33 +2822,24 @@ struct VPaintData : public VPaintDataBase { /* Special storage for smear brush, avoid feedback loop - update each step. */ struct { - void *color_prev; - void *color_curr; + GArray<> color_prev; + GArray<> color_curr; } smear; }; -template -static void *vpaint_init_vpaint(bContext *C, - wmOperator *op, - Scene *scene, - Depsgraph *depsgraph, - VPaint *vp, - Object *ob, - Mesh *me, - const Brush *brush) +static VPaintData *vpaint_init_vpaint(bContext *C, + wmOperator *op, + Scene *scene, + Depsgraph *depsgraph, + VPaint *vp, + Object *ob, + Mesh *me, + const eAttrDomain domain, + const eCustomDataType type, + const Brush *brush) { - VPaintData *vpd; - - /* make mode data storage */ - vpd = MEM_new>("VPaintData"); - - if constexpr (std::is_same_v) { - vpd->type = CD_PROP_COLOR; - } - else { - vpd->type = CD_PROP_BYTE_COLOR; - } - + VPaintData *vpd = MEM_new(__func__); + vpd->type = type; vpd->domain = domain; ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph); @@ -2879,17 +2847,17 @@ static void *vpaint_init_vpaint(bContext *C, vp->paint.brush->falloff_angle, (vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0); - vpd->paintcol = vpaint_get_current_col( + vpd->paintcol = vpaint_get_current_col( scene, vp, (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT)); vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex; if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) { const GVArray attribute = *me->attributes().lookup(me->active_color_attribute, domain); - vpd->smear.color_prev = MEM_malloc_arrayN(attribute.size(), attribute.type().size(), __func__); - attribute.materialize(vpd->smear.color_prev); + vpd->smear.color_prev = GArray(attribute.type(), attribute.size()); + attribute.materialize(vpd->smear.color_prev.data()); - vpd->smear.color_curr = MEM_dupallocN(vpd->smear.color_prev); + vpd->smear.color_curr = vpd->smear.color_prev; } /* Create projection handle */ @@ -2899,7 +2867,7 @@ static void *vpaint_init_vpaint(bContext *C, ob->sculpt->building_vp_handle = false; } - return static_cast(vpd); + return vpd; } static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2]) @@ -2928,30 +2896,8 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo return false; } - void *vpd = nullptr; - - if (meta_data->domain == ATTR_DOMAIN_POINT) { - if (meta_data->data_type == CD_PROP_COLOR) { - vpd = vpaint_init_vpaint( - C, op, scene, depsgraph, vp, ob, me, brush); - } - else if (meta_data->data_type == CD_PROP_BYTE_COLOR) { - vpd = vpaint_init_vpaint( - C, op, scene, depsgraph, vp, ob, me, brush); - } - } - else if (meta_data->domain == ATTR_DOMAIN_CORNER) { - if (meta_data->data_type == CD_PROP_COLOR) { - vpd = vpaint_init_vpaint( - C, op, scene, depsgraph, vp, ob, me, brush); - } - else if (meta_data->data_type == CD_PROP_BYTE_COLOR) { - vpd = vpaint_init_vpaint( - C, op, scene, depsgraph, vp, ob, me, brush); - } - } - - BLI_assert(vpd != nullptr); + VPaintData *vpd = vpaint_init_vpaint( + C, op, scene, depsgraph, vp, ob, me, meta_data->domain, meta_data->data_type, brush); paint_stroke_set_mode_data(stroke, vpd); @@ -2963,24 +2909,40 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo return true; } -template static void do_vpaint_brush_blur_loops(bContext *C, Sculpt * /*sd*/, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Span nodes, - Color *lcol) + GMutableSpan attribute) { - using Blend = typename Traits::BlendType; - SculptSession *ss = ob->sculpt; const Brush *brush = ob->sculpt->cache->brush; const Scene *scene = CTX_data_scene(C); - Color *previous_color = static_cast(ss->cache->prev_colors_vpaint); + const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); + const bool has_grids = (pbvh_type == PBVH_GRIDS); + + const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + const StrokeCache *cache = ss->cache; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data( + scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_normal = vwpaint_use_normal(vp); + const bool use_vert_sel = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != + 0; + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + SculptBrushTest test_init; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test_init, brush->falloff_shape); + const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( + ss, brush->falloff_shape); + + GMutableSpan g_previous_color = ss->cache->prev_colors_vpaint; const blender::VArray select_vert = *me->attributes().lookup_or_default( ".select_vert", ATTR_DOMAIN_POINT, false); @@ -2988,26 +2950,8 @@ static void do_vpaint_brush_blur_loops(bContext *C, ".select_poly", ATTR_DOMAIN_FACE, false); blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { + SculptBrushTest test = test_init; for (int n : range) { - const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); - const bool has_grids = (pbvh_type == PBVH_GRIDS); - - const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - const StrokeCache *cache = ss->cache; - float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; - get_brush_alpha_data( - scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); - const bool use_normal = vwpaint_use_normal(vp); - const bool use_vert_sel = (me->editflag & - (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( - ss, brush->falloff_shape); - /* For each vertex */ PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3036,90 +2980,119 @@ static void do_vpaint_brush_blur_loops(bContext *C, const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); - /* Get the average poly color */ - Color color_final(0, 0, 0, 0); + to_static_color_type(vpd->type, [&](auto dummy) { + using T = decltype(dummy); + using Color = + std::conditional_t, ColorPaint4f, ColorPaint4b>; + using Traits = color::Traits; + using Blend = typename Traits::BlendType; + MutableSpan previous_color = g_previous_color.typed().template cast(); + MutableSpan colors = attribute.typed().template cast(); + /* Get the average poly color */ + Color color_final(0, 0, 0, 0); - int total_hit_loops = 0; - Blend blend[4] = {0}; + int total_hit_loops = 0; + Blend blend[4] = {0}; - for (const int p_index : gmap->vert_to_poly[v_index]) { - if (use_face_sel && !select_poly[p_index]) { - continue; - } - const blender::IndexRange poly = ss->polys[p_index]; - total_hit_loops += poly.size(); - for (const int corner : poly) { - Color *col = lcol + corner; - - /* Color is squared to compensate the `sqrt` color encoding. */ - blend[0] += (Blend)col->r * (Blend)col->r; - blend[1] += (Blend)col->g * (Blend)col->g; - blend[2] += (Blend)col->b * (Blend)col->b; - blend[3] += (Blend)col->a * (Blend)col->a; - } - } - - if (total_hit_loops == 0) { - continue; - } - - /* Use rgb^2 color averaging. */ - Color *col = &color_final; - - color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops))); - color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops))); - color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops))); - color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops))); - - /* For each poly owning this vert, - * paint each loop belonging to this vert. */ - for (const int j : gmap->vert_to_poly[v_index].index_range()) { - const int p_index = gmap->vert_to_poly[v_index][j]; - const int l_index = gmap->vert_to_loop[v_index][j]; - BLI_assert(ss->corner_verts[l_index] == v_index); - if (use_face_sel && !select_poly[p_index]) { - continue; - } - Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ - - if (previous_color != nullptr) { - /* Get the previous loop color */ - if (isZero(previous_color[l_index])) { - previous_color[l_index] = lcol[l_index]; + for (const int p_index : gmap->vert_to_poly[v_index]) { + if (use_face_sel && !select_poly[p_index]) { + return; + } + const blender::IndexRange poly = ss->polys[p_index]; + total_hit_loops += poly.size(); + for (const int corner : poly) { + const Color &col = colors[corner]; + + /* Color is squared to compensate the `sqrt` color encoding. */ + blend[0] += (Blend)col.r * (Blend)col.r; + blend[1] += (Blend)col.g * (Blend)col.g; + blend[2] += (Blend)col.b * (Blend)col.b; + blend[3] += (Blend)col.a * (Blend)col.a; } - color_orig = previous_color[l_index]; } - const float final_alpha = Traits::range * brush_fade * brush_strength * - brush_alpha_pressure * grid_alpha; - /* Mix the new color with the original - * based on the brush strength and the curve. */ - lcol[l_index] = vpaint_blend( - vp, lcol[l_index], color_orig, *col, final_alpha, Traits::range * brush_strength); - } + + if (total_hit_loops == 0) { + return; + } + + /* Use rgb^2 color averaging. */ + Color *col = &color_final; + + color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops))); + color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops))); + color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops))); + color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops))); + + /* For each poly owning this vert, + * paint each loop belonging to this vert. */ + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + const int l_index = gmap->vert_to_loop[v_index][j]; + BLI_assert(ss->corner_verts[l_index] == v_index); + if (use_face_sel && !select_poly[p_index]) { + continue; + } + Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ + + if (!previous_color.is_empty()) { + /* Get the previous loop color */ + if (isZero(previous_color[l_index])) { + previous_color[l_index] = colors[l_index]; + } + color_orig = previous_color[l_index]; + } + const float final_alpha = Traits::range * brush_fade * brush_strength * + brush_alpha_pressure * grid_alpha; + /* Mix the new color with the original + * based on the brush strength and the curve. */ + colors[l_index] = vpaint_blend(vp, + colors[l_index], + color_orig, + *col, + final_alpha, + Traits::range * brush_strength); + } + }); } BKE_pbvh_vertex_iter_end; }; }); } -template static void do_vpaint_brush_blur_verts(bContext *C, Sculpt * /*sd*/, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Span nodes, - Color *lcol) + GMutableSpan attribute) { - using Blend = typename Traits::BlendType; - SculptSession *ss = ob->sculpt; const Brush *brush = ob->sculpt->cache->brush; const Scene *scene = CTX_data_scene(C); - Color *previous_color = static_cast(ss->cache->prev_colors_vpaint); + const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); + const bool has_grids = (pbvh_type == PBVH_GRIDS); + + const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + const StrokeCache *cache = ss->cache; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data( + scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_normal = vwpaint_use_normal(vp); + const bool use_vert_sel = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != + 0; + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + SculptBrushTest test_init; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test_init, brush->falloff_shape); + const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( + ss, brush->falloff_shape); + + GMutableSpan g_previous_color = ss->cache->prev_colors_vpaint; const blender::VArray select_vert = *me->attributes().lookup_or_default( ".select_vert", ATTR_DOMAIN_POINT, false); @@ -3127,26 +3100,8 @@ static void do_vpaint_brush_blur_verts(bContext *C, ".select_poly", ATTR_DOMAIN_FACE, false); blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { + SculptBrushTest test = test_init; for (int n : range) { - const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); - const bool has_grids = (pbvh_type == PBVH_GRIDS); - - const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - const StrokeCache *cache = ss->cache; - float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; - get_brush_alpha_data( - scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); - const bool use_normal = vwpaint_use_normal(vp); - const bool use_vert_sel = (me->editflag & - (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( - ss, brush->falloff_shape); - /* For each vertex */ PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3175,51 +3130,51 @@ static void do_vpaint_brush_blur_verts(bContext *C, const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); /* Get the average poly color */ - Color color_final(0, 0, 0, 0); + to_static_color_type(vpd->type, [&](auto dummy) { + using T = decltype(dummy); + using Color = + std::conditional_t, ColorPaint4f, ColorPaint4b>; + using Traits = color::Traits; + using Blend = typename Traits::BlendType; + MutableSpan previous_color = g_previous_color.typed().template cast(); + MutableSpan colors = attribute.typed().template cast(); + Color color_final(0, 0, 0, 0); - int total_hit_loops = 0; - Blend blend[4] = {0}; + int total_hit_loops = 0; + Blend blend[4] = {0}; - for (const int p_index : gmap->vert_to_poly[v_index]) { - if (use_face_sel && !select_poly[p_index]) { - continue; + for (const int p_index : gmap->vert_to_poly[v_index]) { + if (use_face_sel && !select_poly[p_index]) { + continue; + } + const blender::IndexRange poly = ss->polys[p_index]; + total_hit_loops += poly.size(); + for (const int vert : ss->corner_verts.slice(poly)) { + const Color &col = colors[vert]; + + /* Color is squared to compensate the `sqrt` color encoding. */ + blend[0] += (Blend)col.r * (Blend)col.r; + blend[1] += (Blend)col.g * (Blend)col.g; + blend[2] += (Blend)col.b * (Blend)col.b; + blend[3] += (Blend)col.a * (Blend)col.a; + } } - const blender::IndexRange poly = ss->polys[p_index]; - total_hit_loops += poly.size(); - for (const int vert : ss->corner_verts.slice(poly)) { - Color *col = lcol + vert; - /* Color is squared to compensate the `sqrt` color encoding. */ - blend[0] += (Blend)col->r * (Blend)col->r; - blend[1] += (Blend)col->g * (Blend)col->g; - blend[2] += (Blend)col->b * (Blend)col->b; - blend[3] += (Blend)col->a * (Blend)col->a; + if (total_hit_loops == 0) { + return; } - } + /* Use rgb^2 color averaging. */ + color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops))); + color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops))); + color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops))); + color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops))); - if (total_hit_loops == 0) { - continue; - } - /* Use rgb^2 color averaging. */ - Color *col = &color_final; - - color_final.r = Traits::round(sqrtf(Traits::divide_round(blend[0], total_hit_loops))); - color_final.g = Traits::round(sqrtf(Traits::divide_round(blend[1], total_hit_loops))); - color_final.b = Traits::round(sqrtf(Traits::divide_round(blend[2], total_hit_loops))); - color_final.a = Traits::round(sqrtf(Traits::divide_round(blend[3], total_hit_loops))); - - /* For each poly owning this vert, - * paint each loop belonging to this vert. */ - for (const int p_index : gmap->vert_to_poly[v_index]) { - if (use_face_sel && !select_poly[p_index]) { - continue; - } Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ - if (previous_color != nullptr) { + if (!previous_color.is_empty()) { /* Get the previous loop color */ if (isZero(previous_color[v_index])) { - previous_color[v_index] = lcol[v_index]; + previous_color[v_index] = colors[v_index]; } color_orig = previous_color[v_index]; } @@ -3227,24 +3182,27 @@ static void do_vpaint_brush_blur_verts(bContext *C, brush_alpha_pressure * grid_alpha; /* Mix the new color with the original * based on the brush strength and the curve. */ - lcol[v_index] = vpaint_blend( - vp, lcol[v_index], color_orig, *col, final_alpha, Traits::range * brush_strength); - } + colors[v_index] = vpaint_blend(vp, + colors[v_index], + color_orig, + color_final, + final_alpha, + Traits::range * brush_strength); + }); } BKE_pbvh_vertex_iter_end; }; }); } -template static void do_vpaint_brush_smear(bContext *C, Sculpt * /*sd*/, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Span nodes, - Color *lcol) + GMutableSpan attribute) { SculptSession *ss = ob->sculpt; @@ -3258,9 +3216,31 @@ static void do_vpaint_brush_smear(bContext *C, const Brush *brush = ob->sculpt->cache->brush; const Scene *scene = CTX_data_scene(C); - Color *color_curr = static_cast(vpd->smear.color_curr); - Color *color_prev_smear = static_cast(vpd->smear.color_prev); - Color *color_prev = reinterpret_cast(ss->cache->prev_colors_vpaint); + GMutableSpan g_color_curr = vpd->smear.color_curr; + GMutableSpan g_color_prev_smear = vpd->smear.color_prev; + GMutableSpan g_color_prev = ss->cache->prev_colors_vpaint; + + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + + get_brush_alpha_data( + scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_normal = vwpaint_use_normal(vp); + const bool use_vert_sel = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != + 0; + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + float brush_dir[3]; + sub_v3_v3v3(brush_dir, cache->location, cache->last_location); + project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal); + if (normalize_v3(brush_dir) == 0.0f) { + return; + } + + SculptBrushTest test_init; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test_init, brush->falloff_shape); + const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( + ss, brush->falloff_shape); const blender::VArray select_vert = *me->attributes().lookup_or_default( ".select_vert", ATTR_DOMAIN_POINT, false); @@ -3268,29 +3248,8 @@ static void do_vpaint_brush_smear(bContext *C, ".select_poly", ATTR_DOMAIN_FACE, false); blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { + SculptBrushTest test = test_init; for (int n : range) { - float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; - - get_brush_alpha_data( - scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); - const bool use_normal = vwpaint_use_normal(vp); - const bool use_vert_sel = (me->editflag & - (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - float brush_dir[3]; - sub_v3_v3v3(brush_dir, cache->location, cache->last_location); - project_plane_v3_v3v3(brush_dir, brush_dir, cache->view_normal); - if (normalize_v3(brush_dir) == 0.0f) { - continue; - } - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( - ss, brush->falloff_shape); - /* For each vertex */ PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3328,198 +3287,215 @@ static void do_vpaint_brush_smear(bContext *C, /* Get the color of the loop in the opposite * direction of the brush movement */ - Color color_final(0, 0, 0, 0); + to_static_color_type(vpd->type, [&](auto dummy) { + using T = decltype(dummy); + using Color = + std::conditional_t, ColorPaint4f, ColorPaint4b>; + using Traits = color::Traits; + MutableSpan color_curr = g_color_curr.typed().template cast(); + MutableSpan color_prev_smear = + g_color_prev_smear.typed().template cast(); + MutableSpan color_prev = g_color_prev.typed().template cast(); + MutableSpan colors = attribute.typed().template cast(); - for (const int j : gmap->vert_to_poly[v_index].index_range()) { - const int p_index = gmap->vert_to_poly[v_index][j]; - const int l_index = gmap->vert_to_loop[v_index][j]; - BLI_assert(ss->corner_verts[l_index] == v_index); - UNUSED_VARS_NDEBUG(l_index); - if (use_face_sel && !select_poly[p_index]) { - continue; + Color color_final(0, 0, 0, 0); + + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + const int l_index = gmap->vert_to_loop[v_index][j]; + BLI_assert(ss->corner_verts[l_index] == v_index); + UNUSED_VARS_NDEBUG(l_index); + if (use_face_sel && !select_poly[p_index]) { + continue; + } + for (const int corner : ss->polys[p_index]) { + const int v_other_index = ss->corner_verts[corner]; + if (v_other_index == v_index) { + continue; + } + + /* Get the direction from the + * selected vert to the neighbor. */ + float other_dir[3]; + sub_v3_v3v3(other_dir, mv_curr, ss->vert_positions[v_other_index]); + project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal); + + normalize_v3(other_dir); + + const float stroke_dot = dot_v3v3(other_dir, brush_dir); + int elem_index; + + if (vpd->domain == ATTR_DOMAIN_POINT) { + elem_index = v_other_index; + } + else { + elem_index = corner; + } + + if (stroke_dot > stroke_dot_max) { + stroke_dot_max = stroke_dot; + color_final = color_prev_smear[elem_index]; + do_color = true; + } + } } - for (const int corner : ss->polys[p_index]) { - const int v_other_index = ss->corner_verts[corner]; - if (v_other_index == v_index) { + + if (!do_color) { + return; + } + + const float final_alpha = Traits::range * brush_fade * brush_strength * + brush_alpha_pressure * grid_alpha; + + /* For each poly owning this vert, + * paint each loop belonging to this vert. */ + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + + int elem_index; + if (vpd->domain == ATTR_DOMAIN_POINT) { + elem_index = v_index; + } + else { + const int l_index = gmap->vert_to_loop[v_index][j]; + elem_index = l_index; + BLI_assert(ss->corner_verts[l_index] == v_index); + } + if (use_face_sel && !select_poly[p_index]) { continue; } - /* Get the direction from the - * selected vert to the neighbor. */ - float other_dir[3]; - sub_v3_v3v3(other_dir, mv_curr, ss->vert_positions[v_other_index]); - project_plane_v3_v3v3(other_dir, other_dir, cache->view_normal); - - normalize_v3(other_dir); - - const float stroke_dot = dot_v3v3(other_dir, brush_dir); - int elem_index; - - if constexpr (domain == ATTR_DOMAIN_POINT) { - elem_index = v_other_index; - } - else { - elem_index = corner; - } - - if (stroke_dot > stroke_dot_max) { - stroke_dot_max = stroke_dot; - color_final = color_prev_smear[elem_index]; - do_color = true; - } - } - } - - if (!do_color) { - continue; - } - - const float final_alpha = Traits::range * brush_fade * brush_strength * - brush_alpha_pressure * grid_alpha; - - /* For each poly owning this vert, - * paint each loop belonging to this vert. */ - for (const int j : gmap->vert_to_poly[v_index].index_range()) { - const int p_index = gmap->vert_to_poly[v_index][j]; - - int elem_index; - if constexpr (domain == ATTR_DOMAIN_POINT) { - elem_index = v_index; - } - else { - const int l_index = gmap->vert_to_loop[v_index][j]; - elem_index = l_index; - BLI_assert(ss->corner_verts[l_index] == v_index); - } - if (use_face_sel && !select_poly[p_index]) { - continue; - } - - /* Get the previous element color */ - Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ - - if (color_prev != nullptr) { /* Get the previous element color */ - if (isZero(color_prev[elem_index])) { - color_prev[elem_index] = lcol[elem_index]; - } - color_orig = color_prev[elem_index]; - } - /* Mix the new color with the original - * based on the brush strength and the curve. */ - lcol[elem_index] = vpaint_blend(vp, - lcol[elem_index], - color_orig, - color_final, - final_alpha, - Traits::range * brush_strength); + Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ - color_curr[elem_index] = lcol[elem_index]; - } + if (!color_prev.is_empty()) { + /* Get the previous element color */ + if (isZero(color_prev[elem_index])) { + color_prev[elem_index] = colors[elem_index]; + } + color_orig = color_prev[elem_index]; + } + /* Mix the new color with the original + * based on the brush strength and the curve. */ + colors[elem_index] = vpaint_blend(vp, + colors[elem_index], + color_orig, + color_final, + final_alpha, + Traits::range * brush_strength); + + color_curr[elem_index] = colors[elem_index]; + } + }); } BKE_pbvh_vertex_iter_end; } }); } -template -static void calculate_average_color(VPaintData *vpd, +static void calculate_average_color(VPaintData *vpd, Object *ob, Mesh *me, const Brush *brush, - Color *lcol, + const GSpan attribute, Span nodes) { - using Blend = typename Traits::BlendType; + SculptSession *ss = ob->sculpt; + const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); + const bool has_grids = (pbvh_type == PBVH_GRIDS); + const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + + StrokeCache *cache = ss->cache; + const bool use_vert_sel = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != + 0; + + SculptBrushTest test_init; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test_init, brush->falloff_shape); const blender::VArray select_vert = *me->attributes().lookup_or_default( ".select_vert", ATTR_DOMAIN_POINT, false); - VPaintAverageAccum *accum = (VPaintAverageAccum *)MEM_mallocN( - sizeof(*accum) * nodes.size(), __func__); - blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { - for (int n : range) { - SculptSession *ss = ob->sculpt; - const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); - const bool has_grids = (pbvh_type == PBVH_GRIDS); - const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + to_static_color_type(vpd->type, [&](auto dummy) { + using T = decltype(dummy); + using Color = + std::conditional_t, ColorPaint4f, ColorPaint4b>; + using Traits = color::Traits; + using Blend = typename Traits::BlendType; + const Span colors = attribute.typed().template cast(); - StrokeCache *cache = ss->cache; - const bool use_vert_sel = (me->editflag & - (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; + Array> accum(nodes.size()); + blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { + SculptBrushTest test = test_init; + for (int n : range) { + VPaintAverageAccum &accum2 = accum[n]; + accum2.len = 0; + memset(accum2.value, 0, sizeof(accum2.value)); - VPaintAverageAccum *accum2 = accum + n; - accum2->len = 0; - memset(accum2->value, 0, sizeof(accum2->value)); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - - /* For each vertex */ - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - /* Test to see if the vertex coordinates are within the spherical brush region. */ - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - if (BKE_brush_curve_strength(brush, 0.0, cache->radius) <= 0.0f) { - continue; - } - const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] : - vd.vert_indices[vd.i]; - /* If the vertex is selected for painting. */ - if (use_vert_sel && !select_vert[v_index]) { - continue; - } - - accum2->len += gmap->vert_to_poly[v_index].size(); - /* if a vertex is within the brush region, then add its color to the blend. */ - for (int j = 0; j < gmap->vert_to_poly[v_index].size(); j++) { - int elem_index; - - if constexpr (domain == ATTR_DOMAIN_CORNER) { - elem_index = gmap->vert_to_loop[v_index][j]; + /* For each vertex */ + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { + /* Test to see if the vertex coordinates are within the spherical brush region. */ + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; } - else { - elem_index = v_index; + if (BKE_brush_curve_strength(brush, 0.0, cache->radius) <= 0.0f) { + continue; + } + const int v_index = has_grids ? ss->corner_verts[vd.grid_indices[vd.g]] : + vd.vert_indices[vd.i]; + /* If the vertex is selected for painting. */ + if (use_vert_sel && !select_vert[v_index]) { + continue; } - Color *col = lcol + elem_index; + accum2.len += gmap->vert_to_poly[v_index].size(); + /* if a vertex is within the brush region, then add its color to the blend. */ + for (int j = 0; j < gmap->vert_to_poly[v_index].size(); j++) { + int elem_index; - /* Color is squared to compensate the `sqrt` color encoding. */ - accum2->value[0] += col->r * col->r; - accum2->value[1] += col->g * col->g; - accum2->value[2] += col->b * col->b; + if (vpd->domain == ATTR_DOMAIN_CORNER) { + elem_index = gmap->vert_to_loop[v_index][j]; + } + else { + elem_index = v_index; + } + + /* Color is squared to compensate the `sqrt` color encoding. */ + const Color &col = colors[elem_index]; + accum2.value[0] += col.r * col.r; + accum2.value[1] += col.g * col.g; + accum2.value[2] += col.b * col.b; + } } + BKE_pbvh_vertex_iter_end; } - BKE_pbvh_vertex_iter_end; + }); + + Blend accum_len = 0; + Blend accum_value[3] = {0}; + Color blend(0, 0, 0, 0); + + for (int i = 0; i < nodes.size(); i++) { + accum_len += accum[i].len; + accum_value[0] += accum[i].value[0]; + accum_value[1] += accum[i].value[1]; + accum_value[2] += accum[i].value[2]; + } + if (accum_len != 0) { + blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len))); + blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len))); + blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len))); + blend.a = Traits::range; + + vpd->paintcol = toFloat(blend); } }); - - Blend accum_len = 0; - Blend accum_value[3] = {0}; - Color blend(0, 0, 0, 0); - - for (int i = 0; i < nodes.size(); i++) { - accum_len += accum[i].len; - accum_value[0] += accum[i].value[0]; - accum_value[1] += accum[i].value[1]; - accum_value[2] += accum[i].value[2]; - } - if (accum_len != 0) { - blend.r = Traits::round(sqrtf(Traits::divide_round(accum_value[0], accum_len))); - blend.g = Traits::round(sqrtf(Traits::divide_round(accum_value[1], accum_len))); - blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len))); - blend.a = Traits::range; - - vpd->paintcol = blend; - } } -template +template static float paint_and_tex_color_alpha(VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, const float v_co[3], Color *r_color) { @@ -3535,15 +3511,14 @@ static float paint_and_tex_color_alpha(VPaint *vp, return rgba[3]; } -template static void vpaint_do_draw(bContext *C, Sculpt * /*sd*/, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Span nodes, - Color *lcol) + GMutableSpan attribute) { SculptSession *ss = ob->sculpt; const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); @@ -3551,7 +3526,25 @@ static void vpaint_do_draw(bContext *C, const Brush *brush = ob->sculpt->cache->brush; const Scene *scene = CTX_data_scene(C); - Color *previous_color = static_cast(ss->cache->prev_colors_vpaint); + const bool has_grids = (pbvh_type == PBVH_GRIDS); + const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; + + const StrokeCache *cache = ss->cache; + float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; + get_brush_alpha_data( + scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); + const bool use_normal = vwpaint_use_normal(vp); + const bool use_vert_sel = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != + 0; + const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + + SculptBrushTest test_init; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test_init, brush->falloff_shape); + const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( + ss, brush->falloff_shape); + + GMutableSpan g_previous_color = ss->cache->prev_colors_vpaint; const blender::VArray select_vert = *me->attributes().lookup_or_default( ".select_vert", ATTR_DOMAIN_POINT, false); @@ -3560,26 +3553,7 @@ static void vpaint_do_draw(bContext *C, blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { for (int n : range) { - const bool has_grids = (pbvh_type == PBVH_GRIDS); - const SculptVertexPaintGeomMap *gmap = &ss->mode.vpaint.gmap; - - const StrokeCache *cache = ss->cache; - float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; - get_brush_alpha_data( - scene, ss, brush, &brush_size_pressure, &brush_alpha_value, &brush_alpha_pressure); - const bool use_normal = vwpaint_use_normal(vp); - const bool use_vert_sel = (me->editflag & - (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0; - const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - const float *sculpt_normal_frontface = SCULPT_brush_frontface_normal_from_falloff_shape( - ss, brush->falloff_shape); - - Color paintcol = vpd->paintcol; - + SculptBrushTest test = test_init; /* For each vertex */ PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3610,100 +3584,106 @@ static void vpaint_do_draw(bContext *C, } const float brush_fade = BKE_brush_curve_strength(brush, sqrtf(test.dist), cache->radius); - Color color_final = paintcol; + to_static_color_type(vpd->type, [&](auto dummy) { + using T = decltype(dummy); + using Color = + std::conditional_t, ColorPaint4f, ColorPaint4b>; + using Traits = color::Traits; + MutableSpan colors = attribute.typed().template cast(); + MutableSpan previous_color = g_previous_color.typed().template cast(); + Color color_final = fromFloat(vpd->paintcol); - /* If we're painting with a texture, sample the texture color and alpha. */ - float tex_alpha = 1.0; - if (vpd->is_texbrush) { - /* NOTE: we may want to paint alpha as vertex color alpha. */ - tex_alpha = paint_and_tex_color_alpha( - vp, vpd, vpd->vertexcosnos[v_index].co, &color_final); - } - - Color color_orig(0, 0, 0, 0); - - if constexpr (domain == ATTR_DOMAIN_POINT) { - int v_index = vd.index; - - if (previous_color != nullptr) { - /* Get the previous loop color */ - if (isZero(previous_color[v_index])) { - previous_color[v_index] = lcol[v_index]; - } - color_orig = previous_color[v_index]; + /* If we're painting with a texture, sample the texture color and alpha. */ + float tex_alpha = 1.0; + if (vpd->is_texbrush) { + /* NOTE: we may want to paint alpha as vertex color alpha. */ + tex_alpha = paint_and_tex_color_alpha( + vp, vpd, vpd->vertexcosnos[v_index].co, &color_final); } - const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha * - brush_alpha_pressure * grid_alpha; - lcol[v_index] = vpaint_blend(vp, - lcol[v_index], - color_orig, - color_final, - final_alpha, - Traits::range * brush_strength); - } - else { - /* For each poly owning this vert, paint each loop belonging to this vert. */ - for (const int j : gmap->vert_to_poly[v_index].index_range()) { - const int p_index = gmap->vert_to_poly[v_index][j]; - const int l_index = gmap->vert_to_loop[v_index][j]; - BLI_assert(ss->corner_verts[l_index] == v_index); - if (use_face_sel && !select_poly[p_index]) { - continue; - } - Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */ + Color color_orig(0, 0, 0, 0); - if (previous_color != nullptr) { + if (vpd->domain == ATTR_DOMAIN_POINT) { + int v_index = vd.index; + + if (!previous_color.is_empty()) { /* Get the previous loop color */ - if (isZero(previous_color[l_index])) { - previous_color[l_index] = lcol[l_index]; + if (isZero(previous_color[v_index])) { + previous_color[v_index] = colors[v_index]; } - color_orig = previous_color[l_index]; + color_orig = previous_color[v_index]; } const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha * brush_alpha_pressure * grid_alpha; - /* Mix the new color with the original based on final_alpha. */ - lcol[l_index] = vpaint_blend(vp, - lcol[l_index], - color_orig, - color_final, - final_alpha, - Traits::range * brush_strength); + colors[v_index] = vpaint_blend(vp, + colors[v_index], + color_orig, + color_final, + final_alpha, + Traits::range * brush_strength); } - } + else { + /* For each poly owning this vert, paint each loop belonging to this vert. */ + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + const int l_index = gmap->vert_to_loop[v_index][j]; + BLI_assert(ss->corner_verts[l_index] == v_index); + if (use_face_sel && !select_poly[p_index]) { + continue; + } + Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */ + + if (!previous_color.is_empty()) { + /* Get the previous loop color */ + if (isZero(previous_color[l_index])) { + previous_color[l_index] = colors[l_index]; + } + color_orig = previous_color[l_index]; + } + const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha * + brush_alpha_pressure * grid_alpha; + + /* Mix the new color with the original based on final_alpha. */ + colors[l_index] = vpaint_blend(vp, + colors[l_index], + color_orig, + color_final, + final_alpha, + Traits::range * brush_strength); + } + } + }); } BKE_pbvh_vertex_iter_end; } }); } -template static void vpaint_do_blur(bContext *C, Sculpt *sd, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Span nodes, - Color *lcol) + GMutableSpan attribute) { - if constexpr (domain == ATTR_DOMAIN_POINT) { - do_vpaint_brush_blur_verts(C, sd, vp, vpd, ob, me, nodes, lcol); + if (vpd->domain == ATTR_DOMAIN_POINT) { + do_vpaint_brush_blur_verts(C, sd, vp, vpd, ob, me, nodes, attribute); } else { - do_vpaint_brush_blur_loops(C, sd, vp, vpd, ob, me, nodes, lcol); + do_vpaint_brush_blur_loops(C, sd, vp, vpd, ob, me, nodes, attribute); } } -template static void vpaint_paint_leaves(bContext *C, Sculpt *sd, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, - Color *lcol, + GMutableSpan attribute, Span nodes) { for (PBVHNode *node : nodes) { @@ -3714,27 +3694,26 @@ static void vpaint_paint_leaves(bContext *C, switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) { case VPAINT_TOOL_AVERAGE: - calculate_average_color(vpd, ob, me, brush, lcol, nodes); + calculate_average_color(vpd, ob, me, brush, attribute, nodes); break; case VPAINT_TOOL_DRAW: - vpaint_do_draw(C, sd, vp, vpd, ob, me, nodes, lcol); + vpaint_do_draw(C, sd, vp, vpd, ob, me, nodes, attribute); break; case VPAINT_TOOL_BLUR: - vpaint_do_blur(C, sd, vp, vpd, ob, me, nodes, lcol); + vpaint_do_blur(C, sd, vp, vpd, ob, me, nodes, attribute); break; case VPAINT_TOOL_SMEAR: - do_vpaint_brush_smear(C, sd, vp, vpd, ob, me, nodes, lcol); + do_vpaint_brush_smear(C, sd, vp, vpd, ob, me, nodes, attribute); break; default: break; } } -template static void vpaint_do_paint(bContext *C, Sculpt *sd, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Brush *brush, @@ -3751,21 +3730,18 @@ static void vpaint_do_paint(bContext *C, bke::GSpanAttributeWriter attribute = me->attributes_for_write().lookup_for_write_span( me->active_color_attribute); - BLI_assert(attribute.domain == domain); - - Color *color_data = static_cast(attribute.span.data()); + BLI_assert(attribute.domain == vpd->domain); /* Paint those leaves. */ - vpaint_paint_leaves(C, sd, vp, vpd, ob, me, color_data, nodes); + vpaint_paint_leaves(C, sd, vp, vpd, ob, me, attribute.span, nodes); attribute.finish(); } -template static void vpaint_do_radial_symmetry(bContext *C, Sculpt *sd, VPaint *vp, - VPaintData *vpd, + VPaintData *vpd, Object *ob, Mesh *me, Brush *brush, @@ -3774,15 +3750,14 @@ static void vpaint_do_radial_symmetry(bContext *C, { for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) { const float angle = (2.0 * M_PI) * i / vp->radial_symm[axis - 'X']; - vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle); + vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm, axis, i, angle); } } /* near duplicate of: sculpt.cc's, * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */ -template static void vpaint_do_symmetrical_brush_actions( - bContext *C, Sculpt *sd, VPaint *vp, VPaintData *vpd, Object *ob) + bContext *C, Sculpt *sd, VPaint *vp, VPaintData *vpd, Object *ob) { Brush *brush = BKE_paint_brush(&vp->paint); Mesh *me = (Mesh *)ob->data; @@ -3794,13 +3769,10 @@ static void vpaint_do_symmetrical_brush_actions( /* initial stroke */ const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0); cache->mirror_symmetry_pass = ePaintSymmetryFlags(0); - vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, initial_symm, 'X', 0, 0); - vpaint_do_radial_symmetry( - C, sd, vp, vpd, ob, me, brush, initial_symm, 'X'); - vpaint_do_radial_symmetry( - C, sd, vp, vpd, ob, me, brush, initial_symm, 'Y'); - vpaint_do_radial_symmetry( - C, sd, vp, vpd, ob, me, brush, initial_symm, 'Z'); + vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, initial_symm, 'X', 0, 0); + vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, initial_symm, 'X'); + vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, initial_symm, 'Y'); + vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, initial_symm, 'Z'); cache->symmetry = symm; @@ -3814,22 +3786,16 @@ static void vpaint_do_symmetrical_brush_actions( SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0); if (i & (1 << 0)) { - vpaint_do_paint( - C, sd, vp, vpd, ob, me, brush, symm_pass, 'X', 0, 0); - vpaint_do_radial_symmetry( - C, sd, vp, vpd, ob, me, brush, symm_pass, 'X'); + vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm_pass, 'X', 0, 0); + vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, symm_pass, 'X'); } if (i & (1 << 1)) { - vpaint_do_paint( - C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y', 0, 0); - vpaint_do_radial_symmetry( - C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y'); + vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y', 0, 0); + vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y'); } if (i & (1 << 2)) { - vpaint_do_paint( - C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z', 0, 0); - vpaint_do_radial_symmetry( - C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z'); + vpaint_do_paint(C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z', 0, 0); + vpaint_do_radial_symmetry(C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z'); } } } @@ -3838,13 +3804,14 @@ static void vpaint_do_symmetrical_brush_actions( cache->is_last_valid = true; } -template -static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr) +static void vpaint_stroke_update_step(bContext *C, + wmOperator * /*op*/, + PaintStroke *stroke, + PointerRNA *itemptr) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); - VPaintData *vpd = static_cast *>( - paint_stroke_mode_data(stroke)); + VPaintData *vpd = static_cast(paint_stroke_mode_data(stroke)); VPaint *vp = ts->vpaint; ViewContext *vc = &vpd->vc; Object *ob = vc->obact; @@ -3862,20 +3829,14 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P swap_m4m4(vc->rv3d->persmat, mat); - vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob); + vpaint_do_symmetrical_brush_actions(C, sd, vp, vpd, ob); swap_m4m4(vc->rv3d->persmat, mat); BKE_mesh_batch_cache_dirty_tag((Mesh *)ob->data, BKE_MESH_BATCH_DIRTY_ALL); if (vp->paint.brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) { - Mesh *me = BKE_object_get_original_mesh(ob); - - size_t elem_size; - int elem_num; - - elem_num = get_vcol_elements(me, &elem_size); - memcpy(vpd->smear.color_prev, vpd->smear.color_curr, elem_size * elem_num); + vpd->smear.color_prev = vpd->smear.color_curr; } /* Calculate pivot for rotation around selection if needed. @@ -3889,82 +3850,20 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P DEG_id_tag_update((ID *)ob->data, ID_RECALC_GEOMETRY); } -static void vpaint_stroke_update_step(bContext *C, - wmOperator * /*op*/, - PaintStroke *stroke, - PointerRNA *itemptr) +static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke) { - VPaintDataBase *vpd = static_cast(paint_stroke_mode_data(stroke)); - - if (vpd->domain == ATTR_DOMAIN_POINT) { - if (vpd->type == CD_PROP_COLOR) { - vpaint_stroke_update_step_intern( - C, stroke, itemptr); - } - else if (vpd->type == CD_PROP_BYTE_COLOR) { - vpaint_stroke_update_step_intern( - C, stroke, itemptr); - } - } - else if (vpd->domain == ATTR_DOMAIN_CORNER) { - if (vpd->type == CD_PROP_COLOR) { - vpaint_stroke_update_step_intern( - C, stroke, itemptr); - } - else if (vpd->type == CD_PROP_BYTE_COLOR) { - vpaint_stroke_update_step_intern( - C, stroke, itemptr); - } - } -} - -template -static void vpaint_free_vpaintdata(Object * /*ob*/, void *_vpd) -{ - VPaintData *vpd = static_cast *>(_vpd); + VPaintData *vpd = static_cast(paint_stroke_mode_data(stroke)); + Object *ob = vpd->vc.obact; if (vpd->is_texbrush) { ED_vpaint_proj_handle_free(vpd->vp_handle); } - if (vpd->smear.color_prev) { - MEM_freeN(vpd->smear.color_prev); - } - if (vpd->smear.color_curr) { - MEM_freeN(vpd->smear.color_curr); - } - - MEM_delete>(vpd); -} - -static void vpaint_stroke_done(const bContext *C, PaintStroke *stroke) -{ - void *vpd_ptr = paint_stroke_mode_data(stroke); - VPaintDataBase *vpd = static_cast(vpd_ptr); - - ViewContext *vc = &vpd->vc; - Object *ob = vc->obact; - - if (vpd->domain == ATTR_DOMAIN_POINT) { - if (vpd->type == CD_PROP_COLOR) { - vpaint_free_vpaintdata(ob, vpd); - } - else if (vpd->type == CD_PROP_BYTE_COLOR) { - vpaint_free_vpaintdata(ob, vpd); - } - } - else if (vpd->domain == ATTR_DOMAIN_CORNER) { - if (vpd->type == CD_PROP_COLOR) { - vpaint_free_vpaintdata(ob, vpd); - } - else if (vpd->type == CD_PROP_BYTE_COLOR) { - vpaint_free_vpaintdata(ob, vpd); - } - } + MEM_delete(vpd); SculptSession *ss = ob->sculpt; - if (ss->cache->alt_smooth) { + if (ss->cache && ss->cache->alt_smooth) { ToolSettings *ts = CTX_data_tool_settings(C); VPaint *vp = ts->vpaint; smooth_brush_toggle_off(C, &vp->paint, ss->cache); @@ -4214,9 +4113,7 @@ static int vertex_color_set_exec(bContext *C, wmOperator * /*op*/) Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); - // uint paintcol = vpaint_get_current_color(scene, scene->toolsettings->vpaint, false); - ColorPaint4f paintcol = vpaint_get_current_col( - scene, scene->toolsettings->vpaint, false); + ColorPaint4f paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false); if (paint_object_attributes_active_color_fill_ex(obact, paintcol)) { WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact); diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index bf635e06694..bedf01c85ff 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -4334,7 +4334,6 @@ void SCULPT_cache_free(StrokeCache *cache) MEM_SAFE_FREE(cache->detail_directions); MEM_SAFE_FREE(cache->prev_displacement); MEM_SAFE_FREE(cache->limit_surface_co); - MEM_SAFE_FREE(cache->prev_colors_vpaint); if (cache->pose_ik_chain) { SCULPT_pose_ik_chain_free(cache->pose_ik_chain); @@ -4350,7 +4349,7 @@ void SCULPT_cache_free(StrokeCache *cache) SCULPT_cloth_simulation_free(cache->cloth_sim); } - MEM_freeN(cache); + MEM_delete(cache); } /* Initialize mirror modifier clipping. */ @@ -4454,8 +4453,7 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache static void sculpt_update_cache_invariants( bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2]) { - StrokeCache *cache = static_cast( - MEM_callocN(sizeof(StrokeCache), "stroke cache")); + StrokeCache *cache = MEM_new(__func__); ToolSettings *tool_settings = CTX_data_tool_settings(C); UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings; Brush *brush = BKE_paint_brush(&sd->paint); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index d1bc497f8a2..6c626ef6371 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -21,6 +21,7 @@ #include "BLI_bitmap.h" #include "BLI_compiler_attrs.h" #include "BLI_compiler_compat.h" +#include "BLI_generic_array.hh" #include "BLI_gsqueue.h" #include "BLI_implicit_sharing.hh" #include "BLI_span.hh" @@ -555,7 +556,7 @@ struct StrokeCache { float mouse_event[2]; float (*prev_colors)[4]; - void *prev_colors_vpaint; + blender::GArray<> prev_colors_vpaint; /* Multires Displacement Smear. */ float (*prev_displacement)[3];