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