diff --git a/openVulkanoCpp/Math/RGB565.hpp b/openVulkanoCpp/Math/RGB565.hpp index 357ebfa..2a667d7 100644 --- a/openVulkanoCpp/Math/RGB565.hpp +++ b/openVulkanoCpp/Math/RGB565.hpp @@ -13,8 +13,16 @@ namespace OpenVulkano::Math { class RGB565 { - static uint16_t Make5(uint8_t val) { return val * 31.0f / 255.0f; } - static uint16_t Make6(uint8_t val) { return val * 63.0f / 255.0f; } + static uint16_t Make5(int16_t val) + { + val = std::clamp(val, 0, 255); + return val * 31.0f / 255.0f; + } + static uint16_t Make6(int16_t val) + { + val = std::clamp(val, 0, 255); + return val * 63.0f / 255.0f; + } static uint8_t Unmake5(uint16_t val) { return static_cast(val * 255.0f / 31.0f); } static uint8_t Unmake6(uint16_t val) { return static_cast(val * 255.0f / 63.0f); } static float Unmake5ToFloat(uint16_t val) { return std::clamp(val / 31.0f, 0.0f, 1.0f); } @@ -36,15 +44,15 @@ namespace OpenVulkano::Math RGB565() : r(0), g(0), b(0) {} - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565(const Math::Vector3& color) : b(Make5(color.b)), g(Make6(color.g)), r(Make5(color.r)) { } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565(const Math::Vector4& color) : b(Make5(color.b)), g(Make6(color.g)), r(Make5(color.r)) { } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565(const Math::Vector3_SIMD& color) : b(Make5(color.b)), g(Make6(color.g)), r(Make5(color.r)) { } @@ -68,17 +76,17 @@ namespace OpenVulkano::Math uint8_t GetG() { return Unmake6(g); } uint8_t GetB() { return Unmake5(b); } - template || std::is_signed_v, bool> = true> + template, bool> = true> Math::Vector3 Get3() { return { GetR(), GetG(), GetB() }; } - template || std::is_signed_v, bool> = true> + template, bool> = true> Math::Vector4 Get4() { return { GetR(), GetG(), GetB(), 1 }; } - template || std::is_signed_v, bool> = true> + template, bool> = true> Math::Vector3_SIMD GetSIMD() { return { GetR(), GetG(), GetB() }; @@ -103,7 +111,7 @@ namespace OpenVulkano::Math void SetG(uint8_t green) { g = Make6(green); } void SetB(uint8_t blue) { b = Make5(blue); } - template || std::is_signed_v, bool> = true> + template, bool> = true> void Set(const Math::Vector3& color) { r = Make5(color.r); @@ -111,7 +119,7 @@ namespace OpenVulkano::Math b = Make5(color.b); } - template || std::is_signed_v, bool> = true> + template, bool> = true> void Set(const Math::Vector4& color) { r = Make5(color.r); @@ -143,33 +151,21 @@ namespace OpenVulkano::Math void SetG_Normalized(float green) { g = Make6FromFloat(green); } void SetB_Normalized(float blue) { b = Make5FromFloat(blue); } - RGB565& operator=(const RGB565& other) - { - value = other.value; - return *this; - } - - RGB565& operator=(RGB565&& other) noexcept - { - value = other.value; - return *this; - } - - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator=(const Vector3& color) { Set(color); return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator=(const Vector3_SIMD& color) { Set(color); return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator=(const Vector4_SIMD& color) { Set(color); @@ -197,21 +193,21 @@ namespace OpenVulkano::Math return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator+=(const Vector3& color) { Set(Get3() + color); return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator+=(const Vector4& color) { Set(Get4() + color); return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator+=(const Vector3_SIMD& color) { Set(GetSIMD() + color); @@ -239,21 +235,21 @@ namespace OpenVulkano::Math return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator-=(const Vector3& color) { Set(Get3() - color); return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator-=(const Vector4& color) { Set(Get4() - color); return *this; } - template || std::is_signed_v, bool> = true> + template, bool> = true> RGB565& operator-=(const Vector3_SIMD& color) { Set(GetSIMD() - color); @@ -284,11 +280,11 @@ namespace OpenVulkano::Math bool operator==(const RGB565& other) const { return value == other.value; } bool operator!=(const RGB565& other) const { return value != other.value; } - template || std::is_signed_v, bool> = true> + template, bool> = true> operator Math::Vector4() { return Get4(); } - template || std::is_signed_v, bool> = true> + template, bool> = true> operator Math::Vector3() { return Get3(); } - template || std::is_signed_v, bool> = true> + template, bool> = true> operator Math::Vector3_SIMD() { return GetSIMD(); } template, bool> = true> operator Math::Vector4() { return Get4Normalized(); } diff --git a/tests/RGB565.cpp b/tests/RGB565.cpp new file mode 100644 index 0000000..f2642d1 --- /dev/null +++ b/tests/RGB565.cpp @@ -0,0 +1,194 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include +#include + +#include "Math/RGB565.hpp" + +using namespace OpenVulkano::Math; + +namespace +{ + bool almostEqual(float a, float b, float epsilon = 0.001f) { return std::fabs(a - b) < epsilon; } +} + +TEST_CASE("test_rgb565_default_ctor", "[RGB565]") +{ + RGB565 color; + REQUIRE(color.GetR() == 0); + REQUIRE(color.GetG() == 0); + REQUIRE(color.GetB() == 0); +} + +TEST_CASE("test_rgb565_creation", "[RGB565]") +{ + RGB565 color1(Vector4uc(255, 255, 255, 129)); + REQUIRE(color1.r == 31); + REQUIRE(color1.g == 63); + REQUIRE(color1.b == 31); + + RGB565 color2(Vector4f(1.0f, 1.0f, 1.0f, 1.0f)); + REQUIRE(color2.r == 31); + REQUIRE(color2.g == 63); + REQUIRE(color2.b == 31); + + RGB565 color3(Vector4i(128, 128, 128, 0)); + REQUIRE(color3.r == 15); + REQUIRE(color3.g == 31); + REQUIRE(color3.b == 15); +} + +TEST_CASE("test_rgb565_conversion_to_vector3", "[RGB565]") +{ + RGB565 color(Vector4i(255, 0, 0, 1)); + Vector3f vec = color.Get3Normalized(); + REQUIRE(almostEqual(vec.x, 1.0f)); + REQUIRE(almostEqual(vec.y, 0.0f)); + REQUIRE(almostEqual(vec.z, 0.0f)); + + Vector3f vec3 { 0.1f, 0.5f, 1.0f }; + RGB565 color2(vec3); + REQUIRE(almostEqual(color2.GetR_Normalized(), 0.096)); + REQUIRE(almostEqual(color2.GetG_Normalized(), 0.492)); + REQUIRE(almostEqual(color2.GetB_Normalized(), 1.0)); +} + +TEST_CASE("test_rgb565_conversion_to_vector4", "[RGB565]") +{ + RGB565 color(Vector4i(255, 0, 0, 129)); + Vector4f vec = color.Get4Normalized(); + REQUIRE(almostEqual(vec.x, 1.0f)); + REQUIRE(almostEqual(vec.y, 0.0f)); + REQUIRE(almostEqual(vec.z, 0.0f)); + REQUIRE(almostEqual(vec.w, 1.0f)); +} + +TEST_CASE("test_rgb565_conversion_from_vector3", "[RGB565]") +{ + Vector3f vec(1.0f, 0.5f, 0.25f); + RGB565 color(vec); + REQUIRE(color.r == 31); + REQUIRE(color.g == 31); + REQUIRE(color.b == 7); +} + +TEST_CASE("test_rgb565_conversion_from_vector4", "[RGB565]") +{ + Vector4f vec(0.0f, 1.0f, 0.5f, 0.0f); + RGB565 color(vec); + REQUIRE(color.r == 0); + REQUIRE(color.g == 63); + REQUIRE(color.b == 15); +} + +TEST_CASE("test_rgb565_cast_to_vector4", "[RGB565]") +{ + RGB565 color; + color.r = 31; + color.g = 31; + color.b = 7; + Vector4f casted = (Vector4f)color; + REQUIRE(almostEqual(casted.r, 1.0)); + REQUIRE(almostEqual(casted.g, 0.492)); + REQUIRE(almostEqual(casted.b, 0.225)); +} + +TEST_CASE("test_rgb565_getters_setters", "[RGB565]") +{ + RGB565 color; + color.SetR_Normalized(0.1f); + color.SetG_Normalized(0.5f); + color.SetB_Normalized(1.0f); + + REQUIRE(almostEqual(color.GetR_Normalized(), 0.096)); + REQUIRE(almostEqual(color.GetG_Normalized(), 0.492)); + REQUIRE(almostEqual(color.GetB_Normalized(), 1.0)); + + color = RGB565(Vector3 { 255, 127, 63 }); + Vector3 vec3 = color; + + REQUIRE(vec3.r == 255); + REQUIRE(vec3.g == 125); + REQUIRE(vec3.b == 57); +} + +TEST_CASE("test_rgb565_comparison", "[RGB565]") +{ + RGB565 color1(Vector4{255, 127, 63, 255}); + RGB565 color2(Vector4{255, 127, 63, 255}); + RGB565 color3(Vector4{63, 127, 255, 255}); + + REQUIRE(color1 == color2); + REQUIRE(color1 != color3); + + { + RGB565 color4 = color1; + REQUIRE(color4 == color1); + } + + Vector3 vec3 { 255, 127, 63 }; + color1 = vec3; + REQUIRE(color1.GetR() == 255); + REQUIRE(color1.GetG() == 125); + REQUIRE(color1.GetB() == 57); + + Vector4 vec4 { 0.1f, 0.5f, 1.0f, 0.7f }; + color1 = vec4; + REQUIRE(almostEqual(color1.GetR_Normalized(), 0.096)); + REQUIRE(almostEqual(color1.GetG_Normalized(), 0.492)); + REQUIRE(almostEqual(color1.GetB_Normalized(), 1.0)); +} + +TEST_CASE("test_rgb565_operators", "[RGB565]") +{ + RGB565 rgb1, rgb2; + + rgb1.SetR(255); + rgb1.SetG(127); + rgb1.SetB(63); + + rgb2.SetR(255); + rgb2.SetG(127); + rgb2.SetB(63); + + REQUIRE(rgb1 == rgb2); + + rgb2.SetB(0); + REQUIRE(rgb1 != rgb2); + + rgb1.SetR(255); + rgb1.SetG(127); + rgb1.SetB(63); + + rgb2 = rgb1; + REQUIRE(rgb1 == rgb2); + + Vector3i delta(10, 20, 30); + rgb1.SetR(100); + rgb1.SetG(50); + rgb1.SetB(25); + + rgb1 += delta; + + REQUIRE(rgb1.GetR() == 106); + REQUIRE(rgb1.GetG() == 64); + REQUIRE(rgb1.GetB() == 49); + + rgb1.SetR(100); + rgb1.SetG(50); + rgb1.SetB(25); + + rgb1 -= delta; + + uint8_t r = rgb1.GetR(); + uint8_t g = rgb1.GetG(); + uint8_t b = rgb1.GetB(); + + REQUIRE(rgb1.GetR() == 82); + REQUIRE(rgb1.GetG() == 24); + REQUIRE(rgb1.GetB() == 0); // Expect to clamp here +} \ No newline at end of file