Skip to content

Commit f622fdd

Browse files
authored
Merge pull request #122 from briend/smudge_tweaks
Paint Mode, Smudge Buckets, Posterize Mode, etc
2 parents a2b3f56 + 096acda commit f622fdd

24 files changed

+4209
-148
lines changed

Makefile.am

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ MyPaint_introspectable_headers = \
3131
mypaint-rectangle.h \
3232
mypaint-surface.h \
3333
mypaint-tiled-surface.h \
34+
fastapprox/fastpow.h \
35+
fastapprox/sse.h \
36+
fastapprox/fastexp.h \
37+
fastapprox/cast.h \
38+
fastapprox/fastlog.h \
3439
$(libmypaint_glib)
3540

3641
if HAVE_INTROSPECTION

brushmodes.c

Lines changed: 190 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include <stdint.h>
2020
#include <assert.h>
21+
#include <math.h>
22+
#include "fastapprox/fastpow.h"
2123

2224
#include "helpers.h"
2325

@@ -43,6 +45,7 @@
4345
// resultAlpha = topAlpha + (1.0 - topAlpha) * bottomAlpha
4446
// resultColor = topColor + (1.0 - topAlpha) * bottomColor
4547
//
48+
4649
void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
4750
uint16_t * rgba,
4851
uint16_t color_r,
@@ -66,7 +69,89 @@ void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
6669
}
6770
};
6871

72+
void draw_dab_pixels_BlendMode_Normal_Paint (uint16_t * mask,
73+
uint16_t * rgba,
74+
uint16_t color_r,
75+
uint16_t color_g,
76+
uint16_t color_b,
77+
uint16_t opacity) {
78+
79+
while (1) {
80+
for (; mask[0]; mask++, rgba+=4) {
81+
uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
82+
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha
83+
84+
//alpha-weighted ratio for WGM (sums to 1.0)
85+
float fac_a = (float)opa_a / (opa_a + opa_b * rgba[3] / (1<<15));
86+
//fac_a *= fac_a;
87+
float fac_b = 1.0 - fac_a;
88+
89+
//convert bottom to spectral. Un-premult alpha to obtain reflectance
90+
//color noise is not a problem since low alpha also implies low weight
91+
float spectral_b[10] = {0};
92+
if (rgba[3] > 0) {
93+
rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral_b);
94+
} else {
95+
rgb_to_spectral((float)rgba[0]/ (1<<15), (float)rgba[1]/ (1<<15), (float)rgba[2]/ (1<<15), spectral_b);
96+
}
97+
// convert top to spectral. Already straight color
98+
float spectral_a[10] = {0};
99+
rgb_to_spectral((float)color_r / (1<<15), (float)color_g / (1<<15), (float)color_b / (1<<15), spectral_a);
100+
101+
// mix to the two spectral reflectances using WGM
102+
float spectral_result[10] = {0};
103+
for (int i=0; i<10; i++) {
104+
spectral_result[i] = fastpow(spectral_a[i], fac_a) * fastpow(spectral_b[i], fac_b);
105+
}
106+
107+
// convert back to RGB and premultiply alpha
108+
float rgb_result[3] = {0};
109+
spectral_to_rgb(spectral_result, rgb_result);
110+
rgba[3] = opa_a + opa_b * rgba[3] / (1<<15);
111+
112+
for (int i=0; i<3; i++) {
113+
rgba[i] =(rgb_result[i] * rgba[3]);
114+
}
115+
}
116+
if (!mask[1]) break;
117+
rgba += mask[1];
118+
mask += 2;
119+
}
120+
};
121+
122+
//Posterize. Basically exactly like GIMP's posterize
123+
//reduces colors by adjustable amount (posterize_num).
124+
//posterize the canvas, then blend that via opacity
125+
//does not affect alpha
126+
127+
void draw_dab_pixels_BlendMode_Posterize (uint16_t * mask,
128+
uint16_t * rgba,
129+
uint16_t opacity,
130+
uint16_t posterize_num) {
69131

132+
while (1) {
133+
for (; mask[0]; mask++, rgba+=4) {
134+
135+
float r = (float)rgba[0] / (1<<15);
136+
float g = (float)rgba[1] / (1<<15);
137+
float b = (float)rgba[2] / (1<<15);
138+
139+
uint32_t post_r = (1<<15) * ROUND(r * posterize_num) / posterize_num;
140+
uint32_t post_g = (1<<15) * ROUND(g * posterize_num) / posterize_num;
141+
uint32_t post_b = (1<<15) * ROUND(b * posterize_num) / posterize_num;
142+
143+
uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
144+
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha
145+
rgba[0] = (opa_a*post_r + opa_b*rgba[0])/(1<<15);
146+
rgba[1] = (opa_a*post_g + opa_b*rgba[1])/(1<<15);
147+
rgba[2] = (opa_a*post_b + opa_b*rgba[2])/(1<<15);
148+
149+
}
150+
if (!mask[1]) break;
151+
rgba += mask[1];
152+
mask += 2;
153+
}
154+
};
70155

71156
// Colorize: apply the source hue and saturation, retaining the target
72157
// brightness. Same thing as in the PDF spec addendum, and upcoming SVG
@@ -82,9 +167,9 @@ void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
82167
// http://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html.
83168
// Same as ITU Rec. BT.601 (SDTV) rounded to 2 decimal places.
84169

85-
static const float LUMA_RED_COEFF = 0.3 * (1<<15);
86-
static const float LUMA_GREEN_COEFF = 0.59 * (1<<15);
87-
static const float LUMA_BLUE_COEFF = 0.11 * (1<<15);
170+
static const float LUMA_RED_COEFF = 0.2126 * (1<<15);
171+
static const float LUMA_GREEN_COEFF = 0.7152 * (1<<15);
172+
static const float LUMA_BLUE_COEFF = 0.0722 * (1<<15);
88173

89174
// See also http://en.wikipedia.org/wiki/YCbCr
90175

@@ -224,6 +309,59 @@ void draw_dab_pixels_BlendMode_Normal_and_Eraser (uint16_t * mask,
224309
}
225310
};
226311

312+
void draw_dab_pixels_BlendMode_Normal_and_Eraser_Paint (uint16_t * mask,
313+
uint16_t * rgba,
314+
uint16_t color_r,
315+
uint16_t color_g,
316+
uint16_t color_b,
317+
uint16_t color_a,
318+
uint16_t opacity) {
319+
320+
while (1) {
321+
for (; mask[0]; mask++, rgba+=4) {
322+
uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
323+
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha
324+
325+
float fac_a = (float)opa_a / (opa_a + opa_b * rgba[3] / (1<<15));
326+
//fac_a *= fac_a;
327+
float fac_b = 1.0 - fac_a;
328+
//fac_a *= (float)color_a / (1<<15);
329+
float spectral_b[10] = {0};
330+
if (rgba[3] > 0) {
331+
rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral_b);
332+
} else {
333+
rgb_to_spectral((float)rgba[0]/ (1<<15), (float)rgba[1]/ (1<<15), (float)rgba[2]/ (1<<15), spectral_b);
334+
}
335+
// convert top to spectral. Already straight color
336+
float spectral_a[10] = {0};
337+
rgb_to_spectral((float)color_r / (1<<15), (float)color_g / (1<<15), (float)color_b / (1<<15), spectral_a);
338+
339+
// mix to the two spectral colors using WGM
340+
float spectral_result[10] = {0};
341+
for (int i=0; i<10; i++) {
342+
spectral_result[i] = fastpow(spectral_a[i], fac_a) * fastpow(spectral_b[i], fac_b);
343+
}
344+
// convert back to RGB
345+
float rgb_result[3] = {0};
346+
spectral_to_rgb(spectral_result, rgb_result);
347+
348+
// apply eraser
349+
opa_a = opa_a * color_a / (1<<15);
350+
351+
// calculate alpha normally
352+
rgba[3] = opa_a + opa_b * rgba[3] / (1<<15);
353+
354+
for (int i=0; i<3; i++) {
355+
rgba[i] =(rgb_result[i] * rgba[3]);
356+
}
357+
358+
}
359+
if (!mask[1]) break;
360+
rgba += mask[1];
361+
mask += 2;
362+
}
363+
};
364+
227365
// This is BlendMode_Normal with locked alpha channel.
228366
//
229367
void draw_dab_pixels_BlendMode_LockAlpha (uint16_t * mask,
@@ -251,6 +389,53 @@ void draw_dab_pixels_BlendMode_LockAlpha (uint16_t * mask,
251389
}
252390
};
253391

392+
void draw_dab_pixels_BlendMode_LockAlpha_Paint (uint16_t * mask,
393+
uint16_t * rgba,
394+
uint16_t color_r,
395+
uint16_t color_g,
396+
uint16_t color_b,
397+
uint16_t opacity) {
398+
399+
while (1) {
400+
for (; mask[0]; mask++, rgba+=4) {
401+
402+
uint32_t opa_a = mask[0]*(uint32_t)opacity/(1<<15); // topAlpha
403+
uint32_t opa_b = (1<<15)-opa_a; // bottomAlpha
404+
opa_a *= rgba[3];
405+
opa_a /= (1<<15);
406+
float fac_a = (float)opa_a / (opa_a + opa_b * rgba[3] / (1<<15));
407+
//fac_a *= fac_a;
408+
float fac_b = 1.0 - fac_a;
409+
float spectral_b[10] = {0};
410+
if (rgba[3] > 0) {
411+
rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral_b);
412+
} else {
413+
rgb_to_spectral((float)rgba[0]/ (1<<15), (float)rgba[1]/ (1<<15), (float)rgba[2]/ (1<<15), spectral_b);
414+
}
415+
// convert top to spectral. Already straight color
416+
float spectral_a[10] = {0};
417+
rgb_to_spectral((float)color_r / (1<<15), (float)color_g / (1<<15), (float)color_b / (1<<15), spectral_a);
418+
419+
// mix to the two spectral colors using WGM
420+
float spectral_result[10] = {0};
421+
for (int i=0; i<10; i++) {
422+
spectral_result[i] = fastpow(spectral_a[i], fac_a) * fastpow(spectral_b[i], fac_b);
423+
}
424+
// convert back to RGB
425+
float rgb_result[3] = {0};
426+
spectral_to_rgb(spectral_result, rgb_result);
427+
rgba[3] = opa_a + opa_b * rgba[3] / (1<<15);
428+
429+
for (int i=0; i<3; i++) {
430+
rgba[i] =(rgb_result[i] * rgba[3]);
431+
}
432+
}
433+
if (!mask[1]) break;
434+
rgba += mask[1];
435+
mask += 2;
436+
}
437+
};
438+
254439

255440
// Sum up the color/alpha components inside the masked region.
256441
// Called by get_color().
@@ -299,3 +484,5 @@ void get_color_pixels_accumulate (uint16_t * mask,
299484
*sum_a += a;
300485
};
301486

487+
488+

brushmodes.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,56 @@ void draw_dab_pixels_BlendMode_Normal (uint16_t * mask,
77
uint16_t color_g,
88
uint16_t color_b,
99
uint16_t opacity);
10+
11+
void draw_dab_pixels_BlendMode_Normal_Paint (uint16_t * mask,
12+
uint16_t * rgba,
13+
uint16_t color_r,
14+
uint16_t color_g,
15+
uint16_t color_b,
16+
uint16_t opacity);
1017
void
1118
draw_dab_pixels_BlendMode_Color (uint16_t *mask,
1219
uint16_t *rgba, // b=bottom, premult
1320
uint16_t color_r, // }
1421
uint16_t color_g, // }-- a=top, !premult
1522
uint16_t color_b, // }
1623
uint16_t opacity);
24+
void
25+
draw_dab_pixels_BlendMode_Posterize (uint16_t *mask,
26+
uint16_t *rgba, // b=bottom, premult
27+
uint16_t posterize,
28+
uint16_t posterize_num);
29+
1730
void draw_dab_pixels_BlendMode_Normal_and_Eraser (uint16_t * mask,
1831
uint16_t * rgba,
1932
uint16_t color_r,
2033
uint16_t color_g,
2134
uint16_t color_b,
2235
uint16_t color_a,
2336
uint16_t opacity);
37+
38+
void draw_dab_pixels_BlendMode_Normal_and_Eraser_Paint (uint16_t * mask,
39+
uint16_t * rgba,
40+
uint16_t color_r,
41+
uint16_t color_g,
42+
uint16_t color_b,
43+
uint16_t color_a,
44+
uint16_t opacity);
45+
2446
void draw_dab_pixels_BlendMode_LockAlpha (uint16_t * mask,
2547
uint16_t * rgba,
2648
uint16_t color_r,
2749
uint16_t color_g,
2850
uint16_t color_b,
2951
uint16_t opacity);
52+
53+
void draw_dab_pixels_BlendMode_LockAlpha_Paint (uint16_t * mask,
54+
uint16_t * rgba,
55+
uint16_t color_r,
56+
uint16_t color_g,
57+
uint16_t color_b,
58+
uint16_t opacity);
59+
3060
void get_color_pixels_accumulate (uint16_t * mask,
3161
uint16_t * rgba,
3262
float * sum_weight,

0 commit comments

Comments
 (0)