diff --git a/Makefile.am b/Makefile.am index f6b3073..4a022fb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,7 +8,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = -Wall \ - -std=gnu99 \ + -std=gnu11 \ -O3 \ -Wstrict-aliasing=2 \ -fstrict-aliasing \ @@ -21,7 +21,8 @@ libcglm_la_LDFLAGS = -no-undefined -version-info 0:1:0 checkLDFLAGS = -L./.libs \ -lm \ -lcglm -checkCFLAGS = -I./include +checkCFLAGS = $(AM_CFLAGS) \ + -I./include check_PROGRAMS = test/tests TESTS = $(check_PROGRAMS) @@ -150,7 +151,8 @@ test_tests_SOURCES=\ test/src/test_vec3.c \ test/src/test_mat3.c \ test/src/test_affine.c \ - test/src/test_bezier.c + test/src/test_bezier.c \ + test/src/test_struct.c pkgconfig_DATA=cglm.pc diff --git a/README.md b/README.md index c8a5f53..5243140 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,21 @@ glm_mul(T, R, modelMat); glm_inv_tr(modelMat); ``` +### Struct API + +The struct API works as follows, note the `s` suffix on types, the `glms_` prefix on functions and the `GLMS_` prefix on constants: + +```C +#include + +mat4s mat = GLMS_MAT4_IDENTITY_INIT; +mat4s inv = glms_mat4_inv(mat); +``` + +Struct functions generally take their parameters as *values* and *return* their results, rather than taking pointers and writing to out parameters. That means your parameters can usually be `const`, if you're into that. + +The types used are actually unions that allow access to the same data multiple ways. One of those ways involves anonymous structures, available since C11. MSVC also supports it for earlier C versions out of the box and GCC/Clang do if you enable `-fms-extensions`. To explicitly enable these anonymous structures, `#define CGLM_USE_ANONYMOUS_STRUCT` to `1`, to disable them, to `0`. For backward compatibility, you can also `#define CGLM_NO_ANONYMOUS_STRUCT` (value is irrelevant) to disable them. If you don't specify explicitly, cglm will do a best guess based on your compiler and the C version you're using. + ## Build ### Unix (Autotools) diff --git a/configure.ac b/configure.ac index 45dc219..473a396 100644 --- a/configure.ac +++ b/configure.ac @@ -10,6 +10,9 @@ AC_PREREQ([2.69]) AC_INIT([cglm], [0.6.1], [info@recp.me]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects serial-tests]) +# Don't use the default cflags (-O2 -g), we set ours manually in Makefile.am. +: ${CFLAGS=""} + AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADERS([config.h]) diff --git a/include/cglm/struct/mat3.h b/include/cglm/struct/mat3.h index da53989..53a7273 100644 --- a/include/cglm/struct/mat3.h +++ b/include/cglm/struct/mat3.h @@ -38,12 +38,8 @@ #include "../mat3.h" #include "vec3.h" -#define GLMS_MAT3_IDENTITY_INIT {1.0f, 0.0f, 0.0f, \ - 0.0f, 1.0f, 0.0f, \ - 0.0f, 0.0f, 1.0f} -#define GLMS_MAT3_ZERO_INIT {0.0f, 0.0f, 0.0f, \ - 0.0f, 0.0f, 0.0f, \ - 0.0f, 0.0f, 0.0f} +#define GLMS_MAT3_IDENTITY_INIT {GLM_MAT3_IDENTITY_INIT} +#define GLMS_MAT3_ZERO_INIT {GLM_MAT3_ZERO_INIT} /* for C only */ #define GLMS_MAT3_IDENTITY ((mat3s)GLMS_MAT3_IDENTITY_INIT) diff --git a/include/cglm/struct/mat4.h b/include/cglm/struct/mat4.h index 14fa614..28f80a3 100644 --- a/include/cglm/struct/mat4.h +++ b/include/cglm/struct/mat4.h @@ -53,15 +53,8 @@ #include "vec4.h" #include "vec3.h" -#define GLMS_MAT4_IDENTITY_INIT {1.0f, 0.0f, 0.0f, 0.0f, \ - 0.0f, 1.0f, 0.0f, 0.0f, \ - 0.0f, 0.0f, 1.0f, 0.0f, \ - 0.0f, 0.0f, 0.0f, 1.0f} - -#define GLMS_MAT4_ZERO_INIT {0.0f, 0.0f, 0.0f, 0.0f, \ - 0.0f, 0.0f, 0.0f, 0.0f, \ - 0.0f, 0.0f, 0.0f, 0.0f, \ - 0.0f, 0.0f, 0.0f, 0.0f} +#define GLMS_MAT4_IDENTITY_INIT {GLM_MAT4_IDENTITY_INIT} +#define GLMS_MAT4_ZERO_INIT {GLM_MAT4_ZERO_INIT} /* for C only */ #define GLMS_MAT4_IDENTITY ((mat4s)GLMS_MAT4_IDENTITY_INIT) diff --git a/include/cglm/struct/quat.h b/include/cglm/struct/quat.h index 9807632..2938478 100644 --- a/include/cglm/struct/quat.h +++ b/include/cglm/struct/quat.h @@ -62,7 +62,7 @@ * ---------------------------------------------------------------------------- */ -#define GLMS_QUAT_IDENTITY_INIT GLM_QUAT_IDENTITY_INIT +#define GLMS_QUAT_IDENTITY_INIT {GLM_QUAT_IDENTITY_INIT} #define GLMS_QUAT_IDENTITY ((versors)GLMS_QUAT_IDENTITY_INIT) /*! diff --git a/include/cglm/struct/vec3.h b/include/cglm/struct/vec3.h index 3fbec1b..7fa5b06 100644 --- a/include/cglm/struct/vec3.h +++ b/include/cglm/struct/vec3.h @@ -86,15 +86,15 @@ #include "../vec3.h" #include "vec3-ext.h" -#define GLMS_VEC3_ONE_INIT {1.0f, 1.0f, 1.0f} -#define GLMS_VEC3_ZERO_INIT {0.0f, 0.0f, 0.0f} +#define GLMS_VEC3_ONE_INIT {GLM_VEC3_ONE_INIT} +#define GLMS_VEC3_ZERO_INIT {GLM_VEC3_ZERO_INIT} #define GLMS_VEC3_ONE ((vec3s)GLMS_VEC3_ONE_INIT) #define GLMS_VEC3_ZERO ((vec3s)GLMS_VEC3_ZERO_INIT) -#define GLMS_YUP ((vec3s){0.0f, 1.0f, 0.0f}) -#define GLMS_ZUP ((vec3s){0.0f, 0.0f, 1.0f}) -#define GLMS_XUP ((vec3s){1.0f, 0.0f, 0.0f}) +#define GLMS_YUP ((vec3s){{0.0f, 1.0f, 0.0f}}) +#define GLMS_ZUP ((vec3s){{0.0f, 0.0f, 1.0f}}) +#define GLMS_XUP ((vec3s){{1.0f, 0.0f, 0.0f}}) /*! * @brief init vec3 using vec4 diff --git a/include/cglm/struct/vec4.h b/include/cglm/struct/vec4.h index 7bccf67..4469cb2 100644 --- a/include/cglm/struct/vec4.h +++ b/include/cglm/struct/vec4.h @@ -7,12 +7,12 @@ /* Macros: - GLM_VEC4_ONE_INIT - GLM_VEC4_BLACK_INIT - GLM_VEC4_ZERO_INIT - GLM_VEC4_ONE - GLM_VEC4_BLACK - GLM_VEC4_ZERO + GLMS_VEC4_ONE_INIT + GLMS_VEC4_BLACK_INIT + GLMS_VEC4_ZERO_INIT + GLMS_VEC4_ONE + GLMS_VEC4_BLACK + GLMS_VEC4_ZERO Functions: CGLM_INLINE vec4s glms_vec4(vec3s v3, float last); @@ -72,9 +72,9 @@ #include "../vec4.h" #include "vec4-ext.h" -#define GLMS_VEC4_ONE_INIT {1.0f, 1.0f, 1.0f, 1.0f} -#define GLMS_VEC4_BLACK_INIT {0.0f, 0.0f, 0.0f, 1.0f} -#define GLMS_VEC4_ZERO_INIT {0.0f, 0.0f, 0.0f, 0.0f} +#define GLMS_VEC4_ONE_INIT {GLM_VEC4_ONE_INIT} +#define GLMS_VEC4_BLACK_INIT {GLM_VEC4_BLACK_INIT} +#define GLMS_VEC4_ZERO_INIT {GLM_VEC4_ZERO_INIT} #define GLMS_VEC4_ONE ((vec4s)GLM_VEC4_ONE_INIT) #define GLMS_VEC4_BLACK ((vec4s)GLM_VEC4_BLACK_INIT) diff --git a/include/cglm/types-struct.h b/include/cglm/types-struct.h index f064a43..cfb7f76 100644 --- a/include/cglm/types-struct.h +++ b/include/cglm/types-struct.h @@ -10,40 +10,67 @@ #include "types.h" +/* + * Anonymous structs are available since C11, but we'd like to be compatible + * with C99 and C89 too. So let's figure out if we should be using them or not. + * It's simply a convenience feature, you can e.g. build the library with + * anonymous structs and your application without them and they'll still be + * compatible, cglm doesn't use the anonymous structs internally. + */ +#ifndef CGLM_USE_ANONYMOUS_STRUCT + /* If the user doesn't explicitly specify if they want anonymous structs or + * not, then we'll try to intuit an appropriate choice. */ +# if defined(CGLM_NO_ANONYMOUS_STRUCT) + /* The user has defined CGLM_NO_ANONYMOUS_STRUCT. This used to be the + * only #define governing the use of anonymous structs, so for backward + * compatibility, we still honor that choice and disable them. */ +# define CGLM_USE_ANONYMOUS_STRUCT 0 +# elif __STDC_VERSION__ >= 20112L || defined(_MSVC_VER) + /* We're compiling for C11 or this is the MSVC compiler. In either + * case, anonymous structs are available, so use them. */ +# define CGLM_USE_ANONYMOUS_STRUCT 1 +# else + /* Otherwise, we're presumably building for C99 or C89 and can't rely + * on anonymous structs being available. Turn them off. */ +# define CGLM_USE_ANONYMOUS_STRUCT 0 +# endif +#endif + typedef union vec2s { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + vec2 raw; +#if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; }; #endif - vec2 raw; } vec2s; typedef union vec3s { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + vec3 raw; +#if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; float z; }; #endif - vec3 raw; } vec3s; typedef union ivec3s { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + ivec3 raw; +#if CGLM_USE_ANONYMOUS_STRUCT struct { int x; int y; int z; }; #endif - ivec3 raw; } ivec3s; typedef union CGLM_ALIGN_IF(16) vec4s { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + vec4 raw; +#if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; @@ -51,11 +78,11 @@ typedef union CGLM_ALIGN_IF(16) vec4s { float w; }; #endif - vec4 raw; } vec4s; typedef union CGLM_ALIGN_IF(16) versors { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + vec4 raw; +#if CGLM_USE_ANONYMOUS_STRUCT struct { float x; float y; @@ -68,23 +95,24 @@ typedef union CGLM_ALIGN_IF(16) versors { float real; }; #endif - vec4 raw; } versors; typedef union mat3s { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + mat3 raw; + vec3s col[3]; +#if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02; float m10, m11, m12; float m20, m21, m22; }; #endif - vec3s col[3]; - mat3 raw; } mat3s; typedef union CGLM_ALIGN_MAT mat4s { -#ifndef CGLM_NO_ANONYMOUS_STRUCT + mat4 raw; + vec4s col[4]; +#if CGLM_USE_ANONYMOUS_STRUCT struct { float m00, m01, m02, m03; float m10, m11, m12, m13; @@ -92,8 +120,6 @@ typedef union CGLM_ALIGN_MAT mat4s { float m30, m31, m32, m33; }; #endif - vec4s col[4]; - mat4 raw; } mat4s; #endif /* cglm_types_struct_h */ diff --git a/test/src/test_struct.c b/test/src/test_struct.c new file mode 100644 index 0000000..3423ace --- /dev/null +++ b/test/src/test_struct.c @@ -0,0 +1,71 @@ +#include "test_common.h" + +TEST_IMPL(mat3s_identity_init) { + mat3s mat3_identity = GLMS_MAT3_IDENTITY_INIT; + mat3 mat3_identity_a = GLM_MAT3_IDENTITY_INIT; + test_assert_mat3_eq(mat3_identity.raw, mat3_identity_a); + TEST_SUCCESS +} + +TEST_IMPL(mat3s_zero_init) { + mat3s mat3_zero = GLMS_MAT3_ZERO_INIT; + mat3 mat3_zero_a = GLM_MAT3_ZERO_INIT; + test_assert_mat3_eq(mat3_zero.raw, mat3_zero_a); + TEST_SUCCESS +} + +TEST_IMPL(mat4s_identity_init) { + mat4s mat4_identity = GLMS_MAT4_IDENTITY_INIT; + mat4 mat4_identity_a = GLM_MAT4_IDENTITY_INIT; + test_assert_mat4_eq(mat4_identity.raw, mat4_identity_a); + TEST_SUCCESS +} + +TEST_IMPL(mat4s_zero_init) { + mat4s mat4_zero = GLMS_MAT4_ZERO_INIT; + mat4 mat4_zero_a = GLM_MAT4_ZERO_INIT; + test_assert_mat4_eq(mat4_zero.raw, mat4_zero_a); + TEST_SUCCESS +} + +TEST_IMPL(quats_zero_init) { + versors quat_zero = GLMS_QUAT_IDENTITY_INIT; + versor quat_zero_a = GLM_QUAT_IDENTITY_INIT; + test_assert_quat_eq(quat_zero.raw, quat_zero_a); + TEST_SUCCESS +} + +TEST_IMPL(vec3s_one_init) { + vec3s vec3_one = GLMS_VEC3_ONE_INIT; + vec3 vec3_one_a = GLM_VEC3_ONE_INIT; + test_assert_vec3_eq(vec3_one.raw, vec3_one_a); + TEST_SUCCESS +} + +TEST_IMPL(vec3s_zero_init) { + vec3s vec3_zero = GLMS_VEC3_ZERO_INIT; + vec3 vec3_zero_a = GLM_VEC3_ZERO_INIT; + test_assert_vec3_eq(vec3_zero.raw, vec3_zero_a); + TEST_SUCCESS +} + +TEST_IMPL(vec4s_black_init) { + vec4s vec4_black = GLMS_VEC4_BLACK_INIT; + vec4 vec4_black_a = GLM_VEC4_BLACK_INIT; + test_assert_vec4_eq(vec4_black.raw, vec4_black_a); + TEST_SUCCESS +} + +TEST_IMPL(vec4s_one_init) { + vec4s vec4_one = GLMS_VEC4_ONE_INIT; + vec4 vec4_one_a = GLM_VEC4_ONE_INIT; + test_assert_vec4_eq(vec4_one.raw, vec4_one_a); + TEST_SUCCESS +} + +TEST_IMPL(vec4s_zero_init) { + vec4s vec4_zero = GLMS_VEC4_ZERO_INIT; + vec4 vec4_zero_a = GLM_VEC4_ZERO_INIT; + test_assert_vec4_eq(vec4_zero.raw, vec4_zero_a); + TEST_SUCCESS +} diff --git a/test/tests.h b/test/tests.h index 2193b84..3ace6bf 100644 --- a/test/tests.h +++ b/test/tests.h @@ -504,6 +504,19 @@ TEST_DECLARE(glmc_vec4_fract) TEST_DECLARE(glmc_vec4_hadd) TEST_DECLARE(glmc_vec4_sqrt) +/* structs */ + +TEST_DECLARE(mat3s_identity_init) +TEST_DECLARE(mat3s_zero_init) +TEST_DECLARE(mat4s_identity_init) +TEST_DECLARE(mat4s_zero_init) +TEST_DECLARE(quats_zero_init) +TEST_DECLARE(vec3s_one_init) +TEST_DECLARE(vec3s_zero_init) +TEST_DECLARE(vec4s_black_init) +TEST_DECLARE(vec4s_one_init) +TEST_DECLARE(vec4s_zero_init) + /*****************************************************************************/ TEST_LIST { @@ -996,6 +1009,18 @@ TEST_LIST { TEST_ENTRY(glmc_vec4_fract) TEST_ENTRY(glmc_vec4_hadd) TEST_ENTRY(glmc_vec4_sqrt) + + /* structs */ + TEST_ENTRY(mat3s_identity_init) + TEST_ENTRY(mat3s_zero_init) + TEST_ENTRY(mat4s_identity_init) + TEST_ENTRY(mat4s_zero_init) + TEST_ENTRY(quats_zero_init) + TEST_ENTRY(vec3s_one_init) + TEST_ENTRY(vec3s_zero_init) + TEST_ENTRY(vec4s_black_init) + TEST_ENTRY(vec4s_one_init) + TEST_ENTRY(vec4s_zero_init) }; #endif /* tests_h */