|
@@ -129,33 +129,46 @@ struct [[nodiscard]] Color {
|
|
|
}
|
|
|
|
|
|
_FORCE_INLINE_ uint32_t to_rgbe9995() const {
|
|
|
- const float pow2to9 = 512.0f;
|
|
|
- const float B = 15.0f;
|
|
|
- const float N = 9.0f;
|
|
|
-
|
|
|
- float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
|
|
|
-
|
|
|
- float cRed = MAX(0.0f, MIN(sharedexp, r));
|
|
|
- float cGreen = MAX(0.0f, MIN(sharedexp, g));
|
|
|
- float cBlue = MAX(0.0f, MIN(sharedexp, b));
|
|
|
-
|
|
|
- float cMax = MAX(cRed, MAX(cGreen, cBlue));
|
|
|
-
|
|
|
- float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
|
|
|
-
|
|
|
- float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
|
|
|
-
|
|
|
- float exps = expp + 1.0f;
|
|
|
-
|
|
|
- if (0.0f <= sMax && sMax < pow2to9) {
|
|
|
- exps = expp;
|
|
|
- }
|
|
|
-
|
|
|
- float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
|
|
|
- float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
|
|
|
- float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
|
|
|
-
|
|
|
- return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27);
|
|
|
+ // https://github.com/microsoft/DirectX-Graphics-Samples/blob/v10.0.19041.0/MiniEngine/Core/Color.cpp
|
|
|
+ static const float kMaxVal = float(0x1FF << 7);
|
|
|
+ static const float kMinVal = float(1.f / (1 << 16));
|
|
|
+
|
|
|
+ // Clamp RGB to [0, 1.FF*2^16]
|
|
|
+ const float _r = CLAMP(r, 0.0f, kMaxVal);
|
|
|
+ const float _g = CLAMP(g, 0.0f, kMaxVal);
|
|
|
+ const float _b = CLAMP(b, 0.0f, kMaxVal);
|
|
|
+
|
|
|
+ // Compute the maximum channel, no less than 1.0*2^-15
|
|
|
+ const float MaxChannel = MAX(MAX(_r, _g), MAX(_b, kMinVal));
|
|
|
+
|
|
|
+ // Take the exponent of the maximum channel (rounding up the 9th bit) and
|
|
|
+ // add 15 to it. When added to the channels, it causes the implicit '1.0'
|
|
|
+ // bit and the first 8 mantissa bits to be shifted down to the low 9 bits
|
|
|
+ // of the mantissa, rounding the truncated bits.
|
|
|
+ union {
|
|
|
+ float f;
|
|
|
+ int32_t i;
|
|
|
+ } R, G, B, E;
|
|
|
+
|
|
|
+ E.f = MaxChannel;
|
|
|
+ E.i += 0x07804000; // Add 15 to the exponent and 0x4000 to the mantissa
|
|
|
+ E.i &= 0x7F800000; // Zero the mantissa
|
|
|
+
|
|
|
+ // This shifts the 9-bit values we need into the lowest bits, rounding as
|
|
|
+ // needed. Note that if the channel has a smaller exponent than the max
|
|
|
+ // channel, it will shift even more. This is intentional.
|
|
|
+ R.f = _r + E.f;
|
|
|
+ G.f = _g + E.f;
|
|
|
+ B.f = _b + E.f;
|
|
|
+
|
|
|
+ // Convert the Bias to the correct exponent in the upper 5 bits.
|
|
|
+ E.i <<= 4;
|
|
|
+ E.i += 0x10000000;
|
|
|
+
|
|
|
+ // Combine the fields. RGB floats have unwanted data in the upper 9
|
|
|
+ // bits. Only red needs to mask them off because green and blue shift
|
|
|
+ // it out to the left.
|
|
|
+ return E.i | (B.i << 18) | (G.i << 9) | (R.i & 511);
|
|
|
}
|
|
|
|
|
|
_FORCE_INLINE_ Color blend(const Color &p_over) const {
|