Material Definition Language API nvidia_logo_transpbg.gif Up
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
color.h
Go to the documentation of this file.
1 /***************************************************************************************************
2  * Copyright 2020 NVIDIA Corporation. All rights reserved.
3  **************************************************************************************************/
8 
9 #ifndef MI_MATH_COLOR_H
10 #define MI_MATH_COLOR_H
11 
12 #include <mi/base/types.h>
13 #include <mi/math/assert.h>
14 #include <mi/math/function.h>
15 #include <mi/math/vector.h>
16 
17 namespace mi {
18 
19 namespace math {
20 
32 // Color and Spectrum can be converted into each other. To avoid cyclic dependencies among the
33 // headers, the Spectrum_struct class is already defined here.
34 
35 //------- POD struct that provides storage for spectrum elements --------
36 
47 {
49  Float32 c[3];
50 };
51 
52 //------ Color Class ---------------------------------------------------------
53 
57 enum Clip_mode {
61 };
62 
80 class Color : public Color_struct //-V690 PVS
81 {
82 public:
85  typedef Float32 value_type;
86  typedef Size size_type;
88  typedef Float32 * pointer;
89  typedef const Float32 * const_pointer;
90  typedef Float32 & reference;
91  typedef const Float32 & const_reference;
92 
93  static const Size SIZE = 4;
94 
96  static inline Size size() { return SIZE; }
97 
99  static inline Size max_size() { return SIZE; }
100 
102  inline Float32* begin() { return &r; }
103 
105  inline const Float32* begin() const { return &r; }
106 
110  inline Float32* end() { return begin() + SIZE; }
111 
115  inline const Float32* end() const { return begin() + SIZE; }
116 
118  inline Color()
119  {
120 #if defined(DEBUG) || (defined(_MSC_VER) && _MSC_VER <= 1310)
121  // In debug mode, default-constructed colors are initialized with signaling NaNs or, if not
122  // applicable, with a maximum value to increase the chances of diagnosing incorrect use of
123  // an uninitialized color.
124  //
125  // When compiling with Visual C++ 7.1 or earlier, this code is enabled in all variants to
126  // work around a very obscure compiler bug that causes the compiler to crash.
127  typedef mi::base::numeric_traits<Float32> Traits;
128  Float32 v = (Traits::has_signaling_NaN)
129  ? Traits::signaling_NaN() : Traits::max MI_PREVENT_MACRO_EXPAND ();
130  r = v;
131  g = v;
132  b = v;
133  a = v;
134 #endif
135  }
136 
138  inline Color( const Color_struct& c)
139  {
140  r = c.r;
141  g = c.g;
142  b = c.b;
143  a = c.a;
144  }
145 
146 
148  inline explicit Color( const Float32 s)
149  {
150  r = s;
151  g = s;
152  b = s;
153  a = s;
154  }
155 
157  inline Color( Float32 nr, Float32 ng, Float32 nb, Float32 na = 1.0)
158  {
159  r = nr;
160  g = ng;
161  b = nb;
162  a = na;
163  }
164 
176  template <typename T>
177  inline explicit Color( T array[4])
178  {
179  r = array[0];
180  g = array[1];
181  b = array[2];
182  a = array[3];
183  }
184 
187  inline explicit Color( const Vector<Float32,4>& v)
188  {
189  r = v.x;
190  g = v.y;
191  b = v.z;
192  a = v.w;
193  }
194 
196  inline explicit Color( const Spectrum_struct& s)
197  {
198  r = s.c[0];
199  g = s.c[1];
200  b = s.c[2];
201  a = 1.0f;
202  }
203 
205  inline Color& operator=( const Color& c)
206  {
207  Color_struct::operator=( c);
208  return *this;
209  }
210 
213  inline Color& operator=( const Vector<Float32,4>& v)
214  {
215  r = v.x;
216  g = v.y;
217  b = v.z;
218  a = v.w;
219  return *this;
220  }
221 
223  inline const Float32& operator[]( Size i) const
224  {
225  mi_math_assert_msg( i < 4, "precondition");
226  return (&r)[i];
227  }
228 
230  inline Float32& operator[]( Size i)
231  {
232  mi_math_assert_msg( i < 4, "precondition");
233  return (&r)[i];
234  }
235 
236 
238  inline Float32 get( Size i) const
239  {
240  mi_math_assert_msg( i < 4, "precondition");
241  return (&r)[i];
242  }
243 
245  inline void set( Size i, Float32 value)
246  {
247  mi_math_assert_msg( i < 4, "precondition");
248  (&r)[i] = value;
249  }
250 
252  inline bool is_black() const
253  {
254  return (r == 0.0f) && (g == 0.0f) && (b == 0.0f);
255  }
256 
258  inline Float32 linear_intensity() const
259  {
260  return (r + g + b) * Float32(1.0 / 3.0);
261  }
262 
267  inline Float32 ntsc_intensity() const
268  {
269  return r * 0.299f + g * 0.587f + b * 0.114f;
270  }
271 
276  inline Float32 cie_intensity() const
277  {
278  return r * 0.212671f + g * 0.715160f + b * 0.072169f;
279  }
280 
285  inline Color clip( Clip_mode mode = CLIP_RGB, bool desaturate = false) const;
286 
287 
297  inline Color desaturate( Float32 maxval = 1.0f) const;
298 };
299 
300 //------ Free comparison operators ==, !=, <, <=, >, >= for colors ------------
301 
303 inline bool operator==( const Color& lhs, const Color& rhs)
304 {
305  return is_equal( lhs, rhs);
306 }
307 
309 inline bool operator!=( const Color& lhs, const Color& rhs)
310 {
311  return is_not_equal( lhs, rhs);
312 }
313 
317 inline bool operator<( const Color& lhs, const Color& rhs)
318 {
319  return lexicographically_less( lhs, rhs);
320 }
321 
325 inline bool operator<=( const Color& lhs, const Color& rhs)
326 {
327  return lexicographically_less_or_equal( lhs, rhs);
328 }
329 
333 inline bool operator>( const Color& lhs, const Color& rhs)
334 {
335  return lexicographically_greater( lhs, rhs);
336 }
337 
341 inline bool operator>=( const Color& lhs, const Color& rhs)
342 {
343  return lexicographically_greater_or_equal( lhs, rhs);
344 }
345 
346 
347 
348 //------ Free operators +=, -=, *=, /=, +, -, *, and / for colors --------------
349 
351 inline Color& operator+=( Color& lhs, const Color& rhs)
352 {
353  lhs.r += rhs.r;
354  lhs.g += rhs.g;
355  lhs.b += rhs.b;
356  lhs.a += rhs.a;
357  return lhs;
358 }
359 
361 inline Color& operator-=( Color& lhs, const Color& rhs)
362 {
363  lhs.r -= rhs.r;
364  lhs.g -= rhs.g;
365  lhs.b -= rhs.b;
366  lhs.a -= rhs.a;
367  return lhs;
368 }
369 
371 inline Color& operator*=( Color& lhs, const Color& rhs)
372 {
373  lhs.r *= rhs.r;
374  lhs.g *= rhs.g;
375  lhs.b *= rhs.b;
376  lhs.a *= rhs.a;
377  return lhs;
378 }
379 
381 inline Color& operator/=( Color& lhs, const Color& rhs)
382 {
383  lhs.r /= rhs.r;
384  lhs.g /= rhs.g;
385  lhs.b /= rhs.b;
386  lhs.a /= rhs.a;
387  return lhs;
388 }
389 
391 inline Color operator+( const Color& lhs, const Color& rhs)
392 {
393  return Color( lhs.r + rhs.r, lhs.g + rhs.g, lhs.b + rhs.b, lhs.a + rhs.a);
394 }
395 
397 inline Color operator-( const Color& lhs, const Color& rhs)
398 {
399  return Color( lhs.r - rhs.r, lhs.g - rhs.g, lhs.b - rhs.b, lhs.a - rhs.a);
400 }
401 
403 inline Color operator*( const Color& lhs, const Color& rhs)
404 {
405  return Color( lhs.r * rhs.r, lhs.g * rhs.g, lhs.b * rhs.b, lhs.a * rhs.a);
406 }
407 
409 inline Color operator/( const Color& lhs, const Color& rhs)
410 {
411  return Color( lhs.r / rhs.r, lhs.g / rhs.g, lhs.b / rhs.b, lhs.a / rhs.a);
412 }
413 
415 inline Color operator-( const Color& c)
416 {
417  return Color( -c.r, -c.g, -c.b, -c.a);
418 }
419 
420 
421 
422 //------ Free operator *=, /=, *, and / definitions for scalars ---------------
423 
425 inline Color& operator*=( Color& c, Float32 s)
426 {
427  c.r *= s;
428  c.g *= s;
429  c.b *= s;
430  c.a *= s;
431  return c;
432 }
433 
435 inline Color& operator/=( Color& c, Float32 s)
436 {
437  const Float32 f = 1.0f / s;
438  c.r *= f;
439  c.g *= f;
440  c.b *= f;
441  c.a *= f;
442  return c;
443 }
444 
446 inline Color operator*( const Color& c, Float32 s)
447 {
448  return Color( c.r * s, c.g * s, c.b * s, c.a * s);
449 }
450 
453 inline Color operator*( Float32 s, const Color& c)
454 {
455  return Color( s * c.r, s * c.g, s* c.b, s * c.a);
456 }
457 
459 inline Color operator/( const Color& c, Float32 s)
460 {
461  const Float32 f = 1.0f / s;
462  return Color( c.r * f, c.g * f, c.b * f, c.a * f);
463 }
464 
465 
466 //------ Function Overloads for Color Algorithms ------------------------------
467 
468 
470 inline Color abs( const Color& c)
471 {
472  return Color( abs( c.r), abs( c.g), abs( c.b), abs( c.a));
473 }
474 
476 inline Color acos( const Color& c)
477 {
478  return Color( acos( c.r), acos( c.g), acos( c.b), acos( c.a));
479 }
480 
482 inline bool all( const Color& c)
483 {
484  return (c.r != 0.0f) && (c.g != 0.0f) && (c.b != 0.0f) && (c.a != 0.0f);
485 }
486 
488 inline bool any( const Color& c)
489 {
490  return (c.r != 0.0f) || (c.g != 0.0f) || (c.b != 0.0f) || (c.a != 0.0f);
491 }
492 
494 inline Color asin( const Color& c)
495 {
496  return Color( asin( c.r), asin( c.g), asin( c.b), asin( c.a));
497 }
498 
500 inline Color atan( const Color& c)
501 {
502  return Color( atan( c.r), atan( c.g), atan( c.b), atan( c.a));
503 }
504 
508 inline Color atan2( const Color& c, const Color& d)
509 {
510  return Color( atan2( c.r, d.r), atan2( c.g, d.g), atan2( c.b, d.b), atan2( c.a, d.a));
511 }
512 
515 inline Color ceil( const Color& c)
516 {
517  return Color( ceil( c.r), ceil( c.g), ceil( c.b), ceil( c.a));
518 }
519 
521 inline Color clamp( const Color& c, const Color& low, const Color& high)
522 {
523  return Color( clamp( c.r, low.r, high.r),
524  clamp( c.g, low.g, high.g),
525  clamp( c.b, low.b, high.b),
526  clamp( c.a, low.a, high.a));
527 }
528 
530 inline Color clamp( const Color& c, const Color& low, Float32 high)
531 {
532  return Color( clamp( c.r, low.r, high),
533  clamp( c.g, low.g, high),
534  clamp( c.b, low.b, high),
535  clamp( c.a, low.a, high));
536 }
537 
539 inline Color clamp( const Color& c, Float32 low, const Color& high)
540 {
541  return Color( clamp( c.r, low, high.r),
542  clamp( c.g, low, high.g),
543  clamp( c.b, low, high.b),
544  clamp( c.a, low, high.a));
545 }
546 
548 inline Color clamp( const Color& c, Float32 low, Float32 high)
549 {
550  return Color( clamp( c.r, low, high),
551  clamp( c.g, low, high),
552  clamp( c.b, low, high),
553  clamp( c.a, low, high));
554 }
555 
557 inline Color cos( const Color& c)
558 {
559  return Color( cos( c.r), cos( c.g), cos( c.b), cos( c.a));
560 }
561 
563 inline Color degrees( const Color& c)
564 {
565  return Color( degrees( c.r), degrees( c.g), degrees( c.b), degrees( c.a));
566 }
567 
570 inline Color elementwise_max( const Color& lhs, const Color& rhs)
571 {
572  return Color( base::max MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
573  base::max MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
574  base::max MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
575  base::max MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
576 }
577 
580 inline Color elementwise_min( const Color& lhs, const Color& rhs)
581 {
582  return Color( base::min MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
583  base::min MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
584  base::min MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
585  base::min MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
586 }
587 
589 inline Color exp( const Color& c)
590 {
591  return Color( exp( c.r), exp( c.g), exp( c.b), exp( c.a));
592 }
593 
595 inline Color exp2( const Color& c)
596 {
597  return Color( exp2( c.r), exp2( c.g), exp2( c.b), exp2( c.a));
598 }
599 
602 inline Color floor( const Color& c)
603 {
604  return Color( floor( c.r), floor( c.g), floor( c.b), floor( c.a));
605 }
606 
610 inline Color fmod( const Color& a, const Color& b)
611 {
612  return Color( fmod( a.r, b.r), fmod( a.g, b.g), fmod( a.b, b.b), fmod( a.a, b.a));
613 }
614 
618 inline Color fmod( const Color& a, Float32 b)
619 {
620  return Color( fmod( a.r, b), fmod( a.g, b), fmod( a.b, b), fmod( a.a, b));
621 }
622 
624 inline Color frac( const Color& c)
625 {
626  return Color( frac( c.r), frac( c.g), frac( c.b), frac( c.a));
627 }
628 
637  const Color& color,
638  Float32 gamma_factor)
639 {
640  mi_math_assert( gamma_factor > 0);
641  const Float32 f = Float32(1.0) / gamma_factor;
642  return Color( fast_pow( color.r, f),
643  fast_pow( color.g, f),
644  fast_pow( color.b, f),
645  color.a);
646 }
647 
649 inline bool is_approx_equal(
650  const Color& lhs,
651  const Color& rhs,
652  Float32 e)
653 {
654  return is_approx_equal( lhs.r, rhs.r, e)
655  && is_approx_equal( lhs.g, rhs.g, e)
656  && is_approx_equal( lhs.b, rhs.b, e)
657  && is_approx_equal( lhs.a, rhs.a, e);
658 }
659 
662 inline Color lerp(
663  const Color& c1,
664  const Color& c2,
665  const Color& t)
666 {
667  return Color( lerp( c1.r, c2.r, t.r),
668  lerp( c1.g, c2.g, t.g),
669  lerp( c1.b, c2.b, t.b),
670  lerp( c1.a, c2.a, t.a));
671 }
672 
675 inline Color lerp(
676  const Color& c1,
677  const Color& c2,
678  Float32 t)
679 {
680  // equivalent to: return c1 * (Float32(1)-t) + c2 * t;
681  return Color( lerp( c1.r, c2.r, t),
682  lerp( c1.g, c2.g, t),
683  lerp( c1.b, c2.b, t),
684  lerp( c1.a, c2.a, t));
685 }
686 
688 inline Color log( const Color& c)
689 {
690  return Color( log( c.r), log( c.g), log( c.b), log( c.a));
691 }
692 
695 {
696  return Color( log2 MI_PREVENT_MACRO_EXPAND (c.r),
700 }
701 
703 inline Color log10( const Color& c)
704 {
705  return Color( log10( c.r), log10( c.g), log10( c.b), log10( c.a));
706 }
707 
712 inline Color modf( const Color& c, Color& i)
713 {
714  return Color( modf( c.r, i.r), modf( c.g, i.g), modf( c.b, i.b), modf( c.a, i.a));
715 }
716 
718 inline Color pow( const Color& a, const Color& b)
719 {
720  return Color( pow( a.r, b.r), pow( a.g, b.g), pow( a.b, b.b), pow( a.a, b.a));
721 }
722 
724 inline Color pow( const Color& a, Float32 b)
725 {
726  return Color( pow( a.r, b), pow( a.g, b), pow( a.b, b), pow( a.a, b));
727 }
728 
730 inline Color radians( const Color& c)
731 {
732  return Color( radians( c.r), radians( c.g), radians( c.b), radians( c.a));
733 }
734 
736 inline Color round( const Color& c)
737 {
738  return Color( round( c.r), round( c.g), round( c.b), round( c.a));
739 }
740 
742 inline Color rsqrt( const Color& c)
743 {
744  return Color( rsqrt( c.r), rsqrt( c.g), rsqrt( c.b), rsqrt( c.a));
745 }
746 
748 inline Color saturate( const Color& c)
749 {
750  return Color( saturate( c.r), saturate( c.g), saturate( c.b), saturate( c.a));
751 }
752 
754 inline Color sign( const Color& c)
755 {
756  return Color( sign( c.r), sign( c.g), sign( c.b), sign( c.a));
757 }
758 
760 inline Color sin( const Color& c)
761 {
762  return Color( sin( c.r), sin( c.g), sin( c.b), sin( c.a));
763 }
764 
768 inline void sincos( const Color& a, Color& s, Color& c)
769 {
770  sincos( a.r, s.r, c.r);
771  sincos( a.g, s.g, c.g);
772  sincos( a.b, s.b, c.b);
773  sincos( a.a, s.a, c.a);
774 }
775 
781 inline Color smoothstep( const Color& a, const Color& b, const Color& c)
782 {
783  return Color( smoothstep( a.r, b.r, c.r),
784  smoothstep( a.g, b.g, c.g),
785  smoothstep( a.b, b.b, c.b),
786  smoothstep( a.a, b.a, c.a));
787 }
788 
794 inline Color smoothstep( const Color& a, const Color& b, Float32 x)
795 {
796  return Color( smoothstep( a.r, b.r, x),
797  smoothstep( a.g, b.g, x),
798  smoothstep( a.b, b.b, x),
799  smoothstep( a.a, b.a, x));
800 }
801 
803 inline Color sqrt( const Color& c)
804 {
805  return Color( sqrt( c.r), sqrt( c.g), sqrt( c.b), sqrt( c.a));
806 }
807 
809 inline Color step( const Color& a, const Color& c)
810 {
811  return Color( step( a.r, c.r), step( a.g, c.g), step( a.g, c.b), step( a.a, c.a));
812 }
813 
815 inline Color tan( const Color& c)
816 {
817  return Color( tan( c.r), tan( c.g), tan( c.b), tan( c.a));
818 }
819 
821 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Color& c)
822 {
827 }
828 
831 {
836 }
837 
839 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Color& c)
840 {
841  return isnan MI_PREVENT_MACRO_EXPAND (c.r)
845 }
846 
850 inline void to_rgbe( const Color& color, Uint32& rgbe)
851 {
852  to_rgbe( &color.r, rgbe);
853 }
854 
858 inline void to_rgbe( const Color& color, Uint8 rgbe[4])
859 {
860  to_rgbe( &color.r, rgbe);
861 }
862 
866 inline void from_rgbe( const Uint8 rgbe[4], Color& color)
867 {
868  from_rgbe( rgbe, &color.r);
869  color.a = 1.0f;
870 }
871 
875 inline void from_rgbe( const Uint32 rgbe, Color& color)
876 {
877  from_rgbe( rgbe, &color.r);
878  color.a = 1.0f;
879 }
880 
881 //------ Definitions of member functions --------------------------------------
882 
883 #ifndef MI_FOR_DOXYGEN_ONLY
884 
885 inline Color Color::clip(
886  Clip_mode mode,
887  bool desaturate) const
888 {
889  Float32 max_val = 1.0f;
890  Color col = *this;
891  if( col.a < 0.0f)
892  col.a = 0.0f;
893  if( mode == CLIP_RGB) {
894  if( col.a < col.r) col.a = col.r;
895  if( col.a < col.g) col.a = col.g;
896  if( col.a < col.b) col.a = col.b;
897  }
898  if( col.a > 1.0f)
899  col.a = 1.0f;
900  if( mode == CLIP_ALPHA)
901  max_val = col.a;
902  if( desaturate)
903  return col.desaturate(max_val);
904  return Color( math::clamp( col.r, 0.0f, max_val),
905  math::clamp( col.g, 0.0f, max_val),
906  math::clamp( col.b, 0.0f, max_val),
907  col.a);
908 }
909 
910 inline Color Color::desaturate( Float32 maxval) const
911 {
912  // We compute a new color based on s with the vector formula c(s) = (N + s(I-N)) c0 where N is
913  // the 3 by 3 matrix with the [1,3] vector b with the NTSC values as its rows, and c0 is the
914  // original color. All c(s) have the same brightness, b*c0, as the original color. It can be
915  // algebraically shown that the hue of the c(s) is the same as for c0. Hue can be expressed with
916  // the formula h(c) = (I-A)c, where A is a 3 by 3 matrix with all 1/3 values. Essentially,
917  // h(c(s)) == h(c0), since A*N == N
918 
919  Float32 t; // temp for saturation calc
920 
921  Float32 axis = ntsc_intensity();
922  if( axis < 0) // negative: black, exit.
923  return Color( 0, 0, 0, a);
924  if( axis > maxval) // too bright: all white, exit.
925  return Color( maxval, maxval, maxval, a);
926 
927  Float32 drds = r - axis; // calculate color axis and
928  Float32 dgds = g - axis; // dcol/dsat. sat==1 at the
929  Float32 dbds = b - axis; // outset.
930 
931  Float32 sat = 1.0f; // initial saturation
932  bool clip = false; // outside range, desaturate
933 
934  if( r > maxval) { // red > maxval?
935  clip = true;
936  t = (maxval - axis) / drds;
937  if( t < sat) sat = t;
938  } else if( r < 0) { // red < 0?
939  clip = true;
940  t = -axis / drds;
941  if( t < sat) sat = t;
942  }
943  if( g > maxval) { // green > maxval?
944  clip = true;
945  t = (maxval - axis) / dgds;
946  if( t < sat) sat = t;
947  } else if( g < 0) { // green < 0?
948  clip = true;
949  t = -axis / dgds;
950  if( t < sat) sat = t;
951  }
952  if( b > maxval) { // blue > maxval?
953  clip = true;
954  t = (maxval - axis) / dbds;
955  if( t < sat) sat = t;
956  } else if( b < 0) { // blue < 0?
957  clip = true;
958  t = -axis / dbds;
959  if( t < sat) sat = t;
960  }
961  if( clip) {
962  // negative solutions should not be possible
963  mi_math_assert( sat >= 0);
964  // clamp to avoid numerical imprecision
965  return Color( math::clamp( axis + drds * sat, 0.0f, maxval),
966  math::clamp( axis + dgds * sat, 0.0f, maxval),
967  math::clamp( axis + dbds * sat, 0.0f, maxval),
968  a);
969  }
970  mi_math_assert( r >= 0 && r <= maxval);
971  mi_math_assert( g >= 0 && g <= maxval);
972  mi_math_assert( b >= 0 && b <= maxval);
973  return *this;
974 }
975 
976 #endif // MI_FOR_DOXYGEN_ONLY
977  // end group mi_math_color
979 
980 } // namespace math
981 
982 } // namespace mi
983 
984 #endif // MI_MATH_COLOR_H