Skip to content

Instantly share code, notes, and snippets.

@darkoverlordofdata
Last active June 19, 2019 06:44
Show Gist options
  • Save darkoverlordofdata/0d6603c477d3bcb1471cc01caf0b0998 to your computer and use it in GitHub Desktop.
Save darkoverlordofdata/0d6603c477d3bcb1471cc01caf0b0998 to your computer and use it in GitHub Desktop.
Tiny glm
/*******************************************************************
*
* MIT License Copyright (c) 2018 Dark Overlord of Data
* tglm is Tiny GLM for c99
*
* opengl math helpers inspired by GLM.
* using clang vector extensions and function overload.
*
*/
#pragma once
#ifndef _TGLM_H
#define _TGLM_H
#include <math.h>
/**
* OpenCL Vector definitions
*/
typedef int IVec2 __attribute__((ext_vector_type(2)));
typedef int IVec3 __attribute__((ext_vector_type(3)));
typedef float Vec2 __attribute__((ext_vector_type(2)));
typedef float Vec3 __attribute__((ext_vector_type(3)));
typedef float Vec4 __attribute__((ext_vector_type(4)));
typedef float Mat __attribute__((ext_vector_type(16)));
/**
* clamp number/vector between MIN and MAX values
*
* @param val value
* @param minVal minimum
* @param maxVal maximum
* @returns clamped value
*
*/
static inline float __attribute__((overloadable)) glm_clamp(float val, float minVal, float maxVal) {
float min = (val > minVal) ? val : minVal;
return (min < maxVal) ? min : maxVal;
}
static inline Vec2 __attribute__((overloadable)) glm_clamp(Vec2 v, float minVal, float maxVal) {
return (Vec2) {
glm_clamp(v.x, minVal, maxVal),
glm_clamp(v.y, minVal, maxVal)
};
}
static inline Vec2 __attribute__((overloadable)) glm_clamp(Vec2 v, Vec2 minVal, Vec2 maxVal) {
return (Vec2) {
glm_clamp(v.x, minVal.x, maxVal.x),
glm_clamp(v.y, minVal.y, maxVal.y)
};
}
static inline Vec3 __attribute__((overloadable)) glm_clamp(Vec3 v, float minVal, float maxVal) {
return (Vec3) {
glm_clamp(v.x, minVal, maxVal),
glm_clamp(v.y, minVal, maxVal),
glm_clamp(v.z, minVal, maxVal)
};
}
static inline Vec4 __attribute__((overloadable)) glm_clamp(Vec4 v, float minVal, float maxVal) {
return (Vec4) {
glm_clamp(v.x, minVal, maxVal),
glm_clamp(v.y, minVal, maxVal),
glm_clamp(v.z, minVal, maxVal),
glm_clamp(v.w, minVal, maxVal)
};
}
/**
* translate transform matrix by v vector
*
* @param m affine transfrom
* @param v translate vector [x, y, z]
* @returns translated matrix
*
*/
static inline Mat glm_translate(Mat m, Vec3 v) {
m.scdef = m.scdef + m.s0123 * v.x + m.s4567 * v.y + m.s89ab * v.z;
return m;
}
/**
* length - return scalar Euclidean length of a vector
*
* @param v vector
* @returns norm * norm
*
*/
static inline float __attribute__((overloadable)) glm_length(Vec2 v) {
return sqrtf(v.x * v.x + v.y * v.y);
}
static inline float __attribute__((overloadable)) glm_length(Vec3 v) {
return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
}
static inline float __attribute__((overloadable)) glm_length(Vec4 v) {
return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
}
/**
* vector dot product
*
* @param a vector1
* @param b vector2
* @returns dot product
*
*/
static inline float __attribute__((overloadable)) glm_dot(Vec2 a, Vec2 b) {
return a.x * b.x + a.y * b.y;
}
static inline float __attribute__((overloadable)) glm_dot(Vec3 a, Vec3 b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
static inline float __attribute__((overloadable)) glm_dot(Vec4 a, Vec4 b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
/**
* norm * norm (magnitude) of vector
*
* @param v vector
* @returns norm * norm
*
*/
static inline float __attribute__((overloadable)) glm_norm2(Vec2 v) {
return glm_dot(v, v);
}
static inline float __attribute__((overloadable)) glm_norm2(Vec3 v) {
return glm_dot(v, v);
}
static inline float __attribute__((overloadable)) glm_norm2(Vec4 v) {
return glm_dot(v, v);
}
/**
* norm (magnitude) of vec3
*
* @param vec vector
* @returns norm
*/
static inline float __attribute__((overloadable)) glm_norm(Vec2 vec) {
return sqrtf(glm_norm2(vec));
}
static inline float __attribute__((overloadable)) glm_norm(Vec3 vec) {
return sqrtf(glm_norm2(vec));
}
static inline float __attribute__((overloadable)) glm_norm(Vec4 vec) {
return sqrtf(glm_norm2(vec));
}
/**
* return an identity matrix
*/
static inline Mat mat_identity()
{
return (Mat){ 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 };
}
/**
* normalize vector and store result in same vec
*
* @param v vector
* @returns normalized vector
*
*/
static inline Vec3 __attribute__((overloadable)) glm_normalize(Vec3 v)
{
float n = glm_norm(v);
if (n == 0.0f) {
v.x = v.y = v.z = 0.0f;
return v;
}
v = v * 1.0f / n;
return v;
}
static inline Vec2 __attribute__((overloadable)) glm_normalize(Vec2 v)
{
float n = glm_norm(v);
if (n == 0.0f) {
v.x = v.y = 0.0f;
return v;
}
v = v * 1.0f / n;
return v;
}
/**
* scales existing transform matrix by v vector
* and stores result in same matrix
*
* @param m affine transfrom
* @param v scale vector [x, y, z]
* @returns scaled Vec3
*/
static inline Mat glm_scale(Mat m, Vec3 v)
{
m.s0123 = m.s0123 * v.x;
m.s4567 = m.s4567 * v.y;
m.s89ab = m.s89ab * v.z;
return m;
}
/**
* set up orthographic projection matrix
*
* @param left left and right vertical clipping planes
* @param right left and right vertical clipping planes
* @param bottom bottom and top horizontal clipping planes
* @param top bottom and top horizontal clipping planes
* @param nearVal nearer and farther depth clipping planes
* @param farVal nearer and farther depth clipping planes
* @returns projection matrix
*/
static inline Mat glm_ortho(float left,
float right,
float bottom,
float top,
float nearVal,
float farVal)
{
Mat proj = mat_identity();
proj.s0 = 2 / (right - left);
proj.s5 = 2 / (top - bottom);
proj.sa = -1;
proj.sc = - (right + left) / (right - left);
proj.sd = - (top + bottom) / (top - bottom);
proj.se = - nearVal / (farVal - nearVal);
return proj;
}
//mat[1][1] = cos(fov / 2.0f) / sin(fov / 2.0f);
//mat[0][0] = mat[1][1] / aspect;
//mat[2][2] = (zfar + znear) / (znear - zfar);
//mat[2][3] = -1.0f;
//mat[3][2] = 2.0f * znear * zfar / (znear - zfar);
//mat[3][3] = 1.0f;
static inline Mat glm_perspective(float fov, float aspect, float zNear, float zFar)
{
Mat proj = { 0 };
proj.s5 = cos(fov / 2.0f) / sin(fov / 2.0f);
proj.s0 = proj.s5 / aspect;
proj.sa = (zFar + zNear) / (zNear - zFar);
proj.sb = -1.0f;
proj.sf = 2.0f * zNear * zFar / (zNear - zFar);
proj.sf = 1.0f;
return proj;
}
/**
* rotate existing transform matrix around given axis by angle
*
* @param m affine transfrom
* @param angle angle (radians)
* @param axis axis
*/
static inline Mat glm_rotate(Mat m, float angle, Vec3 v)
{
float a = angle;
float c = cos(a);
float s = sin(a);
Vec3 axis = glm_normalize(v);
Vec3 temp = (1-c) * axis;
Mat rotate;
rotate.s0 = c + temp.x * axis.x;
rotate.s1 = temp.x * axis.y + s * axis.z;
rotate.s2 = temp.x * axis.z - s * axis.y;
rotate.s4 = temp.y * axis.x - s * axis.z;
rotate.s5 = c + temp.y * axis.y;
rotate.s6 = temp.y * axis.z + s * axis.x;
rotate.s8 = temp.z * axis.x + s * axis.y;
rotate.s9 = temp.z * axis.y - s * axis.x;
rotate.sa = c + temp.z * axis.z;
Mat result;
result.s0123 = m.s0123 * rotate.s0 + m.s4567 * rotate.s1 + m.s89ab * rotate.s2;
result.s4567 = m.s0123 * rotate.s4 + m.s4567 * rotate.s5 + m.s89ab * rotate.s6;
result.s89ab = m.s0123 * rotate.s8 + m.s4567 * rotate.s9 + m.s89ab * rotate.sa;
result.scdef = m.scdef;
return result;
}
#endif // _TGLM_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment