#ifndef _TMATH_HPP_ #define _TMATH_HPP_ #include const float pi = 3.141593f; const float pi2 = 6.283185f; const float sr2 = 1.414214f; const float isr2 = 0.7071068f; namespace tmath { template struct vec2 { T val[2]; T& operator [] (int32_t idx) { return val[idx]; } const T& operator [] (int32_t idx) const { return val[idx]; } vec2 operator + (const vec2& m) const { return vec2{val[0] + m.val[0], val[1] + m.val[1]}; } vec2 operator - (const vec2& m) const { return vec2{val[0] - m.val[0], val[1] - m.val[1]}; } vec2 operator * (T scalar) const { return vec2{val[0] * scalar, val[1] * scalar}; } T dot(const vec2& m) const { return val[0] * m.val[0] + val[1] * m.val[1]; } }; template struct vec3 { T val[3]; T& operator [] (int32_t idx) { return val[idx]; } const T& operator [] (int32_t idx) const { return val[idx]; } vec3 operator + (const vec3& m) const { return vec3{val[0] + m.val[0], val[1] + m.val[1], val[2] + m.val[2]}; } vec3 operator - (const vec3& m) const { return vec3{val[0] - m.val[0], val[1] - m.val[1], val[2] - m.val[2]}; } vec3 operator * (T scalar) const { return vec3{val[0] * scalar, val[1] * scalar, val[2] * scalar}; } T dot(const vec3& m) const { return val[0] * m.val[0] + val[1] * m.val[1] + val[2] * m.val[2]; } vec3 cross(const vec3& m) const { return vec3{ val[1] * m.val[2] - val[2] * m.val[1], val[2] * m.val[0] - val[0] * m.val[2], val[0] * m.val[1] - val[1] * m.val[0] }; } vec3 normalize() const { T factor = std::sqrt(val[0] * val[0] + val[1] * val[1] + val[2] * val[2]); return vec3{val[0] / factor, val[1] / factor, val[2] / factor}; } }; template struct vec4 { T val[4]; T& operator [] (int32_t idx) { return val[idx]; } const T& operator [] (int32_t idx) const { return val[idx]; } }; // | 0 4 8 12 | // | 1 5 9 13 | // | 2 6 10 14 | // | 3 7 11 15 | template struct mat4 { T val[16]; T& operator [] (int32_t idx) { return val[idx]; } const T& operator [] (int32_t idx) const { return val[idx]; } mat4 operator + (const mat4& m) const { return mat4 { val[ 0] + m.val[ 0], val[ 1] + m.val[ 1], val[ 2] + m.val[ 2], val[ 3] + m.val[ 3], val[ 4] + m.val[ 4], val[ 5] + m.val[ 5], val[ 6] + m.val[ 6], val[ 7] + m.val[ 7], val[ 8] + m.val[ 8], val[ 9] + m.val[ 9], val[10] + m.val[10], val[11] + m.val[11], val[12] + m.val[12], val[13] + m.val[13], val[14] + m.val[14], val[15] + m.val[15] }; } vec3 operator * (const vec3& m) const { T fx = val[ 0] * m.val[0] + val[ 4] * m.val[1] + val[ 8] * m.val[2] + val[12]; T fy = val[ 1] * m.val[0] + val[ 5] * m.val[1] + val[ 9] * m.val[2] + val[13]; T fz = val[ 2] * m.val[0] + val[ 6] * m.val[1] + val[10] * m.val[2] + val[14]; T fw = val[ 3] * m.val[0] + val[ 7] * m.val[1] + val[11] * m.val[2] + val[15]; return vec3{ fx / fw, fy / fw, fz / fw}; } mat4 operator * (const mat4& m) const { return mat4 { val[ 0] * m.val[ 0] + val[ 4] * m.val[ 1] + val[ 8] * m.val[ 2] + val[12] * m.val[ 3], val[ 1] * m.val[ 0] + val[ 5] * m.val[ 1] + val[ 9] * m.val[ 2] + val[13] * m.val[ 3], val[ 2] * m.val[ 0] + val[ 6] * m.val[ 1] + val[10] * m.val[ 2] + val[14] * m.val[ 3], val[ 3] * m.val[ 0] + val[ 7] * m.val[ 1] + val[11] * m.val[ 2] + val[15] * m.val[ 3], val[ 0] * m.val[ 4] + val[ 4] * m.val[ 5] + val[ 8] * m.val[ 6] + val[12] * m.val[ 7], val[ 1] * m.val[ 4] + val[ 5] * m.val[ 5] + val[ 9] * m.val[ 6] + val[13] * m.val[ 7], val[ 2] * m.val[ 4] + val[ 6] * m.val[ 5] + val[10] * m.val[ 6] + val[14] * m.val[ 7], val[ 3] * m.val[ 4] + val[ 7] * m.val[ 5] + val[11] * m.val[ 6] + val[15] * m.val[ 7], val[ 0] * m.val[ 8] + val[ 4] * m.val[ 9] + val[ 8] * m.val[10] + val[12] * m.val[11], val[ 1] * m.val[ 8] + val[ 5] * m.val[ 9] + val[ 9] * m.val[10] + val[13] * m.val[11], val[ 2] * m.val[ 8] + val[ 6] * m.val[ 9] + val[10] * m.val[10] + val[14] * m.val[11], val[ 3] * m.val[ 8] + val[ 7] * m.val[ 9] + val[11] * m.val[10] + val[15] * m.val[11], val[ 0] * m.val[12] + val[ 4] * m.val[13] + val[ 8] * m.val[14] + val[12] * m.val[15], val[ 1] * m.val[12] + val[ 5] * m.val[13] + val[ 9] * m.val[14] + val[13] * m.val[15], val[ 2] * m.val[12] + val[ 6] * m.val[13] + val[10] * m.val[14] + val[14] * m.val[15], val[ 3] * m.val[12] + val[ 7] * m.val[13] + val[11] * m.val[14] + val[15] * m.val[15] }; } mat4 translate(T tx, T ty, T tz) const { return mat4{ val[ 0] + val[ 3] * tx, val[ 1] + val[ 3] * ty, val[ 2] + val[ 3] * tz, val[ 3], val[ 4] + val[ 7] * tx, val[ 5] + val[ 7] * ty, val[ 6] + val[ 7] * tz, val[ 7], val[ 8] + val[11] * tx, val[ 9] + val[11] * ty, val[10] + val[11] * tz, val[11], val[12] + val[15] * tx, val[13] + val[15] * ty, val[14] + val[15] * tz, val[15] }; } mat4 scale(T sx, T sy, T sz) const { return mat4{ val[ 0] * sx, val[ 1] * sy, val[ 2] * sz, val[ 3], val[ 4] * sx, val[ 5] * sy, val[ 6] * sz, val[ 7], val[ 8] * sx, val[ 9] * sy, val[10] * sz, val[11], val[12] * sx, val[13] * sy, val[14] * sz, val[15] }; } mat4 rotatex(T rx) const { T sv = std::sin(rx); T cv = std::cos(rx); return mat4{ val[ 0], val[ 1] * cv - val[ 2] * sv, val[ 1] * sv + val[ 2] * cv, val[ 3], val[ 4], val[ 5] * cv - val[ 6] * sv, val[ 5] * sv + val[ 6] * cv, val[ 7], val[ 8], val[ 9] * cv - val[10] * sv, val[ 9] * sv + val[10] * cv, val[11], val[12], val[13] * cv - val[14] * sv, val[13] * sv + val[14] * cv, val[15] }; } mat4 rotatey(T ry) const { T sv = std::sin(ry); T cv = std::cos(ry); return mat4{ val[ 0] * cv + val[ 2] * sv, val[ 1], -val[ 0] * sv + val[ 2] * cv, val[ 3], val[ 4] * cv + val[ 6] * sv, val[ 5], -val[ 4] * sv + val[ 6] * cv, val[ 7], val[ 8] * cv + val[10] * sv, val[ 9], -val[ 8] * sv + val[10] * cv, val[11], val[12] * cv + val[14] * sv, val[13], -val[12] * sv + val[14] * cv, val[15] }; } mat4 rotatez(T rz) const { T sv = std::sin(rz); T cv = std::cos(rz); return mat4{ val[ 0] * cv - val[ 1] * sv, val[ 0] * sv + val[ 1] * cv, val[ 2], val[ 3], val[ 4] * cv - val[ 5] * sv, val[ 4] * sv + val[ 5] * cv, val[ 6], val[ 7], val[ 8] * cv - val[ 9] * sv, val[ 8] * sv + val[ 9] * cv, val[10], val[11], val[12] * cv - val[13] * sv, val[12] * sv + val[13] * cv, val[14], val[15] }; } mat4 homo_inverse() const { T det = val[0] * val[5] * val[10] + val[4] * val[9] * val[2] + val[8] * val[1] * val[6] -val[0] * val[6] * val[9] - val[1] * val[4] * val[10] - val[2] * val[5] * val[8]; T idet = (T)1.0 / det; T adj0 = (val[5] * val[10] - val[6] * val[9]) * idet; T adj1 = (val[4] * val[10] - val[6] * val[8]) * -idet; T adj2 = (val[4] * val[9] - val[5] * val[8]) * idet; T adj3 = (val[1] * val[10] - val[2] * val[9]) * -idet; T adj4 = (val[0] * val[10] - val[2] * val[8]) * idet; T adj5 = (val[0] * val[9] - val[1] * val[8]) * -idet; T adj6 = (val[1] * val[6] - val[2] * val[5]) * idet; T adj7 = (val[0] * val[6] - val[2] * val[4]) * -idet; T adj8 = (val[0] * val[5] - val[1] * val[4]) * idet; T d1 = -adj0 * val[12] - adj1 * val[13] - adj2 * val[14]; T d2 = -adj3 * val[12] - adj4 * val[13] - adj5 * val[14]; T d3 = -adj6 * val[12] - adj7 * val[13] - adj8 * val[14]; return mat4{ adj0, adj3, adj6, (T)0, adj1, adj4, adj7, (T)0, adj2, adj5, adj8, (T)0, d1, d2, d3, (T)1 }; } mat4 transpose() const { return mat4{ val[0], val[4], val[ 8], val[12], val[1], val[5], val[ 9], val[13], val[2], val[6], val[10], val[14], val[3], val[7], val[11], val[15], }; } static mat4 identity() { return mat4{(T)1, (T)0, (T)0, (T)0, (T)0, (T)1, (T)0, (T)0, (T)0, (T)0, (T)1, (T)0, (T)0, (T)0, (T)0, (T)1}; } static mat4 perspective(T width, T height, T near, T far, bool lh = true) { T factor = lh ? (T)1 : (T)-1; T val = far / (far - near); return mat4{ (T)2 * near / width, (T)0, (T)0, (T)0, (T)0, (T)2 * near / height, (T)0, (T)0, (T)0, (T)0, val * factor, (T)factor, (T)0, (T)0, -near * val, (T)0 }; } // same as glm::perspectiveNO, mapping z-axis to [-1, 1] (OpenGL clip volume definition) static mat4 perspective_fov(T fov, T aspect, T near, T far, bool lh = true) { T factor = lh ? (T)1 : (T)-1; T yscale = (T)1 / std::tan(fov * (T)0.5); T xscale = yscale / aspect; T val = far / (far - near); return mat4{ xscale, (T)0, (T)0, (T)0, (T)0, yscale, (T)0, (T)0, (T)0, (T)0, (far + near) / (far - near) * factor, (T)factor, (T)0, (T)0, -(T)2 * far * near / (far - near), (T)0 }; } static mat4 orthogonal(T width, T height, T near, T far, bool lh = true) { T factor = lh ? (T)1 : (T)-1; T dist = far - near; return mat4{ (T)2 / width, (T)0, (T)0, (T)0, (T)0, (T)2 / height, (T)0, (T)0, (T)0, (T)0, factor / dist, -near / dist, (T)0, (T)0, (T)0, (T)1 } } static mat4 look_at(vec3 eye, vec3 at, vec3 up, bool lh = true) { T factor = lh ? (T)1 : (T)-1; vec3 zaxis = (at - eye).normalize() * factor; vec3 xaxis = up.cross(zaxis).normalize(); vec3 yaxis = zaxis.cross(xaxis); return mat4{ xaxis[0], yaxis[0], zaxis[0], (T)0, xaxis[1], yaxis[1], zaxis[1], (T)0, xaxis[2], yaxis[2], zaxis[2], (T)0, -xaxis.dot(eye) * factor, -yaxis.dot(eye) * factor, -zaxis.dot(eye) * factor, (T)1 }; } }; using ivec2 = vec2; using ivec3 = vec3; using ivec4 = vec4; using fvec2 = vec2; using fvec3 = vec3; using fvec4 = vec4; using fmat4 = mat4; } #endif