diff --git a/include/cglm/frustum.h b/include/cglm/frustum.h index 78b39d2..5aa3c17 100644 --- a/include/cglm/frustum.h +++ b/include/cglm/frustum.h @@ -65,7 +65,7 @@ * Exracted planes order: [left, right, bottom, top, near, far] * * @param[in] m matrix (see brief) - * @param[out] dest exracted view frustum planes (see brief) + * @param[out] dest extracted view frustum planes (see brief) */ CGLM_INLINE void diff --git a/include/cglm/plane.h b/include/cglm/plane.h index 48fe879..7a5291d 100644 --- a/include/cglm/plane.h +++ b/include/cglm/plane.h @@ -25,7 +25,7 @@ /*! * @brief normalizes a plane * - * @param[in, out] plane pnale to normalize + * @param[in, out] plane plane to normalize */ CGLM_INLINE void diff --git a/include/cglm/structs/affine.h b/include/cglm/structs/affine.h new file mode 100644 index 0000000..6f8be48 --- /dev/null +++ b/include/cglm/structs/affine.h @@ -0,0 +1,343 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); + CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); + CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); + CGLM_INLINE mat4s glms_translate_make(vec3s v); + CGLM_INLINE mat4s glms_scale_to(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_scale_make(vec3s v); + CGLM_INLINE mat4s glms_scale(mat4s m, vec3s v); + CGLM_INLINE mat4s glms_scale_uni(mat4s m, float s); + CGLM_INLINE mat4s glmx_rotate_x(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); + CGLM_INLINE mat4s glms_rotate_make(float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); + CGLM_INLINE mat4s glms_rotate_atm(mat4s m, vec3s pivot, float angle, vec3s axis); + CGLM_INLINE vec3s glms_decompose_scalev(mat4s m); + CGLM_INLINE bool glms_uniscaled(mat4s m); + CGLM_INLINE void glms_decompose_rs(mat4s m, mat4s r, vec3s s); + CGLM_INLINE void glms_decompose(mat4s m, vec4s t, mat4s r, vec3s s); + */ + +#ifndef cglm_affines_h +#define cglm_affines_h + +#include "../common.h" +#include "../types-struct.h" +#include "../affine.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +CGLM_INLINE +mat4s +glms_mat4_mul(mat4s m1, mat4s m2); + +/*! + * @brief translate existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v translate vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate(mat4s m, vec3s v) { + glm_translate(m.raw, v.raw); + return m; +} + +/*! + * @brief translate existing transform matrix by x factor + * + * @param[in] m affine transfrom + * @param[in] x x factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_x(mat4s m, float x) { + glm_translate_x(m.raw, x); + return m; +} + +/*! + * @brief translate existing transform matrix by y factor + * + * @param[in] m affine transfrom + * @param[in] y y factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_y(mat4s m, float y) { + glm_translate_y(m.raw, y); + return m; +} + +/*! + * @brief translate existing transform matrix by z factor + * + * @param[in] m affine transfrom + * @param[in] z z factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_z(mat4s m, float z) { + glm_translate_z(m.raw, z); + return m; +} + +/*! + * @brief creates NEW translate transform matrix by v vector + * + * @param[in] v translate vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_translate_make(vec3s v) { + mat4s m; + glm_translate_make(m.raw, v.raw); + return m; +} + +/*! + * @brief creates NEW scale matrix by v vector + * + * @param[out] m affine transfrom + * @param[in] v scale vector [x, y, z] + */ +CGLM_INLINE +mat4s +glms_scale_make(vec3s v) { + mat4s m; + glm_scale_make(m.raw, v.raw); + return m; +} + +/*! + * @brief scales existing transform matrix by v vector + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] v scale vector [x, y, z] + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_scale(mat4s m, vec3s v) { + mat4s r; + glm_scale_to(m.raw, v.raw, r.raw); + return r; +} + +/*! + * @brief applies uniform scale to existing transform matrix v = [s, s, s] + * and stores result in same matrix + * + * @param[in] m affine transfrom + * @param[in] s scale factor + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_scale_uni(mat4s m, float s) { + glm_scale_uni(m.raw, s); + return m; +} + +/*! + * @brief rotate existing transform matrix around X axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glmx_rotate_x(mat4s m, float angle) { + mat4s r; + glm_rotate_x(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around Y axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotate_y(mat4s m, float angle) { + mat4s r; + glm_rotate_y(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief rotate existing transform matrix around Z axis by angle + * and store result in dest + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @returns rotated matrix + */ +CGLM_INLINE +mat4s +glms_rotate_z(mat4s m, float angle) { + mat4s r; + glm_rotate_z(m.raw, angle, r.raw); + return r; +} + +/*! + * @brief creates NEW rotation matrix by angle and axis + * + * axis will be normalized so you don't need to normalize it + * + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate_make(float angle, vec3s axis) { + mat4s m; + glm_rotate_make(m.raw, angle, axis.raw); + return m; +} + +/*! + * @brief rotate existing transform matrix around given axis by angle + * + * @param[in] m affine transfrom + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate(mat4s m, float angle, vec3s axis) { + glm_rotate(m.raw, angle, axis.raw); + return m; +} + +/*! + * @brief rotate existing transform + * around given axis by angle at given pivot point (rotation center) + * + * @param[in] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis) { + glm_rotate_at(m.raw, pivot.raw, angle, axis.raw); + return m; +} + +/*! + * @brief creates NEW rotation matrix by angle and axis at given point + * + * this creates rotation matrix, it assumes you don't have a matrix + * + * this should work faster than glm_rotate_at because it reduces + * one glm_translate. + * + * @param[in] m affine transfrom + * @param[in] pivot rotation center + * @param[in] angle angle (radians) + * @param[in] axis axis + * @returns affine transfrom + */ +CGLM_INLINE +mat4s +glms_rotate_atm(mat4s m, vec3s pivot, float angle, vec3s axis) { + glm_rotate_atm(m.raw, pivot.raw, angle, axis.raw); + return m; +} + +/*! + * @brief decompose scale vector + * + * @param[in] m affine transform + * @returns scale vector (Sx, Sy, Sz) + */ +CGLM_INLINE +vec3s +glms_decompose_scalev(mat4s m) { + mat3s m3x3; + vec3s s; + + m3x3 = glms_mat4_pick3(m); + + s.x = glms_vec3_norm(m3x3.col[0]); + s.y = glms_vec3_norm(m3x3.col[1]); + s.z = glms_vec3_norm(m3x3.col[2]); + return s; +} + +/*! + * @brief returns true if matrix is uniform scaled. This is helpful for + * creating normal matrix. + * + * @param[in] m m + * + * @return boolean + */ +CGLM_INLINE +bool +glms_uniscaled(mat4s m) { + return glm_uniscaled(m.raw); +} + +/*! + * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] + * DON'T pass projected matrix here + * + * @param[in] m affine transform + * @param[out] r rotation matrix + * @param[out] s scale matrix + */ +CGLM_INLINE +void +glms_decompose_rs(mat4s m, mat4s r, vec3s s) { + glm_decompose_rs(m.raw, r.raw, s.raw); +} + +/*! + * @brief decompose affine transform, TODO: extract shear factors. + * DON'T pass projected matrix here + * + * @param[in] m affine transfrom + * @param[out] t translation vector + * @param[out] r rotation matrix (mat4) + * @param[out] s scaling vector [X, Y, Z] + */ +CGLM_INLINE +void +glms_decompose(mat4s m, vec4s t, mat4s r, vec3s s) { + glm_decompose(m.raw, t.raw, r.raw, s.raw); +} + +#endif /* cglm_affines_h */ diff --git a/include/cglm/structs/box.h b/include/cglm/structs/box.h new file mode 100644 index 0000000..e9c813f --- /dev/null +++ b/include/cglm/structs/box.h @@ -0,0 +1,285 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_boxs_h +#define cglm_boxs_h + +#include "../common.h" +#include "../types-struct.h" +#include "../box.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief apply transform to Axis-Aligned Bounding Box + * + * @param[in] box bounding box + * @param[in] m transform matrix + * @param[out] dest transformed bounding box + */ +CGLM_INLINE +void +glms_aabb_transform(vec3s box[2], mat4s m, vec3s dest[2]) { + vec3s v[2], xa, xb, ya, yb, za, zb; + mat3s m3x3; + + m3x3 = glms_mat4_pick3(m); + + xa = glms_vec3_scale(m3x3.col[0], box[0].x); + xb = glms_vec3_scale(m3x3.col[0], box[1].x); + + ya = glms_vec3_scale(m3x3.col[1], box[0].y); + yb = glms_vec3_scale(m3x3.col[1], box[1].y); + + za = glms_vec3_scale(m3x3.col[2], box[0].z); + zb = glms_vec3_scale(m3x3.col[2], box[1].z); + + /* translation + min(xa, xb) + min(ya, yb) + min(za, zb) */ + v[0] = m3x3.col[3]; + v[0] = glms_vec3_minadd(xa, xb); + v[0] = glms_vec3_minadd(ya, yb); + v[0] = glms_vec3_minadd(za, zb); + + /* translation + max(xa, xb) + max(ya, yb) + max(za, zb) */ + v[1] = m3x3.col[3]; + v[1] = glms_vec3_maxadd(xa, xb); + v[1] = glms_vec3_maxadd(ya, yb); + v[1] = glms_vec3_maxadd(za, zb); + + dest[0] = glms_vec3_copy(v[0]); + dest[1] = glms_vec3_copy(v[1]); +} + +/*! + * @brief merges two AABB bounding box and creates new one + * + * two box must be in same space, if one of box is in different space then + * you should consider to convert it's space by glm_box_space + * + * @param[in] box1 bounding box 1 + * @param[in] box2 bounding box 2 + * @param[out] dest merged bounding box + */ +CGLM_INLINE +void +glms_aabb_merge(vec3s box1[2], vec3s box2[2], vec3s dest[2]) { + dest[0].x = glm_min(box1[0].x, box2[0].x); + dest[0].y = glm_min(box1[0].y, box2[0].y); + dest[0].z = glm_min(box1[0].z, box2[0].z); + + dest[1].x = glm_max(box1[1].x, box2[1].x); + dest[1].y = glm_max(box1[1].y, box2[1].y); + dest[1].z = glm_max(box1[1].z, box2[1].z); +} + +/*! + * @brief crops a bounding box with another one. + * + * this could be useful for gettng a bbox which fits with view frustum and + * object bounding boxes. In this case you crop view frustum box with objects + * box + * + * @param[in] box bounding box 1 + * @param[in] cropBox crop box + * @param[out] dest cropped bounding box + */ +CGLM_INLINE +void +glms_aabb_crop(vec3s box[2], vec3s cropBox[2], vec3s dest[2]) { + dest[0].x = glm_max(box[0].x, cropBox[0].x); + dest[0].y = glm_max(box[0].y, cropBox[0].y); + dest[0].z = glm_max(box[0].z, cropBox[0].z); + + dest[1].x = glm_min(box[1].x, cropBox[1].x); + dest[1].y = glm_min(box[1].y, cropBox[1].y); + dest[1].z = glm_min(box[1].z, cropBox[1].z); +} + +/*! + * @brief crops a bounding box with another one. + * + * this could be useful for gettng a bbox which fits with view frustum and + * object bounding boxes. In this case you crop view frustum box with objects + * box + * + * @param[in] box bounding box + * @param[in] cropBox crop box + * @param[in] clampBox miniumum box + * @param[out] dest cropped bounding box + */ +CGLM_INLINE +void +glms_aabb_crop_until(vec3s box[2], + vec3s cropBox[2], + vec3s clampBox[2], + vec3s dest[2]) { + glms_aabb_crop(box, cropBox, dest); + glms_aabb_merge(clampBox, dest, dest); +} + +/*! + * @brief check if AABB intersects with frustum planes + * + * this could be useful for frustum culling using AABB. + * + * OPTIMIZATION HINT: + * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR + * then this method should run even faster because it would only use two + * planes if object is not inside the two planes + * fortunately cglm extracts planes as this order! just pass what you got! + * + * @param[in] box bounding box + * @param[in] planes frustum planes + */ +CGLM_INLINE +bool +glms_aabb_frustum(vec3s box[2], vec4s planes[6]) { + vec4s p; + float dp; + int i; + + for (i = 0; i < 6; i++) { + p = planes[i]; + dp = p.x * box[p.x > 0.0f].x + + p.y * box[p.y > 0.0f].y + + p.z * box[p.z > 0.0f].z; + + if (dp < -p.w) + return false; + } + + return true; +} + +/*! + * @brief invalidate AABB min and max values + * + * @param[in, out] box bounding box + */ +CGLM_INLINE +void +glms_aabb_invalidate(vec3s box[2]) { + box[0] = glms_vec3_broadcast(FLT_MAX); + box[1] = glms_vec3_broadcast(-FLT_MAX); +} + +/*! + * @brief check if AABB is valid or not + * + * @param[in] box bounding box + */ +CGLM_INLINE +bool +glms_aabb_isvalid(vec3s box[2]) { + return glms_vec3_max(box[0]) != FLT_MAX && + glms_vec3_min(box[1]) != -FLT_MAX; +} + +/*! + * @brief distance between of min and max + * + * @param[in] box bounding box + */ +CGLM_INLINE +float +glms_aabb_size(vec3s box[2]) { + return glms_vec3_distance(box[0], box[1]); +} + +/*! + * @brief radius of sphere which surrounds AABB + * + * @param[in] box bounding box + */ +CGLM_INLINE +float +glms_aabb_radius(vec3s box[2]) { + return glms_aabb_size(box) * 0.5f; +} + +/*! + * @brief computes center point of AABB + * + * @param[in] box bounding box + * @param[out] dest center of bounding box + */ +CGLM_INLINE +vec3s +glms_aabb_center(vec3s box[2]) { + return glms_vec3_center(box[0], box[1]); +} + +/*! + * @brief check if two AABB intersects + * + * @param[in] box bounding box + * @param[in] other other bounding box + */ +CGLM_INLINE +bool +glms_aabb_aabb(vec3s box[2], vec3s other[2]) { + return (box[0].x <= other[1].x && box[1].x >= other[0].x) + && (box[0].y <= other[1].y && box[1].y >= other[0].y) + && (box[0].z <= other[1].z && box[1].z >= other[0].z); +} + +/*! + * @brief check if AABB intersects with sphere + * + * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c + * Solid Box - Solid Sphere test. + * + * @param[in] box solid bounding box + * @param[in] s solid sphere + */ +CGLM_INLINE +bool +glms_aabb_sphere(vec3s box[2], vec4 s) { + float dmin; + int a, b, c; + + a = s[0] >= box[0].x; + b = s[1] >= box[0].y; + c = s[2] >= box[0].z; + + dmin = glm_pow2(s[0] - box[a].x) + + glm_pow2(s[1] - box[b].y) + + glm_pow2(s[2] - box[c].z); + + return dmin <= glm_pow2(s[3]); +} + +/*! + * @brief check if point is inside of AABB + * + * @param[in] box bounding box + * @param[in] point point + */ +CGLM_INLINE +bool +glms_aabb_point(vec3s box[2], vec3s point) { + return (point.x >= box[0].x && point.x <= box[1].x) + && (point.y >= box[0].y && point.y <= box[1].y) + && (point.z >= box[0].z && point.z <= box[1].z); +} + +/*! + * @brief check if AABB contains other AABB + * + * @param[in] box bounding box + * @param[in] other other bounding box + */ +CGLM_INLINE +bool +glms_aabb_contains(vec3s box[2], vec3s other[2]) { + return (box[0].x <= other[0].x && box[1].x >= other[1].x) + && (box[0].y <= other[0].y && box[1].y >= other[1].y) + && (box[0].z <= other[0].z && box[1].z >= other[1].z); +} + +#endif /* cglm_boxs_h */ diff --git a/include/cglm/structs/color.h b/include/cglm/structs/color.h new file mode 100644 index 0000000..62cf5a8 --- /dev/null +++ b/include/cglm/structs/color.h @@ -0,0 +1,27 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_colors_h +#define cglm_colors_h + +#include "../common.h" +#include "../types-struct.h" +#include "../color.h" +#include "vec3.h" + +/*! + * @brief averages the color channels into one value + * + * @param[in] rgb RGB color + */ +CGLM_INLINE +float +glms_luminance(vec3s rgb) { + return glm_luminance(rgb.raw); +} + +#endif /* cglm_colors_h */ diff --git a/include/cglm/structs/curve.h b/include/cglm/structs/curve.h new file mode 100644 index 0000000..724b0be --- /dev/null +++ b/include/cglm/structs/curve.h @@ -0,0 +1,40 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_curves_h +#define cglm_curves_h + +#include "../common.h" +#include "../types-struct.h" +#include "../curve.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief helper function to calculate S*M*C multiplication for curves + * + * This function does not encourage you to use SMC, + * instead it is a helper if you use SMC. + * + * if you want to specify S as vector then use more generic glm_mat4_rmc() func. + * + * Example usage: + * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) + * + * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) + * @param[in] m basis matrix + * @param[in] c position/control vector + * + * @return B(s) + */ +CGLM_INLINE +float +glms_smc(float s, mat4s m, vec4s c) { + return glm_smc(s, m.raw, c.raw); +} + +#endif /* cglm_curves_h */ diff --git a/include/cglm/structs/frustum.h b/include/cglm/structs/frustum.h new file mode 100644 index 0000000..07340c8 --- /dev/null +++ b/include/cglm/structs/frustum.h @@ -0,0 +1,240 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_frustums_h +#define cglm_frustums_h + +#include "../common.h" +#include "../types-struct.h" +#include "../frustum.h" +#include "plane.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/* you can override clip space coords + but you have to provide all with same name + e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ +#ifndef GLM_CUSTOM_CLIPSPACE + +/* near */ +#define GLMS_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} +#define GLMS_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} +#define GLMS_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} +#define GLMS_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} + +/* far */ +#define GLMS_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} +#define GLMS_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} +#define GLMS_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} +#define GLMS_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} + +#endif + +/*! + * @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 extracted view frustum planes (see brief) + */ +CGLM_INLINE +void +glms_frustum_planes(mat4s m, vec4s dest[6]) { + mat4s t; + + t = glms_mat4_transpose(m); + + dest[0] = glms_vec4_add(t.col[3], t.col[0]); /* left */ + dest[1] = glms_vec4_sub(t.col[3], t.col[0]); /* right */ + dest[2] = glms_vec4_add(t.col[3], t.col[1]); /* bottom */ + dest[3] = glms_vec4_sub(t.col[3], t.col[1]); /* top */ + dest[4] = glms_vec4_add(t.col[3], t.col[2]); /* near */ + dest[5] = glms_vec4_sub(t.col[3], t.col[2]); /* far */ + + dest[0] = glms_plane_normalize(dest[0]); + dest[1] = glms_plane_normalize(dest[1]); + dest[2] = glms_plane_normalize(dest[2]); + dest[3] = glms_plane_normalize(dest[3]); + dest[4] = glms_plane_normalize(dest[4]); + dest[5] = glms_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_vec3_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 +glms_frustum_corners(mat4s invMat, vec4s dest[8]) { + vec4s c[8]; + + /* indexOf(nearCoord) = indexOf(farCoord) + 4 */ + vec4s csCoords[8] = { + GLMS_CSCOORD_LBN, + GLMS_CSCOORD_LTN, + GLMS_CSCOORD_RTN, + GLMS_CSCOORD_RBN, + + GLMS_CSCOORD_LBF, + GLMS_CSCOORD_LTF, + GLMS_CSCOORD_RTF, + GLMS_CSCOORD_RBF + }; + + c[0] = glms_mat4_mulv(invMat, csCoords[0]); + c[1] = glms_mat4_mulv(invMat, csCoords[1]); + c[2] = glms_mat4_mulv(invMat, csCoords[2]); + c[3] = glms_mat4_mulv(invMat, csCoords[3]); + c[4] = glms_mat4_mulv(invMat, csCoords[4]); + c[5] = glms_mat4_mulv(invMat, csCoords[5]); + c[6] = glms_mat4_mulv(invMat, csCoords[6]); + c[7] = glms_mat4_mulv(invMat, csCoords[7]); + + dest[0] = glms_vec4_scale(c[0], 1.0f / c[0].z); + dest[1] = glms_vec4_scale(c[1], 1.0f / c[1].z); + dest[2] = glms_vec4_scale(c[2], 1.0f / c[2].z); + dest[3] = glms_vec4_scale(c[3], 1.0f / c[3].z); + dest[4] = glms_vec4_scale(c[4], 1.0f / c[4].z); + dest[5] = glms_vec4_scale(c[5], 1.0f / c[5].z); + dest[6] = glms_vec4_scale(c[6], 1.0f / c[6].z); + dest[7] = glms_vec4_scale(c[7], 1.0f / c[7].z); +} + +/*! + * @brief finds center of view frustum + * + * @param[in] corners view frustum corners + * @returns view frustum center + */ +CGLM_INLINE +vec4s +glms_frustum_center(vec4s corners[8]) { + vec4s center; + + center = glms_vec4_copy(corners[0]); + + center = glms_vec4_add(corners[1], center); + center = glms_vec4_add(corners[2], center); + center = glms_vec4_add(corners[3], center); + center = glms_vec4_add(corners[4], center); + center = glms_vec4_add(corners[5], center); + center = glms_vec4_add(corners[6], center); + center = glms_vec4_add(corners[7], center); + + return glms_vec4_scale(center, 0.125f); +} + +/*! + * @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 +glms_frustum_box(vec4s corners[8], mat4s m, vec3s box[2]) { + vec4s v; + vec3s min, max; + int i; + + min = glms_vec3_broadcast(FLT_MAX); + max = glms_vec3_broadcast(-FLT_MAX); + + for (i = 0; i < 8; i++) { + v = glms_mat4_mulv(m, corners[i]); + + min.x = glm_min(min.x, v.x); + min.y = glm_min(min.y, v.y); + min.z = glm_min(min.z, v.z); + + max.x = glm_max(max.x, v.x); + max.y = glm_max(max.y, v.y); + max.z = glm_max(max.z, v.z); + } + + box[0] = glms_vec3_copy(min); + box[1] = glms_vec3_copy(max); +} + +/*! + * @brief finds planes corners which is between near and far planes (parallel) + * + * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will + * find planes' corners but you will need to one more plane. + * Actually you have it, it is near, far or created previously with this func ;) + * + * @param[in] corners view frustum corners + * @param[in] splitDist split distance + * @param[in] farDist far distance (zFar) + * @param[out] planeCorners plane corners [LB, LT, RT, RB] + */ +CGLM_INLINE +void +glms_frustum_corners_at(vec4s corners[8], + float splitDist, + float farDist, + vec4s planeCorners[4]) { + vec4s corner; + float dist, sc; + + /* because distance and scale is same for all */ + dist = glms_vec4_distance(corners[GLM_RTF], corners[GLM_RTN]); + sc = dist * (splitDist / farDist); + + /* left bottom */ + corner = glms_vec4_sub(corners[GLM_LBF], corners[GLM_LBN]); + corner = glms_vec4_scale_as(corner, sc); + planeCorners[0] = glms_vec4_add(corners[GLM_LBN], corner); + + /* left top */ + corner = glms_vec4_sub(corners[GLM_LTF], corners[GLM_LTN]); + corner = glms_vec4_scale_as(corner, sc); + planeCorners[1] = glms_vec4_add(corners[GLM_LTN], corner); + + /* right top */ + corner = glms_vec4_sub(corners[GLM_RTF], corners[GLM_RTN]); + corner = glms_vec4_scale_as(corner, sc); + planeCorners[2] = glms_vec4_add(corners[GLM_RTN], corner); + + /* right bottom */ + corner = glms_vec4_sub(corners[GLM_RBF], corners[GLM_RBN]); + corner = glms_vec4_scale_as(corner, sc); + planeCorners[3] = glms_vec4_add(corners[GLM_RBN], corner); +} + +#endif /* cglm_frustums_h */ diff --git a/include/cglm/structs/io.h b/include/cglm/structs/io.h new file mode 100644 index 0000000..c209a47 --- /dev/null +++ b/include/cglm/structs/io.h @@ -0,0 +1,100 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +/* + Functions: + CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE *ostream); + CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE *ostream); + CGLM_INLINE void glm_vec4_print(vec4 vec, FILE *ostream); + CGLM_INLINE void glm_vec3_print(vec3 vec, FILE *ostream); + CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE *ostream); + CGLM_INLINE void glm_versor_print(versor vec, FILE *ostream); + */ + +#ifndef cglm_ios_h +#define cglm_ios_h + +#include "../common.h" +#include "../io.h" +#include "mat4.h" + +#include +#include + +CGLM_INLINE +void +glms_mat4_print(mat4s matrix, + FILE * __restrict ostream) { + + glm_mat4_print(matrix.raw, ostream); +} + +CGLM_INLINE +void +glms_mat3_print(mat3s matrix, + FILE * __restrict ostream) { + glm_mat3_print(matrix.raw, ostream); +} + +CGLM_INLINE +void +glms_vec4_print(vec4s vec, + FILE * __restrict ostream) { + glm_vec4_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_vec3_print(vec3s vec, + FILE * __restrict ostream) { + glm_vec3_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_ivec3_print(ivec3s vec, + FILE * __restrict ostream) { + glm_ivec3_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_versor_print(versors vec, + FILE * __restrict ostream) { + glm_versor_print(vec.raw, ostream); +} + +CGLM_INLINE +void +glms_aabb_print(vec3s bbox[2], + const char * __restrict tag, + FILE * __restrict ostream) { + int i, j; + +#define m 3 + + fprintf(ostream, "AABB (%s):\n", tag ? tag : "float"); + + for (i = 0; i < 2; i++) { + fprintf(ostream, "\t|"); + + for (j = 0; j < m; j++) { + fprintf(ostream, "%0.4f", bbox[i].raw[j]); + + if (j != m - 1) + fprintf(ostream, "\t"); + } + + fprintf(ostream, "|\n"); + } + + fprintf(ostream, "\n"); + +#undef m +} + +#endif /* cglm_ios_h */ diff --git a/include/cglm/structs/mat3.h b/include/cglm/structs/mat3.h index 63fe7c6..8072746 100644 --- a/include/cglm/structs/mat3.h +++ b/include/cglm/structs/mat3.h @@ -18,7 +18,6 @@ CGLM_INLINE void glms_mat3_identity_array(mat3s * __restrict mat, size_t count); CGLM_INLINE mat3s glms_mat3_zero(); CGLM_INLINE mat3s glms_mat3_mul(mat3s m1, mat3s m2); - CGLM_INLINE mat3s glms_mat3_transpose_to(mat3s m); CGLM_INLINE ma3s glms_mat3_transpose(mat3s m); CGLM_INLINE vec3s glms_mat3_mulv(mat3s m, vec3s v); CGLM_INLINE float glms_mat3_trace(mat3s m); @@ -140,22 +139,6 @@ glms_mat3_mul(mat3s m1, mat3s m2) { return r; } -/*! - * @brief transpose mat3 and store in dest - * - * source matrix will not be transposed unless dest is m - * - * @param[in] m matrix - * @param[out] dest result - */ -CGLM_INLINE -mat3s -glms_mat3_transpose_to(mat3s m) { - mat3s r; - glm_mat3_transpose_to(m.raw, r.raw); - return r; -} - /*! * @brief tranpose mat3 and store result in same matrix * diff --git a/include/cglm/structs/mat4.h b/include/cglm/structs/mat4.h index a61f18d..72686cd 100644 --- a/include/cglm/structs/mat4.h +++ b/include/cglm/structs/mat4.h @@ -33,7 +33,6 @@ CGLM_INLINE float glms_mat4_trace3(mat4s m); CGLM_INLINE versors glms_mat4_quat(mat4s m); CGLM_INLINE vec3s glms_mat4_mulv3(mat4s m, vec3s v, float last); - CGLM_INLINE mat4s glms_mat4_transpose_to(mat4s m); CGLM_INLINE mat4s glms_mat4_transpose(mat4s m); CGLM_INLINE mat4s glms_mat4_scale_p(mat4s m, float s); CGLM_INLINE mat4s glms_mat4_scale(mat4s m, float s); @@ -54,19 +53,19 @@ #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_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_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} /* for C only */ -#define GLMS_MAT4_IDENTITY ((mat4)GLMS_MAT4_IDENTITY_INIT) -#define GLMS_MAT4_ZERO ((mat4)GLMS_MAT4_ZERO_INIT) +#define GLMS_MAT4_IDENTITY ((mat4s)GLMS_MAT4_IDENTITY_INIT) +#define GLMS_MAT4_ZERO ((mat4s)GLMS_MAT4_ZERO_INIT) /*! * @brief copy all members of [mat] to [dest] @@ -132,7 +131,7 @@ glms_mat4_identity() { CGLM_INLINE void glms_mat4_identity_array(mat4s * __restrict mat, size_t count) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; + CGLM_ALIGN_MAT mat4s t = GLMS_MAT4_IDENTITY_INIT; size_t i; for (i = 0; i < count; i++) { @@ -229,20 +228,25 @@ glms_mat4_mul(mat4s m1, mat4s m2) { * @code * mat m1, m2, m3, m4, res; * - * glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4, res); + * res = glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4); * @endcode * * @warning matrices parameter is pointer array not mat4 array! * * @param[in] matrices mat4 * array * @param[in] len matrices count - * @returns result + * @returns result matrix */ CGLM_INLINE mat4s glms_mat4_mulN(mat4s * __restrict matrices[], uint32_t len) { - mat4s r; - glm_mat4_mulN(matrices, len, r.raw); + CGLM_ALIGN_MAT mat4s r = GLMS_MAT4_IDENTITY_INIT; + uint32_t i; + + for (i = 0; i < len; i++) { + r = glms_mat4_mul(r, *matrices[i]); + } + return r; } @@ -317,22 +321,6 @@ glms_mat4_mulv3(mat4s m, vec3s v, float last) { return r; } -/*! - * @brief transpose mat4 and store in dest - * - * source matrix will not be transposed unless dest is m - * - * @param[in] m matrix - * @returns result - */ -CGLM_INLINE -mat4s -glms_mat4_transpose_to(mat4s m) { - mat4s r; - glm_mat4_transpose_to(m.raw, r.raw); - return r; -} - /*! * @brief tranpose mat4 and store result in same matrix * diff --git a/include/cglm/structs/plane.h b/include/cglm/structs/plane.h new file mode 100644 index 0000000..6e23482 --- /dev/null +++ b/include/cglm/structs/plane.h @@ -0,0 +1,40 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_planes_h +#define cglm_planes_h + +#include "../common.h" +#include "../types-struct.h" +#include "../plane.h" +#include "vec4.h" + +/* + Plane equation: Ax + By + Cz + D = 0; + + It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance +*/ + +/* + Functions: + CGLM_INLINE vec4s glms_plane_normalize(vec4s plane); + */ + +/*! + * @brief normalizes a plane + * + * @param[in] plane plane to normalize + * @returns normalized plane + */ +CGLM_INLINE +vec4s +glms_plane_normalize(vec4s plane) { + glm_plane_normalize(plane.raw); + return plane; +} + +#endif /* cglm_planes_h */ diff --git a/include/cglm/structs/project.h b/include/cglm/structs/project.h new file mode 100644 index 0000000..1cbb137 --- /dev/null +++ b/include/cglm/structs/project.h @@ -0,0 +1,104 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#ifndef cglm_projects_h +#define cglm_projects_h + +#include "../common.h" +#include "../types-struct.h" +#include "../project.h" +#include "vec3.h" +#include "vec4.h" +#include "mat4.h" + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * if you don't have ( and don't want to have ) an inverse matrix then use + * glm_unproject version. You may use existing inverse of matrix in somewhere + * else, this is why glm_unprojecti exists to save save inversion cost + * + * [1] space: + * 1- if m = invProj: View Space + * 2- if m = invViewProj: World Space + * 3- if m = invMVP: Object Space + * + * You probably want to map the coordinates into object space + * so use invMVP as m + * + * Computing viewProj: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * glm_mat4_inv(viewProj, invMVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] invMat matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @returns unprojected coordinates + */ +CGLM_INLINE +vec3s +glms_unprojecti(vec3s pos, mat4s invMat, vec4s vp) { + vec3s r; + glm_unprojecti(pos.raw, invMat.raw, vp.raw, r.raw); + return r; +} + +/*! + * @brief maps the specified viewport coordinates into specified space [1] + * the matrix should contain projection matrix. + * + * this is same as glm_unprojecti except this function get inverse matrix for + * you. + * + * [1] space: + * 1- if m = proj: View Space + * 2- if m = viewProj: World Space + * 3- if m = MVP: Object Space + * + * You probably want to map the coordinates into object space + * so use MVP as m + * + * Computing viewProj and MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos point/position in viewport coordinates + * @param[in] m matrix (see brief) + * @param[in] vp viewport as [x, y, width, height] + * @returns unprojected coordinates + */ +CGLM_INLINE +vec3s +glms_unproject(vec3s pos, mat4s m, vec4s vp) { + vec3s r; + glm_unproject(pos.raw, m.raw, vp.raw, r.raw); + return r; +} + +/*! + * @brief map object coordinates to window coordinates + * + * Computing MVP: + * glm_mat4_mul(proj, view, viewProj); + * glm_mat4_mul(viewProj, model, MVP); + * + * @param[in] pos object coordinates + * @param[in] m MVP matrix + * @param[in] vp viewport as [x, y, width, height] + * @param[out] dest projected coordinates + */ +CGLM_INLINE +vec3s +glms_project(vec3s pos, mat4s m, vec4s vp) { + vec3s r; + glm_project(pos.raw, m.raw, vp.raw, r.raw); + return r; +} + +#endif /* cglm_projects_h */ diff --git a/include/cglm/structs/sphere.h b/include/cglm/structs/sphere.h index b336c3b..164e8bc 100644 --- a/include/cglm/structs/sphere.h +++ b/include/cglm/structs/sphere.h @@ -10,8 +10,8 @@ #include "../common.h" #include "../types-struct.h" -#include "../mat4.h" #include "../sphere.h" +#include "mat4.h" /* Sphere Representation in cglm: [center.x, center.y, center.z, radii] diff --git a/include/cglm/types-struct.h b/include/cglm/types-struct.h index 13431aa..2d54aa4 100644 --- a/include/cglm/types-struct.h +++ b/include/cglm/types-struct.h @@ -21,6 +21,17 @@ typedef union vec3s { vec3 raw; } vec3s; +typedef union ivec3s { +#ifndef CGLM_NO_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 struct { @@ -38,15 +49,9 @@ typedef vec4s versors; typedef union mat3s { #ifndef CGLM_NO_ANONYMOUS_STRUCT struct { - float m00; - float m01; - float m02; - float m10; - float m11; - float m12; - float m20; - float m21; - float m22; + float m00, m01, m02; + float m10, m11, m12; + float m20, m21, m22; }; struct { vec3s col0; @@ -54,32 +59,17 @@ typedef union mat3s { vec3s col2; }; #endif + vec3s col[3]; mat3 raw; } mat3s; -#ifdef __AVX__ -typedef union CGLM_ALIGN_IF(32) mat4s { -#else -typedef union CGLM_ALIGN_IF(16) mat4s { -#endif +typedef union CGLM_ALIGN_MAT mat4s { #ifndef CGLM_NO_ANONYMOUS_STRUCT struct { - float m00; - float m01; - float m02; - float m03; - float m10; - float m11; - float m12; - float m13; - float m20; - float m21; - float m22; - float m23; - float m30; - float m31; - float m32; - float m33; + float m00, m01, m02, m03; + float m10, m11, m12, m13; + float m20, m21, m22, m23; + float m30, m31, m32, m33; }; struct { vec4s col0; @@ -88,6 +78,7 @@ typedef union CGLM_ALIGN_IF(16) mat4s { vec4s col3; }; #endif + vec4s col[4]; mat4 raw; } mat4s;