Merge pull request 'Implementation of RGBA5551 class' (#129) from rgba5551 into master
Reviewed-on: https://git.madvoxel.net/OpenVulkano/OpenVulkano/pulls/129 Reviewed-by: Georg Hagen <georg.hagen@madvoxel.com>
This commit is contained in:
@@ -7,15 +7,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "Math/Math.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenVulkano::Math
|
||||
{
|
||||
class RGBA5551
|
||||
{
|
||||
uint16_t Make5(uint8_t val)
|
||||
{
|
||||
return val * 31.0f / 255.0f;
|
||||
}
|
||||
static uint16_t Make5(uint8_t val) { return static_cast<uint16_t>(val * 31.0f / 255.0f); }
|
||||
static uint8_t Unmake5(uint16_t val) { return static_cast<uint8_t>(val * 255.0f / 31.0f); }
|
||||
static float Unmake5ToFloat(uint16_t val) { return std::clamp(val / 31.0f, 0.0f, 1.0f); }
|
||||
static uint16_t Make5FromFloat(float val) { return (uint16_t) std::clamp(val * 31.0f, 0.0f, 31.f); }
|
||||
|
||||
public:
|
||||
union
|
||||
@@ -30,11 +31,148 @@ namespace OpenVulkano::Math
|
||||
};
|
||||
};
|
||||
|
||||
RGBA5551(Math::Vector4uc color = {0, 0, 0, 1})
|
||||
: b(Make5(color.b))
|
||||
, g(Make5(color.g))
|
||||
, r(Make5(color.r))
|
||||
, a(color.a > 128)
|
||||
{}
|
||||
RGBA5551() : r(0), g(0), b(0), a(1) {}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
RGBA5551(const Math::Vector3<T>& color) : b(Make5(color.b)), g(Make5(color.g)), r(Make5(color.r)), a(1)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
RGBA5551(const Math::Vector4<T>& color)
|
||||
: b(Make5(color.b)), g(Make5(color.g)), r(Make5(color.r)), a(color.a > 128)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
RGBA5551(const Math::Vector3<T>& color)
|
||||
: b(Make5FromFloat(color.b)), g(Make5FromFloat(color.g)), r(Make5FromFloat(color.r)), a(1)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
RGBA5551(const Math::Vector4<T>& color)
|
||||
: b(Make5FromFloat(color.b)), g(Make5FromFloat(color.g)), r(Make5FromFloat(color.r)), a(color.a > 0.5f)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t GetR() const { return Unmake5(r); }
|
||||
uint8_t GetG() const { return Unmake5(g); }
|
||||
uint8_t GetB() const { return Unmake5(b); }
|
||||
uint8_t GetA() const { return a ? 255 : 0; }
|
||||
|
||||
float GetR_Normalized() const { return Unmake5ToFloat(r); }
|
||||
float GetG_Normalized() const { return Unmake5ToFloat(g); }
|
||||
float GetB_Normalized() const { return Unmake5ToFloat(b); }
|
||||
float GetA_Normalized() const { return a; }
|
||||
|
||||
void SetR(uint8_t red) { r = Make5(red); }
|
||||
void SetG(uint8_t green) { g = Make5(green); }
|
||||
void SetB(uint8_t blue) { b = Make5(blue); }
|
||||
void SetA(uint8_t alpha) { a = (alpha > 128); }
|
||||
|
||||
void SetR_Normalized(float red) { r = Make5FromFloat(red); }
|
||||
void SetG_Normalized(float green) { g = Make5FromFloat(green); }
|
||||
void SetB_Normalized(float blue) { b = Make5FromFloat(blue); }
|
||||
void SetA_Normalized(float alpha) { a = (alpha > 0.5f); }
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
Math::Vector3<T> Get3() const
|
||||
{
|
||||
return { GetR(), GetG(), GetB() };
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
Math::Vector4<T> Get4() const
|
||||
{
|
||||
return { GetR(), GetG(), GetB(), GetA() };
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
Math::Vector4<T> Get4Normalized() const
|
||||
{
|
||||
return { GetR_Normalized(), GetG_Normalized(), GetB_Normalized(), GetA_Normalized() };
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
Math::Vector3<T> Get3Normalized() const
|
||||
{
|
||||
return { GetR_Normalized(), GetG_Normalized(), GetB_Normalized() };
|
||||
}
|
||||
|
||||
RGBA5551& operator=(const RGBA5551& other)
|
||||
{
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const RGBA5551& other) const { return value == other.value; }
|
||||
bool operator!=(const RGBA5551& other) const { return value != other.value; }
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
RGBA5551& operator=(const Math::Vector3<T>& color)
|
||||
{
|
||||
SetR_Normalized(color.r);
|
||||
SetG_Normalized(color.g);
|
||||
SetB_Normalized(color.b);
|
||||
SetA_Normalized(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
RGBA5551& operator=(const Math::Vector4<T>& color)
|
||||
{
|
||||
SetR_Normalized(color.r);
|
||||
SetG_Normalized(color.g);
|
||||
SetB_Normalized(color.b);
|
||||
SetA_Normalized(color.a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
RGBA5551& operator=(const Math::Vector3<T>& color)
|
||||
{
|
||||
SetR(color.r);
|
||||
SetG(color.g);
|
||||
SetB(color.b);
|
||||
SetA(255);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
RGBA5551& operator=(const Math::Vector4<T>& color)
|
||||
{
|
||||
SetR(color.r);
|
||||
SetG(color.g);
|
||||
SetB(color.b);
|
||||
SetA(color.a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
operator Math::Vector3<T>() const
|
||||
{
|
||||
return Get3<T>();
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
operator Math::Vector3<T>() const
|
||||
{
|
||||
return Get3Normalized<T>();
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
|
||||
operator Math::Vector4<T>() const
|
||||
{
|
||||
return Get4<T>();
|
||||
}
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
|
||||
operator Math::Vector4<T>() const
|
||||
{
|
||||
return Get4Normalized<T>();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(RGBA5551) == 2);
|
||||
}
|
||||
154
tests/RGBA5551.cpp
Normal file
154
tests/RGBA5551.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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/RGBA5551.hpp"
|
||||
|
||||
using namespace OpenVulkano::Math;
|
||||
|
||||
bool almostEqual(float a, float b, float epsilon = 0.001f) { return std::fabs(a - b) < epsilon; }
|
||||
|
||||
TEST_CASE("test_rgba5551_default_ctor", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 color;
|
||||
REQUIRE(color.GetR() == 0);
|
||||
REQUIRE(color.GetG() == 0);
|
||||
REQUIRE(color.GetB() == 0);
|
||||
REQUIRE(color.GetA() == 255);
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_creation", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 color1(Vector4uc(255, 255, 255, 129));
|
||||
REQUIRE(color1.r == 31);
|
||||
REQUIRE(color1.g == 31);
|
||||
REQUIRE(color1.b == 31);
|
||||
REQUIRE(color1.a == 1);
|
||||
|
||||
RGBA5551 color2(Vector4f(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
REQUIRE(color2.r == 31);
|
||||
REQUIRE(color2.g == 31);
|
||||
REQUIRE(color2.b == 31);
|
||||
REQUIRE(color2.a == 1);
|
||||
|
||||
RGBA5551 color3(Vector4i(128, 128, 128, 0));
|
||||
REQUIRE(color3.r == 15);
|
||||
REQUIRE(color3.g == 15);
|
||||
REQUIRE(color3.b == 15);
|
||||
REQUIRE(color3.a == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_conversion_to_vector3", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 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 };
|
||||
RGBA5551 color2(vec3);
|
||||
REQUIRE(almostEqual(color2.GetR_Normalized(), 0.096f));
|
||||
REQUIRE(almostEqual(color2.GetG_Normalized(), 0.483f));
|
||||
REQUIRE(almostEqual(color2.GetB_Normalized(), 1.0f));
|
||||
REQUIRE(almostEqual(color2.GetA_Normalized(), 1.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_conversion_to_vector4", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 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_rgba5551_conversion_from_vector3", "[RGBA5551]")
|
||||
{
|
||||
Vector3f vec(1.0f, 0.5f, 0.25f);
|
||||
RGBA5551 color(vec);
|
||||
REQUIRE(color.r == 31);
|
||||
REQUIRE(color.g == 15);
|
||||
REQUIRE(color.b == 7);
|
||||
REQUIRE(color.a == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_conversion_from_vector4", "[RGBA5551]")
|
||||
{
|
||||
Vector4f vec(0.0f, 1.0f, 0.5f, 0.0f);
|
||||
RGBA5551 color(vec);
|
||||
REQUIRE(color.r == 0);
|
||||
REQUIRE(color.g == 31);
|
||||
REQUIRE(color.b == 15);
|
||||
REQUIRE(color.a == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_cast_to_vector4", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 color;
|
||||
color.r = 31;
|
||||
color.g = 15;
|
||||
color.b = 7;
|
||||
color.a = 1;
|
||||
Vector4f casted = (Vector4f)color;
|
||||
REQUIRE(almostEqual(casted.r, 1.0));
|
||||
REQUIRE(almostEqual(casted.g, 0.483));
|
||||
REQUIRE(almostEqual(casted.b, 0.225));
|
||||
REQUIRE(almostEqual(casted.a, 1));
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_getters_setters", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 color;
|
||||
color.SetR_Normalized(0.1f);
|
||||
color.SetG_Normalized(0.5f);
|
||||
color.SetB_Normalized(1.0f);
|
||||
color.SetA_Normalized(0.7f);
|
||||
|
||||
REQUIRE(almostEqual(color.GetR_Normalized(), 0.096f));
|
||||
REQUIRE(almostEqual(color.GetG_Normalized(), 0.483f));
|
||||
REQUIRE(almostEqual(color.GetB_Normalized(), 1.0f));
|
||||
REQUIRE(color.GetA() == 255);
|
||||
|
||||
color = RGBA5551(Vector3<uint8_t> { 255, 127, 63 });
|
||||
Vector3<uint8_t> vec3 = color;
|
||||
|
||||
REQUIRE(vec3.r == 255);
|
||||
REQUIRE(vec3.g == 123);
|
||||
REQUIRE(vec3.b == 57);
|
||||
}
|
||||
|
||||
TEST_CASE("test_rgba5551_comparison", "[RGBA5551]")
|
||||
{
|
||||
RGBA5551 color1(Vector4<uint8_t>{255, 127, 63, 255});
|
||||
RGBA5551 color2(Vector4<uint8_t>{255, 127, 63, 255});
|
||||
RGBA5551 color3(Vector4<uint8_t>{63, 127, 255, 255});
|
||||
|
||||
REQUIRE(color1 == color2);
|
||||
REQUIRE(color1 != color3);
|
||||
|
||||
{
|
||||
RGBA5551 color4 = color1;
|
||||
REQUIRE(color4 == color1);
|
||||
}
|
||||
|
||||
Vector3<uint8_t> vec3 { 255, 127, 63 };
|
||||
color1 = vec3;
|
||||
REQUIRE(color1.GetR() == 255);
|
||||
REQUIRE(color1.GetG() == 123);
|
||||
REQUIRE(color1.GetB() == 57);
|
||||
REQUIRE(color1.GetA() == 255);
|
||||
|
||||
Vector4<float> vec4 { 0.1f, 0.5f, 1.0f, 0.7f };
|
||||
color1 = vec4;
|
||||
REQUIRE(almostEqual(color1.GetR_Normalized(), 0.096f));
|
||||
REQUIRE(almostEqual(color1.GetG_Normalized(), 0.483f));
|
||||
REQUIRE(almostEqual(color1.GetB_Normalized(), 1.0f));
|
||||
REQUIRE(color1.GetA() == 255);
|
||||
}
|
||||
Reference in New Issue
Block a user