1 // Aseprite Document Library
2 // Copyright (c) 2001-2017 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 //
7 // --
8 //
9 // Some references about alpha compositing and blend modes:
10 //
11 // http://dev.w3.org/fxtf/compositing-1/
12 // http://www.adobe.com/devnet/pdf/pdf_reference.html
13 //
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #include "doc/blend_funcs.h"
20
21 #include "base/base.h"
22 #include "base/debug.h"
23 #include "doc/blend_internals.h"
24
25 #include <cmath>
26
27 namespace {
28
29 #define blend_multiply(b, s, t) (MUL_UN8((b), (s), (t)))
30 #define blend_screen(b, s, t) ((b) + (s) - MUL_UN8((b), (s), (t)))
31 #define blend_overlay(b, s, t) (blend_hard_light(s, b, t))
32 #define blend_darken(b, s) (MIN((b), (s)))
33 #define blend_lighten(b, s) (MAX((b), (s)))
34 #define blend_hard_light(b, s, t) ((s) < 128 ? \
35 blend_multiply((b), (s)<<1, (t)): \
36 blend_screen((b), ((s)<<1)-255, (t)))
37 #define blend_difference(b, s) (ABS((b) - (s)))
38 #define blend_exclusion(b, s, t) ((t) = MUL_UN8((b), (s), (t)), ((b) + (s) - 2*(t)))
39
blend_divide(uint32_t b,uint32_t s)40 inline uint32_t blend_divide(uint32_t b, uint32_t s)
41 {
42 if (b == 0)
43 return 0;
44 else if (b >= s)
45 return 255;
46 else
47 return DIV_UN8(b, s); // return b / s
48 }
49
blend_color_dodge(uint32_t b,uint32_t s)50 inline uint32_t blend_color_dodge(uint32_t b, uint32_t s)
51 {
52 if (b == 0)
53 return 0;
54
55 s = (255 - s);
56 if (b >= s)
57 return 255;
58 else
59 return DIV_UN8(b, s); // return b / (1-s)
60 }
61
blend_color_burn(uint32_t b,uint32_t s)62 inline uint32_t blend_color_burn(uint32_t b, uint32_t s)
63 {
64 if (b == 255)
65 return 255;
66
67 b = (255 - b);
68 if (b >= s)
69 return 0;
70 else
71 return 255 - DIV_UN8(b, s); // return 1 - ((1-b)/s)
72 }
73
blend_soft_light(uint32_t _b,uint32_t _s)74 inline uint32_t blend_soft_light(uint32_t _b, uint32_t _s)
75 {
76 double b = _b / 255.0;
77 double s = _s / 255.0;
78 double r, d;
79
80 if (b <= 0.25)
81 d = ((16*b-12)*b+4)*b;
82 else
83 d = std::sqrt(b);
84
85 if (s <= 0.5)
86 r = b - (1.0 - 2.0 * s) * b * (1.0 - b);
87 else
88 r = b + (2.0 * s - 1.0) * (d - b);
89
90 return (uint32_t)(r * 255 + 0.5);
91 }
92
93 } // annonymous namespace
94
95 namespace doc {
96
97 //////////////////////////////////////////////////////////////////////
98 // RGB blenders
99
rgba_blender_src(color_t backdrop,color_t src,int opacity)100 color_t rgba_blender_src(color_t backdrop, color_t src, int opacity)
101 {
102 return src;
103 }
104
rgba_blender_merge(color_t backdrop,color_t src,int opacity)105 color_t rgba_blender_merge(color_t backdrop, color_t src, int opacity)
106 {
107 int Br, Bg, Bb, Ba;
108 int Sr, Sg, Sb, Sa;
109 int Rr, Rg, Rb, Ra;
110 int t;
111
112 Br = rgba_getr(backdrop);
113 Bg = rgba_getg(backdrop);
114 Bb = rgba_getb(backdrop);
115 Ba = rgba_geta(backdrop);
116
117 Sr = rgba_getr(src);
118 Sg = rgba_getg(src);
119 Sb = rgba_getb(src);
120 Sa = rgba_geta(src);
121
122 if (Ba == 0) {
123 Rr = Sr;
124 Rg = Sg;
125 Rb = Sb;
126 }
127 else if (Sa == 0) {
128 Rr = Br;
129 Rg = Bg;
130 Rb = Bb;
131 }
132 else {
133 Rr = Br + MUL_UN8((Sr - Br), opacity, t);
134 Rg = Bg + MUL_UN8((Sg - Bg), opacity, t);
135 Rb = Bb + MUL_UN8((Sb - Bb), opacity, t);
136 }
137 Ra = Ba + MUL_UN8((Sa - Ba), opacity, t);
138 if (Ra == 0)
139 Rr = Rg = Rb = 0;
140
141 return rgba(Rr, Rg, Rb, Ra);
142 }
143
rgba_blender_neg_bw(color_t backdrop,color_t src,int opacity)144 color_t rgba_blender_neg_bw(color_t backdrop, color_t src, int opacity)
145 {
146 if (!(backdrop & rgba_a_mask))
147 return rgba(0, 0, 0, 255);
148 else if (rgba_luma(backdrop) < 128)
149 return rgba(255, 255, 255, 255);
150 else
151 return rgba(0, 0, 0, 255);
152 }
153
rgba_blender_red_tint(color_t backdrop,color_t src,int opacity)154 color_t rgba_blender_red_tint(color_t backdrop, color_t src, int opacity)
155 {
156 int v = rgba_luma(src);
157 src = rgba((255+v)/2, v/2, v/2, rgba_geta(src));
158 return rgba_blender_normal(backdrop, src, opacity);
159 }
160
rgba_blender_blue_tint(color_t backdrop,color_t src,int opacity)161 color_t rgba_blender_blue_tint(color_t backdrop, color_t src, int opacity)
162 {
163 int v = rgba_luma(src);
164 src = rgba(v/2, v/2, (255+v)/2, rgba_geta(src));
165 return rgba_blender_normal(backdrop, src, opacity);
166 }
167
rgba_blender_normal(color_t backdrop,color_t src,int opacity)168 color_t rgba_blender_normal(color_t backdrop, color_t src, int opacity)
169 {
170 int t;
171
172 if ((backdrop & rgba_a_mask) == 0) {
173 int a = rgba_geta(src);
174 a = MUL_UN8(a, opacity, t);
175 a <<= rgba_a_shift;
176 return (src & rgba_rgb_mask) | a;
177 }
178 else if ((src & rgba_a_mask) == 0) {
179 return backdrop;
180 }
181
182 const int Br = rgba_getr(backdrop);
183 const int Bg = rgba_getg(backdrop);
184 const int Bb = rgba_getb(backdrop);
185 const int Ba = rgba_geta(backdrop);
186
187 const int Sr = rgba_getr(src);
188 const int Sg = rgba_getg(src);
189 const int Sb = rgba_getb(src);
190 int Sa = rgba_geta(src);
191 Sa = MUL_UN8(Sa, opacity, t);
192
193 // Ra = Sa + Ba*(1-Sa)
194 // = Sa + Ba - Ba*Sa
195 const int Ra = Sa + Ba - MUL_UN8(Ba, Sa, t);
196
197 // Ra = Sa + Ba*(1-Sa)
198 // Ba = (Ra-Sa) / (1-Sa)
199 // Rc = (Sc*Sa + Bc*Ba*(1-Sa)) / Ra Replacing Ba with (Ra-Sa) / (1-Sa)...
200 // = (Sc*Sa + Bc*(Ra-Sa)/(1-Sa)*(1-Sa)) / Ra
201 // = (Sc*Sa + Bc*(Ra-Sa)) / Ra
202 // = Sc*Sa/Ra + Bc*Ra/Ra - Bc*Sa/Ra
203 // = Sc*Sa/Ra + Bc - Bc*Sa/Ra
204 // = Bc + (Sc-Bc)*Sa/Ra
205 const int Rr = Br + (Sr-Br) * Sa / Ra;
206 const int Rg = Bg + (Sg-Bg) * Sa / Ra;
207 const int Rb = Bb + (Sb-Bb) * Sa / Ra;
208
209 return rgba(Rr, Rg, Rb, Ra);
210 }
211
rgba_blender_multiply(color_t backdrop,color_t src,int opacity)212 color_t rgba_blender_multiply(color_t backdrop, color_t src, int opacity)
213 {
214 int t;
215 int r = blend_multiply(rgba_getr(backdrop), rgba_getr(src), t);
216 int g = blend_multiply(rgba_getg(backdrop), rgba_getg(src), t);
217 int b = blend_multiply(rgba_getb(backdrop), rgba_getb(src), t);
218 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
219 return rgba_blender_normal(backdrop, src, opacity);
220 }
221
rgba_blender_screen(color_t backdrop,color_t src,int opacity)222 color_t rgba_blender_screen(color_t backdrop, color_t src, int opacity)
223 {
224 int t;
225 int r = blend_screen(rgba_getr(backdrop), rgba_getr(src), t);
226 int g = blend_screen(rgba_getg(backdrop), rgba_getg(src), t);
227 int b = blend_screen(rgba_getb(backdrop), rgba_getb(src), t);
228 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
229 return rgba_blender_normal(backdrop, src, opacity);
230 }
231
rgba_blender_overlay(color_t backdrop,color_t src,int opacity)232 color_t rgba_blender_overlay(color_t backdrop, color_t src, int opacity)
233 {
234 int t;
235 int r = blend_overlay(rgba_getr(backdrop), rgba_getr(src), t);
236 int g = blend_overlay(rgba_getg(backdrop), rgba_getg(src), t);
237 int b = blend_overlay(rgba_getb(backdrop), rgba_getb(src), t);
238 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
239 return rgba_blender_normal(backdrop, src, opacity);
240 }
241
rgba_blender_darken(color_t backdrop,color_t src,int opacity)242 color_t rgba_blender_darken(color_t backdrop, color_t src, int opacity)
243 {
244 int r = blend_darken(rgba_getr(backdrop), rgba_getr(src));
245 int g = blend_darken(rgba_getg(backdrop), rgba_getg(src));
246 int b = blend_darken(rgba_getb(backdrop), rgba_getb(src));
247 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
248 return rgba_blender_normal(backdrop, src, opacity);
249 }
250
rgba_blender_lighten(color_t backdrop,color_t src,int opacity)251 color_t rgba_blender_lighten(color_t backdrop, color_t src, int opacity)
252 {
253 int r = blend_lighten(rgba_getr(backdrop), rgba_getr(src));
254 int g = blend_lighten(rgba_getg(backdrop), rgba_getg(src));
255 int b = blend_lighten(rgba_getb(backdrop), rgba_getb(src));
256 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
257 return rgba_blender_normal(backdrop, src, opacity);
258 }
259
rgba_blender_color_dodge(color_t backdrop,color_t src,int opacity)260 color_t rgba_blender_color_dodge(color_t backdrop, color_t src, int opacity)
261 {
262 int r = blend_color_dodge(rgba_getr(backdrop), rgba_getr(src));
263 int g = blend_color_dodge(rgba_getg(backdrop), rgba_getg(src));
264 int b = blend_color_dodge(rgba_getb(backdrop), rgba_getb(src));
265 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
266 return rgba_blender_normal(backdrop, src, opacity);
267 }
268
rgba_blender_color_burn(color_t backdrop,color_t src,int opacity)269 color_t rgba_blender_color_burn(color_t backdrop, color_t src, int opacity)
270 {
271 int r = blend_color_burn(rgba_getr(backdrop), rgba_getr(src));
272 int g = blend_color_burn(rgba_getg(backdrop), rgba_getg(src));
273 int b = blend_color_burn(rgba_getb(backdrop), rgba_getb(src));
274 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
275 return rgba_blender_normal(backdrop, src, opacity);
276 }
277
rgba_blender_hard_light(color_t backdrop,color_t src,int opacity)278 color_t rgba_blender_hard_light(color_t backdrop, color_t src, int opacity)
279 {
280 int t;
281 int r = blend_hard_light(rgba_getr(backdrop), rgba_getr(src), t);
282 int g = blend_hard_light(rgba_getg(backdrop), rgba_getg(src), t);
283 int b = blend_hard_light(rgba_getb(backdrop), rgba_getb(src), t);
284 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
285 return rgba_blender_normal(backdrop, src, opacity);
286 }
287
rgba_blender_soft_light(color_t backdrop,color_t src,int opacity)288 color_t rgba_blender_soft_light(color_t backdrop, color_t src, int opacity)
289 {
290 int r = blend_soft_light(rgba_getr(backdrop), rgba_getr(src));
291 int g = blend_soft_light(rgba_getg(backdrop), rgba_getg(src));
292 int b = blend_soft_light(rgba_getb(backdrop), rgba_getb(src));
293 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
294 return rgba_blender_normal(backdrop, src, opacity);
295 }
296
rgba_blender_difference(color_t backdrop,color_t src,int opacity)297 color_t rgba_blender_difference(color_t backdrop, color_t src, int opacity)
298 {
299 int r = blend_difference(rgba_getr(backdrop), rgba_getr(src));
300 int g = blend_difference(rgba_getg(backdrop), rgba_getg(src));
301 int b = blend_difference(rgba_getb(backdrop), rgba_getb(src));
302 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
303 return rgba_blender_normal(backdrop, src, opacity);
304 }
305
rgba_blender_exclusion(color_t backdrop,color_t src,int opacity)306 color_t rgba_blender_exclusion(color_t backdrop, color_t src, int opacity)
307 {
308 int t;
309 int r = blend_exclusion(rgba_getr(backdrop), rgba_getr(src), t);
310 int g = blend_exclusion(rgba_getg(backdrop), rgba_getg(src), t);
311 int b = blend_exclusion(rgba_getb(backdrop), rgba_getb(src), t);
312 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
313 return rgba_blender_normal(backdrop, src, opacity);
314 }
315
316 //////////////////////////////////////////////////////////////////////
317 // HSV blenders
318
lum(double r,double g,double b)319 static double lum(double r, double g, double b)
320 {
321 return 0.3*r + 0.59*g + 0.11*b;
322 }
323
sat(double r,double g,double b)324 static double sat(double r, double g, double b)
325 {
326 return MAX(r, MAX(g, b)) - MIN(r, MIN(g, b));
327 }
328
clip_color(double & r,double & g,double & b)329 static void clip_color(double& r, double& g, double& b)
330 {
331 double l = lum(r, g, b);
332 double n = MIN(r, MIN(g, b));
333 double x = MAX(r, MAX(g, b));
334
335 if (n < 0) {
336 r = l + (((r - l) * l) / (l - n));
337 g = l + (((g - l) * l) / (l - n));
338 b = l + (((b - l) * l) / (l - n));
339 }
340
341 if (x > 1) {
342 r = l + (((r - l) * (1 - l)) / (x - l));
343 g = l + (((g - l) * (1 - l)) / (x - l));
344 b = l + (((b - l) * (1 - l)) / (x - l));
345 }
346 }
347
set_lum(double & r,double & g,double & b,double l)348 static void set_lum(double& r, double& g, double& b, double l)
349 {
350 double d = l - lum(r, g, b);
351 r += d;
352 g += d;
353 b += d;
354 clip_color(r, g, b);
355 }
356
set_sat(double & r,double & g,double & b,double s)357 static void set_sat(double& r, double& g, double& b, double s)
358 {
359 double& min = MIN(r, MIN(g, b));
360 double& mid = MID(r, g, b);
361 double& max = MAX(r, MAX(g, b));
362
363 if (max > min) {
364 mid = ((mid - min)*s) / (max - min);
365 max = s;
366 }
367 else
368 mid = max = 0;
369
370 min = 0;
371 }
372
rgba_blender_hsl_hue(color_t backdrop,color_t src,int opacity)373 color_t rgba_blender_hsl_hue(color_t backdrop, color_t src, int opacity)
374 {
375 double r = rgba_getr(backdrop)/255.0;
376 double g = rgba_getg(backdrop)/255.0;
377 double b = rgba_getb(backdrop)/255.0;
378 double s = sat(r, g, b);
379 double l = lum(r, g, b);
380
381 r = rgba_getr(src)/255.0;
382 g = rgba_getg(src)/255.0;
383 b = rgba_getb(src)/255.0;
384
385 set_sat(r, g, b, s);
386 set_lum(r, g, b, l);
387
388 src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
389 return rgba_blender_normal(backdrop, src, opacity);
390 }
391
rgba_blender_hsl_saturation(color_t backdrop,color_t src,int opacity)392 color_t rgba_blender_hsl_saturation(color_t backdrop, color_t src, int opacity)
393 {
394 double r = rgba_getr(src)/255.0;
395 double g = rgba_getg(src)/255.0;
396 double b = rgba_getb(src)/255.0;
397 double s = sat(r, g, b);
398
399 r = rgba_getr(backdrop)/255.0;
400 g = rgba_getg(backdrop)/255.0;
401 b = rgba_getb(backdrop)/255.0;
402 double l = lum(r, g, b);
403
404 set_sat(r, g, b, s);
405 set_lum(r, g, b, l);
406
407 src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
408 return rgba_blender_normal(backdrop, src, opacity);
409 }
410
rgba_blender_hsl_color(color_t backdrop,color_t src,int opacity)411 color_t rgba_blender_hsl_color(color_t backdrop, color_t src, int opacity)
412 {
413 double r = rgba_getr(backdrop)/255.0;
414 double g = rgba_getg(backdrop)/255.0;
415 double b = rgba_getb(backdrop)/255.0;
416 double l = lum(r, g, b);
417
418 r = rgba_getr(src)/255.0;
419 g = rgba_getg(src)/255.0;
420 b = rgba_getb(src)/255.0;
421
422 set_lum(r, g, b, l);
423
424 src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
425 return rgba_blender_normal(backdrop, src, opacity);
426 }
427
rgba_blender_hsl_luminosity(color_t backdrop,color_t src,int opacity)428 color_t rgba_blender_hsl_luminosity(color_t backdrop, color_t src, int opacity)
429 {
430 double r = rgba_getr(src)/255.0;
431 double g = rgba_getg(src)/255.0;
432 double b = rgba_getb(src)/255.0;
433 double l = lum(r, g, b);
434
435 r = rgba_getr(backdrop)/255.0;
436 g = rgba_getg(backdrop)/255.0;
437 b = rgba_getb(backdrop)/255.0;
438
439 set_lum(r, g, b, l);
440
441 src = rgba(int(255.0*r), int(255.0*g), int(255.0*b), 0) | (src & rgba_a_mask);
442 return rgba_blender_normal(backdrop, src, opacity);
443 }
444
rgba_blender_addition(color_t backdrop,color_t src,int opacity)445 color_t rgba_blender_addition(color_t backdrop, color_t src, int opacity)
446 {
447 int r = rgba_getr(backdrop) + rgba_getr(src);
448 int g = rgba_getg(backdrop) + rgba_getg(src);
449 int b = rgba_getb(backdrop) + rgba_getb(src);
450 src = rgba(MIN(r, 255), MIN(g, 255), MIN(b, 255), 0) | (src & rgba_a_mask);
451 return rgba_blender_normal(backdrop, src, opacity);
452 }
453
rgba_blender_subtract(color_t backdrop,color_t src,int opacity)454 color_t rgba_blender_subtract(color_t backdrop, color_t src, int opacity)
455 {
456 int r = rgba_getr(backdrop) - rgba_getr(src);
457 int g = rgba_getg(backdrop) - rgba_getg(src);
458 int b = rgba_getb(backdrop) - rgba_getb(src);
459 src = rgba(MAX(r, 0), MAX(g, 0), MAX(b, 0), 0) | (src & rgba_a_mask);
460 return rgba_blender_normal(backdrop, src, opacity);
461 }
462
rgba_blender_divide(color_t backdrop,color_t src,int opacity)463 color_t rgba_blender_divide(color_t backdrop, color_t src, int opacity)
464 {
465 int r = blend_divide(rgba_getr(backdrop), rgba_getr(src));
466 int g = blend_divide(rgba_getg(backdrop), rgba_getg(src));
467 int b = blend_divide(rgba_getb(backdrop), rgba_getb(src));
468 src = rgba(r, g, b, 0) | (src & rgba_a_mask);
469 return rgba_blender_normal(backdrop, src, opacity);
470 }
471
472 //////////////////////////////////////////////////////////////////////
473 // GRAY blenders
474
graya_blender_src(color_t backdrop,color_t src,int opacity)475 color_t graya_blender_src(color_t backdrop, color_t src, int opacity)
476 {
477 return src;
478 }
479
graya_blender_merge(color_t backdrop,color_t src,int opacity)480 color_t graya_blender_merge(color_t backdrop, color_t src, int opacity)
481 {
482 int Bk, Ba;
483 int Sk, Sa;
484 int Rk, Ra;
485 int t;
486
487 Bk = graya_getv(backdrop);
488 Ba = graya_geta(backdrop);
489
490 Sk = graya_getv(src);
491 Sa = graya_geta(src);
492
493 if (Ba == 0) {
494 Rk = Sk;
495 }
496 else if (Sa == 0) {
497 Rk = Bk;
498 }
499 else {
500 Rk = Bk + MUL_UN8((Sk-Bk), opacity, t);
501 }
502 Ra = Ba + MUL_UN8((Sa-Ba), opacity, t);
503 if (Ra == 0)
504 Rk = 0;
505
506 return graya(Rk, Ra);
507 }
508
graya_blender_neg_bw(color_t backdrop,color_t src,int opacity)509 color_t graya_blender_neg_bw(color_t backdrop, color_t src, int opacity)
510 {
511 if ((backdrop & graya_a_mask) == 0)
512 return src;
513 else if (graya_getv(backdrop) < 128)
514 return graya(255, 255);
515 else
516 return graya(0, 255);
517 }
518
graya_blender_normal(color_t backdrop,color_t src,int opacity)519 color_t graya_blender_normal(color_t backdrop, color_t src, int opacity)
520 {
521 int t;
522
523 if ((backdrop & graya_a_mask) == 0) {
524 int a = graya_geta(src);
525 a = MUL_UN8(a, opacity, t);
526 a <<= graya_a_shift;
527 return (src & 0xff) | a;
528 }
529 else if ((src & graya_a_mask) == 0)
530 return backdrop;
531
532 int Bg, Ba;
533 int Sg, Sa;
534 int Rg, Ra;
535
536 Bg = graya_getv(backdrop);
537 Ba = graya_geta(backdrop);
538
539 Sg = graya_getv(src);
540 Sa = graya_geta(src);
541 Sa = MUL_UN8(Sa, opacity, t);
542
543 Ra = Ba + Sa - MUL_UN8(Ba, Sa, t);
544 Rg = Bg + (Sg-Bg) * Sa / Ra;
545
546 return graya(Rg, Ra);
547 }
548
graya_blender_multiply(color_t backdrop,color_t src,int opacity)549 color_t graya_blender_multiply(color_t backdrop, color_t src, int opacity)
550 {
551 int t;
552 int v = blend_multiply(graya_getv(backdrop), graya_getv(src), t);
553 src = graya(v, 0) | (src & graya_a_mask);
554 return graya_blender_normal(backdrop, src, opacity);
555 }
556
graya_blender_screen(color_t backdrop,color_t src,int opacity)557 color_t graya_blender_screen(color_t backdrop, color_t src, int opacity)
558 {
559 int t;
560 int v = blend_screen(graya_getv(backdrop), graya_getv(src), t);
561 src = graya(v, 0) | (src & graya_a_mask);
562 return graya_blender_normal(backdrop, src, opacity);
563 }
564
graya_blender_overlay(color_t backdrop,color_t src,int opacity)565 color_t graya_blender_overlay(color_t backdrop, color_t src, int opacity)
566 {
567 int t;
568 int v = blend_overlay(graya_getv(backdrop), graya_getv(src), t);
569 src = graya(v, 0) | (src & graya_a_mask);
570 return graya_blender_normal(backdrop, src, opacity);
571 }
572
graya_blender_darken(color_t backdrop,color_t src,int opacity)573 color_t graya_blender_darken(color_t backdrop, color_t src, int opacity)
574 {
575 int v = blend_darken(graya_getv(backdrop), graya_getv(src));
576 src = graya(v, 0) | (src & graya_a_mask);
577 return graya_blender_normal(backdrop, src, opacity);
578 }
579
graya_blender_lighten(color_t backdrop,color_t src,int opacity)580 color_t graya_blender_lighten(color_t backdrop, color_t src, int opacity)
581 {
582 int v = blend_lighten(graya_getv(backdrop), graya_getv(src));
583 src = graya(v, 0) | (src & graya_a_mask);
584 return graya_blender_normal(backdrop, src, opacity);
585 }
586
graya_blender_color_dodge(color_t backdrop,color_t src,int opacity)587 color_t graya_blender_color_dodge(color_t backdrop, color_t src, int opacity)
588 {
589 int v = blend_color_dodge(graya_getv(backdrop), graya_getv(src));
590 src = graya(v, 0) | (src & graya_a_mask);
591 return graya_blender_normal(backdrop, src, opacity);
592 }
593
graya_blender_color_burn(color_t backdrop,color_t src,int opacity)594 color_t graya_blender_color_burn(color_t backdrop, color_t src, int opacity)
595 {
596 int v = blend_color_burn(graya_getv(backdrop), graya_getv(src));
597 src = graya(v, 0) | (src & graya_a_mask);
598 return graya_blender_normal(backdrop, src, opacity);
599 }
600
graya_blender_hard_light(color_t backdrop,color_t src,int opacity)601 color_t graya_blender_hard_light(color_t backdrop, color_t src, int opacity)
602 {
603 int t;
604 int v = blend_hard_light(graya_getv(backdrop), graya_getv(src), t);
605 src = graya(v, 0) | (src & graya_a_mask);
606 return graya_blender_normal(backdrop, src, opacity);
607 }
608
graya_blender_soft_light(color_t backdrop,color_t src,int opacity)609 color_t graya_blender_soft_light(color_t backdrop, color_t src, int opacity)
610 {
611 int v = blend_soft_light(graya_getv(backdrop), graya_getv(src));
612 src = graya(v, 0) | (src & graya_a_mask);
613 return graya_blender_normal(backdrop, src, opacity);
614 }
615
graya_blender_difference(color_t backdrop,color_t src,int opacity)616 color_t graya_blender_difference(color_t backdrop, color_t src, int opacity)
617 {
618 int v = blend_difference(graya_getv(backdrop), graya_getv(src));
619 src = graya(v, 0) | (src & graya_a_mask);
620 return graya_blender_normal(backdrop, src, opacity);
621 }
622
graya_blender_exclusion(color_t backdrop,color_t src,int opacity)623 color_t graya_blender_exclusion(color_t backdrop, color_t src, int opacity)
624 {
625 int t;
626 int v = blend_exclusion(graya_getv(backdrop), graya_getv(src), t);
627 src = graya(v, 0) | (src & graya_a_mask);
628 return graya_blender_normal(backdrop, src, opacity);
629 }
630
graya_blender_addition(color_t backdrop,color_t src,int opacity)631 color_t graya_blender_addition(color_t backdrop, color_t src, int opacity)
632 {
633 int v = graya_getv(backdrop) + graya_getv(src);
634 src = graya(MIN(v, 255), 0) | (src & graya_a_mask);
635 return graya_blender_normal(backdrop, src, opacity);
636 }
637
graya_blender_subtract(color_t backdrop,color_t src,int opacity)638 color_t graya_blender_subtract(color_t backdrop, color_t src, int opacity)
639 {
640 int v = graya_getv(backdrop) - graya_getv(src);
641 src = graya(MAX(v, 0), 0) | (src & graya_a_mask);
642 return graya_blender_normal(backdrop, src, opacity);
643 }
644
graya_blender_divide(color_t backdrop,color_t src,int opacity)645 color_t graya_blender_divide(color_t backdrop, color_t src, int opacity)
646 {
647 int v = blend_divide(graya_getv(backdrop), graya_getv(src));
648 src = graya(v, 0) | (src & graya_a_mask);
649 return graya_blender_normal(backdrop, src, opacity);
650 }
651
652 //////////////////////////////////////////////////////////////////////
653 // indexed
654
indexed_blender_src(color_t dst,color_t src,int opacity)655 color_t indexed_blender_src(color_t dst, color_t src, int opacity)
656 {
657 return src;
658 }
659
660 //////////////////////////////////////////////////////////////////////
661 // getters
662
get_rgba_blender(BlendMode blendmode)663 BlendFunc get_rgba_blender(BlendMode blendmode)
664 {
665 switch (blendmode) {
666 case BlendMode::SRC: return rgba_blender_src;
667 case BlendMode::MERGE: return rgba_blender_merge;
668 case BlendMode::NEG_BW: return rgba_blender_neg_bw;
669 case BlendMode::RED_TINT: return rgba_blender_red_tint;
670 case BlendMode::BLUE_TINT: return rgba_blender_blue_tint;
671
672 case BlendMode::NORMAL: return rgba_blender_normal;
673 case BlendMode::MULTIPLY: return rgba_blender_multiply;
674 case BlendMode::SCREEN: return rgba_blender_screen;
675 case BlendMode::OVERLAY: return rgba_blender_overlay;
676 case BlendMode::DARKEN: return rgba_blender_darken;
677 case BlendMode::LIGHTEN: return rgba_blender_lighten;
678 case BlendMode::COLOR_DODGE: return rgba_blender_color_dodge;
679 case BlendMode::COLOR_BURN: return rgba_blender_color_burn;
680 case BlendMode::HARD_LIGHT: return rgba_blender_hard_light;
681 case BlendMode::SOFT_LIGHT: return rgba_blender_soft_light;
682 case BlendMode::DIFFERENCE: return rgba_blender_difference;
683 case BlendMode::EXCLUSION: return rgba_blender_exclusion;
684 case BlendMode::HSL_HUE: return rgba_blender_hsl_hue;
685 case BlendMode::HSL_SATURATION: return rgba_blender_hsl_saturation;
686 case BlendMode::HSL_COLOR: return rgba_blender_hsl_color;
687 case BlendMode::HSL_LUMINOSITY: return rgba_blender_hsl_luminosity;
688 case BlendMode::ADDITION: return rgba_blender_addition;
689 case BlendMode::SUBTRACT: return rgba_blender_subtract;
690 case BlendMode::DIVIDE: return rgba_blender_divide;
691 }
692 ASSERT(false);
693 return rgba_blender_src;
694 }
695
get_graya_blender(BlendMode blendmode)696 BlendFunc get_graya_blender(BlendMode blendmode)
697 {
698 switch (blendmode) {
699 case BlendMode::SRC: return graya_blender_src;
700 case BlendMode::MERGE: return graya_blender_merge;
701 case BlendMode::NEG_BW: return graya_blender_neg_bw;
702 case BlendMode::RED_TINT: return graya_blender_normal;
703 case BlendMode::BLUE_TINT: return graya_blender_normal;
704
705 case BlendMode::NORMAL: return graya_blender_normal;
706 case BlendMode::MULTIPLY: return graya_blender_multiply;
707 case BlendMode::SCREEN: return graya_blender_screen;
708 case BlendMode::OVERLAY: return graya_blender_overlay;
709 case BlendMode::DARKEN: return graya_blender_darken;
710 case BlendMode::LIGHTEN: return graya_blender_lighten;
711 case BlendMode::COLOR_DODGE: return graya_blender_color_dodge;
712 case BlendMode::COLOR_BURN: return graya_blender_color_burn;
713 case BlendMode::HARD_LIGHT: return graya_blender_hard_light;
714 case BlendMode::SOFT_LIGHT: return graya_blender_soft_light;
715 case BlendMode::DIFFERENCE: return graya_blender_difference;
716 case BlendMode::EXCLUSION: return graya_blender_exclusion;
717 case BlendMode::HSL_HUE: return graya_blender_normal;
718 case BlendMode::HSL_SATURATION: return graya_blender_normal;
719 case BlendMode::HSL_COLOR: return graya_blender_normal;
720 case BlendMode::HSL_LUMINOSITY: return graya_blender_normal;
721 case BlendMode::ADDITION: return graya_blender_addition;
722 case BlendMode::SUBTRACT: return graya_blender_subtract;
723 case BlendMode::DIVIDE: return graya_blender_divide;
724 }
725 ASSERT(false);
726 return graya_blender_src;
727 }
728
get_indexed_blender(BlendMode blendmode)729 BlendFunc get_indexed_blender(BlendMode blendmode)
730 {
731 return indexed_blender_src;
732 }
733
734 } // namespace doc
735