Implement swizzles

This commit is contained in:
Joshua Ashton 2022-08-13 09:39:26 +00:00
parent 7024d9b5a8
commit 4ca37f3d5c
2 changed files with 217 additions and 49 deletions

View File

@ -0,0 +1,196 @@
#pragma once
#include <Orange/Core/Array.h>
namespace orange
{
template <typename T, size_t Alignment, size_t Size>
struct alignas(Alignment) Swizzle
{
Array<T, Size> data;
// TODO: Deduplicate these constructors... somehow
constexpr Swizzle()
: data{ } {}
constexpr explicit Swizzle(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Swizzle(const T components[Size])
{
Copy(&components[0], &components[Size], data.begin());
}
};
template <typename T, size_t Alignment>
struct alignas(Alignment) Swizzle<T, Alignment, 1>
{
union
{
Array<T, 1> data;
struct
{
float x;
};
struct
{
float r;
};
};
constexpr Swizzle()
: data{ } {}
constexpr explicit Swizzle(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Swizzle(const T components[1])
{
Copy(&components[0], &components[1], data.begin());
}
template <typename... Args>
constexpr Swizzle(const Args&... args)
: data {{ args... }}
{
static_assert(sizeof...(Args) == 1);
}
constexpr Swizzle(const Swizzle& other) = default;
};
template <typename T, size_t Alignment>
struct alignas(Alignment) Swizzle<T, Alignment, 2>
{
union
{
Array<T, 2> data;
struct
{
float x;
float y;
};
struct
{
float r;
float g;
};
};
constexpr Swizzle()
: data{ } {}
constexpr explicit Swizzle(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Swizzle(const T components[2])
{
Copy(&components[0], &components[2], data.begin());
}
template <typename... Args>
constexpr Swizzle(const Args&... args)
: data {{ args... }}
{
static_assert(sizeof...(Args) == 2);
}
constexpr Swizzle(const Swizzle& other) = default;
};
template <typename T, size_t Alignment>
struct alignas(Alignment) Swizzle<T, Alignment, 3>
{
union
{
Array<T, 3> data;
struct
{
float x;
float y;
float z;
};
struct
{
float r;
float g;
float b;
};
};
constexpr Swizzle()
: data{ } {}
constexpr explicit Swizzle(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Swizzle(const T components[3])
{
Copy(&components[0], &components[3], data.begin());
}
template <typename... Args>
constexpr Swizzle(const Args&... args)
: data {{ args... }}
{
static_assert(sizeof...(Args) == 3);
}
constexpr Swizzle(const Swizzle& other) = default;
};
template <typename T, size_t Alignment>
struct alignas(Alignment) Swizzle<T, Alignment, 4>
{
union
{
Array<T, 4> data;
struct
{
float x;
float y;
float z;
float w;
};
struct
{
float r;
float g;
float b;
float a;
};
};
constexpr Swizzle()
: data{ } {}
constexpr explicit Swizzle(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Swizzle(const T components[4])
{
Copy(&components[0], &components[4], data.begin());
}
template <typename... Args>
constexpr Swizzle(const Args&... args)
: data {{ args... }}
{
static_assert(sizeof...(Args) == 4);
}
constexpr Swizzle(const Swizzle& other) = default;
};
}

View File

@ -5,46 +5,38 @@
#include <Orange/Core/Array.h>
#include <Orange/Math/Basic.h>
#include <Orange/Math/Swizzle.h>
namespace orange
{
// Align to 16 if the size is a multiple of 4 and T is 4 bytes in size.
// to take advantage of aligned load/stores.
template <typename T, size_t Size>
struct Vec
struct VectorAlignmentHelper
{
static constexpr size_t Alignment =
(Size % 4zu == 0 && sizeof(T) == 4zu)
? Max<size_t>(16zu, alignof(T))
: alignof(T);
};
template <typename T, size_t Size>
struct Vec : public Swizzle<T, VectorAlignmentHelper<T, Size>::Alignment, Size>
{
static constexpr size_t Alignment = VectorAlignmentHelper<T, Size>::Alignment;
using DefaultLengthType = DefaultLengthTypeResolver<T>::LengthType;
using DefaultLengthVec = Vec<DefaultLengthType, Size>;
constexpr Vec()
: data{ } {}
using Swizzle<T, Alignment, Size>::Swizzle;
constexpr explicit Vec(T splat)
{
Fill(data.begin(), data.end(), splat);
}
constexpr Vec(const T components[Size])
{
Copy(&components[0], &components[Size], data.begin());
}
template <typename... Args>
constexpr Vec(const Args&... args)
: data {{ args... }}
{
static_assert(sizeof...(Args) == Size);
}
constexpr Vec(const Vec& other) = default;
constexpr T& operator[](size_t index) { return this->data[index]; }
constexpr const T& operator[](size_t index) const { return this->data[index]; }
constexpr T& operator[](size_t index) { return data[index]; }
constexpr const T& operator[](size_t index) const { return data[index]; }
constexpr const T* begin() const { return data.begin(); }
constexpr T* begin() { return data.begin(); }
constexpr const T* end() const { return data.end(); }
constexpr T* end() { return data.end(); }
constexpr const T* begin() const { return this->data.begin(); }
constexpr T* begin() { return this->data.begin(); }
constexpr const T* end() const { return this->data.end(); }
constexpr T* end() { return this->data.end(); }
constexpr bool operator==(const Vec& other) const
@ -188,26 +180,6 @@ namespace orange
static constexpr Vec Zero = Vec{ T{ 0 } };
static constexpr Vec Identity = Vec{ T{ 1 } };
// Align to 16 if the size is a multiple of 4 and T is 4 bytes in size.
// to take advantage of aligned load/stores.
static constexpr size_t Alignment =
(Size % 4zu == 0 && sizeof(T) == 4zu)
? Max<size_t>(16zu, alignof(T))
: alignof(T);
union
{
alignas(Alignment) Array<T, Size> data;
struct
{
alignas(Alignment) float x;
float y;
float z;
float w;
};
};
};
template <typename T, size_t Size>