Browse Source

Vector3 tests and implementation

Kajetan Johannes Hammerle 1 month ago
parent
commit
f917fe0e8d
6 changed files with 436 additions and 8 deletions
  1. 3 5
      CMakeLists.txt
  2. 53 0
      include/core/Vector.h
  3. 147 0
      src/Vector.c
  4. 1 2
      test/Main.c
  5. 0 1
      test/Tests.h
  6. 232 0
      test/modules/VectorTests.c

+ 3 - 5
CMakeLists.txt

@@ -8,6 +8,7 @@ set(SRC
     "src/Logger.c"
     "src/Random.c"
     "src/Utility.c"
+    "src/Vector.c"
     #"src/BitArray.cpp"
     #"src/Box.cpp"
     #"src/Frustum.cpp"
@@ -17,7 +18,6 @@ set(SRC
     #"src/Quaternion.cpp"
     #"src/SpinLock.cpp"
     #"src/Thread.cpp"
-    #"src/Vector.cpp"
     #"src/View.cpp"
 )
 
@@ -27,9 +27,9 @@ set(SRC_TESTS
     "test/modules/BufferTests.c"
     "test/modules/RandomTests.c"
     "test/modules/UtilityTests.c"
+    "test/modules/VectorTests.c"
     #"test/modules/BitArrayTests.cpp"
     #"test/modules/BoxTests.cpp"
-    #"test/modules/ColorTests.cpp"
     #"test/modules/ComponentsTests.cpp"
     #"test/modules/FrustumTests.cpp"
     #"test/modules/HashMapTests.cpp"
@@ -42,7 +42,6 @@ set(SRC_TESTS
     #"test/modules/RingBufferTests.cpp"
     #"test/modules/StackTests.cpp"
     #"test/modules/ThreadTests.cpp"
-    #"test/modules/VectorTests.cpp"
     #"test/modules/ViewTests.cpp"
 )
 
@@ -151,7 +150,7 @@ target_compile_definitions(core
     PRIVATE ${DEFINITIONS}
 )
 target_link_libraries(core 
-    PRIVATE ${LINK_OPTIONS}
+    PRIVATE m ${LINK_OPTIONS}
 )
 target_sources(core PUBLIC 
     FILE_SET HEADERS
@@ -165,7 +164,6 @@ target_sources(core PUBLIC
         ./include/core/Utility.h
 #        ./include/core/BitArray.hpp
 #        ./include/core/Box.hpp
-#        ./include/core/Color.hpp
 #        ./include/core/Components.hpp
 #        ./include/core/Frustum.hpp
 #        ./include/core/HashMap.hpp

+ 53 - 0
include/core/Vector.h

@@ -0,0 +1,53 @@
+#ifndef CORE_VECTOR_H
+#define CORE_VECTOR_H
+
+#include "core/Types.h"
+
+#define CORE_VECTOR_OP2(name) name *r, const name *a
+#define CORE_VECTOR_OP3(name) CORE_VECTOR_OP2(name), const name* b
+
+#define CORE_DEFINE_VECTOR(N, name, sname, type, factor)                       \
+    typedef struct {                                                           \
+        type data[N];                                                          \
+    } name;                                                                    \
+    name* coreAddSet##sname(CORE_VECTOR_OP2(name));                            \
+    name* coreAdd##sname(CORE_VECTOR_OP3(name));                               \
+    name* coreSubSet##sname(CORE_VECTOR_OP2(name));                            \
+    name* coreSub##sname(CORE_VECTOR_OP3(name));                               \
+    name* coreMulSet##sname(CORE_VECTOR_OP2(name));                            \
+    name* coreMul##sname(CORE_VECTOR_OP3(name));                               \
+    name* coreDivSet##sname(CORE_VECTOR_OP2(name));                            \
+    name* coreDiv##sname(CORE_VECTOR_OP3(name));                               \
+    name* coreMulSet##sname##factor(name* r, type f);                          \
+    name* coreMul##sname##factor(name* r, const name* a, type f);              \
+    name* coreDivSet##sname##factor(name* r, type f);                          \
+    name* coreDiv##sname##factor(name* r, const name* a, type f);              \
+    name* coreInvertSet##sname(name* r);                                       \
+    name* coreInvert##sname(name* r, const name* a);                           \
+    type coreDot##sname(const name* a, const name* b);                         \
+    type coreSquareLength##sname(const name* a);                               \
+    type coreLength##sname(const name* a);                                     \
+    name* coreNormalize##sname(name* r);                                       \
+    void coreToString##sname(const name* a, char* buffer, size_t n);
+
+CORE_DEFINE_VECTOR(2, CoreVector2, V2, float, F)
+CORE_DEFINE_VECTOR(3, CoreVector3, V3, float, F)
+CORE_DEFINE_VECTOR(4, CoreVector4, V4, float, F)
+CORE_DEFINE_VECTOR(2, CoreIntVector2, IV2, int, I)
+CORE_DEFINE_VECTOR(3, CoreIntVector3, IV3, int, I)
+CORE_DEFINE_VECTOR(4, CoreIntVector4, IV4, int, I)
+
+CoreVector3* coreAngles(CoreVector3* r, float lengthAngle, float widthAngle);
+CoreVector3* coreCross(CORE_VECTOR_OP3(CoreVector3));
+
+#define CORE_DEFINE_VECTOR_CONVERSION(a, b, name)                              \
+    a* coreConvert##name(a* r, const b* c)
+
+CORE_DEFINE_VECTOR_CONVERSION(CoreVector2, CoreIntVector2, IV2);
+CORE_DEFINE_VECTOR_CONVERSION(CoreVector3, CoreIntVector3, IV3);
+CORE_DEFINE_VECTOR_CONVERSION(CoreVector4, CoreIntVector4, IV4);
+CORE_DEFINE_VECTOR_CONVERSION(CoreIntVector2, CoreVector2, V2);
+CORE_DEFINE_VECTOR_CONVERSION(CoreIntVector3, CoreVector3, V3);
+CORE_DEFINE_VECTOR_CONVERSION(CoreIntVector4, CoreVector4, V4);
+
+#endif

+ 147 - 0
src/Vector.c

@@ -0,0 +1,147 @@
+#include "core/Vector.h"
+
+#include <math.h>
+#include <stdio.h>
+
+#include "core/Utility.h"
+
+#define V3 CoreVector3
+#define IV3 CoreIntVector3
+
+V3* coreAddSetV3(V3* r, const V3* a) {
+    return coreAddV3(r, r, a);
+}
+
+V3* coreAddV3(V3* r, const V3* a, const V3* b) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = a->data[i] + b->data[i];
+    }
+    return r;
+}
+
+V3* coreSubSetV3(V3* r, const V3* a) {
+    return coreSubV3(r, r, a);
+}
+
+V3* coreSubV3(V3* r, const V3* a, const V3* b) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = a->data[i] - b->data[i];
+    }
+    return r;
+}
+
+V3* coreMulSetV3(V3* r, const V3* a) {
+    return coreMulV3(r, r, a);
+}
+
+V3* coreMulV3(V3* r, const V3* a, const V3* b) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = a->data[i] * b->data[i];
+    }
+    return r;
+}
+
+V3* coreDivSetV3(V3* r, const V3* a) {
+    return coreDivV3(r, r, a);
+}
+
+V3* coreDivV3(V3* r, const V3* a, const V3* b) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = a->data[i] / b->data[i];
+    }
+    return r;
+}
+
+V3* coreMulSetV3F(V3* r, float f) {
+    return coreMulV3F(r, r, f);
+}
+
+V3* coreMulV3F(V3* r, const V3* a, float f) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = a->data[i] * f;
+    }
+    return r;
+}
+
+V3* coreDivSetV3F(V3* r, float f) {
+    return coreDivV3F(r, r, f);
+}
+
+V3* coreDivV3F(V3* r, const V3* a, float f) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = a->data[i] / f;
+    }
+    return r;
+}
+
+V3* coreInvertSetV3(V3* r) {
+    return coreInvertV3(r, r);
+}
+
+V3* coreInvertV3(V3* r, const V3* a) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = -a->data[i];
+    }
+    return r;
+}
+
+float coreDotV3(const V3* a, const V3* b) {
+    float length = 0.0f;
+    for(int i = 0; i < 3; i++) {
+        length += a->data[i] * b->data[i];
+    }
+    return length;
+}
+
+float coreSquareLengthV3(const V3* a) {
+    return coreDotV3(a, a);
+}
+
+float coreLengthV3(const V3* a) {
+    return sqrtf(coreSquareLengthV3(a));
+}
+
+V3* coreNormalizeV3(V3* r) {
+    return coreMulSetV3F(r, 1.0f / coreLengthV3(r));
+}
+
+void coreToStringV3(const V3* a, char* buffer, size_t n) {
+    snprintf(buffer, n, "[%.3f, %.3f, %.3f]", (double)a->data[0],
+             (double)a->data[1], (double)a->data[2]);
+}
+
+V3* coreAngles(V3* r, float lengthAngle, float widthAngle) {
+    lengthAngle = coreDegreeToRadian(lengthAngle);
+    widthAngle = coreDegreeToRadian(widthAngle);
+
+    float sWidth = sinf(widthAngle);
+    float cWidth = cosf(widthAngle);
+    float sLength = sinf(lengthAngle);
+    float cLength = cosf(lengthAngle);
+
+    r->data[0] = cWidth * cLength;
+    r->data[1] = sWidth;
+    r->data[2] = -sLength * cWidth;
+    return r;
+}
+
+V3* coreCross(V3* r, const V3* a, const V3* b) {
+    r->data[0] = a->data[1] * b->data[2] - a->data[2] * b->data[1];
+    r->data[1] = a->data[2] * b->data[0] - a->data[0] * b->data[2];
+    r->data[2] = a->data[0] * b->data[1] - a->data[1] * b->data[0];
+    return r;
+}
+
+V3* coreConvertIV3(V3* r, const IV3* a) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = (float)a->data[i];
+    }
+    return r;
+}
+
+IV3* coreConvertV3(IV3* r, const V3* a) {
+    for(int i = 0; i < 3; i++) {
+        r->data[i] = (int)a->data[i];
+    }
+    return r;
+}

+ 1 - 2
test/Main.c

@@ -34,7 +34,6 @@ int main(int argAmount, const char** args) {
     // coreTestBitArray();
     // coreTestBox();
     coreTestBuffer(light);
-    // coreTestColor();
     // coreTestComponents();
     // coreTestFrustum();
     // coreTestHashMap(light);
@@ -49,7 +48,7 @@ int main(int argAmount, const char** args) {
     // coreTestStack(light);
     // coreTestThread();
     coreTestUtility(light);
-    // coreTestVector();
+    coreTestVector();
     // coreTestView();
 
     coreLogLevel = CORE_LOG_WARNING;

+ 0 - 1
test/Tests.h

@@ -6,7 +6,6 @@
 void coreTestBitArray(void);
 void coreTestBox(void);
 void coreTestBuffer(bool light);
-void coreTestColor(void);
 void coreTestComponents(void);
 void coreTestFileReader(void);
 void coreTestFrustum(void);

+ 232 - 0
test/modules/VectorTests.c

@@ -0,0 +1,232 @@
+#include <math.h>
+
+#include "../Tests.h"
+#include "core/Vector.h"
+
+const float eps = 0.0001f;
+
+#define V3 CoreVector3
+#define CV3(a, b, c)                                                           \
+    &(V3) {                                                                    \
+        a, b, c                                                                \
+    }
+#define CV30 CV3(0, 0, 0)
+
+#define IV3 CoreIntVector3
+#define CIV3(a, b, c)                                                          \
+    &(IV3) {                                                                   \
+        a, b, c                                                                \
+    }
+#define CIV30 CIV3(0, 0, 0)
+
+static void testVector3B(const char* file, int line, const V3* wanted,
+                         const V3* actual) {
+    for(int i = 0; i < 3; i++) {
+        coreTestFloat(file, line, wanted->data[i], actual->data[i], eps);
+    }
+}
+
+#define testVector3(wanted, actual)                                            \
+    testVector3B(__FILE__, __LINE__, wanted, actual)
+
+static void testIntVector3(const IV3* wanted, const IV3* actual) {
+    for(int i = 0; i < 3; i++) {
+        CORE_TEST_INT(wanted->data[i], actual->data[i]);
+    }
+}
+
+static void testSetAngles() {
+    float root = sqrtf(2) * 0.5f;
+    testVector3(CV3(1, 0, 0), coreAngles(CV30, 0, 0));
+    testVector3(CV3(root, 0, -root), coreAngles(CV30, 45, 0));
+    testVector3(CV3(0, 0, -1), coreAngles(CV30, 90, 0));
+    testVector3(CV3(-root, 0, -root), coreAngles(CV30, 135, 0));
+    testVector3(CV3(-1, 0, 0), coreAngles(CV30, 180, 0));
+    testVector3(CV3(-root, 0, root), coreAngles(CV30, 225, 0));
+    testVector3(CV3(0, 0, 1), coreAngles(CV30, 270, 0));
+    testVector3(CV3(root, 0, root), coreAngles(CV30, 315, 0));
+
+    testVector3(CV3(0, 1, 0), coreAngles(CV30, 0, 90));
+    testVector3(CV3(0, 1, 0), coreAngles(CV30, 90, 90));
+    testVector3(CV3(0, 1, 0), coreAngles(CV30, 180, 90));
+    testVector3(CV3(0, 1, 0), coreAngles(CV30, 270, 90));
+
+    testVector3(CV3(0, -1, 0), coreAngles(CV30, 0, -90));
+    testVector3(CV3(0, -1, 0), coreAngles(CV30, 90, -90));
+    testVector3(CV3(0, -1, 0), coreAngles(CV30, 180, -90));
+    testVector3(CV3(0, -1, 0), coreAngles(CV30, 270, -90));
+
+    testVector3(CV3(root, root, 0), coreAngles(CV30, 0, 45));
+    testVector3(CV3(0, root, -root), coreAngles(CV30, 90, 45));
+    testVector3(CV3(-root, root, 0), coreAngles(CV30, 180, 45));
+    testVector3(CV3(0, root, root), coreAngles(CV30, 270, 45));
+
+    testVector3(CV3(root, -root, 0), coreAngles(CV30, 0, -45));
+    testVector3(CV3(0, -root, -root), coreAngles(CV30, 90, -45));
+    testVector3(CV3(-root, -root, 0), coreAngles(CV30, 180, -45));
+    testVector3(CV3(0, -root, root), coreAngles(CV30, 270, -45));
+
+    testVector3(CV3(0.5f, root, -0.5f), coreAngles(CV30, 45, 45));
+}
+
+static void testCross() {
+    testVector3(CV3(0, 0, 1), coreCross(CV30, CV3(1, 0, 0), CV3(0, 1, 0)));
+    testVector3(CV3(0, -1, 0), coreCross(CV30, CV3(1, 0, 0), CV3(0, 0, 1)));
+    testVector3(CV3(0, 0, -1), coreCross(CV30, CV3(0, 1, 0), CV3(1, 0, 0)));
+    testVector3(CV3(1, 0, 0), coreCross(CV30, CV3(0, 1, 0), CV3(0, 0, 1)));
+    testVector3(CV3(0, 1, 0), coreCross(CV30, CV3(0, 0, 1), CV3(1, 0, 0)));
+    testVector3(CV3(-1, 0, 0), coreCross(CV30, CV3(0, 0, 1), CV3(0, 1, 0)));
+}
+
+static void testSetAdd() {
+    V3 v = {0};
+    coreAddSetV3(&v, CV3(1, 2, 3));
+    testVector3(CV3(1, 2, 3), &v);
+    coreAddSetV3(&v, CV3(2, 3, 4));
+    testVector3(CV3(3, 5, 7), &v);
+}
+
+static void testAdd() {
+    testVector3(CV3(1, 2, 3), coreAddV3(CV30, CV30, CV3(1, 2, 3)));
+    testVector3(CV3(3, 5, 7), coreAddV3(CV30, CV3(1, 2, 3), CV3(2, 3, 4)));
+}
+
+static void testSetSub() {
+    V3 v = {0};
+    coreSubSetV3(&v, CV3(1, 2, 3));
+    testVector3(CV3(-1, -2, -3), &v);
+    coreSubSetV3(&v, CV3(2, 3, 4));
+    testVector3(CV3(-3, -5, -7), &v);
+}
+
+static void testSub() {
+    testVector3(CV3(1, 2, 3), coreSubV3(CV30, CV30, CV3(-1, -2, -3)));
+    testVector3(CV3(-1, -1, -1), coreSubV3(CV30, CV3(1, 2, 3), CV3(2, 3, 4)));
+}
+
+static void testSetMul() {
+    V3 v = {1, 2, 3};
+    coreMulSetV3F(&v, 3);
+    testVector3(CV3(3, 6, 9), &v);
+    coreMulSetV3F(&v, -2);
+    testVector3(CV3(-6, -12, -18), &v);
+}
+
+static void testMul() {
+    testVector3(CV3(3, 6, 9), coreMulV3F(CV30, CV3(1, 2, 3), 3));
+}
+
+static void testSetMulVector() {
+    V3 v = {1, 2, 3};
+    coreMulSetV3(&v, CV3(2, 1, 3));
+    testVector3(CV3(2, 2, 9), &v);
+    coreMulSetV3(&v, CV3(-3, 4, -2));
+    testVector3(CV3(-6, 8, -18), &v);
+}
+
+static void testMulVector() {
+    testVector3(CV3(-2, -2, -9),
+                coreMulV3(CV30, CV3(2, 1, 3), CV3(-1, -2, -3)));
+    testVector3(CV3(2, 2, 9), coreMulV3(CV30, CV3(1, 2, 3), CV3(2, 1, 3)));
+}
+
+static void testSetDiv() {
+    V3 v = {12, 24, 9};
+    coreDivSetV3F(&v, 3);
+    testVector3(CV3(4, 8, 3), &v);
+    coreDivSetV3F(&v, -2);
+    testVector3(CV3(-2, -4, -1.5f), &v);
+}
+
+static void testDiv() {
+    testVector3(CV3(-1, -2, -3), coreDivV3F(CV30, CV3(-3, -6, -9), 3));
+}
+
+static void testSetDivVector() {
+    V3 v = {3, 4, 6};
+    coreDivSetV3(&v, CV3(2, 1, 3));
+    testVector3(CV3(1.5f, 4, 2), &v);
+    coreDivSetV3(&v, CV3(-3, 4, -2));
+    testVector3(CV3(-0.5f, 1, -1), &v);
+}
+
+static void testDivVector() {
+    testVector3(CV3(-2, -0.5f, -1),
+                coreDivV3(CV30, CV3(2, 1, 3), CV3(-1, -2, -3)));
+    testVector3(CV3(0.5f, 2, 1), coreDivV3(CV30, CV3(1, 2, 3), CV3(2, 1, 3)));
+}
+
+static void testSetInvert() {
+    testVector3(CV3(-1, 2, 3), coreInvertSetV3(CV3(1, -2, -3)));
+}
+
+static void testInvert() {
+    testVector3(CV3(-1, 2, 3), coreInvertV3(CV30, CV3(1, -2, -3)));
+}
+
+static void testDot() {
+    CORE_TEST_FLOAT(9, coreDotV3(CV3(-4, 2, -3), CV3(-1, -2, -3)), eps);
+    CORE_TEST_FLOAT(-22, coreDotV3(CV3(2, 2, -4), CV3(1, -2, 5)), eps);
+}
+
+static void testSquareLength() {
+    CORE_TEST_FLOAT(29, coreSquareLengthV3(CV3(-4, 2, -3)), eps);
+    CORE_TEST_FLOAT(24, coreSquareLengthV3(CV3(2, 2, -4)), eps);
+}
+
+static void testLength() {
+    CORE_TEST_FLOAT(3, coreLengthV3(CV3(-2, 2, -1)), eps);
+    CORE_TEST_FLOAT(7, coreLengthV3(CV3(6, 2, -3)), eps);
+}
+
+static void testNormalize() {
+    V3 v1 = {-2, 2, -1};
+    V3 v2;
+    coreMulV3F(&v2, &v1, 1.0f / 3.0f);
+    coreNormalizeV3(&v1);
+    testVector3(&v2, &v1);
+
+    V3 v3 = {6, 2, -3};
+    V3 v4;
+    coreMulV3F(&v4, &v3, 1.0f / 7.0f);
+    coreNormalizeV3(&v3);
+    testVector3(&v4, &v3);
+}
+
+static void testCast() {
+    testVector3(CV3(-2.0f, 2.0f, 9.0f), coreConvertIV3(CV30, CIV3(-2, 2, 9)));
+    testIntVector3(CIV3(-2, 2, 9),
+                   coreConvertV3(CIV30, CV3(-2.5f, 2.6f, 9.0f)));
+}
+
+static void testToString() {
+    V3 v = {4, 5, 6};
+    char buffer[64];
+    coreToStringV3(&v, buffer, sizeof(buffer));
+    CORE_TEST_STRING("[4.000, 5.000, 6.000]", buffer);
+}
+
+void coreTestVector() {
+    testSetAngles();
+    testCross();
+    testSetAdd();
+    testAdd();
+    testSetSub();
+    testSub();
+    testSetMul();
+    testMul();
+    testSetMulVector();
+    testMulVector();
+    testSetDiv();
+    testDiv();
+    testSetDivVector();
+    testDivVector();
+    testSetInvert();
+    testInvert();
+    testDot();
+    testSquareLength();
+    testLength();
+    testNormalize();
+    testCast();
+    testToString();
+}