Skip to content

Commit

Permalink
Eliminated some inconsistencies in RGBE-format colour handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
c-lipka committed Feb 27, 2016
1 parent 9762bc5 commit f6888be
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 64 deletions.
155 changes: 93 additions & 62 deletions source/base/colour.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class GenericColour;
template<typename T>
class GenericTransColour;

template<int BIAS, typename T = unsigned char>
template<int BIAS, bool QUANTIZE_TO_NEAREST, typename T = unsigned char>
class GenericRGBEColour;

/// @name Colour Channel Luminance
Expand Down Expand Up @@ -170,15 +170,16 @@ class GenericRGBColour
mColour[BLUE] = col.blue();
}

template<int BIAS, typename T2>
inline explicit GenericRGBColour(const GenericRGBEColour<BIAS,T2>& col)
template<int BIAS, bool QUANTIZE_TO_NEAREST, typename T2>
inline explicit GenericRGBColour(const GenericRGBEColour<BIAS,QUANTIZE_TO_NEAREST,T2>& col)
{
if (col.mData[GenericRGBEColour<BIAS,T2>::EXP] > std::numeric_limits<T2>::min())
if (col.mData[GenericRGBEColour<BIAS,QUANTIZE_TO_NEAREST,T2>::EXP] > std::numeric_limits<T2>::min())
{
double expFactor = ldexp(1.0,(int)col.mData[GenericRGBEColour<BIAS,T2>::EXP]-(int)(BIAS+8));
mColour[RED] = (col.mData[GenericRGBEColour<BIAS,T2>::RED]) * expFactor;
mColour[GREEN] = (col.mData[GenericRGBEColour<BIAS,T2>::GREEN]) * expFactor;
mColour[BLUE] = (col.mData[GenericRGBEColour<BIAS,T2>::BLUE]) * expFactor;
double expFactor = ldexp(1.0,(int)col.mData[GenericRGBEColour<BIAS,QUANTIZE_TO_NEAREST,T2>::EXP]-(int)(BIAS+8));
double quantizationFix = (QUANTIZE_TO_NEAREST? 0.0 : 0.5);
mColour[RED] = (col.mData[GenericRGBEColour<BIAS,QUANTIZE_TO_NEAREST,T2>::RED] + quantizationFix) * expFactor;
mColour[GREEN] = (col.mData[GenericRGBEColour<BIAS,QUANTIZE_TO_NEAREST,T2>::GREEN] + quantizationFix) * expFactor;
mColour[BLUE] = (col.mData[GenericRGBEColour<BIAS,QUANTIZE_TO_NEAREST,T2>::BLUE] + quantizationFix) * expFactor;
}
else
{
Expand Down Expand Up @@ -2074,12 +2075,14 @@ typedef GenericTransColour<PreciseColourChannel> 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<int BIAS, typename T>
template<int BIAS, bool QUANTIZE_TO_NEAREST, typename T>
class GenericRGBEColour
{
public:
Expand All @@ -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)
Expand All @@ -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<T>(floor(col.red() * scaleFactor));
mData[GREEN] = clipToType<T>(floor(col.green() * scaleFactor));
mData[BLUE] = clipToType<T>(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<T>::min();
}
Quantize(mData, RGBColour(red, green, blue));
}

inline explicit GenericRGBEColour(const RGBColour& col)
{
double scaleFactor;
if (ComputeExponent(col, mData[EXP], scaleFactor))
{
mData[RED] = clipToType<T>(floor(col.red() * scaleFactor + 0.5));
mData[GREEN] = clipToType<T>(floor(col.green() * scaleFactor + 0.5));
mData[BLUE] = clipToType<T>(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<T>::min();
}
Quantize(mData, col);
}

inline explicit GenericRGBEColour(const RGBColour& col, const RGBColour& dither)
{
double scaleFactor;
if (ComputeExponent(col, mData[EXP], scaleFactor))
{
mData[RED] = clip<T>(floor(col.red() * scaleFactor + 0.5 + dither.red()));
mData[GREEN] = clip<T>(floor(col.green() * scaleFactor + 0.5 + dither.green()));
mData[BLUE] = clip<T>(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<T>::min();
}
Quantize(mData, col, dither);
}

inline const DATA& operator*() const
Expand All @@ -2178,29 +2153,85 @@ class GenericRGBEColour

inline static bool ComputeExponent(const RGBColour& col, T& biasedExponent, double& scaleFactor)
{
ColourChannel maxChannel;
if (std::numeric_limits<T>::is_signed)
maxChannel = col.MaxAbs();
else
maxChannel = col.Max();
// Determine the magnitude of the colour value.
ColourChannel maxChannel = (std::numeric_limits<T>::is_signed ? col.MaxAbs() : col.Max());

if (maxChannel <= 1.0e-32) // TODO - magic number
return false;

int exponent;
double maxChannelMantissa = frexp(maxChannel, &exponent);
biasedExponent = clipToType<T>(exponent + BIAS);
scaleFactor = ldexp(std::numeric_limits<T>::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<T>::min();
}

scaleFactor = (std::numeric_limits<T>::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<T>(floor(colMantissa.red()));
data[GREEN] = clipToType<T>(floor(colMantissa.green()));
data[BLUE] = clipToType<T>(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<T>::is_signed ? colMantissa.MaxAbs() : colMantissa.Max());
if (maxChannel > std::numeric_limits<T>::max())
{
if (data[EXP] < std::numeric_limits<T>::max())
{
data[EXP] ++;
scaleFactor *= 0.5;
colMantissa = col * scaleFactor + encOff;
}
}
else if (maxChannel * 2.0 <= std::numeric_limits<T>::max())
{
if (data[EXP] > std::numeric_limits<T>::min())
{
data[EXP] --;
scaleFactor *= 2.0;
colMantissa = col * scaleFactor + encOff;
}
}

data[RED] = clipToType<T>(floor(colMantissa.red()));
data[GREEN] = clipToType<T>(floor(colMantissa.green()));
data[BLUE] = clipToType<T>(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.

}

Expand Down
2 changes: 1 addition & 1 deletion source/base/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion unix/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.7.1-alpha.8492620
3.7.1-alpha.8497793

0 comments on commit f6888be

Please sign in to comment.