Kajetan Johannes Hammerle 2 ヶ月 前
コミット
94b32bf050

+ 2 - 1
CMakeLists.txt

@@ -24,7 +24,7 @@ set(SRC
     "src/ToString.cpp"
     #"src/Unicode.cpp"
     "src/Utility.cpp"
-    #"src/Vector.cpp"
+    "src/Vector.cpp"
     #"src/View.cpp"
 )
 
@@ -53,6 +53,7 @@ set(SRC_TESTS
     #"test/modules/ViewTests.cpp"
     "test/modules/ListTests.cpp"
     "test/modules/UniquePointerTests.cpp"
+    "test/modules/VectorTests.cpp"
 )
 
 set(SRC_PERFORMANCE

+ 2 - 1
include/core/Terminal.hpp

@@ -1,6 +1,7 @@
 #ifndef CORE_TERMINAL_H
 #define CORE_TERMINAL_H
 
+#include "core/Types.hpp"
 #include "core/Vector.hpp"
 
 #define ESC "\33["
@@ -88,7 +89,7 @@
 
 void enterAlternativeTerminal();
 void leaveAlternativeTerminal();
-IntVector2 getTerminalSize();
+Core::IntVector2 getTerminalSize();
 void clearTerminal();
 void clearTerminalLine();
 

+ 0 - 1
include/core/Test.hpp

@@ -2,7 +2,6 @@
 #define CORE_TEST_H
 
 #include "core/Logger.hpp"
-#include "core/Meta.hpp"
 
 namespace Core {
     void finalizeTests(void);

+ 2 - 0
include/core/ToString.hpp

@@ -13,6 +13,8 @@ size_t toString(long long v, char* s, size_t n);
 size_t toString(unsigned int v, char* s, size_t n);
 size_t toString(unsigned long v, char* s, size_t n);
 size_t toString(unsigned long long v, char* s, size_t n);
+size_t toString(float v, char* s, size_t n);
+size_t toString(double v, char* s, size_t n);
 size_t toString(const char* v, char* s, size_t n);
 size_t toString(char* v, char* s, size_t n);
 size_t toString(bool v, char* s, size_t n);

+ 230 - 79
include/core/Vector.hpp

@@ -1,81 +1,232 @@
-#ifndef CORE_VECTOR_H
-#define CORE_VECTOR_H
-
-#include "core/Types.hpp"
-
-#define VECTOR_OP2(name) name *r, const name *a
-#define VECTOR_OP3(name) VECTOR_OP2(name), const name* b
-
-#define VECTOR_TYPE(type, Type) \
-    typedef union {             \
-        type data[2];           \
-    } Type##2;                  \
-    typedef union {             \
-        type data[3];           \
-    } Type##3;                  \
-    typedef union {             \
-        type data[4];           \
-    } Type##4
-
-VECTOR_TYPE(float, Vector);
-VECTOR_TYPE(int, IntVector);
-
-#define DEFINE_VECTOR(N, name, sname, type)                        \
-    name* addSet##sname(VECTOR_OP2(name));                         \
-    name* add##sname(VECTOR_OP3(name));                            \
-    name* subSet##sname(VECTOR_OP2(name));                         \
-    name* sub##sname(VECTOR_OP3(name));                            \
-    name* mulSet##sname(VECTOR_OP2(name));                         \
-    name* mul##sname(VECTOR_OP3(name));                            \
-    name* divSet##sname(VECTOR_OP2(name));                         \
-    name* div##sname(VECTOR_OP3(name));                            \
-    name* mulSet##sname##F(name* r, type f);                       \
-    name* mul##sname##F(name* r, const name* a, type f);           \
-    name* divSet##sname##F(name* r, type f);                       \
-    name* div##sname##F(name* r, const name* a, type f);           \
-    name* invertSet##sname(name* r);                               \
-    name* invert##sname(name* r, const name* a);                   \
-    size_t toString##sname(const name* a, char* buffer, size_t n);
-
-#define DEFINE_FVECTOR(N, name)                  \
-    float dotV##N(const name* a, const name* b); \
-    float squareLengthV##N(const name* a);       \
-    float lengthV##N(const name* a);             \
-    name* normalizeV##N(name* r);
-
-DEFINE_VECTOR(2, Vector2, V2, float)
-DEFINE_VECTOR(3, Vector3, V3, float)
-DEFINE_VECTOR(4, Vector4, V4, float)
-DEFINE_FVECTOR(2, Vector2)
-DEFINE_FVECTOR(3, Vector3)
-DEFINE_FVECTOR(4, Vector4)
-DEFINE_VECTOR(2, IntVector2, IV2, int)
-DEFINE_VECTOR(3, IntVector3, IV3, int)
-DEFINE_VECTOR(4, IntVector4, IV4, int)
-
-Vector3* angles(Vector3* r, float lengthAngle, float widthAngle);
-Vector3* cross(VECTOR_OP3(Vector3));
-
-#define DEFINE_VECTOR_CONVERSION(a, nameA, b, nameB) \
-    a* convert##nameB(a* r, const b* c);             \
-    b* convert##nameA(b* r, const a* c)
-
-DEFINE_VECTOR_CONVERSION(Vector2, V2, IntVector2, IV2);
-DEFINE_VECTOR_CONVERSION(Vector3, V3, IntVector3, IV3);
-DEFINE_VECTOR_CONVERSION(Vector4, V4, IntVector4, IV4);
-
-#define VECTOR2 ((Vector2){0})
-#define VECTOR3 ((Vector3){0})
-#define VECTOR4 ((Vector4){0})
-#define INT_VECTOR2 ((IntVector2){0})
-#define INT_VECTOR3 ((IntVector3){0})
-#define INT_VECTOR4 ((IntVector4){0})
-
-#define SELECT_VECTOR(_1, _2, _3, _4, name, ...) name
-#define V(...) \
-    ((SELECT_VECTOR(__VA_ARGS__, Vector4, Vector3, Vector2, 0)){{__VA_ARGS__}})
-#define IV(...)                                                           \
-    ((SELECT_VECTOR(__VA_ARGS__, IntVector4, IntVector3, IntVector2, 0)){ \
-        {__VA_ARGS__}})
+#ifndef CORE_VECTOR_HPP
+#define CORE_VECTOR_HPP
+
+#include <cmath>
+
+#include "core/Math.hpp"
+#include "core/ToString.hpp"
+
+namespace Core {
+    template<size_t N, typename T>
+    class alignas(sizeof(T) * (Core::isPowerOf2(N) ? N : 1)) Vector final {
+        T values[N];
+
+    public:
+        Vector() {
+            for(size_t i = 0; i < N; i++) {
+                values[i] = static_cast<T>(0);
+            }
+        }
+
+        template<typename OT, typename... Args>
+        Vector(OT a, Args&&... args) :
+            values(static_cast<T>(a), static_cast<T>(args)...) {
+            static_assert(
+                sizeof...(args) + 1 == N,
+                "vector parameters do not match its size");
+        }
+
+        Vector& operator+=(const Vector& other) {
+            for(size_t i = 0; i < N; i++) {
+                values[i] += other.values[i];
+            }
+            return *this;
+        }
+
+        Vector operator+(const Vector& other) const {
+            Vector v = *this;
+            v += other;
+            return v;
+        }
+
+        Vector& operator-=(const Vector& other) {
+            for(size_t i = 0; i < N; i++) {
+                values[i] -= other.values[i];
+            }
+            return *this;
+        }
+
+        Vector operator-() const {
+            Vector v = *this;
+            for(size_t i = 0; i < N; i++) {
+                v.values[i] = -v.values[i];
+            }
+            return v;
+        }
+
+        Vector operator-(const Vector& other) const {
+            Vector v = *this;
+            v -= other;
+            return v;
+        }
+
+        Vector& operator*=(T factor) {
+            for(size_t i = 0; i < N; i++) {
+                values[i] *= factor;
+            }
+            return *this;
+        }
+
+        Vector& operator*=(const Vector& other) {
+            for(size_t i = 0; i < N; i++) {
+                values[i] *= other.values[i];
+            }
+            return *this;
+        }
+
+        Vector operator*(T factor) const {
+            Vector v = *this;
+            v *= factor;
+            return v;
+        }
+
+        Vector operator*(const Vector& other) const {
+            Vector v = *this;
+            v *= other;
+            return v;
+        }
+
+        Vector& operator/=(T factor) {
+            for(size_t i = 0; i < N; i++) {
+                values[i] /= factor;
+            }
+            return *this;
+        }
+
+        Vector& operator/=(const Vector& other) {
+            for(size_t i = 0; i < N; i++) {
+                values[i] /= other.values[i];
+            }
+            return *this;
+        }
+
+        Vector operator/(T factor) const {
+            Vector v = *this;
+            v /= factor;
+            return v;
+        }
+
+        Vector operator/(const Vector& other) const {
+            Vector v = *this;
+            v /= other;
+            return v;
+        }
+
+        T dot(const Vector& v) const {
+            T length = 0.0f;
+            for(size_t i = 0; i < N; i++) {
+                length += values[i] * v.values[i];
+            }
+            return length;
+        }
+
+        T squareLength() const {
+            return dot(*this);
+        }
+
+        float length() const {
+            return sqrtf(static_cast<float>(squareLength()));
+        }
+
+        Vector& normalize() {
+            if constexpr(Core::IsSame<float, T> || Core::IsSame<double, T>) {
+                *this *= 1.0f / length();
+            } else {
+                *this /= static_cast<T>(length());
+            }
+            return *this;
+        }
+
+        T& operator[](size_t index) {
+            return values[index];
+        }
+
+        const T& operator[](size_t index) const {
+            return values[index];
+        }
+
+        template<typename C>
+        Vector<N, C> to() const {
+            Vector<N, C> cast;
+            for(size_t i = 0; i < N; i++) {
+                cast[i] = static_cast<C>(values[i]);
+            }
+            return cast;
+        }
+
+        Vector<N, int> toInt() const {
+            return to<int>();
+        }
+
+        Vector<N, float> toFloat() const {
+            return to<float>();
+        }
+
+        size_t toString(char* s, size_t n) const {
+            size_t total = 0;
+            addString("[", s, n, total);
+            for(size_t i = 0; i < N - 1; i++) {
+                addString(values[i], s, n, total);
+                addString(", ", s, n, total);
+            }
+            if constexpr(N > 0) {
+                addString(values[N - 1], s, n, total);
+            }
+            addString("]", s, n, total);
+            return total;
+        }
+
+        bool operator==(const Vector& other) const {
+            for(size_t i = 0; i < N; i++) {
+                if(notEqual(values[i], other.values[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+    private:
+        template<typename O>
+        static bool notEqual(const O& a, const O& b) {
+            return a != b;
+        }
+
+        static bool notEqual(float a, float b) {
+            constexpr float e = 0.00001f;
+            float diff = a - b;
+            return diff < -e || diff > e;
+        }
+    };
+
+    using Vector4 = Vector<4, float>;
+    using Vector3 = Vector<3, float>;
+    using Vector2 = Vector<2, float>;
+
+    static_assert(
+        alignof(Vector4) == sizeof(float) * 4, "invalid Vector4 alignment");
+    static_assert(
+        alignof(Vector3) == sizeof(float), "invalid Vector3 alignment");
+    static_assert(
+        alignof(Vector2) == sizeof(float) * 2, "invalid Vector2 alignment");
+
+    using IntVector4 = Vector<4, int>;
+    using IntVector3 = Vector<3, int>;
+    using IntVector2 = Vector<2, int>;
+
+    static_assert(
+        alignof(IntVector4) == sizeof(int) * 4, "invalid IntVector4 alignment");
+    static_assert(
+        alignof(IntVector3) == sizeof(int), "invalid IntVector3 alignment");
+    static_assert(
+        alignof(IntVector2) == sizeof(int) * 2, "invalid IntVector2 alignment");
+
+    void setAngles(Vector3& v, float lengthAngle, float widthAngle);
+    Vector3 cross(const Vector3& a, const Vector3& b);
+}
+
+template<size_t N, typename T>
+Core::Vector<N, T> operator*(T factor, const Core::Vector<N, T>& v) {
+    return v * factor;
+}
 
 #endif

+ 0 - 21
old/Vector.cpp

@@ -1,21 +0,0 @@
-#include "core/math/Vector.hpp"
-
-template<>
-Core::Vector3& Core::Vector3::setAngles(float lengthAngle, float widthAngle) {
-    float sWidth = 0.0f;
-    float cWidth = 0.0f;
-    sincosf(Math::degreeToRadian(widthAngle), &sWidth, &cWidth);
-
-    float sLength = 0.0f;
-    float cLength = 0.0f;
-    sincosf(Math::degreeToRadian(lengthAngle), &sLength, &cLength);
-
-    return *this = Vector3(cWidth * cLength, sWidth, -sLength * cWidth);
-}
-
-template<>
-Core::Vector3 Core::Vector3::cross(const Vector3& other) const {
-    return Vector3(values[1] * other.values[2] - values[2] * other.values[1],
-                   values[2] * other.values[0] - values[0] * other.values[2],
-                   values[0] * other.values[1] - values[1] * other.values[0]);
-}

+ 0 - 214
old/Vector.hpp

@@ -1,214 +0,0 @@
-#ifndef CORE_VECTOR_HPP
-#define CORE_VECTOR_HPP
-
-#include <math.h>
-
-#include "core/math/Math.hpp"
-#include "core/utils/ArrayString.hpp"
-
-namespace Core {
-    template<size_t N, typename T>
-    class alignas(sizeof(T) * (Math::isPowerOf2(N) ? N : 1)) Vector final {
-        T values[N];
-
-    public:
-        Vector() {
-            for(size_t i = 0; i < N; i++) {
-                values[i] = static_cast<T>(0);
-            }
-        }
-
-        template<typename OT, typename... Args>
-        Vector(OT a, Args&&... args)
-            : values(static_cast<T>(a), static_cast<T>(args)...) {
-            static_assert(sizeof...(args) + 1 == N,
-                          "vector parameters do not match its size");
-        }
-
-    public:
-        Vector& setAngles(float, float) = delete;
-        Vector cross(const Vector&) const = delete;
-
-        Vector& operator+=(const Vector& other) {
-            for(size_t i = 0; i < N; i++) {
-                values[i] += other.values[i];
-            }
-            return *this;
-        }
-
-        Vector operator+(const Vector& other) const {
-            Vector v = *this;
-            v += other;
-            return v;
-        }
-
-        Vector& operator-=(const Vector& other) {
-            for(size_t i = 0; i < N; i++) {
-                values[i] -= other.values[i];
-            }
-            return *this;
-        }
-
-        Vector operator-() const {
-            Vector v = *this;
-            for(size_t i = 0; i < N; i++) {
-                v.values[i] = -v.values[i];
-            }
-            return v;
-        }
-
-        Vector operator-(const Vector& other) const {
-            Vector v = *this;
-            v -= other;
-            return v;
-        }
-
-        Vector& operator*=(T factor) {
-            for(size_t i = 0; i < N; i++) {
-                values[i] *= factor;
-            }
-            return *this;
-        }
-
-        Vector& operator*=(const Vector& other) {
-            for(size_t i = 0; i < N; i++) {
-                values[i] *= other.values[i];
-            }
-            return *this;
-        }
-
-        Vector operator*(T factor) const {
-            Vector v = *this;
-            v *= factor;
-            return v;
-        }
-
-        Vector operator*(const Vector& other) const {
-            Vector v = *this;
-            v *= other;
-            return v;
-        }
-
-        Vector& operator/=(T factor) {
-            for(size_t i = 0; i < N; i++) {
-                values[i] /= factor;
-            }
-            return *this;
-        }
-
-        Vector& operator/=(const Vector& other) {
-            for(size_t i = 0; i < N; i++) {
-                values[i] /= other.values[i];
-            }
-            return *this;
-        }
-
-        Vector operator/(T factor) const {
-            Vector v = *this;
-            v /= factor;
-            return v;
-        }
-
-        Vector operator/(const Vector& other) const {
-            Vector v = *this;
-            v /= other;
-            return v;
-        }
-
-        T dot(const Vector& v) const {
-            T length = 0.0f;
-            for(size_t i = 0; i < N; i++) {
-                length += values[i] * v.values[i];
-            }
-            return length;
-        }
-
-        T squareLength() const {
-            return dot(*this);
-        }
-
-        float length() const {
-            return sqrtf(static_cast<float>(squareLength()));
-        }
-
-        Vector& normalize() {
-            if constexpr(Core::IsSame<float, T> || Core::IsSame<double, T>) {
-                *this *= 1.0f / length();
-            } else {
-                *this /= static_cast<T>(length());
-            }
-            return *this;
-        }
-
-        T& operator[](size_t index) {
-            return values[index];
-        }
-
-        const T& operator[](size_t index) const {
-            return values[index];
-        }
-
-        template<typename C>
-        Vector<N, C> to() const {
-            Vector<N, C> cast;
-            for(size_t i = 0; i < N; i++) {
-                cast[i] = static_cast<C>(values[i]);
-            }
-            return cast;
-        }
-
-        Vector<N, int> toInt() const {
-            return to<int>();
-        }
-
-        Vector<N, float> toFloat() const {
-            return to<float>();
-        }
-
-        void toString(BufferString& s) const {
-            s.append("[");
-            for(size_t i = 0; i < N - 1; i++) {
-                s.append(values[i]).append(", ");
-            }
-            if(N > 0) {
-                s.append(values[N - 1]);
-            }
-            s.append("]");
-        }
-    };
-
-    using Vector4 = Vector<4, float>;
-    using Vector3 = Vector<3, float>;
-    using Vector2 = Vector<2, float>;
-
-    static_assert(alignof(Vector4) == sizeof(float) * 4,
-                  "invalid Vector4 alignment");
-    static_assert(alignof(Vector3) == sizeof(float),
-                  "invalid Vector3 alignment");
-    static_assert(alignof(Vector2) == sizeof(float) * 2,
-                  "invalid Vector2 alignment");
-
-    using IntVector4 = Vector<4, int>;
-    using IntVector3 = Vector<3, int>;
-    using IntVector2 = Vector<2, int>;
-
-    static_assert(alignof(IntVector4) == sizeof(int) * 4,
-                  "invalid IntVector4 alignment");
-    static_assert(alignof(IntVector3) == sizeof(int),
-                  "invalid IntVector3 alignment");
-    static_assert(alignof(IntVector2) == sizeof(int) * 2,
-                  "invalid IntVector2 alignment");
-
-    template<>
-    Vector3& Vector3::setAngles(float lengthAngle, float widthAngle);
-
-    template<>
-    Vector3 Vector3::cross(const Vector3& other) const;
-}
-
-template<size_t N, typename T>
-Core::Vector<N, T> operator*(T factor, const Core::Vector<N, T>& v) {
-    return v * factor;
-}
-
-#endif

+ 0 - 228
old/VectorTests.cpp

@@ -1,228 +0,0 @@
-#include "../Tests.hpp"
-#include "core/math/Vector.hpp"
-
-const float eps = 0.0001f;
-
-using V3 = Core::Vector3;
-using I3 = Core::IntVector3;
-
-template class Core::Vector<4, float>;
-template class Core::Vector<4, int>;
-template class Core::Vector<3, float>;
-template class Core::Vector<3, int>;
-template class Core::Vector<2, float>;
-template class Core::Vector<2, int>;
-
-static void testInitAndRead() {
-    V3 v1;
-    Core::Vector2 v2(1.0f, 2.0f);
-    V3 v3(3.0f, 4.0f, 5.0f);
-    Core::Vector4 v4(6.0f, 7.0f, 8.0f, 9.0f);
-    CORE_TEST_FLOAT(0.0f, v1[0], 0.0f);
-    CORE_TEST_FLOAT(0.0f, v1[0], 0.0f);
-    CORE_TEST_FLOAT(0.0f, v1[0], 0.0f);
-    CORE_TEST_FLOAT(1.0f, v2[0], 0.0f);
-    CORE_TEST_FLOAT(2.0f, v2[1], 0.0f);
-    CORE_TEST_FLOAT(3.0f, v3[0], 0.0f);
-    CORE_TEST_FLOAT(4.0f, v3[1], 0.0f);
-    CORE_TEST_FLOAT(5.0f, v3[2], 0.0f);
-    CORE_TEST_FLOAT(6.0f, v4[0], 0.0f);
-    CORE_TEST_FLOAT(7.0f, v4[1], 0.0f);
-    CORE_TEST_FLOAT(8.0f, v4[2], 0.0f);
-    CORE_TEST_FLOAT(9.0f, v4[3], 0.0f);
-}
-
-static void testSetAngles() {
-    float root = sqrtf(2.0f) * 0.5f;
-    CORE_TEST_VECTOR(V3(1.0f, 0.0f, 0.0f), V3().setAngles(0.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(root, 0.0f, -root), V3().setAngles(45.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(0.0f, 0.0f, -1.0f), V3().setAngles(90.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(-root, 0.0f, -root), V3().setAngles(135.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(-1.0f, 0.0f, 0.0f), V3().setAngles(180.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(-root, 0.0f, root), V3().setAngles(225.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(0.0f, 0.0f, 1.0f), V3().setAngles(270.0f, 0.0f));
-    CORE_TEST_VECTOR(V3(root, 0.0f, root), V3().setAngles(315.0f, 0.0f));
-
-    CORE_TEST_VECTOR(V3(0.0f, 1.0f, 0.0f), V3().setAngles(0.0f, 90.0f));
-    CORE_TEST_VECTOR(V3(0.0f, 1.0f, 0.0f), V3().setAngles(90.0f, 90.0f));
-    CORE_TEST_VECTOR(V3(0.0f, 1.0f, 0.0f), V3().setAngles(180.0f, 90.0f));
-    CORE_TEST_VECTOR(V3(0.0f, 1.0f, 0.0f), V3().setAngles(270.0f, 90.0f));
-
-    CORE_TEST_VECTOR(V3(0.0f, -1.0f, 0.0f), V3().setAngles(0.0f, -90.0f));
-    CORE_TEST_VECTOR(V3(0.0f, -1.0f, 0.0f), V3().setAngles(90.0f, -90.0f));
-    CORE_TEST_VECTOR(V3(0.0f, -1.0f, 0.0f), V3().setAngles(180.0f, -90.0f));
-    CORE_TEST_VECTOR(V3(0.0f, -1.0f, 0.0f), V3().setAngles(270.0f, -90.0f));
-
-    CORE_TEST_VECTOR(V3(root, root, 0.0f), V3().setAngles(0.0f, 45.0f));
-    CORE_TEST_VECTOR(V3(0.0f, root, -root), V3().setAngles(90.0f, 45.0f));
-    CORE_TEST_VECTOR(V3(-root, root, 0.0f), V3().setAngles(180.0f, 45.0f));
-    CORE_TEST_VECTOR(V3(0.0f, root, root), V3().setAngles(270.0f, 45.0f));
-
-    CORE_TEST_VECTOR(V3(root, -root, 0.0f), V3().setAngles(0.0f, -45.0f));
-    CORE_TEST_VECTOR(V3(0.0f, -root, -root), V3().setAngles(90.0f, -45.0f));
-    CORE_TEST_VECTOR(V3(-root, -root, 0.0f), V3().setAngles(180.0f, -45.0f));
-    CORE_TEST_VECTOR(V3(0.0f, -root, root), V3().setAngles(270.0f, -45.0f));
-
-    CORE_TEST_VECTOR(V3(0.5f, root, -0.5f), V3().setAngles(45.0f, 45.0f));
-}
-
-static void testCross() {
-    CORE_TEST_VECTOR(V3(0.0f, 0.0f, 1.0f),
-                     V3(1.0f, 0.0f, 0.0f).cross(V3(0.0f, 1.0f, 0.0f)));
-    CORE_TEST_VECTOR(V3(0.0f, -1.0f, 0.0f),
-                     V3(1.0f, 0.0f, 0.0f).cross(V3(0.0f, 0.0f, 1.0f)));
-    CORE_TEST_VECTOR(V3(0.0f, 0.0f, -1.0f),
-                     V3(0.0f, 1.0f, 0.0f).cross(V3(1.0f, 0.0f, 0.0f)));
-    CORE_TEST_VECTOR(V3(1.0f, 0.0f, 0.0f),
-                     V3(0.0f, 1.0f, 0.0f).cross(V3(0.0f, 0.0f, 1.0f)));
-    CORE_TEST_VECTOR(V3(0.0f, 1.0f, 0.0f),
-                     V3(0.0f, 0.0f, 1.0f).cross(V3(1.0f, 0.0f, 0.0f)));
-    CORE_TEST_VECTOR(V3(-1.0f, 0.0f, 0.0f),
-                     V3(0.0f, 0.0f, 1.0f).cross(V3(0.0f, 1.0f, 0.0f)));
-}
-
-static void testSetAdd() {
-    V3 v;
-    v += V3(1.0f, 2.0f, 3.0f);
-    CORE_TEST_VECTOR(V3(1.0f, 2.0f, 3.0f), v);
-    v += V3(2.0f, 3.0f, 4.0f);
-    CORE_TEST_VECTOR(V3(3.0f, 5.0f, 7.0f), v);
-}
-
-static void testAdd() {
-    CORE_TEST_VECTOR(V3(1.0f, 2.0f, 3.0f), V3() + V3(1.0f, 2.0f, 3.0f));
-    CORE_TEST_VECTOR(V3(3.0f, 5.0f, 7.0f),
-                     V3(1.0f, 2.0f, 3.0f) + V3(2.0f, 3.0f, 4.0f));
-}
-
-static void testSetSub() {
-    V3 v;
-    v -= V3(1.0f, 2.0f, 3.0f);
-    CORE_TEST_VECTOR(V3(-1.0f, -2.0f, -3.0f), v);
-    v -= V3(2.0f, 3.0f, 4.0f);
-    CORE_TEST_VECTOR(V3(-3.0f, -5.0f, -7.0f), v);
-}
-
-static void testSub() {
-    CORE_TEST_VECTOR(V3(1.0f, 2.0f, 3.0f), V3() - V3(-1.0f, -2.0f, -3.0f));
-    CORE_TEST_VECTOR(V3(-1.0f, -1.0f, -1.0f),
-                     V3(1.0f, 2.0f, 3.0f) - V3(2.0f, 3.0f, 4.0f));
-}
-
-static void testInvert() {
-    CORE_TEST_VECTOR(V3(-1.0f, 2.0f, 3.0f), -V3(1.0f, -2.0f, -3.0f));
-}
-
-static void testSetMul() {
-    V3 v(1.0f, 2.0f, 3.0f);
-    v *= 3.0f;
-    CORE_TEST_VECTOR(V3(3.0f, 6.0f, 9.0f), v);
-    v *= -2.0f;
-    CORE_TEST_VECTOR(V3(-6.0f, -12.0f, -18.0f), v);
-}
-
-static void testMul() {
-    CORE_TEST_VECTOR(V3(-3.0f, -6.0f, -9.0f), 3.0f * V3(-1.0f, -2.0f, -3.0f));
-    CORE_TEST_VECTOR(V3(3.0f, 6.0f, 9.0f), V3(1.0f, 2.0f, 3.0f) * 3.0);
-}
-
-static void testSetMulVector() {
-    V3 v(1.0f, 2.0f, 3.0f);
-    v *= V3(2.0f, 1.0f, 3.0f);
-    CORE_TEST_VECTOR(V3(2.0f, 2.0f, 9.0f), v);
-    v *= V3(-3.0f, 4.0f, -2.0f);
-    CORE_TEST_VECTOR(V3(-6.0f, 8.0f, -18.0f), v);
-}
-
-static void testMulVector() {
-    CORE_TEST_VECTOR(V3(-2.0f, -2.0f, -9.0f),
-                     V3(2.0f, 1.0f, 3.0f) * V3(-1.0f, -2.0f, -3.0f));
-    CORE_TEST_VECTOR(V3(2.0f, 2.0f, 9.0f),
-                     V3(1.0f, 2.0f, 3.0f) * V3(2.0f, 1.0f, 3.0f));
-}
-
-static void testSetDiv() {
-    V3 v(12.0f, 24.0f, 9.0f);
-    v /= 3.0f;
-    CORE_TEST_VECTOR(V3(4.0f, 8.0f, 3.0f), v);
-    v /= -2.0f;
-    CORE_TEST_VECTOR(V3(-2.0f, -4.0f, -1.5f), v);
-}
-
-static void testDiv() {
-    CORE_TEST_VECTOR(V3(-1.0f, -2.0f, -3.0f), V3(-3.0f, -6.0f, -9.0f) / 3.0f);
-}
-
-static void testDot() {
-    CORE_TEST_FLOAT(9.0f, V3(-4.0f, 2.0f, -3.0f).dot(V3(-1.0f, -2.0f, -3.0f)),
-                    eps);
-    CORE_TEST_FLOAT(-22.0f, V3(2.0f, 2.0f, -4.0f).dot(V3(1.0f, -2.0f, 5.0f)),
-                    eps);
-}
-
-static void testSquareLength() {
-    CORE_TEST_FLOAT(29.0f, V3(-4.0f, 2.0f, -3.0f).squareLength(), eps);
-    CORE_TEST_FLOAT(24.0f, V3(2.0f, 2.0f, -4.0f).squareLength(), eps);
-}
-
-static void testLength() {
-    CORE_TEST_FLOAT(3.0f, V3(-2.0f, 2.0f, -1.0f).length(), eps);
-    CORE_TEST_FLOAT(7.0f, V3(6.0f, 2.0f, -3.0f).length(), eps);
-}
-
-static void testNormalize() {
-    V3 v1(-2.0f, 2.0f, -1.0f);
-    V3 v2 = v1 * (1.0f / 3.0f);
-    v1.normalize();
-    CORE_TEST_VECTOR(v2, v1);
-
-    V3 v3(6.0f, 2.0f, -3.0f);
-    V3 v4 = v3 * (1.0f / 7.0f);
-    v3.normalize();
-    CORE_TEST_VECTOR(v4, v3);
-}
-
-static void testCast() {
-    CORE_TEST_VECTOR(V3(-2.5f, 2.6f, 9.0f).toInt(), I3(-2, 2, 9));
-    CORE_TEST_VECTOR(I3(-2.5f, 2.6f, 9.0f).toFloat(), V3(-2.0f, 2.0f, 9.0f));
-}
-
-static void testToString() {
-    Core::ArrayString<200> s;
-    s.append(Core::Vector<1, float>());
-    s.append(Core::Vector2(2.0f, 3.0f));
-    s.append(V3(4.0f, 5.0f, 6.0f));
-    Core::ArrayString<200> s2;
-    s2.append("[0.00][2.00, 3.00][4.00, 5.00, 6.00]");
-    CORE_TEST_EQUAL(s2, s);
-}
-
-static void testNormalizeIntVector() {
-    I3 i(1, 2, 3);
-    i.normalize();
-    CORE_TEST_VECTOR(I3(0, 0, 1), i);
-}
-
-void Core::testVector() {
-    testInitAndRead();
-    testSetAngles();
-    testCross();
-    testSetAdd();
-    testAdd();
-    testSetSub();
-    testSub();
-    testInvert();
-    testSetMul();
-    testMul();
-    testSetMulVector();
-    testMulVector();
-    testSetDiv();
-    testDiv();
-    testDot();
-    testSquareLength();
-    testLength();
-    testNormalize();
-    testCast();
-    testToString();
-    testNormalizeIntVector();
-}

+ 6 - 0
src/ToString.cpp

@@ -15,8 +15,14 @@ TO_STRING(long long, "%lld")
 TO_STRING(unsigned int, "%u")
 TO_STRING(unsigned long, "%lu")
 TO_STRING(unsigned long long, "%llu")
+TO_STRING(double, "%.2f")
 TO_STRING(const char*, "%s")
 
+size_t toString(float v, char* s, size_t n) {
+    int e = snprintf(s, n, "%.2f", static_cast<double>(v));
+    return e < 0 ? 0 : static_cast<size_t>(e);
+}
+
 size_t toString(char* v, char* s, size_t n) {
     return toString(static_cast<const char*>(v), s, n);
 }

+ 14 - 175
src/Vector.cpp

@@ -1,182 +1,21 @@
 #include "core/Vector.hpp"
 
-#include <math.h>
+void Core::setAngles(Vector3& v, float lengthAngle, float widthAngle) {
+    float sWidth = 0.0f;
+    float cWidth = 0.0f;
+    sincosf(Core::degreeToRadian(widthAngle), &sWidth, &cWidth);
 
-#include "core/ToString.hpp"
+    float sLength = 0.0f;
+    float cLength = 0.0f;
+    sincosf(Core::degreeToRadian(lengthAngle), &sLength, &cLength);
 
-typedef Vector2 V2;
-typedef Vector3 V3;
-typedef Vector4 V4;
-typedef IntVector2 IV2;
-typedef IntVector3 IV3;
-typedef IntVector4 IV4;
-
-V3* angles(V3* r, float lengthAngle, float widthAngle) {
-    float sWidth = sinf(widthAngle);
-    float cWidth = cosf(widthAngle);
-    float sLength = sinf(lengthAngle);
-    float cLength = cosf(lengthAngle);
-
-    r->x = cWidth * cLength;
-    r->y = sWidth;
-    r->z = -sLength * cWidth;
-    return r;
-}
-
-V3* cross(V3* r, const V3* a, const V3* b) {
-    r->x = a->y * b->z - a->z * b->y;
-    r->y = a->z * b->x - a->x * b->z;
-    r->z = a->x * b->y - a->y * b->x;
-    return r;
-}
-
-#define ADD_OP(i) r->data[i] = a->data[i] + b->data[i]
-#define SUB_OP(i) r->data[i] = a->data[i] - b->data[i]
-#define MUL_OP(i) r->data[i] = a->data[i] * b->data[i]
-#define MUL_F_OP(i) r->data[i] = a->data[i] * f
-#define DIV_OP(i) r->data[i] = a->data[i] / b->data[i]
-#define DIV_F_OP(i) r->data[i] = a->data[i] / f
-#define INVERT_OP(i) r->data[i] = -a->data[i];
-#define DOT_OP(i) length += a->data[i] * b->data[i];
-#define FLOAT_CAST_OP(i) r->data[i] = (float)a->data[i];
-#define INT_CAST_OP(i) r->data[i] = (int)a->data[i];
-#define DO2(OP) \
-    OP(0);      \
-    OP(1)
-#define DO3(OP) \
-    DO2(OP);    \
-    OP(2)
-#define DO4(OP) \
-    DO3(OP);    \
-    OP(3)
-
-#define VECTOR_IMPL(T, N, FT)                 \
-    T* addSet##T(T* r, const T* a) {          \
-        return add##T(r, r, a);               \
-    }                                         \
-                                              \
-    T* add##T(T* r, const T* a, const T* b) { \
-        DO##N(ADD_OP);                        \
-        return r;                             \
-    }                                         \
-                                              \
-    T* subSet##T(T* r, const T* a) {          \
-        return sub##T(r, r, a);               \
-    }                                         \
-                                              \
-    T* sub##T(T* r, const T* a, const T* b) { \
-        DO##N(SUB_OP);                        \
-        return r;                             \
-    }                                         \
-                                              \
-    T* mulSet##T(T* r, const T* a) {          \
-        return mul##T(r, r, a);               \
-    }                                         \
-                                              \
-    T* mul##T(T* r, const T* a, const T* b) { \
-        DO##N(MUL_OP);                        \
-        return r;                             \
-    }                                         \
-                                              \
-    T* divSet##T(T* r, const T* a) {          \
-        return div##T(r, r, a);               \
-    }                                         \
-                                              \
-    T* div##T(T* r, const T* a, const T* b) { \
-        DO##N(DIV_OP);                        \
-        return r;                             \
-    }                                         \
-                                              \
-    T* mulSet##T##F(T* r, FT f) {             \
-        return mul##T##F(r, r, f);            \
-    }                                         \
-                                              \
-    T* mul##T##F(T* r, const T* a, FT f) {    \
-        DO##N(MUL_F_OP);                      \
-        return r;                             \
-    }                                         \
-                                              \
-    T* divSet##T##F(T* r, FT f) {             \
-        return div##T##F(r, r, f);            \
-    }                                         \
-                                              \
-    T* div##T##F(T* r, const T* a, FT f) {    \
-        DO##N(DIV_F_OP);                      \
-        return r;                             \
-    }                                         \
-                                              \
-    T* invertSet##T(T* r) {                   \
-        return invert##T(r, r);               \
-    }                                         \
-                                              \
-    T* invert##T(T* r, const T* a) {          \
-        DO##N(INVERT_OP);                     \
-        return r;                             \
-    }
-
-#define VECTOR_IMPL_FLOAT(T, N, CN)                  \
-    float dot##T(const T* a, const T* b) {           \
-        float length = 0;                            \
-        DO##N(DOT_OP);                               \
-        return length;                               \
-    }                                                \
-                                                     \
-    float squareLength##T(const T* a) {              \
-        return dot##T(a, a);                         \
-    }                                                \
-                                                     \
-    float length##T(const T* a) {                    \
-        return sqrtf(squareLength##T(a));            \
-    }                                                \
-                                                     \
-    T* normalize##T(T* r) {                          \
-        return mulSet##T##F(r, 1.0f / length##T(r)); \
-    }                                                \
-                                                     \
-    T* convertI##T(T* r, const CN* a) {              \
-        DO##N(FLOAT_CAST_OP);                        \
-        return r;                                    \
-    }                                                \
-                                                     \
-    CN* convert##T(CN* r, const T* a) {              \
-        DO##N(INT_CAST_OP);                          \
-        return r;                                    \
-    }
-
-VECTOR_IMPL(V2, 2, float)
-VECTOR_IMPL(V3, 3, float)
-VECTOR_IMPL(V4, 4, float)
-VECTOR_IMPL(IV2, 2, int)
-VECTOR_IMPL(IV3, 3, int)
-VECTOR_IMPL(IV4, 4, int)
-VECTOR_IMPL_FLOAT(V2, 2, IV2)
-VECTOR_IMPL_FLOAT(V3, 3, IV3)
-VECTOR_IMPL_FLOAT(V4, 4, IV4)
-
-size_t toStringV2(const V2* a, char* buffer, size_t n) {
-    return toString(buffer, n, "[%.3f, %.3f]", (double)a->x, (double)a->y);
-}
-
-size_t toStringV3(const V3* a, char* buffer, size_t n) {
-    return toString(
-        buffer, n, "[%.3f, %.3f, %.3f]", (double)a->x, (double)a->y,
-        (double)a->z);
-}
-
-size_t toStringV4(const V4* a, char* buffer, size_t n) {
-    return toString(
-        buffer, n, "[%.3f, %.3f, %.3f, %.3f]", (double)a->x, (double)a->y,
-        (double)a->z, (double)a->w);
-}
-
-size_t toStringIV2(const IV2* a, char* buffer, size_t n) {
-    return toString(buffer, n, "[%d, %d]", a->x, a->y);
-}
-
-size_t toStringIV3(const IV3* a, char* buffer, size_t n) {
-    return toString(buffer, n, "[%d, %d, %d]", a->x, a->y, a->z);
+    v[0] = cWidth * cLength;
+    v[1] = sWidth;
+    v[2] = -sLength * cWidth;
 }
 
-size_t toStringIV4(const IV4* a, char* buffer, size_t n) {
-    return toString(buffer, n, "[%d, %d, %d, %d]", a->x, a->y, a->z, a->w);
+Core::Vector3 Core::cross(const Vector3& a, const Vector3& b) {
+    return Vector3(
+        a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
+        a[0] * b[1] - a[1] * b[0]);
 }

+ 1 - 0
test/Main.cpp

@@ -64,6 +64,7 @@ int main(int argAmount, const char** args) {
 
     testList(light);
     testUniquePointer();
+    testVector();
     // testBitArray();
     // testBox();
     // testBuffer(light);

+ 148 - 245
test/modules/VectorTests.cpp

@@ -1,320 +1,223 @@
-#include <math.h>
-
-#include "../Tests.h"
-#include "core/Generic.h"
-#include "core/Utility.h"
-
-static const float eps = 0.0001f;
-
-#define V2 Vector2
-#define CV2(a, b, c, d) (&(V2){{a, b}})
-#define FV2(a, b) CV2(a, b, 0, 0)
-#define CV20 CV2(0, 0, 0, 0)
-
-#define V3 Vector3
-#define CV3(a, b, c, d) (&(V3){{a, b, c}})
-#define FV3(a, b, c) CV3(a, b, c, 0)
-#define CV30 CV3(0, 0, 0, 0)
-
-#define V4 Vector4
-#define CV4(a, b, c, d) (&(V4){{a, b, c, d}})
-#define CV40 CV4(0, 0, 0, 0)
-
-#define IV2 IntVector2
-#define CIV2(a, b, c, d) (&(IV2){{a, b}})
-#define FIV2(a, b) CIV2(a, b, 0, 0)
-#define CIV20 CIV2(0, 0, 0, 0)
-
-#define IV3 IntVector3
-#define CIV3(a, b, c, d) (&(IV3){{a, b, c}})
-#define FIV3(a, b, c) CIV3(a, b, c, 0)
-#define CIV30 CIV3(0, 0, 0, 0)
-
-#define IV4 IntVector4
-#define CIV4(a, b, c, d) (&(IV4){{a, b, c, d}})
-#define CIV40 CIV4(0, 0, 0, 0)
-
-#define TESTS X(V2) X(V3) X(V4) X(IV2) X(IV3) X(IV4)
-
-#define R45 degreeToRadian(45.0f)
-#define R90 degreeToRadian(90.0f)
-#define R135 degreeToRadian(135.0f)
-#define R180 degreeToRadian(180.0f)
-#define R225 degreeToRadian(225.0f)
-#define R270 degreeToRadian(270.0f)
-#define R315 degreeToRadian(315.0f)
+#include "../Tests.hpp"
+#include "core/Test.hpp"
+#include "core/Vector.hpp"
+
+const float eps = 0.0001f;
+
+using V3 = Core::Vector3;
+using I3 = Core::IntVector3;
+
+template class Core::Vector<4, float>;
+template class Core::Vector<4, int>;
+template class Core::Vector<3, float>;
+template class Core::Vector<3, int>;
+template class Core::Vector<2, float>;
+template class Core::Vector<2, int>;
+
+static void testInitAndRead() {
+    V3 v1;
+    Core::Vector2 v2(1.0f, 2.0f);
+    V3 v3(3.0f, 4.0f, 5.0f);
+    Core::Vector4 v4(6.0f, 7.0f, 8.0f, 9.0f);
+    TEST_FLOAT(0.0f, v1[0], 0.0f);
+    TEST_FLOAT(0.0f, v1[0], 0.0f);
+    TEST_FLOAT(0.0f, v1[0], 0.0f);
+    TEST_FLOAT(1.0f, v2[0], 0.0f);
+    TEST_FLOAT(2.0f, v2[1], 0.0f);
+    TEST_FLOAT(3.0f, v3[0], 0.0f);
+    TEST_FLOAT(4.0f, v3[1], 0.0f);
+    TEST_FLOAT(5.0f, v3[2], 0.0f);
+    TEST_FLOAT(6.0f, v4[0], 0.0f);
+    TEST_FLOAT(7.0f, v4[1], 0.0f);
+    TEST_FLOAT(8.0f, v4[2], 0.0f);
+    TEST_FLOAT(9.0f, v4[3], 0.0f);
+}
+
+static V3 angles(float lengthAngle, float widthAngle) {
+    V3 v;
+    Core::setAngles(v, lengthAngle, widthAngle);
+    return v;
+}
 
 static void testSetAngles() {
-    float root = sqrtf(2) * 0.5f;
-    TEST_V3(FV3(1, 0, 0), angles(CV30, 0, 0));
-    TEST_V3(FV3(root, 0, -root), angles(CV30, R45, 0));
-    TEST_V3(FV3(0, 0, -1), angles(CV30, R90, 0));
-    TEST_V3(FV3(-root, 0, -root), angles(CV30, R135, 0));
-    TEST_V3(FV3(-1, 0, 0), angles(CV30, R180, 0));
-    TEST_V3(FV3(-root, 0, root), angles(CV30, R225, 0));
-    TEST_V3(FV3(0, 0, 1), angles(CV30, R270, 0));
-    TEST_V3(FV3(root, 0, root), angles(CV30, R315, 0));
-
-    TEST_V3(FV3(0, 1, 0), angles(CV30, 0, R90));
-    TEST_V3(FV3(0, 1, 0), angles(CV30, R90, R90));
-    TEST_V3(FV3(0, 1, 0), angles(CV30, R180, R90));
-    TEST_V3(FV3(0, 1, 0), angles(CV30, R270, R90));
-
-    TEST_V3(FV3(0, -1, 0), angles(CV30, 0, -R90));
-    TEST_V3(FV3(0, -1, 0), angles(CV30, R90, -R90));
-    TEST_V3(FV3(0, -1, 0), angles(CV30, R180, -R90));
-    TEST_V3(FV3(0, -1, 0), angles(CV30, R270, -R90));
-
-    TEST_V3(FV3(root, root, 0), angles(CV30, 0, R45));
-    TEST_V3(FV3(0, root, -root), angles(CV30, R90, R45));
-    TEST_V3(FV3(-root, root, 0), angles(CV30, R180, R45));
-    TEST_V3(FV3(0, root, root), angles(CV30, R270, R45));
-
-    TEST_V3(FV3(root, -root, 0), angles(CV30, 0, -R45));
-    TEST_V3(FV3(0, -root, -root), angles(CV30, R90, -R45));
-    TEST_V3(FV3(-root, -root, 0), angles(CV30, R180, -R45));
-    TEST_V3(FV3(0, -root, root), angles(CV30, R270, -R45));
-
-    TEST_V3(FV3(0.5f, root, -0.5f), angles(CV30, R45, R45));
+    float root = sqrtf(2.0f) * 0.5f;
+    TEST(V3(1.0f, 0.0f, 0.0f), angles(0.0f, 0.0f));
+    TEST(V3(root, 0.0f, -root), angles(45.0f, 0.0f));
+    TEST(V3(0.0f, 0.0f, -1.0f), angles(90.0f, 0.0f));
+    TEST(V3(-root, 0.0f, -root), angles(135.0f, 0.0f));
+    TEST(V3(-1.0f, 0.0f, 0.0f), angles(180.0f, 0.0f));
+    TEST(V3(-root, 0.0f, root), angles(225.0f, 0.0f));
+    TEST(V3(0.0f, 0.0f, 1.0f), angles(270.0f, 0.0f));
+    TEST(V3(root, 0.0f, root), angles(315.0f, 0.0f));
+
+    TEST(V3(0.0f, 1.0f, 0.0f), angles(0.0f, 90.0f));
+    TEST(V3(0.0f, 1.0f, 0.0f), angles(90.0f, 90.0f));
+    TEST(V3(0.0f, 1.0f, 0.0f), angles(180.0f, 90.0f));
+    TEST(V3(0.0f, 1.0f, 0.0f), angles(270.0f, 90.0f));
+
+    TEST(V3(0.0f, -1.0f, 0.0f), angles(0.0f, -90.0f));
+    TEST(V3(0.0f, -1.0f, 0.0f), angles(90.0f, -90.0f));
+    TEST(V3(0.0f, -1.0f, 0.0f), angles(180.0f, -90.0f));
+    TEST(V3(0.0f, -1.0f, 0.0f), angles(270.0f, -90.0f));
+
+    TEST(V3(root, root, 0.0f), angles(0.0f, 45.0f));
+    TEST(V3(0.0f, root, -root), angles(90.0f, 45.0f));
+    TEST(V3(-root, root, 0.0f), angles(180.0f, 45.0f));
+    TEST(V3(0.0f, root, root), angles(270.0f, 45.0f));
+
+    TEST(V3(root, -root, 0.0f), angles(0.0f, -45.0f));
+    TEST(V3(0.0f, -root, -root), angles(90.0f, -45.0f));
+    TEST(V3(-root, -root, 0.0f), angles(180.0f, -45.0f));
+    TEST(V3(0.0f, -root, root), angles(270.0f, -45.0f));
+
+    TEST(V3(0.5f, root, -0.5f), angles(45.0f, 45.0f));
 }
 
 static void testCross() {
-    TEST_V3(FV3(0, 0, 1), cross(FV3(1, 0, 0), FV3(0, 1, 0)));
-    TEST_V3(FV3(0, -1, 0), cross(FV3(1, 0, 0), FV3(0, 0, 1)));
-    TEST_V3(FV3(0, 0, -1), cross(FV3(0, 1, 0), FV3(1, 0, 0)));
-    TEST_V3(FV3(1, 0, 0), cross(FV3(0, 1, 0), FV3(0, 0, 1)));
-    TEST_V3(FV3(0, 1, 0), cross(FV3(0, 0, 1), FV3(1, 0, 0)));
-    TEST_V3(FV3(-1, 0, 0), cross(FV3(0, 0, 1), FV3(0, 1, 0)));
+    TEST(V3(0, 0, 1), Core::cross(V3(1, 0, 0), V3(0, 1, 0)));
+    TEST(V3(0, -1, 0), Core::cross(V3(1, 0, 0), V3(0, 0, 1)));
+    TEST(V3(0, 0, -1), Core::cross(V3(0, 1, 0), V3(1, 0, 0)));
+    TEST(V3(1, 0, 0), Core::cross(V3(0, 1, 0), V3(0, 0, 1)));
+    TEST(V3(0, 1, 0), Core::cross(V3(0, 0, 1), V3(1, 0, 0)));
+    TEST(V3(-1, 0, 0), Core::cross(V3(0, 0, 1), V3(0, 1, 0)));
 }
 
 static void testSetAdd() {
-#define X(T)                            \
-    {                                   \
-        T v = *C##T(0, 0, 0, 0);        \
-        addSet(&v, C##T(1, 2, 3, 4));   \
-        TEST_##T(C##T(1, 2, 3, 4), &v); \
-        addSet(&v, C##T(2, 3, 4, 5));   \
-        TEST_##T(C##T(3, 5, 7, 9), &v); \
-    }
-    TESTS
-#undef X
+    V3 v;
+    v += V3(1.0f, 2.0f, 3.0f);
+    TEST(V3(1.0f, 2.0f, 3.0f), v);
+    v += V3(2.0f, 3.0f, 4.0f);
+    TEST(V3(3.0f, 5.0f, 7.0f), v);
 }
 
 static void testAdd() {
-    TEST_V3(FV3(1, 2, 3), add(CV30, FV3(1, 2, 3)));
-    TEST_V3(FV3(3, 5, 7), add(FV3(1, 2, 3), FV3(2, 3, 4)));
+    TEST(V3(1.0f, 2.0f, 3.0f), V3() + V3(1.0f, 2.0f, 3.0f));
+    TEST(V3(3.0f, 5.0f, 7.0f), V3(1.0f, 2.0f, 3.0f) + V3(2.0f, 3.0f, 4.0f));
 }
 
 static void testSetSub() {
-#define X(T)                                \
-    {                                       \
-        T v = *C##T(0, 0, 0, 0);            \
-        subSet(&v, C##T(1, 2, 3, 4));       \
-        TEST_##T(C##T(-1, -2, -3, -4), &v); \
-        subSet(&v, C##T(2, 3, 4, 5));       \
-        TEST_##T(C##T(-3, -5, -7, -9), &v); \
-    }
-    TESTS
-#undef X
+    V3 v;
+    v -= V3(1.0f, 2.0f, 3.0f);
+    TEST(V3(-1.0f, -2.0f, -3.0f), v);
+    v -= V3(2.0f, 3.0f, 4.0f);
+    TEST(V3(-3.0f, -5.0f, -7.0f), v);
 }
 
 static void testSub() {
-    TEST_V3(FV3(1, 2, 3), sub(CV30, FV3(-1, -2, -3)));
-    TEST_V3(FV3(-1, -1, -1), sub(FV3(1, 2, 3), FV3(2, 3, 4)));
+    TEST(V3(1.0f, 2.0f, 3.0f), V3() - V3(-1.0f, -2.0f, -3.0f));
+    TEST(V3(-1.0f, -1.0f, -1.0f), V3(1.0f, 2.0f, 3.0f) - V3(2.0f, 3.0f, 4.0f));
+}
+
+static void testInvert() {
+    TEST(V3(-1.0f, 2.0f, 3.0f), -V3(1.0f, -2.0f, -3.0f));
 }
 
 static void testSetMul() {
-#define X(T)                                   \
-    {                                          \
-        T v = *C##T(1, 2, 3, 4);               \
-        mulSet(&v, 3);                         \
-        TEST_##T(C##T(3, 6, 9, 12), &v);       \
-        mulSet(&v, -2);                        \
-        TEST_##T(C##T(-6, -12, -18, -24), &v); \
-    }
-    TESTS
-#undef X
+    V3 v(1.0f, 2.0f, 3.0f);
+    v *= 3.0f;
+    TEST(V3(3.0f, 6.0f, 9.0f), v);
+    v *= -2.0f;
+    TEST(V3(-6.0f, -12.0f, -18.0f), v);
 }
 
 static void testMul() {
-    TEST_V3(FV3(3, 6, 9), mul(FV3(1, 2, 3), 3));
+    TEST(V3(-3.0f, -6.0f, -9.0f), 3.0f * V3(-1.0f, -2.0f, -3.0f));
+    TEST(V3(3.0f, 6.0f, 9.0f), V3(1.0f, 2.0f, 3.0f) * 3.0);
 }
 
 static void testSetMulVector() {
-#define X(T)                                 \
-    {                                        \
-        T v = *C##T(1, 2, 3, 4);             \
-        mulSet(&v, C##T(2, 1, 3, 4));        \
-        TEST_##T(C##T(2, 2, 9, 16), &v);     \
-        mulSet(&v, C##T(-3, 4, -2, -2));     \
-        TEST_##T(C##T(-6, 8, -18, -32), &v); \
-    }
-    TESTS
-#undef X
+    V3 v(1.0f, 2.0f, 3.0f);
+    v *= V3(2.0f, 1.0f, 3.0f);
+    TEST(V3(2.0f, 2.0f, 9.0f), v);
+    v *= V3(-3.0f, 4.0f, -2.0f);
+    TEST(V3(-6.0f, 8.0f, -18.0f), v);
 }
 
 static void testMulVector() {
-    TEST_V3(FV3(-2, -2, -9), mul(FV3(2, 1, 3), FV3(-1, -2, -3)));
-    TEST_V3(FV3(2, 2, 9), mul(FV3(1, 2, 3), FV3(2, 1, 3)));
+    TEST(
+        V3(-2.0f, -2.0f, -9.0f),
+        V3(2.0f, 1.0f, 3.0f) * V3(-1.0f, -2.0f, -3.0f));
+    TEST(V3(2.0f, 2.0f, 9.0f), V3(1.0f, 2.0f, 3.0f) * V3(2.0f, 1.0f, 3.0f));
 }
 
 static void testSetDiv() {
-#define X(T)                                \
-    {                                       \
-        T v = *C##T(18, 36, 9, 27);         \
-        divSet(&v, 3);                      \
-        TEST_##T(C##T(6, 12, 3, 9), &v);    \
-        divSet(&v, -3);                     \
-        TEST_##T(C##T(-2, -4, -1, -3), &v); \
-    }
-    TESTS
-#undef X
+    V3 v(12.0f, 24.0f, 9.0f);
+    v /= 3.0f;
+    TEST(V3(4.0f, 8.0f, 3.0f), v);
+    v /= -2.0f;
+    TEST(V3(-2.0f, -4.0f, -1.5f), v);
 }
 
 static void testDiv() {
-    TEST_V3(FV3(-1, -2, -3), div(FV3(-3, -6, -9), 3));
-}
-
-static void testSetDivVector() {
-#define X(T)                               \
-    {                                      \
-        T v = *C##T(12, 4, 6, 8);          \
-        divSet(&v, C##T(2, 1, 3, 4));      \
-        TEST_##T(C##T(6, 4, 2, 2), &v);    \
-        divSet(&v, C##T(-3, 4, -2, -1));   \
-        TEST_##T(C##T(-2, 1, -1, -2), &v); \
-    }
-    TESTS
-#undef X
-}
-
-static void testDivVector() {
-    TEST_V3(FV3(-2, -0.5f, -1), div(FV3(2, 1, 3), FV3(-1, -2, -3)));
-    TEST_V3(FV3(0.5f, 2, 1), div(FV3(1, 2, 3), FV3(2, 1, 3)));
-}
-
-static void testSetInvert() {
-    TEST_V2(FV2(-1, 2), invertSet(FV2(1, -2)));
-    TEST_V3(FV3(-1, 2, 3), invertSet(FV3(1, -2, -3)));
-    TEST_V4(CV4(-1, 2, 3, 4), invertSet(CV4(1, -2, -3, -4)));
-    TEST_IV2(FIV2(-1, 2), invertSet(FIV2(1, -2)));
-    TEST_IV3(FIV3(-1, 2, 3), invertSet(FIV3(1, -2, -3)));
-    TEST_IV4(CIV4(-1, 2, 3, 4), invertSet(CIV4(1, -2, -3, -4)));
-}
-
-static void testInvert() {
-    TEST_V3(FV3(-1, 2, 3), invert(FV3(1, -2, -3)));
+    TEST(V3(-1.0f, -2.0f, -3.0f), V3(-3.0f, -6.0f, -9.0f) / 3.0f);
 }
 
 static void testDot() {
-    TEST_FLOAT(0, dot(FV2(-4, 2), FV2(-1, -2)), eps);
-    TEST_FLOAT(9, dot(FV3(-4, 2, -3), FV3(-1, -2, -3)), eps);
-    TEST_FLOAT(16, dot(CV4(-4, 2, -3, 1), CV4(-1, -2, -3, 7)), eps);
+    TEST_FLOAT(9.0f, V3(-4.0f, 2.0f, -3.0f).dot(V3(-1.0f, -2.0f, -3.0f)), eps);
+    TEST_FLOAT(-22.0f, V3(2.0f, 2.0f, -4.0f).dot(V3(1.0f, -2.0f, 5.0f)), eps);
 }
 
 static void testSquareLength() {
-    TEST_FLOAT(20, squareLength(FV2(-4, 2)), eps);
-    TEST_FLOAT(29, squareLength(FV3(-4, 2, -3)), eps);
-    TEST_FLOAT(54, squareLength(CV4(-4, 2, -3, 5)), eps);
+    TEST_FLOAT(29.0f, V3(-4.0f, 2.0f, -3.0f).squareLength(), eps);
+    TEST_FLOAT(24.0f, V3(2.0f, 2.0f, -4.0f).squareLength(), eps);
 }
 
 static void testLength() {
-    TEST_FLOAT(5, length(FV2(-3, 4)), eps);
-    TEST_FLOAT(13, length(FV2(5, 12)), eps);
-    TEST_FLOAT(3, length(FV3(-2, 2, -1)), eps);
-    TEST_FLOAT(7, length(FV3(6, 2, -3)), eps);
-    TEST_FLOAT(3, length(CV4(-2, 2, 0, -1)), eps);
-    TEST_FLOAT(9, length(CV4(6, 0, -6, 3)), eps);
+    TEST_FLOAT(3.0f, V3(-2.0f, 2.0f, -1.0f).length(), eps);
+    TEST_FLOAT(7.0f, V3(6.0f, 2.0f, -3.0f).length(), eps);
 }
 
 static void testNormalize() {
-    {
-        V2 v1 = {{-15, 20}};
-        V2 v2;
-        mul(&v2, &v1, 1.0f / 25.0f);
-        normalize(&v1);
-        TEST_V2(&v2, &v1);
-
-        V2 v3 = {{15, 36}};
-        V2 v4;
-        mul(&v4, &v3, 1.0f / 39.0f);
-        normalize(&v3);
-        TEST_V2(&v4, &v3);
-    }
-    {
-        V3 v1 = {{-2, 2, -1}};
-        V3 v2;
-        mul(&v2, &v1, 1.0f / 3.0f);
-        normalize(&v1);
-        TEST_V3(&v2, &v1);
-
-        V3 v3 = {{6, 2, -3}};
-        V3 v4;
-        mul(&v4, &v3, 1.0f / 7.0f);
-        normalize(&v3);
-        TEST_V3(&v4, &v3);
-    }
-    {
-        V4 v1 = {{-2, 2, 0, -1}};
-        V4 v2;
-        mul(&v2, &v1, 1.0f / 3.0f);
-        normalize(&v1);
-        TEST_V4(&v2, &v1);
-
-        V4 v3 = {{6, 0, -6, 3}};
-        V4 v4;
-        mul(&v4, &v3, 1.0f / 9.0f);
-        normalize(&v3);
-        TEST_V4(&v4, &v3);
-    }
+    V3 v1(-2.0f, 2.0f, -1.0f);
+    V3 v2 = v1 * (1.0f / 3.0f);
+    v1.normalize();
+    TEST(v2, v1);
+
+    V3 v3(6.0f, 2.0f, -3.0f);
+    V3 v4 = v3 * (1.0f / 7.0f);
+    v3.normalize();
+    TEST(v4, v3);
 }
 
 static void testCast() {
-    TEST_V2(FV2(-2.0f, 2.0f), convert(CV20, FIV2(-2, 2)));
-    TEST_IV2(FIV2(-2, 2), convert(CIV20, FV2(-2.5f, 2.6f)));
-    TEST_V3(FV3(-2.0f, 2.0f, 9.0f), convert(CV30, FIV3(-2, 2, 9)));
-    TEST_IV3(FIV3(-2, 2, 9), convert(CIV30, FV3(-2.5f, 2.6f, 9.0f)));
-    TEST_V4(CV4(-2.0f, 2.0f, 9.0f, 6.0f), convert(CV40, CIV4(-2, 2, 9, 6)));
-    TEST_IV4(CIV4(-2, 2, 9, 3), convert(CIV40, CV4(-2.5f, 2.6f, 9.0f, 3.2f)));
+    TEST(V3(-2.5f, 2.6f, 9.0f).toInt(), I3(-2, 2, 9));
+    TEST(I3(-2.5f, 2.6f, 9.0f).toFloat(), V3(-2.0f, 2.0f, 9.0f));
 }
 
 static void testToString() {
-    char buffer[64];
-    toStringV2(FV2(4, 5), buffer, sizeof(buffer));
-    TEST_STRING("[4.000, 5.000]", buffer);
-    toStringV3(FV3(4, 5, 6), buffer, sizeof(buffer));
-    TEST_STRING("[4.000, 5.000, 6.000]", buffer);
-    toStringV4(CV4(4, 5, 6, 7), buffer, sizeof(buffer));
-    TEST_STRING("[4.000, 5.000, 6.000, 7.000]", buffer);
-    toStringIV2(FIV2(4, 5), buffer, sizeof(buffer));
-    TEST_STRING("[4, 5]", buffer);
-    toStringIV3(FIV3(4, 5, 6), buffer, sizeof(buffer));
-    TEST_STRING("[4, 5, 6]", buffer);
-    toStringIV4(CIV4(4, 5, 6, 7), buffer, sizeof(buffer));
-    TEST_STRING("[4, 5, 6, 7]", buffer);
+    char buffer[200];
+    formatBuffer(
+        buffer, sizeof(buffer), "# # #", Core::Vector<1, float>(),
+        Core::Vector2(2.0f, 3.0f), V3(4.0f, 5.0f, 6.0f));
+    TEST_STRING("[0.00] [2.00, 3.00] [4.00, 5.00, 6.00]", buffer);
+}
+
+static void testNormalizeIntVector() {
+    I3 i(1, 2, 3);
+    i.normalize();
+    TEST(I3(0, 0, 1), i);
 }
 
 void testVector() {
+    testInitAndRead();
     testSetAngles();
     testCross();
     testSetAdd();
     testAdd();
     testSetSub();
     testSub();
+    testInvert();
     testSetMul();
     testMul();
     testSetMulVector();
     testMulVector();
     testSetDiv();
     testDiv();
-    testSetDivVector();
-    testDivVector();
-    testSetInvert();
-    testInvert();
     testDot();
     testSquareLength();
     testLength();
     testNormalize();
     testCast();
     testToString();
+    testNormalizeIntVector();
 }