Rewrite math vector implementation and add tests
This new implementation consolidates vec2/3/4 into one base class and improves performance.
This commit is contained in:
parent
b7decb3923
commit
64f44984b6
100
include/mtl/tests/vec.hpp
Normal file
100
include/mtl/tests/vec.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "mtl/test.hpp"
|
||||
|
||||
#include "mtl/vec.hpp"
|
||||
|
||||
namespace mtl {
|
||||
|
||||
namespace test {
|
||||
|
||||
class vec_suite : public suite<vec_suite> {
|
||||
public:
|
||||
vec_suite() {
|
||||
add_test(&construction_v2, "construction");
|
||||
add_test(&construction_v3, "construction");
|
||||
add_test(&construction_v4, "construction");
|
||||
|
||||
add_test(&addition_v2, "addition_v2");
|
||||
add_test(&addition_v3, "addition_v3");
|
||||
add_test(&addition_v4, "addition_v4");
|
||||
add_test(&subtraction_v2, "subtraction_v2");
|
||||
add_test(&subtraction_v3, "subtraction_v3");
|
||||
add_test(&subtraction_v4, "subtraction_v4");
|
||||
add_test(&negation_v2, "negation_v2");
|
||||
add_test(&negation_v3, "negation_v3");
|
||||
add_test(&negation_v4, "negation_v4");
|
||||
add_test(&mult_scalar_v2, "mult_scalar_v2");
|
||||
add_test(&mult_scalar_v3, "mult_scalar_v3");
|
||||
add_test(&mult_scalar_v4, "mult_scalar_v4");
|
||||
add_test(&dot_v2, "dot_v2");
|
||||
add_test(&dot_v3, "dot_v3");
|
||||
add_test(&dot_v4, "dot_v4");
|
||||
add_test(&division_scalar_v2, "division_scalar_v2");
|
||||
add_test(&division_scalar_v3, "division_scalar_v3");
|
||||
add_test(&division_scalar_v4, "division_scalar_v4");
|
||||
add_test(&magnitude_sqr_v2, "magnitude_sqr_v2");
|
||||
add_test(&magnitude_sqr_v3, "magnitude_sqr_v3");
|
||||
add_test(&magnitude_sqr_v4, "magnitude_sqr_v4");
|
||||
add_test(&transpose_v2, "transpose_v2");
|
||||
add_test(&transpose_v3, "transpose_v3");
|
||||
add_test(&transpose_v4, "transpose_v4");
|
||||
}
|
||||
|
||||
virtual string_view name() {
|
||||
return "vec_suite";
|
||||
}
|
||||
|
||||
static bool construction_v2() {
|
||||
vec2 a(1, 2);
|
||||
|
||||
return a.x == 1 && a.y == 2;
|
||||
}
|
||||
static bool construction_v3() {
|
||||
vec3 a(1, 2, 3);
|
||||
|
||||
return a.x == 1 && a.y == 2 && a.z == 3;
|
||||
}
|
||||
static bool construction_v4() {
|
||||
vec4 a(1, 2, 3, 4);
|
||||
|
||||
return a.x == 1 && a.y == 2 && a.z == 3 && a.w == 4;
|
||||
}
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool addition_v2();
|
||||
GBA_IWRAM ARM_MODE static bool addition_v3();
|
||||
GBA_IWRAM ARM_MODE static bool addition_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool subtraction_v2();
|
||||
GBA_IWRAM ARM_MODE static bool subtraction_v3();
|
||||
GBA_IWRAM ARM_MODE static bool subtraction_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool negation_v2();
|
||||
GBA_IWRAM ARM_MODE static bool negation_v3();
|
||||
GBA_IWRAM ARM_MODE static bool negation_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool mult_scalar_v2();
|
||||
GBA_IWRAM ARM_MODE static bool mult_scalar_v3();
|
||||
GBA_IWRAM ARM_MODE static bool mult_scalar_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool dot_v2();
|
||||
GBA_IWRAM ARM_MODE static bool dot_v3();
|
||||
GBA_IWRAM ARM_MODE static bool dot_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool division_scalar_v2();
|
||||
GBA_IWRAM ARM_MODE static bool division_scalar_v3();
|
||||
GBA_IWRAM ARM_MODE static bool division_scalar_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool magnitude_sqr_v2();
|
||||
GBA_IWRAM ARM_MODE static bool magnitude_sqr_v3();
|
||||
GBA_IWRAM ARM_MODE static bool magnitude_sqr_v4();
|
||||
|
||||
GBA_IWRAM ARM_MODE static bool transpose_v2();
|
||||
GBA_IWRAM ARM_MODE static bool transpose_v3();
|
||||
GBA_IWRAM ARM_MODE static bool transpose_v4();
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace mtl
|
||||
|
||||
163
include/mtl/vec.hpp
Normal file
163
include/mtl/vec.hpp
Normal file
@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include "mtl/target.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "mtl/fixed.hpp"
|
||||
|
||||
namespace mtl {
|
||||
|
||||
template <size_t M, size_t N>
|
||||
class mat;
|
||||
|
||||
template <size_t N>
|
||||
class vec {
|
||||
public:
|
||||
fixed e[N];
|
||||
|
||||
constexpr vec() noexcept {}
|
||||
|
||||
constexpr vec(const vec<N>& other) noexcept {
|
||||
// We need to explicitly define the copy constructor, otherwise
|
||||
// GCC uses memcpy to copy while in Thumb mode, and that's slow.
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
e[i] = other.e[i];
|
||||
}
|
||||
}
|
||||
constexpr vec(const fixed (&_e)[N]) noexcept {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
e[i] = _e[i];
|
||||
}
|
||||
}
|
||||
|
||||
constexpr fixed& operator[](size_t i) noexcept {
|
||||
return e[i];
|
||||
}
|
||||
constexpr const fixed& operator[](size_t i) const noexcept {
|
||||
return e[i];
|
||||
}
|
||||
|
||||
vec<N> operator+(const vec<N>& rhs) const noexcept {
|
||||
vec<N> res;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
res[i] = e[i] + rhs[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
vec<N> operator-(const vec<N>& rhs) const noexcept {
|
||||
vec<N> res;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
res[i] = e[i] - rhs[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
vec<N> operator-() const noexcept {
|
||||
vec<N> res;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
res[i] = -e[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
vec<N> operator*(fixed rhs) const noexcept {
|
||||
vec<N> res;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
res[i] = e[i] * rhs;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
friend vec<N> operator*(fixed lhs, vec<N> rhs) noexcept {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
fixed operator*(const vec<N>& rhs) const noexcept {
|
||||
fixed res;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
res += e[i] * rhs[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
vec<N> operator/(fixed rhs) const noexcept {
|
||||
vec<N> r;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
r[i] = e[i] / rhs;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
fixed magnitude_sqr() const noexcept {
|
||||
fixed r;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
r += e[i] * e[i];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
mat<1, N> transpose() const noexcept;
|
||||
};
|
||||
|
||||
class vec2 : public vec<2> {
|
||||
public:
|
||||
fixed& x = e[0];
|
||||
fixed& y = e[1];
|
||||
|
||||
constexpr vec2() noexcept {}
|
||||
constexpr vec2(const vec<2>& other) noexcept : vec(other) {}
|
||||
constexpr vec2(fixed _x, fixed _y) noexcept {
|
||||
x = _x;
|
||||
y = _y;
|
||||
}
|
||||
};
|
||||
|
||||
class vec3 : public vec<3> {
|
||||
public:
|
||||
fixed& x = e[0];
|
||||
fixed& y = e[1];
|
||||
fixed& z = e[2];
|
||||
|
||||
constexpr vec3() noexcept {}
|
||||
constexpr vec3(const vec<3>& other) noexcept : vec(other) {}
|
||||
constexpr vec3(fixed _x, fixed _y, fixed _z) noexcept {
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
};
|
||||
|
||||
class vec4 : public vec<4> {
|
||||
public:
|
||||
fixed& x = e[0];
|
||||
fixed& y = e[1];
|
||||
fixed& z = e[2];
|
||||
fixed& w = e[3];
|
||||
|
||||
constexpr vec4() noexcept {}
|
||||
constexpr vec4(const vec<4>& other) noexcept : vec(other) {}
|
||||
constexpr vec4(fixed _x, fixed _y, fixed _z, fixed _w) noexcept {
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
w = _w;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mtl
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "mtl/target.hpp"
|
||||
|
||||
#include "mtl/fixed.hpp"
|
||||
|
||||
TARGET_ARM_MODE
|
||||
|
||||
namespace mtl {
|
||||
|
||||
class vec4 {
|
||||
public:
|
||||
fixed x, y, z, w;
|
||||
|
||||
constexpr vec4(fixed _x = 0, fixed _y = 0, fixed _z = 0, fixed _w = 0)
|
||||
: x(_x), y(_y), z(_z), w(_w) {}
|
||||
|
||||
vec4 operator+(const vec4& rhs) const;
|
||||
vec4 operator-(const vec4& rhs) const;
|
||||
|
||||
vec4 operator*(fixed rhs) const;
|
||||
friend vec4 operator*(fixed lhs, const vec4& rhs) {
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
fixed operator*(const vec4& rhs) const;
|
||||
|
||||
fixed magnitude_sqr() const;
|
||||
};
|
||||
|
||||
} // namespace mtl
|
||||
|
||||
TARGET_END_MODE
|
||||
|
||||
261
src/tests/vec.cpp
Normal file
261
src/tests/vec.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
#include "mtl/tests/vec.hpp"
|
||||
|
||||
#include "mtl/target.hpp"
|
||||
#include "mtl/vec.hpp"
|
||||
|
||||
namespace mtl {
|
||||
|
||||
namespace test {
|
||||
|
||||
bool vec_suite::addition_v2() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec2 operator()(vec2 a, vec2 b) {
|
||||
return a + b;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec2 c = f(vec2(1, 2), vec2(10, 20));
|
||||
|
||||
return c.x == 11 && c.y == 22;
|
||||
}
|
||||
bool vec_suite::addition_v3() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec3 operator()(vec3 a, vec3 b) {
|
||||
return a + b;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec3 c = f(vec3(1, 2, 3), vec3(10, 20, 30));
|
||||
|
||||
return c.x == 11 && c.y == 22 && c.z == 33;
|
||||
}
|
||||
bool vec_suite::addition_v4() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec4 operator()(vec4 a, vec4 b) {
|
||||
return a + b;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec4 c = f(vec4(1, 2, 3, 4), vec4(10, 20, 30, 40));
|
||||
|
||||
return c.x == 11 && c.y == 22 && c.z == 33 && c.w == 44;
|
||||
}
|
||||
|
||||
bool vec_suite::subtraction_v2() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec2 operator()(vec2 a, vec2 b) {
|
||||
return a - b;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec2 c = f(vec2(10, 20), vec2(1, 2));
|
||||
|
||||
return c.x == 9 && c.y == 18;
|
||||
}
|
||||
bool vec_suite::subtraction_v3() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec3 operator()(vec3 a, vec3 b) {
|
||||
return a - b;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec3 c = f(vec3(10, 20, 30), vec3(1, 2, 3));
|
||||
|
||||
return c.x == 9 && c.y == 18 && c.z == 27;
|
||||
}
|
||||
bool vec_suite::subtraction_v4() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec4 operator()(vec4 a, vec4 b) {
|
||||
return a - b;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec4 c = f(vec4(10, 20, 30, 40), vec4(1, 2, 3, 4));
|
||||
|
||||
return c.x == 9 && c.y == 18 && c.z == 27 && c.w == 36;
|
||||
}
|
||||
|
||||
bool vec_suite::negation_v2() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec2 operator()(vec2 a) {
|
||||
return -a;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec2 c = f(vec2(10, 20));
|
||||
|
||||
return c.x == -10 && c.y == -20;
|
||||
}
|
||||
bool vec_suite::negation_v3() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec3 operator()(vec3 a) {
|
||||
return -a;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec3 c = f(vec3(10, 20, 30));
|
||||
|
||||
return c.x == -10 && c.y == -20 && c.z == -30;
|
||||
}
|
||||
bool vec_suite::negation_v4() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec4 operator()(vec4 a) {
|
||||
return -a;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec4 c = f(vec4(10, 20, 30, 40));
|
||||
|
||||
return c.x == -10 && c.y == -20 && c.z == -30 && c.w == -40;
|
||||
}
|
||||
|
||||
bool vec_suite::mult_scalar_v2() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec2 operator()(vec2 a, fixed x) {
|
||||
return a * x;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec2 c = f(vec2(10, 20), 10);
|
||||
|
||||
return c.x == 100 && c.y == 200;
|
||||
}
|
||||
bool vec_suite::mult_scalar_v3() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec3 operator()(vec3 a, fixed x) {
|
||||
return a * x;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec3 c = f(vec3(10, 20, 30), 10);
|
||||
|
||||
return c.x == 100 && c.y == 200 && c.z == 300;
|
||||
}
|
||||
bool vec_suite::mult_scalar_v4() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec4 operator()(vec4 a, fixed x) {
|
||||
return a * x;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec4 c = f(vec4(10, 20, 30, 40), 10);
|
||||
|
||||
return c.x == 100 && c.y == 200 && c.z == 300 && c.w == 400;
|
||||
}
|
||||
|
||||
bool vec_suite::dot_v2() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
fixed operator()(vec2 a, vec2 b) {
|
||||
return a * b;
|
||||
}
|
||||
} f;
|
||||
|
||||
fixed c = f(vec2(1, 2), vec2(1, 10));
|
||||
|
||||
return c == 21;
|
||||
}
|
||||
bool vec_suite::dot_v3() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
fixed operator()(vec3 a, vec3 b) {
|
||||
return a * b;
|
||||
}
|
||||
} f;
|
||||
|
||||
fixed c = f(vec3(1, 2, 3), vec3(1, 10, 100));
|
||||
|
||||
return c == 321;
|
||||
}
|
||||
bool vec_suite::dot_v4() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
fixed operator()(vec4 a, vec4 b) {
|
||||
return a * b;
|
||||
}
|
||||
} f;
|
||||
|
||||
fixed c = f(vec4(1, 2, 3, 4), vec4(1, 10, 100, 1000));
|
||||
|
||||
return c == 4321;
|
||||
}
|
||||
|
||||
bool vec_suite::division_scalar_v2() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec2 operator()(vec2 a, fixed x) {
|
||||
return a / x;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec2 c = f(vec2(10, 20), 10);
|
||||
|
||||
return c.x == 1 && c.y == 2;
|
||||
}
|
||||
bool vec_suite::division_scalar_v3() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec3 operator()(vec3 a, fixed x) {
|
||||
return a / x;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec3 c = f(vec3(10, 20, 30), 10);
|
||||
|
||||
return c.x == 1 && c.y == 2 && c.z == 3;
|
||||
}
|
||||
bool vec_suite::division_scalar_v4() {
|
||||
struct {
|
||||
NOINLINE GBA_IWRAM ARM_MODE
|
||||
vec4 operator()(vec4 a, fixed x) {
|
||||
return a / x;
|
||||
}
|
||||
} f;
|
||||
|
||||
vec4 c = f(vec4(10, 20, 30, 40), 10);
|
||||
|
||||
return c.x == 1 && c.y == 2 && c.z == 3 && c.w == 4;
|
||||
}
|
||||
|
||||
bool vec_suite::magnitude_sqr_v2() {
|
||||
log::debug << "UNIMPLEMENTED" << endl;
|
||||
return true;
|
||||
}
|
||||
bool vec_suite::magnitude_sqr_v3() {
|
||||
log::debug << "UNIMPLEMENTED" << endl;
|
||||
return true;
|
||||
}
|
||||
bool vec_suite::magnitude_sqr_v4() {
|
||||
log::debug << "UNIMPLEMENTED" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vec_suite::transpose_v2() {
|
||||
log::debug << "UNIMPLEMENTED" << endl;
|
||||
return true;
|
||||
}
|
||||
bool vec_suite::transpose_v3() {
|
||||
log::debug << "UNIMPLEMENTED" << endl;
|
||||
return true;
|
||||
}
|
||||
bool vec_suite::transpose_v4() {
|
||||
log::debug << "UNIMPLEMENTED" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace mtl
|
||||
|
||||
29
src/vec4.cpp
29
src/vec4.cpp
@ -1,29 +0,0 @@
|
||||
#include "mtl/vec4.hpp"
|
||||
|
||||
TARGET_ARM_MODE
|
||||
|
||||
namespace mtl {
|
||||
|
||||
GBA_IWRAM vec4 vec4::operator+(const vec4& rhs) const {
|
||||
return vec4(x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w);
|
||||
}
|
||||
GBA_IWRAM vec4 vec4::operator-(const vec4& rhs) const {
|
||||
return vec4(x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w);
|
||||
}
|
||||
|
||||
GBA_IWRAM vec4 vec4::operator*(fixed rhs) const {
|
||||
return vec4(x * rhs, y * rhs, z * rhs, w * rhs);
|
||||
}
|
||||
|
||||
GBA_IWRAM fixed vec4::operator*(const vec4& rhs) const {
|
||||
return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w;
|
||||
}
|
||||
|
||||
GBA_IWRAM fixed vec4::magnitude_sqr() const {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
} // namespace mtl
|
||||
|
||||
TARGET_END_MODE
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user