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