--- /dev/null
+*.o
+*.swp
+*.d
--- /dev/null
+Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-/* C version of the graphene math library */
+/* C version of the graphene math library
+ * Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+ *
+ * This program is free software. Feel free to use, modify, and/or redistribute
+ * it under the terms of the MIT/X11 license. See LICENSE for details.
+ * If you intend to redistribute parts of the code without the LICENSE file
+ * replace this paragraph with the full contents of the LICENSE file.
+ *
+ * Function prefixes signify the data type of their operand(s):
+ * - cgm_v... functions are operations on cgm_vec3 vectors
+ * - cgm_w... functions are operations on cgm_vec4 vectors
+ * - cgm_q... functions are operations on cgm_quat quaternions (w + xi + yj + zk)
+ * - cgm_m... functions are operations on 4x4 matrices (stored as linear 16 float arrays)
+ *
+ * NOTE: *ALL* matrix arguments are pointers to 16 floats. Even the functions
+ * which operate on 3x3 matrices, actually use the upper 3x3 of a 4x4 matrix,
+ * and still expect an array of 16 floats.
+ *
+ * NOTE: matrices are treated by all operations as column-major, to match OpenGL
+ * conventions, so everything is pretty much transposed.
+ */
#ifndef CGMATH_H_
#define CGMATH_H_
#include <math.h>
+#include <string.h>
typedef struct {
float x, y, z;
typedef struct {
float x, y, z, w;
-} cgm_quat;
+} cgm_vec4, cgm_quat;
+
+typedef enum cgm_euler_mode {
+ CGM_EULER_XYZ,
+ CGM_EULER_XZY,
+ CGM_EULER_YXZ,
+ CGM_EULER_YZX,
+ CGM_EULER_ZXY,
+ CGM_EULER_ZYX,
+ CGM_EULER_ZXZ,
+ CGM_EULER_ZYZ,
+ CGM_EULER_YXY,
+ CGM_EULER_YZY,
+ CGM_EULER_XYX,
+ CGM_EULER_XZX
+} cgm_euler_mode;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --- operations on cgm_vec3 --- */
+static inline void cgm_vcons(cgm_vec3 *v, float x, float y, float z);
static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b);
static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b);
static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b);
static inline void cgm_vscale(cgm_vec3 *v, float s);
+static inline void cgm_vmul_m4v3(cgm_vec3 *v, const float *m); /* m4x4 * v */
+static inline void cgm_vmul_v3m4(cgm_vec3 *v, const float *m); /* v * m4x4 */
+static inline void cgm_vmul_m3v3(cgm_vec3 *v, const float *m); /* m3x3 * v (m still 16 floats) */
+static inline void cgm_vmul_v3m3(cgm_vec3 *v, const float *m); /* v * m3x3 (m still 16 floats) */
static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b);
static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b);
static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b);
static inline void cgm_vnormalize(cgm_vec3 *v);
-#include "cgmath.inl"
+static inline void cgm_vreflect(cgm_vec3 *v, const cgm_vec3 *n);
+static inline void cgm_vrefract(cgm_vec3 *v, const cgm_vec3 *n, float ior);
+
+static inline void cgm_vrotate_quat(cgm_vec3 *v, const cgm_quat *q);
+static inline void cgm_vrotate_axis(cgm_vec3 *v, const cgm_vec3 *axis, float angle);
+static inline void cgm_vrotate_euler(cgm_vec3 *v, const cgm_vec3 *euler, enum cgm_euler_mode mode);
+
+static inline void cgm_vlerp(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b, float t);
+
+/* --- operations on cgm_vec4 --- */
+static inline void cgm_wcons(cgm_vec4 *v, float x, float y, float z, float w);
+
+static inline void cgm_wadd(cgm_vec4 *a, const cgm_vec4 *b);
+static inline void cgm_wsub(cgm_vec4 *a, const cgm_vec4 *b);
+static inline void cgm_wmul(cgm_vec4 *a, const cgm_vec4 *b);
+static inline void cgm_wscale(cgm_vec4 *v, float s);
+
+static inline void cgm_wmul_m4v4(cgm_vec4 *v, const float *m);
+static inline void cgm_wmul_v4m4(cgm_vec4 *v, const float *m);
+static inline void cgm_wmul_m34v4(cgm_vec4 *v, const float *m); /* doesn't affect w */
+static inline void cgm_wmul_v4m43(cgm_vec4 *v, const float *m); /* doesn't affect w */
+static inline void cgm_wmul_m3v4(cgm_vec4 *v, const float *m); /* (m still 16 floats) */
+static inline void cgm_wmul_v4m3(cgm_vec4 *v, const float *m); /* (m still 16 floats) */
+
+static inline float cgm_wlength(const cgm_vec4 *v);
+static inline float cgm_wlength_sq(const cgm_vec4 *v);
+static inline float cgm_wdist(const cgm_vec4 *a, const cgm_vec4 *b);
+static inline float cgm_wdist_sq(const cgm_vec4 *a, const cgm_vec4 *b);
+static inline void cgm_wnormalize(cgm_vec4 *v);
+
+static inline void cgm_wlerp(cgm_vec4 *res, const cgm_vec4 *a, const cgm_vec4 *b, float t);
+
+/* --- operations on quaternions --- */
+static inline void cgm_qcons(cgm_quat *q, float x, float y, float z, float w);
+
+static inline void cgm_qneg(cgm_quat *q);
+static inline void cgm_qadd(cgm_quat *a, const cgm_quat *b);
+static inline void cgm_qsub(cgm_quat *a, const cgm_quat *b);
+static inline void cgm_qmul(cgm_quat *a, const cgm_quat *b);
+
+static inline float cgm_qlength(const cgm_quat *q);
+static inline float cgm_qlength_sq(const cgm_quat *q);
+static inline void cgm_qnormalize(cgm_quat *q);
+static inline void cgm_qconjugate(cgm_quat *q);
+static inline void cgm_qinvert(cgm_quat *q);
+
+static inline void cgm_qrotation(cgm_quat *q, const cgm_vec3 *axis, float angle);
+static inline void cgm_qrotate(cgm_quat *q, const cgm_vec3 *axis, float angle);
+
+static inline void cgm_qslerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t);
+static inline void cgm_qlerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t);
+
+/* --- operations on matrices --- */
+static inline void cgm_mcopy(float *dest, const float *src);
+static inline void cgm_mzero(float *m);
+static inline void cgm_midentity(float *m);
+
+static inline void cgm_msetrow_v3(float *m, int idx, const cgm_vec3 *v);
+static inline void cgm_msetrow_v4(float *m, int idx, const cgm_vec4 *v);
+static inline void cgm_msetcol_v3(float *m, int idx, const cgm_vec3 *v);
+static inline void cgm_msetcol_v4(float *m, int idx, const cgm_vec4 *v);
+static inline void cgm_mgetrow_v3(cgm_vec3 *v, const float *m, int idx);
+static inline void cgm_mgetrow_v4(cgm_vec4 *v, const float *m, int idx);
+static inline void cgm_mgetcol_v3(cgm_vec3 *v, const float *m, int idx);
+static inline void cgm_mgetcol_v4(cgm_vec4 *v, const float *m, int idx);
+
+static inline void cgm_mupper3(float *m);
+
+#include "cgmvec3.inl"
+#include "cgmvec4.inl"
+#include "cgmquat.inl"
+#include "cgmmat.inl"
+
+#ifdef __cplusplus
+}
+#endif
#endif /* CGMATH_H_ */
+++ /dev/null
-static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b)
-{
- a->x += b->x;
- a->y += b->y;
- a->z += b->z;
-}
-
-static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b)
-{
- a->x -= b->x;
- a->y -= b->y;
- a->z -= b->z;
-}
-
-static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b)
-{
- a->x *= b->x;
- a->y *= b->y;
- a->z *= b->z;
-}
-
-static inline void cgm_vscale(cgm_vec3 *v, float s)
-{
- v->x *= s;
- v->y *= s;
- v->z *= s;
-}
-
-static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b)
-{
- return a->x * b->x + a->y * b->y + a->z * b->z;
-}
-
-static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b)
-{
- res->x = a->y * b->z - a->z * b->y;
- res->y = a->z * b->x - a->x * b->z;
- res->z = a->x * b->y - a->y * b->x;
-}
-
-static inline float cgm_vlength(const cgm_vec3 *v)
-{
- return sqrt(v->x * v->x + v->y * v->y + v->z * v->z);
-}
-
-static inline float cgm_vlength_sq(const cgm_vec3 *v)
-{
- return v->x * v->x + v->y * v->y + v->z * v->z;
-}
-
-static inline float cgm_vdist(const cgm_vec3 *a, const cgm_vec3 *b)
-{
- float dx = a->x - b->x;
- float dy = a->y - b->y;
- float dz = a->z - b->z;
- return sqrt(dx * dx + dy * dy + dz * dz);
-}
-
-static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b)
-{
- float dx = a->x - b->x;
- float dy = a->y - b->y;
- float dz = a->z - b->z;
- return dx * dx + dy * dy + dz * dz;
-}
-
-static inline void cgm_vnormalize(cgm_vec3 *v)
-{
- float len = cgm_vlength(v);
- if(len != 0.0f) {
- float s = 1.0f / len;
- v->x *= s;
- v->y *= s;
- v->z *= s;
- }
-}
--- /dev/null
+static inline void cgm_mcopy(float *dest, const float *src)
+{
+ memcpy(dest, src, 16 * sizeof(float));
+}
+
+static inline void cgm_mzero(float *m)
+{
+ static float z[16];
+ cgm_mcopy(m, z);
+}
+
+static inline void cgm_midentity(float *m)
+{
+ static float id[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
+ cgm_mcopy(m, id);
+}
+
+static inline void cgm_msetrow_v3(float *m, int idx, const cgm_vec3 *v)
+{
+ m[idx] = v->x;
+ m[idx + 4] = v->y;
+ m[idx + 8] = v->z;
+ m[idx + 12] = 0.0f;
+}
+
+static inline void cgm_msetrow_v4(float *m, int idx, const cgm_vec4 *v)
+{
+ m[idx] = v->x;
+ m[idx + 4] = v->y;
+ m[idx + 8] = v->z;
+ m[idx + 12] = v->w;
+}
+
+static inline void cgm_msetcol_v3(float *m, int idx, const cgm_vec3 *v)
+{
+ m[idx * 4] = v->x;
+ m[idx * 4 + 1] = v->y;
+ m[idx * 4 + 2] = v->z;
+ m[idx * 4 + 3] = 0.0f;
+}
+
+static inline void cgm_msetcol_v4(float *m, int idx, const cgm_vec4 *v)
+{
+ m[idx * 4] = v->x;
+ m[idx * 4 + 1] = v->y;
+ m[idx * 4 + 2] = v->z;
+ m[idx * 4 + 3] = v->w;
+}
+
+static inline void cgm_mgetrow_v3(cgm_vec3 *v, const float *m, int idx)
+{
+ v->x = m[idx];
+ v->y = m[idx + 4];
+ v->z = m[idx + 8];
+}
+
+static inline void cgm_mgetrow_v4(cgm_vec4 *v, const float *m, int idx)
+{
+ v->x = m[idx];
+ v->y = m[idx + 4];
+ v->z = m[idx + 8];
+ v->w = m[idx + 12];
+}
+
+static inline void cgm_mgetcol_v3(cgm_vec3 *v, const float *m, int idx)
+{
+ v->x = m[idx * 4];
+ v->y = m[idx * 4 + 1];
+ v->z = m[idx * 4 + 2];
+}
+
+static inline void cgm_mgetcol_v4(cgm_vec4 *v, const float *m, int idx)
+{
+ v->x = m[idx * 4];
+ v->y = m[idx * 4 + 1];
+ v->z = m[idx * 4 + 2];
+ v->w = m[idx * 4 + 3];
+}
+
+static inline void cgm_msubmatrix(float *m, int row, int col)
+{
+}
+
+static inline void cgm_mupper3(float *m)
+{
+ m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f;
+ m[15] = 1.0f;
+}
--- /dev/null
+static inline void cgm_qcons(cgm_quat *q, float x, float y, float z, float w)
+{
+ q->x = x;
+ q->y = y;
+ q->z = z;
+ q->w = w;
+}
+
+
+static inline void cgm_qneg(cgm_quat *q)
+{
+ q->x = -q->x;
+ q->y = -q->y;
+ q->z = -q->z;
+ q->w = -q->w;
+}
+
+static inline void cgm_qadd(cgm_quat *a, const cgm_quat *b)
+{
+ a->x += b->x;
+ a->y += b->y;
+ a->z += b->z;
+ a->w += b->w;
+}
+
+static inline void cgm_qsub(cgm_quat *a, const cgm_quat *b)
+{
+ a->x -= b->x;
+ a->y -= b->y;
+ a->z -= b->z;
+ a->w -= b->w;
+}
+
+static inline void cgm_qmul(cgm_quat *a, const cgm_quat *b)
+{
+ float x, y, z, dot;
+ cgm_vec3 cross;
+
+ dot = a->x * b->x + a->y * b->y + a->z * b->z;
+ cgm_vcross(&cross, (cgm_vec3*)a, (cgm_vec3*)b);
+
+ x = a->w * b->x + b->w * a->x + cross.x;
+ y = a->w * b->y + b->w * a->y + cross.y;
+ z = a->w * b->z + b->w * a->z + cross.z;
+ a->w = a->w * b->w - dot;
+ a->x = x;
+ a->y = y;
+ a->z = z;
+}
+
+static inline float cgm_qlength(const cgm_quat *q)
+{
+ return sqrt(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
+}
+
+static inline float cgm_qlength_sq(const cgm_quat *q)
+{
+ return q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
+}
+
+static inline void cgm_qnormalize(cgm_quat *q)
+{
+ float len = cgm_qlength(q);
+ if(len != 0.0f) {
+ float s = 1.0f / len;
+ q->x *= s;
+ q->y *= s;
+ q->z *= s;
+ q->w *= s;
+ }
+}
+
+static inline void cgm_qconjugate(cgm_quat *q)
+{
+ q->x = -q->x;
+ q->y = -q->y;
+ q->z = -q->z;
+}
+
+static inline void cgm_qinvert(cgm_quat *q)
+{
+ float len_sq = cgm_qlength_sq(q);
+ cgm_qconjugate(q);
+ if(len_sq != 0.0f) {
+ float s = 1.0f / len_sq;
+ q->x *= s;
+ q->y *= s;
+ q->z *= s;
+ q->w *= s;
+ }
+}
+
+static inline void cgm_qrotation(cgm_quat *q, const cgm_vec3 *axis, float angle)
+{
+ float hangle = angle * 0.5f;
+ float sin_ha = sin(hangle);
+ q->w = cos(hangle);
+ q->x = axis->x * sin_ha;
+ q->y = axis->y * sin_ha;
+ q->z = axis->z * sin_ha;
+}
+
+static inline void cgm_qrotate(cgm_quat *q, const cgm_vec3 *axis, float angle)
+{
+ cgm_quat qrot;
+ cgm_qrotation(&qrot, axis, angle);
+ cgm_qmul(q, &qrot);
+}
+
+static inline void cgm_qslerp(cgm_quat *res, const cgm_quat *quat1, const cgm_quat *q2, float t)
+{
+ float angle, dot, a, b, sin_angle;
+ cgm_quat q1 = *quat1;
+
+ dot = quat1->x * q2->x + quat1->y * q2->y + quat1->z * q2->z + quat1->w * q2->w;
+ if(dot < 0.0f) {
+ /* make sure we inteprolate across the shortest arc */
+ cgm_qneg(&q1);
+ dot = -dot;
+ }
+
+ /* clamp dot to [-1, 1] in order to avoid domain errors in acos due to
+ * floating point imprecisions
+ */
+ if(dot < -1.0f) dot = -1.0f;
+ if(dot > 1.0f) dot = 1.0f;
+ angle = acos(dot);
+
+ sin_angle = sin(angle);
+ if(sin_angle == 0.0f) {
+ /* use linear interpolation to avoid div/zero */
+ a = 1.0f;
+ b = t;
+ } else {
+ a = sin((1.0f - t) * angle) / sin_angle;
+ b = sin(t * angle) / sin_angle;
+ }
+
+ res->x = q1.x * a + q2->x * b;
+ res->y = q1.y * a + q2->y * b;
+ res->z = q1.z * a + q2->z * b;
+ res->w = q1.w * a + q2->w * b;
+}
+
+static inline void cgm_qlerp(cgm_quat *res, const cgm_quat *a, const cgm_quat *b, float t)
+{
+ res->x = a->x + (b->x - a->x) * t;
+ res->y = a->y + (b->y - a->y) * t;
+ res->z = a->z + (b->z - a->z) * t;
+ res->w = a->w + (b->w - a->w) * t;
+}
--- /dev/null
+static inline void cgm_vcons(cgm_vec3 *v, float x, float y, float z)
+{
+ v->x = x;
+ v->y = y;
+ v->z = z;
+}
+
+static inline void cgm_vadd(cgm_vec3 *a, const cgm_vec3 *b)
+{
+ a->x += b->x;
+ a->y += b->y;
+ a->z += b->z;
+}
+
+static inline void cgm_vsub(cgm_vec3 *a, const cgm_vec3 *b)
+{
+ a->x -= b->x;
+ a->y -= b->y;
+ a->z -= b->z;
+}
+
+static inline void cgm_vmul(cgm_vec3 *a, const cgm_vec3 *b)
+{
+ a->x *= b->x;
+ a->y *= b->y;
+ a->z *= b->z;
+}
+
+static inline void cgm_vscale(cgm_vec3 *v, float s)
+{
+ v->x *= s;
+ v->y *= s;
+ v->z *= s;
+}
+
+static inline void cgm_vmul_m4v3(cgm_vec3 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + m[12];
+ float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + m[13];
+ v->z = v->x * m[2] + v->y * m[6] + v->z * m[10] + m[14];
+ v->x = x;
+ v->y = y;
+}
+
+static inline void cgm_vmul_v3m4(cgm_vec3 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + m[3];
+ float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + m[7];
+ v->z = v->x * m[8] + v->y * m[9] + v->z * m[10] + m[11];
+ v->x = x;
+ v->y = y;
+}
+
+static inline void cgm_vmul_m3v3(cgm_vec3 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[4] + v->z * m[8];
+ float y = v->x * m[1] + v->y * m[5] + v->z * m[9];
+ v->z = v->x * m[2] + v->y * m[6] + v->z * m[10];
+ v->x = x;
+ v->y = y;
+}
+
+static inline void cgm_vmul_v3m3(cgm_vec3 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[1] + v->z * m[2];
+ float y = v->x * m[4] + v->y * m[5] + v->z * m[6];
+ v->z = v->x * m[8] + v->y * m[9] + v->z * m[10];
+ v->x = x;
+ v->y = y;
+}
+
+static inline float cgm_vdot(const cgm_vec3 *a, const cgm_vec3 *b)
+{
+ return a->x * b->x + a->y * b->y + a->z * b->z;
+}
+
+static inline void cgm_vcross(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b)
+{
+ res->x = a->y * b->z - a->z * b->y;
+ res->y = a->z * b->x - a->x * b->z;
+ res->z = a->x * b->y - a->y * b->x;
+}
+
+static inline float cgm_vlength(const cgm_vec3 *v)
+{
+ return sqrt(v->x * v->x + v->y * v->y + v->z * v->z);
+}
+
+static inline float cgm_vlength_sq(const cgm_vec3 *v)
+{
+ return v->x * v->x + v->y * v->y + v->z * v->z;
+}
+
+static inline float cgm_vdist(const cgm_vec3 *a, const cgm_vec3 *b)
+{
+ float dx = a->x - b->x;
+ float dy = a->y - b->y;
+ float dz = a->z - b->z;
+ return sqrt(dx * dx + dy * dy + dz * dz);
+}
+
+static inline float cgm_vdist_sq(const cgm_vec3 *a, const cgm_vec3 *b)
+{
+ float dx = a->x - b->x;
+ float dy = a->y - b->y;
+ float dz = a->z - b->z;
+ return dx * dx + dy * dy + dz * dz;
+}
+
+static inline void cgm_vnormalize(cgm_vec3 *v)
+{
+ float len = cgm_vlength(v);
+ if(len != 0.0f) {
+ float s = 1.0f / len;
+ v->x *= s;
+ v->y *= s;
+ v->z *= s;
+ }
+}
+
+static inline void cgm_vreflect(cgm_vec3 *v, const cgm_vec3 *n)
+{
+ float ndotv2 = cgm_vdot(v, n) * 2.0f;
+ v->x -= n->x * ndotv2;
+ v->y -= n->y * ndotv2;
+ v->z -= n->z * ndotv2;
+}
+
+static inline void cgm_vrefract(cgm_vec3 *v, const cgm_vec3 *n, float ior)
+{
+ float ndotv = cgm_vdot(v, n);
+ float k = 1.0f - ior * ior * (1.0f - ndotv * ndotv);
+ if(k < 0.0f) {
+ cgm_vreflect(v, n); /* TIR */
+ } else {
+ float sqrt_k = sqrt(k);
+ v->x = ior * v->x - (ior * ndotv + sqrt_k) * n->x;
+ v->y = ior * v->y - (ior * ndotv + sqrt_k) * n->y;
+ v->z = ior * v->z - (ior * ndotv + sqrt_k) * n->z;
+ }
+}
+
+static inline void cgm_vrotate_quat(cgm_vec3 *v, const cgm_quat *q)
+{
+ cgm_quat vq, inv_q = *q, tmp_q = *q;
+
+ cgm_qcons(&vq, v->x, v->y, v->z, 0.0f);
+ cgm_qinvert(&inv_q);
+ cgm_qmul(&tmp_q, &vq);
+ cgm_qmul(&vq, &inv_q);
+ cgm_vcons(v, vq.x, vq.y, vq.z);
+}
+
+static inline void cgm_vrotate_axis(cgm_vec3 *v, const cgm_vec3 *axis, float angle)
+{
+ float m[16];
+ cgm_mrotation_axis(m, axis, angle);
+ cgm_vmul_m3v3(v, m);
+}
+
+static inline void cgm_vrotate_euler(cgm_vec3 *v, const cgm_vec3 *euler, enum cgm_euler_mode mode)
+{
+ float m[16];
+ cgm_mrotation_euler(m, euler, mode);
+ cgm_vmul_m3v3(v, m);
+}
+
+static inline void cgm_vlerp(cgm_vec3 *res, const cgm_vec3 *a, const cgm_vec3 *b, float t)
+{
+ res->x = a->x * (b->x - a->x) * t;
+ res->y = a->y * (b->y - a->y) * t;
+ res->z = a->z * (b->z - a->z) * t;
+}
--- /dev/null
+static inline void cgm_wcons(cgm_vec4 *v, float x, float y, float z, float w)
+{
+ v->x = x;
+ v->y = y;
+ v->z = z;
+ v->w = w;
+}
+
+static inline void cgm_wadd(cgm_vec4 *a, const cgm_vec4 *b)
+{
+ a->x += b->x;
+ a->y += b->y;
+ a->z += b->z;
+ a->w += b->w;
+}
+
+static inline void cgm_wsub(cgm_vec4 *a, const cgm_vec4 *b)
+{
+ a->x -= b->x;
+ a->y -= b->y;
+ a->z -= b->z;
+ a->w -= b->w;
+}
+
+static inline void cgm_wmul(cgm_vec4 *a, const cgm_vec4 *b)
+{
+ a->x *= b->x;
+ a->y *= b->y;
+ a->z *= b->z;
+ a->w *= b->w;
+}
+
+static inline void cgm_wscale(cgm_vec4 *v, float s)
+{
+ v->x *= s;
+ v->y *= s;
+ v->z *= s;
+ v->w *= s;
+}
+
+static inline void cgm_wmul_m4v4(cgm_vec4 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + v->w * m[12];
+ float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + v->w * m[13];
+ float z = v->x * m[2] + v->y * m[6] + v->z * m[10] + v->w * m[14];
+ v->w = v->x * m[3] + v->y * m[7] + v->z * m[11] + v->w * m[15];
+ v->x = x;
+ v->y = y;
+ v->z = z;
+}
+
+static inline void cgm_wmul_v4m4(cgm_vec4 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + v->w * m[3];
+ float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + v->w * m[7];
+ float z = v->x * m[8] + v->y * m[9] + v->z * m[10] + v->w * m[11];
+ v->w = v->x * m[12] + v->y * m[13] + v->z * m[14] + v->w * m[15];
+ v->x = x;
+ v->y = y;
+ v->z = z;
+}
+
+static inline void cgm_wmul_m34v4(cgm_vec4 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[4] + v->z * m[8] + v->w * m[12];
+ float y = v->x * m[1] + v->y * m[5] + v->z * m[9] + v->w * m[13];
+ v->z = v->x * m[2] + v->y * m[6] + v->z * m[10] + v->w * m[14];
+ v->x = x;
+ v->y = y;
+}
+
+static inline void cgm_wmul_v4m43(cgm_vec4 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[1] + v->z * m[2] + v->w * m[3];
+ float y = v->x * m[4] + v->y * m[5] + v->z * m[6] + v->w * m[7];
+ v->z = v->x * m[8] + v->y * m[9] + v->z * m[10] + v->w * m[11];
+ v->x = x;
+ v->y = y;
+}
+
+static inline void cgm_wmul_m3v4(cgm_vec4 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[4] + v->z * m[8];
+ float y = v->x * m[1] + v->y * m[5] + v->z * m[9];
+ v->z = v->x * m[2] + v->y * m[6] + v->z * m[10];
+ v->x = x;
+ v->y = y;
+}
+
+static inline void cgm_wmul_v4m3(cgm_vec4 *v, const float *m)
+{
+ float x = v->x * m[0] + v->y * m[1] + v->z * m[2];
+ float y = v->x * m[4] + v->y * m[5] + v->z * m[6];
+ v->z = v->x * m[8] + v->y * m[9] + v->z * m[10];
+ v->x = x;
+ v->y = y;
+}
+
+static inline float cgm_wlength(const cgm_vec4 *v)
+{
+ return sqrt(v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w);
+}
+
+static inline float cgm_wlength_sq(const cgm_vec4 *v)
+{
+ return v->x * v->x + v->y * v->y + v->z * v->z + v->w * v->w;
+}
+
+static inline float cgm_wdist(const cgm_vec4 *a, const cgm_vec4 *b)
+{
+ float dx = a->x - b->x;
+ float dy = a->y - b->y;
+ float dz = a->z - b->z;
+ float dw = a->w - b->w;
+ return sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
+}
+
+static inline float cgm_wdist_sq(const cgm_vec4 *a, const cgm_vec4 *b)
+{
+ float dx = a->x - b->x;
+ float dy = a->y - b->y;
+ float dz = a->z - b->z;
+ float dw = a->w - b->w;
+ return dx * dx + dy * dy + dz * dz + dw * dw;
+}
+
+static inline void cgm_wnormalize(cgm_vec4 *v)
+{
+ float len = cgm_wlength(v);
+ if(len != 0.0f) {
+ float s = 1.0f / len;
+ v->x *= s;
+ v->y *= s;
+ v->z *= s;
+ v->w *= s;
+ }
+}
+
+static inline void cgm_wlerp(cgm_vec4 *res, const cgm_vec4 *a, const cgm_vec4 *b, float t)
+{
+ res->x = a->x + (b->x - a->x) * t;
+ res->y = a->y + (b->y - a->y) * t;
+ res->z = a->z + (b->z - a->z) * t;
+ res->w = a->w + (b->w - a->w) * t;
+}