Test if two 3D vectors are equal within epsilon tolerance.
Test if two 3D vectors are equal within epsilon tolerance.Performs component-wise comparison with floating-point tolerance.
#ifndef __VEC_SIMD_H__
#define __VEC_SIMD_H__
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
typedef union ALIGN(16) SimdVec2 {
simd_vec_t v;
float f32[4];
struct {
float x;
float y;
};
} SimdVec2;
typedef union ALIGN(16) SimdVec3 {
simd_vec_t v;
float f32[4];
struct {
float x;
float y;
float z;
float w;
};
} SimdVec3;
typedef union ALIGN(16) SimdVec4 {
simd_vec_t v;
float f32[4];
struct {
float x;
float y;
float z;
float w;
};
} SimdVec4;
static inline void vec2_print(
const Vec2 v,
const char* name) {
if (name) {
printf("%s: ", name);
}
printf(
"Vec2(%f, %f)\n", v.
x, v.
y);
}
static inline void vec3_print(
const Vec3 v,
const char* name) {
if (name) {
printf("%s: ", name);
}
printf(
"Vec3(%.4f, %.4f, %.4f)\n", v.
x, v.
y, v.z);
}
static inline void vec3_print_ex(
const Vec3 v,
const char* name) {
if (name) {
printf("%s: ", name);
}
printf(
"Vec3(%f, %f, %f)\n", v.
x, v.
y, v.z);
}
static inline void vec4_print(
const Vec4 v,
const char* name) {
if (name) {
printf("%s: ", name);
}
printf(
"Vec4(%.4f, %.4f, %.4f, %.4f)\n", v.
x, v.
y, v.z, v.w);
}
static inline SimdVec2 vec2_load(
Vec2 v) {
SimdVec2 res;
res.v = simd_set(v.
x, v.
y, 0.0f, 0.0f);
return res;
}
static inline Vec2 vec2_store(SimdVec2 v) {
}
static inline SimdVec2 vec2_add(SimdVec2 a, SimdVec2 b) { return (SimdVec2){.v = simd_add(a.v, b.v)}; }
static inline SimdVec2 vec2_sub(SimdVec2 a, SimdVec2 b) { return (SimdVec2){.v = simd_sub(a.v, b.v)}; }
static inline SimdVec2 vec2_mul(SimdVec2 a, float s) { return (SimdVec2){.v = simd_mul(a.v, simd_set1(s))}; }
static inline float vec2_dot(SimdVec2 a, SimdVec2 b) {
return (a.x * b.x) + (a.y * b.y);
}
static inline float vec2_length_sq(SimdVec2 v) { return vec2_dot(v, v); }
static inline float vec2_length(SimdVec2 v) { return sqrtf(vec2_length_sq(v)); }
static inline SimdVec2 vec2_normalize(SimdVec2 v) {
return (SimdVec2){.v = simd_normalize3(v.v)};
}
static inline SimdVec2 vec2_rotate(SimdVec2 v, float angle) {
float c = cosf(angle);
float s = sinf(angle);
simd_vec_t x = simd_splat_x(v.v);
simd_vec_t y = simd_splat_y(v.v);
simd_vec_t c0 = simd_set(c, s, 0.0f, 0.0f);
simd_vec_t c1 = simd_set(-s, c, 0.0f, 0.0f);
return (SimdVec2){.v = simd_add(simd_mul(x, c0), simd_mul(y, c1))};
}
static inline float vec2_distance_sq(SimdVec2 a, SimdVec2 b) { return vec2_length_sq(vec2_sub(b, a)); }
static inline float vec2_distance(SimdVec2 a, SimdVec2 b) { return sqrtf(vec2_distance_sq(a, b)); }
static inline SimdVec2 vec2_lerp(SimdVec2 a, SimdVec2 b, float t) {
SimdVec2 diff = vec2_sub(b, a);
SimdVec2 part = vec2_mul(diff, t);
return vec2_add(a, part);
}
static inline SimdVec2 vec2_project(SimdVec2 a, SimdVec2 b) {
float b_len_sq = vec2_length_sq(b);
if (b_len_sq < 1e-6f) return (SimdVec2){{0}};
float scale = vec2_dot(a, b) / b_len_sq;
return vec2_mul(b, scale);
}
static inline SimdVec2 vec2_reject(SimdVec2 a, SimdVec2 b) { return vec2_sub(a, vec2_project(a, b)); }
static inline SimdVec2 vec2_perpendicular(SimdVec2 v) {
return (SimdVec2){.v = simd_set(-v.y, v.x, 0.0f, 0.0f)};
}
static inline SimdVec3 vec3_load(
Vec3 v) {
SimdVec3 res;
res.v = simd_set(v.
x, v.
y, v.
z, 0.0f);
return res;
}
static inline Vec3 vec3_store(SimdVec3 v) {
return (
Vec3){v.
x, v.y, v.z}; }
static inline SimdVec3 vec3_add(SimdVec3 a, SimdVec3 b) { return (SimdVec3){.v = simd_add(a.v, b.v)}; }
static inline SimdVec3 vec3_sub(SimdVec3 a, SimdVec3 b) { return (SimdVec3){.v = simd_sub(a.v, b.v)}; }
static inline SimdVec3 vec3_mul(SimdVec3 a, float s) { return (SimdVec3){.v = simd_mul(a.v, simd_set1(s))}; }
static inline SimdVec3 vec3_scale(SimdVec3 a, SimdVec3 b) { return (SimdVec3){.v = simd_mul(a.v, b.v)}; }
static inline float vec3_dot(SimdVec3 a, SimdVec3 b) { return simd_dot3(a.v, b.v); }
static inline SimdVec3 vec3_cross(SimdVec3 a, SimdVec3 b) { return (SimdVec3){.v = simd_cross(a.v, b.v)}; }
static inline float vec3_length_sq(SimdVec3 v) { return simd_length_sq3(v.v); }
static inline float vec3_length(SimdVec3 v) { return simd_length3(v.v); }
static inline SimdVec3 vec3_normalize(SimdVec3 v) { return (SimdVec3){.v = simd_normalize3(v.v)}; }
static inline SimdVec3 vec3_normalize_fast(SimdVec3 v) { return (SimdVec3){.v = simd_normalize3_fast(v.v)}; }
static inline float vec3_distance_sq(SimdVec3 a, SimdVec3 b) { return vec3_length_sq(vec3_sub(b, a)); }
static inline float vec3_distance(SimdVec3 a, SimdVec3 b) { return sqrtf(vec3_distance_sq(a, b)); }
static inline SimdVec3 vec3_lerp(SimdVec3 a, SimdVec3 b, float t) {
SimdVec3 diff = vec3_sub(b, a);
return vec3_add(a, vec3_mul(diff, t));
}
static inline SimdVec3 vec3_project(SimdVec3 a, SimdVec3 b) {
float b_len_sq = vec3_length_sq(b);
if (b_len_sq < 1e-6f) return (SimdVec3){{0}};
float scale = vec3_dot(a, b) / b_len_sq;
return vec3_mul(b, scale);
}
static inline SimdVec3 vec3_reject(SimdVec3 a, SimdVec3 b) { return vec3_sub(a, vec3_project(a, b)); }
static inline SimdVec3 vec3_perpendicular(SimdVec3 v) {
SimdVec3 axis;
if (fabsf(v.y) < 0.99f) {
axis = vec3_load((
Vec3){0.0f, 1.0f, 0.0f});
} else {
axis = vec3_load((
Vec3){1.0f, 0.0f, 0.0f});
}
return vec3_normalize(vec3_cross(v, axis));
}
static inline SimdVec4 vec4_load(
Vec4 v) {
SimdVec4 res;
res.v = simd_set(v.
x, v.
y, v.
z, v.
w);
return res;
}
static inline Vec4 vec4_store(SimdVec4 v) {
return (
Vec4){v.
x, v.y, v.z, v.w}; }
static inline float vec4_length(SimdVec4 v) { return simd_length4(v.v); }
static inline float vec4_length_sq(SimdVec4 v) { return simd_length_sq4(v.v); }
static inline SimdVec4 vec4_add(SimdVec4 a, SimdVec4 b) { return (SimdVec4){.v = simd_add(a.v, b.v)}; }
static inline SimdVec4 vec4_sub(SimdVec4 a, SimdVec4 b) { return (SimdVec4){.v = simd_sub(a.v, b.v)}; }
static inline SimdVec4 vec4_mul(SimdVec4 a, float s) { return (SimdVec4){.v = simd_mul(a.v, simd_set1(s))}; }
static inline SimdVec4 vec4_div(SimdVec4 a, float s) {
if (fabsf(s) < 1e-8f) {
return (SimdVec4){.v = simd_set_zero()};
}
return vec4_mul(a, 1.0f / s);
}
static inline float vec4_dot(SimdVec4 a, SimdVec4 b) { return simd_dot4(a.v, b.v); }
static inline SimdVec4 vec4_scale(SimdVec4 a, SimdVec4 b) { return (SimdVec4){.v = simd_mul(a.v, b.v)}; }
static inline SimdVec4 vec4_normalize(SimdVec4 a) { return (SimdVec4){.v = simd_normalize4(a.v)}; }
static inline SimdVec4 vec4_rotate_x(SimdVec4 v, float angle) {
float c = cosf(angle);
float s = sinf(angle);
float ny = v.
y * c - v.z * s;
float nz = v.
y * s + v.z * c;
return (SimdVec4){.v = simd_set(v.
x, ny, nz, v.w)};
}
static inline SimdVec4 vec4_rotate_y(SimdVec4 v, float angle) {
float c = cosf(angle);
float s = sinf(angle);
float nx = v.
x * c + v.z * s;
float nz = -v.
x * s + v.z * c;
return (SimdVec4){.v = simd_set(nx, v.
y, nz, v.w)};
}
static inline SimdVec4 vec4_rotate_z(SimdVec4 v, float angle) {
float c = cosf(angle);
float s = sinf(angle);
float nx = v.
x * c - v.
y * s;
float ny = v.
x * s + v.
y * c;
return (SimdVec4){.v = simd_set(nx, ny, v.z, v.w)};
}
static inline bool vec3_equals(
Vec3 a,
Vec3 b,
float epsilon) {
SimdVec3 sa = vec3_load(a);
SimdVec3 sb = vec3_load(b);
return simd_equals_eps(sa.v, sb.v, epsilon);
}
static inline bool vec4_equals(
Vec4 a,
Vec4 b,
float epsilon) {
SimdVec4 sa = vec4_load(a);
SimdVec4 sb = vec4_load(b);
return simd_equals_eps(sa.v, sb.v, epsilon);
}
static inline float vec4_distance_sq(SimdVec4 a, SimdVec4 b) { return vec4_length_sq(vec4_sub(b, a)); }
static inline float vec4_distance(SimdVec4 a, SimdVec4 b) { return sqrtf(vec4_distance_sq(a, b)); }
static inline SimdVec4 vec4_lerp(SimdVec4 a, SimdVec4 b, float t) {
SimdVec4 diff = vec4_sub(b, a);
return vec4_add(a, vec4_mul(diff, t));
}
static inline SimdVec4 vec4_project(SimdVec4 a, SimdVec4 b) {
float b_len_sq = vec4_length_sq(b);
if (b_len_sq < 1e-6f) return (SimdVec4){{0}};
float scale = vec4_dot(a, b) / b_len_sq;
return vec4_mul(b, scale);
}
static inline SimdVec4 vec4_reject(SimdVec4 a, SimdVec4 b) { return vec4_sub(a, vec4_project(a, b)); }
static inline SimdVec4 vec4_min(SimdVec4 a, SimdVec4 b) { return (SimdVec4){.v = simd_min(a.v, b.v)}; }
static inline SimdVec4 vec4_max(SimdVec4 a, SimdVec4 b) { return (SimdVec4){.v = simd_max(a.v, b.v)}; }
static inline SimdVec4 vec4_abs(SimdVec4 v) { return (SimdVec4){.v = simd_abs(v.v)}; }
static inline float vec4_sum(SimdVec4 v) { return simd_hadd(v.v); }
#ifdef __cplusplus
}
#endif
#endif
Portable Single Instruction Multiple Data (SIMD) Intrinsics Wrapper.
2D vector storage type (8 bytes, unaligned).
3D vector storage type (12 bytes, unaligned).
4D vector storage type (16 bytes, naturally aligned).
float w
W component (also used for homogeneous coordinates)