diff --git a/include/cglm/common.h b/include/cglm/common.h index c7c5eb8..83d54be 100644 --- a/include/cglm/common.h +++ b/include/cglm/common.h @@ -28,6 +28,9 @@ # define CGLM_INLINE static inline __attribute((always_inline)) #endif +#define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) +#define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x)) + #include "types.h" #include "simd/intrin.h" diff --git a/include/cglm/struct/vec3.h b/include/cglm/struct/vec3.h index fbe716d..4e8d677 100644 --- a/include/cglm/struct/vec3.h +++ b/include/cglm/struct/vec3.h @@ -58,6 +58,7 @@ CGLM_INLINE vec3s glms_vec3_ortho(vec3s v); CGLM_INLINE vec3s glms_vec3_clamp(vec3s v, float minVal, float maxVal); CGLM_INLINE vec3s glms_vec3_lerp(vec3s from, vec3s to, float t); + CGLM_INLINE vec3s glms_vec3_swizzle(vec3s v, int mask); Convenient: CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b); @@ -747,4 +748,21 @@ glms_normalize(vec3s v) { return v; } +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXX, GLM_ZYX + * + * @param[in] v source + * @param[in] mask mask + * @returns swizzled vector + */ +CGLM_INLINE +vec3s +glms_vec3_swizzle(vec3s v, int mask) { + vec3s dest; + glm_vec3_swizzle(v.raw, mask, dest.raw); + return dest; +} + #endif /* cglms_vec3s_h */ diff --git a/include/cglm/struct/vec4.h b/include/cglm/struct/vec4.h index 4fe75ba..0b403a9 100644 --- a/include/cglm/struct/vec4.h +++ b/include/cglm/struct/vec4.h @@ -48,6 +48,7 @@ CGLM_INLINE vec4s glms_vec4_clamp(vec4s v, float minVal, float maxVal); CGLM_INLINE vec4s glms_vec4_lerp(vec4s from, vec4s to, float t); CGLM_INLINE vec4s glms_vec4_cubic(float s); + CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask); */ #ifndef cglms_vec4s_h @@ -577,4 +578,21 @@ glms_vec4_cubic(float s) { return r; } +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXXX, GLM_WZYX + * + * @param[in] v source + * @param[in] mask mask + * @returns swizzled vector + */ +CGLM_INLINE +vec4s +glms_vec4_swizzle(vec4s v, int mask) { + vec4s dest; + glm_vec4_swizzle(v.raw, mask, dest.raw); + return dest; +} + #endif /* cglms_vec4s_h */ diff --git a/include/cglm/vec3.h b/include/cglm/vec3.h index e67cc2f..323618a 100644 --- a/include/cglm/vec3.h +++ b/include/cglm/vec3.h @@ -61,6 +61,7 @@ CGLM_INLINE void glm_vec3_ortho(vec3 v, vec3 dest); CGLM_INLINE void glm_vec3_clamp(vec3 v, float minVal, float maxVal); CGLM_INLINE void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); + CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest); Convenient: CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d); @@ -103,6 +104,11 @@ #define GLM_ZUP ((vec3){0.0f, 0.0f, 1.0f}) #define GLM_XUP ((vec3){1.0f, 0.0f, 0.0f}) +#define GLM_XXX GLM_SHUFFLE3(0, 0, 0) +#define GLM_YYY GLM_SHUFFLE3(1, 1, 1) +#define GLM_ZZZ GLM_SHUFFLE3(2, 2, 2) +#define GLM_ZYX GLM_SHUFFLE3(0, 1, 2) + /*! * @brief init vec3 using vec4 * @@ -845,4 +851,25 @@ glm_normalize_to(vec3 v, vec3 dest) { glm_vec3_normalize_to(v, dest); } +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXX, GLM_ZYX + * + * @param[in] v source + * @param[in] mask mask + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec3_swizzle(vec3 v, int mask, vec3 dest) { + vec3 t; + + t[0] = v[(mask & (3 << 0))]; + t[1] = v[(mask & (3 << 2)) >> 2]; + t[2] = v[(mask & (3 << 4)) >> 4]; + + glm_vec3_copy(t, dest); +} + #endif /* cglm_vec3_h */ diff --git a/include/cglm/vec4.h b/include/cglm/vec4.h index d053ed5..abfe22b 100644 --- a/include/cglm/vec4.h +++ b/include/cglm/vec4.h @@ -47,6 +47,7 @@ CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest); CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal); CGLM_INLINE void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) + CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest); DEPRECATED: glm_vec4_dup @@ -81,6 +82,12 @@ #define GLM_VEC4_BLACK ((vec4)GLM_VEC4_BLACK_INIT) #define GLM_VEC4_ZERO ((vec4)GLM_VEC4_ZERO_INIT) +#define GLM_XXXX GLM_SHUFFLE4(0, 0, 0, 0) +#define GLM_YYYY GLM_SHUFFLE4(1, 1, 1, 1) +#define GLM_ZZZZ GLM_SHUFFLE4(2, 2, 2, 2) +#define GLM_WWWW GLM_SHUFFLE4(3, 3, 3, 3) +#define GLM_WZYX GLM_SHUFFLE4(0, 1, 2, 3) + /*! * @brief init vec4 using vec3 * @@ -810,4 +817,26 @@ glm_vec4_cubic(float s, vec4 dest) { dest[3] = 1.0f; } +/*! + * @brief swizzle vector components + * + * you can use existin masks e.g. GLM_XXXX, GLM_WZYX + * + * @param[in] v source + * @param[in] mask mask + * @param[out] dest destination + */ +CGLM_INLINE +void +glm_vec4_swizzle(vec4 v, int mask, vec4 dest) { + vec4 t; + + t[0] = v[(mask & (3 << 0))]; + t[1] = v[(mask & (3 << 2)) >> 2]; + t[2] = v[(mask & (3 << 4)) >> 4]; + t[3] = v[(mask & (3 << 6)) >> 6]; + + glm_vec4_copy(t, dest); +} + #endif /* cglm_vec4_h */ diff --git a/test/src/test_vec3.c b/test/src/test_vec3.c index 4f1f2d1..19af4aa 100644 --- a/test/src/test_vec3.c +++ b/test/src/test_vec3.c @@ -84,4 +84,30 @@ test_vec3(void **state) { vs3 = glms_vec3_add(vs1, vs2); vs4 = glms_vec3_maxv(vs1, vs3); test_assert_vec3s_eq(vs3, vs4); + + /* swizzle */ + + /* ZYX */ + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + glm_vec3_swizzle(v1, GLM_ZYX, v1); + test_assert_vec3_eq(v1, (vec3){3, 2, 1}); + + glm_vec3_swizzle(v1, GLM_XXX, v1); + test_assert_vec3_eq(v1, (vec3){3, 3, 3}); + + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + + glm_vec3_swizzle(v1, GLM_YYY, v1); + test_assert_vec3_eq(v1, (vec3){2, 2, 2}); + + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + + glm_vec3_swizzle(v1, GLM_ZZZ, v1); + test_assert_vec3_eq(v1, (vec3){3, 3, 3}); } diff --git a/test/src/test_vec4.c b/test/src/test_vec4.c index 02137b0..2e9d12e 100644 --- a/test/src/test_vec4.c +++ b/test/src/test_vec4.c @@ -183,6 +183,44 @@ test_vec4(void **state) { assert_true(v3[2] >= 0.0999 && v3[2] <= 0.80001); assert_true(v3[3] >= 0.0999 && v3[3] <= 0.80001); + /* swizzle */ + + /* ZYX */ + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + v1[3] = 4; + + glm_vec4_swizzle(v1, GLM_WZYX, v1); + test_assert_vec4_eq(v1, (vec4){4, 3, 2, 1}); + + glm_vec4_swizzle(v1, GLM_XXXX, v1); + test_assert_vec4_eq(v1, (vec4){4, 4, 4, 4}); + + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + v1[3] = 4; + + glm_vec4_swizzle(v1, GLM_YYYY, v1); + test_assert_vec4_eq(v1, (vec4){2, 2, 2, 2}); + + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + v1[3] = 4; + + glm_vec4_swizzle(v1, GLM_ZZZZ, v1); + test_assert_vec4_eq(v1, (vec4){3, 3, 3, 3}); + + v1[0] = 1; + v1[1] = 2; + v1[2] = 3; + v1[3] = 4; + + glm_vec4_swizzle(v1, GLM_WWWW, v1); + test_assert_vec4_eq(v1, (vec4){4, 4, 4, 4}); + /* structs */ vs1 = test_rand_vec4s(); vs2 = test_rand_vec4s();