Skip to content

Commit cff0fe4

Browse files
committed
brush: Convert SmudgeBucket from array to struct
This will make the code slightly more readable.
1 parent 0303431 commit cff0fe4

File tree

1 file changed

+86
-68
lines changed

1 file changed

+86
-68
lines changed

mypaint-brush.c

Lines changed: 86 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,28 @@
5454

5555
#define GRID_SIZE 256.0
5656

57-
/* Named indices for the smudge bucket arrays */
58-
enum {
59-
SMUDGE_R, SMUDGE_G, SMUDGE_B, SMUDGE_A,
60-
PREV_COL_R, PREV_COL_G, PREV_COL_B, PREV_COL_A,
61-
PREV_COL_RECENTNESS,
62-
SMUDGE_BUCKET_SIZE
63-
};
57+
#define SMUDGE_BUCKET_SIZE (sizeof(SmudgeBucket) / sizeof(float))
58+
59+
/**
60+
* SmudgeBucket:
61+
*
62+
* Optionally used by MyPaintBrush.
63+
*
64+
* Usually used for brushes with multiple offset dabs, where each
65+
* dab is assigned its own bucket containing a smudge state.
66+
*/
67+
typedef struct {
68+
float smudge_r;
69+
float smudge_g;
70+
float smudge_b;
71+
float smudge_a;
72+
float prev_col_r;
73+
float prev_col_g;
74+
float prev_col_b;
75+
float prev_col_a;
76+
float prev_col_recentness;
77+
float smudge_bucket_size;
78+
} SmudgeBucket;
6479

6580
/* The Brush class stores two things:
6681
b) settings: constant during a stroke (eg. size, spacing, dynamics, color selected by the user)
@@ -94,7 +109,7 @@ struct MyPaintBrush {
94109
// smudge bucket array: part of the state, but stored separately.
95110
// Usually used for brushes with multiple offset dabs, where each
96111
// dab is assigned its own bucket containing a smudge state.
97-
float *smudge_buckets;
112+
SmudgeBucket *smudge_buckets;
98113
int num_buckets;
99114
int min_bucket_used;
100115
int max_bucket_used;
@@ -158,7 +173,7 @@ brush_reset(MyPaintBrush *self)
158173
int min_index = self->min_bucket_used;
159174
if (min_index != -1) {
160175
int max_index = self->max_bucket_used;
161-
size_t num_bytes = (max_index - min_index + 1) * sizeof(self->smudge_buckets[0]) * SMUDGE_BUCKET_SIZE;
176+
size_t num_bytes = (max_index - min_index + 1) * sizeof(self->smudge_buckets[0]);
162177
memset(self->smudge_buckets + min_index, 0, num_bytes);
163178
self->min_bucket_used = -1;
164179
self->max_bucket_used = -1;
@@ -195,7 +210,7 @@ mypaint_brush_new_with_buckets(int num_smudge_buckets)
195210
}
196211

197212
if (num_smudge_buckets > 0) {
198-
float *bucket_array = malloc(num_smudge_buckets * SMUDGE_BUCKET_SIZE * sizeof(float));
213+
SmudgeBucket *bucket_array = malloc(num_smudge_buckets * sizeof(SmudgeBucket));
199214
if (!bucket_array) {
200215
free(self);
201216
return NULL;
@@ -460,16 +475,16 @@ mypaint_brush_set_smudge_bucket_state(
460475
float prev_color_recentness)
461476
{
462477
if (self->num_buckets > bucket_index) {
463-
float* bucket = &self->smudge_buckets[bucket_index];
464-
bucket[SMUDGE_R] = r;
465-
bucket[SMUDGE_G] = g;
466-
bucket[SMUDGE_B] = b;
467-
bucket[SMUDGE_A] = a;
468-
bucket[PREV_COL_R] = prev_r;
469-
bucket[PREV_COL_G] = prev_g;
470-
bucket[PREV_COL_B] = prev_b;
471-
bucket[PREV_COL_A] = prev_a;
472-
bucket[PREV_COL_RECENTNESS] = prev_color_recentness;
478+
SmudgeBucket* bucket = &self->smudge_buckets[bucket_index];
479+
bucket->smudge_r = r;
480+
bucket->smudge_g = g;
481+
bucket->smudge_b = b;
482+
bucket->smudge_a = a;
483+
bucket->prev_col_r = prev_r;
484+
bucket->prev_col_g = prev_g;
485+
bucket->prev_col_b = prev_b;
486+
bucket->prev_col_a = prev_a;
487+
bucket->prev_col_recentness = prev_color_recentness;
473488
return TRUE;
474489
}
475490
return FALSE;
@@ -492,16 +507,16 @@ mypaint_brush_get_smudge_bucket_state(
492507
float* prev_color_recentness)
493508
{
494509
if (self->num_buckets > bucket_index) {
495-
float* bucket = &self->smudge_buckets[bucket_index];
496-
*r = bucket[SMUDGE_R];
497-
*g = bucket[SMUDGE_G];
498-
*b = bucket[SMUDGE_B];
499-
*a = bucket[SMUDGE_A];
500-
*prev_r = bucket[PREV_COL_R];
501-
*prev_g = bucket[PREV_COL_G];
502-
*prev_b = bucket[PREV_COL_B];
503-
*prev_a = bucket[PREV_COL_A];
504-
*prev_color_recentness = bucket[PREV_COL_RECENTNESS];
510+
SmudgeBucket* bucket = &self->smudge_buckets[bucket_index];
511+
*r = bucket->smudge_r;
512+
*g = bucket->smudge_g;
513+
*b = bucket->smudge_b;
514+
*a = bucket->smudge_a;
515+
*prev_r = bucket->prev_col_r;
516+
*prev_g = bucket->prev_col_g;
517+
*prev_b = bucket->prev_col_b;
518+
*prev_a = bucket->prev_col_a;
519+
*prev_color_recentness = bucket->prev_col_recentness;
505520
return TRUE;
506521
}
507522
return FALSE;
@@ -903,9 +918,12 @@ void print_inputs(MyPaintBrush *self, float* inputs)
903918
STATE(self, ACTUAL_ELLIPTICAL_DAB_ANGLE) = mod_arith(SETTING(self, ELLIPTICAL_DAB_ANGLE) - viewrotation + 180.0, 180.0) - 180.0;
904919
}
905920

906-
float *fetch_smudge_bucket(MyPaintBrush *self) {
921+
SmudgeBucket *fetch_smudge_bucket(MyPaintBrush *self) {
907922
if (!self->smudge_buckets || !self->num_buckets) {
908-
return &STATE(self, SMUDGE_RA);
923+
float *smudge_state = &STATE(self, SMUDGE_RA);
924+
// Not sure this can be done in general.
925+
// static_assert (sizeof (SmudgeBucket) == sizeof(smudge_state) * SMUDGE_BUCKET_SIZE, "SmudgeBucket includes padding");
926+
return (SmudgeBucket*) smudge_state;
909927
}
910928
const int bucket_index = CLAMP(roundf(SETTING(self, SMUDGE_BUCKET)), 0, self->num_buckets - 1);
911929
if (self->min_bucket_used == -1 || self->min_bucket_used > bucket_index) {
@@ -914,12 +932,12 @@ void print_inputs(MyPaintBrush *self, float* inputs)
914932
if (self->max_bucket_used < bucket_index) {
915933
self->max_bucket_used = bucket_index;
916934
}
917-
return &self->smudge_buckets[bucket_index * SMUDGE_BUCKET_SIZE];
935+
return &self->smudge_buckets[bucket_index];
918936
}
919937

920938
gboolean
921939
update_smudge_color(
922-
const MyPaintBrush* self, MyPaintSurface* surface, float* const smudge_bucket, const float smudge_length, int px,
940+
const MyPaintBrush* self, MyPaintSurface* surface, SmudgeBucket* const smudge_bucket, const float smudge_length, int px,
923941
int py, const float radius, const float legacy_smudge, const float paint_factor)
924942
{
925943

@@ -934,16 +952,16 @@ void print_inputs(MyPaintBrush *self, float* inputs)
934952
float r, g, b, a;
935953
const float smudge_length_log = SETTING(self, SMUDGE_LENGTH_LOG);
936954

937-
const float recentness = smudge_bucket[PREV_COL_RECENTNESS] * update_factor;
938-
smudge_bucket[PREV_COL_RECENTNESS] = recentness;
955+
const float recentness = smudge_bucket->prev_col_recentness * update_factor;
956+
smudge_bucket->prev_col_recentness = recentness;
939957

940958
const float margin = 0.0000000000000001;
941959
if (recentness < MIN(1.0, powf(0.5 * update_factor, smudge_length_log) + margin)) {
942960
if (recentness == 0.0) {
943961
// first initialization of smudge color (initiate with color sampled from canvas)
944962
update_factor = 0.0;
945963
}
946-
smudge_bucket[PREV_COL_RECENTNESS] = 1.0;
964+
smudge_bucket->prev_col_recentness = 1.0;
947965

948966
const float radius_log = SETTING(self, SMUDGE_RADIUS_LOG);
949967
const float smudge_radius = CLAMP(radius * expf(radius_log), ACTUAL_RADIUS_MIN, ACTUAL_RADIUS_MAX);
@@ -960,45 +978,45 @@ void print_inputs(MyPaintBrush *self, float* inputs)
960978
if ((smudge_op_lim > 0.0 && a < smudge_op_lim) || (smudge_op_lim < 0.0 && a > -smudge_op_lim)) {
961979
return TRUE; // signals the caller to return early
962980
}
963-
smudge_bucket[PREV_COL_R] = r;
964-
smudge_bucket[PREV_COL_G] = g;
965-
smudge_bucket[PREV_COL_B] = b;
966-
smudge_bucket[PREV_COL_A] = a;
981+
smudge_bucket->prev_col_r = r;
982+
smudge_bucket->prev_col_g = g;
983+
smudge_bucket->prev_col_b = b;
984+
smudge_bucket->prev_col_a = a;
967985
} else {
968-
r = smudge_bucket[PREV_COL_R];
969-
g = smudge_bucket[PREV_COL_G];
970-
b = smudge_bucket[PREV_COL_B];
971-
a = smudge_bucket[PREV_COL_A];
986+
r = smudge_bucket->prev_col_r;
987+
g = smudge_bucket->prev_col_g;
988+
b = smudge_bucket->prev_col_b;
989+
a = smudge_bucket->prev_col_a;
972990
}
973991

974992
if (legacy_smudge) {
975993
const float fac_old = update_factor;
976994
const float fac_new = (1.0 - update_factor) * a;
977-
smudge_bucket[SMUDGE_R] = fac_old * smudge_bucket[SMUDGE_R] + fac_new * r;
978-
smudge_bucket[SMUDGE_G] = fac_old * smudge_bucket[SMUDGE_G] + fac_new * g;
979-
smudge_bucket[SMUDGE_B] = fac_old * smudge_bucket[SMUDGE_B] + fac_new * b;
980-
smudge_bucket[SMUDGE_A] = CLAMP((fac_old * smudge_bucket[SMUDGE_A] + fac_new), 0.0, 1.0);
995+
smudge_bucket->smudge_r = fac_old * smudge_bucket->smudge_r + fac_new * r;
996+
smudge_bucket->smudge_g = fac_old * smudge_bucket->smudge_g + fac_new * g;
997+
smudge_bucket->smudge_b = fac_old * smudge_bucket->smudge_b + fac_new * b;
998+
smudge_bucket->smudge_a = CLAMP((fac_old * smudge_bucket->smudge_a + fac_new), 0.0, 1.0);
981999
} else if (a > WGM_EPSILON * 10) {
982-
float prev_smudge_color[4] = {smudge_bucket[SMUDGE_R], smudge_bucket[SMUDGE_G], smudge_bucket[SMUDGE_B],
983-
smudge_bucket[SMUDGE_A]};
1000+
float prev_smudge_color[4] = {smudge_bucket->smudge_r, smudge_bucket->smudge_g, smudge_bucket->smudge_b,
1001+
smudge_bucket->smudge_a};
9841002
float sampled_color[4] = {r, g, b, a};
9851003

9861004
float* smudge_new = mix_colors(prev_smudge_color, sampled_color, update_factor, paint_factor);
987-
smudge_bucket[SMUDGE_R] = smudge_new[SMUDGE_R];
988-
smudge_bucket[SMUDGE_G] = smudge_new[SMUDGE_G];
989-
smudge_bucket[SMUDGE_B] = smudge_new[SMUDGE_B];
990-
smudge_bucket[SMUDGE_A] = smudge_new[SMUDGE_A];
1005+
smudge_bucket->smudge_r = smudge_new[0];
1006+
smudge_bucket->smudge_g = smudge_new[1];
1007+
smudge_bucket->smudge_b = smudge_new[2];
1008+
smudge_bucket->smudge_a = smudge_new[3];
9911009
} else {
9921010
// To avoid color noise from spectral mixing with a low alpha,
9931011
// we'll just decrease the alpha of the existing smudge color.
994-
smudge_bucket[SMUDGE_A] = (smudge_bucket[SMUDGE_A] + a) / 2;
1012+
smudge_bucket->smudge_a = (smudge_bucket->smudge_a + a) / 2;
9951013
}
9961014
return FALSE; // signals the caller to not return early (the default)
9971015
}
9981016

9991017
float
10001018
apply_smudge(
1001-
const float* const smudge_bucket, const float smudge_value, const gboolean legacy_smudge,
1019+
const SmudgeBucket* const smudge_bucket, const float smudge_value, const gboolean legacy_smudge,
10021020
const float paint_factor, float* color_r, float* color_g, float* color_b)
10031021
{
10041022
float smudge_factor = MIN(1.0, smudge_value);
@@ -1007,22 +1025,22 @@ void print_inputs(MyPaintBrush *self, float* inputs)
10071025
// dab will do erasing towards that transparency level.
10081026
// see also ../doc/smudge_math.png
10091027
const float eraser_target_alpha =
1010-
CLAMP((1.0 - smudge_factor) + smudge_factor * smudge_bucket[SMUDGE_A], 0.0, 1.0);
1028+
CLAMP((1.0 - smudge_factor) + smudge_factor * smudge_bucket->smudge_a, 0.0, 1.0);
10111029

10121030
if (eraser_target_alpha > 0) {
10131031
if (legacy_smudge) {
10141032
const float col_factor = 1.0 - smudge_factor;
1015-
*color_r = (smudge_factor * smudge_bucket[SMUDGE_R] + col_factor * *color_r) / eraser_target_alpha;
1016-
*color_g = (smudge_factor * smudge_bucket[SMUDGE_G] + col_factor * *color_g) / eraser_target_alpha;
1017-
*color_b = (smudge_factor * smudge_bucket[SMUDGE_B] + col_factor * *color_b) / eraser_target_alpha;
1033+
*color_r = (smudge_factor * smudge_bucket->smudge_r + col_factor * *color_r) / eraser_target_alpha;
1034+
*color_g = (smudge_factor * smudge_bucket->smudge_g + col_factor * *color_g) / eraser_target_alpha;
1035+
*color_b = (smudge_factor * smudge_bucket->smudge_b + col_factor * *color_b) / eraser_target_alpha;
10181036
} else {
1019-
float smudge_color[4] = {smudge_bucket[SMUDGE_R], smudge_bucket[SMUDGE_G], smudge_bucket[SMUDGE_B],
1020-
smudge_bucket[SMUDGE_A]};
1037+
float smudge_color[4] = {smudge_bucket->smudge_r, smudge_bucket->smudge_g, smudge_bucket->smudge_b,
1038+
smudge_bucket->smudge_a};
10211039
float brush_color[4] = {*color_r, *color_g, *color_b, 1.0};
10221040
float* color_new = mix_colors(smudge_color, brush_color, smudge_factor, paint_factor);
1023-
*color_r = color_new[SMUDGE_R];
1024-
*color_g = color_new[SMUDGE_G];
1025-
*color_b = color_new[SMUDGE_B];
1041+
*color_r = color_new[0];
1042+
*color_g = color_new[1];
1043+
*color_b = color_new[2];
10261044
}
10271045
} else {
10281046
// we are only erasing; the color does (should) not matter
@@ -1123,7 +1141,7 @@ gboolean prepare_and_draw_dab (MyPaintBrush *self, MyPaintSurface * surface, gbo
11231141
const float smudge_length = SETTING(self, SMUDGE_LENGTH);
11241142
if (smudge_length < 1.0 && // default smudge length is 0.5, so the smudge factor is checked as well
11251143
(SETTING(self, SMUDGE) != 0.0 || !mypaint_mapping_is_constant(self->settings[MYPAINT_BRUSH_SETTING_SMUDGE]))) {
1126-
float* const bucket = fetch_smudge_bucket(self);
1144+
SmudgeBucket* const bucket = fetch_smudge_bucket(self);
11271145
gboolean return_early = update_smudge_color(
11281146
self, surface, bucket, smudge_length, ROUND(x), ROUND(y), radius, legacy_smudge, paint_factor);
11291147
if (return_early) {
@@ -1135,7 +1153,7 @@ gboolean prepare_and_draw_dab (MyPaintBrush *self, MyPaintSurface * surface, gbo
11351153
const float smudge_value = SETTING(self, SMUDGE);
11361154

11371155
if (smudge_value > 0.0) {
1138-
float* const bucket = fetch_smudge_bucket(self);
1156+
SmudgeBucket* const bucket = fetch_smudge_bucket(self);
11391157
eraser_target_alpha =
11401158
apply_smudge(bucket, smudge_value, legacy_smudge, paint_factor, &color_h, &color_s, &color_v);
11411159
}

0 commit comments

Comments
 (0)