Initial commit

This commit is contained in:
Gericom
2025-11-22 17:21:45 +01:00
commit 5d6f67c612
517 changed files with 63025 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
#pragma once
#include "Rgb.h"
class Rgb8To5Table
{
u8 _table[256];
public:
constexpr Rgb8To5Table()
: _table()
{
for (u32 i = 0; i < 256; i++)
{
u32 value5 = (i * 63 + 255) / (255 * 2);
if (value5 > 31)
value5 = 31;
_table[i] = value5;
}
}
constexpr u8 Rgb8ToRgb5(u32 rgb8) const { return _table[rgb8]; }
};
class Rgb8To6Table
{
u8 _table[256];
public:
constexpr Rgb8To6Table()
: _table()
{
for (u32 i = 0; i < 256; i++)
_table[i] = (i * 63 + 128) / 255;
}
constexpr u8 Rgb8ToRgb6(u32 rgb8) const { return _table[rgb8]; }
};
class ColorConverter
{
static constexpr Rgb8To5Table sRgb8To5Table { };
static constexpr Rgb8To6Table sRgb8To6Table { };
public:
/// @brief Unpacks a 15 bit color with format xbbb bbgg gggr rrrr.
/// @param color The packed color.
/// @return The unpacked color.
static Rgb<5, 5, 5> FromXBGR555(u16 color)
{
return Rgb<5, 5, 5>(color & 0x1F, (color >> 5) & 0x1F, (color >> 10) & 0x1F);
}
/// @brief Packs a 15 bit color with format xbbb bbgg gggr rrrr.
/// Note that the color components are not clamped or masked.
/// @param color The color to pack.
/// @return The packed color.
static u16 ToXBGR555(const Rgb<5, 5, 5>& color)
{
return color.r | (color.g << 5) | (color.b << 10);
}
/// @brief Unpacks a 16 bit color with format Gbbb bbgg gggr rrrr.
/// With G an additional lsb of green forming a 6 bit value together with ggggg.
/// @param color The packed color.
/// @return The unpacked color.
static Rgb<5, 6, 5> FromGBGR565(u16 color)
{
return Rgb<5, 6, 5>(color & 0x1F, ((color >> 4) & 0x3E) | (color >> 15), (color >> 10) & 0x1F);
}
/// @brief Packs a 16 bit color with format Gbbb bbgg gggr rrrr.
/// With G an additional lsb of green forming a 6 bit value together with ggggg.
/// Note that the color components are not clamped or masked.
/// @param color The color to pack.
/// @return The packed color.
static u16 ToGBGR565(const Rgb<5, 6, 5>& color)
{
return color.r | ((color.g >> 1) << 5) | (color.b << 10) | (color.g << 15);
}
/// @brief Packs a 16 bit color with format Gbbb bbgg gggr rrrr.
/// With G an additional lsb of green forming a 6 bit value together with ggggg.
/// Note that the color components are not clamped or masked.
/// @param color The color to pack.
/// @return The packed color.
static u16 ToGBGR565(const Rgb<8, 8, 8>& color)
{
u32 r = sRgb8To5Table.Rgb8ToRgb5(color.r);
u32 g = sRgb8To6Table.Rgb8ToRgb6(color.g);
u32 b = sRgb8To5Table.Rgb8ToRgb5(color.b);
return r | ((g >> 1) << 5) | (b << 10) | (g << 15);
}
};

View File

@@ -0,0 +1,18 @@
#pragma once
struct Point
{
int x;
int y;
constexpr Point()
: x(0), y(0) { }
constexpr Point(int x, int y)
: x(x), y(y) { }
constexpr s64 DistanceSquaredTo(const Point& other) const
{
return (s64)(other.x - x) * (other.x - x) + (s64)(other.y - y) * (other.y - y);
}
};

View File

@@ -0,0 +1,74 @@
#pragma once
#include "Point.h"
/// @brief Class representing a 2d rectangle.
class Rectangle
{
int _x;
int _y;
int _width;
int _height;
public:
constexpr Rectangle(const Point& point, int width, int height)
: _x(point.x), _y(point.y), _width(width), _height(height) { }
constexpr Rectangle(const Point& topLeft, const Point& bottomRight)
: _x(topLeft.x), _y(topLeft.y)
, _width(bottomRight.x - topLeft.x), _height(bottomRight.y - topLeft.y) { }
constexpr Rectangle(int x, int y, int width, int height)
: _x(x), _y(y), _width(width), _height(height) { }
constexpr int GetX() const { return _x; }
constexpr int GetY() const { return _y; }
constexpr int GetWidth() const { return _width; }
constexpr int GetHeight() const { return _height; }
constexpr int GetLeft() const { return _x; }
constexpr int GetRight() const { return _x + _width; }
constexpr int GetTop() const { return _y; }
constexpr int GetBottom() const { return _y + _height; }
constexpr Point GetTopLeft() const { return Point(_x, _y); }
constexpr Point GetBottomRight() const { return Point(_x + _width, _y + _height); }
constexpr Point GetTopCenter() const { return Point(_x + (_width >> 1), _y); }
constexpr Point GetCenter() const { return Point(_x + (_width >> 1), _y + (_height >> 1)); }
constexpr Point GetBottomCenter() const { return Point(_x + (_width >> 1), _y); }
/// @brief Checks if the given rectangle overlaps with this rectangle.
/// @param other The rectangle to check.
/// @return True if the given rectangle overlaps with this rectangle,
/// or false otherwise.
constexpr bool OverlapsWith(const Rectangle& other) const
{
return GetLeft() < other.GetRight() && other.GetLeft() < GetRight()
&& GetTop() < other.GetBottom() && other.GetTop() < GetBottom();
}
/// @brief Checks if the given point is contained in this rectangle.
/// @param point The point to check.
/// @return True if the given point is contained in this rectangle,
/// or false otherwise.
constexpr bool Contains(const Point& point) const
{
return point.x >= GetLeft() && point.x < GetRight()
&& point.y >= GetTop() && point.y < GetBottom();
}
/// @brief Checks if the given rectangle is fully contained in this rectangle.
/// @param other The rectangle to check.
/// @return True if the given rectangle is fully contained in this rectangle,
/// or false otherwise.
constexpr bool Contains(const Rectangle& other) const
{
return other.GetLeft() >= GetLeft() && other.GetRight() <= GetRight()
&& other.GetTop() >= GetTop() && other.GetBottom() <= GetBottom();
}
constexpr Rectangle OffsetBy(const Point& point) const
{
return Rectangle(_x + point.x, _y + point.y, _width, _height);
}
};

View File

@@ -0,0 +1,77 @@
#pragma once
#include <algorithm>
#include "common.h"
template <u32 RBits, u32 GBits, u32 BBits>
class Rgb
{
public:
u8 r, g, b;
constexpr Rgb()
: r(0), g(0), b(0) { }
constexpr Rgb(u32 red, u32 green, u32 blue)
: r(red), g(green), b(blue) { }
constexpr Rgb(const Rgb<RBits, GBits, BBits>& rgb)
: r(rgb.r), g(rgb.g), b(rgb.b) { }
template <u32 RBits2, u32 GBits2, u32 BBits2>
explicit constexpr Rgb(const Rgb<RBits2, GBits2, BBits2>& rgb)
// {
// if (RBits2 > RBits)
// r = rgb.r >> (RBits2 - RBits);
// else if (RBits2 < RBits)
// r = rgb.r << (RBits - RBits2);
// else
// r = rgb.r;
// if (GBits2 > GBits)
// g = rgb.g >> (GBits2 - GBits);
// else if (GBits2 < GBits)
// g = rgb.g << (GBits - GBits2);
// else
// g = rgb.g;
// if (BBits2 > BBits)
// b = rgb.b >> (BBits2 - BBits);
// else if (BBits2 < BBits)
// b = rgb.b << (BBits - BBits2);
// else
// b = rgb.b;
// }
: r((rgb.r * ((1 << RBits) - 1) + ((1 << RBits2) >> 1)) / ((1 << RBits2) - 1))
, g((rgb.g * ((1 << GBits) - 1) + ((1 << GBits2) >> 1)) / ((1 << GBits2) - 1))
, b((rgb.b * ((1 << BBits) - 1) + ((1 << BBits2) >> 1)) / ((1 << BBits2) - 1)) { }
/// @brief Returns this color with its components clamped to their allowed range.
/// @return The clamped color.
constexpr Rgb Clamped() const
{
return Rgb(
std::clamp<u32>(r, 0, (1 << RBits) - 1),
std::clamp<u32>(g, 0, (1 << GBits) - 1),
std::clamp<u32>(b, 0, (1 << BBits) - 1));
}
/// @brief Adds the \p other color and clamps the resulting rgb values to their allowed range.
/// @param other The color to add.
/// @return The result of adding the colors and clamping the result.
constexpr Rgb operator+(const Rgb& other) const
{
return Rgb(
std::clamp<u32>(r + other.r, 0, (1 << RBits) - 1),
std::clamp<u32>(g + other.g, 0, (1 << GBits) - 1),
std::clamp<u32>(b + other.b, 0, (1 << BBits) - 1));
}
/// @brief Adds the \p other color and without clamping the resulting rgb values.
/// Note that this can cause an overflow.
/// @param other The color to add.
/// @return The result of adding the colors.
constexpr Rgb AddUnclamped(const Rgb& other) const
{
return Rgb(r + other.r, g + other.g, b + other.b);
}
};

View File

@@ -0,0 +1,26 @@
#pragma once
#include "Rgb.h"
#include "fixed.h"
#include "ColorConverter.h"
class RgbMixer
{
public:
template <u32 RBits, u32 GBits, u32 BBits>
static Rgb<RBits, GBits, BBits> Lerp(const Rgb<RBits, GBits, BBits>& from, const Rgb<RBits, GBits, BBits>& to, int t, int tMax)
{
return Rgb<RBits, GBits, BBits>(
(u32)((from.r * (tMax - t) + to.r * t) + (tMax >> 1)) / tMax,
(u32)((from.g * (tMax - t) + to.g * t) + (tMax >> 1)) / tMax,
(u32)((from.b * (tMax - t) + to.b * t) + (tMax >> 1)) / tMax);
}
static void MakeGradientPalette(u16* palette, const Rgb<8, 8, 8>& from, const Rgb<8, 8, 8>& to)
{
for (int i = 0; i < 16; i++)
{
auto newColor = Lerp(from, to, i, 15);
palette[i] = ColorConverter::ToGBGR565(newColor);
}
}
};

View File

@@ -0,0 +1,29 @@
#pragma once
#include <cmath>
#include "fixed.h"
template<int N>
class SinTable
{
struct sin_cos_t
{
fix16<14> sin = 0;
fix16<14> cos = 0;
};
sin_cos_t _table[N];
public:
constexpr SinTable()
: _table()
{
for (auto i = 0; i < N; i++)
_table[i] = { sin(i * 2 * M_PI / N), cos(i * 2 * M_PI / N) };
}
constexpr fix16<14> Sin(u16 angle) const { return _table[(angle * N) >> 16].sin; }
constexpr fix16<14> Cos(u16 angle) const { return _table[(angle * N) >> 16].cos; }
constexpr const sin_cos_t& SinCos(u16 angle) const { return _table[(angle * N) >> 16]; }
};
constexpr SinTable<4096> gSinTable = SinTable<4096>();

View File

@@ -0,0 +1,479 @@
#pragma once
#include <libtwl/math/mathDiv.h>
template <typename T, u32 FractionBits>
class fixed
{
protected:
T _value;
constexpr fixed(T rawValue, int dummy)
: _value(rawValue) { }
public:
constexpr fixed() { }
template <typename T2>
constexpr fixed(fixed<T2, FractionBits> value)
: _value(value.GetRawValue()) { }
template <typename T2, u32 OtherFractionBits>
explicit constexpr fixed(fixed<T2, OtherFractionBits> value)
{
if (FractionBits == OtherFractionBits)
_value = value.GetRawValue();
else if (OtherFractionBits < FractionBits)
_value = value.GetRawValue() << (FractionBits - OtherFractionBits);
else
{
const T2 rounding = (T2)(1ULL << ((OtherFractionBits - FractionBits) - 1));
const int shift = OtherFractionBits - FractionBits;
_value = (value.GetRawValue() + rounding) >> shift;
}
}
constexpr fixed(int value)
: _value(value << FractionBits) { }
constexpr fixed(s64 value)
: _value(value << FractionBits) { }
constexpr fixed(float value)
: _value(std::round(value * (1 << FractionBits))) { }
constexpr fixed(double value)
: _value(std::round(value * (1 << FractionBits))) { }
constexpr fixed(long double value)
: _value(std::round(value * (1 << FractionBits))) { }
constexpr T Int() const
{
return _value >> FractionBits;
}
constexpr T GetRawValue() const { return _value; }
};
template <u32 FractionBits>
class fix32;
template <u32 FractionBits>
class fix64;
template <u32 FractionBits>
class fix16 : public fixed<s16, FractionBits>
{
constexpr fix16(s16 rawValue, int dummy)
: fixed<s16, FractionBits>(rawValue, dummy) { }
public:
constexpr fix16() { }
constexpr fix16(const fix16<FractionBits>& value)
: fixed<s16, FractionBits>(value) { }
template <typename T2, u32 OtherFractionBits>
explicit constexpr fix16(const fixed<T2, OtherFractionBits>& value)
: fixed<s16, FractionBits>(value) { }
constexpr fix16(s16 value)
: fixed<s16, FractionBits>(value) { }
constexpr fix16(int value)
: fixed<s16, FractionBits>(value) { }
constexpr fix16(float value)
: fixed<s16, FractionBits>(value) { }
constexpr fix16(double value)
: fixed<s16, FractionBits>(value) { }
constexpr fix16(long double value)
: fixed<s16, FractionBits>(value) { }
constexpr bool operator<(const fix16& other) const
{
return this->_value < other._value;
}
constexpr bool operator<=(const fix16& other) const
{
return this->_value <= other._value;
}
constexpr bool operator>(const fix16& other) const
{
return this->_value > other._value;
}
constexpr bool operator>=(const fix16& other) const
{
return this->_value >= other._value;
}
constexpr fix16 operator-() const
{
return FromRawValue(-this->_value);
}
constexpr fix16 operator+(const fix16& other) const
{
return FromRawValue(this->_value + other._value);
}
template <typename TOther>
constexpr fix16 operator+(TOther other) const
{
return FromRawValue(this->_value + fix16(other)._value);
}
template <typename TLhs>
constexpr friend fix16 operator+(TLhs lhs, const fix16& rhs)
{
return FromRawValue(fix16(lhs)._value + rhs._value);
}
constexpr fix16 operator-(const fix16& other) const
{
return FromRawValue(this->_value - other._value);
}
template <typename TOther>
constexpr fix16 operator-(TOther other) const
{
return FromRawValue(this->_value - fix16(other)._value);
}
template <typename TLhs>
constexpr friend fix16 operator-(TLhs lhs, fix16 rhs)
{
return FromRawValue(fix16(lhs)._value - rhs._value);
}
constexpr fix16 operator<<(int rhs) const
{
return FromRawValue(this->_value << rhs);
}
constexpr fix16 operator>>(int rhs) const
{
return FromRawValue(this->_value >> rhs);
}
constexpr fix16 abs() const
{
return FromRawValue(std::abs(this->_value));
}
template <u32 OtherFractionBits>
constexpr fix32<FractionBits + OtherFractionBits> LongMul(const fix16<OtherFractionBits>& other) const
{
return fix32<FractionBits + OtherFractionBits>::FromRawValue(this->_value * other.GetRawValue());
}
template <u32 OtherFractionBits>
constexpr fix64<FractionBits + OtherFractionBits> LongMul(const fix32<OtherFractionBits>& other) const
{
return fix64<FractionBits + OtherFractionBits>::FromRawValue(this->_value * (s64)other._value);
}
template <u32 OtherFractionBits>
constexpr fix16 operator*(const fix16<OtherFractionBits>& other) const
{
return fix16(LongMul(other));
}
template <u32 OtherFractionBits>
constexpr fix16 operator*(const fix32<OtherFractionBits>& other) const
{
return fix16(LongMul(other));
}
constexpr fix16 operator*(s16 other) const
{
return FromRawValue(this->_value * other);
}
constexpr friend fix16 operator*(s16 lhs, const fix16& rhs)
{
return FromRawValue(lhs * rhs.GetRawValue());
}
template <u32 OtherFractionBits>
constexpr fix16 operator/(const fix16<OtherFractionBits>& other) const
{
s32 lhs = (s32)this->_value << 16;
s32 rhs = other.GetRawValue();
s32 divResult;
if (std::is_constant_evaluated())
divResult = lhs / rhs;
else
divResult = math_div32(lhs, rhs);
return fix16(fix32<FractionBits + 16 - OtherFractionBits>::FromRawValue(divResult));
}
static constexpr fix16 FromRawValue(s16 value)
{
return fix16(value, 0);
}
};
template <u32 FractionBits>
class fix32 : public fixed<int, FractionBits>
{
constexpr fix32(int rawValue, int dummy)
: fixed<int, FractionBits>(rawValue, dummy) { }
public:
constexpr fix32() { }
constexpr fix32(const fix16<FractionBits>& value)
: fixed<int, FractionBits>(value) { }
constexpr fix32(const fix32<FractionBits>& value)
: fixed<int, FractionBits>(value) { }
template <typename T2, u32 OtherFractionBits>
explicit constexpr fix32(const fixed<T2, OtherFractionBits>& value)
: fixed<int, FractionBits>(value) { }
constexpr fix32(int value)
: fixed<int, FractionBits>(value) { }
constexpr fix32(float value)
: fixed<int, FractionBits>(value) { }
constexpr fix32(double value)
: fixed<int, FractionBits>(value) { }
constexpr fix32(long double value)
: fixed<int, FractionBits>(value) { }
constexpr bool operator==(const fix32& other) const
{
return this->_value == other._value;
}
constexpr bool operator!=(const fix32& other) const
{
return this->_value != other._value;
}
constexpr bool operator<(const fix32& other) const
{
return this->_value < other._value;
}
constexpr bool operator<=(const fix32& other) const
{
return this->_value <= other._value;
}
constexpr bool operator>(const fix32& other) const
{
return this->_value > other._value;
}
constexpr bool operator>=(const fix32& other) const
{
return this->_value >= other._value;
}
constexpr fix32 operator-() const
{
return FromRawValue(-this->_value);
}
constexpr fix32 operator+(const fix32& other) const
{
return FromRawValue(this->_value + other._value);
}
template <typename TOther>
constexpr fix32 operator+(TOther other) const
{
return FromRawValue(this->_value + fix32(other)._value);
}
template <typename TLhs>
constexpr friend fix32 operator+(TLhs lhs, const fix32& rhs)
{
return FromRawValue(fix32(lhs)._value + rhs._value);
}
constexpr fix32 operator-(const fix32& other) const
{
return FromRawValue(this->_value - other._value);
}
constexpr fix32 operator-(int other) const
{
return FromRawValue(this->_value - fix32(other)._value);
}
constexpr friend fix32 operator-(int lhs, const fix32& rhs)
{
return FromRawValue(fix32(lhs)._value - rhs._value);
}
constexpr fix32 operator/(int other) const
{
return FromRawValue(this->_value / other);
}
constexpr fix32 operator<<(int rhs) const
{
return FromRawValue(this->_value << rhs);
}
constexpr fix32 operator>>(int rhs) const
{
return FromRawValue(this->_value >> rhs);
}
constexpr fix32 Abs() const
{
return FromRawValue(std::abs(this->_value));
}
template <u32 OtherFractionBits>
constexpr fix64<FractionBits + OtherFractionBits> LongMul(const fix16<OtherFractionBits>& other) const
{
return fix64<FractionBits + OtherFractionBits>::FromRawValue((s64)this->_value * other.GetRawValue());
}
template <u32 OtherFractionBits>
constexpr fix64<FractionBits + OtherFractionBits> LongMul(const fix32<OtherFractionBits>& other) const
{
return fix64<FractionBits + OtherFractionBits>::FromRawValue((s64)this->_value * other.GetRawValue());
}
constexpr fix64<FractionBits> LongMul(int other) const
{
return fix64<FractionBits>::FromRawValue((s64)this->_value * other);
}
template <u32 OtherFractionBits>
constexpr fix32 operator*(const fix16<OtherFractionBits>& other) const
{
return fix32(LongMul(other));
}
template <u32 OtherFractionBits>
constexpr fix32 operator*(const fix32<OtherFractionBits>& other) const
{
return fix32(LongMul(other));
}
constexpr fix32 operator*(int other) const
{
return FromRawValue(this->_value * other);
}
constexpr friend fix32 operator*(int lhs, const fix32& rhs)
{
return FromRawValue(lhs * rhs.GetRawValue());
}
template <u32 OtherFractionBits>
constexpr fix32 operator/(const fix16<OtherFractionBits>& other) const
{
s64 lhs = (s64)this->_value << 32;
s32 rhs = other.GetRawValue();
s64 divResult;
if (std::is_constant_evaluated())
divResult = lhs / rhs;
else
divResult = math_div6432(lhs, rhs);
return fix32(fix64<FractionBits + 32 - OtherFractionBits>::FromRawValue(divResult));
}
template <u32 OtherFractionBits>
constexpr fix32 operator/(const fix32<OtherFractionBits>& other) const
{
s64 lhs = (s64)this->_value << 32;
s32 rhs = other.GetRawValue();
s64 divResult;
if (std::is_constant_evaluated())
divResult = lhs / rhs;
else
divResult = math_div6432(lhs, rhs);
return fix32(fix64<FractionBits + 32 - OtherFractionBits>::FromRawValue(divResult));
}
static constexpr fix32 FromRawValue(int value)
{
return fix32(value, 0);
}
};
// static constexpr fix32<12> operator""fx(long double value) { return fix32<12>(value); }
template <u32 FractionBits>
class fix64 : public fixed<s64, FractionBits>
{
constexpr fix64(s64 rawValue, int dummy)
: fixed<s64, FractionBits>(rawValue, dummy) { }
public:
constexpr fix64() { }
template <typename T2>
constexpr fix64(const fixed<T2, FractionBits>& value)
: fixed<s64, FractionBits>(value) { }
template <typename T2, u32 OtherFractionBits>
explicit constexpr fix64(const fixed<T2, OtherFractionBits>& value)
: fixed<s64, FractionBits>(value) { }
constexpr fix64(int value)
: fixed<s64, FractionBits>(value) { }
constexpr fix64(s64 value)
: fixed<s64, FractionBits>(value) { }
constexpr fix64(float value)
: fixed<s64, FractionBits>(value) { }
constexpr fix64(double value)
: fixed<s64, FractionBits>(value) { }
constexpr fix64(long double value)
: fixed<s64, FractionBits>(value) { }
constexpr bool operator<(const fix64& other) const
{
return this->_value < other._value;
}
constexpr bool operator<=(const fix64& other) const
{
return this->_value <= other._value;
}
constexpr bool operator>(const fix64& other) const
{
return this->_value > other._value;
}
constexpr bool operator>=(const fix64& other) const
{
return this->_value >= other._value;
}
constexpr fix64 operator+(const fix64& other) const
{
return FromRawValue(this->_value + other._value);
}
constexpr fix64 operator-(const fix64& other) const
{
return FromRawValue(this->_value - other._value);
}
static constexpr fix64 FromRawValue(s64 value)
{
return fix64(value, 0);
}
};