169 lines
5.3 KiB
Text
169 lines
5.3 KiB
Text
/**
|
|
* PANDA 3D SOFTWARE
|
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
*
|
|
* All use of this software is subject to the terms of the revised BSD
|
|
* license. You should have received a copy of this license along
|
|
* with this source code in a file named "LICENSE."
|
|
*
|
|
* @file convert_srgb.I
|
|
* @author rdb
|
|
* @date 2014-10-29
|
|
*/
|
|
|
|
/**
|
|
* Decodes the sRGB-encoded unsigned char value to a linearized float in the
|
|
* range 0-1.
|
|
*/
|
|
INLINE float decode_sRGB_float(unsigned char val) {
|
|
return to_linear_float_table[val];
|
|
}
|
|
|
|
/**
|
|
* Decodes the sRGB-encoded floating-point value in the range 0-1 to a
|
|
* linearized float in the range 0-1. Inputs outside this range produce
|
|
* invalid results.
|
|
*/
|
|
INLINE float decode_sRGB_float(float val) {
|
|
return (val <= 0.04045f)
|
|
? (val * (1.f / 12.92f))
|
|
: cpow((val + 0.055f) * (1.f / 1.055f), 2.4f);
|
|
}
|
|
|
|
/**
|
|
* Decodes the sRGB-encoded unsigned char value to a linearized unsigned char
|
|
* value.
|
|
*/
|
|
INLINE unsigned char decode_sRGB_uchar(unsigned char val) {
|
|
return to_linear_uchar_table[val];
|
|
}
|
|
|
|
/**
|
|
* Decodes the sRGB-encoded floating-point value in the range 0-1 to a
|
|
* linearized unsigned char value. Inputs outside this range are clamped.
|
|
*/
|
|
INLINE unsigned char decode_sRGB_uchar(float val) {
|
|
return (val <= 0.04045f)
|
|
? (unsigned char)(std::max(0.f, val) * (255.f / 12.92f) + 0.5f)
|
|
: (unsigned char)(cpow((std::min(val, 1.f) + 0.055f) * (1.f / 1.055f), 2.4f) * 255.f + 0.5f);
|
|
}
|
|
|
|
/**
|
|
* Encodes the linearized unsigned char value to an sRGB-encoded floating-
|
|
* point value in ther range 0-1.
|
|
*/
|
|
INLINE float
|
|
encode_sRGB_float(unsigned char val) {
|
|
// This seems like a very unlikely use case, so I didn't bother making a
|
|
// look-up table for this.
|
|
return (val == 0) ? 0
|
|
: (1.055f * cpow((float)val * (1.f / 255.f), 0.41666f) - 0.055f);
|
|
}
|
|
|
|
/**
|
|
* Encodes the linearized floating-point value in the range 0-1 to an sRGB-
|
|
* encoded float in the range 0-1. Inputs outside this range produce invalid
|
|
* results.
|
|
*/
|
|
INLINE float
|
|
encode_sRGB_float(float val) {
|
|
return (val < 0.0031308f)
|
|
? (val * 12.92f)
|
|
: (1.055f * cpow(val, 0.41666f) - 0.055f);
|
|
}
|
|
|
|
/**
|
|
* Encodes the linearized unsigned char value to an sRGB-encoded unsigned char
|
|
* value.
|
|
*/
|
|
INLINE unsigned char
|
|
encode_sRGB_uchar(unsigned char val) {
|
|
return to_srgb8_table[val];
|
|
}
|
|
|
|
/**
|
|
* Encodes the linearized floating-point value in the range 0-1 to an sRGB-
|
|
* encoded unsigned char value. Inputs outside this range are clamped.
|
|
*
|
|
* When SSE2 support is known at compile time, this automatically uses an
|
|
* optimized version. Otherwise, it does not attempt runtime CPU detection.
|
|
* If you know that SSE2 is supported (ie. if the function
|
|
* has_sse2_sRGB_encode() returns true) you should call encode_sRGB_uchar_sse2
|
|
* instead.
|
|
*/
|
|
INLINE unsigned char
|
|
encode_sRGB_uchar(float val) {
|
|
#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
|
|
// Use a highly optimized approximation that has more than enough accuracy
|
|
// for an unsigned char.
|
|
return encode_sRGB_uchar_sse2(val);
|
|
#else
|
|
return (val < 0.0031308f)
|
|
? (unsigned char) (std::max(0.f, val) * 3294.6f + 0.5f)
|
|
: (unsigned char) (269.025f * cpow(std::min(val, 1.f), 0.41666f) - 13.525f);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Encodes the linearized floating-point color value an sRGB-encoded xel in
|
|
* the range 0-255.
|
|
*
|
|
* When SSE2 support is known at compile time, this automatically uses an
|
|
* optimized version. Otherwise, it does not attempt runtime CPU detection.
|
|
* If you know that SSE2 is supported (ie. if the function
|
|
* has_sse2_sRGB_encode() returns true) you should call encode_sRGB_uchar_sse2
|
|
* instead.
|
|
*/
|
|
INLINE void
|
|
encode_sRGB_uchar(const LColorf &color, xel &into) {
|
|
#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
|
|
// SSE2 support compiled-in; we're guaranteed to have it.
|
|
encode_sRGB_uchar_sse2(color, into);
|
|
#else
|
|
// Boring, slow, non-SSE2 version.
|
|
PPM_ASSIGN(into,
|
|
encode_sRGB_uchar(color[0]),
|
|
encode_sRGB_uchar(color[1]),
|
|
encode_sRGB_uchar(color[2]));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Encodes the linearized floating-point color value an sRGB-encoded xel and
|
|
* alpha in the range 0-255. The alpha value is not sRGB-encoded.
|
|
*
|
|
* When SSE2 support is known at compile time, this automatically uses an
|
|
* optimized version. Otherwise, it does not attempt runtime CPU detection.
|
|
* If you know that SSE2 is supported (ie. if the function
|
|
* has_sse2_sRGB_encode() returns true) you should call encode_sRGB_uchar_sse2
|
|
* instead.
|
|
*/
|
|
INLINE void
|
|
encode_sRGB_uchar(const LColorf &color, xel &into, xelval &into_alpha) {
|
|
#if defined(__SSE2__) || (_M_IX86_FP >= 2) || defined(_M_X64) || defined(_M_AMD64)
|
|
// SSE2 support compiled-in; we're guaranteed to have it.
|
|
encode_sRGB_uchar_sse2(color, into, into_alpha);
|
|
#else
|
|
// Boring, slow, non-SSE2 version.
|
|
PPM_ASSIGN(into,
|
|
encode_sRGB_uchar(color[0]),
|
|
encode_sRGB_uchar(color[1]),
|
|
encode_sRGB_uchar(color[2]));
|
|
|
|
into_alpha = (xelval) (color[3] * 255.f + 0.5f);
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Double-precision versions of the above.
|
|
*/
|
|
INLINE void
|
|
encode_sRGB_uchar(const LColord &color, xel &into) {
|
|
return encode_sRGB_uchar(LCAST(float, color), into);
|
|
}
|
|
|
|
INLINE void
|
|
encode_sRGB_uchar(const LColord &color, xel &into, xelval &into_alpha) {
|
|
return encode_sRGB_uchar(LCAST(float, color), into, into_alpha);
|
|
}
|