diff --git a/include/cglm/call.h b/include/cglm/call.h index c306ab9..00eb13c 100644 --- a/include/cglm/call.h +++ b/include/cglm/call.h @@ -21,6 +21,7 @@ extern "C" { #include "call/quat.h" #include "call/euler.h" #include "call/plane.h" +#include "call/frustum.h" #include "call/io.h" #ifdef __cplusplus diff --git a/include/cglm/call/cam.h b/include/cglm/call/cam.h index dc01f6f..35fb18d 100644 --- a/include/cglm/call/cam.h +++ b/include/cglm/call/cam.h @@ -53,18 +53,6 @@ CGLM_EXPORT void glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest); -CGLM_EXPORT -void -glmc_frustum_planes(mat4 m, vec4 dest[6]); - -CGLM_EXPORT -void -glmc_frustum_corners(mat4 invMat, vec4 dest[8]); - -CGLM_EXPORT -void -glmc_frustum_center(vec4 corners[8], vec4 dest); - #ifdef __cplusplus } #endif diff --git a/include/cglm/call/frustum.h b/include/cglm/call/frustum.h new file mode 100644 index 0000000..066ed40 --- /dev/null +++ b/include/cglm/call/frustum.h @@ -0,0 +1,35 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglmc_frustum_h +#define cglmc_frustum_h +#ifdef __cplusplus +extern "C" { +#endif + +#include "../cglm.h" + +CGLM_EXPORT +void +glmc_frustum_planes(mat4 m, vec4 dest[6]); + +CGLM_EXPORT +void +glmc_frustum_corners(mat4 invMat, vec4 dest[8]); + +CGLM_EXPORT +void +glmc_frustum_center(vec4 corners[8], vec4 dest); + +CGLM_EXPORT +void +glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]); + +#ifdef __cplusplus +} +#endif +#endif /* cglmc_frustum_h */ diff --git a/include/cglm/cam.h b/include/cglm/cam.h index 23504cc..0d13a3d 100644 --- a/include/cglm/cam.h +++ b/include/cglm/cam.h @@ -541,116 +541,4 @@ glm_persp_sizes(mat4 proj, float fovy, vec4 dest) { dest[2] = a * dest[3]; } -/*! - * @brief extracts view frustum planes - * - * planes' space: - * 1- if m = proj: View Space - * 2- if m = viewProj: World Space - * 3- if m = MVP: Object Space - * - * You probably want to extract planes in world space so use viewProj as m - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * - * Exracted planes order: [left, right, bottom, top, near, far] - * - * @param[in] m matrix (see brief) - * @param[out] dest exracted view frustum planes (see brief) - */ -CGLM_INLINE -void -glm_frustum_planes(mat4 m, vec4 dest[6]) { - mat4 t; - - glm_mat4_transpose_to(m, t); - - glm_vec4_add(t[3], t[0], dest[0]); /* left */ - glm_vec4_sub(t[3], t[0], dest[1]); /* right */ - glm_vec4_add(t[3], t[1], dest[2]); /* bottom */ - glm_vec4_sub(t[3], t[1], dest[3]); /* top */ - glm_vec4_add(t[3], t[2], dest[4]); /* near */ - glm_vec4_sub(t[3], t[2], dest[5]); /* far */ - - glm_plane_normalize(dest[0]); - glm_plane_normalize(dest[1]); - glm_plane_normalize(dest[2]); - glm_plane_normalize(dest[3]); - glm_plane_normalize(dest[4]); - glm_plane_normalize(dest[5]); -} - -/*! - * @brief extracts view frustum corners using clip-space coordinates - * - * corners' space: - * 1- if m = invViewProj: World Space - * 2- if m = invMVP: Object Space - * - * You probably want to extract corners in world space so use invViewProj - * Computing invViewProj: - * glm_mat4_mul(proj, view, viewProj); - * ... - * glm_mat4_inv(viewProj, invViewProj); - * - * @param[in] invMat matrix (see brief) - * @param[out] dest exracted view frustum corners (see brief) - */ -CGLM_INLINE -void -glm_frustum_corners(mat4 invMat, vec4 dest[8]) { - vec4 c[8]; - vec4 csCoords[8] = { - {-1.0f, -1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f, 1.0f}, - { 1.0f, -1.0f, -1.0f, 1.0f}, - { 1.0f, 1.0f, -1.0f, 1.0f}, - {-1.0f, -1.0f, 1.0f, 1.0f}, - {-1.0f, 1.0f, 1.0f, 1.0f}, - { 1.0f, -1.0f, 1.0f, 1.0f}, - { 1.0f, 1.0f, 1.0f, 1.0f} - }; - - glm_mat4_mulv(invMat, csCoords[0], c[0]); - glm_mat4_mulv(invMat, csCoords[1], c[1]); - glm_mat4_mulv(invMat, csCoords[2], c[2]); - glm_mat4_mulv(invMat, csCoords[3], c[3]); - glm_mat4_mulv(invMat, csCoords[4], c[4]); - glm_mat4_mulv(invMat, csCoords[5], c[5]); - glm_mat4_mulv(invMat, csCoords[6], c[6]); - glm_mat4_mulv(invMat, csCoords[7], c[7]); - - glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]); - glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]); - glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]); - glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]); - glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]); - glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]); - glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]); -} - -/*! - * @brief finds center of view frustum - * - * @param[in] corners view frustum corners - * @param[out] dest view frustum center - */ -CGLM_INLINE -void -glm_frustum_center(vec4 corners[8], vec4 dest) { - vec4 center; - - glm_vec4_copy(corners[0], center); - - glm_vec4_add(corners[1], center, center); - glm_vec4_add(corners[2], center, center); - glm_vec4_add(corners[3], center, center); - glm_vec4_add(corners[4], center, center); - glm_vec4_add(corners[5], center, center); - glm_vec4_add(corners[6], center, center); - glm_vec4_add(corners[7], center, center); - - glm_vec4_scale(center, 0.125f, dest); -} - #endif /* cglm_vcam_h */ diff --git a/include/cglm/cglm.h b/include/cglm/cglm.h index 24544d1..e9fa774 100644 --- a/include/cglm/cglm.h +++ b/include/cglm/cglm.h @@ -15,6 +15,7 @@ #include "mat3.h" #include "affine.h" #include "cam.h" +#include "frustum.h" #include "quat.h" #include "euler.h" #include "plane.h" diff --git a/include/cglm/frustum.h b/include/cglm/frustum.h new file mode 100644 index 0000000..74a1769 --- /dev/null +++ b/include/cglm/frustum.h @@ -0,0 +1,176 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_frustum_h +#define cglm_frustum_h + +#include "common.h" +#include "plane.h" + +#define GLM_LBN 0 +#define GLM_LTN 1 +#define GLM_RTN 2 +#define GLM_RBN 3 + +#define GLM_LBF 4 +#define GLM_LTF 5 +#define GLM_RTF 6 +#define GLM_RBF 7 + +/*! + * @brief extracts view frustum planes + * + * planes' space: + * 1- if m = proj: View Space + * 2- if m = viewProj: World Space + * 3- if m = MVP: Object Space + * + * You probably want to extract planes in world space so use viewProj as m + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * + * Exracted planes order: [left, right, bottom, top, near, far] + * + * @param[in] m matrix (see brief) + * @param[out] dest exracted view frustum planes (see brief) + */ +CGLM_INLINE +void +glm_frustum_planes(mat4 m, vec4 dest[6]) { + mat4 t; + + glm_mat4_transpose_to(m, t); + + glm_vec4_add(t[3], t[0], dest[0]); /* left */ + glm_vec4_sub(t[3], t[0], dest[1]); /* right */ + glm_vec4_add(t[3], t[1], dest[2]); /* bottom */ + glm_vec4_sub(t[3], t[1], dest[3]); /* top */ + glm_vec4_add(t[3], t[2], dest[4]); /* near */ + glm_vec4_sub(t[3], t[2], dest[5]); /* far */ + + glm_plane_normalize(dest[0]); + glm_plane_normalize(dest[1]); + glm_plane_normalize(dest[2]); + glm_plane_normalize(dest[3]); + glm_plane_normalize(dest[4]); + glm_plane_normalize(dest[5]); +} + +/*! + * @brief extracts view frustum corners using clip-space coordinates + * + * corners' space: + * 1- if m = invViewProj: World Space + * 2- if m = invMVP: Object Space + * + * You probably want to extract corners in world space so use invViewProj + * Computing invViewProj: + * glm_mat4_mul(proj, view, viewProj); + * ... + * glm_mat4_inv(viewProj, invViewProj); + * + * if you have a near coord at i index, you can get it's far coord by i + 4 + * + * Find center coordinates: + * for (j = 0; j < 4; j++) { + * glm_vec_center(corners[i], corners[i + 4], centerCorners[i]); + * } + * + * @param[in] invMat matrix (see brief) + * @param[out] dest exracted view frustum corners (see brief) + */ +CGLM_INLINE +void +glm_frustum_corners(mat4 invMat, vec4 dest[8]) { + vec4 c[8]; + + /* indexOf(nearCoord) = indexOf(farCoord) + 4 */ + vec4 csCoords[8] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, /* GLM_LBN */ + {-1.0f, 1.0f, -1.0f, 1.0f}, /* GLM_LTN */ + { 1.0f, 1.0f, -1.0f, 1.0f}, /* GLM_RTN */ + { 1.0f, -1.0f, -1.0f, 1.0f}, /* GLM_RBN */ + + {-1.0f, -1.0f, 1.0f, 1.0f}, /* GLM_LBF */ + {-1.0f, 1.0f, 1.0f, 1.0f}, /* GLM_LTF */ + { 1.0f, 1.0f, 1.0f, 1.0f}, /* GLM_RTF */ + { 1.0f, -1.0f, 1.0f, 1.0f} /* GLM_RBF */ + }; + + glm_mat4_mulv(invMat, csCoords[0], c[0]); + glm_mat4_mulv(invMat, csCoords[1], c[1]); + glm_mat4_mulv(invMat, csCoords[2], c[2]); + glm_mat4_mulv(invMat, csCoords[3], c[3]); + glm_mat4_mulv(invMat, csCoords[4], c[4]); + glm_mat4_mulv(invMat, csCoords[5], c[5]); + glm_mat4_mulv(invMat, csCoords[6], c[6]); + glm_mat4_mulv(invMat, csCoords[7], c[7]); + + glm_vec4_scale(c[0], 1.0f / c[1][3], dest[0]); + glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]); + glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]); + glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]); + glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]); + glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]); + glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]); + glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]); +} + +/*! + * @brief finds center of view frustum + * + * @param[in] corners view frustum corners + * @param[out] dest view frustum center + */ +CGLM_INLINE +void +glm_frustum_center(vec4 corners[8], vec4 dest) { + vec4 center; + + glm_vec4_copy(corners[0], center); + + glm_vec4_add(corners[1], center, center); + glm_vec4_add(corners[2], center, center); + glm_vec4_add(corners[3], center, center); + glm_vec4_add(corners[4], center, center); + glm_vec4_add(corners[5], center, center); + glm_vec4_add(corners[6], center, center); + glm_vec4_add(corners[7], center, center); + + glm_vec4_scale(center, 0.125f, dest); +} + +/*! + * @brief finds bounding box of frustum relative to given matrix e.g. view mat + * + * @param[in] corners view frustum corners + * @param[in] m matrix to convert existing conners + * @param[out] box bounding box as array [min, max] + */ +CGLM_INLINE +void +glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) { + vec4 v; + int i; + + glm_vec_broadcast(0.0f, box[0]); + glm_vec_broadcast(0.0f, box[1]); + + for (i = 0; i < 8; i++) { + glm_mat4_mulv(m, corners[i], v); + + box[0][0] = glm_min(box[0][0], v[0]); + box[0][1] = glm_min(box[0][1], v[1]); + box[0][2] = glm_min(box[0][2], v[2]); + + box[1][0] = glm_max(box[1][0], v[0]); + box[1][1] = glm_max(box[1][1], v[1]); + box[1][2] = glm_max(box[1][2], v[2]); + } +} + +#endif /* cglm_frustum_h */ diff --git a/makefile.am b/makefile.am index 5830700..2350b9c 100644 --- a/makefile.am +++ b/makefile.am @@ -88,7 +88,9 @@ libcglm_la_SOURCES=\ src/vec3.c \ src/vec4.c \ src/mat3.c \ - src/mat4.c + src/mat4.c \ + src/plane.c \ + src/frustum.c test_tests_SOURCES=\ test/src/test_common.c \ diff --git a/src/cam.c b/src/cam.c index 3def839..aeac3c7 100644 --- a/src/cam.c +++ b/src/cam.c @@ -78,21 +78,3 @@ void glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest) { glm_look_anyup(eye, dir, dest); } - -CGLM_EXPORT -void -glmc_frustum_planes(mat4 m, vec4 dest[6]) { - glm_frustum_planes(m, dest); -} - -CGLM_EXPORT -void -glmc_frustum_corners(mat4 invMat, vec4 dest[8]) { - glm_frustum_corners(invMat, dest); -} - -CGLM_EXPORT -void -glmc_frustum_center(vec4 corners[8], vec4 dest) { - glm_frustum_center(corners, dest); -} diff --git a/src/frustum.c b/src/frustum.c new file mode 100644 index 0000000..b175421 --- /dev/null +++ b/src/frustum.c @@ -0,0 +1,33 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#include "../include/cglm/cglm.h" +#include "../include/cglm/call.h" + +CGLM_EXPORT +void +glmc_frustum_planes(mat4 m, vec4 dest[6]) { + glm_frustum_planes(m, dest); +} + +CGLM_EXPORT +void +glmc_frustum_corners(mat4 invMat, vec4 dest[8]) { + glm_frustum_corners(invMat, dest); +} + +CGLM_EXPORT +void +glmc_frustum_center(vec4 corners[8], vec4 dest) { + glm_frustum_center(corners, dest); +} + +CGLM_EXPORT +void +glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) { + glm_frustum_box(corners, m, box); +}