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