|
@@ -34,9 +34,24 @@
|
|
|
#include "console/engineAPI.h"
|
|
|
#endif
|
|
|
|
|
|
+#ifdef TORQUE_USE_LEGACY_GAMMA
|
|
|
const F32 gGamma = 2.2f;
|
|
|
const F32 gOneOverGamma = 1.f / 2.2f;
|
|
|
+#else
|
|
|
+const F32 gGamma = 2.4f;
|
|
|
+const F32 gOneOverGamma = 1.f / 2.4f;
|
|
|
const F32 gOneOver255 = 1.f / 255.f;
|
|
|
+#endif
|
|
|
+
|
|
|
+struct Hsb
|
|
|
+{
|
|
|
+ Hsb() :hue(0), sat(0), brightness(0) {};
|
|
|
+ Hsb(F64 h, F64 s, F64 b) :hue(h), sat(s), brightness(b) {};
|
|
|
+
|
|
|
+ F64 hue; ///Hue
|
|
|
+ F64 sat; ///Saturation
|
|
|
+ F64 brightness; //Brightness/Value/Lightness
|
|
|
+};
|
|
|
|
|
|
class ColorI;
|
|
|
|
|
@@ -55,9 +70,14 @@ public:
|
|
|
LinearColorF(const F32 in_r, const F32 in_g, const F32 in_b, const F32 in_a = 1.0f);
|
|
|
LinearColorF(const ColorI &color);
|
|
|
LinearColorF(const char* pStockColorName);
|
|
|
+ LinearColorF(const Hsb& color);
|
|
|
+
|
|
|
+ F32 srgbToLinearChannel(const F32 chan_col);
|
|
|
+ F32 linearChannelToSrgb(const F32 chan_col);
|
|
|
|
|
|
void set( const F32 in_r, const F32 in_g, const F32 in_b, const F32 in_a = 1.0f );
|
|
|
void set( const char* pStockColorName );
|
|
|
+ void set(const Hsb& color);
|
|
|
|
|
|
static const LinearColorF& StockColor( const char* pStockColorName );
|
|
|
StringTableEntry StockColor( void );
|
|
@@ -88,6 +108,7 @@ public:
|
|
|
U32 getARGBPack() const;
|
|
|
U32 getRGBAPack() const;
|
|
|
U32 getABGRPack() const;
|
|
|
+ Hsb getHSB() const;
|
|
|
|
|
|
void interpolate(const LinearColorF& in_rC1,
|
|
|
const LinearColorF& in_rC2,
|
|
@@ -126,16 +147,6 @@ public:
|
|
|
U8 blue;
|
|
|
U8 alpha;
|
|
|
|
|
|
- struct Hsb
|
|
|
- {
|
|
|
- Hsb() :hue(0), sat(0), brightness(0){};
|
|
|
- Hsb(F64 h, F64 s, F64 b) :hue(h), sat(s), brightness(b){};
|
|
|
-
|
|
|
- F64 hue; ///Hue
|
|
|
- F64 sat; ///Saturation
|
|
|
- F64 brightness; //Brightness/Value/Lightness
|
|
|
- };
|
|
|
-
|
|
|
public:
|
|
|
ColorI() : red(0), green(0), blue(0), alpha(0) {}
|
|
|
ColorI(const ColorI& in_rCopy);
|
|
@@ -247,6 +258,27 @@ public:
|
|
|
static void destroy( void );
|
|
|
};
|
|
|
|
|
|
+inline F32 LinearColorF::srgbToLinearChannel(const F32 chan_col)
|
|
|
+{
|
|
|
+ if (chan_col < 0.0405f) {
|
|
|
+ return chan_col / 12.92f;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return mPow((chan_col + 0.055f) / 1.055f, gGamma);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+inline F32 LinearColorF::linearChannelToSrgb(const F32 chan_col)
|
|
|
+{
|
|
|
+ if (chan_col <= 0.0031308f) {
|
|
|
+ return chan_col * 12.92f;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return 1.055f * mPow(chan_col, gOneOverGamma) - 0.055f;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
//------------------------------------------------------------------------------
|
|
|
//-------------------------------------- INLINES (LinearColorF)
|
|
|
//
|
|
@@ -441,6 +473,72 @@ inline F32 LinearColorF::luminance()
|
|
|
return red * 0.3f + green * 0.59f + blue * 0.11f;
|
|
|
}
|
|
|
|
|
|
+inline LinearColorF::LinearColorF(const Hsb& color)
|
|
|
+{
|
|
|
+ set(color);
|
|
|
+}
|
|
|
+
|
|
|
+inline void LinearColorF::set(const Hsb& color)
|
|
|
+{
|
|
|
+ F64 c = (color.brightness / 100.0) * (color.sat / 100.0);
|
|
|
+ F64 x = c * (1.0 - fabs(fmod(color.hue / 60.0, 2.0) - 1.0));
|
|
|
+ F64 m = (color.brightness / 100.0) - c;
|
|
|
+
|
|
|
+ F64 r = 0.0, g = 0.0, b = 0.0;
|
|
|
+ if (color.hue < 60.0) {
|
|
|
+ r = c; g = x; b = 0.0;
|
|
|
+ }
|
|
|
+ else if (color.hue < 120.0) {
|
|
|
+ r = x; g = c; b = 0.0;
|
|
|
+ }
|
|
|
+ else if (color.hue < 180.0) {
|
|
|
+ r = 0.0; g = c; b = x;
|
|
|
+ }
|
|
|
+ else if (color.hue < 240.0) {
|
|
|
+ r = 0.0; g = x; b = c;
|
|
|
+ }
|
|
|
+ else if (color.hue < 300.0) {
|
|
|
+ r = x; g = 0.0; b = c;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ r = c; g = 0.0; b = x;
|
|
|
+ }
|
|
|
+
|
|
|
+ red = static_cast<F32>(r + m);
|
|
|
+ green = static_cast<F32>(g + m);
|
|
|
+ blue = static_cast<F32>(b + m);
|
|
|
+ alpha = 1.0f; // Default alpha to 1.0
|
|
|
+}
|
|
|
+
|
|
|
+inline Hsb LinearColorF::getHSB() const
|
|
|
+{
|
|
|
+ F32 maxVal = mMax( red, mMax(green, blue));
|
|
|
+ F32 minVal = mMin(red, mMin(green, blue));
|
|
|
+ F32 delta = maxVal - minVal;
|
|
|
+
|
|
|
+ Hsb hsb;
|
|
|
+ hsb.brightness = maxVal * 100.0; // Convert to percentage
|
|
|
+ hsb.sat = (maxVal > 0.0f) ? (delta / maxVal) * 100.0 : 0.0;
|
|
|
+
|
|
|
+ if (delta > 0.0f) {
|
|
|
+ if (red == maxVal)
|
|
|
+ hsb.hue = 60.0 * mFmod(((green - blue) / delta), 6.0);
|
|
|
+ else if (green == maxVal)
|
|
|
+ hsb.hue = 60.0 * (((blue - red) / delta) + 2.0);
|
|
|
+ else
|
|
|
+ hsb.hue = 60.0 * (((red - green) / delta) + 4.0);
|
|
|
+
|
|
|
+ if (hsb.hue < 0.0)
|
|
|
+ hsb.hue += 360.0;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ hsb.hue = 0.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return hsb;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
//------------------------------------------------------------------------------
|
|
|
//-------------------------------------- INLINES (ColorI)
|
|
|
//
|
|
@@ -719,7 +817,7 @@ inline U16 ColorI::get4444() const
|
|
|
U16(U16(blue >> 4) << 0));
|
|
|
}
|
|
|
|
|
|
-inline ColorI::Hsb ColorI::getHSB() const
|
|
|
+inline Hsb ColorI::getHSB() const
|
|
|
{
|
|
|
// Normalize RGB values to [0, 1]
|
|
|
F64 rPercent = (F64)red / 255.0;
|
|
@@ -740,22 +838,22 @@ inline ColorI::Hsb ColorI::getHSB() const
|
|
|
S = delta / maxColor; // Saturation
|
|
|
|
|
|
// Compute hue
|
|
|
- if (fabs(maxColor - rPercent) < 1e-6)
|
|
|
+ if (mFabsD(maxColor - rPercent) < 1e-6)
|
|
|
{
|
|
|
H = 60.0 * ((gPercent - bPercent) / delta);
|
|
|
}
|
|
|
- else if (fabs(maxColor - gPercent) < 1e-6)
|
|
|
+ else if (mFabsD(maxColor - gPercent) < 1e-6)
|
|
|
{
|
|
|
H = 60.0 * (((bPercent - rPercent) / delta) + 2.0);
|
|
|
}
|
|
|
- else if (fabs(maxColor - bPercent) < 1e-6)
|
|
|
+ else if (mFabsD(maxColor - bPercent) < 1e-6)
|
|
|
{
|
|
|
H = 60.0 * (((rPercent - gPercent) / delta) + 4.0);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Prepare the output HSB struct
|
|
|
- ColorI::Hsb val;
|
|
|
+ Hsb val;
|
|
|
val.hue = H; // Round to nearest integer
|
|
|
val.sat = S * 100.0; // Convert to percentage
|
|
|
val.brightness = B * 100.0; // Convert to percentage
|
|
@@ -782,9 +880,9 @@ inline String ColorI::getHex() const
|
|
|
|
|
|
inline LinearColorF::LinearColorF( const ColorI &color)
|
|
|
{
|
|
|
- red = sSrgbToLinear[color.red],
|
|
|
- green = sSrgbToLinear[color.green],
|
|
|
- blue = sSrgbToLinear[color.blue],
|
|
|
+ red = srgbToLinearChannel(color.red * gOneOver255),
|
|
|
+ green = srgbToLinearChannel(color.green * gOneOver255),
|
|
|
+ blue = srgbToLinearChannel(color.blue * gOneOver255),
|
|
|
alpha = F32(color.alpha * gOneOver255);
|
|
|
}
|
|
|
|
|
@@ -799,14 +897,14 @@ inline ColorI LinearColorF::toColorI(const bool keepAsLinear)
|
|
|
else
|
|
|
{
|
|
|
#ifdef TORQUE_USE_LEGACY_GAMMA
|
|
|
- float r = mPow(red, gOneOverGamma);
|
|
|
- float g = mPow(green, gOneOverGamma);
|
|
|
- float b = mPow(blue, gOneOverGamma);
|
|
|
+ F32 r = mPow(red, gOneOverGamma);
|
|
|
+ F32 g = mPow(green, gOneOverGamma);
|
|
|
+ F32 b = mPow(blue, gOneOverGamma);
|
|
|
return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
|
|
|
#else
|
|
|
- float r = red < 0.0031308f ? 12.92f * red : 1.055f * mPow(red, 1.0f / 2.4f) - 0.055f;
|
|
|
- float g = green < 0.0031308f ? 12.92f * green : 1.055f * mPow(green, 1.0f / 2.4f) - 0.055f;
|
|
|
- float b = blue < 0.0031308f ? 12.92f * blue : 1.055f * mPow(blue, 1.0f / 2.4f) - 0.055f;
|
|
|
+ F32 r = linearChannelToSrgb(red);
|
|
|
+ F32 g = linearChannelToSrgb(green);
|
|
|
+ F32 b = linearChannelToSrgb(blue);
|
|
|
return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5f));
|
|
|
#endif
|
|
|
}
|
|
@@ -823,14 +921,14 @@ inline ColorI LinearColorF::toColorI(const bool keepAsLinear)
|
|
|
else
|
|
|
{
|
|
|
#ifdef TORQUE_USE_LEGACY_GAMMA
|
|
|
- float r = mPow(red, gOneOverGamma);
|
|
|
- float g = mPow(green, gOneOverGamma);
|
|
|
- float b = mPow(blue, gOneOverGamma);
|
|
|
+ F32 r = mPow(red, gOneOverGamma);
|
|
|
+ F32 g = mPow(green, gOneOverGamma);
|
|
|
+ F32 b = mPow(blue, gOneOverGamma);
|
|
|
return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
|
|
|
#else
|
|
|
- float r = red < 0.0031308f ? 12.92f * red : 1.055f * mPow(red, 1.0f / 2.4f) - 0.055f;
|
|
|
- float g = green < 0.0031308f ? 12.92f * green : 1.055f * mPow(green, 1.0f / 2.4f) - 0.055f;
|
|
|
- float b = blue < 0.0031308f ? 12.92f * blue : 1.055f * mPow(blue, 1.0f / 2.4f) - 0.055f;
|
|
|
+ F32 r = linearChannelToSrgb(red);
|
|
|
+ F32 g = linearChannelToSrgb(green);
|
|
|
+ F32 b = linearChannelToSrgb(blue);
|
|
|
return ColorI(U8(r * 255.0f + 0.5f), U8(g * 255.0f + 0.5f), U8(b * 255.0f + 0.5f), U8(alpha * 255.0f + 0.5f));
|
|
|
#endif
|
|
|
}
|