MDL SDK 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 2021 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 
137 #if (__cplusplus >= 201103L)
138  Color( const Color& c) = default;
140 #endif
141 
143  inline Color( const Color_struct& c)
144  {
145  r = c.r;
146  g = c.g;
147  b = c.b;
148  a = c.a;
149  }
150 
152  inline explicit Color( const Float32 s)
153  {
154  r = s;
155  g = s;
156  b = s;
157  a = s;
158  }
159 
161  inline Color( Float32 nr, Float32 ng, Float32 nb, Float32 na = 1.0)
162  {
163  r = nr;
164  g = ng;
165  b = nb;
166  a = na;
167  }
168 
180  template <typename T>
181  inline explicit Color( T array[4])
182  {
183  r = array[0];
184  g = array[1];
185  b = array[2];
186  a = array[3];
187  }
188 
191  inline explicit Color( const Vector<Float32,4>& v)
192  {
193  r = v.x;
194  g = v.y;
195  b = v.z;
196  a = v.w;
197  }
198 
200  inline explicit Color( const Spectrum_struct& s)
201  {
202  r = s.c[0];
203  g = s.c[1];
204  b = s.c[2];
205  a = 1.0f;
206  }
207 
209  inline Color& operator=( const Color& c)
210  {
211  Color_struct::operator=( c);
212  return *this;
213  }
214 
217  inline Color& operator=( const Vector<Float32,4>& v)
218  {
219  r = v.x;
220  g = v.y;
221  b = v.z;
222  a = v.w;
223  return *this;
224  }
225 
227  inline const Float32& operator[]( Size i) const
228  {
229  mi_math_assert_msg( i < 4, "precondition");
230  return (&r)[i];
231  }
232 
234  inline Float32& operator[]( Size i)
235  {
236  mi_math_assert_msg( i < 4, "precondition");
237  return (&r)[i];
238  }
239 
240 
242  inline Float32 get( Size i) const
243  {
244  mi_math_assert_msg( i < 4, "precondition");
245  return (&r)[i];
246  }
247 
249  inline void set( Size i, Float32 value)
250  {
251  mi_math_assert_msg( i < 4, "precondition");
252  (&r)[i] = value;
253  }
254 
256  inline bool is_black() const
257  {
258  return (r == 0.0f) && (g == 0.0f) && (b == 0.0f);
259  }
260 
262  inline Float32 linear_intensity() const
263  {
264  return (r + g + b) * Float32(1.0 / 3.0);
265  }
266 
271  inline Float32 ntsc_intensity() const
272  {
273  return r * 0.299f + g * 0.587f + b * 0.114f;
274  }
275 
280  inline Float32 cie_intensity() const
281  {
282  return r * 0.212671f + g * 0.715160f + b * 0.072169f;
283  }
284 
289  inline Color clip( Clip_mode mode = CLIP_RGB, bool desaturate = false) const;
290 
291 
301  inline Color desaturate( Float32 maxval = 1.0f) const;
302 };
303 
304 //------ Free comparison operators ==, !=, <, <=, >, >= for colors ------------
305 
307 inline bool operator==( const Color& lhs, const Color& rhs)
308 {
309  return is_equal( lhs, rhs);
310 }
311 
313 inline bool operator!=( const Color& lhs, const Color& rhs)
314 {
315  return is_not_equal( lhs, rhs);
316 }
317 
321 inline bool operator<( const Color& lhs, const Color& rhs)
322 {
323  return lexicographically_less( lhs, rhs);
324 }
325 
329 inline bool operator<=( const Color& lhs, const Color& rhs)
330 {
331  return lexicographically_less_or_equal( lhs, rhs);
332 }
333 
337 inline bool operator>( const Color& lhs, const Color& rhs)
338 {
339  return lexicographically_greater( lhs, rhs);
340 }
341 
345 inline bool operator>=( const Color& lhs, const Color& rhs)
346 {
347  return lexicographically_greater_or_equal( lhs, rhs);
348 }
349 
350 
351 
352 //------ Free operators +=, -=, *=, /=, +, -, *, and / for colors --------------
353 
355 inline Color& operator+=( Color& lhs, const Color& rhs)
356 {
357  lhs.r += rhs.r;
358  lhs.g += rhs.g;
359  lhs.b += rhs.b;
360  lhs.a += rhs.a;
361  return lhs;
362 }
363 
365 inline Color& operator-=( Color& lhs, const Color& rhs)
366 {
367  lhs.r -= rhs.r;
368  lhs.g -= rhs.g;
369  lhs.b -= rhs.b;
370  lhs.a -= rhs.a;
371  return lhs;
372 }
373 
375 inline Color& operator*=( Color& lhs, const Color& rhs)
376 {
377  lhs.r *= rhs.r;
378  lhs.g *= rhs.g;
379  lhs.b *= rhs.b;
380  lhs.a *= rhs.a;
381  return lhs;
382 }
383 
385 inline Color& operator/=( Color& lhs, const Color& rhs)
386 {
387  lhs.r /= rhs.r;
388  lhs.g /= rhs.g;
389  lhs.b /= rhs.b;
390  lhs.a /= rhs.a;
391  return lhs;
392 }
393 
395 inline Color operator+( const Color& lhs, const Color& rhs)
396 {
397  return Color( lhs.r + rhs.r, lhs.g + rhs.g, lhs.b + rhs.b, lhs.a + rhs.a);
398 }
399 
401 inline Color operator-( const Color& lhs, const Color& rhs)
402 {
403  return Color( lhs.r - rhs.r, lhs.g - rhs.g, lhs.b - rhs.b, lhs.a - rhs.a);
404 }
405 
407 inline Color operator*( const Color& lhs, const Color& rhs)
408 {
409  return Color( lhs.r * rhs.r, lhs.g * rhs.g, lhs.b * rhs.b, lhs.a * rhs.a);
410 }
411 
413 inline Color operator/( const Color& lhs, const Color& rhs)
414 {
415  return Color( lhs.r / rhs.r, lhs.g / rhs.g, lhs.b / rhs.b, lhs.a / rhs.a);
416 }
417 
419 inline Color operator-( const Color& c)
420 {
421  return Color( -c.r, -c.g, -c.b, -c.a);
422 }
423 
424 
425 
426 //------ Free operator *=, /=, *, and / definitions for scalars ---------------
427 
429 inline Color& operator*=( Color& c, Float32 s)
430 {
431  c.r *= s;
432  c.g *= s;
433  c.b *= s;
434  c.a *= s;
435  return c;
436 }
437 
439 inline Color& operator/=( Color& c, Float32 s)
440 {
441  const Float32 f = 1.0f / s;
442  c.r *= f;
443  c.g *= f;
444  c.b *= f;
445  c.a *= f;
446  return c;
447 }
448 
450 inline Color operator*( const Color& c, Float32 s)
451 {
452  return Color( c.r * s, c.g * s, c.b * s, c.a * s);
453 }
454 
457 inline Color operator*( Float32 s, const Color& c)
458 {
459  return Color( s * c.r, s * c.g, s* c.b, s * c.a);
460 }
461 
463 inline Color operator/( const Color& c, Float32 s)
464 {
465  const Float32 f = 1.0f / s;
466  return Color( c.r * f, c.g * f, c.b * f, c.a * f);
467 }
468 
469 
470 //------ Function Overloads for Color Algorithms ------------------------------
471 
472 
474 inline Color abs( const Color& c)
475 {
476  return Color( abs( c.r), abs( c.g), abs( c.b), abs( c.a));
477 }
478 
480 inline Color acos( const Color& c)
481 {
482  return Color( acos( c.r), acos( c.g), acos( c.b), acos( c.a));
483 }
484 
486 inline bool all( const Color& c)
487 {
488  return (c.r != 0.0f) && (c.g != 0.0f) && (c.b != 0.0f) && (c.a != 0.0f);
489 }
490 
492 inline bool any( const Color& c)
493 {
494  return (c.r != 0.0f) || (c.g != 0.0f) || (c.b != 0.0f) || (c.a != 0.0f);
495 }
496 
498 inline Color asin( const Color& c)
499 {
500  return Color( asin( c.r), asin( c.g), asin( c.b), asin( c.a));
501 }
502 
504 inline Color atan( const Color& c)
505 {
506  return Color( atan( c.r), atan( c.g), atan( c.b), atan( c.a));
507 }
508 
512 inline Color atan2( const Color& c, const Color& d)
513 {
514  return Color( atan2( c.r, d.r), atan2( c.g, d.g), atan2( c.b, d.b), atan2( c.a, d.a));
515 }
516 
519 inline Color ceil( const Color& c)
520 {
521  return Color( ceil( c.r), ceil( c.g), ceil( c.b), ceil( c.a));
522 }
523 
525 inline Color clamp( const Color& c, const Color& low, const Color& high)
526 {
527  return Color( clamp( c.r, low.r, high.r),
528  clamp( c.g, low.g, high.g),
529  clamp( c.b, low.b, high.b),
530  clamp( c.a, low.a, high.a));
531 }
532 
534 inline Color clamp( const Color& c, const Color& low, Float32 high)
535 {
536  return Color( clamp( c.r, low.r, high),
537  clamp( c.g, low.g, high),
538  clamp( c.b, low.b, high),
539  clamp( c.a, low.a, high));
540 }
541 
543 inline Color clamp( const Color& c, Float32 low, const Color& high)
544 {
545  return Color( clamp( c.r, low, high.r),
546  clamp( c.g, low, high.g),
547  clamp( c.b, low, high.b),
548  clamp( c.a, low, high.a));
549 }
550 
552 inline Color clamp( const Color& c, Float32 low, Float32 high)
553 {
554  return Color( clamp( c.r, low, high),
555  clamp( c.g, low, high),
556  clamp( c.b, low, high),
557  clamp( c.a, low, high));
558 }
559 
561 inline Color cos( const Color& c)
562 {
563  return Color( cos( c.r), cos( c.g), cos( c.b), cos( c.a));
564 }
565 
567 inline Color degrees( const Color& c)
568 {
569  return Color( degrees( c.r), degrees( c.g), degrees( c.b), degrees( c.a));
570 }
571 
574 inline Color elementwise_max( const Color& lhs, const Color& rhs)
575 {
576  return Color( base::max MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
577  base::max MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
578  base::max MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
579  base::max MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
580 }
581 
584 inline Color elementwise_min( const Color& lhs, const Color& rhs)
585 {
586  return Color( base::min MI_PREVENT_MACRO_EXPAND ( lhs.r, rhs.r),
587  base::min MI_PREVENT_MACRO_EXPAND ( lhs.g, rhs.g),
588  base::min MI_PREVENT_MACRO_EXPAND ( lhs.b, rhs.b),
589  base::min MI_PREVENT_MACRO_EXPAND ( lhs.a, rhs.a));
590 }
591 
593 inline Color exp( const Color& c)
594 {
595  return Color( exp( c.r), exp( c.g), exp( c.b), exp( c.a));
596 }
597 
599 inline Color exp2( const Color& c)
600 {
601  return Color( exp2( c.r), exp2( c.g), exp2( c.b), exp2( c.a));
602 }
603 
606 inline Color floor( const Color& c)
607 {
608  return Color( floor( c.r), floor( c.g), floor( c.b), floor( c.a));
609 }
610 
614 inline Color fmod( const Color& a, const Color& b)
615 {
616  return Color( fmod( a.r, b.r), fmod( a.g, b.g), fmod( a.b, b.b), fmod( a.a, b.a));
617 }
618 
622 inline Color fmod( const Color& a, Float32 b)
623 {
624  return Color( fmod( a.r, b), fmod( a.g, b), fmod( a.b, b), fmod( a.a, b));
625 }
626 
628 inline Color frac( const Color& c)
629 {
630  return Color( frac( c.r), frac( c.g), frac( c.b), frac( c.a));
631 }
632 
641  const Color& color,
642  Float32 gamma_factor)
643 {
644  mi_math_assert( gamma_factor > 0);
645  const Float32 f = Float32(1.0) / gamma_factor;
646  return Color( fast_pow( color.r, f),
647  fast_pow( color.g, f),
648  fast_pow( color.b, f),
649  fast_pow( color.a, f));
650 }
651 
653 inline bool is_approx_equal(
654  const Color& lhs,
655  const Color& rhs,
656  Float32 e)
657 {
658  return is_approx_equal( lhs.r, rhs.r, e)
659  && is_approx_equal( lhs.g, rhs.g, e)
660  && is_approx_equal( lhs.b, rhs.b, e)
661  && is_approx_equal( lhs.a, rhs.a, e);
662 }
663 
666 inline Color lerp(
667  const Color& c1,
668  const Color& c2,
669  const Color& t)
670 {
671  return Color( lerp( c1.r, c2.r, t.r),
672  lerp( c1.g, c2.g, t.g),
673  lerp( c1.b, c2.b, t.b),
674  lerp( c1.a, c2.a, t.a));
675 }
676 
679 inline Color lerp(
680  const Color& c1,
681  const Color& c2,
682  Float32 t)
683 {
684  // equivalent to: return c1 * (Float32(1)-t) + c2 * t;
685  return Color( lerp( c1.r, c2.r, t),
686  lerp( c1.g, c2.g, t),
687  lerp( c1.b, c2.b, t),
688  lerp( c1.a, c2.a, t));
689 }
690 
692 inline Color log( const Color& c)
693 {
694  return Color( log( c.r), log( c.g), log( c.b), log( c.a));
695 }
696 
699 {
700  return Color( log2 MI_PREVENT_MACRO_EXPAND (c.r),
704 }
705 
707 inline Color log10( const Color& c)
708 {
709  return Color( log10( c.r), log10( c.g), log10( c.b), log10( c.a));
710 }
711 
716 inline Color modf( const Color& c, Color& i)
717 {
718  return Color( modf( c.r, i.r), modf( c.g, i.g), modf( c.b, i.b), modf( c.a, i.a));
719 }
720 
722 inline Color pow( const Color& a, const Color& b)
723 {
724  return Color( pow( a.r, b.r), pow( a.g, b.g), pow( a.b, b.b), pow( a.a, b.a));
725 }
726 
728 inline Color pow( const Color& a, Float32 b)
729 {
730  return Color( pow( a.r, b), pow( a.g, b), pow( a.b, b), pow( a.a, b));
731 }
732 
734 inline Color radians( const Color& c)
735 {
736  return Color( radians( c.r), radians( c.g), radians( c.b), radians( c.a));
737 }
738 
740 inline Color round( const Color& c)
741 {
742  return Color( round( c.r), round( c.g), round( c.b), round( c.a));
743 }
744 
746 inline Color rsqrt( const Color& c)
747 {
748  return Color( rsqrt( c.r), rsqrt( c.g), rsqrt( c.b), rsqrt( c.a));
749 }
750 
752 inline Color saturate( const Color& c)
753 {
754  return Color( saturate( c.r), saturate( c.g), saturate( c.b), saturate( c.a));
755 }
756 
758 inline Color sign( const Color& c)
759 {
760  return Color( sign( c.r), sign( c.g), sign( c.b), sign( c.a));
761 }
762 
764 inline Color sin( const Color& c)
765 {
766  return Color( sin( c.r), sin( c.g), sin( c.b), sin( c.a));
767 }
768 
772 inline void sincos( const Color& a, Color& s, Color& c)
773 {
774  sincos( a.r, s.r, c.r);
775  sincos( a.g, s.g, c.g);
776  sincos( a.b, s.b, c.b);
777  sincos( a.a, s.a, c.a);
778 }
779 
785 inline Color smoothstep( const Color& a, const Color& b, const Color& c)
786 {
787  return Color( smoothstep( a.r, b.r, c.r),
788  smoothstep( a.g, b.g, c.g),
789  smoothstep( a.b, b.b, c.b),
790  smoothstep( a.a, b.a, c.a));
791 }
792 
798 inline Color smoothstep( const Color& a, const Color& b, Float32 x)
799 {
800  return Color( smoothstep( a.r, b.r, x),
801  smoothstep( a.g, b.g, x),
802  smoothstep( a.b, b.b, x),
803  smoothstep( a.a, b.a, x));
804 }
805 
807 inline Color sqrt( const Color& c)
808 {
809  return Color( sqrt( c.r), sqrt( c.g), sqrt( c.b), sqrt( c.a));
810 }
811 
813 inline Color step( const Color& a, const Color& c)
814 {
815  return Color( step( a.r, c.r), step( a.g, c.g), step( a.g, c.b), step( a.a, c.a));
816 }
817 
819 inline Color tan( const Color& c)
820 {
821  return Color( tan( c.r), tan( c.g), tan( c.b), tan( c.a));
822 }
823 
825 inline bool isfinite MI_PREVENT_MACRO_EXPAND (const Color& c)
826 {
831 }
832 
835 {
840 }
841 
843 inline bool isnan MI_PREVENT_MACRO_EXPAND (const Color& c)
844 {
845  return isnan MI_PREVENT_MACRO_EXPAND (c.r)
849 }
850 
854 MI_HOST_DEVICE_INLINE void to_rgbe( const Color& color, Uint32& rgbe)
855 {
856  to_rgbe( &color.r, rgbe);
857 }
858 
862 MI_HOST_DEVICE_INLINE void to_rgbe( const Color& color, Uint8 rgbe[4])
863 {
864  to_rgbe( &color.r, rgbe);
865 }
866 
870 MI_HOST_DEVICE_INLINE void from_rgbe( const Uint8 rgbe[4], Color& color)
871 {
872  from_rgbe( rgbe, &color.r);
873  color.a = 1.0f;
874 }
875 
879 MI_HOST_DEVICE_INLINE void from_rgbe( const Uint32 rgbe, Color& color)
880 {
881  from_rgbe( rgbe, &color.r);
882  color.a = 1.0f;
883 }
884 
885 //------ Definitions of member functions --------------------------------------
886 
887 #ifndef MI_FOR_DOXYGEN_ONLY
888 
889 inline Color Color::clip(
890  Clip_mode mode,
891  bool desaturate) const
892 {
893  Float32 max_val = 1.0f;
894  Color col = *this;
895  if( col.a < 0.0f)
896  col.a = 0.0f;
897  if( mode == CLIP_RGB) {
898  if( col.a < col.r) col.a = col.r;
899  if( col.a < col.g) col.a = col.g;
900  if( col.a < col.b) col.a = col.b;
901  }
902  if( col.a > 1.0f)
903  col.a = 1.0f;
904  if( mode == CLIP_ALPHA)
905  max_val = col.a;
906  if( desaturate)
907  return col.desaturate(max_val);
908  return Color( math::clamp( col.r, 0.0f, max_val),
909  math::clamp( col.g, 0.0f, max_val),
910  math::clamp( col.b, 0.0f, max_val),
911  col.a);
912 }
913 
914 inline Color Color::desaturate( Float32 maxval) const
915 {
916  // We compute a new color based on s with the vector formula c(s) = (N + s(I-N)) c0 where N is
917  // the 3 by 3 matrix with the [1,3] vector b with the NTSC values as its rows, and c0 is the
918  // original color. All c(s) have the same brightness, b*c0, as the original color. It can be
919  // algebraically shown that the hue of the c(s) is the same as for c0. Hue can be expressed with
920  // the formula h(c) = (I-A)c, where A is a 3 by 3 matrix with all 1/3 values. Essentially,
921  // h(c(s)) == h(c0), since A*N == N
922 
923  Float32 t; // temp for saturation calc
924 
925  Float32 axis = ntsc_intensity();
926  if( axis < 0) // negative: black, exit.
927  return Color( 0, 0, 0, a);
928  if( axis > maxval) // too bright: all white, exit.
929  return Color( maxval, maxval, maxval, a);
930 
931  Float32 drds = r - axis; // calculate color axis and
932  Float32 dgds = g - axis; // dcol/dsat. sat==1 at the
933  Float32 dbds = b - axis; // outset.
934 
935  Float32 sat = 1.0f; // initial saturation
936  bool clip = false; // outside range, desaturate
937 
938  if( r > maxval) { // red > maxval?
939  clip = true;
940  t = (maxval - axis) / drds;
941  if( t < sat) sat = t;
942  } else if( r < 0) { // red < 0?
943  clip = true;
944  t = -axis / drds;
945  if( t < sat) sat = t;
946  }
947  if( g > maxval) { // green > maxval?
948  clip = true;
949  t = (maxval - axis) / dgds;
950  if( t < sat) sat = t;
951  } else if( g < 0) { // green < 0?
952  clip = true;
953  t = -axis / dgds;
954  if( t < sat) sat = t;
955  }
956  if( b > maxval) { // blue > maxval?
957  clip = true;
958  t = (maxval - axis) / dbds;
959  if( t < sat) sat = t;
960  } else if( b < 0) { // blue < 0?
961  clip = true;
962  t = -axis / dbds;
963  if( t < sat) sat = t;
964  }
965  if( clip) {
966  // negative solutions should not be possible
967  mi_math_assert( sat >= 0);
968  // clamp to avoid numerical imprecision
969  return Color( math::clamp( axis + drds * sat, 0.0f, maxval),
970  math::clamp( axis + dgds * sat, 0.0f, maxval),
971  math::clamp( axis + dbds * sat, 0.0f, maxval),
972  a);
973  }
974  mi_math_assert( r >= 0 && r <= maxval);
975  mi_math_assert( g >= 0 && g <= maxval);
976  mi_math_assert( b >= 0 && b <= maxval);
977  return *this;
978 }
979 
980 #endif // MI_FOR_DOXYGEN_ONLY
981  // end group mi_math_color
983 
984 } // namespace math
985 
986 } // namespace mi
987 
988 #endif // MI_MATH_COLOR_H