š½ Highly Optimized 2D / 3D Graphics Math (glm) for C
C
Highly optimized 2D|3D math library, also known as OpenGL Mathematics (glm) for `C`. cglm provides lot of utils to help math operations to be fast and quick to write. It is community friendly, feel free to bring any issues, bugs you faced.
Almost all functions (inline versions) and parameters are documented inside the corresponding headers.
Complete documentation: http://cglm.readthedocs.io
glm_vec_dup -> glm_vec3_copy
CGLM_FORCE_DEPTH_ZERO_TO_ONE
and CGLM_FORCE_LEFT_HANDED
is provided to control clipspace. You should be able to use cglm with Vulkan, DirectX and Metal nowā¦ see https://cglm.readthedocs.io/en/latest/opt.html#clipspace-option-sIf you are not aware of the original GLM library yet, you may also want to look at:
https://github.com/g-truc/glm
vec4
and mat4
variables must be aligned. (There will be unaligned versions later)cglm
doesnāt alloc any memory on heap. So it doesnāt provide any allocator. You should alloc memory for out parameters too if you pass pointer of memory location. Donāt forget that vec4 (also quat/versor) and mat4 must be aligned (16-bytes), because cglm uses SIMD instructions to optimize most operations if available.
cglm supports both ARRAY API and STRUCT API, so you can return structs if you utilize struct api (glms_
).
Like some other graphics libraries (especially OpenGL) this library use Column-Major layout to keep matrices in the memory.
In the future the library may support an option to use row-major layout, CURRENTLY if you need to row-major layout you will need to transpose it.
|
You have two options to call a function/operation: inline or library call (link)
Almost all functions are marked inline (always_inline) so compiler will probably inline.
To call pre-compiled versions, just use glmc_
(c stands for ācallā) instead of glm_
.
#include <cglm/cglm.h> /* for inline */
#include <cglm/call.h> /* for library call (this also includes cglm.h) */
mat4 rot, trans, rt;
/* ... */
glm_mul(trans, rot, rt); /* inline */
glmc_mul(trans, rot, rt); /* call from library */
Most of math functions are optimized manually with SSE2 if available, if not? Dont worry there are non-sse versions of all operations
You can pass matrices and vectors as array to functions rather than get address.
mat4 m = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
glm_translate(m, (vec3){1.0f, 0.0f, 0.0f});
Library contains general purpose mat4 mul and inverse functions, and also contains some special forms (optimized) of these functions for affine transformationsā matrices. If you want to multiply two affine transformation matrices you can use glm_mul instead of glm_mat4_mul and glm_inv_tr (ROT + TR) instead glm_mat4_inv
/* multiplication */
mat4 modelMat;
glm_mul(T, R, modelMat);
/* othonormal rot + tr matrix inverse (rigid-body) */
glm_inv_tr(modelMat);
The struct API works as follows, note the s
suffix on types, the glms_
prefix on functions and the GLMS_
prefix on constants:
#include <cglm/struct.h>
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.
$ mkdir build
$ cd build
$ cmake .. # [Optional] -DCGLM_SHARED=ON
$ make
$ sudo make install # [Optional]
option(CGLM_SHARED "Shared build" ON)
option(CGLM_STATIC "Static build" OFF)
option(CGLM_USE_C99 "" OFF) #Ā C11
option(CGLM_USE_TEST "Enable Tests" OFF) #Ā for make check - make test
This requires no building or installation of cglm.
cmake_minimum_required(VERSION 3.8.2)
project(<Your Project Name>)
add_executable(${PROJECT_NAME} src/main.c)
target_link_libraries(${LIBRARY_NAME} PRIVATE
cglm_headers)
add_subdirectory(external/cglm/ EXCLUDE_FROM_ALL)
cmake_minimum_required(VERSION 3.8.2)
project(<Your Project Name>)
add_executable(${PROJECT_NAME} src/main.c)
target_link_libraries(${LIBRARY_NAME} PRIVATE
cglm)
add_subdirectory(external/cglm/)
# or you can use find_package to configure cglm
Since math functions like sinf
is used, this can not be targeted at wasm32-unknown-unknown
, one of wasi-sdk or emscripten should be used.
Should note that shared build is not yet supported for WebAssembly.
For simd128 support, add -msimd128
to CMAKE_C_FLAGS
, in command line -DCMAKE_C_FLAGS="-msimd128"
.
For tests, the cmake option CGLM_USE_TEST
would still work, youāll need a wasi runtime for running tests, see our ci config file for a detailed example.
$ cmake .. \
-DCMAKE_TOOLCHAIN_FILE=/path/to/wasi-sdk-19.0/share/cmake/wasi-sdk.cmake \
-DWASI_SDK_PREFIX=/path/to/wasi-sdk-19.0
Where /path/to/wasi-sdk-19.0/
is the path to extracted wasi sdk.
In this case it would by default make a static build.
$ emcmake cmake .. \
-DCMAKE_EXE_LINKER_FLAGS="-s STANDALONE_WASM" \
-DCGLM_STATIC=ON
The emcmake
here is the cmake wrapper for Emscripten from installed emsdk.
$ meson build # [Optional] --default-library=static
$ cd build
$ ninja
$ sudo ninja install # [Optional]
c_std=c11
buildtype=release
default_library=shared
build_tests=true #Ā to run tests: ninja test
# Clone cglm or create a cglm.wrap under <source_root>/subprojects
project('name', 'c')
cglm_dep = dependency('cglm', fallback : 'cglm', 'cglm_dep')
executable('exe', 'src/main.c', dependencies : cglm_dep)
Currently only default build options are supported. Add cglm dependency to your project:
...
Package(
...
dependencies: [
...
.package(url: "https://github.com/recp/cglm", .branch("master")),
]
...
)
Now add cgml as a dependency to your target. Product choices are:
...
.target(
...
dependencies: [
...
.product(name: "cglm", package: "cglm"),
]
...
)
...
$ sh autogen.sh
$ ./configure
$ make
$ make check # [Optional]
$ [sudo] make install # [Optional]
This will also install pkg-config files so you can use
pkg-config --cflags cglm
and pkg-config --libs cglm
to retrieve compiler
and linker flags.
The files will be installed into the given prefix (usually /usr/local
by
default on Linux), but your pkg-config may not be configured to actually check
there. You can figure out where itās looking by running pkg-config --variable pc_path pkg-config
and change the path the files are installed to via
./configure --with-pkgconfigdir=/your/path
. Alternatively, you can add the
prefix path to your PKG_CONFIG_PATH
environment variable.
Windows related build file and project files are located in win
folder,
make sure you are inside cglm/win
folder.
Code Analysis is enabled, so it may take awhile to build.
$ cd win
$ .\build.bat
if msbuild
wonāt work (because of multi version VS) then try to build with devenv
:
$ devenv cglm.sln /Build Release
You can see test project in same visual studio solution file. It is enough to run that project to run tests.
First you need install Sphinx: http://www.sphinx-doc.org/en/master/usage/installation.html
then:
$ cd docs
$ sphinx-build source build
it will compile docs into build folder, you can run index.html inside that function.
If you want to use the inline versions of functions, then include the main header
#include <cglm/cglm.h>
the header will include all headers. Then call the func you want e.g. rotate vector by axis:
glm_vec3_rotate(v1, glm_rad(45), (vec3){1.0f, 0.0f, 0.0f});
some functions are overloaded š e.g you can normalize vector:
glm_vec3_normalize(vec);
this will normalize vec and store normalized vector into vec
but if you will store normalized vector into another vector do this:
glm_vec3_normalize_to(vec, result);
like this function you may see _to
postfix, this functions store results to another variables and save temp memory
to call pre-compiled versions include header with c
postfix, c means call. Pre-compiled versions are just wrappers.
#include <cglm/call.h>
this header will include all headers with c postfix. You need to call functions with c posfix:
glmc_vec3_normalize(vec);
Function usage and parameters are documented inside related headers. You may see same parameter passed twice in some examples like this:
glm_mat4_mul(m1, m2, m1);
/* or */
glm_mat4_mul(m1, m1, m1);
the first two parameter are [in] and the last one is [out] parameter. After multiplying m1 and m2, the result is stored in m1. This is why we send m1 twice. You may store the result in a different matrix, this is just an example.
mat4 proj, view, model, mvp;
/* init proj, view and model ... */
glm_mat4_mul(proj, view, viewProj);
glm_mat4_mul(viewProj, model, mvp);
mat4 proj, view, model, mvp;
/* init proj, view and model ... */
glm_mat4_mulN((mat4 *[]){&proj, &view, &model}, 3, mvp);
mat4 is array of vec4 and vec4 is array of floats. glUniformMatrix4fv
functions accecpts float*
as value
(last param), so you can cast mat4 to float* or you can pass first column of matrix as beginning of memory of matrix:
Option 1: Send first column
glUniformMatrix4fv(location, 1, GL_FALSE, matrix[0]);
/* array of matrices */
glUniformMatrix4fv(location, 1, GL_FALSE, matrix[0][0]);
Option 2: Cast matrix to pointer type (also valid for multiple dimensional arrays)
glUniformMatrix4fv(location, 1, GL_FALSE, (float *)matrix);
You can pass matrices the same way to other APIs e.g. Vulkan, DXā¦
TODO:
glm_umat4_mul
)This project exists thanks to all the people who contribute. [Contribute].
Thank you to all our backers! š [Become a backer]
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]
MIT. check the LICENSE file