/** * 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); }