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