Blender V4.3
BLI_color_mix.hh
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
11#include "BLI_color.hh"
12#include "BLI_math_base.h"
13#include "BLI_math_color.h"
14#include "BLI_sys_types.h"
15
17#include "IMB_imbuf.hh"
18
19#include <type_traits>
20
21namespace blender::color {
22
23struct ByteTraits {
25 using BlendType = int;
26
27 inline static const uchar range = 255; /* Zero-based maximum value. */
28 inline static const float frange = 255.0f; /* Convenient floating-point version of range. */
29 inline static const int cmpRange = 254;
30 inline static const int expandedRange = 256; /* One-based maximum value. */
31
32 inline static const int bytes = 1;
33 inline static const float unit = 255.0f;
34
36 {
37 return divide_round_i(a, b);
38 }
39
40 static inline BlendType min(BlendType a, BlendType b)
41 {
42 return min_ii(a, b);
43 }
44
45 static inline BlendType max(BlendType a, BlendType b)
46 {
47 return max_ii(a, b);
48 }
49 /* Discretizes in steps of 1.0 / range */
50 static inline ValueType round(float f)
51 {
52 return round_fl_to_uchar(f);
53 }
54};
55
59
60 inline const static float range = 1.0f;
61 inline const static float frange = 1.0f;
62 inline const static float cmpRange = 0.9999f;
63 inline static const int expandedRange = 1.0f;
64
65 inline const static float unit = 1.0f;
66 inline const static int bytes = 4;
67
69 {
70 return a / b;
71 }
72
73 static inline BlendType min(BlendType a, BlendType b)
74 {
75 return min_ff(a, b);
76 }
77
78 static inline BlendType max(BlendType a, BlendType b)
79 {
80 return max_ff(a, b);
81 }
82
83 /* Discretizes in steps of 1.0 / range */
84 static inline ValueType round(float f)
85 {
86 return f;
87 }
88};
89
90template<typename T> struct TraitsType {
91 using type = void;
92};
93template<> struct TraitsType<ColorPaint4f> {
95};
96template<> struct TraitsType<ColorPaint4b> {
98};
99template<typename T> using Traits = typename TraitsType<T>::type;
100
101static inline float get_luminance(ColorPaint4f c)
102{
104}
105
106static inline int get_luminance(ColorPaint4b c)
107{
109}
110
111#define EPS_SATURATION 0.0005f
112
113/* -------------------------------------------------------------------- */
117template<typename Color, typename Traits>
118static Color mix_blend(Color col_src, Color col_dst, typename Traits::BlendType fac)
119{
120 using Value = typename Traits::ValueType;
121 using Blend = typename Traits::BlendType;
122
123 Value *cp_src, *cp_dst, *cp_mix;
124 Color col_mix(0, 0, 0, 0);
125 Blend mfac;
126
127 if (fac == 0) {
128 return col_src;
129 }
130
131 if (fac >= Traits::range) {
132 return col_dst;
133 }
134
135 mfac = Traits::range - fac;
136
137 cp_src = &col_src.r;
138 cp_dst = &col_dst.r;
139 cp_mix = &col_mix.r;
140
141 /* Updated to use the rgb squared color model which blends nicer. */
142 Blend r1 = cp_src[0] * cp_src[0];
143 Blend g1 = cp_src[1] * cp_src[1];
144 Blend b1 = cp_src[2] * cp_src[2];
145 Blend a1 = cp_src[3] * cp_src[3];
146
147 Blend r2 = cp_dst[0] * cp_dst[0];
148 Blend g2 = cp_dst[1] * cp_dst[1];
149 Blend b2 = cp_dst[2] * cp_dst[2];
150 Blend a2 = cp_dst[3] * cp_dst[3];
151
152 cp_mix[0] = Traits::round(sqrtf(Traits::divide_round((mfac * r1 + fac * r2), Traits::range)));
153 cp_mix[1] = Traits::round(sqrtf(Traits::divide_round((mfac * g1 + fac * g2), Traits::range)));
154 cp_mix[2] = Traits::round(sqrtf(Traits::divide_round((mfac * b1 + fac * b2), Traits::range)));
155 cp_mix[3] = Traits::round(sqrtf(Traits::divide_round((mfac * a1 + fac * a2), Traits::range)));
156 return Color(col_mix[0], col_mix[1], col_mix[2], col_mix[3]);
157
158 return col_mix;
159}
160
161template<typename Color, typename Traits>
162static Color mix_add(Color col_src, Color col_dst, typename Traits::BlendType fac)
163{
164 using Value = typename Traits::ValueType;
165 using Blend = typename Traits::BlendType;
166
167 Value *cp_src, *cp_dst, *cp_mix;
168 Blend temp;
169 Color col_mix(0, 0, 0, 0);
170
171 if (fac == 0) {
172 return col_src;
173 }
174
175 cp_src = (Value *)&col_src.r;
176 cp_dst = (Value *)&col_dst.r;
177 cp_mix = (Value *)&col_mix.r;
178
179 temp = cp_src[0] + Traits::divide_round((fac * cp_dst[0]), Traits::range);
180 cp_mix[0] = (temp > Traits::cmpRange) ? Traits::range : temp;
181 temp = cp_src[1] + Traits::divide_round((fac * cp_dst[1]), Traits::range);
182 cp_mix[1] = (temp > Traits::cmpRange) ? Traits::range : temp;
183 temp = cp_src[2] + Traits::divide_round((fac * cp_dst[2]), Traits::range);
184 cp_mix[2] = (temp > Traits::cmpRange) ? Traits::range : temp;
185 temp = cp_src[3] + Traits::divide_round((fac * cp_dst[3]), Traits::range);
186 cp_mix[3] = (temp > Traits::cmpRange) ? Traits::range : temp;
187
188 return col_mix;
189}
190
191template<typename Color, typename Traits>
192static Color mix_sub(Color col_src, Color col_dst, typename Traits::BlendType fac)
193{
194 using Value = typename Traits::ValueType;
195 using Blend = typename Traits::BlendType;
196
197 Value *cp_src, *cp_dst, *cp_mix;
198 Blend temp;
199 Color col_mix(0, 0, 0, 0);
200
201 cp_src = (Value *)&col_src.r;
202 cp_dst = (Value *)&col_dst.r;
203 cp_mix = (Value *)&col_mix.r;
204
205 temp = cp_src[0] - Traits::divide_round((fac * cp_dst[0]), Traits::range);
206 cp_mix[0] = (temp < 0) ? 0 : temp;
207 temp = cp_src[1] - Traits::divide_round((fac * cp_dst[1]), Traits::range);
208 cp_mix[1] = (temp < 0) ? 0 : temp;
209 temp = cp_src[2] - Traits::divide_round((fac * cp_dst[2]), Traits::range);
210 cp_mix[2] = (temp < 0) ? 0 : temp;
211 temp = cp_src[3] - Traits::divide_round((fac * cp_dst[3]), Traits::range);
212 cp_mix[3] = (temp < 0) ? 0 : temp;
213
214 return col_mix;
215}
216
217template<typename Color, typename Traits>
218static Color mix_mul(Color col_src, Color col_dst, typename Traits::BlendType fac)
219{
220 using Value = typename Traits::ValueType;
221 using Blend = typename Traits::BlendType;
222
223 Value *cp_src, *cp_dst, *cp_mix;
224 Blend mfac;
225 Color col_mix(0, 0, 0, 0);
226
227 if (fac == 0) {
228 return col_src;
229 }
230
231 mfac = Traits::range - fac;
232
233 cp_src = (Value *)&col_src;
234 cp_dst = (Value *)&col_dst;
235 cp_mix = (Value *)&col_mix;
236
237 /* first mul, then blend the fac */
238 cp_mix[0] = Traits::divide_round(mfac * cp_src[0] * Traits::range + fac * cp_dst[0] * cp_src[0],
239 Traits::range * Traits::range);
240 cp_mix[1] = Traits::divide_round(mfac * cp_src[1] * Traits::range + fac * cp_dst[1] * cp_src[1],
241 Traits::range * Traits::range);
242 cp_mix[2] = Traits::divide_round(mfac * cp_src[2] * Traits::range + fac * cp_dst[2] * cp_src[2],
243 Traits::range * Traits::range);
244 cp_mix[3] = Traits::divide_round(mfac * cp_src[3] * Traits::range + fac * cp_dst[3] * cp_src[3],
245 Traits::range * Traits::range);
246
247 return col_mix;
248}
249
250template<typename Color, typename Traits>
251static Color mix_lighten(Color col_src, Color col_dst, typename Traits::BlendType fac)
252{
253 using Value = typename Traits::ValueType;
254 using Blend = typename Traits::BlendType;
255
256 Value *cp_src, *cp_dst, *cp_mix;
257 Blend mfac;
258 Color col_mix(0, 0, 0, 0);
259
260 if (fac == 0) {
261 return col_src;
262 }
263 if (fac >= Traits::range) {
264 return col_dst;
265 }
266
267 mfac = Traits::range - fac;
268
269 cp_src = (Value *)&col_src;
270 cp_dst = (Value *)&col_dst;
271 cp_mix = (Value *)&col_mix;
272
273 /* See if we're lighter, if so mix, else don't do anything.
274 * if the paint color is darker then the original, then ignore */
275 if (get_luminance(cp_src) > get_luminance(cp_dst)) {
276 return col_src;
277 }
278
279 cp_mix[0] = Traits::divide_round(mfac * cp_src[0] + fac * cp_dst[0], Traits::range);
280 cp_mix[1] = Traits::divide_round(mfac * cp_src[1] + fac * cp_dst[1], Traits::range);
281 cp_mix[2] = Traits::divide_round(mfac * cp_src[2] + fac * cp_dst[2], Traits::range);
282 cp_mix[3] = Traits::divide_round(mfac * cp_src[3] + fac * cp_dst[3], Traits::range);
283
284 return col_mix;
285}
286
287template<typename Color, typename Traits>
288static Color mix_darken(Color col_src, Color col_dst, typename Traits::BlendType fac)
289{
290 using Value = typename Traits::ValueType;
291 using Blend = typename Traits::BlendType;
292
293 Value *cp_src, *cp_dst, *cp_mix;
294 Blend mfac;
295 Color col_mix(0, 0, 0, 0);
296
297 if (fac == 0) {
298 return col_src;
299 }
300 if (fac >= Traits::range) {
301 return col_dst;
302 }
303
304 mfac = Traits::range - fac;
305
306 cp_src = (Value *)&col_src;
307 cp_dst = (Value *)&col_dst;
308 cp_mix = (Value *)&col_mix;
309
310 /* See if we're darker, if so mix, else don't do anything.
311 * if the paint color is brighter then the original, then ignore */
312 if (get_luminance(cp_src) < get_luminance(cp_dst)) {
313 return col_src;
314 }
315
316 cp_mix[0] = Traits::divide_round((mfac * cp_src[0] + fac * cp_dst[0]), Traits::range);
317 cp_mix[1] = Traits::divide_round((mfac * cp_src[1] + fac * cp_dst[1]), Traits::range);
318 cp_mix[2] = Traits::divide_round((mfac * cp_src[2] + fac * cp_dst[2]), Traits::range);
319 cp_mix[3] = Traits::divide_round((mfac * cp_src[3] + fac * cp_dst[3]), Traits::range);
320 return col_mix;
321}
322
323template<typename Color, typename Traits>
324static Color mix_colordodge(Color col_src, Color col_dst, typename Traits::BlendType fac)
325{
326 using Value = typename Traits::ValueType;
327 using Blend = typename Traits::BlendType;
328
329 Value *cp_src, *cp_dst, *cp_mix;
330 Blend mfac, temp;
331 Color col_mix(0, 0, 0, 0);
332
333 if (fac == 0) {
334 return col_src;
335 }
336
337 mfac = Traits::range - fac;
338
339 cp_src = (Value *)&col_src;
340 cp_dst = (Value *)&col_dst;
341 cp_mix = (Value *)&col_mix;
342
343 Blend dodgefac = (Blend)((float)Traits::range * 0.885f); /* ~225/255 */
344
345 temp = (cp_dst[0] == Traits::range) ?
346 Traits::range :
347 Traits::min((cp_src[0] * dodgefac) / (Traits::range - cp_dst[0]), Traits::range);
348 cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
349 temp = (cp_dst[1] == Traits::range) ?
350 Traits::range :
351 Traits::min((cp_src[1] * dodgefac) / (Traits::range - cp_dst[1]), Traits::range);
352 cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
353 temp = (cp_dst[2] == Traits::range) ?
354 Traits::range :
355 Traits::min((cp_src[2] * dodgefac) / (Traits::range - cp_dst[2]), Traits::range);
356 cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
357 temp = (cp_dst[3] == Traits::range) ?
358 Traits::range :
359 Traits::min((cp_src[3] * dodgefac) / (Traits::range - cp_dst[3]), Traits::range);
360 cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
361 return col_mix;
362}
363
364template<typename Color, typename Traits>
365static Color mix_difference(Color col_src, Color col_dst, typename Traits::BlendType fac)
366{
367 using Value = typename Traits::ValueType;
368 using Blend = typename Traits::BlendType;
369
370 Value *cp_src, *cp_dst, *cp_mix;
371 Blend mfac, temp;
372 Color col_mix(0, 0, 0, 0);
373
374 if (fac == 0) {
375 return col_src;
376 }
377
378 mfac = Traits::range - fac;
379
380 cp_src = (Value *)&col_src;
381 cp_dst = (Value *)&col_dst;
382 cp_mix = (Value *)&col_mix;
383
384 temp = abs(cp_src[0] - cp_dst[0]);
385 cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
386 temp = abs(cp_src[1] - cp_dst[1]);
387 cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
388 temp = abs(cp_src[2] - cp_dst[2]);
389 cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
390 temp = abs(cp_src[3] - cp_dst[3]);
391 cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
392 return col_mix;
393}
394
395template<typename Color, typename Traits>
396static Color mix_screen(Color col_src, Color col_dst, typename Traits::BlendType fac)
397{
398 using Value = typename Traits::ValueType;
399 using Blend = typename Traits::BlendType;
400
401 Value *cp_src, *cp_dst, *cp_mix;
402 Blend mfac, temp;
403 Color col_mix(0, 0, 0, 0);
404
405 if (fac == 0) {
406 return col_src;
407 }
408
409 mfac = Traits::range - fac;
410
411 cp_src = (Value *)&col_src;
412 cp_dst = (Value *)&col_dst;
413 cp_mix = (Value *)&col_mix;
414
415 temp = Traits::max(Traits::range - (((Traits::range - cp_src[0]) * (Traits::range - cp_dst[0])) /
416 Traits::range),
417 0);
418 cp_mix[0] = (mfac * cp_src[0] + temp * fac) / Traits::range;
419 temp = Traits::max(Traits::range - (((Traits::range - cp_src[1]) * (Traits::range - cp_dst[1])) /
420 Traits::range),
421 0);
422 cp_mix[1] = (mfac * cp_src[1] + temp * fac) / Traits::range;
423 temp = Traits::max(Traits::range - (((Traits::range - cp_src[2]) * (Traits::range - cp_dst[2])) /
424 Traits::range),
425 0);
426 cp_mix[2] = (mfac * cp_src[2] + temp * fac) / Traits::range;
427 temp = Traits::max(Traits::range - (((Traits::range - cp_src[3]) * (Traits::range - cp_dst[3])) /
428 Traits::range),
429 0);
430 cp_mix[3] = (mfac * cp_src[3] + temp * fac) / Traits::range;
431 return col_mix;
432}
433
434template<typename Color, typename Traits>
435static Color mix_hardlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
436{
437 using Value = typename Traits::ValueType;
438 using Blend = typename Traits::BlendType;
439
440 Value *cp_src, *cp_dst, *cp_mix;
441 Blend mfac, temp;
442 Color col_mix(0, 0, 0, 0);
443
444 if (fac == 0) {
445 return col_src;
446 }
447
448 mfac = Traits::range - fac;
449
450 cp_src = (Value *)&col_src;
451 cp_dst = (Value *)&col_dst;
452 cp_mix = (Value *)&col_mix;
453
454 int i = 0;
455
456 for (i = 0; i < 4; i++) {
457 if (cp_dst[i] > (Traits::range / 2)) {
458 temp = Traits::range - ((Traits::range - 2 * (cp_dst[i] - (Traits::range / 2))) *
459 (Traits::range - cp_src[i]) / Traits::range);
460 }
461 else {
462 temp = (2 * cp_dst[i] * cp_src[i]) / Traits::expandedRange;
463 }
464 cp_mix[i] = Traits::min((mfac * cp_src[i] + temp * fac) / Traits::range, Traits::range);
465 }
466 return col_mix;
467}
468
469template<typename Color, typename Traits>
470static Color mix_overlay(Color col_src, Color col_dst, typename Traits::BlendType fac)
471{
472 using Value = typename Traits::ValueType;
473 using Blend = typename Traits::BlendType;
474
475 Value *cp_src, *cp_dst, *cp_mix;
476 Blend mfac, temp;
477 Color col_mix(0, 0, 0, 0);
478
479 if (fac == 0) {
480 return col_src;
481 }
482
483 mfac = Traits::range - fac;
484
485 cp_src = (Value *)&col_src;
486 cp_dst = (Value *)&col_dst;
487 cp_mix = (Value *)&col_mix;
488
489 int i = 0;
490
491 for (i = 0; i < 4; i++) {
492 if (cp_src[i] > (Traits::range / 2)) {
493 temp = Traits::range - ((Traits::range - 2 * (cp_src[i] - (Traits::range / 2))) *
494 (Traits::range - cp_dst[i]) / Traits::range);
495 }
496 else {
497 temp = (2 * cp_dst[i] * cp_src[i]) / Traits::expandedRange;
498 }
499 cp_mix[i] = Traits::min((mfac * cp_src[i] + temp * fac) / Traits::range, Traits::range);
500 }
501 return col_mix;
502}
503
504template<typename Color, typename Traits>
505static Color mix_softlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
506{
507 using Value = typename Traits::ValueType;
508 using Blend = typename Traits::BlendType;
509
510 Value *cp_src, *cp_dst, *cp_mix;
511 Blend mfac, temp;
512 Color col_mix(0, 0, 0, 0);
513
514 if (fac == 0) {
515 return col_src;
516 }
517
518 mfac = Traits::range - fac;
519
520 cp_src = (Value *)&col_src;
521 cp_dst = (Value *)&col_dst;
522 cp_mix = (Value *)&col_mix;
523
524 /* Use divide_round so we don't alter original byte equations. */
525 const int add = Traits::divide_round(Traits::range, 4);
526
527 for (int i = 0; i < 4; i++) {
528 if (cp_src[i] < (Traits::range / 2)) {
529 temp = ((2 * ((cp_dst[i] / 2) + add)) * cp_src[i]) / Traits::range;
530 }
531 else {
532 temp = Traits::range - (2 * (Traits::range - ((cp_dst[i] / 2) + add)) *
533 (Traits::range - cp_src[i]) / Traits::range);
534 }
535 cp_mix[i] = (temp * fac + cp_src[i] * mfac) / Traits::range;
536 }
537 return col_mix;
538}
539
540template<typename Color, typename Traits>
541static Color mix_exclusion(Color col_src, Color col_dst, typename Traits::BlendType fac)
542{
543 using Value = typename Traits::ValueType;
544 using Blend = typename Traits::BlendType;
545
546 Value *cp_src, *cp_dst, *cp_mix;
547 Blend mfac, temp;
548 Color col_mix(0, 0, 0, 0);
549
550 if (fac == 0) {
551 return col_src;
552 }
553
554 mfac = Traits::range - fac;
555
556 cp_src = (Value *)&col_src;
557 cp_dst = (Value *)&col_dst;
558 cp_mix = (Value *)&col_mix;
559
560 int i = 0;
561
562 for (i = 0; i < 4; i++) {
563 temp = (Traits::range / 2) -
564 ((2 * (cp_src[i] - (Traits::range / 2)) * (cp_dst[i] - (Traits::range / 2))) /
565 Traits::range);
566 cp_mix[i] = (temp * fac + cp_src[i] * mfac) / Traits::range;
567 }
568 return col_mix;
569}
570
571template<typename Color, typename Traits>
572static Color mix_luminosity(Color col_src, Color col_dst, typename Traits::BlendType fac)
573{
574 using Value = typename Traits::ValueType;
575 using Blend = typename Traits::BlendType;
576
577 Value *cp_src, *cp_dst, *cp_mix;
578 Blend mfac;
579 Color col_mix(0, 0, 0, 0);
580
581 if (fac == 0) {
582 return col_src;
583 }
584
585 mfac = Traits::range - fac;
586
587 cp_src = (Value *)&col_src;
588 cp_dst = (Value *)&col_dst;
589 cp_mix = (Value *)&col_mix;
590
591 float h1, s1, v1;
592 float h2, s2, v2;
593 float r, g, b;
594 rgb_to_hsv(cp_src[0] / Traits::frange,
595 cp_src[1] / Traits::frange,
596 cp_src[2] / Traits::frange,
597 &h1,
598 &s1,
599 &v1);
600 rgb_to_hsv(cp_dst[0] / Traits::frange,
601 cp_dst[1] / Traits::frange,
602 cp_dst[2] / Traits::frange,
603 &h2,
604 &s2,
605 &v2);
606
607 v1 = v2;
608
609 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
610
611 cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
612 cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
613 cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
614 cp_mix[3] = ((Blend)(cp_dst[3]) * fac + mfac * cp_src[3]) / Traits::range;
615 return col_mix;
616}
617
618template<typename Color, typename Traits>
619static Color mix_saturation(Color col_src, Color col_dst, typename Traits::BlendType fac)
620{
621 using Value = typename Traits::ValueType;
622 using Blend = typename Traits::BlendType;
623
624 Value *cp_src, *cp_dst, *cp_mix;
625 Blend mfac;
626 Color col_mix(0, 0, 0, 0);
627
628 if (fac == 0) {
629 return col_src;
630 }
631
632 mfac = Traits::range - fac;
633
634 cp_src = (Value *)&col_src;
635 cp_dst = (Value *)&col_dst;
636 cp_mix = (Value *)&col_mix;
637
638 float h1, s1, v1;
639 float h2, s2, v2;
640 float r, g, b;
641 rgb_to_hsv(cp_src[0] / Traits::frange,
642 cp_src[1] / Traits::frange,
643 cp_src[2] / Traits::frange,
644 &h1,
645 &s1,
646 &v1);
647 rgb_to_hsv(cp_dst[0] / Traits::frange,
648 cp_dst[1] / Traits::frange,
649 cp_dst[2] / Traits::frange,
650 &h2,
651 &s2,
652 &v2);
653
654 if (s1 > EPS_SATURATION) {
655 s1 = s2;
656 }
657
658 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
659
660 cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
661 cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
662 cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
663 return col_mix;
664}
665
666template<typename Color, typename Traits>
667static Color mix_hue(Color col_src, Color col_dst, typename Traits::BlendType fac)
668{
669 using Value = typename Traits::ValueType;
670 using Blend = typename Traits::BlendType;
671
672 Value *cp_src, *cp_dst, *cp_mix;
673 Blend mfac;
674 Color col_mix(0, 0, 0, 0);
675
676 if (fac == 0) {
677 return col_src;
678 }
679
680 mfac = Traits::range - fac;
681
682 cp_src = (Value *)&col_src;
683 cp_dst = (Value *)&col_dst;
684 cp_mix = (Value *)&col_mix;
685
686 float h1, s1, v1;
687 float h2, s2, v2;
688 float r, g, b;
689 rgb_to_hsv(cp_src[0] / Traits::frange,
690 cp_src[1] / Traits::frange,
691 cp_src[2] / Traits::frange,
692 &h1,
693 &s1,
694 &v1);
695 rgb_to_hsv(cp_dst[0] / Traits::frange,
696 cp_dst[1] / Traits::frange,
697 cp_dst[2] / Traits::frange,
698 &h2,
699 &s2,
700 &v2);
701
702 h1 = h2;
703
704 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
705
706 cp_mix[0] = ((Blend)(r * Traits::frange) * fac + mfac * cp_src[0]) / Traits::range;
707 cp_mix[1] = ((Blend)(g * Traits::frange) * fac + mfac * cp_src[1]) / Traits::range;
708 cp_mix[2] = ((Blend)(b * Traits::frange) * fac + mfac * cp_src[2]) / Traits::range;
709 cp_mix[3] = ((Blend)(cp_dst[3]) * fac + mfac * cp_src[3]) / Traits::range;
710 return col_mix;
711}
712
713template<typename Color, typename Traits>
714static Color mix_alpha_add(Color col_src, typename Traits::BlendType fac)
715{
716 using Value = typename Traits::ValueType;
717 using Blend = typename Traits::BlendType;
718
719 Value *cp_src, *cp_mix;
720 Blend temp;
721 Color col_mix = col_src;
722
723 if (fac == 0) {
724 return col_src;
725 }
726
727 cp_src = (Value *)&col_src;
728 cp_mix = (Value *)&col_mix;
729
730 temp = cp_src[3] + fac;
731 cp_mix[3] = (temp > Traits::cmpRange) ? Traits::range : temp;
732
733 return col_mix;
734}
735
736template<typename Color, typename Traits>
737static Color mix_alpha_sub(Color col_src, typename Traits::BlendType fac)
738{
739 using Value = typename Traits::ValueType;
740 using Blend = typename Traits::BlendType;
741
742 Value *cp_src, *cp_mix;
743 Blend temp;
744 Color col_mix = col_src;
745
746 if (fac == 0) {
747 return col_src;
748 }
749
750 cp_src = (Value *)&col_src;
751 cp_mix = (Value *)&col_mix;
752
753 temp = cp_src[3] - fac;
754 cp_mix[3] = temp < 0 ? 0 : temp;
755
756 return col_mix;
757}
758
759template<typename Color, typename Traits>
760static Color mix_pinlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
761{
762 using Value = typename Traits::ValueType;
763 using Blend = typename Traits::BlendType;
764
765 Value *cp_src, *cp_dst, *cp_mix;
766 Blend mfac;
767 Color col_mix(0, 0, 0, 0);
768
769 if (fac == 0) {
770 return col_src;
771 }
772
773 mfac = Traits::range - fac;
774
775 cp_src = (Value *)&col_src;
776 cp_dst = (Value *)&col_dst;
777 cp_mix = (Value *)&col_mix;
778
779 const Blend cmp = Traits::range / 2;
780
781 int i = 3;
782 Blend temp;
783
784 while (i--) {
785 if (cp_dst[i] > cmp) {
786 temp = Traits::max(2 * (cp_dst[i] - cmp), cp_src[i]);
787 }
788 else {
789 temp = Traits::min(2 * cp_dst[i], cp_src[i]);
790 }
791 cp_mix[i] = (Value)((Traits::min(temp, Traits::range) * fac + cp_src[i] * mfac) /
792 Traits::range);
793 }
794
795 col_mix.a = col_src.a;
796 return col_mix;
797}
798
799template<typename Color, typename Traits>
800static Color mix_linearlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
801{
802 using Value = typename Traits::ValueType;
803 using Blend = typename Traits::BlendType;
804
805 Value *cp_src, *cp_dst, *cp_mix;
806 Blend mfac;
807 Color col_mix(0, 0, 0, 0);
808
809 if (fac == 0) {
810 return col_src;
811 }
812
813 mfac = Traits::range - fac;
814
815 cp_src = (Value *)&col_src;
816 cp_dst = (Value *)&col_dst;
817 cp_mix = (Value *)&col_mix;
818
819 const Blend cmp = Traits::range / 2;
820
821 int i = 3;
822 while (i--) {
823 Blend temp;
824
825 if (cp_dst[i] > cmp) {
826 temp = Traits::min(cp_src[i] + 2 * (cp_dst[i] - cmp), Traits::range);
827 }
828 else {
829 temp = Traits::max(cp_src[i] + 2 * cp_dst[i] - Traits::range, 0);
830 }
831
832 cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
833 }
834
835 col_mix.a = col_src.a;
836 return col_mix;
837}
838
839template<typename Color, typename Traits>
840static Color mix_vividlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
841{
842 using Value = typename Traits::ValueType;
843 using Blend = typename Traits::BlendType;
844
845 Value *cp_src, *cp_dst;
846 Blend mfac;
847 Color col_mix(0, 0, 0, 0);
848
849 if (fac == 0) {
850 return col_src;
851 }
852
853 mfac = Traits::range - fac;
854
855 cp_src = (Value *)&col_src;
856 cp_dst = (Value *)&col_dst;
857
858 const Blend cmp = Traits::range / 2;
859
860 int i = 3;
861
862 while (i--) {
863 Blend temp;
864
865 if (cp_dst[i] == Traits::range) {
866 temp = (cp_src[i] == 0) ? cmp : Traits::range;
867 }
868 else if (cp_dst[i] == 0) {
869 temp = (cp_src[i] == Traits::range) ? cmp : 0;
870 }
871 else if (cp_dst[i] > cmp) {
872 temp = Traits::min(((cp_src[i]) * Traits::range) / (2 * (Traits::range - cp_dst[i])),
873 Traits::range);
874 }
875 else {
876 temp = Traits::max(
877 Traits::range - ((Traits::range - cp_src[i]) * Traits::range / (2 * cp_dst[i])), 0);
878 }
879 col_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
880 }
881
882 col_mix.a = col_src.a;
883 return col_mix;
884}
885
886template<typename Color, typename Traits>
887static Color mix_color(Color col_src, Color col_dst, typename Traits::BlendType fac)
888{
889 using Value = typename Traits::ValueType;
890 using Blend = typename Traits::BlendType;
891
892 Value *cp_src, *cp_dst, *cp_mix;
893 Blend mfac;
894 Color col_mix(0, 0, 0, 0);
895
896 if (fac == 0) {
897 return col_src;
898 }
899
900 mfac = Traits::range - fac;
901
902 cp_src = (Value *)&col_src;
903 cp_dst = (Value *)&col_dst;
904 cp_mix = (Value *)&col_mix;
905
906 float h1, s1, v1;
907 float h2, s2, v2;
908 float r, g, b;
909
910 rgb_to_hsv(cp_src[0] / Traits::frange,
911 cp_src[1] / Traits::frange,
912 cp_src[2] / Traits::frange,
913 &h1,
914 &s1,
915 &v1);
916 rgb_to_hsv(cp_dst[0] / Traits::frange,
917 cp_dst[1] / Traits::frange,
918 cp_dst[2] / Traits::frange,
919 &h2,
920 &s2,
921 &v2);
922
923 h1 = h2;
924 s1 = s2;
925
926 hsv_to_rgb(h1, s1, v1, &r, &g, &b);
927
928 cp_mix[0] = (Value)(((Blend)(r * Traits::frange) * fac + cp_src[0] * mfac) / Traits::range);
929 cp_mix[1] = (Value)(((Blend)(g * Traits::frange) * fac + cp_src[1] * mfac) / Traits::range);
930 cp_mix[2] = (Value)(((Blend)(b * Traits::frange) * fac + cp_src[2] * mfac) / Traits::range);
931
932 col_mix.a = col_src.a;
933 return col_mix;
934}
935
936template<typename Color, typename Traits>
937static Color mix_colorburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
938{
939 using Value = typename Traits::ValueType;
940 using Blend = typename Traits::BlendType;
941
942 Value *cp_src, *cp_dst, *cp_mix;
943 Blend mfac;
944 Color col_mix(0, 0, 0, 0);
945
946 if (fac == 0) {
947 return col_src;
948 }
949
950 mfac = Traits::range - fac;
951
952 cp_src = (Value *)&col_src;
953 cp_dst = (Value *)&col_dst;
954 cp_mix = (Value *)&col_mix;
955
956 int i = 3;
957
958 while (i--) {
959 const Blend temp =
960 (cp_dst[i] == 0) ?
961 0 :
962 Traits::max(Traits::range - ((Traits::range - cp_src[i]) * Traits::range) / cp_dst[i],
963 0);
964 cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
965 }
966
967 col_mix.a = col_src.a;
968 return col_mix;
969}
970
971template<typename Color, typename Traits>
972static Color mix_linearburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
973{
974 using Value = typename Traits::ValueType;
975 using Blend = typename Traits::BlendType;
976
977 Value *cp_src, *cp_dst, *cp_mix;
978 Blend mfac;
979 Color col_mix(0, 0, 0, 0);
980
981 if (fac == 0) {
982 return col_src;
983 }
984
985 mfac = Traits::range - fac;
986
987 cp_src = (Value *)&col_src;
988 cp_dst = (Value *)&col_dst;
989 cp_mix = (Value *)&col_mix;
990
991 int i = 3;
992
993 while (i--) {
994 const Blend temp = Traits::max(cp_src[i] + cp_dst[i] - Traits::range, 0);
995 cp_mix[i] = (Value)((temp * fac + cp_src[i] * mfac) / Traits::range);
996 }
997
998 col_mix.a = col_src.a;
999 return col_mix;
1000}
1001
1002template<typename Color, typename Traits>
1004 const Color a,
1005 const Color b,
1006 const typename Traits::BlendType alpha)
1007{
1008 switch ((IMB_BlendMode)tool) {
1009 case IMB_BLEND_MIX:
1010 return mix_blend<Color, Traits>(a, b, alpha);
1011 case IMB_BLEND_ADD:
1012 return mix_add<Color, Traits>(a, b, alpha);
1013 case IMB_BLEND_SUB:
1014 return mix_sub<Color, Traits>(a, b, alpha);
1015 case IMB_BLEND_MUL:
1016 return mix_mul<Color, Traits>(a, b, alpha);
1017 case IMB_BLEND_LIGHTEN:
1018 return mix_lighten<Color, Traits>(a, b, alpha);
1019 case IMB_BLEND_DARKEN:
1020 return mix_darken<Color, Traits>(a, b, alpha);
1022 return mix_colordodge<Color, Traits>(a, b, alpha);
1024 return mix_colorburn<Color, Traits>(a, b, alpha);
1026 return mix_difference<Color, Traits>(a, b, alpha);
1027 case IMB_BLEND_SCREEN:
1028 return mix_screen<Color, Traits>(a, b, alpha);
1030 return mix_hardlight<Color, Traits>(a, b, alpha);
1031 case IMB_BLEND_OVERLAY:
1032 return mix_overlay<Color, Traits>(a, b, alpha);
1034 return mix_softlight<Color, Traits>(a, b, alpha);
1036 return mix_exclusion<Color, Traits>(a, b, alpha);
1038 return mix_luminosity<Color, Traits>(a, b, alpha);
1040 return mix_saturation<Color, Traits>(a, b, alpha);
1041 case IMB_BLEND_HUE:
1042 return mix_hue<Color, Traits>(a, b, alpha);
1043 /* non-color */
1045 return mix_alpha_sub<Color, Traits>(a, alpha);
1047 return mix_alpha_add<Color, Traits>(a, alpha);
1048 case IMB_BLEND_PINLIGHT:
1049 return mix_pinlight<Color, Traits>(a, b, alpha);
1051 return mix_linearlight<Color, Traits>(a, b, alpha);
1053 return mix_vividlight<Color, Traits>(a, b, alpha);
1054 case IMB_BLEND_COLOR:
1055 return mix_color<Color, Traits>(a, b, alpha);
1056 default:
1058 return Color(0, 0, 0, 0);
1059 }
1060}
1063} // namespace blender::color
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define EPS_SATURATION
#define BLI_INLINE
MINLINE unsigned char round_fl_to_uchar(float a)
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
unsigned char uchar
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3])
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
IMB_BlendMode
Definition IMB_imbuf.hh:186
@ IMB_BLEND_EXCLUSION
Definition IMB_imbuf.hh:206
@ IMB_BLEND_DIFFERENCE
Definition IMB_imbuf.hh:205
@ IMB_BLEND_HARDLIGHT
Definition IMB_imbuf.hh:196
@ IMB_BLEND_COLORBURN
Definition IMB_imbuf.hh:197
@ IMB_BLEND_COLORDODGE
Definition IMB_imbuf.hh:199
@ IMB_BLEND_ERASE_ALPHA
Definition IMB_imbuf.hh:193
@ IMB_BLEND_SCREEN
Definition IMB_imbuf.hh:200
@ IMB_BLEND_HUE
Definition IMB_imbuf.hh:207
@ IMB_BLEND_MUL
Definition IMB_imbuf.hh:190
@ IMB_BLEND_ADD_ALPHA
Definition IMB_imbuf.hh:194
@ IMB_BLEND_DARKEN
Definition IMB_imbuf.hh:192
@ IMB_BLEND_OVERLAY
Definition IMB_imbuf.hh:195
@ IMB_BLEND_SATURATION
Definition IMB_imbuf.hh:208
@ IMB_BLEND_VIVIDLIGHT
Definition IMB_imbuf.hh:203
@ IMB_BLEND_LUMINOSITY
Definition IMB_imbuf.hh:209
@ IMB_BLEND_LIGHTEN
Definition IMB_imbuf.hh:191
@ IMB_BLEND_SOFTLIGHT
Definition IMB_imbuf.hh:201
@ IMB_BLEND_COLOR
Definition IMB_imbuf.hh:210
@ IMB_BLEND_LINEARLIGHT
Definition IMB_imbuf.hh:204
@ IMB_BLEND_PINLIGHT
Definition IMB_imbuf.hh:202
@ IMB_BLEND_MIX
Definition IMB_imbuf.hh:187
@ IMB_BLEND_ADD
Definition IMB_imbuf.hh:188
@ IMB_BLEND_SUB
Definition IMB_imbuf.hh:189
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Color
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue Hue Saturation Value
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ChannelStorageType r
Definition BLI_color.hh:88
local_group_size(16, 16) .push_constant(Type b
#define sqrtf(x)
draw_view in_light_buf[] float
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
static Color mix_pinlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_difference(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_alpha_sub(Color col_src, typename Traits::BlendType fac)
static float get_luminance(ColorPaint4f c)
static Color mix_screen(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_alpha_add(Color col_src, typename Traits::BlendType fac)
static Color mix_colorburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_colordodge(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_hardlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_vividlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_linearburn(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_sub(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_luminosity(Color col_src, Color col_dst, typename Traits::BlendType fac)
BLI_INLINE Color BLI_mix_colors(const IMB_BlendMode tool, const Color a, const Color b, const typename Traits::BlendType alpha)
static Color mix_softlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_color(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_overlay(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_mul(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_add(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_lighten(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_darken(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_linearlight(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_hue(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_blend(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_saturation(Color col_src, Color col_dst, typename Traits::BlendType fac)
static Color mix_exclusion(Color col_src, Color col_dst, typename Traits::BlendType fac)
Traits are traits classes to determine the type of a derivative of another type.
Definition traits.h:41
static const float frange
static BlendType max(BlendType a, BlendType b)
static const int expandedRange
static BlendType min(BlendType a, BlendType b)
static ValueType round(float f)
static BlendType divide_round(BlendType a, BlendType b)
static const float frange
static ValueType round(float f)
static const float cmpRange
static BlendType min(BlendType a, BlendType b)
static const int expandedRange
static BlendType max(BlendType a, BlendType b)
static BlendType divide_round(BlendType a, BlendType b)
ccl_device_inline int abs(int x)
Definition util/math.h:120