// This file is part of Blend2D project // // See blend2d.h or LICENSE.md for license and copyright information // SPDX-License-Identifier: Zlib #ifndef BLEND2D_RGBA_H_INCLUDED #define BLEND2D_RGBA_H_INCLUDED #include "api.h" //! \addtogroup blend2d_api_styling //! \{ //! 32-bit RGBA color (8-bit per component) stored as `0xAARRGGBB`. struct BLRgba32 { //! Packed 32-bit RGBA value. uint32_t value; #ifdef __cplusplus //! \name Construction & Destruction //! \{ BL_INLINE_NODEBUG BLRgba32() noexcept = default; BL_INLINE_NODEBUG constexpr BLRgba32(const BLRgba32&) noexcept = default; BL_INLINE_NODEBUG constexpr explicit BLRgba32(uint32_t rgba32) noexcept : value(rgba32) {} BL_INLINE_NODEBUG explicit BLRgba32(const BLRgba64& rgba64) noexcept { reset(rgba64); } BL_INLINE_NODEBUG constexpr BLRgba32(uint32_t r, uint32_t g, uint32_t b, uint32_t a = 0xFFu) noexcept : value((r << 16) | (g << 8) | b | (a << 24)) {} //! \} //! \name Overloaded Operators //! \{ BL_INLINE_NODEBUG constexpr explicit operator bool() const noexcept { return value != 0; } BL_INLINE_NODEBUG BLRgba32& operator=(const BLRgba32& other) noexcept = default; BL_NODISCARD BL_INLINE_NODEBUG constexpr bool operator==(const BLRgba32& other) const noexcept { return equals(other); } BL_NODISCARD BL_INLINE_NODEBUG constexpr bool operator!=(const BLRgba32& other) const noexcept { return !equals(other); } //! \} //! \name Accessors //! \{ BL_INLINE_NODEBUG constexpr uint32_t r() const noexcept { return (value >> 16) & 0xFFu; } BL_INLINE_NODEBUG constexpr uint32_t g() const noexcept { return (value >> 8) & 0xFFu; } BL_INLINE_NODEBUG constexpr uint32_t b() const noexcept { return (value >> 0) & 0xFFu; } BL_INLINE_NODEBUG constexpr uint32_t a() const noexcept { return (value >> 24); } BL_INLINE_NODEBUG void setR(uint32_t r) noexcept { value = (value & 0xFF00FFFFu) | (r << 16); } BL_INLINE_NODEBUG void setG(uint32_t g) noexcept { value = (value & 0xFFFF00FFu) | (g << 8); } BL_INLINE_NODEBUG void setB(uint32_t b) noexcept { value = (value & 0xFFFFFF00u) | (b << 0); } BL_INLINE_NODEBUG void setA(uint32_t a) noexcept { value = (value & 0x00FFFFFFu) | (a << 24); } //! \} //! \name Common Functionality //! \{ BL_INLINE_NODEBUG void reset() noexcept { value = 0u; } BL_INLINE_NODEBUG void reset(uint32_t rgba32) noexcept { value = rgba32;} BL_INLINE_NODEBUG void reset(uint32_t r, uint32_t g, uint32_t b, uint32_t a = 0xFFu) noexcept { value = (r << 16) | (g << 8) | b | (a << 24); } BL_INLINE_NODEBUG void reset(const BLRgba32& rgba32) noexcept { value = rgba32.value; } BL_INLINE_NODEBUG void reset(const BLRgba64& rgba64) noexcept; BL_NODISCARD BL_INLINE_NODEBUG constexpr bool equals(const BLRgba32& other) const noexcept { return value == other.value; } //! \} //! \name Utilities //! \{ //! Tests whether the color is fully-opaque (alpha equals 0xFFFF). BL_NODISCARD BL_INLINE_NODEBUG constexpr bool isOpaque() const noexcept { return value >= 0xFF000000u; } //! Tests whether the color is fully-transparent (alpha equals 0). BL_NODISCARD BL_INLINE_NODEBUG constexpr bool isTransparent() const noexcept { return value <= 0x00FFFFFFu; } //! \} #endif }; //! 64-bit RGBA color (16-bit per component) stored as `0xAAAARRRRGGGGBBBB`. struct BLRgba64 { //! Packed 64-bit RGBA value. uint64_t value; #ifdef __cplusplus //! \name Construction & Destruction //! \{ BL_INLINE_NODEBUG BLRgba64() noexcept = default; BL_INLINE_NODEBUG constexpr BLRgba64(const BLRgba64&) noexcept = default; BL_INLINE_NODEBUG constexpr explicit BLRgba64(uint64_t rgba64) noexcept : value(rgba64) {} BL_INLINE_NODEBUG constexpr BLRgba64(uint32_t r, uint32_t g, uint32_t b, uint32_t a = 0xFFFFu) noexcept : value((uint64_t(a) << 48) | (uint64_t(r) << 32) | (uint64_t(g) << 16) | (uint64_t(b) << 0) ) {} BL_INLINE_NODEBUG constexpr explicit BLRgba64(const BLRgba32& rgba32) noexcept : value(((uint64_t(rgba32.r()) << 32) | (uint64_t(rgba32.g()) << 16) | (uint64_t(rgba32.b()) << 0) | (uint64_t(rgba32.a()) << 48)) * 0x0101u) {} //! \} //! \name Overloaded Operators //! \{ BL_INLINE_NODEBUG constexpr explicit operator bool() const noexcept { return value != 0; } BL_INLINE_NODEBUG BLRgba64& operator=(const BLRgba64& other) noexcept = default; BL_NODISCARD BL_INLINE_NODEBUG constexpr bool operator==(const BLRgba64& other) const noexcept { return equals(other); } BL_NODISCARD BL_INLINE_NODEBUG constexpr bool operator!=(const BLRgba64& other) const noexcept { return !equals(other); } //! \} //! \name Accessors //! \{ BL_INLINE_NODEBUG constexpr uint32_t r() const noexcept { return uint32_t((value >> 32) & 0xFFFFu); } BL_INLINE_NODEBUG constexpr uint32_t g() const noexcept { return uint32_t((value >> 16) & 0xFFFFu); } BL_INLINE_NODEBUG constexpr uint32_t b() const noexcept { return uint32_t((value >> 0) & 0xFFFFu); } BL_INLINE_NODEBUG constexpr uint32_t a() const noexcept { return uint32_t((value >> 48)); } BL_INLINE_NODEBUG void setR(uint32_t r) noexcept { value = (value & 0xFFFF0000FFFFFFFFu) | (uint64_t(r) << 32); } BL_INLINE_NODEBUG void setG(uint32_t g) noexcept { value = (value & 0xFFFFFFFF0000FFFFu) | (uint64_t(g) << 16); } BL_INLINE_NODEBUG void setB(uint32_t b) noexcept { value = (value & 0xFFFFFFFFFFFF0000u) | (uint64_t(b) << 0); } BL_INLINE_NODEBUG void setA(uint32_t a) noexcept { value = (value & 0x0000FFFFFFFFFFFFu) | (uint64_t(a) << 48); } //! \} //! \name Common Functionality //! \{ BL_INLINE_NODEBUG void reset() noexcept { value = 0u; } BL_INLINE_NODEBUG void reset(uint64_t rgba64) noexcept { value = rgba64; } BL_INLINE_NODEBUG void reset(uint32_t r, uint32_t g, uint32_t b, uint32_t a = 0xFFFFu) noexcept { value = (uint64_t(r) << 32) | (uint64_t(g) << 16) | (uint64_t(b) << 0) | (uint64_t(a) << 48); } BL_INLINE_NODEBUG void reset(const BLRgba64& rgba64) noexcept { value = rgba64.value; } BL_INLINE_NODEBUG void reset(const BLRgba32& rgba32) noexcept { value = ((uint64_t(rgba32.r()) << 32) | (uint64_t(rgba32.g()) << 16) | (uint64_t(rgba32.b()) << 0) | (uint64_t(rgba32.a()) << 48)) * 0x0101u; } BL_NODISCARD BL_INLINE_NODEBUG constexpr bool equals(const BLRgba64& other) const noexcept { return value == other.value; } //! \} //! \name Utilities //! \{ //! Tests whether the color is fully-opaque (alpha equals 0xFFFF). BL_NODISCARD BL_INLINE_NODEBUG constexpr bool isOpaque() const noexcept { return value >= 0xFFFF000000000000u; } //! Tests whether the color is fully-transparent (alpha equals 0). BL_NODISCARD BL_INLINE_NODEBUG constexpr bool isTransparent() const noexcept { return value <= 0x0000FFFFFFFFFFFFu; } //! \} #endif }; //! 128-bit RGBA color stored as 4 32-bit floating point values in [RGBA] order. struct BLRgba { //! Red component. float r; //! Green component. float g; //! Blur component. float b; //! Alpha component. float a; #ifdef __cplusplus //! \name Construction & Destruction //! \{ BL_INLINE_NODEBUG BLRgba() noexcept = default; BL_INLINE_NODEBUG constexpr BLRgba(const BLRgba&) noexcept = default; BL_INLINE_NODEBUG constexpr BLRgba(float rValue, float gValue, float bValue, float aValue = 1.0f) noexcept : r(rValue), g(gValue), b(bValue), a(aValue) {} BL_INLINE_NODEBUG constexpr BLRgba(const BLRgba32& rgba32) noexcept : r(float(int32_t(rgba32.r())) * (1.0f / 255.0f)), g(float(int32_t(rgba32.g())) * (1.0f / 255.0f)), b(float(int32_t(rgba32.b())) * (1.0f / 255.0f)), a(float(int32_t(rgba32.a())) * (1.0f / 255.0f)) {} BL_INLINE_NODEBUG constexpr BLRgba(const BLRgba64& rgba64) noexcept : r(float(int32_t(rgba64.r())) * (1.0f / 65535.0f)), g(float(int32_t(rgba64.g())) * (1.0f / 65535.0f)), b(float(int32_t(rgba64.b())) * (1.0f / 65535.0f)), a(float(int32_t(rgba64.a())) * (1.0f / 65535.0f)) {} //! \} //! \name Overloaded Operators //! \{ BL_INLINE_NODEBUG constexpr explicit operator bool() const noexcept { return !((r == 0.0f) & (g == 0.0f) & (b == 0.0f) & (a == 0.0f)); } BL_INLINE_NODEBUG BLRgba& operator=(const BLRgba& other) noexcept = default; BL_NODISCARD BL_INLINE_NODEBUG bool operator==(const BLRgba& other) const noexcept { return equals(other); } BL_NODISCARD BL_INLINE_NODEBUG bool operator!=(const BLRgba& other) const noexcept { return !equals(other); } //! \} //! \name Common Functionality //! \{ BL_INLINE_NODEBUG void reset() noexcept { reset(0.0f, 0.0f, 0.0f, 0.0f); } BL_INLINE_NODEBUG void reset(const BLRgba32& rgba32) noexcept { *this = BLRgba(rgba32); } BL_INLINE_NODEBUG void reset(const BLRgba64& rgba64) noexcept { *this = BLRgba(rgba64); } BL_INLINE_NODEBUG void reset(const BLRgba& other) noexcept { reset(other.r, other.g, other.b, other.a); } BL_INLINE_NODEBUG void reset(float rValue, float gValue, float bValue, float aValue = 1.0f) noexcept { this->r = rValue; this->g = gValue; this->b = bValue; this->a = aValue; } BL_NODISCARD BL_INLINE_NODEBUG bool equals(const BLRgba32& rgba32) const noexcept { return equals(BLRgba(rgba32)); } BL_NODISCARD BL_INLINE_NODEBUG bool equals(const BLRgba64& rgba64) const noexcept { return equals(BLRgba(rgba64)); } BL_NODISCARD BL_INLINE_NODEBUG bool equals(const BLRgba& other) const noexcept { return bool(unsigned(blEquals(this->r, other.r)) & unsigned(blEquals(this->g, other.g)) & unsigned(blEquals(this->b, other.b)) & unsigned(blEquals(this->a, other.a))); } BL_NODISCARD BL_INLINE_NODEBUG bool equals(float rValue, float gValue, float bValue, float aValue = 1.0f) const noexcept { return bool(unsigned(blEquals(this->r, rValue)) & unsigned(blEquals(this->g, gValue)) & unsigned(blEquals(this->b, bValue)) & unsigned(blEquals(this->a, aValue))); } //! \} //! \name Conversion //! \{ BL_INLINE_NODEBUG BLRgba32 toRgba32() const noexcept { return BLRgba32(uint32_t(int(blClamp(r, 0.0f, 1.0f) * 255.0f + 0.5f)), uint32_t(int(blClamp(g, 0.0f, 1.0f) * 255.0f + 0.5f)), uint32_t(int(blClamp(b, 0.0f, 1.0f) * 255.0f + 0.5f)), uint32_t(int(blClamp(a, 0.0f, 1.0f) * 255.0f + 0.5f))); } BL_INLINE_NODEBUG BLRgba64 toRgba64() const noexcept { return BLRgba64(uint32_t(int(blClamp(r, 0.0f, 1.0f) * 65535.0f + 0.5f)), uint32_t(int(blClamp(g, 0.0f, 1.0f) * 65535.0f + 0.5f)), uint32_t(int(blClamp(b, 0.0f, 1.0f) * 65535.0f + 0.5f)), uint32_t(int(blClamp(a, 0.0f, 1.0f) * 65535.0f + 0.5f))); } //! \} //! \name Utilities //! \{ //! Tests whether the color is fully-opaque (alpha equals 1.0). BL_NODISCARD BL_INLINE_NODEBUG constexpr bool isOpaque() const noexcept { return a >= 1.0; } //! Tests whether the color is fully-transparent (alpha equals 0.0). BL_NODISCARD BL_INLINE_NODEBUG constexpr bool isTransparent() const noexcept { return a <= 0.0; } //! \} #endif }; #ifdef __cplusplus BL_INLINE_NODEBUG void BLRgba32::reset(const BLRgba64& rgba64) noexcept { reset(uint32_t((rgba64.value >> 40) & 0xFF), uint32_t((rgba64.value >> 24) & 0xFF), uint32_t((rgba64.value >> 8) & 0xFF), uint32_t((rgba64.value >> 56) )); } static BL_INLINE_NODEBUG constexpr BLRgba32 blMin(const BLRgba32& a, const BLRgba32& b) noexcept { return BLRgba32(blMin(a.r(), b.r()), blMin(a.g(), b.g()), blMin(a.b(), b.b()), blMin(a.a(), b.a())); } static BL_INLINE_NODEBUG constexpr BLRgba32 blMax(const BLRgba32& a, const BLRgba32& b) noexcept { return BLRgba32(blMax(a.r(), b.r()), blMax(a.g(), b.g()), blMax(a.b(), b.b()), blMax(a.a(), b.a())); } BL_NODISCARD static BL_INLINE_NODEBUG constexpr BLRgba64 blMin(const BLRgba64& a, const BLRgba64& b) noexcept { return BLRgba64(blMin(a.r(), b.r()), blMin(a.g(), b.g()), blMin(a.b(), b.b()), blMin(a.a(), b.a())); } BL_NODISCARD static BL_INLINE_NODEBUG constexpr BLRgba64 blMax(const BLRgba64& a, const BLRgba64& b) noexcept { return BLRgba64(blMax(a.r(), b.r()), blMax(a.g(), b.g()), blMax(a.b(), b.b()), blMax(a.a(), b.a())); } BL_NODISCARD static BL_INLINE_NODEBUG constexpr BLRgba blMin(const BLRgba& a, const BLRgba& b) noexcept { return BLRgba(blMin(a.r, b.r), blMin(a.g, b.g), blMin(a.b, b.b), blMin(a.a, b.a)); } BL_NODISCARD static BL_INLINE_NODEBUG constexpr BLRgba blMax(const BLRgba& a, const BLRgba& b) noexcept { return BLRgba(blMax(a.r, b.r), blMax(a.g, b.g), blMax(a.b, b.b), blMax(a.a, b.a)); } #endif #ifdef __cplusplus static_assert(sizeof(BLRgba) == 16, "'BLRgba' struct must be exactly 16 bytes long"); static_assert(sizeof(BLRgba32) == 4, "'BLRgba32' struct must be exactly 4 bytes long"); static_assert(sizeof(BLRgba64) == 8, "'BLRgba64' struct must be exactly 8 bytes long"); #endif //! \} #endif // BLEND2D_RGBA_H_INCLUDED