Added rgb565 test file, clamping Make5/6, proper integral SFINAE condition, removed operators =

This commit is contained in:
Vladyslav Baranovskyi
2024-10-02 16:03:17 +03:00
parent 1872a03ff5
commit 996ec4c168
2 changed files with 224 additions and 34 deletions

View File

@@ -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<int16_t>(val, 0, 255);
return val * 31.0f / 255.0f;
}
static uint16_t Make6(int16_t val)
{
val = std::clamp<int16_t>(val, 0, 255);
return val * 63.0f / 255.0f;
}
static uint8_t Unmake5(uint16_t val) { return static_cast<uint8_t>(val * 255.0f / 31.0f); }
static uint8_t Unmake6(uint16_t val) { return static_cast<uint8_t>(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<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565(const Math::Vector3<T>& color) : b(Make5(color.b)), g(Make6(color.g)), r(Make5(color.r))
{
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565(const Math::Vector4<T>& color) : b(Make5(color.b)), g(Make6(color.g)), r(Make5(color.r))
{
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565(const Math::Vector3_SIMD<T>& 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<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
Math::Vector3<T> Get3()
{
return { GetR(), GetG(), GetB() };
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
Math::Vector4<T> Get4()
{
return { GetR(), GetG(), GetB(), 1 };
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
Math::Vector3_SIMD<T> 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<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
void Set(const Math::Vector3<T>& color)
{
r = Make5(color.r);
@@ -111,7 +119,7 @@ namespace OpenVulkano::Math
b = Make5(color.b);
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
void Set(const Math::Vector4<T>& 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<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator=(const Vector3<T>& color)
{
Set(color);
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator=(const Vector3_SIMD<T>& color)
{
Set(color);
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator=(const Vector4_SIMD<T>& color)
{
Set(color);
@@ -197,21 +193,21 @@ namespace OpenVulkano::Math
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator+=(const Vector3<T>& color)
{
Set(Get3<T>() + color);
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator+=(const Vector4<T>& color)
{
Set(Get4<T>() + color);
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator+=(const Vector3_SIMD<T>& color)
{
Set(GetSIMD<T>() + color);
@@ -239,21 +235,21 @@ namespace OpenVulkano::Math
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator-=(const Vector3<T>& color)
{
Set(Get3<T>() - color);
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator-=(const Vector4<T>& color)
{
Set(Get4<T>() - color);
return *this;
}
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
RGB565& operator-=(const Vector3_SIMD<T>& color)
{
Set(GetSIMD<T>() - 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<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
operator Math::Vector4<T>() { return Get4<T>(); }
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
operator Math::Vector3<T>() { return Get3<T>(); }
template<typename T, std::enable_if_t<std::is_unsigned_v<T> || std::is_signed_v<T>, bool> = true>
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
operator Math::Vector3_SIMD<T>() { return GetSIMD<T>(); }
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
operator Math::Vector4<T>() { return Get4Normalized<T>(); }

194
tests/RGB565.cpp Normal file
View File

@@ -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 <catch2/catch_all.hpp>
#include <cmath>
#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<float>();
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<float>();
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<uint8_t> { 255, 127, 63 });
Vector3<uint8_t> vec3 = color;
REQUIRE(vec3.r == 255);
REQUIRE(vec3.g == 125);
REQUIRE(vec3.b == 57);
}
TEST_CASE("test_rgb565_comparison", "[RGB565]")
{
RGB565 color1(Vector4<uint8_t>{255, 127, 63, 255});
RGB565 color2(Vector4<uint8_t>{255, 127, 63, 255});
RGB565 color3(Vector4<uint8_t>{63, 127, 255, 255});
REQUIRE(color1 == color2);
REQUIRE(color1 != color3);
{
RGB565 color4 = color1;
REQUIRE(color4 == color1);
}
Vector3<uint8_t> vec3 { 255, 127, 63 };
color1 = vec3;
REQUIRE(color1.GetR() == 255);
REQUIRE(color1.GetG() == 125);
REQUIRE(color1.GetB() == 57);
Vector4<float> 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
}