1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 *
19 * The Original Code is: some of this file.
20 *
21 * */
22
23 /** \file
24 * \ingroup bli
25 */
26
27 #include "BLI_math_base.h"
28 #include "BLI_math_color.h"
29 #include "BLI_math_color_blend.h"
30 #include "BLI_math_vector.h"
31 #include "BLI_utildefines.h"
32
33 #ifndef __MATH_COLOR_BLEND_INLINE_C__
34 # define __MATH_COLOR_BLEND_INLINE_C__
35
36 /* don't add any saturation to a completely black and white image */
37 # define EPS_SATURATION 0.0005f
38 # define EPS_ALPHA 0.0005f
39
40 /***************************** Color Blending ********************************
41 *
42 * - byte colors are assumed to be straight alpha
43 * - byte colors uses to do >>8 (same as /256) but actually should do /255,
44 * otherwise get quick darkening due to rounding
45 * - divide_round_i is also used to avoid darkening due to integers always
46 * rounding down
47 * - float colors are assumed to be premultiplied alpha
48 */
49
50 /* straight alpha byte blending modes */
51
blend_color_mix_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])52 MINLINE void blend_color_mix_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
53 {
54 if (src2[3] != 0) {
55 /* straight over operation */
56 const int t = src2[3];
57 const int mt = 255 - t;
58 int tmp[4];
59
60 tmp[0] = (mt * src1[3] * src1[0]) + (t * 255 * src2[0]);
61 tmp[1] = (mt * src1[3] * src1[1]) + (t * 255 * src2[1]);
62 tmp[2] = (mt * src1[3] * src1[2]) + (t * 255 * src2[2]);
63 tmp[3] = (mt * src1[3]) + (t * 255);
64
65 dst[0] = (uchar)divide_round_i(tmp[0], tmp[3]);
66 dst[1] = (uchar)divide_round_i(tmp[1], tmp[3]);
67 dst[2] = (uchar)divide_round_i(tmp[2], tmp[3]);
68 dst[3] = (uchar)divide_round_i(tmp[3], 255);
69 }
70 else {
71 /* no op */
72 copy_v4_v4_uchar(dst, src1);
73 }
74 }
75
blend_color_add_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])76 MINLINE void blend_color_add_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
77 {
78 if (src2[3] != 0) {
79 /* straight add operation */
80 const int t = src2[3];
81 int tmp[3];
82
83 tmp[0] = (src1[0] * 255) + (src2[0] * t);
84 tmp[1] = (src1[1] * 255) + (src2[1] * t);
85 tmp[2] = (src1[2] * 255) + (src2[2] * t);
86
87 dst[0] = (uchar)min_ii(divide_round_i(tmp[0], 255), 255);
88 dst[1] = (uchar)min_ii(divide_round_i(tmp[1], 255), 255);
89 dst[2] = (uchar)min_ii(divide_round_i(tmp[2], 255), 255);
90 dst[3] = src1[3];
91 }
92 else {
93 /* no op */
94 copy_v4_v4_uchar(dst, src1);
95 }
96 }
97
blend_color_sub_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])98 MINLINE void blend_color_sub_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
99 {
100 if (src2[3] != 0) {
101 /* straight sub operation */
102 const int t = src2[3];
103 int tmp[3];
104
105 tmp[0] = (src1[0] * 255) - (src2[0] * t);
106 tmp[1] = (src1[1] * 255) - (src2[1] * t);
107 tmp[2] = (src1[2] * 255) - (src2[2] * t);
108
109 dst[0] = (uchar)max_ii(divide_round_i(tmp[0], 255), 0);
110 dst[1] = (uchar)max_ii(divide_round_i(tmp[1], 255), 0);
111 dst[2] = (uchar)max_ii(divide_round_i(tmp[2], 255), 0);
112 dst[3] = src1[3];
113 }
114 else {
115 /* no op */
116 copy_v4_v4_uchar(dst, src1);
117 }
118 }
119
blend_color_mul_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])120 MINLINE void blend_color_mul_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
121 {
122 if (src2[3] != 0) {
123 /* straight multiply operation */
124 const int t = src2[3];
125 const int mt = 255 - t;
126 int tmp[3];
127
128 tmp[0] = (mt * src1[0] * 255) + (t * src1[0] * src2[0]);
129 tmp[1] = (mt * src1[1] * 255) + (t * src1[1] * src2[1]);
130 tmp[2] = (mt * src1[2] * 255) + (t * src1[2] * src2[2]);
131
132 dst[0] = (uchar)divide_round_i(tmp[0], 255 * 255);
133 dst[1] = (uchar)divide_round_i(tmp[1], 255 * 255);
134 dst[2] = (uchar)divide_round_i(tmp[2], 255 * 255);
135 dst[3] = src1[3];
136 }
137 else {
138 /* no op */
139 copy_v4_v4_uchar(dst, src1);
140 }
141 }
142
blend_color_lighten_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])143 MINLINE void blend_color_lighten_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
144 {
145 if (src2[3] != 0) {
146 /* straight lighten operation */
147 const int t = src2[3];
148 const int mt = 255 - t;
149 int tmp[3];
150
151 tmp[0] = (mt * src1[0]) + (t * max_ii(src1[0], src2[0]));
152 tmp[1] = (mt * src1[1]) + (t * max_ii(src1[1], src2[1]));
153 tmp[2] = (mt * src1[2]) + (t * max_ii(src1[2], src2[2]));
154
155 dst[0] = (uchar)divide_round_i(tmp[0], 255);
156 dst[1] = (uchar)divide_round_i(tmp[1], 255);
157 dst[2] = (uchar)divide_round_i(tmp[2], 255);
158 dst[3] = src1[3];
159 }
160 else {
161 /* no op */
162 copy_v4_v4_uchar(dst, src1);
163 }
164 }
165
blend_color_darken_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])166 MINLINE void blend_color_darken_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
167 {
168 if (src2[3] != 0) {
169 /* straight darken operation */
170 const int t = src2[3];
171 const int mt = 255 - t;
172 int tmp[3];
173
174 tmp[0] = (mt * src1[0]) + (t * min_ii(src1[0], src2[0]));
175 tmp[1] = (mt * src1[1]) + (t * min_ii(src1[1], src2[1]));
176 tmp[2] = (mt * src1[2]) + (t * min_ii(src1[2], src2[2]));
177
178 dst[0] = (uchar)divide_round_i(tmp[0], 255);
179 dst[1] = (uchar)divide_round_i(tmp[1], 255);
180 dst[2] = (uchar)divide_round_i(tmp[2], 255);
181 dst[3] = src1[3];
182 }
183 else {
184 /* no op */
185 copy_v4_v4_uchar(dst, src1);
186 }
187 }
188
blend_color_erase_alpha_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])189 MINLINE void blend_color_erase_alpha_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
190 {
191 if (src2[3] != 0) {
192 /* straight so just modify alpha channel */
193 const int t = src2[3];
194
195 dst[0] = src1[0];
196 dst[1] = src1[1];
197 dst[2] = src1[2];
198 dst[3] = (uchar)max_ii(src1[3] - divide_round_i(t * src2[3], 255), 0);
199 }
200 else {
201 /* no op */
202 copy_v4_v4_uchar(dst, src1);
203 }
204 }
205
blend_color_add_alpha_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])206 MINLINE void blend_color_add_alpha_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
207 {
208 if (src2[3] != 0) {
209 /* straight so just modify alpha channel */
210 const int t = src2[3];
211
212 dst[0] = src1[0];
213 dst[1] = src1[1];
214 dst[2] = src1[2];
215 dst[3] = (uchar)min_ii(src1[3] + divide_round_i(t * src2[3], 255), 255);
216 }
217 else {
218 /* no op */
219 copy_v4_v4_uchar(dst, src1);
220 }
221 }
222
blend_color_overlay_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])223 MINLINE void blend_color_overlay_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
224 {
225 const int fac = (int)src2[3];
226 if (fac != 0) {
227 const int mfac = 255 - fac;
228 int i = 3;
229
230 while (i--) {
231 int temp;
232
233 if (src1[i] > 127) {
234 temp = 255 - ((255 - 2 * (src1[i] - 127)) * (255 - src2[i]) / 255);
235 }
236 else {
237 temp = (2 * src1[i] * src2[i]) >> 8;
238 }
239 dst[i] = (uchar)min_ii((temp * fac + src1[i] * mfac) / 255, 255);
240 }
241 }
242 else {
243 /* no op */
244 copy_v4_v4_uchar(dst, src1);
245 }
246 }
247
blend_color_hardlight_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])248 MINLINE void blend_color_hardlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
249 {
250 const int fac = (int)src2[3];
251 if (fac != 0) {
252 const int mfac = 255 - fac;
253 int i = 3;
254
255 while (i--) {
256 int temp;
257
258 if (src2[i] > 127) {
259 temp = 255 - ((255 - 2 * (src2[i] - 127)) * (255 - src1[i]) / 255);
260 }
261 else {
262 temp = (2 * src2[i] * src1[i]) >> 8;
263 }
264 dst[i] = (uchar)min_ii((temp * fac + src1[i] * mfac) / 255, 255);
265 }
266 }
267 else {
268 /* no op */
269 copy_v4_v4_uchar(dst, src1);
270 }
271 }
272
blend_color_burn_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])273 MINLINE void blend_color_burn_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
274 {
275 const int fac = src2[3];
276 if (fac != 0) {
277 const int mfac = 255 - fac;
278 int i = 3;
279
280 while (i--) {
281 const int temp = (src2[i] == 0) ? 0 : max_ii(255 - ((255 - src1[i]) * 255) / src2[i], 0);
282 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
283 }
284 }
285 else {
286 /* no op */
287 copy_v4_v4_uchar(dst, src1);
288 }
289 }
290
blend_color_linearburn_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])291 MINLINE void blend_color_linearburn_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
292 {
293 const int fac = src2[3];
294 if (fac != 0) {
295 const int mfac = 255 - fac;
296 int i = 3;
297
298 while (i--) {
299 const int temp = max_ii(src1[i] + src2[i] - 255, 0);
300 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
301 }
302 }
303 else {
304 /* no op */
305 copy_v4_v4_uchar(dst, src1);
306 }
307 }
308
blend_color_dodge_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])309 MINLINE void blend_color_dodge_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
310 {
311 const int fac = src2[3];
312 if (fac != 0) {
313 const int mfac = 255 - fac;
314 int i = 3;
315
316 while (i--) {
317 const int temp = (src2[i] == 255) ? 255 : min_ii((src1[i] * 255) / (255 - src2[i]), 255);
318 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
319 }
320 }
321 else {
322 /* no op */
323 copy_v4_v4_uchar(dst, src1);
324 }
325 }
326
blend_color_screen_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])327 MINLINE void blend_color_screen_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
328 {
329 const int fac = src2[3];
330 if (fac != 0) {
331 const int mfac = 255 - fac;
332 int i = 3;
333
334 while (i--) {
335 const int temp = max_ii(255 - (((255 - src1[i]) * (255 - src2[i])) / 255), 0);
336 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
337 }
338 }
339 else {
340 /* no op */
341 copy_v4_v4_uchar(dst, src1);
342 }
343 }
344
blend_color_softlight_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])345 MINLINE void blend_color_softlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
346 {
347 const int fac = src2[3];
348 if (fac != 0) {
349 const int mfac = 255 - fac;
350 int i = 3;
351
352 while (i--) {
353 int temp;
354
355 if (src1[i] < 127) {
356 temp = ((2 * ((src2[i] / 2) + 64)) * src1[i]) / 255;
357 }
358 else {
359 temp = 255 - (2 * (255 - ((src2[i] / 2) + 64)) * (255 - src1[i]) / 255);
360 }
361 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
362 }
363 }
364 else {
365 /* no op */
366 copy_v4_v4_uchar(dst, src1);
367 }
368 }
369
blend_color_pinlight_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])370 MINLINE void blend_color_pinlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
371 {
372 const int fac = src2[3];
373 if (fac != 0) {
374 const int mfac = 255 - fac;
375 int i = 3;
376
377 while (i--) {
378 int temp;
379
380 if (src2[i] > 127) {
381 temp = max_ii(2 * (src2[i] - 127), src1[i]);
382 }
383 else {
384 temp = min_ii(2 * src2[i], src1[i]);
385 }
386 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
387 }
388 }
389 else {
390 /* no op */
391 copy_v4_v4_uchar(dst, src1);
392 }
393 }
394
blend_color_linearlight_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])395 MINLINE void blend_color_linearlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
396 {
397 const int fac = src2[3];
398 if (fac != 0) {
399 const int mfac = 255 - fac;
400 int i = 3;
401
402 while (i--) {
403 int temp;
404
405 if (src2[i] > 127) {
406 temp = min_ii(src1[i] + 2 * (src2[i] - 127), 255);
407 }
408 else {
409 temp = max_ii(src1[i] + 2 * src2[i] - 255, 0);
410 }
411 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
412 }
413 }
414 else {
415 /* no op */
416 copy_v4_v4_uchar(dst, src1);
417 }
418 }
419
blend_color_vividlight_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])420 MINLINE void blend_color_vividlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
421 {
422 const int fac = src2[3];
423 if (fac != 0) {
424 const int mfac = 255 - fac;
425 int i = 3;
426
427 while (i--) {
428 int temp;
429
430 if (src2[i] == 255) {
431 temp = (src1[i] == 0) ? 127 : 255;
432 }
433 else if (src2[i] == 0) {
434 temp = (src1[i] == 255) ? 127 : 0;
435 }
436 else if (src2[i] > 127) {
437 temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255);
438 }
439 else {
440 temp = max_ii(255 - ((255 - src1[i]) * 255 / (2 * src2[i])), 0);
441 }
442 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
443 }
444 }
445 else {
446 /* no op */
447 copy_v4_v4_uchar(dst, src1);
448 }
449 }
450
blend_color_difference_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])451 MINLINE void blend_color_difference_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
452 {
453 const int fac = src2[3];
454 if (fac != 0) {
455 const int mfac = 255 - fac;
456 int i = 3;
457
458 while (i--) {
459 const int temp = abs(src1[i] - src2[i]);
460 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
461 }
462 }
463 else {
464 /* no op */
465 copy_v4_v4_uchar(dst, src1);
466 }
467 }
468
blend_color_exclusion_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])469 MINLINE void blend_color_exclusion_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
470 {
471 const int fac = src2[3];
472 if (fac != 0) {
473 const int mfac = 255 - fac;
474 int i = 3;
475
476 while (i--) {
477 const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255);
478 dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
479 }
480 }
481 else {
482 /* no op */
483 copy_v4_v4_uchar(dst, src1);
484 }
485 }
486
blend_color_color_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])487 MINLINE void blend_color_color_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
488 {
489 const int fac = src2[3];
490 if (fac != 0) {
491 const int mfac = 255 - fac;
492 float h1, s1, v1;
493 float h2, s2, v2;
494 float r, g, b;
495 rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
496 rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
497
498 h1 = h2;
499 s1 = s2;
500
501 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
502
503 dst[0] = (uchar)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
504 dst[1] = (uchar)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
505 dst[2] = (uchar)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
506 }
507 else {
508 /* no op */
509 copy_v4_v4_uchar(dst, src1);
510 }
511 }
512
blend_color_hue_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])513 MINLINE void blend_color_hue_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
514 {
515 const int fac = src2[3];
516 if (fac != 0) {
517 const int mfac = 255 - fac;
518 float h1, s1, v1;
519 float h2, s2, v2;
520 float r, g, b;
521 rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
522 rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
523
524 h1 = h2;
525
526 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
527
528 dst[0] = (uchar)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
529 dst[1] = (uchar)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
530 dst[2] = (uchar)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
531 }
532 else {
533 /* no op */
534 copy_v4_v4_uchar(dst, src1);
535 }
536 }
537
blend_color_saturation_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])538 MINLINE void blend_color_saturation_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
539 {
540 const int fac = src2[3];
541 if (fac != 0) {
542 const int mfac = 255 - fac;
543 float h1, s1, v1;
544 float h2, s2, v2;
545 float r, g, b;
546 rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
547 rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
548
549 if (s1 > EPS_SATURATION) {
550 s1 = s2;
551 }
552
553 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
554
555 dst[0] = (uchar)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
556 dst[1] = (uchar)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
557 dst[2] = (uchar)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
558 }
559 else {
560 /* no op */
561 copy_v4_v4_uchar(dst, src1);
562 }
563 }
564
blend_color_luminosity_byte(uchar dst[4],const uchar src1[4],const uchar src2[4])565 MINLINE void blend_color_luminosity_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
566 {
567 const int fac = src2[3];
568 if (fac != 0) {
569 const int mfac = 255 - fac;
570 float h1, s1, v1;
571 float h2, s2, v2;
572 float r, g, b;
573 rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
574 rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
575
576 v1 = v2;
577
578 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
579
580 dst[0] = (uchar)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
581 dst[1] = (uchar)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
582 dst[2] = (uchar)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
583 }
584 else {
585 /* no op */
586 copy_v4_v4_uchar(dst, src1);
587 }
588 }
589
blend_color_interpolate_byte(uchar dst[4],const uchar src1[4],const uchar src2[4],float ft)590 MINLINE void blend_color_interpolate_byte(uchar dst[4],
591 const uchar src1[4],
592 const uchar src2[4],
593 float ft)
594 {
595 /* do color interpolation, but in premultiplied space so that RGB colors
596 * from zero alpha regions have no influence */
597 const int t = (int)(255 * ft);
598 const int mt = 255 - t;
599 int tmp = (mt * src1[3] + t * src2[3]);
600
601 if (tmp > 0) {
602 dst[0] = (uchar)divide_round_i(mt * src1[0] * src1[3] + t * src2[0] * src2[3], tmp);
603 dst[1] = (uchar)divide_round_i(mt * src1[1] * src1[3] + t * src2[1] * src2[3], tmp);
604 dst[2] = (uchar)divide_round_i(mt * src1[2] * src1[3] + t * src2[2] * src2[3], tmp);
605 dst[3] = (uchar)divide_round_i(tmp, 255);
606 }
607 else {
608 copy_v4_v4_uchar(dst, src1);
609 dst[3] = 0;
610 }
611 }
612
613 /* premultiplied alpha float blending modes */
614
blend_color_mix_float(float dst[4],const float src1[4],const float src2[4])615 MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
616 {
617 if (src2[3] != 0.0f) {
618 /* premul over operation */
619 const float t = src2[3];
620 const float mt = 1.0f - t;
621
622 dst[0] = mt * src1[0] + src2[0];
623 dst[1] = mt * src1[1] + src2[1];
624 dst[2] = mt * src1[2] + src2[2];
625 dst[3] = mt * src1[3] + t;
626 }
627 else {
628 /* no op */
629 copy_v4_v4(dst, src1);
630 }
631 }
632
blend_color_add_float(float dst[4],const float src1[4],const float src2[4])633 MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
634 {
635 if (src2[3] != 0.0f) {
636 /* unpremul > add > premul, simplified */
637 dst[0] = src1[0] + src2[0] * src1[3];
638 dst[1] = src1[1] + src2[1] * src1[3];
639 dst[2] = src1[2] + src2[2] * src1[3];
640 dst[3] = src1[3];
641 }
642 else {
643 /* no op */
644 copy_v4_v4(dst, src1);
645 }
646 }
647
blend_color_sub_float(float dst[4],const float src1[4],const float src2[4])648 MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
649 {
650 if (src2[3] != 0.0f) {
651 /* unpremul > subtract > premul, simplified */
652 dst[0] = max_ff(src1[0] - src2[0] * src1[3], 0.0f);
653 dst[1] = max_ff(src1[1] - src2[1] * src1[3], 0.0f);
654 dst[2] = max_ff(src1[2] - src2[2] * src1[3], 0.0f);
655 dst[3] = src1[3];
656 }
657 else {
658 /* no op */
659 copy_v4_v4(dst, src1);
660 }
661 }
662
blend_color_mul_float(float dst[4],const float src1[4],const float src2[4])663 MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
664 {
665 if (src2[3] != 0.0f) {
666 /* unpremul > multiply > premul, simplified */
667 const float t = src2[3];
668 const float mt = 1.0f - t;
669
670 dst[0] = mt * src1[0] + src1[0] * src2[0] * src1[3];
671 dst[1] = mt * src1[1] + src1[1] * src2[1] * src1[3];
672 dst[2] = mt * src1[2] + src1[2] * src2[2] * src1[3];
673 dst[3] = src1[3];
674 }
675 else {
676 /* no op */
677 copy_v4_v4(dst, src1);
678 }
679 }
680
blend_color_lighten_float(float dst[4],const float src1[4],const float src2[4])681 MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4])
682 {
683 if (src2[3] != 0.0f) {
684 /* remap src2 to have same alpha as src1 premultiplied, take maximum of
685 * src1 and src2, then blend it with src1 */
686 const float t = src2[3];
687 const float mt = 1.0f - t;
688 const float map_alpha = src1[3] / src2[3];
689
690 dst[0] = mt * src1[0] + t * max_ff(src1[0], src2[0] * map_alpha);
691 dst[1] = mt * src1[1] + t * max_ff(src1[1], src2[1] * map_alpha);
692 dst[2] = mt * src1[2] + t * max_ff(src1[2], src2[2] * map_alpha);
693 dst[3] = src1[3];
694 }
695 else {
696 /* no op */
697 copy_v4_v4(dst, src1);
698 }
699 }
700
blend_color_darken_float(float dst[4],const float src1[4],const float src2[4])701 MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4])
702 {
703 if (src2[3] != 0.0f) {
704 /* remap src2 to have same alpha as src1 premultiplied, take minimum of
705 * src1 and src2, then blend it with src1 */
706 const float t = src2[3];
707 const float mt = 1.0f - t;
708 const float map_alpha = src1[3] / src2[3];
709
710 dst[0] = mt * src1[0] + t * min_ff(src1[0], src2[0] * map_alpha);
711 dst[1] = mt * src1[1] + t * min_ff(src1[1], src2[1] * map_alpha);
712 dst[2] = mt * src1[2] + t * min_ff(src1[2], src2[2] * map_alpha);
713 dst[3] = src1[3];
714 }
715 else {
716 /* no op */
717 copy_v4_v4(dst, src1);
718 }
719 }
720
blend_color_erase_alpha_float(float dst[4],const float src1[4],const float src2[4])721 MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4])
722 {
723 if (src2[3] != 0.0f && src1[3] > 0.0f) {
724 /* subtract alpha and remap RGB channels to match */
725 float alpha = max_ff(src1[3] - src2[3], 0.0f);
726 float map_alpha;
727
728 if (alpha <= EPS_ALPHA) {
729 alpha = 0.0f;
730 }
731
732 map_alpha = alpha / src1[3];
733
734 dst[0] = src1[0] * map_alpha;
735 dst[1] = src1[1] * map_alpha;
736 dst[2] = src1[2] * map_alpha;
737 dst[3] = alpha;
738 }
739 else {
740 /* no op */
741 copy_v4_v4(dst, src1);
742 }
743 }
744
blend_color_add_alpha_float(float dst[4],const float src1[4],const float src2[4])745 MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4])
746 {
747 if (src2[3] != 0.0f && src1[3] < 1.0f) {
748 /* add alpha and remap RGB channels to match */
749 float alpha = min_ff(src1[3] + src2[3], 1.0f);
750 float map_alpha;
751
752 if (alpha >= 1.0f - EPS_ALPHA) {
753 alpha = 1.0f;
754 }
755
756 map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
757
758 dst[0] = src1[0] * map_alpha;
759 dst[1] = src1[1] * map_alpha;
760 dst[2] = src1[2] * map_alpha;
761 dst[3] = alpha;
762 }
763 else {
764 /* no op */
765 copy_v4_v4(dst, src1);
766 }
767 }
768
blend_color_overlay_float(float dst[4],const float src1[4],const float src2[4])769 MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4])
770 {
771 const float fac = src2[3];
772 if (fac != 0.0f) {
773 const float mfac = 1.0f - fac;
774 int i = 3;
775
776 while (i--) {
777 float temp;
778
779 if (src1[i] > 0.5f) {
780 temp = 1.0f - (1.0f - 2.0f * (src1[i] - 0.5f)) * (1.0f - src2[i]);
781 }
782 else {
783 temp = 2.0f * src1[i] * src2[i];
784 }
785 dst[i] = min_ff(temp * fac + src1[i] * mfac, 1.0f);
786 }
787 }
788 else {
789 /* no op */
790 copy_v4_v4(dst, src1);
791 }
792 }
793
blend_color_hardlight_float(float dst[4],const float src1[4],const float src2[4])794 MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4])
795 {
796 const float fac = src2[3];
797 if (fac != 0.0f) {
798 const float mfac = 1.0f - fac;
799 int i = 3;
800
801 while (i--) {
802 float temp;
803
804 if (src2[i] > 0.5f) {
805 temp = 1.0f - ((1.0f - 2.0f * (src2[i] - 0.5f)) * (1.0f - src1[i]));
806 }
807 else {
808 temp = 2.0f * src2[i] * src1[i];
809 }
810 dst[i] = min_ff((temp * fac + src1[i] * mfac) / 1.0f, 1.0f);
811 }
812 }
813 else {
814 /* no op */
815 copy_v4_v4(dst, src1);
816 }
817 }
818
blend_color_burn_float(float dst[4],const float src1[4],const float src2[4])819 MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4])
820 {
821 const float fac = src2[3];
822 if (fac != 0.0f) {
823 const float mfac = 1.0f - fac;
824 int i = 3;
825
826 while (i--) {
827 const float temp = (src2[i] == 0.0f) ? 0.0f :
828 max_ff(1.0f - ((1.0f - src1[i]) / src2[i]), 0.0f);
829 dst[i] = (temp * fac + src1[i] * mfac);
830 }
831 }
832 else {
833 /* no op */
834 copy_v4_v4(dst, src1);
835 }
836 }
837
blend_color_linearburn_float(float dst[4],const float src1[4],const float src2[4])838 MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4])
839 {
840 const float fac = src2[3];
841 if (fac != 0.0f) {
842 const float mfac = 1.0f - fac;
843 int i = 3;
844
845 while (i--) {
846 const float temp = max_ff(src1[i] + src2[i] - 1.0f, 0.0f);
847 dst[i] = (temp * fac + src1[i] * mfac);
848 }
849 }
850 else {
851 /* no op */
852 copy_v4_v4(dst, src1);
853 }
854 }
855
blend_color_dodge_float(float dst[4],const float src1[4],const float src2[4])856 MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4])
857 {
858 const float fac = src2[3];
859 if (fac != 0.0f) {
860 const float mfac = 1.0f - fac;
861 int i = 3;
862
863 while (i--) {
864 const float temp = (src2[i] >= 1.0f) ? 1.0f : min_ff(src1[i] / (1.0f - src2[i]), 1.0f);
865 dst[i] = (temp * fac + src1[i] * mfac);
866 }
867 }
868 else {
869 /* no op */
870 copy_v4_v4(dst, src1);
871 }
872 }
873
blend_color_screen_float(float dst[4],const float src1[4],const float src2[4])874 MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4])
875 {
876 const float fac = src2[3];
877 if (fac != 0.0f) {
878 const float mfac = 1.0f - fac;
879 int i = 3;
880
881 while (i--) {
882 const float temp = max_ff(1.0f - ((1.0f - src1[i]) * (1.0f - src2[i])), 0.0f);
883 dst[i] = (temp * fac + src1[i] * mfac);
884 }
885 }
886 else {
887 /* no op */
888 copy_v4_v4(dst, src1);
889 }
890 }
891
blend_color_softlight_float(float dst[4],const float src1[4],const float src2[4])892 MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4])
893 {
894 const float fac = src2[3];
895 if (fac != 0.0f) {
896 const float mfac = 1.0f - fac;
897 int i = 3;
898
899 while (i--) {
900 float temp;
901
902 if (src1[i] < 0.5f) {
903 temp = (src2[i] + 0.5f) * src1[i];
904 }
905 else {
906 temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i]));
907 }
908 dst[i] = (temp * fac + src1[i] * mfac);
909 }
910 }
911 else {
912 /* no op */
913 copy_v4_v4(dst, src1);
914 }
915 }
916
blend_color_pinlight_float(float dst[4],const float src1[4],const float src2[4])917 MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4])
918 {
919 const float fac = src2[3];
920 if (fac != 0.0f) {
921 const float mfac = 1.0f - fac;
922 int i = 3;
923
924 while (i--) {
925 float temp;
926
927 if (src2[i] > 0.5f) {
928 temp = max_ff(2.0f * (src2[i] - 0.5f), src1[i]);
929 }
930 else {
931 temp = min_ff(2.0f * src2[i], src1[i]);
932 }
933 dst[i] = (temp * fac + src1[i] * mfac);
934 }
935 }
936 else {
937 /* no op */
938 copy_v4_v4(dst, src1);
939 }
940 }
941
blend_color_linearlight_float(float dst[4],const float src1[4],const float src2[4])942 MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4])
943 {
944 const float fac = src2[3];
945 if (fac != 0.0f) {
946 const float mfac = 1.0f - fac;
947 int i = 3;
948
949 while (i--) {
950 float temp;
951
952 if (src2[i] > 0.5f) {
953 temp = min_ff(src1[i] + 2.0f * (src2[i] - 0.5f), 1.0f);
954 }
955 else {
956 temp = max_ff(src1[i] + 2.0f * src2[i] - 1.0f, 0.0f);
957 }
958 dst[i] = (temp * fac + src1[i] * mfac);
959 }
960 }
961 else {
962 /* no op */
963 copy_v4_v4(dst, src1);
964 }
965 }
966
blend_color_vividlight_float(float dst[4],const float src1[4],const float src2[4])967 MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4])
968 {
969 const float fac = src2[3];
970 if (fac != 0.0f) {
971 const float mfac = 1.0f - fac;
972 int i = 3;
973
974 while (i--) {
975 float temp;
976
977 if (src2[i] == 1.0f) {
978 temp = (src1[i] == 0.0f) ? 0.5f : 1.0f;
979 }
980 else if (src2[i] == 0.0f) {
981 temp = (src1[i] == 1.0f) ? 0.5f : 0.0f;
982 }
983 else if (src2[i] > 0.5f) {
984 temp = min_ff(((src1[i]) * 1.0f) / (2.0f * (1.0f - src2[i])), 1.0f);
985 }
986 else {
987 temp = max_ff(1.0f - ((1.0f - src1[i]) * 1.0f / (2.0f * src2[i])), 0.0f);
988 }
989 dst[i] = (temp * fac + src1[i] * mfac);
990 }
991 }
992 else {
993 /* no op */
994 copy_v4_v4(dst, src1);
995 }
996 }
997
blend_color_difference_float(float dst[4],const float src1[4],const float src2[4])998 MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4])
999 {
1000 const float fac = src2[3];
1001 if (fac != 0.0f) {
1002 const float mfac = 1.0f - fac;
1003 int i = 3;
1004
1005 while (i--) {
1006 dst[i] = (fabsf(src1[i] - src2[i]) * fac + src1[i] * mfac);
1007 }
1008 }
1009 else {
1010 /* no op */
1011 copy_v4_v4(dst, src1);
1012 }
1013 }
1014
blend_color_exclusion_float(float dst[4],const float src1[4],const float src2[4])1015 MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4])
1016 {
1017 const float fac = src2[3];
1018 if (fac != 0.0f) {
1019 const float mfac = 1.0f - fac;
1020 int i = 3;
1021
1022 while (i--) {
1023 const float temp = 0.5f - ((2 * (src1[i] - 0.5f) * (src2[i] - 0.5f)));
1024 dst[i] = (temp * fac + src1[i] * mfac);
1025 }
1026 }
1027 else {
1028 /* no op */
1029 copy_v4_v4(dst, src1);
1030 }
1031 }
1032
blend_color_color_float(float dst[4],const float src1[4],const float src2[4])1033 MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4])
1034 {
1035 const float fac = src2[3];
1036 if (fac != 0.0f) {
1037 const float mfac = 1.0f - fac;
1038 float h1, s1, v1;
1039 float h2, s2, v2;
1040 float r, g, b;
1041
1042 rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
1043 rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
1044
1045 h1 = h2;
1046 s1 = s2;
1047
1048 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
1049
1050 dst[0] = (r * fac + src1[0] * mfac);
1051 dst[1] = (g * fac + src1[1] * mfac);
1052 dst[2] = (b * fac + src1[2] * mfac);
1053 }
1054 else {
1055 /* no op */
1056 copy_v4_v4(dst, src1);
1057 }
1058 }
1059
blend_color_hue_float(float dst[4],const float src1[4],const float src2[4])1060 MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4])
1061 {
1062 const float fac = src2[3];
1063 if (fac != 0.0f) {
1064 const float mfac = 1.0f - fac;
1065 float h1, s1, v1;
1066 float h2, s2, v2;
1067 float r, g, b;
1068
1069 rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
1070 rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
1071
1072 h1 = h2;
1073
1074 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
1075
1076 dst[0] = (r * fac + src1[0] * mfac);
1077 dst[1] = (g * fac + src1[1] * mfac);
1078 dst[2] = (b * fac + src1[2] * mfac);
1079 }
1080 else {
1081 /* no op */
1082 copy_v4_v4(dst, src1);
1083 }
1084 }
1085
blend_color_saturation_float(float dst[4],const float src1[4],const float src2[4])1086 MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4])
1087 {
1088 const float fac = src2[3];
1089 if (fac != 0.0f) {
1090 const float mfac = 1.0f - fac;
1091 float h1, s1, v1;
1092 float h2, s2, v2;
1093 float r, g, b;
1094
1095 rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
1096 rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
1097
1098 if (s1 > EPS_SATURATION) {
1099 s1 = s2;
1100 }
1101 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
1102
1103 dst[0] = (r * fac + src1[0] * mfac);
1104 dst[1] = (g * fac + src1[1] * mfac);
1105 dst[2] = (b * fac + src1[2] * mfac);
1106 }
1107 else {
1108 /* no op */
1109 copy_v4_v4(dst, src1);
1110 }
1111 }
1112
blend_color_luminosity_float(float dst[4],const float src1[4],const float src2[4])1113 MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4])
1114 {
1115 const float fac = src2[3];
1116 if (fac != 0.0f) {
1117 const float mfac = 1.0f - fac;
1118 float h1, s1, v1;
1119 float h2, s2, v2;
1120 float r, g, b;
1121
1122 rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
1123 rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
1124
1125 v1 = v2;
1126 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
1127
1128 dst[0] = (r * fac + src1[0] * mfac);
1129 dst[1] = (g * fac + src1[1] * mfac);
1130 dst[2] = (b * fac + src1[2] * mfac);
1131 }
1132 else {
1133 /* no op */
1134 copy_v4_v4(dst, src1);
1135 }
1136 }
1137
blend_color_interpolate_float(float dst[4],const float src1[4],const float src2[4],float t)1138 MINLINE void blend_color_interpolate_float(float dst[4],
1139 const float src1[4],
1140 const float src2[4],
1141 float t)
1142 {
1143 /* interpolation, colors are premultiplied so it goes fine */
1144 const float mt = 1.0f - t;
1145
1146 dst[0] = mt * src1[0] + t * src2[0];
1147 dst[1] = mt * src1[1] + t * src2[1];
1148 dst[2] = mt * src1[2] + t * src2[2];
1149 dst[3] = mt * src1[3] + t * src2[3];
1150 }
1151
1152 # undef EPS_SATURATION
1153 # undef EPS_ALPHA
1154
1155 #endif /* __MATH_COLOR_BLEND_INLINE_C__ */
1156