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