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