jak-project/common/math/Vector.h

395 lines
8.7 KiB
C
Raw Normal View History

#pragma once
#include <cmath>
#include "third-party/fmt/core.h"
namespace math {
template <typename T, int Size>
class Vector {
public:
Vector() = default;
static Vector<T, Size> zero() {
Vector<T, Size> result;
for (auto& x : result.m_data) {
x = T(0);
}
return result;
}
template <typename... Args>
explicit Vector(Args... args) : m_data{T(args)...} {}
T* begin() { return &m_data[0]; }
T* end() { return &m_data[Size]; }
const T* begin() const { return &m_data[0]; }
const T* end() const { return &m_data[Size]; }
T& x() { return m_data[0]; }
const T& x() const { return m_data[0]; }
T& y() {
static_assert(Size >= 1, "Out of bounds");
return m_data[1];
}
const T& y() const {
static_assert(Size >= 1, "Out of bounds");
return m_data[1];
}
T& z() {
static_assert(Size >= 2, "Out of bounds");
return m_data[2];
}
const T& z() const {
static_assert(Size >= 2, "Out of bounds");
return m_data[2];
}
T& w() {
static_assert(Size >= 3, "Out of bounds");
return m_data[3];
}
const T& w() const {
static_assert(Size >= 3, "Out of bounds");
return m_data[3];
}
const T squared_length() const {
T sum = T(0);
for (auto val : m_data) {
sum += val * val;
}
return sum;
}
bool operator==(const Vector<T, Size>& other) const {
for (int i = 0; i < Size; i++) {
if (m_data[i] != other.m_data[i]) {
return false;
}
}
return true;
}
bool operator==(const T other) const {
for (int i = 0; i < Size; i++) {
if (m_data[i] != other) {
return false;
}
}
return true;
}
bool operator!=(const Vector<T, Size>& other) const { return !((*this) == other); }
bool operator!=(const T other) const { return !((*this) == other); }
const T length() const { return std::sqrt(squared_length()); }
Vector<T, Size> operator+(const Vector<T, Size>& other) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] + other[i];
}
return result;
}
Vector<T, Size> operator+(const T& other) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] + other;
}
return result;
}
Vector<T, Size>& operator+=(const Vector<T, Size>& other) {
for (int i = 0; i < Size; i++) {
m_data[i] += other[i];
}
return *this;
}
Vector<T, Size>& operator-=(const Vector<T, Size>& other) {
for (int i = 0; i < Size; i++) {
m_data[i] -= other[i];
}
return *this;
}
Vector<T, Size>& operator-=(const T& other) {
for (int i = 0; i < Size; i++) {
m_data[i] -= other;
}
return *this;
}
Vector<T, Size>& operator+=(const T& other) {
for (int i = 0; i < Size; i++) {
m_data[i] += other;
}
return *this;
}
Vector<T, Size> elementwise_multiply(const Vector<T, Size>& other) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] * other[i];
}
return result;
}
Vector<T, Size> operator-(const Vector<T, Size>& other) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] - other[i];
}
return result;
}
Vector<T, Size> operator-(const T& other) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] - other;
}
return result;
}
T dot(const Vector<T, Size>& other) const {
T result(0);
for (int i = 0; i < Size; i++) {
result += m_data[i] * other[i];
}
return result;
}
T operator[](int idx) const { return m_data[idx]; }
T& operator[](int idx) { return m_data[idx]; }
Vector<T, Size> operator/(const T& val) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] / val;
}
return result;
}
Vector<T, Size> operator*(const T& val) const {
Vector<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = m_data[i] * val;
}
return result;
}
Vector<T, Size>& operator*=(const T& val) {
for (int i = 0; i < Size; i++) {
m_data[i] *= val;
}
return *this;
}
Vector<T, Size>& operator/=(const T& val) {
for (int i = 0; i < Size; i++) {
m_data[i] /= val;
}
return *this;
}
2021-08-08 21:50:34 -04:00
Vector<T, Size> cross(const Vector<T, Size>& other) const {
static_assert(Size == 3, "Size for cross");
Vector<T, Size> result{y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(),
x() * other.y() - y() * other.x()};
2021-08-08 21:50:34 -04:00
return result;
}
Vector<T, Size> normalized(const T& norm = T(1)) const { return (*this) * (norm / length()); }
void normalize(const T& norm = T(1)) { *this = normalized(norm); }
void max_in_place(const Vector<T, Size>& other) {
for (int i = 0; i < Size; i++) {
m_data[i] = std::max(m_data[i], other[i]);
}
}
void min_in_place(const Vector<T, Size>& other) {
for (int i = 0; i < Size; i++) {
m_data[i] = std::min(m_data[i], other[i]);
}
}
std::string to_string_aligned() const {
std::string result = "[";
for (auto x : m_data) {
result.append(fmt::format("{:6.3f} ", x));
}
result.pop_back();
return result + "]";
}
std::string to_string_hex_byte() const {
std::string result = "[";
for (auto x : m_data) {
result.append(fmt::format("0x{:02x} ", x));
}
result.pop_back();
return result + "]";
}
[decomp] Decompile some time-of-day stuff, support new style Jak 2 time of day (#1943) - Add "tfrag-water" tfrag tree support (may just be the same as Jak 1's 'dirt' for the settings) - Add "tfrag-trans" tfrag tree support, reusing "trans-tfrag" from jak 1. - Add a hack to `LinkedObjectFileCreation` to handle `oracle`, which is accidentally multiply defined as a type leftover from jak 1 (an entity in village1), and level info for jak 2. - Add `VI1.DGO` - add `time-of-day.gc`, and a few other stub functions so it works - Set up some time of day stuff in GOAL for jak 2/PC renderers - Clean up time of day in c++ renderers, support the more complicated weight system used by jak 2 (backward compatible with jak 1, thankfully) The mood functions now run, so this could cause problems if they rely on stuff we don't have yet. But it seems fine for ctysluma and prison for now. ![image](https://user-images.githubusercontent.com/48171810/194719441-d185f59c-19dc-4cd3-a5c4-00b0cfe1d6c3.png) ![image](https://user-images.githubusercontent.com/48171810/194719449-6e051bf3-0750-42e5-a654-901313dbe479.png) ![image](https://user-images.githubusercontent.com/48171810/194719455-3ca6793e-873a-449a-8e85-9c20ffeb4da3.png) ![image](https://user-images.githubusercontent.com/48171810/194719461-8f27af17-4434-4492-96cd-8c5eec6eafdf.png) ![image](https://user-images.githubusercontent.com/48171810/194719468-720715b9-985a-4acf-928c-eab948cfcb03.png) ![image](https://user-images.githubusercontent.com/48171810/194719486-bfb91e83-f6ca-4585-80ad-3b2c0cbbd5af.png) ![image](https://user-images.githubusercontent.com/48171810/194719492-df065d2f-cb5a-47e3-a248-f5317c42082f.png) ![image](https://user-images.githubusercontent.com/48171810/194719507-91e1f477-ecfe-4d6c-b744-5f24646255ca.png)
2022-10-08 13:33:03 -04:00
std::string to_string_hex_word() const {
std::string result = "[";
for (auto x : m_data) {
result.append(fmt::format("0x{:08x} ", x));
}
result.pop_back();
return result + "]";
}
2021-08-07 18:57:13 -04:00
T* data() { return m_data; }
const T* data() const { return m_data; }
2021-08-08 21:50:34 -04:00
template <typename U>
Vector<U, Size> cast() const {
2021-08-08 21:50:34 -04:00
Vector<U, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = (U)m_data[i];
}
return result;
}
template <int len>
Vector<T, len> head() const {
static_assert(len < Size);
Vector<T, len> result;
for (int i = 0; i < len; i++) {
result[i] = m_data[i];
}
return result;
}
Vector<T, 3> xyz() const { return head<3>(); }
Vector<T, 2> xy() const { return head<2>(); }
void fill(const T& val) {
for (auto& x : m_data) {
x = val;
}
}
void set_zero() { fill(0); }
private:
T m_data[Size];
};
// column major
template <typename T, int Rows, int Cols>
struct Matrix {
Matrix() = default;
static Matrix zero() {
Matrix result;
for (auto& x : result.m_data) {
x = 0;
}
return result;
}
static Matrix identity() {
Matrix result;
for (int c = 0; c < Cols; c++) {
for (int r = 0; r < Rows; r++) {
result(r, c) = r == c ? T(1) : T(0);
}
}
return result;
}
void set_zero() {
for (auto& x : m_data) {
x = 0;
}
}
T& operator()(int r, int c) { return m_data[r + c * Rows]; }
const T& operator()(int r, int c) const { return m_data[r + c * Rows]; }
Vector<T, Rows> col(int c) const {
Vector<T, Rows> result;
for (int i = 0; i < Rows; i++) {
result[i] = m_data[c * Rows + i];
}
return result;
}
T* data() { return m_data; }
const T* data() const { return m_data; }
std::string to_string_aligned() const {
std::string result;
for (int row = 0; row < Rows; row++) {
result += "[";
for (int col = 0; col < Cols; col++) {
result.append(fmt::format("{:6.3f} ", m_data[row + col * Rows]));
}
result.pop_back();
result += "]\n";
}
return result;
}
template <int OtherCols>
Matrix<T, Rows, OtherCols> operator*(const Matrix<T, Cols, OtherCols>& y) const {
Matrix<T, Rows, OtherCols> result;
result.set_zero();
for (int rx = 0; rx < Rows; rx++) {
for (int cx = 0; cx < Cols; cx++) {
for (int yi = 0; yi < OtherCols; yi++) {
result(rx, yi) += operator()(rx, cx) * y(cx, yi);
}
}
}
return result;
}
Vector<T, Rows> operator*(const Vector<T, Cols>& y) const {
Vector<T, Rows> result;
result.set_zero();
for (int rx = 0; rx < Rows; rx++) {
for (int cx = 0; cx < Cols; cx++) {
result[rx] += operator()(rx, cx) * y[cx];
}
}
return result;
}
private:
T m_data[Rows * Cols];
};
template <typename T>
using Vector2 = Vector<T, 2>;
template <typename T>
using Vector3 = Vector<T, 3>;
template <typename T>
using Vector4 = Vector<T, 4>;
using Vector2f = Vector2<float>;
using Vector3f = Vector3<float>;
using Vector4f = Vector4<float>;
using Vector2d = Vector2<double>;
using Vector3d = Vector3<double>;
using Vector4d = Vector4<double>;
using Matrix4f = Matrix<float, 4, 4>;
} // namespace math