diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 68ae187aa9..bee4cba7b7 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -298,6 +298,8 @@ add_subdirectory(angelwrap)
add_subdirectory(cgame)
add_subdirectory(game)
add_subdirectory(steamshim)
+add_subdirectory(gameshared/q_math)
+
if (NOT GAME_MODULES_ONLY)
add_subdirectory(cin)
diff --git a/source/gameshared/q_math/CMakeLists.txt b/source/gameshared/q_math/CMakeLists.txt
new file mode 100644
index 0000000000..782723887e
--- /dev/null
+++ b/source/gameshared/q_math/CMakeLists.txt
@@ -0,0 +1,21 @@
+project(vectmath)
+
+
+function(add_ref_math_test)
+ cmake_parse_arguments(
+ P_ARGS
+ ""
+ "NAME"
+ "SRCS"
+ ${ARGN}
+ )
+ add_executable(${P_ARGS_NAME} ${P_ARGS_SRCS} ${CMOCKA_SRC_FILES})
+ target_include_directories(${P_ARGS_NAME} PRIVATE ${CMOCKA_INCLUDE_DIR} ${STB_INCLUDE_DIR} ".")
+ target_link_libraries(${P_ARGS_NAME} PRIVATE "m")
+ qf_set_output_dir(${P_ARGS_NAME} test)
+endfunction()
+
+if(BUILD_UNIT_TEST )
+ add_ref_math_test(NAME vec_test SRCS "test/vector_test.c")
+endif()
+
diff --git a/source/gameshared/q_math/LICENSE.txt b/source/gameshared/q_math/LICENSE.txt
new file mode 100644
index 0000000000..7fb03efcd4
--- /dev/null
+++ b/source/gameshared/q_math/LICENSE.txt
@@ -0,0 +1,30 @@
+ Vector Math library for 3-D linear algebra (vector, matrix, quaternion)
+ SIMD support for SSE. Also includes generic multi-platform scalar version.
+
+ Copyright (C) 2006, 2007 Sony Computer Entertainment Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms,
+ with or without modification, are permitted provided that the
+ following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Sony Computer Entertainment Inc nor the names
+ of its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/source/gameshared/q_math/README.md b/source/gameshared/q_math/README.md
new file mode 100644
index 0000000000..23e481df9b
--- /dev/null
+++ b/source/gameshared/q_math/README.md
@@ -0,0 +1,53 @@
+
+# Vectormath
+
+Modified version of Sony's open sourced header-only vector and matrix math library.
+I've uploaded a copy here so it can be easily submoduled on other projects.
+
+The main differences from the original library released by Sony:
+
+- Removed deprecated SPU/PPU implementations that only targeted PS3/PowerPC.
+- Removed the C interfaces - the C++ interface is much nicer to use with operator overloads, return by val, etc.
+- Massive namespace cleanup. Removed or replaced most macros with functions and constants.
+- Better compliance with strict aliasing rules.
+- Added portable macros for alignment annotations to remove some `#ifdefs`.
+- Internal SSE helper code moved to a separate header - other files also renamed.
+- Removed the Aos/Soa sub-namespaces, since the Soa implementations were only available for SPU.
+- The library now includes only the generic scalar version and the x86/64 SSE intrinsics version.
+- Added an unpadded `Vector2` and `Point2` to also support basic 2D vector maths. These are always scalar mode (size = 2 floats).
+- All you need to do is include the public header file `vectormath.hpp`. It will expose the relevant parts of the library for you and try to select the SSE implementation if supported.
+
+### Original copyright notice:
+
+
+ Vector Math library for 3-D linear algebra (vector, matrix, quaternion)
+ SIMD support for SSE. Also includes generic multi-platform scalar version.
+
+ Copyright (C) 2006, 2007 Sony Computer Entertainment Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms,
+ with or without modification, are permitted provided that the
+ following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Sony Computer Entertainment Inc nor the names
+ of its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+
diff --git a/source/gameshared/q_math/q_math.h b/source/gameshared/q_math/q_math.h
new file mode 100644
index 0000000000..16c0e16e03
--- /dev/null
+++ b/source/gameshared/q_math/q_math.h
@@ -0,0 +1,32 @@
+#ifndef Q_MATH_H_
+#define Q_MATH_H_
+
+#include "../q_arch.h"
+
+
+#ifdef __cplusplus
+ #define Q_MATH_METHOD(METHOD_C, METHOD_CPP) METHOD_CPP
+#else
+ #define Q_MATH_METHOD(METHOD_C, METHOD_CPP) METHOD_C
+#endif
+
+
+//#elif (VECTORMATH_CPU_HAS_SSE1_OR_BETTER && !VECTORMATH_FORCE_SCALAR_MODE) // SSE
+// #include "sse/vectormath.hpp"
+// using namespace Vectormath::SSE;
+//#elif (VECTORMATH_CPU_HAS_NEON && !VECTORMATH_FORCE_SCALAR_MODE) // NEON
+// #include "neon/vectormath.hpp"
+// using namespace Vectormath::Neon;
+//#else // !SSE
+//#endif // Vectormath mode selection
+
+#include "q_vector_math.h"
+#include "q_math_common.h"
+
+#ifdef __cplusplus
+#else
+#endif
+
+
+#endif
+
diff --git a/source/gameshared/q_math/q_math_common.h b/source/gameshared/q_math/q_math_common.h
new file mode 100644
index 0000000000..7d888b6ad7
--- /dev/null
+++ b/source/gameshared/q_math/q_math_common.h
@@ -0,0 +1,64 @@
+
+
+//----------------------------------------------------------------------------
+// floatX
+//----------------------------------------------------------------------------
+// A simple structure containing 3 floating point values.
+// float3 is always guaranteed to be 3 floats in size. Only use when a very
+// specific size is required (like defining structures that need to be the
+// same across platforms, or the same on CPU and GPU (like constant and
+// structured buffers) In all other cases you should opt to use Vector3, since
+// it uses SIMD optimizations whenever possible. float3 does not.
+//----------------------------------------------------------------------------
+
+#ifndef Q_MATH_COMMON_H_
+#define Q_MATH_COMMON_H_
+
+#if defined( _MSC_VER )
+// Visual Studio (MS compiler)
+#define Q_MATH_ALIGNED( type ) __declspec( align( 16 ) ) type
+#define Q_MATH_ALIGNED_TYPE_PRE __declspec( align( 16 ) )
+#define Q_MATH_ALIGNED_TYPE_POST /* nothing */
+#elif defined( __GNUC__ )
+// GCC or Clang
+#define Q_MATH_ALIGNED( type ) type __attribute__( ( aligned( 16 ) ) )
+#define Q_MATH_ALIGNED_TYPE_PRE /* nothing */
+#define Q_MATH_ALIGNED_TYPE_POST __attribute__( ( aligned( 16 ) ) )
+#else
+// Unknown compiler
+#error "Define Q_MATH_ALIGNED for your compiler or platform!"
+#endif
+
+
+#define q_abs(x) (( (x) > 0 ) ? (x) : -(x))
+#define q_max( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
+#define q_min( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
+
+struct float4 {
+ union {
+ struct {
+ float x, y, z, w;
+ };
+ float v[4];
+ };
+};
+
+struct float3 {
+ union {
+ struct {
+ float x, y, z;
+ };
+ float v[3];
+ };
+};
+
+struct float2 {
+ union {
+ struct {
+ float x, y;
+ };
+ float v[2];
+ };
+};
+
+#endif
diff --git a/source/gameshared/q_math/q_math_settings.h b/source/gameshared/q_math/q_math_settings.h
new file mode 100644
index 0000000000..4c5cfd440e
--- /dev/null
+++ b/source/gameshared/q_math/q_math_settings.h
@@ -0,0 +1,78 @@
+
+// ================================================================================================
+// -*- C++ -*-
+// File: vectormath/vectormath_settings.hpp
+// Author: Guilherme R. Lampert
+// Created on: April 1st, 2021
+// Brief: This header exposes the Sony Vectormath library settings.
+// ================================================================================================
+
+#ifndef VECTORMATH_SETTINGS_HPP
+#define VECTORMATH_SETTINGS_HPP
+
+#if (!defined(VECTORMATH_DEBUG) && (defined(DEBUG) || defined(_DEBUG)))
+#define VECTORMATH_DEBUG 1
+#endif // DEBUG || _DEBUG
+
+// Detecting the availability of SSE at compile-time is a bit more involving with Visual Studio...
+#if defined(_MSC_VER) && !defined(NN_NINTENDO_SDK)
+ #if (defined(__AVX__) || defined(__AVX2__) || defined(_M_AMD64) || defined(_M_X64) || (_M_IX86_FP == 1) || (_M_IX86_FP == 2))
+ #define VECTORMATH_CPU_HAS_SSE1_OR_BETTER 1
+ #else // SSE support
+ #define VECTORMATH_CPU_HAS_SSE1_OR_BETTER 0
+ #endif // SSE support
+#else // !_MSC_VER
+ #if defined(__SSE__)
+ #define VECTORMATH_CPU_HAS_SSE1_OR_BETTER 1
+ #elif defined(__ANDROID__)
+ #if defined(ANDROID_ARM_NEON)
+ #define VECTORMATH_CPU_HAS_NEON 1
+ #else
+ #define VECTORMATH_CPU_HAS_SSE1_OR_BETTER 0
+ #define VECTORMATH_CPU_HAS_NEON 0
+ #endif
+ #elif defined(__arm64) || defined(__aarch64__) || defined(__arm__ )
+ #define VECTORMATH_CPU_HAS_NEON 1
+ #else // !__SSE__
+ #define VECTORMATH_CPU_HAS_SSE1_OR_BETTER 0
+ #define VECTORMATH_CPU_HAS_NEON 0
+ #endif // __SSE__
+#endif // _MSC_VER
+
+#define VECTORMATH_FORCE_SCALAR_MODE 0
+
+#if defined(ORBIS) || defined(PROSPERO)
+ #define VECTORMATH_MODE_SCE 1
+#endif
+
+#if defined(__APPLE__) && defined(__arm__)
+ #define VECTORMATH_CPU_HAS_SSE1_OR_BETTER 0
+ #define VECTORMATH_CPU_HAS_NEON 1
+#endif
+
+// Vectormath mode selection
+#if VECTORMATH_MODE_SCE
+#define VECTORMATH_MODE_SCALAR 0
+#define VECTORMATH_MODE_SSE 1
+#define VECTORMATH_MODE_NEON 0
+#define VECTORMATH_MIN_ALIGN 16
+#elif (VECTORMATH_CPU_HAS_SSE1_OR_BETTER && !VECTORMATH_FORCE_SCALAR_MODE) // SSE
+#define VECTORMATH_MODE_SCALAR 0
+#define VECTORMATH_MODE_SSE 1
+#define VECTORMATH_MODE_NEON 0
+#define VECTORMATH_MIN_ALIGN 16
+#elif (VECTORMATH_CPU_HAS_NEON && !VECTORMATH_FORCE_SCALAR_MODE) // NEON
+#define VECTORMATH_MODE_SCALAR 0
+#define VECTORMATH_MODE_SSE 0
+#define VECTORMATH_MODE_NEON 1
+#define VECTORMATH_MIN_ALIGN 16
+#else // !SSE
+#define VECTORMATH_MODE_SCALAR 1
+#define VECTORMATH_MODE_SSE 0
+#define VECTORMATH_MODE_NEON 0
+#define VECTORMATH_MIN_ALIGN 0
+#endif // Vectormath mode selection
+
+
+
+#endif // VECTORMATH_SETTINGS_HPP
diff --git a/source/gameshared/q_math/q_vector_math.h b/source/gameshared/q_math/q_vector_math.h
new file mode 100644
index 0000000000..011e6ec049
--- /dev/null
+++ b/source/gameshared/q_math/q_vector_math.h
@@ -0,0 +1,735 @@
+
+#include
+#include
+#include "q_math_common.h"
+
+
+#ifndef Q_VECTOR_MATH_H
+#define Q_VECTOR_MATH_H
+
+static const float VECTORMATH_SLERP_TOL = 0.999f;
+static const double VECTORMATH_SLERP_TOL_D = 0.999;
+
+//Q_MATH_ALIGNED_TYPE_PRE struct vec4i_s {
+// int x, y, z, w;
+//} Q_MATH_ALIGNED_TYPE_POST;
+
+Q_MATH_ALIGNED_TYPE_PRE struct vec3_s {
+ float x, y, z;
+} Q_MATH_ALIGNED_TYPE_POST;
+
+Q_MATH_ALIGNED_TYPE_PRE struct vec4_s {
+ float x, y, z, w;
+} Q_MATH_ALIGNED_TYPE_POST;
+
+Q_MATH_ALIGNED_TYPE_PRE struct vec2_s {
+ float x, y;
+} Q_MATH_ALIGNED_TYPE_POST;
+
+Q_MATH_ALIGNED_TYPE_PRE struct mat3_s {
+ struct vec3_s col0;
+ struct vec3_s col1;
+ struct vec3_s col2;
+ struct vec3_s col3;
+} Q_MATH_ALIGNED_TYPE_POST;
+
+Q_MATH_ALIGNED_TYPE_PRE struct mat4_s {
+ struct vec4_s col0;
+ struct vec4_s col1;
+ struct vec4_s col2;
+ struct vec4_s col3;
+} Q_MATH_ALIGNED_TYPE_POST;
+
+Q_MATH_ALIGNED_TYPE_PRE struct quat_s {
+ float x, y, z, w;
+} Q_MATH_ALIGNED_TYPE_POST;
+
+// quaternion
+inline struct quat_s q_quat_create( float x, float y, float z, float w);
+
+inline float q_quat_ele(uint_fast8_t index, const struct quat_s v1 );
+inline float q_quat_x(const struct quat_s v1 );
+inline float q_quat_y(const struct quat_s v1 );
+inline float q_quat_z(const struct quat_s v1 );
+inline float q_quat_w(const struct quat_s v1 );
+
+// vec2
+inline struct vec2_s q_vec2_create( float x, float y );
+
+inline float q_vec2_ele( uint_fast8_t index, const struct vec2_s v1 );
+inline float q_vec2_x( const struct vec2_s v1 );
+inline float q_vec2_y( const struct vec2_s v1 );
+
+// vec3
+inline struct vec3_s q_vec3_create( float x, float y, float z );
+
+inline float q_vec3_dot( const struct vec3_s v1, const struct vec3_s v2);
+inline float q_vec3_sum(const struct vec3_s vec);
+inline struct vec3_s q_vec3_slerp( float t, const struct vec3_s unitVec0, const struct vec3_s unitVec1 );
+inline struct vec3_s q_vec3_add( const struct vec3_s v1, const struct vec3_s v2 );
+inline struct vec3_s q_vec3_div( const struct vec3_s v1, const struct vec3_s v2 );
+inline struct vec3_s q_vec3_sub( const struct vec3_s v1, const struct vec3_s v2 );
+inline struct vec3_s q_vec3_mul( const struct vec3_s v1, const struct vec3_s v2 );
+
+inline float q_vec3_ele( uint_fast8_t index, const struct vec3_s v1 );
+inline float q_vec3_x( const struct vec3_s v1 );
+inline float q_vec3_y( const struct vec3_s v1 );
+inline float q_vec3_z( const struct vec3_s v1 );
+
+inline struct vec3_s q_vec3_add_scalar( const struct vec3_s v1, float value );
+inline struct vec3_s q_vec3_sub_scalar( const struct vec3_s v1, float value );
+inline struct vec3_s q_vec3_mul_scalar( const struct vec3_s v1, float value );
+inline struct vec3_s q_vec3_div_scalar( const struct vec3_s v1, float value );
+
+inline struct vec3_s q_vec3_max_per_element( const struct vec3_s v1, const struct vec3_s v2);
+inline struct vec3_s q_vec3_min_per_element( const struct vec3_s v1, const struct vec3_s v2);
+inline const struct vec3_s q_vec3_copy_sign_element( const struct vec3_s v1, const struct vec3_s v2);
+
+inline float q_vec3_max_element( struct vec3_s v1);
+inline float q_vec3_min_element( struct vec3_s v1);
+
+inline struct vec3_s q_vec3_normalize( const struct vec3_s v1);
+inline float q_vec3_length( const struct vec3_s v1);
+inline float q_vec3_length_sqr( const struct vec3_s v1);
+
+inline const struct vec3_s q_vec3_cross( const struct vec3_s v1, const struct vec3_s v2);
+
+// vec4
+inline float q_vec4_ele(uint_fast8_t index, const struct vec4_s v1 );
+inline float q_vec4_x(const struct vec4_s v1 );
+inline float q_vec4_y(const struct vec4_s v1 );
+inline float q_vec4_z(const struct vec4_s v1 );
+inline float q_vec4_w(const struct vec4_s v1 );
+
+inline struct vec3_s q_vec4_as_vec3( const struct vec4_s v );
+inline struct vec2_s q_vec4_as_vec2( const struct vec4_s v );
+
+inline struct vec4_s q_vec4_create( float x, float y, float z, float w);
+
+inline struct vec4_s q_vec4_slerp( float t, const struct vec4_s unitVec0, const struct vec4_s unitVec1 );
+
+inline struct vec4_s q_vec4_add_scalar( const struct vec4_s v1, float value);
+inline struct vec4_s q_vec4_sub_scalar( const struct vec4_s v1, float value );
+inline struct vec4_s q_vec4_mul_scalar( const struct vec4_s v1, float value );
+
+inline struct vec4_s q_vec4_max_per_ele( const struct vec4_s v1, const struct vec4_s v2);
+inline struct vec4_s q_vec4_min_per_ele( const struct vec4_s v1, const struct vec4_s v2);
+inline struct vec4_s q_vec4_copy_sign_ele( const struct vec4_s v1, const struct vec4_s v2);
+
+inline float q_vec4_max_ele( const struct vec4_s v1);
+inline float q_vec4_min_ele( const struct vec4_s v1);
+
+inline struct vec4_s q_vec4_normalize( const struct vec4_s v1);
+inline float q_vec4_length( const struct vec4_s v1);
+inline float q_vec4_length_sqr( const struct vec4_s v1);
+inline float q_vec4_dot( const struct vec4_s v1,const struct vec4_s v2);
+
+inline float q_vec4_sum(const struct vec4_s vec);
+inline struct vec4_s q_vec4_add( const struct vec4_s v1, const struct vec4_s v2 );
+inline struct vec4_s q_vec4_sub( const struct vec4_s v1, const struct vec4_s v2 );
+inline struct vec4_s q_vec4_mul( const struct vec4_s v1, const struct vec4_s v2 );
+
+// mat3
+inline struct mat3_s q_mat3_create(
+ const struct vec3_s col0,
+ const struct vec3_s col1,
+ const struct vec3_s col2 );
+inline struct mat3_s q_mat3_create_quat(const struct quat_s q);
+inline float q_mat3_ele( const struct mat3_s v1, uint_fast8_t col, uint_fast8_t row );
+
+// mat4
+
+inline struct mat4_s q_mat4_create( const struct vec4_s col0,
+ const struct vec4_s col1,
+ const struct vec4_s col2,
+ const struct vec4_s col3 );
+inline float q_mat4_ele( const struct mat4_s v1, uint_fast8_t col, uint_fast8_t row );
+inline struct mat4_s q_mat4_create_quat(const struct quat_s q);
+
+// ---------------------------
+
+#ifdef __cplusplus
+ inline struct vec3_s q_vec_add(const struct vec3_s a, const struct vec3_s b) { return q_vec3_add(a,b); }
+ inline struct vec3_s q_vec_add(const struct vec3_s a, float b) { return q_vec3_add_scalar (a,b); }
+#else
+ #define __Q_MATH_VEC_GENERIC_2(a,b) (void(*)(typeof(a), typeof(b)))0
+ #define q_vec_mul(a,b) _Generic(__Q_MATH_VEC_GENERIC_2(a,b), \
+ void(*)(const struct vec3_s, const struct vec3_s): q_vec3_mul, \
+ void(*)(const struct vec3_s, float): q_vec3_mul_scalar \
+ )(a,b)
+ #define q_vec_add(a,b) _Generic(__Q_MATH_VEC_GENERIC_2(a,b), \
+ void(*)(const struct vec3_s, const struct vec3_s): q_vec3_add, \
+ void(*)(const struct vec3_s, float): q_vec3_add_scalar \
+ )(a,b)
+ #define q_vec_sub(a,b) _Generic(__Q_MATH_VEC_GENERIC_2(a,b), \
+ void(*)(const struct vec3_s, const struct vec3_s): q_vec3_sub, \
+ void(*)(const struct vec3_s, float): q_vec3_sub_scalar \
+ )(a,b)
+ #define q_vec_div(a,b) _Generic(__Q_MATH_VEC_GENERIC_2(a,b), \
+ void(*)(const struct vec3_s, const struct vec3_s): q_vec3_div_scalar, \
+ void(*)(const struct vec3_s, float): q_vec3_div_scalar \
+ )(a,b)
+#endif
+
+
+struct mat4_s q_mat4_create( const struct vec4_s col0,
+ const struct vec4_s col1,
+ const struct vec4_s col2,
+ const struct vec4_s col3 ) {
+ struct mat4_s res;
+ res.col0 = col0;
+ res.col1 = col1;
+ res.col2 = col2;
+ res.col3 = col3;
+ return res;
+}
+struct mat4_s q_mat4_create_quat(const struct quat_s q) {
+
+}
+
+struct mat3_s q_mat3_create_quat(const struct quat_s q) {
+ float qx, qy, qz, qw, qx2, qy2, qz2, qxqx2, qyqy2, qzqz2, qxqy2, qyqz2, qzqw2, qxqz2, qyqw2, qxqw2;
+ qx = q_quat_x(q);
+ qy = q_quat_y(q);
+ qz = q_quat_z(q);
+ qw = q_quat_w(q);
+ qx2 = (qx + qx);
+ qy2 = (qy + qy);
+ qz2 = (qz + qz);
+ qxqx2 = (qx * qx2);
+ qxqy2 = (qx * qy2);
+ qxqz2 = (qx * qz2);
+ qxqw2 = (qw * qx2);
+ qyqy2 = (qy * qy2);
+ qyqz2 = (qy * qz2);
+ qyqw2 = (qw * qy2);
+ qzqz2 = (qz * qz2);
+ qzqw2 = (qw * qz2);
+ struct mat3_s res;
+ res.col0 = q_vec3_create(((1.0f - qyqy2) - qzqz2), (qxqy2 + qzqw2), (qxqz2 - qyqw2));
+ res.col1 = q_vec3_create((qxqy2 - qzqw2), ((1.0f - qxqx2) - qzqz2), (qyqz2 + qxqw2));
+ res.col1 = q_vec3_create((qxqz2 + qyqw2), (qyqz2 - qxqw2), ((1.0f - qxqx2) - qyqy2));
+ return res;
+}
+
+
+float q_mat4_ele( const struct mat4_s v1, uint_fast8_t col, uint_fast8_t row ) {
+ switch(col) {
+ case 0:
+ return q_vec4_ele(row, v1.col0);
+ case 1:
+ return q_vec4_ele(row, v1.col1);
+ case 2:
+ return q_vec4_ele(row, v1.col2);
+ case 3:
+ return q_vec4_ele(row, v1.col3);
+ }
+ return 0.0f;
+}
+
+struct mat3_s q_mat3_create( const struct vec3_s col0,
+ const struct vec3_s col1,
+ const struct vec3_s col2 ) {
+ struct mat3_s res;
+ res.col0 = col0;
+ res.col1 = col1;
+ res.col2 = col2;
+ return res;
+}
+
+float q_mat3_ele( const struct mat3_s v1, uint_fast8_t col, uint_fast8_t row ) {
+ switch(col) {
+ case 0:
+ return q_vec3_ele(row, v1.col0);
+ case 1:
+ return q_vec3_ele(row, v1.col1);
+ case 2:
+ return q_vec3_ele(row, v1.col2);
+ }
+ return 0.0f;
+}
+
+struct vec2_s q_vec2_create( float x, float y ) {
+ struct vec2_s res;
+ res.x = x;
+ res.y = y;
+ return res;
+
+}
+struct vec4_s q_vec4_create( float x, float y, float z, float w )
+{
+ struct vec4_s res;
+ res.x = x;
+ res.y = y;
+ res.z = z;
+ res.w = z;
+ return res;
+}
+
+struct vec3_s q_vec3_create( float x, float y, float z )
+{
+ struct vec3_s res;
+ res.x = x;
+ res.y = y;
+ res.z = z;
+ return res;
+}
+
+float q_vec3_sum(const struct vec3_s vec) {
+ return vec.x + vec.y + vec.z;
+}
+
+float q_vec4_dot( const struct vec4_s v1,const struct vec4_s v2) {
+ float result = ( v1.x * v2.x );
+ result += ( v1.y * v2.y );
+ result += ( v1.z * v2.z );
+ result += ( v1.z * v2.z );
+ return result;
+
+}
+
+float q_vec3_dot( const struct vec3_s v1, const struct vec3_s v2 )
+{
+ float result = ( v1.x * v2.x );
+ result += ( v1.y * v2.y );
+ result += ( v1.z * v2.z );
+ return result;
+}
+
+float q_vec4_sum(const struct vec4_s vec) {
+ return vec.x + vec.y + vec.z + vec.w;
+}
+
+struct vec4_s q_vec4_add( const struct vec4_s v1, const struct vec4_s v2 ) {
+ struct vec4_s res;
+ res.x = v1.x + v2.x;
+ res.y = v1.y + v2.x;
+ res.z = v1.z + v2.y;
+ res.w = v1.w + v2.z;
+ return res;
+
+}
+
+struct vec4_s q_vec4_sub( const struct vec4_s v1, const struct vec4_s v2 ) {
+ struct vec4_s res;
+ res.x = v1.x - v2.x;
+ res.y = v1.y - v2.x;
+ res.z = v1.z - v2.y;
+ res.w = v1.w - v2.z;
+ return res;
+}
+
+struct vec4_s q_vec4_mul( const struct vec4_s v1, const struct vec4_s v2 ) {
+ struct vec4_s res;
+ res.x = v1.x * v2.x;
+ res.y = v1.y * v2.x;
+ res.z = v1.z * v2.y;
+ res.w = v1.w * v2.z;
+ return res;
+}
+
+
+struct vec3_s q_vec3_add( const struct vec3_s v1, const struct vec3_s v2 )
+{
+ struct vec3_s res;
+ res.x = v1.x + v2.x;
+ res.y = v1.y + v2.y;
+ res.z = v1.z + v2.z;
+ return res;
+}
+
+struct vec3_s q_vec3_div( const struct vec3_s v1, const struct vec3_s v2 )
+{
+ struct vec3_s res;
+ res.x = v1.x / v2.x;
+ res.y = v1.y / v2.y;
+ res.z = v1.z / v2.z;
+ return res;
+}
+
+struct vec3_s q_vec3_sub( const struct vec3_s v1, const struct vec3_s v2 )
+{
+ struct vec3_s res;
+ res.x = v1.x - v2.x;
+ res.y = v1.y - v2.y;
+ res.z = v1.z - v2.z;
+ return res;
+}
+
+struct vec3_s q_vec3_mul( const struct vec3_s v1, const struct vec3_s v2 )
+{
+ struct vec3_s res;
+ res.x = v1.x * v2.x;
+ res.y = v1.y * v2.y;
+ res.z = v1.z * v2.z;
+ return res;
+}
+
+float q_vec3_ele( uint_fast8_t index, const struct vec3_s v1 )
+{
+ switch( index ) {
+ case 0:
+ return v1.x;
+ case 1:
+ return v1.y;
+ case 2:
+ return v1.z;
+ }
+ assert( 0 ); // this is bad
+ return 0.0f;
+}
+
+struct vec3_s q_vec3_slerp( float t, const struct vec3_s unitVec0, const struct vec3_s unitVec1 ) {
+ float recipSinAngle, scale0, scale1, cosAngle, angle;
+ cosAngle = q_vec3_dot(unitVec0, unitVec1);
+ if (cosAngle < VECTORMATH_SLERP_TOL)
+ {
+ angle = acosf(cosAngle);
+ recipSinAngle = (1.0f / sinf(angle));
+ scale0 = (sinf(((1.0f - t) * angle)) * recipSinAngle);
+ scale1 = (sinf((t * angle)) * recipSinAngle);
+ }
+ else
+ {
+ scale0 = (1.0f - t);
+ scale1 = t;
+ }
+
+ return q_vec3_add(q_vec3_mul_scalar(unitVec0, scale0), q_vec3_mul_scalar(unitVec1, scale1));
+}
+
+struct vec4_s q_vec4_slerp( float t, const struct vec4_s unitVec0, const struct vec4_s unitVec1 ) {
+ float recipSinAngle, scale0, scale1, cosAngle, angle;
+ cosAngle = q_vec4_dot(unitVec0, unitVec1);
+ if (cosAngle < VECTORMATH_SLERP_TOL)
+ {
+ angle = acosf(cosAngle);
+ recipSinAngle = (1.0f / sinf(angle));
+ scale0 = (sinf(((1.0f - t) * angle)) * recipSinAngle);
+ scale1 = (sinf((t * angle)) * recipSinAngle);
+ }
+ else
+ {
+ scale0 = (1.0f - t);
+ scale1 = t;
+ }
+ return q_vec4_add(q_vec4_mul_scalar(unitVec0, scale0),q_vec4_mul_scalar(unitVec1,scale1));
+
+}
+
+
+struct vec3_s q_vec3_div_scalar( const struct vec3_s v1, float value )
+{
+ struct vec3_s res;
+ res.x = v1.x / value;
+ res.y = v1.y / value;
+ res.z = v1.z / value;
+ return res;
+}
+
+struct vec4_s q_vec4_add_scalar( const struct vec4_s v1, float value) {
+ struct vec4_s res;
+ res.x = v1.x + value;
+ res.y = v1.y + value;
+ res.z = v1.z + value;
+ res.z = v1.z + value;
+ return res;
+}
+
+struct vec4_s q_vec4_sub_scalar( const struct vec4_s v1, float value ) {
+ struct vec4_s res;
+ res.x = v1.x - value;
+ res.y = v1.y - value;
+ res.z = v1.z - value;
+ res.z = v1.z - value;
+ return res;
+
+}
+struct vec4_s q_vec4_mul_scalar( const struct vec4_s v1, float value ) {
+ struct vec4_s res;
+ res.x = v1.x * value;
+ res.y = v1.y * value;
+ res.z = v1.z * value;
+ res.z = v1.z * value;
+ return res;
+}
+
+struct vec3_s q_vec3_add_scalar( const struct vec3_s v1, float value )
+{
+ struct vec3_s res;
+ res.x = v1.x + value;
+ res.y = v1.y + value;
+ res.z = v1.z + value;
+ return res;
+}
+
+struct vec3_s q_vec3_sub_scalar( const struct vec3_s v1, float value )
+{
+ struct vec3_s res;
+ res.x = v1.x - value;
+ res.y = v1.y - value;
+ res.z = v1.z - value;
+ return res;
+}
+
+struct vec3_s q_vec3_mul_scalar( const struct vec3_s v1, float value )
+{
+ struct vec3_s res;
+ res.x = v1.x * value;
+ res.y = v1.y * value;
+ res.z = v1.z * value;
+ return res;
+}
+
+struct vec4_s q_vec4_max_per_ele( const struct vec4_s v1, const struct vec4_s v2) {
+ struct vec4_s res;
+ res.x = q_max(v1.x, v2.x);
+ res.y = q_max(v1.y, v2.y);
+ res.z = q_max(v1.z, v2.z);
+ res.w = q_max(v1.w, v2.w);
+ return res;
+}
+
+struct vec4_s q_vec4_min_per_ele( const struct vec4_s v1, const struct vec4_s v2) {
+ struct vec4_s res;
+ res.x = q_min(v1.x, v2.x);
+ res.y = q_min(v1.y, v2.y);
+ res.z = q_min(v1.z, v2.z);
+ res.w = q_min(v1.w, v2.w);
+ return res;
+}
+
+struct vec4_s q_vec4_copy_sign_ele( const struct vec4_s v1, const struct vec4_s v2) {
+ struct vec4_s res;
+ res.x = ( v1.x < 0 ) ? -fabsf( v2.x ) : fabsf( v2.x );
+ res.y = ( v1.y < 0 ) ? -fabsf( v2.y ) : fabsf( v2.y );
+ res.z = ( v1.z < 0 ) ? -fabsf( v2.z ) : fabsf( v2.z );
+ res.w = ( v1.w < 0 ) ? -fabsf( v2.w ) : fabsf( v2.w );
+ return res;
+}
+
+struct vec3_s q_vec3_max_per_element( const struct vec3_s v1, const struct vec3_s v2) {
+ struct vec3_s res;
+ res.x = q_max(v1.x, v2.x);
+ res.y = q_max(v1.y, v2.y);
+ res.z = q_max(v1.z, v2.z);
+ return res;
+}
+struct vec3_s q_vec3_min_per_element( const struct vec3_s v1, const struct vec3_s v2) {
+ struct vec3_s res;
+ res.x = q_min(v1.x, v2.x);
+ res.y = q_min(v1.y, v2.y);
+ res.z = q_min(v1.z, v2.z);
+ return res;
+}
+inline const struct vec3_s q_vec3_copy_sign_element( const struct vec3_s v1, const struct vec3_s v2) {
+ struct vec3_s res;
+ res.x = ( v2.x < 0 ) ? -q_abs(v1.x) : q_abs(v1.x);
+ res.y = ( v2.y < 0 ) ? -q_abs(v1.y) : q_abs(v1.y);
+ res.z = ( v2.z < 0 ) ? -q_abs(v1.z) : q_abs(v1.z);
+ return res;
+}
+
+float q_vec4_ele(uint_fast8_t index, const struct vec4_s v1 ) {
+ switch(index) {
+ case 0:
+ return v1.x;
+ case 1:
+ return v1.y;
+ case 2:
+ return v1.z;
+ case 3:
+ return v1.w;
+ }
+ assert(0);
+ return 0;
+}
+
+
+float q_vec4_x( const struct vec4_s v1 )
+{
+ return v1.x;
+}
+
+float q_vec4_y( const struct vec4_s v1 )
+{
+ return v1.y;
+}
+
+float q_vec4_z( const struct vec4_s v1 )
+{
+ return v1.z;
+}
+
+float q_vec4_w( const struct vec4_s v1 )
+{
+ return v1.w;
+}
+
+float q_vec3_x( const struct vec3_s v1 )
+{
+ return v1.x;
+}
+
+float q_vec3_y( const struct vec3_s v1 )
+{
+ return v1.y;
+}
+
+float q_vec3_z( const struct vec3_s v1 )
+{
+ return v1.z;
+}
+
+float q_vec2_ele( uint_fast8_t index, const struct vec2_s v1 ) {
+ switch( index ) {
+ case 0:
+ return v1.x;
+ case 1:
+ return v1.y;
+ }
+ assert( 0 );
+ return 0;
+}
+
+float q_vec2_x( const struct vec2_s v1 ) {
+ return v1.x;
+}
+
+float q_vec2_y( const struct vec2_s v1 ) {
+ return v1.y;
+}
+
+float q_quat_ele(uint_fast8_t index, const struct quat_s v1 ) {
+ switch(index) {
+ case 0:
+ return v1.x;
+ case 1:
+ return v1.y;
+ case 2:
+ return v1.z;
+ case 3:
+ return v1.w;
+ }
+ assert(0);
+ return 0;
+}
+float q_quat_x(const struct quat_s v1 ) {
+ return v1.x;
+}
+float q_quat_y(const struct quat_s v1 ) {
+ return v1.y;
+}
+float q_quat_z(const struct quat_s v1 ) {
+ return v1.z;
+}
+float q_quat_w(const struct quat_s v1 ) {
+ return v1.w;
+}
+
+struct vec3_s q_vec4_as_vec3( const struct vec4_s v ) {
+ return q_vec3_create(v.x, v.y, v.z);
+}
+
+struct vec2_s q_vec4_as_vec2( const struct vec4_s v ) {
+ return q_vec2_create(v.x, v.y);
+}
+
+float q_vec4_max_ele( const struct vec4_s v1) {
+ const float x = q_vec4_x(v1);
+ const float y = q_vec4_y(v1);
+ const float z = q_vec4_z(v1);
+ const float w = q_vec4_z(v1);
+ return q_max(q_max(x, y), q_max(z,w));
+}
+
+float q_vec4_min_ele( const struct vec4_s v1) {
+ const float x = q_vec4_x(v1);
+ const float y = q_vec4_y(v1);
+ const float z = q_vec4_z(v1);
+ const float w = q_vec4_z(v1);
+ return q_min(q_min(x, y), q_min(z,w));
+}
+
+float q_vec3_max_element( struct vec3_s v1) {
+ const float x = q_vec3_x(v1);
+ const float y = q_vec3_y(v1);
+ const float z = q_vec3_z(v1);
+ return q_max(q_max(x, y), z);
+}
+
+float q_vec3_min_element( struct vec3_s v1) {
+ const float x = q_vec3_x(v1);
+ const float y = q_vec3_y(v1);
+ const float z = q_vec3_z(v1);
+ return q_min(q_min(x, y), z);
+}
+
+struct vec4_s q_vec4_normalize( const struct vec4_s v1) {
+ const float lenSqr = q_vec4_length_sqr(v1);
+ const float lenInv = (1.0 / sqrt(lenSqr));
+ return q_vec4_create((q_vec4_x(v1) * lenInv),
+ (q_vec4_y(v1) * lenInv),
+ (q_vec4_z(v1) * lenInv),
+ (q_vec4_w(v1) * lenInv));
+
+}
+
+float q_vec4_length( const struct vec4_s v1) {
+ return sqrt(q_vec4_x(v1) * q_vec4_x(v1) +
+ q_vec4_y(v1) * q_vec4_y(v1) +
+ q_vec4_z(v1) * q_vec4_z(v1) +
+ q_vec4_w(v1) * q_vec4_w(v1));
+
+}
+
+float q_vec4_length_sqr( const struct vec4_s v1) {
+ return q_vec4_x(v1) * q_vec4_x(v1) +
+ q_vec4_y(v1) * q_vec4_y(v1) +
+ q_vec4_z(v1) * q_vec4_z(v1) +
+ q_vec4_w(v1) * q_vec4_w(v1);
+
+}
+
+struct vec3_s q_vec3_normalize( const struct vec3_s v1 )
+{
+ const float lenSqr = q_vec3_length_sqr(v1);
+ const float lenInv = (1.0 / sqrt(lenSqr));
+ return q_vec3_create((q_vec3_x(v1) * lenInv),
+ (q_vec3_y(v1) * lenInv),
+ (q_vec3_z(v1) * lenInv));
+}
+
+float q_vec3_length( const struct vec3_s v1 )
+{
+ return sqrtf(
+ q_vec3_x(v1) * q_vec3_x(v1) +
+ q_vec3_y(v1) * q_vec3_y(v1) +
+ q_vec3_z(v1) * q_vec3_z(v1));
+}
+
+float q_vec3_length_sqr( const struct vec3_s v1 )
+{
+ return q_vec3_x(v1) * q_vec3_x(v1) +
+ q_vec3_y(v1) * q_vec3_y(v1) +
+ q_vec3_z(v1) * q_vec3_z(v1);
+}
+
+inline const struct vec3_s q_vec3_cross( const struct vec3_s v1, const struct vec3_s v2){
+ return q_vec3_create(((q_vec3_y(v1) * q_vec3_z(v2)) - (q_vec3_z(v1) * q_vec3_y(v2))),
+ ((q_vec3_z(v1) * q_vec3_x(v2)) - (q_vec3_x(v1) * q_vec3_z(v2))),
+ ((q_vec3_x(v1) * q_vec3_y(v2)) - (q_vec3_y(v1) * q_vec3_x(v2))));
+
+}
+
+struct quat_s q_quat_create( float x, float y, float z, float w )
+{
+ struct quat_s quat;
+ quat.x = x;
+ quat.y = y;
+ quat.z = z;
+ quat.w = w;
+ return quat;
+}
+
+#endif
diff --git a/source/gameshared/q_math/test/vector_test.c b/source/gameshared/q_math/test/vector_test.c
new file mode 100644
index 0000000000..5fb8d15f09
--- /dev/null
+++ b/source/gameshared/q_math/test/vector_test.c
@@ -0,0 +1,247 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "../q_math.h"
+#include "../q_arch.h"
+
+
+void test_vec3_vec3_mul() {
+ struct {
+ struct vec3_s v1, v2;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), q_vec3_create(1, 1, 1), q_vec3_create(1, 0, 0)},
+ {q_vec3_create(0, 0, 0), q_vec3_create(1, 1, 1), q_vec3_create(0, 0, 0)},
+ {q_vec3_create(-1, -1, -1), q_vec3_create(1, 1, 1), q_vec3_create(-1, -1, -1)}
+ };
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec_mul(test[i].v1, test[i].v2);
+ assert_float_equal(
+ q_vec3_ele(0,res),
+ q_vec3_ele(0,test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1,res),
+ q_vec3_ele(1,test[i].expected), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele( 2,res ),
+ q_vec3_ele( 2,test[i].expected), 0.9999f );
+ }
+
+}
+
+void test_vec3_scalar_sub() {
+ struct {
+ struct vec3_s v1;
+ float scalar;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), 1, q_vec3_create(0, -1, -1)},
+ {q_vec3_create(0, 0, 0), 1, q_vec3_create(-1, -1, -1)},
+ {q_vec3_create(-1, -1, -1), 1, q_vec3_create(-2, -2, -2)}
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec_sub(test[i].v1, test[i].scalar);
+ assert_float_equal(
+ q_vec3_ele(0, res),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res ),
+ q_vec3_ele(1, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+
+}
+
+void test_vec3_scalar_add() {
+ struct {
+ struct vec3_s v1;
+ float scalar;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), 1, q_vec3_create(2, 1, 1)},
+ {q_vec3_create(0, 0, 0), 1, q_vec3_create(1, 1, 1)},
+ {q_vec3_create(-1, -1, -1), 1, q_vec3_create(0, 0, 0)}
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec3_add_scalar(test[i].v1, test[i].scalar);
+ assert_float_equal(
+ q_vec3_ele(0, res ),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res ),
+ q_vec3_ele(1, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+
+}
+
+void test_vec3_slerp() {
+ struct {
+ struct vec3_s v1, v2;
+ float slerp;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1.0f, 0.0f, 0.0f), q_vec3_create(0.0f, 1.0f, 0.0f), 0.5f, q_vec3_create(0.7071f, 0.7071f, 0.0f)},
+ };
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec3_slerp(test[i].slerp,test[i].v1, test[i].v2);
+ assert_float_equal(
+ q_vec3_ele(0, res ),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res),
+ q_vec3_ele(1, test[i].expected), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+
+}
+
+void test_vec3_cross() {
+ struct {
+ struct vec3_s v1, v2;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1.0f, 2.0f, 3.0f), q_vec3_create(3.0f, 1.0f, -1.0f), q_vec3_create(-5.0f, 10.0f, -5.0f)},
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec3_cross(test[i].v1, test[i].v2);
+ assert_float_equal(
+ q_vec3_ele(0, res ),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res ),
+ q_vec3_ele(1, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+}
+
+void test_vec3_min_per_element() {
+ struct {
+ struct vec3_s v1, v2;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), q_vec3_create(0, 1, 1), q_vec3_create(0, 0, 0)},
+ {q_vec3_create(1, 0, 0), q_vec3_create(0, 1, 0), q_vec3_create(0, 0, 0)}, // Orthogonal vectors
+ {q_vec3_create(1, 1, 1), q_vec3_create(1, 1, 1), q_vec3_create(1, 1, 1)}, // Non-orthogonal, positive dot product
+ {q_vec3_create(1, 0, 0), q_vec3_create(-1, 0, 0), q_vec3_create(-1, 0, 0)}, // Non-orthogonal, negative dot product
+ {q_vec3_create(2, 3, 4), q_vec3_create(1, 0, 0), q_vec3_create(1, 0, 0)}, // Vectors with different lengths
+ {q_vec3_create(0, 0, 0), q_vec3_create(0, 0, 0), q_vec3_create(0, 0, 0)}, // Zero vectors
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec3_min_per_element(test[i].v1, test[i].v2);
+ assert_float_equal(
+ q_vec3_ele(0, res ),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res ),
+ q_vec3_ele(1, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+
+}
+
+void test_vec3_max_per_element() {
+ struct {
+ struct vec3_s v1, v2;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), q_vec3_create(0, 1, 1), q_vec3_create(1, 1, 1)},
+ {q_vec3_create(1, 0, 0), q_vec3_create(0, 1, 0), q_vec3_create(1, 1, 0)}, // Orthogonal vectors
+ {q_vec3_create(1, 1, 1), q_vec3_create(1, 1, 1), q_vec3_create(1, 1, 1)}, // Non-orthogonal, positive dot product
+ {q_vec3_create(1, 0, 0), q_vec3_create(-1, 0, 0), q_vec3_create(1, 0, 0)}, // Non-orthogonal, negative dot product
+ {q_vec3_create(2, 3, 4), q_vec3_create(1, 0, 0), q_vec3_create(2, 3, 4)}, // Vectors with different lengths
+ {q_vec3_create(0, 0, 0), q_vec3_create(0, 0, 0), q_vec3_create(0, 0, 0)}, // Zero vectors
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec3_max_per_element(test[i].v1, test[i].v2);
+ assert_float_equal(
+ q_vec3_ele(0, res ),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res ),
+ q_vec3_ele(1, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+
+}
+
+
+void test_vec3_dot() {
+ struct {
+ struct vec3_s v1, v2;
+ float expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), q_vec3_create(0, 1, 1), 0},
+ {q_vec3_create(1, 0, 0), q_vec3_create(0, 1, 0), 0}, // Orthogonal vectors
+ {q_vec3_create(1, 1, 1), q_vec3_create(1, 1, 1), 3}, // Non-orthogonal, positive dot product
+ {q_vec3_create(1, 0, 0), q_vec3_create(-1, 0, 0), -1}, // Non-orthogonal, negative dot product
+ {q_vec3_create(2, 3, 4), q_vec3_create(1, 0, 0), 2}, // Vectors with different lengths
+ {q_vec3_create(0, 0, 0), q_vec3_create(0, 0, 0), 0}, // Zero vectors
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ assert_float_equal(q_vec3_dot(test[i].v1, test[i].v2), test[i].expected, 0.9999f);
+ }
+
+}
+
+void test_vec3_vec3_add() {
+ struct {
+ struct vec3_s v1, v2;
+ struct vec3_s expected;
+ } test[] = {
+ {q_vec3_create(1, 0, 0), q_vec3_create(1, 1, 1), q_vec3_create(2, 1, 1)},
+ {q_vec3_create(0, 0, 0), q_vec3_create(1, 1, 1), q_vec3_create(1, 1, 1)},
+ {q_vec3_create(-1, -1, -1), q_vec3_create(1, 1, 1), q_vec3_create(0, 0, 0)}
+ };
+
+ for(size_t i = 0; i < Q_ARRAY_COUNT(test); i++){
+ struct vec3_s res = q_vec_add(test[i].v1, test[i].v2);
+ assert_float_equal(
+ q_vec3_ele(0, res ),
+ q_vec3_ele(0, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(1, res ),
+ q_vec3_ele(1, test[i].expected ), 0.9999f );
+ assert_float_equal(
+ q_vec3_ele(2, res ),
+ q_vec3_ele(2, test[i].expected ), 0.9999f );
+ }
+}
+
+int main( void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test( test_vec3_vec3_add ),
+ cmocka_unit_test( test_vec3_vec3_mul ),
+ cmocka_unit_test( test_vec3_scalar_add ),
+ cmocka_unit_test( test_vec3_scalar_sub ),
+ cmocka_unit_test( test_vec3_dot ),
+ cmocka_unit_test( test_vec3_max_per_element ),
+ cmocka_unit_test( test_vec3_min_per_element ),
+ cmocka_unit_test( test_vec3_cross),
+ cmocka_unit_test( test_vec3_slerp),
+ };
+
+ return cmocka_run_group_tests( tests, NULL, NULL );
+}
diff --git a/source/ref_base/CMakeLists.txt b/source/ref_base/CMakeLists.txt
index 399072d216..d129d95a45 100644
--- a/source/ref_base/CMakeLists.txt
+++ b/source/ref_base/CMakeLists.txt
@@ -1,5 +1,4 @@
-
function(add_ref_base_test)
cmake_parse_arguments(
P_ARGS