Cleanup: Reduce use and scope of templates in vertex paint #2

Closed
Hans Goudey wants to merge 10 commits from paint-vertex-fewer-templates into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 118 additions and 92 deletions
Showing only changes of commit a7978142af - Show all commits

View File

@ -87,6 +87,17 @@ struct FloatTraits {
} }
}; };
template<typename T> struct TraitsType {
using type = void;
};
template<> struct TraitsType<ColorPaint4f> {
using type = FloatTraits;
};
template<> struct TraitsType<ColorPaint4b> {
using type = ByteTraits;
};
template<typename T> using Traits = typename TraitsType<T>::type;
static float get_luminance(ColorPaint4f c) static float get_luminance(ColorPaint4f c)
{ {
return IMB_colormanagement_get_luminance(&c.r); return IMB_colormanagement_get_luminance(&c.r);

View File

@ -2916,14 +2916,14 @@ static void do_vpaint_brush_blur_loops(bContext *C,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
Span<PBVHNode *> nodes, Span<PBVHNode *> nodes,
GMutableSpan lcol) GMutableSpan attribute)
{ {
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
const Brush *brush = ob->sculpt->cache->brush; const Brush *brush = ob->sculpt->cache->brush;
const Scene *scene = CTX_data_scene(C); const Scene *scene = CTX_data_scene(C);
GMutableSpan previous_color = ss->cache->prev_colors_vpaint; GMutableSpan g_previous_color = ss->cache->prev_colors_vpaint;
const blender::VArray<bool> select_vert = *me->attributes().lookup_or_default<bool>( const blender::VArray<bool> select_vert = *me->attributes().lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false); ".select_vert", ATTR_DOMAIN_POINT, false);
@ -2981,8 +2981,10 @@ static void do_vpaint_brush_blur_loops(bContext *C,
to_static_color_type(vpd->type, [&](auto dummy) { to_static_color_type(vpd->type, [&](auto dummy) {
using Color = decltype(dummy); using Color = decltype(dummy);
// using Traits = using Traits = color::Traits<Color>;
using Blend = typename Traits::BlendType; using Blend = typename Traits::BlendType;
MutableSpan<Color> previous_color = g_previous_color.typed<Color>();
MutableSpan<Color> colors = attribute.typed<Color>();
/* Get the average poly color */ /* Get the average poly color */
Color color_final(0, 0, 0, 0); Color color_final(0, 0, 0, 0);
@ -2991,23 +2993,23 @@ static void do_vpaint_brush_blur_loops(bContext *C,
for (const int p_index : gmap->vert_to_poly[v_index]) { for (const int p_index : gmap->vert_to_poly[v_index]) {
if (use_face_sel && !select_poly[p_index]) { if (use_face_sel && !select_poly[p_index]) {
continue; return;
} }
const blender::IndexRange poly = ss->polys[p_index]; const blender::IndexRange poly = ss->polys[p_index];
total_hit_loops += poly.size(); total_hit_loops += poly.size();
for (const int corner : poly) { for (const int corner : poly) {
Color *col = lcol + corner; const Color &col = colors[corner];
/* Color is squared to compensate the `sqrt` color encoding. */ /* Color is squared to compensate the `sqrt` color encoding. */
blend[0] += (Blend)col->r * (Blend)col->r; blend[0] += (Blend)col.r * (Blend)col.r;
blend[1] += (Blend)col->g * (Blend)col->g; blend[1] += (Blend)col.g * (Blend)col.g;
blend[2] += (Blend)col->b * (Blend)col->b; blend[2] += (Blend)col.b * (Blend)col.b;
blend[3] += (Blend)col->a * (Blend)col->a; blend[3] += (Blend)col.a * (Blend)col.a;
} }
} }
if (total_hit_loops == 0) { if (total_hit_loops == 0) {
continue; return;
} }
/* Use rgb^2 color averaging. */ /* Use rgb^2 color averaging. */
@ -3032,7 +3034,7 @@ static void do_vpaint_brush_blur_loops(bContext *C,
if (!previous_color.is_empty()) { if (!previous_color.is_empty()) {
/* Get the previous loop color */ /* Get the previous loop color */
if (isZero(previous_color[l_index])) { if (isZero(previous_color[l_index])) {
previous_color[l_index] = lcol[l_index]; previous_color[l_index] = colors[l_index];
} }
color_orig = previous_color[l_index]; color_orig = previous_color[l_index];
} }
@ -3040,8 +3042,12 @@ static void do_vpaint_brush_blur_loops(bContext *C,
brush_alpha_pressure * grid_alpha; brush_alpha_pressure * grid_alpha;
/* Mix the new color with the original /* Mix the new color with the original
* based on the brush strength and the curve. */ * based on the brush strength and the curve. */
lcol[l_index] = vpaint_blend<Color, Traits>( colors[l_index] = vpaint_blend<Color, Traits>(vp,
vp, lcol[l_index], color_orig, *col, final_alpha, Traits::range * brush_strength); colors[l_index],
color_orig,
*col,
final_alpha,
Traits::range * brush_strength);
} }
}); });
} }
@ -3057,14 +3063,14 @@ static void do_vpaint_brush_blur_verts(bContext *C,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
Span<PBVHNode *> nodes, Span<PBVHNode *> nodes,
GMutableSpan lcol) GMutableSpan attribute)
{ {
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
const Brush *brush = ob->sculpt->cache->brush; const Brush *brush = ob->sculpt->cache->brush;
const Scene *scene = CTX_data_scene(C); const Scene *scene = CTX_data_scene(C);
GMutableSpan previous_color = ss->cache->prev_colors_vpaint; GMutableSpan g_previous_color = ss->cache->prev_colors_vpaint;
const blender::VArray<bool> select_vert = *me->attributes().lookup_or_default<bool>( const blender::VArray<bool> select_vert = *me->attributes().lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false); ".select_vert", ATTR_DOMAIN_POINT, false);
@ -3122,7 +3128,10 @@ static void do_vpaint_brush_blur_verts(bContext *C,
/* Get the average poly color */ /* Get the average poly color */
to_static_color_type(vpd->type, [&](auto dummy) { to_static_color_type(vpd->type, [&](auto dummy) {
using Color = decltype(dummy); using Color = decltype(dummy);
using Traits = color::Traits<Color>;
using Blend = typename Traits::BlendType; using Blend = typename Traits::BlendType;
MutableSpan<Color> previous_color = g_previous_color.typed<Color>();
MutableSpan<Color> colors = attribute.typed<Color>();
Color color_final(0, 0, 0, 0); Color color_final(0, 0, 0, 0);
int total_hit_loops = 0; int total_hit_loops = 0;
@ -3135,39 +3144,31 @@ static void do_vpaint_brush_blur_verts(bContext *C,
const blender::IndexRange poly = ss->polys[p_index]; const blender::IndexRange poly = ss->polys[p_index];
total_hit_loops += poly.size(); total_hit_loops += poly.size();
for (const int vert : ss->corner_verts.slice(poly)) { for (const int vert : ss->corner_verts.slice(poly)) {
Color *col = lcol + vert; const Color &col = colors[vert];
/* Color is squared to compensate the `sqrt` color encoding. */ /* Color is squared to compensate the `sqrt` color encoding. */
blend[0] += (Blend)col->r * (Blend)col->r; blend[0] += (Blend)col.r * (Blend)col.r;
blend[1] += (Blend)col->g * (Blend)col->g; blend[1] += (Blend)col.g * (Blend)col.g;
blend[2] += (Blend)col->b * (Blend)col->b; blend[2] += (Blend)col.b * (Blend)col.b;
blend[3] += (Blend)col->a * (Blend)col->a; blend[3] += (Blend)col.a * (Blend)col.a;
} }
} }
if (total_hit_loops == 0) { if (total_hit_loops == 0) {
continue; return;
} }
/* Use rgb^2 color averaging. */ /* 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.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.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.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))); 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 */ Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
if (!previous_color.is_empty()) { if (!previous_color.is_empty()) {
/* Get the previous loop color */ /* Get the previous loop color */
if (isZero(previous_color[v_index])) { 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]; color_orig = previous_color[v_index];
} }
@ -3175,9 +3176,12 @@ static void do_vpaint_brush_blur_verts(bContext *C,
brush_alpha_pressure * grid_alpha; brush_alpha_pressure * grid_alpha;
/* Mix the new color with the original /* Mix the new color with the original
* based on the brush strength and the curve. */ * based on the brush strength and the curve. */
lcol[v_index] = vpaint_blend<Color, Traits>( colors[v_index] = vpaint_blend<Color, Traits>(vp,
vp, lcol[v_index], color_orig, *col, final_alpha, Traits::range * brush_strength); colors[v_index],
} color_orig,
color_final,
final_alpha,
Traits::range * brush_strength);
}); });
} }
BKE_pbvh_vertex_iter_end; BKE_pbvh_vertex_iter_end;
@ -3192,7 +3196,7 @@ static void do_vpaint_brush_smear(bContext *C,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
Span<PBVHNode *> nodes, Span<PBVHNode *> nodes,
GMutableSpan lcol) GMutableSpan attribute)
{ {
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
@ -3206,9 +3210,9 @@ static void do_vpaint_brush_smear(bContext *C,
const Brush *brush = ob->sculpt->cache->brush; const Brush *brush = ob->sculpt->cache->brush;
const Scene *scene = CTX_data_scene(C); const Scene *scene = CTX_data_scene(C);
GMutableSpan color_curr = vpd->smear.color_curr; GMutableSpan g_color_curr = vpd->smear.color_curr;
GMutableSpan color_prev_smear = vpd->smear.color_prev; GMutableSpan g_color_prev_smear = vpd->smear.color_prev;
GMutableSpan color_prev = ss->cache->prev_colors_vpaint; GMutableSpan g_color_prev = ss->cache->prev_colors_vpaint;
float brush_size_pressure, brush_alpha_value, brush_alpha_pressure; float brush_size_pressure, brush_alpha_value, brush_alpha_pressure;
@ -3278,6 +3282,12 @@ static void do_vpaint_brush_smear(bContext *C,
* direction of the brush movement */ * direction of the brush movement */
to_static_color_type(vpd->type, [&](auto dummy) { to_static_color_type(vpd->type, [&](auto dummy) {
using Color = decltype(dummy); using Color = decltype(dummy);
using Traits = color::Traits<Color>;
MutableSpan<Color> color_curr = g_color_curr.typed<Color>();
MutableSpan<Color> color_prev_smear = g_color_prev_smear.typed<Color>();
MutableSpan<Color> color_prev = g_color_prev.typed<Color>();
MutableSpan<Color> colors = attribute.typed<Color>();
Color color_final(0, 0, 0, 0); Color color_final(0, 0, 0, 0);
for (const int j : gmap->vert_to_poly[v_index].index_range()) { for (const int j : gmap->vert_to_poly[v_index].index_range()) {
@ -3305,7 +3315,7 @@ static void do_vpaint_brush_smear(bContext *C,
const float stroke_dot = dot_v3v3(other_dir, brush_dir); const float stroke_dot = dot_v3v3(other_dir, brush_dir);
int elem_index; int elem_index;
if (domain == ATTR_DOMAIN_POINT) { if (vpd->domain == ATTR_DOMAIN_POINT) {
elem_index = v_other_index; elem_index = v_other_index;
} }
else { else {
@ -3321,7 +3331,7 @@ static void do_vpaint_brush_smear(bContext *C,
} }
if (!do_color) { if (!do_color) {
continue; return;
} }
const float final_alpha = Traits::range * brush_fade * brush_strength * const float final_alpha = Traits::range * brush_fade * brush_strength *
@ -3348,23 +3358,23 @@ static void do_vpaint_brush_smear(bContext *C,
/* Get the previous element color */ /* Get the previous element color */
Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */
if (color_prev != nullptr) { if (!color_prev.is_empty()) {
/* Get the previous element color */ /* Get the previous element color */
if (isZero(color_prev[elem_index])) { if (isZero(color_prev[elem_index])) {
color_prev[elem_index] = lcol[elem_index]; color_prev[elem_index] = colors[elem_index];
} }
color_orig = color_prev[elem_index]; color_orig = color_prev[elem_index];
} }
/* Mix the new color with the original /* Mix the new color with the original
* based on the brush strength and the curve. */ * based on the brush strength and the curve. */
lcol[elem_index] = vpaint_blend<Color, Traits>(vp, colors[elem_index] = vpaint_blend<Color, Traits>(vp,
lcol[elem_index], colors[elem_index],
color_orig, color_orig,
color_final, color_final,
final_alpha, final_alpha,
Traits::range * brush_strength); Traits::range * brush_strength);
color_curr[elem_index] = lcol[elem_index]; color_curr[elem_index] = colors[elem_index];
} }
}); });
} }
@ -3377,7 +3387,7 @@ static void calculate_average_color(VPaintData *vpd,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
const Brush *brush, const Brush *brush,
GMutableSpan lcol, const GSpan attribute,
Span<PBVHNode *> nodes) Span<PBVHNode *> nodes)
{ {
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
@ -3398,7 +3408,9 @@ static void calculate_average_color(VPaintData *vpd,
to_static_color_type(vpd->type, [&](auto dummy) { to_static_color_type(vpd->type, [&](auto dummy) {
using Color = decltype(dummy); using Color = decltype(dummy);
using Traits = color::Traits<Color>;
using Blend = typename Traits::BlendType; using Blend = typename Traits::BlendType;
const Span<Color> colors = attribute.typed<Color>();
Array<VPaintAverageAccum<Blend>> accum(nodes.size()); Array<VPaintAverageAccum<Blend>> accum(nodes.size());
blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) { blender::threading::parallel_for(nodes.index_range(), 1LL, [&](IndexRange range) {
@ -3436,12 +3448,11 @@ static void calculate_average_color(VPaintData *vpd,
elem_index = v_index; elem_index = v_index;
} }
Color *col = lcol + elem_index;
/* Color is squared to compensate the `sqrt` color encoding. */ /* Color is squared to compensate the `sqrt` color encoding. */
accum2.value[0] += col->r * col->r; const Color &col = colors[elem_index];
accum2.value[1] += col->g * col->g; accum2.value[0] += col.r * col.r;
accum2.value[2] += col->b * col->b; accum2.value[1] += col.g * col.g;
accum2.value[2] += col.b * col.b;
} }
} }
BKE_pbvh_vertex_iter_end; BKE_pbvh_vertex_iter_end;
@ -3464,7 +3475,7 @@ static void calculate_average_color(VPaintData *vpd,
blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len))); blend.b = Traits::round(sqrtf(Traits::divide_round(accum_value[2], accum_len)));
blend.a = Traits::range; blend.a = Traits::range;
vpd->paintcol = blend; vpd->paintcol = toFloat(blend);
} }
}); });
} }
@ -3494,7 +3505,7 @@ static void vpaint_do_draw(bContext *C,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
Span<PBVHNode *> nodes, Span<PBVHNode *> nodes,
GMutableSpan lcol) GMutableSpan attribute)
{ {
SculptSession *ss = ob->sculpt; SculptSession *ss = ob->sculpt;
const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh); const PBVHType pbvh_type = BKE_pbvh_type(ss->pbvh);
@ -3522,7 +3533,7 @@ static void vpaint_do_draw(bContext *C,
const ColorPaint4f paintcol = vpd->paintcol; const ColorPaint4f paintcol = vpd->paintcol;
GMutableSpan previous_color = ss->cache->prev_colors_vpaint; GMutableSpan g_previous_color = ss->cache->prev_colors_vpaint;
const blender::VArray<bool> select_vert = *me->attributes().lookup_or_default<bool>( const blender::VArray<bool> select_vert = *me->attributes().lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false); ".select_vert", ATTR_DOMAIN_POINT, false);
@ -3563,13 +3574,16 @@ static void vpaint_do_draw(bContext *C,
to_static_color_type(vpd->type, [&](auto dummy) { to_static_color_type(vpd->type, [&](auto dummy) {
using Color = decltype(dummy); using Color = decltype(dummy);
Color color_final = paintcol; using Traits = color::Traits<Color>;
MutableSpan<Color> colors = attribute.typed<Color>();
MutableSpan<Color> previous_color = g_previous_color.typed<Color>();
Color color_final = fromFloat<Color>(paintcol);
/* If we're painting with a texture, sample the texture color and alpha. */ /* If we're painting with a texture, sample the texture color and alpha. */
float tex_alpha = 1.0; float tex_alpha = 1.0;
if (vpd->is_texbrush) { if (vpd->is_texbrush) {
/* NOTE: we may want to paint alpha as vertex color alpha. */ /* NOTE: we may want to paint alpha as vertex color alpha. */
tex_alpha = paint_and_tex_color_alpha<Color, Traits, domain>( tex_alpha = paint_and_tex_color_alpha<Color>(
vp, vpd, vpd->vertexcosnos[v_index].co, &color_final); vp, vpd, vpd->vertexcosnos[v_index].co, &color_final);
} }
@ -3581,15 +3595,15 @@ static void vpaint_do_draw(bContext *C,
if (!previous_color.is_empty()) { if (!previous_color.is_empty()) {
/* Get the previous loop color */ /* Get the previous loop color */
if (isZero(previous_color[v_index])) { 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]; color_orig = previous_color[v_index];
} }
const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha * const float final_alpha = Traits::frange * brush_fade * brush_strength * tex_alpha *
brush_alpha_pressure * grid_alpha; brush_alpha_pressure * grid_alpha;
lcol[v_index] = vpaint_blend<Color, Traits>(vp, colors[v_index] = vpaint_blend<Color, Traits>(vp,
lcol[v_index], colors[v_index],
color_orig, color_orig,
color_final, color_final,
final_alpha, final_alpha,
@ -3609,7 +3623,7 @@ static void vpaint_do_draw(bContext *C,
if (!previous_color.is_empty()) { if (!previous_color.is_empty()) {
/* Get the previous loop color */ /* Get the previous loop color */
if (isZero(previous_color[l_index])) { if (isZero(previous_color[l_index])) {
previous_color[l_index] = lcol[l_index]; previous_color[l_index] = colors[l_index];
} }
color_orig = previous_color[l_index]; color_orig = previous_color[l_index];
} }
@ -3617,8 +3631,8 @@ static void vpaint_do_draw(bContext *C,
brush_alpha_pressure * grid_alpha; brush_alpha_pressure * grid_alpha;
/* Mix the new color with the original based on final_alpha. */ /* Mix the new color with the original based on final_alpha. */
lcol[l_index] = vpaint_blend<Color, Traits>(vp, colors[l_index] = vpaint_blend<Color, Traits>(vp,
lcol[l_index], colors[l_index],
color_orig, color_orig,
color_final, color_final,
final_alpha, final_alpha,
@ -3639,13 +3653,13 @@ static void vpaint_do_blur(bContext *C,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
Span<PBVHNode *> nodes, Span<PBVHNode *> nodes,
GMutableSpan lcol) GMutableSpan attribute)
{ {
if (vpd->domain == ATTR_DOMAIN_POINT) { if (vpd->domain == ATTR_DOMAIN_POINT) {
do_vpaint_brush_blur_verts(C, sd, vp, vpd, ob, me, nodes, lcol); do_vpaint_brush_blur_verts(C, sd, vp, vpd, ob, me, nodes, attribute);
} }
else { 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);
} }
} }
@ -3655,7 +3669,7 @@ static void vpaint_paint_leaves(bContext *C,
VPaintData *vpd, VPaintData *vpd,
Object *ob, Object *ob,
Mesh *me, Mesh *me,
GMutableSpan lcol, GMutableSpan attribute,
Span<PBVHNode *> nodes) Span<PBVHNode *> nodes)
{ {
for (PBVHNode *node : nodes) { for (PBVHNode *node : nodes) {
@ -3666,16 +3680,16 @@ static void vpaint_paint_leaves(bContext *C,
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) { switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE: case VPAINT_TOOL_AVERAGE:
calculate_average_color(vpd, ob, me, brush, lcol, nodes); calculate_average_color(vpd, ob, me, brush, attribute, nodes);
break; break;
case VPAINT_TOOL_DRAW: 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; break;
case VPAINT_TOOL_BLUR: 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; break;
case VPAINT_TOOL_SMEAR: 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; break;
default: default:
break; break;
@ -3702,7 +3716,7 @@ static void vpaint_do_paint(bContext *C,
bke::GSpanAttributeWriter attribute = me->attributes_for_write().lookup_for_write_span( bke::GSpanAttributeWriter attribute = me->attributes_for_write().lookup_for_write_span(
me->active_color_attribute); me->active_color_attribute);
BLI_assert(attribute.domain == domain); BLI_assert(attribute.domain == vpd->domain);
/* Paint those leaves. */ /* Paint those leaves. */
vpaint_paint_leaves(C, sd, vp, vpd, ob, me, attribute.span, nodes); vpaint_paint_leaves(C, sd, vp, vpd, ob, me, attribute.span, nodes);

View File

@ -21,6 +21,7 @@
#include "BLI_bitmap.h" #include "BLI_bitmap.h"
#include "BLI_compiler_attrs.h" #include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h" #include "BLI_compiler_compat.h"
#include "BLI_generic_array.hh"
#include "BLI_gsqueue.h" #include "BLI_gsqueue.h"
#include "BLI_implicit_sharing.hh" #include "BLI_implicit_sharing.hh"
#include "BLI_span.hh" #include "BLI_span.hh"
@ -555,7 +556,7 @@ struct StrokeCache {
float mouse_event[2]; float mouse_event[2];
float (*prev_colors)[4]; float (*prev_colors)[4];
GArray<> prev_colors_vpaint; blender::GArray<> prev_colors_vpaint;
/* Multires Displacement Smear. */ /* Multires Displacement Smear. */
float (*prev_displacement)[3]; float (*prev_displacement)[3];