NVIDIA Iray API
 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, 2014 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 (lhs.r == rhs.r) && (lhs.g == rhs.g) && (lhs.b == rhs.b) && (lhs.a == rhs.a);
307 }
308 
310 inline bool operator!=( const Color& lhs, const Color& rhs)
311 {
312  return (lhs.r != rhs.r) || (lhs.g != rhs.g) || (lhs.b != rhs.b) || (lhs.a != rhs.a);
313 }
314 
318 inline bool operator<( const Color& lhs, const Color& rhs)
319 {
320  if( lhs.r != rhs.r)
321  return lhs.r < rhs.r;
322  if( lhs.g != rhs.g)
323  return lhs.g < rhs.g;
324  if( lhs.b != rhs.b)
325  return lhs.b < rhs.b;
326  return lhs.a < rhs.a;
327 }
328 
332 inline bool operator<=( const Color& lhs, const Color& rhs)
333 {
334  return ! (rhs < lhs);
335 }
336 
340 inline bool operator>( const Color& lhs, const Color& rhs)
341 {
342  return rhs < lhs;
343 }
344 
348 inline bool operator>=( const Color& lhs, const Color& rhs)
349 {
350  return ! (lhs < rhs);
351 }
352 
353 
354 
355 //------ Free operators +=, -=, *=, /=, +, -, *, and / for colors --------------
356 
358 inline Color& operator+=( Color& lhs, const Color& rhs)
359 {
360  lhs.r += rhs.r;
361  lhs.g += rhs.g;
362  lhs.b += rhs.b;
363  lhs.a += rhs.a;
364  return lhs;
365 }
366 
368 inline Color& operator-=( Color& lhs, const Color& rhs)
369 {
370  lhs.r -= rhs.r;
371  lhs.g -= rhs.g;
372  lhs.b -= rhs.b;
373  lhs.a -= rhs.a;
374  return lhs;
375 }
376 
378 inline Color& operator*=( Color& lhs, const Color& rhs)
379 {
380  lhs.r *= rhs.r;
381  lhs.g *= rhs.g;
382  lhs.b *= rhs.b;
383  lhs.a *= rhs.a;
384  return lhs;
385 }
386 
388 inline Color& operator/=( Color& lhs, const Color& rhs)
389 {
390  lhs.r /= rhs.r;
391  lhs.g /= rhs.g;
392  lhs.b /= rhs.b;
393  lhs.a /= rhs.a;
394  return lhs;
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& lhs, const Color& rhs)
417 {
418  return Color( lhs.r / rhs.r, lhs.g / rhs.g, lhs.b / rhs.b, lhs.a / rhs.a);
419 }
420 
422 inline Color operator-( const Color& c)
423 {
424  return Color( -c.r, -c.g, -c.b, -c.a);
425 }
426 
427 
428 
429 //------ Free operator *=, /=, *, and / definitions for scalars ---------------
430 
432 inline Color& operator*=( Color& c, Float32 s)
433 {
434  c.r *= s;
435  c.g *= s;
436  c.b *= s;
437  c.a *= s;
438  return c;
439 }
440 
442 inline Color& operator/=( Color& c, Float32 s)
443 {
444  const Float32 f = 1.0f / s;
445  c.r *= f;
446  c.g *= f;
447  c.b *= f;
448  c.a *= f;
449  return c;
450 }
451 
453 inline Color operator*( const Color& c, Float32 s)
454 {
455  return Color( c.r * s, c.g * s, c.b * s, c.a * s);
456 }
457 
460 inline Color operator*( Float32 s, const Color& c)
461 {
462  return Color( s * c.r, s * c.g, s* c.b, s * c.a);
463 }
464 
466 inline Color operator/( const Color& c, Float32 s)
467 {
468  const Float32 f = 1.0f / s;
469  return Color( c.r * f, c.g * f, c.b * f, c.a * f);
470 }
471 
472 
473 //------ Function Overloads for Color Algorithms ------------------------------
474 
475 
477 inline Color abs( const Color& c)
478 {
479  return Color( abs( c.r), abs( c.g), abs( c.b), abs( c.a));
480 }
481 
483 inline Color acos( const Color& c)
484 {
485  return Color( acos( c.r), acos( c.g), acos( c.b), acos( c.a));
486 }
487 
489 inline bool all( 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 bool any( const Color& c)
496 {
497  return (c.r != 0.0f) || (c.g != 0.0f) || (c.b != 0.0f) || (c.a != 0.0f);
498 }
499 
501 inline Color asin( const Color& c)
502 {
503  return Color( asin( c.r), asin( c.g), asin( c.b), asin( c.a));
504 }
505 
507 inline Color atan( const Color& c)
508 {
509  return Color( atan( c.r), atan( c.g), atan( c.b), atan( c.a));
510 }
511 
515 inline Color atan2( const Color& c, const Color& d)
516 {
517  return Color( atan2( c.r, d.r), atan2( c.g, d.g), atan2( c.b, d.b), atan2( c.a, d.a));
518 }
519 
522 inline Color ceil( const Color& c)
523 {
524  return Color( ceil( c.r), ceil( c.g), ceil( c.b), ceil( c.a));
525 }
526 
528 inline Color clamp( const Color& c, const Color& low, const Color& high)
529 {
530  return Color( clamp( c.r, low.r, high.r),
531  clamp( c.g, low.g, high.g),
532  clamp( c.b, low.b, high.b),
533  clamp( c.a, low.a, high.a));
534 }
535 
537 inline Color clamp( const Color& c, const Color& low, Float32 high)
538 {
539  return Color( clamp( c.r, low.r, high),
540  clamp( c.g, low.g, high),
541  clamp( c.b, low.b, high),
542  clamp( c.a, low.a, high));
543 }
544 
546 inline Color clamp( const Color& c, Float32 low, const Color& high)
547 {
548  return Color( clamp( c.r, low, high.r),
549  clamp( c.g, low, high.g),
550  clamp( c.b, low, high.b),
551  clamp( c.a, low, high.a));
552 }
553 
555 inline Color clamp( const Color& c, Float32 low, Float32 high)
556 {
557  return Color( clamp( c.r, low, high),
558  clamp( c.g, low, high),
559  clamp( c.b, low, high),
560  clamp( c.a, low, high));
561 }
562 
564 inline Color cos( const Color& c)
565 {
566  return Color( cos( c.r), cos( c.g), cos( c.b), cos( c.a));
567 }
568 
570 inline Color degrees( const Color& c)
571 {
572  return Color( degrees( c.r), degrees( c.g), degrees( c.b), degrees( c.a));
573 }
574 
577 inline Color elementwise_max( const Color& lhs, const Color& rhs)
578 {
579  return Color( base::max MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
580  base::max MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
581  base::max MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
582  base::max MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
583 }
584 
587 inline Color elementwise_min( const Color& lhs, const Color& rhs)
588 {
589  return Color( base::min MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
590  base::min MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
591  base::min MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
592  base::min MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
593 }
594 
596 inline Color exp( const Color& c)
597 {
598  return Color( exp( c.r), exp( c.g), exp( c.b), exp( c.a));
599 }
600 
602 inline Color exp2( const Color& c)
603 {
604  return Color( exp2( c.r), exp2( c.g), exp2( c.b), exp2( c.a));
605 }
606 
609 inline Color floor( const Color& c)
610 {
611  return Color( floor( c.r), floor( c.g), floor( c.b), floor( c.a));
612 }
613 
617 inline Color fmod( const Color& a, const Color& b)
618 {
619  return Color( fmod( a.r, b.r), fmod( a.g, b.g), fmod( a.b, b.b), fmod( a.a, b.a));
620 }
621 
625 inline Color fmod( const Color& a, Float32 b)
626 {
627  return Color( fmod( a.r, b), fmod( a.g, b), fmod( a.b, b), fmod( a.a, b));
628 }
629 
631 inline Color frac( const Color& c)
632 {
633  return Color( frac( c.r), frac( c.g), frac( c.b), frac( c.a));
634 }
635 
644  const Color& color,
645  Float32 gamma_factor)
646 {
647  mi_math_assert( gamma_factor > 0);
648  const Float32 f = Float32(1.0) / gamma_factor;
649  return Color( fast_pow( color.r, f),
650  fast_pow( color.g, f),
651  fast_pow( color.b, f),
652  color.a);
653 }
654 
656 inline bool is_approx_equal(
657  const Color& lhs,
658  const Color& rhs,
659  Float32 e)
660 {
661  return is_approx_equal( lhs.r, rhs.r, e)
662  && is_approx_equal( lhs.g, rhs.g, e)
663  && is_approx_equal( lhs.b, rhs.b, e)
664  && is_approx_equal( lhs.a, rhs.a, e);
665 }
666 
669 inline Color lerp(
670  const Color& c1,
671  const Color& c2,
672  const Color& t)
673 {
674  return Color( lerp( c1.r, c2.r, t.r),
675  lerp( c1.g, c2.g, t.g),
676  lerp( c1.b, c2.b, t.b),
677  lerp( c1.a, c2.a, t.a));
678 }
679 
682 inline Color lerp(
683  const Color& c1,
684  const Color& c2,
685  Float32 t)
686 {
687  // equivalent to: return c1 * (Float32(1)-t) + c2 * t;
688  return Color( lerp( c1.r, c2.r, t),
689  lerp( c1.g, c2.g, t),
690  lerp( c1.b, c2.b, t),
691  lerp( c1.a, c2.a, t));
692 }
693 
695 inline Color log( const Color& c)
696 {
697  return Color( log( c.r), log( c.g), log( c.b), log( c.a));
698 }
699 
702 {
703  return Color( log2 MI_PREVENT_MACRO_EXPAND (c.r),
707 }
708 
710 inline Color log10( const Color& c)
711 {
712  return Color( log10( c.r), log10( c.g), log10( c.b), log10( c.a));
713 }
714 
719 inline Color modf( const Color& c, Color& i)
720 {
721  return Color( modf( c.r, i.r), modf( c.g, i.g), modf( c.b, i.b), modf( c.a, i.a));
722 }
723 
725 inline Color pow( const Color& a, const Color& b)
726 {
727  return Color( pow( a.r, b.r), pow( a.g, b.g), pow( a.b, b.b), pow( a.a, b.a));
728 }
729 
731 inline Color pow( const Color& a, Float32 b)
732 {
733  return Color( pow( a.r, b), pow( a.g, b), pow( a.b, b), pow( a.a, b));
734 }
735 
737 inline Color radians( const Color& c)
738 {
739  return Color( radians( c.r), radians( c.g), radians( c.b), radians( c.a));
740 }
741 
743 inline Color round( const Color& c)
744 {
745  return Color( round( c.r), round( c.g), round( c.b), round( c.a));
746 }
747 
749 inline Color rsqrt( const Color& c)
750 {
751  return Color( rsqrt( c.r), rsqrt( c.g), rsqrt( c.b), rsqrt( c.a));
752 }
753 
755 inline Color saturate( const Color& c)
756 {
757  return Color( saturate( c.r), saturate( c.g), saturate( c.b), saturate( c.a));
758 }
759 
761 inline Color sign( const Color& c)
762 {
763  return Color( sign( c.r), sign( c.g), sign( c.b), sign( c.a));
764 }
765 
767 inline Color sin( const Color& c)
768 {
769  return Color( sin( c.r), sin( c.g), sin( c.b), sin( c.a));
770 }
771 
775 inline void sincos( const Color& a, Color& s, Color& c)
776 {
777  sincos( a.r, s.r, c.r);
778  sincos( a.g, s.g, c.g);
779  sincos( a.b, s.b, c.b);
780  sincos( a.a, s.a, c.a);
781 }
782 
788 inline Color smoothstep( const Color& a, const Color& b, const Color& c)
789 {
790  return Color( smoothstep( a.r, b.r, c.r),
791  smoothstep( a.g, b.g, c.g),
792  smoothstep( a.b, b.b, c.b),
793  smoothstep( a.a, b.a, c.a));
794 }
795 
801 inline Color smoothstep( const Color& a, const Color& b, Float32 x)
802 {
803  return Color( smoothstep( a.r, b.r, x),
804  smoothstep( a.g, b.g, x),
805  smoothstep( a.b, b.b, x),
806  smoothstep( a.a, b.a, x));
807 }
808 
810 inline Color sqrt( const Color& c)
811 {
812  return Color( sqrt( c.r), sqrt( c.g), sqrt( c.b), sqrt( c.a));
813 }
814 
816 inline Color step( const Color& a, const Color& c)
817 {
818  return Color( step( a.r, c.r), step( a.g, c.g), step( a.g, c.b), step( a.a, c.a));
819 }
820 
822 inline Color tan( const Color& c)
823 {
824  return Color( tan( c.r), tan( c.g), tan( c.b), tan( c.a));
825 }
826 
828 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Color& c)
829 {
834 }
835 
838 {
843 }
844 
846 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Color& c)
847 {
848  return isnan MI_PREVENT_MACRO_EXPAND (c.r)
852 }
853 
857 inline void to_rgbe( const Color& color, Uint32& rgbe)
858 {
859  to_rgbe( &color.r, rgbe);
860 }
861 
865 inline void to_rgbe( const Color& color, Uint8 rgbe[4])
866 {
867  to_rgbe( &color.r, rgbe);
868 }
869 
873 inline void from_rgbe( const Uint8 rgbe[4], Color& color)
874 {
875  from_rgbe( rgbe, &color.r);
876  color.a = 1.0f;
877 }
878 
882 inline void from_rgbe( const Uint32 rgbe, Color& color)
883 {
884  from_rgbe( rgbe, &color.r);
885  color.a = 1.0f;
886 }
887 
888 //------ Definitions of member functions --------------------------------------
889 
890 #ifndef MI_FOR_DOXYGEN_ONLY
891 
892 inline Color Color::clip(
893  Clip_mode mode,
894  bool desaturate) const
895 {
896  Float32 max_val = 1.0f;
897  Color col = *this;
898  if( col.a < 0.0f)
899  col.a = 0.0f;
900  if( mode == CLIP_RGB) {
901  if( col.a < col.r) col.a = col.r;
902  if( col.a < col.g) col.a = col.g;
903  if( col.a < col.b) col.a = col.b;
904  }
905  if( col.a > 1.0f)
906  col.a = 1.0f;
907  if( mode == CLIP_ALPHA)
908  max_val = col.a;
909  if( desaturate)
910  return col.desaturate(max_val);
911  return Color( math::clamp( col.r, 0.0f, max_val),
912  math::clamp( col.g, 0.0f, max_val),
913  math::clamp( col.b, 0.0f, max_val),
914  col.a);
915 }
916 
917 inline Color Color::desaturate( Float32 maxval) const
918 {
919  // We compute a new color based on s with the vector formula c(s) = (N + s(I-N)) c0 where N is
920  // the 3 by 3 matrix with the [1,3] vector b with the NTSC values as its rows, and c0 is the
921  // original color. All c(s) have the same brightness, b*c0, as the original color. It can be
922  // algebraically shown that the hue of the c(s) is the same as for c0. Hue can be expressed with
923  // the formula h(c) = (I-A)c, where A is a 3 by 3 matrix with all 1/3 values. Essentially,
924  // h(c(s)) == h(c0), since A*N == N
925 
926  Float32 t; // temp for saturation calc
927 
928  Float32 axis = ntsc_intensity();
929  if( axis < 0) // negative: black, exit.
930  return Color( 0, 0, 0, a);
931  if( axis > maxval) // too bright: all white, exit.
932  return Color( maxval, maxval, maxval, a);
933 
934  Float32 drds = r - axis; // calculate color axis and
935  Float32 dgds = g - axis; // dcol/dsat. sat==1 at the
936  Float32 dbds = b - axis; // outset.
937 
938  Float32 sat = 1.0f; // initial saturation
939  bool clip = false; // outside range, desaturate
940 
941  if( r > maxval) { // red > maxval?
942  clip = true;
943  t = (maxval - axis) / drds;
944  if( t < sat) sat = t;
945  } else if( r < 0) { // red < 0?
946  clip = true;
947  t = -axis / drds;
948  if( t < sat) sat = t;
949  }
950  if( g > maxval) { // green > maxval?
951  clip = true;
952  t = (maxval - axis) / dgds;
953  if( t < sat) sat = t;
954  } else if( g < 0) { // green < 0?
955  clip = true;
956  t = -axis / dgds;
957  if( t < sat) sat = t;
958  }
959  if( b > maxval) { // blue > maxval?
960  clip = true;
961  t = (maxval - axis) / dbds;
962  if( t < sat) sat = t;
963  } else if( b < 0) { // blue < 0?
964  clip = true;
965  t = -axis / dbds;
966  if( t < sat) sat = t;
967  }
968  if( clip) {
969  // negative solutions should not be possible
970  mi_math_assert( sat >= 0);
971  // clamp to avoid numerical imprecision
972  return Color( math::clamp( axis + drds * sat, 0.0f, maxval),
973  math::clamp( axis + dgds * sat, 0.0f, maxval),
974  math::clamp( axis + dbds * sat, 0.0f, maxval),
975  a);
976  }
977  mi_math_assert( r >= 0 && r <= maxval);
978  mi_math_assert( g >= 0 && g <= maxval);
979  mi_math_assert( b >= 0 && b <= maxval);
980  return *this;
981 }
982 
983 #endif // MI_FOR_DOXYGEN_ONLY
984  // end group mi_math_color
986 
987 } // namespace math
988 
989 } // namespace mi
990 
991 #endif // MI_MATH_COLOR_H