zeus/include/zeus/CColor.hpp

363 lines
10 KiB
C++
Raw Permalink Normal View History

2018-10-06 20:39:40 -07:00
#pragma once
2015-04-30 23:31:59 -07:00
#include <algorithm>
#include <cassert>
#include <functional>
#include "zeus/CVector4f.hpp"
#include "zeus/Global.hpp"
2016-03-04 15:03:26 -08:00
#include "zeus/Math.hpp"
2018-12-07 17:16:50 -08:00
2016-09-18 18:03:37 -07:00
#undef min
#undef max
2021-10-25 19:54:47 -07:00
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
2018-12-07 21:23:50 -08:00
#define COLOR(rgba) \
2021-10-25 16:17:25 -07:00
(zeus::Comp32)(((rgba)&0x000000FF) << 24 | ((rgba)&0x0000FF00) << 8 | ((rgba)&0x00FF0000) >> 8 | \
((rgba)&0xFF000000) >> 24)
#else
2021-10-25 19:54:47 -07:00
#define COLOR(rgba) (zeus::Comp32)(rgba)
#endif
2018-12-07 17:16:50 -08:00
namespace zeus {
using Comp8 = uint8_t;
using Comp32 = uint32_t;
2016-07-08 11:42:42 -07:00
constexpr float OneOver255 = 1.f / 255.f;
union RGBA32 {
2018-12-07 17:16:50 -08:00
struct {
Comp8 r, g, b, a;
};
Comp32 rgba;
};
2015-11-25 17:26:23 -08:00
class CVector4f;
2018-12-07 17:16:50 -08:00
class CColor {
2015-04-30 23:31:59 -07:00
public:
2018-12-07 17:16:50 -08:00
simd<float> mSimd;
2019-02-23 23:15:32 -08:00
constexpr CColor() : mSimd(1.f) {}
2018-12-07 17:16:50 -08:00
2019-02-23 23:15:32 -08:00
constexpr CColor(float rgb, float a = 1.0) : mSimd(rgb, rgb, rgb, a) {}
2018-12-07 17:16:50 -08:00
2019-02-23 23:15:32 -08:00
constexpr CColor(float r, float g, float b, float a = 1.0f) : mSimd(r, g, b, a) {}
2022-05-13 23:46:19 -07:00
constexpr CColor(Comp32 rgba)
: mSimd(((COLOR(rgba) >> 0) & 0xff) * OneOver255, ((COLOR(rgba) >> 8) & 0xff) * OneOver255,
((COLOR(rgba) >> 16) & 0xff) * OneOver255, ((COLOR(rgba) >> 24) & 0xff) * OneOver255) {}
2018-12-07 17:16:50 -08:00
2022-05-13 23:46:19 -07:00
constexpr CColor(const Comp8* rgba)
: mSimd(rgba[0] * OneOver255, rgba[1] * OneOver255, rgba[2] * OneOver255, rgba[3] * OneOver255) {}
2018-12-07 17:16:50 -08:00
2019-02-23 23:15:32 -08:00
constexpr CColor(const CVector4f& other) : mSimd(other.mSimd) {}
2018-12-07 17:16:50 -08:00
template <typename T>
2019-02-23 23:15:32 -08:00
constexpr CColor(const simd<T>& s) : mSimd(s) {}
2018-12-07 17:16:50 -08:00
CColor& operator=(const CVector4f& other) {
mSimd = other.mSimd;
return *this;
}
#if ZE_ATHENA_TYPES
2016-12-22 12:35:29 -08:00
[[nodiscard]] static CColor ReadRGBABig(athena::io::IStreamReader& reader) {
2018-12-07 17:16:50 -08:00
CColor ret;
ret.readRGBABig(reader);
return ret;
}
void readRGBABig(athena::io::IStreamReader& reader) {
simd_floats f;
f[0] = reader.readFloatBig();
f[1] = reader.readFloatBig();
f[2] = reader.readFloatBig();
f[3] = reader.readFloatBig();
mSimd.copy_from(f);
}
void readBGRABig(athena::io::IStreamReader& reader) {
simd_floats f;
f[2] = reader.readFloatBig();
f[1] = reader.readFloatBig();
f[0] = reader.readFloatBig();
f[3] = reader.readFloatBig();
mSimd.copy_from(f);
}
void writeRGBABig(athena::io::IStreamWriter& writer) const {
simd_floats f(mSimd);
writer.writeFloatBig(f[0]);
writer.writeFloatBig(f[1]);
writer.writeFloatBig(f[2]);
writer.writeFloatBig(f[3]);
}
void writeBGRABig(athena::io::IStreamWriter& writer) const {
simd_floats f(mSimd);
writer.writeFloatBig(f[2]);
writer.writeFloatBig(f[1]);
writer.writeFloatBig(f[0]);
writer.writeFloatBig(f[3]);
}
void writeRGBA8(athena::io::IStreamWriter& writer) const {
simd_floats f(mSimd);
writer.writeUByte(atUint8(f[0] * 255));
writer.writeUByte(atUint8(f[1] * 255));
writer.writeUByte(atUint8(f[2] * 255));
writer.writeUByte(atUint8(f[3] * 255));
}
2015-11-25 17:26:23 -08:00
#endif
2018-12-07 17:16:50 -08:00
[[nodiscard]] bool operator==(const CColor& rhs) const {
2018-12-07 17:16:50 -08:00
return (r() == rhs.r() && g() == rhs.g() && b() == rhs.b() && a() == rhs.a());
}
[[nodiscard]] bool operator!=(const CColor& rhs) const { return !(*this == rhs); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator+(const CColor& rhs) const { return CColor(mSimd + rhs.mSimd).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator-(const CColor& rhs) const { return CColor(mSimd - rhs.mSimd).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator*(const CColor& rhs) const { return CColor(mSimd * rhs.mSimd).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator/(const CColor& rhs) const { return CColor(mSimd / rhs.mSimd).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator+(float val) const { return CColor(mSimd + simd<float>(val)).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator-(float val) const { return CColor(mSimd - simd<float>(val)).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator*(float val) const { return CColor(mSimd * simd<float>(val)).Clamp(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] CColor operator/(float val) const { return CColor(mSimd / simd<float>(val)).Clamp(); }
2018-12-07 17:16:50 -08:00
const CColor& operator+=(const CColor& rhs) {
mSimd += rhs.mSimd;
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator-=(const CColor& rhs) {
mSimd -= rhs.mSimd;
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator*=(const CColor& rhs) {
mSimd *= rhs.mSimd;
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator/=(const CColor& rhs) {
mSimd /= rhs.mSimd;
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator+=(float rhs) {
mSimd += simd<float>(rhs);
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator-=(float rhs) {
mSimd -= simd<float>(rhs);
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator*=(float rhs) {
mSimd *= simd<float>(rhs);
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
const CColor& operator/=(float rhs) {
mSimd /= simd<float>(rhs);
2019-03-24 01:06:25 -07:00
Clamp();
2018-12-07 17:16:50 -08:00
return *this;
}
void normalize() {
float mag = magnitude();
mag = 1.f / mag;
*this *= mag;
}
[[nodiscard]] CColor normalized() const {
2018-12-07 17:16:50 -08:00
float mag = magnitude();
mag = 1.f / mag;
return *this * mag;
}
[[nodiscard]] float magSquared() const { return mSimd.dot4(mSimd); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] float magnitude() const { return std::sqrt(magSquared()); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] static CColor lerp(const CColor& a, const CColor& b, float t) {
2018-12-07 17:16:50 -08:00
return zeus::simd<float>(1.f - t) * a.mSimd + b.mSimd * zeus::simd<float>(t);
}
[[nodiscard]] static CColor nlerp(const CColor& a, const CColor& b, float t) { return lerp(a, b, t).normalized(); }
2018-12-07 17:16:50 -08:00
[[nodiscard]] simd<float>::reference operator[](const size_t& idx) {
2018-12-07 17:16:50 -08:00
assert(idx < 4);
return mSimd[idx];
}
[[nodiscard]] float operator[](const size_t& idx) const {
2018-12-07 17:16:50 -08:00
assert(idx < 4);
return mSimd[idx];
}
void splat(float rgb, float a) {
mSimd = simd<float>(rgb);
mSimd[3] = a;
}
[[nodiscard]] float rgbDot(const CColor& rhs) const { return mSimd.dot3(rhs.mSimd); }
2018-12-07 17:16:50 -08:00
void fromRGBA8(const Comp8 ri, const Comp8 gi, const Comp8 bi, const Comp8 ai) {
mSimd = simd<float>(ri * OneOver255, gi * OneOver255, bi * OneOver255, ai * OneOver255);
}
void fromRGBA32(Comp32 rgba) {
2019-02-23 23:15:32 -08:00
RGBA32 tmp;
2018-12-07 17:16:50 -08:00
tmp.rgba = COLOR(rgba);
fromRGBA8(tmp.r, tmp.g, tmp.b, tmp.a);
}
/**
* @brief Converts a CColor to RGBA8
* @param ro Red component
* @param go Green component
* @param bo Blue component
* @param ao Alpha component
2018-12-07 17:16:50 -08:00
*/
void toRGBA8(Comp8& ro, Comp8& go, Comp8& bo, Comp8& ao) const {
ro = Comp8(r() * 255);
go = Comp8(g() * 255);
bo = Comp8(b() * 255);
ao = Comp8(a() * 255);
}
2022-05-13 23:46:19 -07:00
Comp32 toRGBA() const {
RGBA32 ret;
ret.r = r() * 255;
ret.g = g() * 255;
ret.b = b() * 255;
ret.a = a() * 255;
return ret.rgba;
}
[[nodiscard]] unsigned short toRGB5A3() const {
Comp8 r;
Comp8 g;
Comp8 b;
Comp8 a;
toRGBA8(r, g, b, a);
if (a == 255) {
return static_cast<unsigned short>((r & 0xf8) << 7 | (g & 0xf8) << 2 | b >> 3 | 0x8000);
}
return static_cast<unsigned short>((r & 0xf0) << 4 | (g & 0xf0) | b >> 4 | (a & 0xe0) << 7);
}
2018-12-07 17:16:50 -08:00
/**
* @brief Assigns rgba from hsv
* @param h[0-1] The hue percentage of the color.
2018-12-07 17:16:50 -08:00
* @param s[0-1] The saturation percentage of the color.
* @param v[0-1] The value percentage of the color.
* @param _a[0-1] The alpha percentage of the color.
2018-12-07 17:16:50 -08:00
*/
void fromHSV(float h, float s, float v, float _a = 1.0);
/**
* @brief Converts rgba to hsv
* @param h[0-1] The hue percentage of the color.
2018-12-07 17:16:50 -08:00
* @param s[0-1] The saturation percentage of the color.
* @param v[0-1] The value percentage of the color.
*/
void toHSV(float& h, float& s, float& v) const;
void fromHSL(float h, float s, float l, float _a = 1.0);
void toHSL(float& h, float& s, float& l) const;
[[nodiscard]] CColor toGrayscale() const { return {std::sqrt((r() * r() + g() * g() + b() * b()) / 3), a()}; }
2018-12-07 17:16:50 -08:00
/**
* @brief Clamps to GPU-safe RGBA values [0,1]
*/
2019-03-24 01:06:25 -07:00
CColor& Clamp() {
2018-12-07 17:16:50 -08:00
r() = std::min(1.f, std::max(0.f, float(r())));
g() = std::min(1.f, std::max(0.f, float(g())));
b() = std::min(1.f, std::max(0.f, float(b())));
a() = std::min(1.f, std::max(0.f, float(a())));
2019-03-24 01:06:25 -07:00
return *this;
2018-12-07 17:16:50 -08:00
}
[[nodiscard]] float r() const { return mSimd[0]; }
[[nodiscard]] float g() const { return mSimd[1]; }
[[nodiscard]] float b() const { return mSimd[2]; }
[[nodiscard]] float a() const { return mSimd[3]; }
2018-12-07 17:16:50 -08:00
[[nodiscard]] simd<float>::reference r() { return mSimd[0]; }
[[nodiscard]] simd<float>::reference g() { return mSimd[1]; }
[[nodiscard]] simd<float>::reference b() { return mSimd[2]; }
[[nodiscard]] simd<float>::reference a() { return mSimd[3]; }
2015-04-30 23:31:59 -07:00
};
2019-02-23 23:15:32 -08:00
constexpr CVector4f::CVector4f(const zeus::CColor& other) : mSimd(other.mSimd) {}
2015-04-30 23:31:59 -07:00
2019-02-23 23:15:32 -08:00
constexpr CVector4f& CVector4f::operator=(const CColor& other) {
mSimd = other.mSimd;
return *this;
}
constexpr inline CColor skRed(1.f, 0.f, 0.f, 1.f);
constexpr inline CColor skBlack(0.f, 0.f, 0.f, 1.f);
constexpr inline CColor skBlue(0.f, 0.f, 1.f, 1.f);
constexpr inline CColor skCyan(0.f, 1.f, 1.f, 1.f);
constexpr inline CColor skGreen(0.f, 1.f, 0.f, 1.f);
constexpr inline CColor skGrey(0.5f, 0.5f, 0.5f, 1.f);
constexpr inline CColor skMagenta(1.f, 0.f, 1.f, 1.f);
constexpr inline CColor skOrange(1.f, 0.43f, 0.f, 1.f);
constexpr inline CColor skPurple(0.63f, 0.f, 1.f, 1.f);
constexpr inline CColor skYellow(1.f, 1.f, 0.f, 1.f);
constexpr inline CColor skWhite(1.f, 1.f, 1.f, 1.f);
constexpr inline CColor skClear(0.f, 0.f, 0.f, 0.f);
[[nodiscard]] inline CColor operator+(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) + rhs.mSimd).Clamp();
}
[[nodiscard]] inline CColor operator-(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) - rhs.mSimd).Clamp();
}
2019-02-23 23:15:32 -08:00
[[nodiscard]] inline CColor operator*(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) * rhs.mSimd).Clamp();
}
2019-02-23 23:15:32 -08:00
[[nodiscard]] inline CColor operator/(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) / rhs.mSimd).Clamp();
}
2018-12-07 21:23:50 -08:00
} // namespace zeus
2019-05-07 20:49:27 -07:00
namespace std {
template <>
struct hash<zeus::CColor> {
size_t operator()(const zeus::CColor& color) const noexcept {
size_t ret = std::hash<float>()(color.r());
zeus::hash_combine_impl(ret, std::hash<float>()(color.g()));
zeus::hash_combine_impl(ret, std::hash<float>()(color.b()));
zeus::hash_combine_impl(ret, std::hash<float>()(color.a()));
return ret;
}
};
2022-05-13 23:46:19 -07:00
} // namespace std