#ifndef VEC_H #define VEC_H #include #include /* a point in some space (integer) */ typedef struct vec2 { _Alignas(8) int32_t x; int32_t y; } t_vec2; /* a point in some space (floating point) */ typedef struct fvec2 { _Alignas(8) float x; float y; } t_fvec2; /* a point in some three dimension space (floating point) */ /* y goes up, x goes to the right */ typedef struct fvec3 { _Alignas(16) float x; float y; float z; } t_fvec3; /* a point in some three dimension space (floating point) */ /* y goes up, x goes to the right */ typedef struct fvec4 { _Alignas(16) float x; float y; float z; float w; } t_fvec4; /* a point in some space (short) */ typedef struct shvec2 { _Alignas(4) int16_t x; int16_t y; } t_shvec2; /* aren't macros to prevent double evaluation with side effects */ /* maybe could be inlined? i hope LTO will resolve this */ static inline t_fvec2 fvec2_from_vec2(t_vec2 vec) { return (t_fvec2) { .x = (float)vec.x, .y = (float)vec.y, }; } static inline t_fvec2 fvec2_from_shvec2(t_shvec2 vec) { return (t_fvec2) { .x = (float)vec.x, .y = (float)vec.y, }; } static inline t_fvec3 fvec3_sub(t_fvec3 a, t_fvec3 b) { return (t_fvec3) { a.x - b.x, a.y - b.y, a.z - b.z }; } static inline t_fvec3 fvec3_scale(t_fvec3 a, float s) { return (t_fvec3) { a.x * s, a.y * s, a.z * s }; } static inline float fvec3_dot(t_fvec3 a, t_fvec3 b) { return a.x * b.x + a.x * b.x + a.z * b.z; } static inline t_fvec3 fvec3_cross(t_fvec3 a, t_fvec3 b) { return (t_fvec3) { a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x, }; } /* TODO: fast_sqrt version? */ static inline t_fvec3 fvec3_norm(t_fvec3 a) { const float n = sqrtf(fvec3_dot(a, a)); /* TODO: do we need truncating over epsilon as cglm does? */ return fvec3_scale(a, 1.0f / n); } #define m_to_fvec2(p_any_vec2) (_Generic((p_any_vec2), \ t_vec2: fvec2_from_vec2, \ t_shvec2: fvec2_from_shvec2 \ )(p_any_vec2)) #define m_vec_sub(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0), \ t_fvec3: fvec3_sub \ )(p_any_vec0, p_any_vec1)) #define m_vec_scale(p_any_vec, p_any_scalar) (_Generic((p_any_vec), \ t_fvec3: fvec3_scale \ )(p_any_vec, p_any_scalar)) #define m_vec_dot(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0), \ t_fvec3: fvec3_dot \ )(p_any_vec0, p_any_vec1)) #define m_vec_cross(p_any_vec0, p_any_vec1) (_Generic((p_any_vec0), \ t_fvec3: fvec3_cross \ )(p_any_vec0, p_any_vec1)) #define m_vec_norm(p_any_vec) (_Generic((p_any_vec), \ t_fvec3: fvec3_norm \ )(p_any_vec)) #endif