// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QRGBAFLOAT_H #define QRGBAFLOAT_H #include #include #include #include #include QT_BEGIN_NAMESPACE template class alignas(sizeof(F) * 4) QRgbaFloat { static_assert(std::is_same::value || std::is_same::value); public: using Type = F; #if defined(__AVX512FP16__) && QFLOAT16_IS_NATIVE // AVX512FP16 has multiplication instructions using FastType = F; #else // use FP32 for multiplications using FastType = float; #endif F r; F g; F b; F a; static constexpr QRgbaFloat fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha) { constexpr FastType scale = FastType(1.0f / 65535.0f); return QRgbaFloat{ F(red * scale), F(green * scale), F(blue * scale), F(alpha * scale) }; } static constexpr QRgbaFloat fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha) { constexpr FastType scale = FastType(1.0f / 255.0f); return QRgbaFloat{ F(red * scale), F(green * scale), F(blue * scale), F(alpha * scale) }; } static constexpr QRgbaFloat fromArgb32(uint rgb) { return fromRgba(quint8(rgb >> 16), quint8(rgb >> 8), quint8(rgb), quint8(rgb >> 24)); } constexpr bool isOpaque() const { return a >= FastType(1.0f); } constexpr bool isTransparent() const { return a <= FastType(0.0f); } constexpr float red() const { return r; } constexpr float green() const { return g; } constexpr float blue() const { return b; } constexpr float alpha() const { return a; } void setRed(float _red) { r = F(_red); } void setGreen(float _green) { g = F(_green); } void setBlue(float _blue) { b = F(_blue); } void setAlpha(float _alpha) { a = F(_alpha); } constexpr float redNormalized() const { return clamp01(r); } constexpr float greenNormalized() const { return clamp01(g); } constexpr float blueNormalized() const { return clamp01(b); } constexpr float alphaNormalized() const { return clamp01(a); } constexpr quint8 red8() const { return qRound(redNormalized() * FastType(255.0f)); } constexpr quint8 green8() const { return qRound(greenNormalized() * FastType(255.0f)); } constexpr quint8 blue8() const { return qRound(blueNormalized() * FastType(255.0f)); } constexpr quint8 alpha8() const { return qRound(alphaNormalized() * FastType(255.0f)); } constexpr uint toArgb32() const { return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8()); } constexpr quint16 red16() const { return qRound(redNormalized() * FastType(65535.0f)); } constexpr quint16 green16() const { return qRound(greenNormalized() * FastType(65535.0f)); } constexpr quint16 blue16() const { return qRound(blueNormalized() * FastType(65535.0f)); } constexpr quint16 alpha16() const { return qRound(alphaNormalized() * FastType(65535.0f)); } constexpr Q_ALWAYS_INLINE QRgbaFloat premultiplied() const { return QRgbaFloat{r * a, g * a, b * a, a}; } constexpr Q_ALWAYS_INLINE QRgbaFloat unpremultiplied() const { if (a <= F{0.0f}) return QRgbaFloat{}; // default-initialization: zeroes if (a >= F{1.0f}) return *this; const FastType ia = 1.0f / a; return QRgbaFloat{F(r * ia), F(g * ia), F(b * ia), F(a)}; } constexpr bool operator==(QRgbaFloat f) const { return r == f.r && g == f.g && b == f.b && a == f.a; } constexpr bool operator!=(QRgbaFloat f) const { return !(*this == f); } private: constexpr static FastType clamp01(Type f) { return std::clamp(FastType(f), FastType(0.0f), FastType(1.0f)); } }; typedef QRgbaFloat QRgbaFloat16; typedef QRgbaFloat QRgbaFloat32; QT_END_NAMESPACE #endif // QRGBAFLOAT_H