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