diff --git a/source/base/colour.h b/source/base/colour.h index 74552f1ab..b9a426ac0 100644 --- a/source/base/colour.h +++ b/source/base/colour.h @@ -87,7 +87,7 @@ class GenericColour; template class GenericTransColour; -template +template class GenericRGBEColour; /// @name Colour Channel Luminance @@ -170,15 +170,16 @@ class GenericRGBColour mColour[BLUE] = col.blue(); } - template - inline explicit GenericRGBColour(const GenericRGBEColour& col) + template + inline explicit GenericRGBColour(const GenericRGBEColour& col) { - if (col.mData[GenericRGBEColour::EXP] > std::numeric_limits::min()) + if (col.mData[GenericRGBEColour::EXP] > std::numeric_limits::min()) { - double expFactor = ldexp(1.0,(int)col.mData[GenericRGBEColour::EXP]-(int)(BIAS+8)); - mColour[RED] = (col.mData[GenericRGBEColour::RED]) * expFactor; - mColour[GREEN] = (col.mData[GenericRGBEColour::GREEN]) * expFactor; - mColour[BLUE] = (col.mData[GenericRGBEColour::BLUE]) * expFactor; + double expFactor = ldexp(1.0,(int)col.mData[GenericRGBEColour::EXP]-(int)(BIAS+8)); + double quantizationFix = (QUANTIZE_TO_NEAREST? 0.0 : 0.5); + mColour[RED] = (col.mData[GenericRGBEColour::RED] + quantizationFix) * expFactor; + mColour[GREEN] = (col.mData[GenericRGBEColour::GREEN] + quantizationFix) * expFactor; + mColour[BLUE] = (col.mData[GenericRGBEColour::BLUE] + quantizationFix) * expFactor; } else { @@ -2074,12 +2075,14 @@ typedef GenericTransColour PreciseTransColour; ///< Hig /// @author Christoph Lipka /// @author Based on MegaPOV HDR code written by Mael and Christoph Hormann /// -/// @tparam BIAS Bias to use for the exponent. -/// A value of 128 matches Greg Ward's original proposal. -/// @tparam T Type to use for the colour components. -/// Defaults to unsigned char. +/// @tparam BIAS Bias to use for the exponent. +/// A value of 128 matches Greg Ward's original proposal. +/// @tparam QUANTIZE_TO_NEAREST Whether quantization should use round-to-nearest mode, as opposed to rounding +/// towards zero and compensating upon decoding as in Greg Ward's original proposal. +/// @tparam T Type to use for the colour components. +/// Defaults to unsigned char. /// -template +template class GenericRGBEColour { public: @@ -2099,10 +2102,7 @@ class GenericRGBEColour inline GenericRGBEColour() { - mData[RED] = 0; - mData[GREEN] = 0; - mData[BLUE] = 0; - mData[EXP] = 0; + SetToZero(mData); } inline GenericRGBEColour(const GenericRGBEColour& col) @@ -2115,51 +2115,26 @@ class GenericRGBEColour inline explicit GenericRGBEColour(ColourChannel red, ColourChannel green, ColourChannel blue) { - RGBColour col (red, green, blue); - double scaleFactor; - if (ComputeExponent(col, mData[EXP], scaleFactor)) - { - mData[RED] = clipToType(floor(col.red() * scaleFactor)); - mData[GREEN] = clipToType(floor(col.green() * scaleFactor)); - mData[BLUE] = clipToType(floor(col.blue() * scaleFactor)); - } + if (QUANTIZE_TO_NEAREST) + Quantize(mData, RGBColour(red, green, blue), RGBColour(0.5)); else - { - mData[RED] = mData[GREEN] = mData[BLUE] = 0; - mData[EXP] = std::numeric_limits::min(); - } + Quantize(mData, RGBColour(red, green, blue)); } inline explicit GenericRGBEColour(const RGBColour& col) { - double scaleFactor; - if (ComputeExponent(col, mData[EXP], scaleFactor)) - { - mData[RED] = clipToType(floor(col.red() * scaleFactor + 0.5)); - mData[GREEN] = clipToType(floor(col.green() * scaleFactor + 0.5)); - mData[BLUE] = clipToType(floor(col.blue() * scaleFactor + 0.5)); - } + if (QUANTIZE_TO_NEAREST) + Quantize(mData, col, RGBColour(0.5)); else - { - mData[RED] = mData[GREEN] = mData[BLUE] = 0; - mData[EXP] = std::numeric_limits::min(); - } + Quantize(mData, col); } inline explicit GenericRGBEColour(const RGBColour& col, const RGBColour& dither) { - double scaleFactor; - if (ComputeExponent(col, mData[EXP], scaleFactor)) - { - mData[RED] = clip(floor(col.red() * scaleFactor + 0.5 + dither.red())); - mData[GREEN] = clip(floor(col.green() * scaleFactor + 0.5 + dither.green())); - mData[BLUE] = clip(floor(col.blue() * scaleFactor + 0.5 + dither.blue())); - } + if (QUANTIZE_TO_NEAREST) + Quantize(mData, col, RGBColour(0.5) + dither); else - { - mData[RED] = mData[GREEN] = mData[BLUE] = 0; - mData[EXP] = std::numeric_limits::min(); - } + Quantize(mData, col, dither); } inline const DATA& operator*() const @@ -2178,11 +2153,8 @@ class GenericRGBEColour inline static bool ComputeExponent(const RGBColour& col, T& biasedExponent, double& scaleFactor) { - ColourChannel maxChannel; - if (std::numeric_limits::is_signed) - maxChannel = col.MaxAbs(); - else - maxChannel = col.Max(); + // Determine the magnitude of the colour value. + ColourChannel maxChannel = (std::numeric_limits::is_signed ? col.MaxAbs() : col.Max()); if (maxChannel <= 1.0e-32) // TODO - magic number return false; @@ -2190,17 +2162,76 @@ class GenericRGBEColour int exponent; double maxChannelMantissa = frexp(maxChannel, &exponent); biasedExponent = clipToType(exponent + BIAS); + scaleFactor = ldexp(std::numeric_limits::max() + 1.0, BIAS-biasedExponent); + return true; + } - if (biasedExponent != exponent + BIAS) - maxChannelMantissa = ldexp(maxChannelMantissa, exponent + BIAS - biasedExponent); + inline static void SetToZero(DATA& data) + { + data[RED] = data[GREEN] = data[BLUE] = 0; + data[EXP] = std::numeric_limits::min(); + } - scaleFactor = (std::numeric_limits::max() + 1.0) * maxChannelMantissa / maxChannel; - return true; + /// @param[out] data The quantized data. + /// @param[in] col The colour to quantize. + inline static void Quantize(DATA& data, const RGBColour& col) + { + double scaleFactor; + if (ComputeExponent(col, data[EXP], scaleFactor)) + { + RGBColour colMantissa = col * scaleFactor; + data[RED] = clipToType(floor(colMantissa.red())); + data[GREEN] = clipToType(floor(colMantissa.green())); + data[BLUE] = clipToType(floor(colMantissa.blue())); + } + else + SetToZero(data); + } + + /// @param[out] data The quantized data. + /// @param[in] col The colour to quantize. + /// @param[in] encOff An offset to add to the mantissa before quantization. + inline static void Quantize(DATA& data, const RGBColour& col, const RGBColour& encOff) + { + double scaleFactor; + if (ComputeExponent(col, data[EXP], scaleFactor)) + { + RGBColour colMantissa = col * scaleFactor + encOff; + + // The additional encoding offset might have resulted in one of the mantissas to exceed the maximum, + // or make all drop below half the maximum; in both cases we want to adjust the exponent and mantissas + // accordingly. + ColourChannel maxChannel = (std::numeric_limits::is_signed ? colMantissa.MaxAbs() : colMantissa.Max()); + if (maxChannel > std::numeric_limits::max()) + { + if (data[EXP] < std::numeric_limits::max()) + { + data[EXP] ++; + scaleFactor *= 0.5; + colMantissa = col * scaleFactor + encOff; + } + } + else if (maxChannel * 2.0 <= std::numeric_limits::max()) + { + if (data[EXP] > std::numeric_limits::min()) + { + data[EXP] --; + scaleFactor *= 2.0; + colMantissa = col * scaleFactor + encOff; + } + } + + data[RED] = clipToType(floor(colMantissa.red())); + data[GREEN] = clipToType(floor(colMantissa.green())); + data[BLUE] = clipToType(floor(colMantissa.blue())); + } + else + SetToZero(data); } }; -typedef GenericRGBEColour<128> RadianceHDRColour; ///< RGBE format as originally proposed by Greg Ward. -typedef GenericRGBEColour<250> PhotonColour; ///< RGBE format as adapted by Nathan Kopp for photon mapping. +typedef GenericRGBEColour<128,false> RadianceHDRColour; ///< RGBE format as originally proposed by Greg Ward. +typedef GenericRGBEColour<250,true> PhotonColour; ///< RGBE format as adapted by Nathan Kopp for photon mapping. } diff --git a/source/base/version.h b/source/base/version.h index fa946e325..a4ca4eea1 100644 --- a/source/base/version.h +++ b/source/base/version.h @@ -45,7 +45,7 @@ #define OFFICIAL_VERSION_STRING "3.7.1" #define OFFICIAL_VERSION_NUMBER 371 -#define POV_RAY_PRERELEASE "alpha.8492620" +#define POV_RAY_PRERELEASE "alpha.8497793" #if (POV_RAY_IS_AUTOBUILD == 1) && ((POV_RAY_IS_OFFICIAL == 1) || (POV_RAY_IS_SEMI_OFFICIAL == 1)) #ifdef POV_RAY_PRERELEASE diff --git a/unix/VERSION b/unix/VERSION index 4e7d40370..368bcc068 100644 --- a/unix/VERSION +++ b/unix/VERSION @@ -1 +1 @@ -3.7.1-alpha.8492620 +3.7.1-alpha.8497793