NVIDIA Iray API Home  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 1986, 2016 NVIDIA Corporation. All rights reserved.
3 //*****************************************************************************
8 //*****************************************************************************
9 
10 #ifndef MI_MATH_COLOR_H
11 #define MI_MATH_COLOR_H
12 
13 #include <mi/base/types.h>
14 #include <mi/math/assert.h>
15 #include <mi/math/function.h>
16 #include <mi/math/vector.h>
17 
18 namespace mi {
19 
20 namespace math {
21 
33 // Color and Spectrum can be converted into each other. To avoid cyclic dependencies among the
34 // headers, the Spectrum_struct class is already defined here.
35 
36 //------- POD struct that provides storage for spectrum elements --------
37 
48 {
50  Float32 c[3];
51 };
52 
53 //------ Color Class ---------------------------------------------------------
54 
58 enum Clip_mode {
62 };
63 
81 class Color : public Color_struct
82 {
83 public:
86  typedef Float32 value_type;
87  typedef Size size_type;
89  typedef Float32 * pointer;
90  typedef const Float32 * const_pointer;
91  typedef Float32 & reference;
92  typedef const Float32 & const_reference;
93 
94  static const Size SIZE = 4;
95 
97  static inline Size size() { return SIZE; }
98 
100  static inline Size max_size() { return SIZE; }
101 
103  inline Float32* begin() { return &r; }
104 
106  inline const Float32* begin() const { return &r; }
107 
111  inline Float32* end() { return begin() + SIZE; }
112 
116  inline const Float32* end() const { return begin() + SIZE; }
117 
119  inline Color()
120  {
121 #if defined(DEBUG) || (defined(_MSC_VER) && _MSC_VER <= 1310)
122  // In debug mode, default-constructed colors are initialized with signaling NaNs or, if not
123  // applicable, with a maximum value to increase the chances of diagnosing incorrect use of
124  // an uninitialized color.
125  //
126  // When compiling with Visual C++ 7.1 or earlier, this code is enabled in all variants to
127  // work around a very obscure compiler bug that causes the compiler to crash.
128  typedef mi::base::numeric_traits<Float32> Traits;
129  Float32 v = (Traits::has_signaling_NaN)
130  ? Traits::signaling_NaN() : Traits::max MI_PREVENT_MACRO_EXPAND ();
131  r = v;
132  g = v;
133  b = v;
134  a = v;
135 #endif
136  }
137 
139  inline Color( const Color_struct& c)
140  {
141  r = c.r;
142  g = c.g;
143  b = c.b;
144  a = c.a;
145  }
146 
147 
149  inline explicit Color( const Float32 s)
150  {
151  r = s;
152  g = s;
153  b = s;
154  a = s;
155  }
156 
158  inline Color( Float32 nr, Float32 ng, Float32 nb, Float32 na = 1.0)
159  {
160  r = nr;
161  g = ng;
162  b = nb;
163  a = na;
164  }
165 
177  template <typename T>
178  inline explicit Color( T array[4])
179  {
180  r = array[0];
181  g = array[1];
182  b = array[2];
183  a = array[3];
184  }
185 
188  inline explicit Color( const Vector<Float32,4>& v)
189  {
190  r = v.x;
191  g = v.y;
192  b = v.z;
193  a = v.w;
194  }
195 
197  inline explicit Color( const Spectrum_struct& s)
198  {
199  r = s.c[0];
200  g = s.c[1];
201  b = s.c[2];
202  a = 1.0f;
203  }
204 
206  inline Color& operator=( const Color& c)
207  {
208  Color_struct::operator=( c);
209  return *this;
210  }
211 
214  inline Color& operator=( const Vector<Float32,4>& v)
215  {
216  r = v.x;
217  g = v.y;
218  b = v.z;
219  a = v.w;
220  return *this;
221  }
222 
224  inline const Float32& operator[]( Size i) const
225  {
226  mi_math_assert_msg( i < 4, "precondition");
227  return (&r)[i];
228  }
229 
231  inline Float32& operator[]( Size i)
232  {
233  mi_math_assert_msg( i < 4, "precondition");
234  return (&r)[i];
235  }
236 
237 
239  inline Float32 get( Size i) const
240  {
241  mi_math_assert_msg( i < 4, "precondition");
242  return (&r)[i];
243  }
244 
246  inline void set( Size i, Float32 value)
247  {
248  mi_math_assert_msg( i < 4, "precondition");
249  (&r)[i] = value;
250  }
251 
253  inline bool is_black() const
254  {
255  return (r == 0.0f) && (g == 0.0f) && (b == 0.0f);
256  }
257 
259  inline Float32 linear_intensity() const
260  {
261  return (r + g + b) * Float32(1.0 / 3.0);
262  }
263 
268  inline Float32 ntsc_intensity() const
269  {
270  return r * 0.299f + g * 0.587f + b * 0.114f;
271  }
272 
277  inline Float32 cie_intensity() const
278  {
279  return r * 0.212671f + g * 0.715160f + b * 0.072169f;
280  }
281 
286  inline Color clip( Clip_mode mode = CLIP_RGB, bool desaturate = false) const;
287 
288 
298  inline Color desaturate( Float32 maxval = 1.0f) const;
299 };
300 
301 //------ Free comparison operators ==, !=, <, <=, >, >= for colors ------------
302 
304 inline bool operator==( const Color& lhs, const Color& rhs)
305 {
306  return is_equal( lhs, rhs);
307 }
308 
310 inline bool operator!=( const Color& lhs, const Color& rhs)
311 {
312  return is_not_equal( lhs, rhs);
313 }
314 
318 inline bool operator<( const Color& lhs, const Color& rhs)
319 {
320  return lexicographically_less( lhs, rhs);
321 }
322 
326 inline bool operator<=( const Color& lhs, const Color& rhs)
327 {
328  return lexicographically_less_or_equal( lhs, rhs);
329 }
330 
334 inline bool operator>( const Color& lhs, const Color& rhs)
335 {
336  return lexicographically_greater( lhs, rhs);
337 }
338 
342 inline bool operator>=( const Color& lhs, const Color& rhs)
343 {
344  return lexicographically_greater_or_equal( lhs, rhs);
345 }
346 
347 
348 
349 //------ Free operators +=, -=, *=, /=, +, -, *, and / for colors --------------
350 
352 inline Color& operator+=( Color& lhs, const Color& rhs)
353 {
354  lhs.r += rhs.r;
355  lhs.g += rhs.g;
356  lhs.b += rhs.b;
357  lhs.a += rhs.a;
358  return lhs;
359 }
360 
362 inline Color& operator-=( Color& lhs, const Color& rhs)
363 {
364  lhs.r -= rhs.r;
365  lhs.g -= rhs.g;
366  lhs.b -= rhs.b;
367  lhs.a -= rhs.a;
368  return lhs;
369 }
370 
372 inline Color& operator*=( Color& lhs, const Color& rhs)
373 {
374  lhs.r *= rhs.r;
375  lhs.g *= rhs.g;
376  lhs.b *= rhs.b;
377  lhs.a *= rhs.a;
378  return lhs;
379 }
380 
382 inline Color& operator/=( Color& lhs, const Color& rhs)
383 {
384  lhs.r /= rhs.r;
385  lhs.g /= rhs.g;
386  lhs.b /= rhs.b;
387  lhs.a /= rhs.a;
388  return lhs;
389 }
390 
392 inline Color operator+( const Color& lhs, const Color& rhs)
393 {
394  return Color( lhs.r + rhs.r, lhs.g + rhs.g, lhs.b + rhs.b, lhs.a + rhs.a);
395 }
396 
398 inline Color operator-( const Color& lhs, const Color& rhs)
399 {
400  return Color( lhs.r - rhs.r, lhs.g - rhs.g, lhs.b - rhs.b, lhs.a - rhs.a);
401 }
402 
404 inline Color operator*( const Color& lhs, const Color& rhs)
405 {
406  return Color( lhs.r * rhs.r, lhs.g * rhs.g, lhs.b * rhs.b, lhs.a * rhs.a);
407 }
408 
410 inline Color operator/( const Color& lhs, const Color& rhs)
411 {
412  return Color( lhs.r / rhs.r, lhs.g / rhs.g, lhs.b / rhs.b, lhs.a / rhs.a);
413 }
414 
416 inline Color operator-( const Color& c)
417 {
418  return Color( -c.r, -c.g, -c.b, -c.a);
419 }
420 
421 
422 
423 //------ Free operator *=, /=, *, and / definitions for scalars ---------------
424 
426 inline Color& operator*=( Color& c, Float32 s)
427 {
428  c.r *= s;
429  c.g *= s;
430  c.b *= s;
431  c.a *= s;
432  return c;
433 }
434 
436 inline Color& operator/=( Color& c, Float32 s)
437 {
438  const Float32 f = 1.0f / s;
439  c.r *= f;
440  c.g *= f;
441  c.b *= f;
442  c.a *= f;
443  return c;
444 }
445 
447 inline Color operator*( const Color& c, Float32 s)
448 {
449  return Color( c.r * s, c.g * s, c.b * s, c.a * s);
450 }
451 
454 inline Color operator*( Float32 s, const Color& c)
455 {
456  return Color( s * c.r, s * c.g, s* c.b, s * c.a);
457 }
458 
460 inline Color operator/( const Color& c, Float32 s)
461 {
462  const Float32 f = 1.0f / s;
463  return Color( c.r * f, c.g * f, c.b * f, c.a * f);
464 }
465 
466 
467 //------ Function Overloads for Color Algorithms ------------------------------
468 
469 
471 inline Color abs( const Color& c)
472 {
473  return Color( abs( c.r), abs( c.g), abs( c.b), abs( c.a));
474 }
475 
477 inline Color acos( const Color& c)
478 {
479  return Color( acos( c.r), acos( c.g), acos( c.b), acos( c.a));
480 }
481 
483 inline bool all( const Color& c)
484 {
485  return (c.r != 0.0f) && (c.g != 0.0f) && (c.b != 0.0f) && (c.a != 0.0f);
486 }
487 
489 inline bool any( const Color& c)
490 {
491  return (c.r != 0.0f) || (c.g != 0.0f) || (c.b != 0.0f) || (c.a != 0.0f);
492 }
493 
495 inline Color asin( const Color& c)
496 {
497  return Color( asin( c.r), asin( c.g), asin( c.b), asin( c.a));
498 }
499 
501 inline Color atan( const Color& c)
502 {
503  return Color( atan( c.r), atan( c.g), atan( c.b), atan( c.a));
504 }
505 
509 inline Color atan2( const Color& c, const Color& d)
510 {
511  return Color( atan2( c.r, d.r), atan2( c.g, d.g), atan2( c.b, d.b), atan2( c.a, d.a));
512 }
513 
516 inline Color ceil( const Color& c)
517 {
518  return Color( ceil( c.r), ceil( c.g), ceil( c.b), ceil( c.a));
519 }
520 
522 inline Color clamp( const Color& c, const Color& low, const Color& high)
523 {
524  return Color( clamp( c.r, low.r, high.r),
525  clamp( c.g, low.g, high.g),
526  clamp( c.b, low.b, high.b),
527  clamp( c.a, low.a, high.a));
528 }
529 
531 inline Color clamp( const Color& c, const Color& low, Float32 high)
532 {
533  return Color( clamp( c.r, low.r, high),
534  clamp( c.g, low.g, high),
535  clamp( c.b, low.b, high),
536  clamp( c.a, low.a, high));
537 }
538 
540 inline Color clamp( const Color& c, Float32 low, const Color& high)
541 {
542  return Color( clamp( c.r, low, high.r),
543  clamp( c.g, low, high.g),
544  clamp( c.b, low, high.b),
545  clamp( c.a, low, high.a));
546 }
547 
549 inline Color clamp( const Color& c, Float32 low, Float32 high)
550 {
551  return Color( clamp( c.r, low, high),
552  clamp( c.g, low, high),
553  clamp( c.b, low, high),
554  clamp( c.a, low, high));
555 }
556 
558 inline Color cos( const Color& c)
559 {
560  return Color( cos( c.r), cos( c.g), cos( c.b), cos( c.a));
561 }
562 
564 inline Color degrees( const Color& c)
565 {
566  return Color( degrees( c.r), degrees( c.g), degrees( c.b), degrees( c.a));
567 }
568 
571 inline Color elementwise_max( const Color& lhs, const Color& rhs)
572 {
573  return Color( base::max MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
574  base::max MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
575  base::max MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
576  base::max MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
577 }
578 
581 inline Color elementwise_min( const Color& lhs, const Color& rhs)
582 {
583  return Color( base::min MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
584  base::min MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
585  base::min MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
586  base::min MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
587 }
588 
590 inline Color exp( const Color& c)
591 {
592  return Color( exp( c.r), exp( c.g), exp( c.b), exp( c.a));
593 }
594 
596 inline Color exp2( const Color& c)
597 {
598  return Color( exp2( c.r), exp2( c.g), exp2( c.b), exp2( c.a));
599 }
600 
603 inline Color floor( const Color& c)
604 {
605  return Color( floor( c.r), floor( c.g), floor( c.b), floor( c.a));
606 }
607 
611 inline Color fmod( const Color& a, const Color& b)
612 {
613  return Color( fmod( a.r, b.r), fmod( a.g, b.g), fmod( a.b, b.b), fmod( a.a, b.a));
614 }
615 
619 inline Color fmod( const Color& a, Float32 b)
620 {
621  return Color( fmod( a.r, b), fmod( a.g, b), fmod( a.b, b), fmod( a.a, b));
622 }
623 
625 inline Color frac( const Color& c)
626 {
627  return Color( frac( c.r), frac( c.g), frac( c.b), frac( c.a));
628 }
629 
638  const Color& color,
639  Float32 gamma_factor)
640 {
641  mi_math_assert( gamma_factor > 0);
642  const Float32 f = Float32(1.0) / gamma_factor;
643  return Color( fast_pow( color.r, f),
644  fast_pow( color.g, f),
645  fast_pow( color.b, f),
646  color.a);
647 }
648 
650 inline bool is_approx_equal(
651  const Color& lhs,
652  const Color& rhs,
653  Float32 e)
654 {
655  return is_approx_equal( lhs.r, rhs.r, e)
656  && is_approx_equal( lhs.g, rhs.g, e)
657  && is_approx_equal( lhs.b, rhs.b, e)
658  && is_approx_equal( lhs.a, rhs.a, e);
659 }
660 
663 inline Color lerp(
664  const Color& c1,
665  const Color& c2,
666  const Color& t)
667 {
668  return Color( lerp( c1.r, c2.r, t.r),
669  lerp( c1.g, c2.g, t.g),
670  lerp( c1.b, c2.b, t.b),
671  lerp( c1.a, c2.a, t.a));
672 }
673 
676 inline Color lerp(
677  const Color& c1,
678  const Color& c2,
679  Float32 t)
680 {
681  // equivalent to: return c1 * (Float32(1)-t) + c2 * t;
682  return Color( lerp( c1.r, c2.r, t),
683  lerp( c1.g, c2.g, t),
684  lerp( c1.b, c2.b, t),
685  lerp( c1.a, c2.a, t));
686 }
687 
689 inline Color log( const Color& c)
690 {
691  return Color( log( c.r), log( c.g), log( c.b), log( c.a));
692 }
693 
696 {
697  return Color( log2 MI_PREVENT_MACRO_EXPAND (c.r),
701 }
702 
704 inline Color log10( const Color& c)
705 {
706  return Color( log10( c.r), log10( c.g), log10( c.b), log10( c.a));
707 }
708 
713 inline Color modf( const Color& c, Color& i)
714 {
715  return Color( modf( c.r, i.r), modf( c.g, i.g), modf( c.b, i.b), modf( c.a, i.a));
716 }
717 
719 inline Color pow( const Color& a, const Color& b)
720 {
721  return Color( pow( a.r, b.r), pow( a.g, b.g), pow( a.b, b.b), pow( a.a, b.a));
722 }
723 
725 inline Color pow( const Color& a, Float32 b)
726 {
727  return Color( pow( a.r, b), pow( a.g, b), pow( a.b, b), pow( a.a, b));
728 }
729 
731 inline Color radians( const Color& c)
732 {
733  return Color( radians( c.r), radians( c.g), radians( c.b), radians( c.a));
734 }
735 
737 inline Color round( const Color& c)
738 {
739  return Color( round( c.r), round( c.g), round( c.b), round( c.a));
740 }
741 
743 inline Color rsqrt( const Color& c)
744 {
745  return Color( rsqrt( c.r), rsqrt( c.g), rsqrt( c.b), rsqrt( c.a));
746 }
747 
749 inline Color saturate( const Color& c)
750 {
751  return Color( saturate( c.r), saturate( c.g), saturate( c.b), saturate( c.a));
752 }
753 
755 inline Color sign( const Color& c)
756 {
757  return Color( sign( c.r), sign( c.g), sign( c.b), sign( c.a));
758 }
759 
761 inline Color sin( const Color& c)
762 {
763  return Color( sin( c.r), sin( c.g), sin( c.b), sin( c.a));
764 }
765 
769 inline void sincos( const Color& a, Color& s, Color& c)
770 {
771  sincos( a.r, s.r, c.r);
772  sincos( a.g, s.g, c.g);
773  sincos( a.b, s.b, c.b);
774  sincos( a.a, s.a, c.a);
775 }
776 
782 inline Color smoothstep( const Color& a, const Color& b, const Color& c)
783 {
784  return Color( smoothstep( a.r, b.r, c.r),
785  smoothstep( a.g, b.g, c.g),
786  smoothstep( a.b, b.b, c.b),
787  smoothstep( a.a, b.a, c.a));
788 }
789 
795 inline Color smoothstep( const Color& a, const Color& b, Float32 x)
796 {
797  return Color( smoothstep( a.r, b.r, x),
798  smoothstep( a.g, b.g, x),
799  smoothstep( a.b, b.b, x),
800  smoothstep( a.a, b.a, x));
801 }
802 
804 inline Color sqrt( const Color& c)
805 {
806  return Color( sqrt( c.r), sqrt( c.g), sqrt( c.b), sqrt( c.a));
807 }
808 
810 inline Color step( const Color& a, const Color& c)
811 {
812  return Color( step( a.r, c.r), step( a.g, c.g), step( a.g, c.b), step( a.a, c.a));
813 }
814 
816 inline Color tan( const Color& c)
817 {
818  return Color( tan( c.r), tan( c.g), tan( c.b), tan( c.a));
819 }
820 
822 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Color& c)
823 {
828 }
829 
832 {
837 }
838 
840 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Color& c)
841 {
842  return isnan MI_PREVENT_MACRO_EXPAND (c.r)
846 }
847 
851 inline void to_rgbe( const Color& color, Uint32& rgbe)
852 {
853  to_rgbe( &color.r, rgbe);
854 }
855 
859 inline void to_rgbe( const Color& color, Uint8 rgbe[4])
860 {
861  to_rgbe( &color.r, rgbe);
862 }
863 
867 inline void from_rgbe( const Uint8 rgbe[4], Color& color)
868 {
869  from_rgbe( rgbe, &color.r);
870  color.a = 1.0f;
871 }
872 
876 inline void from_rgbe( const Uint32 rgbe, Color& color)
877 {
878  from_rgbe( rgbe, &color.r);
879  color.a = 1.0f;
880 }
881 
882 //------ Definitions of member functions --------------------------------------
883 
884 #ifndef MI_FOR_DOXYGEN_ONLY
885 
886 inline Color Color::clip(
887  Clip_mode mode,
888  bool desaturate) const
889 {
890  Float32 max_val = 1.0f;
891  Color col = *this;
892  if( col.a < 0.0f)
893  col.a = 0.0f;
894  if( mode == CLIP_RGB) {
895  if( col.a < col.r) col.a = col.r;
896  if( col.a < col.g) col.a = col.g;
897  if( col.a < col.b) col.a = col.b;
898  }
899  if( col.a > 1.0f)
900  col.a = 1.0f;
901  if( mode == CLIP_ALPHA)
902  max_val = col.a;
903  if( desaturate)
904  return col.desaturate(max_val);
905  return Color( math::clamp( col.r, 0.0f, max_val),
906  math::clamp( col.g, 0.0f, max_val),
907  math::clamp( col.b, 0.0f, max_val),
908  col.a);
909 }
910 
911 inline Color Color::desaturate( Float32 maxval) const
912 {
913  // We compute a new color based on s with the vector formula c(s) = (N + s(I-N)) c0 where N is
914  // the 3 by 3 matrix with the [1,3] vector b with the NTSC values as its rows, and c0 is the
915  // original color. All c(s) have the same brightness, b*c0, as the original color. It can be
916  // algebraically shown that the hue of the c(s) is the same as for c0. Hue can be expressed with
917  // the formula h(c) = (I-A)c, where A is a 3 by 3 matrix with all 1/3 values. Essentially,
918  // h(c(s)) == h(c0), since A*N == N
919 
920  Float32 t; // temp for saturation calc
921 
922  Float32 axis = ntsc_intensity();
923  if( axis < 0) // negative: black, exit.
924  return Color( 0, 0, 0, a);
925  if( axis > maxval) // too bright: all white, exit.
926  return Color( maxval, maxval, maxval, a);
927 
928  Float32 drds = r - axis; // calculate color axis and
929  Float32 dgds = g - axis; // dcol/dsat. sat==1 at the
930  Float32 dbds = b - axis; // outset.
931 
932  Float32 sat = 1.0f; // initial saturation
933  bool clip = false; // outside range, desaturate
934 
935  if( r > maxval) { // red > maxval?
936  clip = true;
937  t = (maxval - axis) / drds;
938  if( t < sat) sat = t;
939  } else if( r < 0) { // red < 0?
940  clip = true;
941  t = -axis / drds;
942  if( t < sat) sat = t;
943  }
944  if( g > maxval) { // green > maxval?
945  clip = true;
946  t = (maxval - axis) / dgds;
947  if( t < sat) sat = t;
948  } else if( g < 0) { // green < 0?
949  clip = true;
950  t = -axis / dgds;
951  if( t < sat) sat = t;
952  }
953  if( b > maxval) { // blue > maxval?
954  clip = true;
955  t = (maxval - axis) / dbds;
956  if( t < sat) sat = t;
957  } else if( b < 0) { // blue < 0?
958  clip = true;
959  t = -axis / dbds;
960  if( t < sat) sat = t;
961  }
962  if( clip) {
963  // negative solutions should not be possible
964  mi_math_assert( sat >= 0);
965  // clamp to avoid numerical imprecision
966  return Color( math::clamp( axis + drds * sat, 0.0f, maxval),
967  math::clamp( axis + dgds * sat, 0.0f, maxval),
968  math::clamp( axis + dbds * sat, 0.0f, maxval),
969  a);
970  }
971  mi_math_assert( r >= 0 && r <= maxval);
972  mi_math_assert( g >= 0 && g <= maxval);
973  mi_math_assert( b >= 0 && b <= maxval);
974  return *this;
975 }
976 
977 #endif // MI_FOR_DOXYGEN_ONLY
978  // end group mi_math_color
980 
981 } // namespace math
982 
983 } // namespace mi
984 
985 #endif // MI_MATH_COLOR_H