123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757 |
-
- /******************************************************************************\
- | OpenGL 4 Example Code. |
- | Accompanies written series "Anton's OpenGL 4 Tutorials" |
- | Email: anton at antongerdelan dot net |
- | First version 27 Jan 2014 |
- | Copyright Dr Anton Gerdelan, Trinity College Dublin, Ireland. |
- | See individual libraries' separate legal notices |
- |******************************************************************************|
- | Commonly-used maths structures and functions |
- | Simple-as-possible. No disgusting templates. |
- | Structs vec3, mat4, versor. just hold arrays of floats called "v","m","q", |
- | respectively. So, for example, to get values from a mat4 do: my_mat.m |
- | A versor is the proper name for a unit quaternion. |
- \******************************************************************************/
- #include "mathfuncs.h"
- #include <stdio.h>
- #define _USE_MATH_DEFINES
- #include <math.h>
-
- /*--------------------------------CONSTRUCTORS--------------------------------*/
- vec2::vec2 () {}
-
- vec2::vec2 (float x, float y) {
- v[0] = x;
- v[1] = y;
- }
-
- vec3::vec3 () {}
-
- vec3::vec3 (float x, float y, float z) {
- v[0] = x;
- v[1] = y;
- v[2] = z;
- }
-
- vec3::vec3 (const vec2& vv, float z) {
- v[0] = vv.v[0];
- v[1] = vv.v[1];
- v[2] = z;
- }
-
- vec3::vec3 (const vec4& vv) {
- v[0] = vv.v[0];
- v[1] = vv.v[1];
- v[2] = vv.v[2];
- }
-
- vec4::vec4 () {}
-
- vec4::vec4 (float x, float y, float z, float w) {
- v[0] = x;
- v[1] = y;
- v[2] = z;
- v[3] = w;
- }
-
- vec4::vec4 (const vec2& vv, float z, float w) {
- v[0] = vv.v[0];
- v[1] = vv.v[1];
- v[2] = z;
- v[3] = w;
- }
-
- vec4::vec4 (const vec3& vv, float w) {
- v[0] = vv.v[0];
- v[1] = vv.v[1];
- v[2] = vv.v[2];
- v[3] = w;
- }
-
- mat3::mat3 () {}
-
- /* note: entered in COLUMNS */
- mat3::mat3 (float a, float b, float c,
- float d, float e, float f,
- float g, float h, float i) {
- m[0] = a;
- m[1] = b;
- m[2] = c;
- m[3] = d;
- m[4] = e;
- m[5] = f;
- m[6] = g;
- m[7] = h;
- m[8] = i;
- }
-
- mat4::mat4 () {}
-
- /* note: entered in COLUMNS */
- mat4::mat4 (float a, float b, float c, float d,
- float e, float f, float g, float h,
- float i, float j, float k, float l,
- float mm, float n, float o, float p) {
- m[0] = a;
- m[1] = b;
- m[2] = c;
- m[3] = d;
- m[4] = e;
- m[5] = f;
- m[6] = g;
- m[7] = h;
- m[8] = i;
- m[9] = j;
- m[10] = k;
- m[11] = l;
- m[12] = mm;
- m[13] = n;
- m[14] = o;
- m[15] = p;
- }
-
- /*-----------------------------PRINT FUNCTIONS--------------------------------*/
- void print (const vec2& v) {
- printf ("[%.2f, %.2f]\n", v.v[0], v.v[1]);
- }
-
- void print (const vec3& v) {
- printf ("[%.2f, %.2f, %.2f]\n", v.v[0], v.v[1], v.v[2]);
- }
-
- void print (const vec4& v) {
- printf ("[%.2f, %.2f, %.2f, %.2f]\n", v.v[0], v.v[1], v.v[2], v.v[3]);
- }
-
- void print (const mat3& m) {
- printf("\n");
- printf ("[%.2f][%.2f][%.2f]\n", m.m[0], m.m[3], m.m[6]);
- printf ("[%.2f][%.2f][%.2f]\n", m.m[1], m.m[4], m.m[7]);
- printf ("[%.2f][%.2f][%.2f]\n", m.m[2], m.m[5], m.m[8]);
- }
-
- void print (const mat4& m) {
- printf("\n");
- printf ("[%.2f][%.2f][%.2f][%.2f]\n", m.m[0], m.m[4], m.m[8], m.m[12]);
- printf ("[%.2f][%.2f][%.2f][%.2f]\n", m.m[1], m.m[5], m.m[9], m.m[13]);
- printf ("[%.2f][%.2f][%.2f][%.2f]\n", m.m[2], m.m[6], m.m[10], m.m[14]);
- printf ("[%.2f][%.2f][%.2f][%.2f]\n", m.m[3], m.m[7], m.m[11], m.m[15]);
- }
-
- /*--------------------------FLOATING POINT FUNCTIONS--------------------------*/
- int signum(const float& f) {
- return (f > 0.0f) ? 1 : (f < 0.0f) ? -1 : 0;
- }
-
- float intbound(const float& s, const float& ds) {
- if (ds < 0) {
- return intbound(-s, -ds);
- } else {
- float ss = mod(s, 1);
- return (1-ss)/ds;
- }
- }
-
- float mod(const float& value, const float& modulus) {
- return fmod((fmod(value, modulus) + modulus), modulus);
- }
-
- /*------------------------------VECTOR FUNCTIONS------------------------------*/
- float length (const vec3& v) {
- return sqrt (v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2]);
- }
-
- // squared length
- float length2 (const vec3& v) {
- return v.v[0] * v.v[0] + v.v[1] * v.v[1] + v.v[2] * v.v[2];
- }
-
- // note: proper spelling (hehe)
- vec3 normalise (const vec3& v) {
- vec3 vb;
- float l = length (v);
- if (0.0f == l) {
- return vec3 (0.0f, 0.0f, 0.0f);
- }
- vb.v[0] = v.v[0] / l;
- vb.v[1] = v.v[1] / l;
- vb.v[2] = v.v[2] / l;
- return vb;
- }
-
- vec3 vec3::operator+ (const vec3& rhs) {
- vec3 vc;
- vc.v[0] = v[0] + rhs.v[0];
- vc.v[1] = v[1] + rhs.v[1];
- vc.v[2] = v[2] + rhs.v[2];
- return vc;
- }
-
- vec3& vec3::operator+= (const vec3& rhs) {
- v[0] += rhs.v[0];
- v[1] += rhs.v[1];
- v[2] += rhs.v[2];
- return *this; // return self
- }
-
- vec3 vec3::operator- (const vec3& rhs) {
- vec3 vc;
- vc.v[0] = v[0] - rhs.v[0];
- vc.v[1] = v[1] - rhs.v[1];
- vc.v[2] = v[2] - rhs.v[2];
- return vc;
- }
-
- vec3& vec3::operator-= (const vec3& rhs) {
- v[0] -= rhs.v[0];
- v[1] -= rhs.v[1];
- v[2] -= rhs.v[2];
- return *this;
- }
-
- vec3 vec3::operator+ (float rhs) {
- vec3 vc;
- vc.v[0] = v[0] + rhs;
- vc.v[1] = v[1] + rhs;
- vc.v[2] = v[2] + rhs;
- return vc;
- }
-
- vec3 vec3::operator- (float rhs) {
- vec3 vc;
- vc.v[0] = v[0] - rhs;
- vc.v[1] = v[1] - rhs;
- vc.v[2] = v[2] - rhs;
- return vc;
- }
-
- vec3 vec3::operator* (float rhs) {
- vec3 vc;
- vc.v[0] = v[0] * rhs;
- vc.v[1] = v[1] * rhs;
- vc.v[2] = v[2] * rhs;
- return vc;
- }
-
- vec3 vec3::operator/ (float rhs) {
- vec3 vc;
- vc.v[0] = v[0] / rhs;
- vc.v[1] = v[1] / rhs;
- vc.v[2] = v[2] / rhs;
- return vc;
- }
-
- vec3& vec3::operator*= (float rhs) {
- v[0] = v[0] * rhs;
- v[1] = v[1] * rhs;
- v[2] = v[2] * rhs;
- return *this;
- }
-
- vec3& vec3::operator= (const vec3& rhs) {
- v[0] = rhs.v[0];
- v[1] = rhs.v[1];
- v[2] = rhs.v[2];
- return *this;
- }
-
- float dot (const vec3& a, const vec3& b) {
- return a.v[0] * b.v[0] + a.v[1] * b.v[1] + a.v[2] * b.v[2];
- }
-
- vec3 cross (const vec3& a, const vec3& b) {
- float x = a.v[1] * b.v[2] - a.v[2] * b.v[1];
- float y = a.v[2] * b.v[0] - a.v[0] * b.v[2];
- float z = a.v[0] * b.v[1] - a.v[1] * b.v[0];
- return vec3 (x, y, z);
- }
-
- float get_squared_dist (vec3 from, vec3 to) {
- float x = (to.v[0] - from.v[0]) * (to.v[0] - from.v[0]);
- float y = (to.v[1] - from.v[1]) * (to.v[1] - from.v[1]);
- float z = (to.v[2] - from.v[2]) * (to.v[2] - from.v[2]);
- return x + y + z;
- }
-
- /* converts an un-normalised direction into a heading in degrees
- NB i suspect that the z is backwards here but i've used in in
- several places like this. d'oh! */
- float direction_to_heading (vec3 d) {
- return atan2 (-d.v[0], -d.v[2]) * ONE_RAD_IN_DEG;
- }
-
- vec3 heading_to_direction (float degrees) {
- float rad = degrees * ONE_DEG_IN_RAD;
- return vec3 (-sinf (rad), 0.0f, -cosf (rad));
- }
-
- /*-----------------------------MATRIX FUNCTIONS-------------------------------*/
- mat3 zero_mat3 () {
- return mat3 (
- 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f
- );
- }
-
- mat3 identity_mat3 () {
- return mat3 (
- 1.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 1.0f
- );
- }
-
- mat4 zero_mat4 () {
- return mat4 (
- 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
- );
- }
-
- mat4 identity_mat4 () {
- return mat4 (
- 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
- );
- }
-
- /* mat4 array layout
- 0 4 8 12
- 1 5 9 13
- 2 6 10 14
- 3 7 11 15
- */
-
- vec4 mat4::operator* (const vec4& rhs) {
- // 0x + 4y + 8z + 12w
- float x =
- m[0] * rhs.v[0] +
- m[4] * rhs.v[1] +
- m[8] * rhs.v[2] +
- m[12] * rhs.v[3];
- // 1x + 5y + 9z + 13w
- float y = m[1] * rhs.v[0] +
- m[5] * rhs.v[1] +
- m[9] * rhs.v[2] +
- m[13] * rhs.v[3];
- // 2x + 6y + 10z + 14w
- float z = m[2] * rhs.v[0] +
- m[6] * rhs.v[1] +
- m[10] * rhs.v[2] +
- m[14] * rhs.v[3];
- // 3x + 7y + 11z + 15w
- float w = m[3] * rhs.v[0] +
- m[7] * rhs.v[1] +
- m[11] * rhs.v[2] +
- m[15] * rhs.v[3];
- return vec4 (x, y, z, w);
- }
-
- mat4 mat4::operator* (const mat4& rhs) {
- mat4 r = zero_mat4 ();
- int r_index = 0;
- for (int col = 0; col < 4; col++) {
- for (int row = 0; row < 4; row++) {
- float sum = 0.0f;
- for (int i = 0; i < 4; i++) {
- sum += rhs.m[i + col * 4] * m[row + i * 4];
- }
- r.m[r_index] = sum;
- r_index++;
- }
- }
- return r;
- }
-
- mat4& mat4::operator= (const mat4& rhs) {
- for (int i = 0; i < 16; i++) {
- m[i] = rhs.m[i];
- }
- return *this;
- }
-
- // returns a scalar value with the determinant for a 4x4 matrix
- // see http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/fourD/index.htm
- float determinant (const mat4& mm) {
- return
- mm.m[12] * mm.m[9] * mm.m[6] * mm.m[3] -
- mm.m[8] * mm.m[13] * mm.m[6] * mm.m[3] -
- mm.m[12] * mm.m[5] * mm.m[10] * mm.m[3] +
- mm.m[4] * mm.m[13] * mm.m[10] * mm.m[3] +
- mm.m[8] * mm.m[5] * mm.m[14] * mm.m[3] -
- mm.m[4] * mm.m[9] * mm.m[14] * mm.m[3] -
- mm.m[12] * mm.m[9] * mm.m[2] * mm.m[7] +
- mm.m[8] * mm.m[13] * mm.m[2] * mm.m[7] +
- mm.m[12] * mm.m[1] * mm.m[10] * mm.m[7] -
- mm.m[0] * mm.m[13] * mm.m[10] * mm.m[7] -
- mm.m[8] * mm.m[1] * mm.m[14] * mm.m[7] +
- mm.m[0] * mm.m[9] * mm.m[14] * mm.m[7] +
- mm.m[12] * mm.m[5] * mm.m[2] * mm.m[11] -
- mm.m[4] * mm.m[13] * mm.m[2] * mm.m[11] -
- mm.m[12] * mm.m[1] * mm.m[6] * mm.m[11] +
- mm.m[0] * mm.m[13] * mm.m[6] * mm.m[11] +
- mm.m[4] * mm.m[1] * mm.m[14] * mm.m[11] -
- mm.m[0] * mm.m[5] * mm.m[14] * mm.m[11] -
- mm.m[8] * mm.m[5] * mm.m[2] * mm.m[15] +
- mm.m[4] * mm.m[9] * mm.m[2] * mm.m[15] +
- mm.m[8] * mm.m[1] * mm.m[6] * mm.m[15] -
- mm.m[0] * mm.m[9] * mm.m[6] * mm.m[15] -
- mm.m[4] * mm.m[1] * mm.m[10] * mm.m[15] +
- mm.m[0] * mm.m[5] * mm.m[10] * mm.m[15];
- }
-
- /* returns a 16-element array that is the inverse of a 16-element array (4x4
- matrix). see http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm */
- mat4 inverse (const mat4& mm) {
- float det = determinant (mm);
- /* there is no inverse if determinant is zero (not likely unless scale is
- broken) */
- if (0.0f == det) {
- fprintf (stderr, "WARNING. matrix has no determinant. can not invert\n");
- return mm;
- }
- float inv_det = 1.0f / det;
-
- return mat4 (
- inv_det * (
- mm.m[9] * mm.m[14] * mm.m[7] - mm.m[13] * mm.m[10] * mm.m[7] +
- mm.m[13] * mm.m[6] * mm.m[11] - mm.m[5] * mm.m[14] * mm.m[11] -
- mm.m[9] * mm.m[6] * mm.m[15] + mm.m[5] * mm.m[10] * mm.m[15]
- ),
- inv_det * (
- mm.m[13] * mm.m[10] * mm.m[3] - mm.m[9] * mm.m[14] * mm.m[3] -
- mm.m[13] * mm.m[2] * mm.m[11] + mm.m[1] * mm.m[14] * mm.m[11] +
- mm.m[9] * mm.m[2] * mm.m[15] - mm.m[1] * mm.m[10] * mm.m[15]
- ),
- inv_det * (
- mm.m[5] * mm.m[14] * mm.m[3] - mm.m[13] * mm.m[6] * mm.m[3] +
- mm.m[13] * mm.m[2] * mm.m[7] - mm.m[1] * mm.m[14] * mm.m[7] -
- mm.m[5] * mm.m[2] * mm.m[15] + mm.m[1] * mm.m[6] * mm.m[15]
- ),
- inv_det * (
- mm.m[9] * mm.m[6] * mm.m[3] - mm.m[5] * mm.m[10] * mm.m[3] -
- mm.m[9] * mm.m[2] * mm.m[7] + mm.m[1] * mm.m[10] * mm.m[7] +
- mm.m[5] * mm.m[2] * mm.m[11] - mm.m[1] * mm.m[6] * mm.m[11]
- ),
- inv_det * (
- mm.m[12] * mm.m[10] * mm.m[7] - mm.m[8] * mm.m[14] * mm.m[7] -
- mm.m[12] * mm.m[6] * mm.m[11] + mm.m[4] * mm.m[14] * mm.m[11] +
- mm.m[8] * mm.m[6] * mm.m[15] - mm.m[4] * mm.m[10] * mm.m[15]
- ),
- inv_det * (
- mm.m[8] * mm.m[14] * mm.m[3] - mm.m[12] * mm.m[10] * mm.m[3] +
- mm.m[12] * mm.m[2] * mm.m[11] - mm.m[0] * mm.m[14] * mm.m[11] -
- mm.m[8] * mm.m[2] * mm.m[15] + mm.m[0] * mm.m[10] * mm.m[15]
- ),
- inv_det * (
- mm.m[12] * mm.m[6] * mm.m[3] - mm.m[4] * mm.m[14] * mm.m[3] -
- mm.m[12] * mm.m[2] * mm.m[7] + mm.m[0] * mm.m[14] * mm.m[7] +
- mm.m[4] * mm.m[2] * mm.m[15] - mm.m[0] * mm.m[6] * mm.m[15]
- ),
- inv_det * (
- mm.m[4] * mm.m[10] * mm.m[3] - mm.m[8] * mm.m[6] * mm.m[3] +
- mm.m[8] * mm.m[2] * mm.m[7] - mm.m[0] * mm.m[10] * mm.m[7] -
- mm.m[4] * mm.m[2] * mm.m[11] + mm.m[0] * mm.m[6] * mm.m[11]
- ),
- inv_det * (
- mm.m[8] * mm.m[13] * mm.m[7] - mm.m[12] * mm.m[9] * mm.m[7] +
- mm.m[12] * mm.m[5] * mm.m[11] - mm.m[4] * mm.m[13] * mm.m[11] -
- mm.m[8] * mm.m[5] * mm.m[15] + mm.m[4] * mm.m[9] * mm.m[15]
- ),
- inv_det * (
- mm.m[12] * mm.m[9] * mm.m[3] - mm.m[8] * mm.m[13] * mm.m[3] -
- mm.m[12] * mm.m[1] * mm.m[11] + mm.m[0] * mm.m[13] * mm.m[11] +
- mm.m[8] * mm.m[1] * mm.m[15] - mm.m[0] * mm.m[9] * mm.m[15]
- ),
- inv_det * (
- mm.m[4] * mm.m[13] * mm.m[3] - mm.m[12] * mm.m[5] * mm.m[3] +
- mm.m[12] * mm.m[1] * mm.m[7] - mm.m[0] * mm.m[13] * mm.m[7] -
- mm.m[4] * mm.m[1] * mm.m[15] + mm.m[0] * mm.m[5] * mm.m[15]
- ),
- inv_det * (
- mm.m[8] * mm.m[5] * mm.m[3] - mm.m[4] * mm.m[9] * mm.m[3] -
- mm.m[8] * mm.m[1] * mm.m[7] + mm.m[0] * mm.m[9] * mm.m[7] +
- mm.m[4] * mm.m[1] * mm.m[11] - mm.m[0] * mm.m[5] * mm.m[11]
- ),
- inv_det * (
- mm.m[12] * mm.m[9] * mm.m[6] - mm.m[8] * mm.m[13] * mm.m[6] -
- mm.m[12] * mm.m[5] * mm.m[10] + mm.m[4] * mm.m[13] * mm.m[10] +
- mm.m[8] * mm.m[5] * mm.m[14] - mm.m[4] * mm.m[9] * mm.m[14]
- ),
- inv_det * (
- mm.m[8] * mm.m[13] * mm.m[2] - mm.m[12] * mm.m[9] * mm.m[2] +
- mm.m[12] * mm.m[1] * mm.m[10] - mm.m[0] * mm.m[13] * mm.m[10] -
- mm.m[8] * mm.m[1] * mm.m[14] + mm.m[0] * mm.m[9] * mm.m[14]
- ),
- inv_det * (
- mm.m[12] * mm.m[5] * mm.m[2] - mm.m[4] * mm.m[13] * mm.m[2] -
- mm.m[12] * mm.m[1] * mm.m[6] + mm.m[0] * mm.m[13] * mm.m[6] +
- mm.m[4] * mm.m[1] * mm.m[14] - mm.m[0] * mm.m[5] * mm.m[14]
- ),
- inv_det * (
- mm.m[4] * mm.m[9] * mm.m[2] - mm.m[8] * mm.m[5] * mm.m[2] +
- mm.m[8] * mm.m[1] * mm.m[6] - mm.m[0] * mm.m[9] * mm.m[6] -
- mm.m[4] * mm.m[1] * mm.m[10] + mm.m[0] * mm.m[5] * mm.m[10]
- )
- );
- }
-
- // returns a 16-element array flipped on the main diagonal
- mat4 transpose (const mat4& mm) {
- return mat4 (
- mm.m[0], mm.m[4], mm.m[8], mm.m[12],
- mm.m[1], mm.m[5], mm.m[9], mm.m[13],
- mm.m[2], mm.m[6], mm.m[10], mm.m[14],
- mm.m[3], mm.m[7], mm.m[11], mm.m[15]
- );
- }
-
- /*--------------------------AFFINE MATRIX FUNCTIONS---------------------------*/
- // translate a 4d matrix with xyz array
- mat4 translate (const mat4& m, const vec3& v) {
- mat4 m_t = identity_mat4 ();
- m_t.m[12] = v.v[0];
- m_t.m[13] = v.v[1];
- m_t.m[14] = v.v[2];
- return m_t * m;
- }
-
- // rotate around x axis by an angle in degrees
- mat4 rotate_x_deg (const mat4& m, float deg) {
- // convert to radians
- float rad = deg * ONE_DEG_IN_RAD;
- mat4 m_r = identity_mat4 ();
- m_r.m[5] = cos (rad);
- m_r.m[9] = -sin (rad);
- m_r.m[6] = sin (rad);
- m_r.m[10] = cos (rad);
- return m_r * m;
- }
-
- // rotate around y axis by an angle in degrees
- mat4 rotate_y_deg (const mat4& m, float deg) {
- // convert to radians
- float rad = deg * ONE_DEG_IN_RAD;
- mat4 m_r = identity_mat4 ();
- m_r.m[0] = cos (rad);
- m_r.m[8] = sin (rad);
- m_r.m[2] = -sin (rad);
- m_r.m[10] = cos (rad);
- return m_r * m;
- }
-
- // rotate around z axis by an angle in degrees
- mat4 rotate_z_deg (const mat4& m, float deg) {
- // convert to radians
- float rad = deg * ONE_DEG_IN_RAD;
- mat4 m_r = identity_mat4 ();
- m_r.m[0] = cos (rad);
- m_r.m[4] = -sin (rad);
- m_r.m[1] = sin (rad);
- m_r.m[5] = cos (rad);
- return m_r * m;
- }
-
- // scale a matrix by [x, y, z]
- mat4 scale (const mat4& m, const vec3& v) {
- mat4 a = identity_mat4 ();
- a.m[0] = v.v[0];
- a.m[5] = v.v[1];
- a.m[10] = v.v[2];
- return a * m;
- }
-
- /*-----------------------VIRTUAL CAMERA MATRIX FUNCTIONS----------------------*/
- // returns a view matrix using the opengl lookAt style. COLUMN ORDER.
- mat4 look_at (const vec3& cam_pos, vec3 targ_pos, const vec3& up) {
- // inverse translation
- mat4 p = identity_mat4 ();
- p = translate (p, vec3 (-cam_pos.v[0], -cam_pos.v[1], -cam_pos.v[2]));
- // distance vector
- vec3 d = targ_pos - cam_pos;
- // forward vector
- vec3 f = normalise (d);
- // right vector
- vec3 r = normalise (cross (f, up));
- // real up vector
- vec3 u = normalise (cross (r, f));
- mat4 ori = identity_mat4 ();
- ori.m[0] = r.v[0];
- ori.m[4] = r.v[1];
- ori.m[8] = r.v[2];
- ori.m[1] = u.v[0];
- ori.m[5] = u.v[1];
- ori.m[9] = u.v[2];
- ori.m[2] = -f.v[0];
- ori.m[6] = -f.v[1];
- ori.m[10] = -f.v[2];
-
- return ori * p;//p * ori;
- }
-
- // returns a perspective function mimicking the opengl projection style.
- mat4 perspective (float fovy, float aspect, float near, float far) {
- float fov_rad = fovy * ONE_DEG_IN_RAD;
- float range = tan (fov_rad / 2.0f) * near;
- float sx = (2.0f * near) / (range * aspect + range * aspect);
- float sy = near / range;
- float sz = -(far + near) / (far - near);
- float pz = -(2.0f * far * near) / (far - near);
- mat4 m = zero_mat4 (); // make sure bottom-right corner is zero
- m.m[0] = sx;
- m.m[5] = sy;
- m.m[10] = sz;
- m.m[14] = pz;
- m.m[11] = -1.0f;
- return m;
- }
-
- /*----------------------------HAMILTON IN DA HOUSE!---------------------------*/
- versor::versor () { }
-
- versor versor::operator/ (float rhs) {
- versor result;
- result.q[0] = q[0] / rhs;
- result.q[1] = q[1] / rhs;
- result.q[2] = q[2] / rhs;
- result.q[3] = q[3] / rhs;
- return result;
- }
-
- versor versor::operator* (float rhs) {
- versor result;
- result.q[0] = q[0] * rhs;
- result.q[1] = q[1] * rhs;
- result.q[2] = q[2] * rhs;
- result.q[3] = q[3] * rhs;
- return result;
- }
-
- void print (const versor& q) {
- printf ("[%.2f ,%.2f, %.2f, %.2f]\n", q.q[0], q.q[1], q.q[2], q.q[3]);
- }
-
- versor versor::operator* (const versor& rhs) {
- versor result;
- result.q[0] = rhs.q[0] * q[0] - rhs.q[1] * q[1] -
- rhs.q[2] * q[2] - rhs.q[3] * q[3];
- result.q[1] = rhs.q[0] * q[1] + rhs.q[1] * q[0] -
- rhs.q[2] * q[3] + rhs.q[3] * q[2];
- result.q[2] = rhs.q[0] * q[2] + rhs.q[1] * q[3] +
- rhs.q[2] * q[0] - rhs.q[3] * q[1];
- result.q[3] = rhs.q[0] * q[3] - rhs.q[1] * q[2] +
- rhs.q[2] * q[1] + rhs.q[3] * q[0];
- // re-normalise in case of mangling
- return normalise (result);
- }
-
- versor versor::operator+ (const versor& rhs) {
- versor result;
- result.q[0] = rhs.q[0] + q[0];
- result.q[1] = rhs.q[1] + q[1];
- result.q[2] = rhs.q[2] + q[2];
- result.q[3] = rhs.q[3] + q[3];
- // re-normalise in case of mangling
- return normalise (result);
- }
-
- versor quat_from_axis_rad (float radians, float x, float y, float z) {
- versor result;
- result.q[0] = cos (radians / 2.0);
- result.q[1] = sin (radians / 2.0) * x;
- result.q[2] = sin (radians / 2.0) * y;
- result.q[3] = sin (radians / 2.0) * z;
- return result;
- }
-
- versor quat_from_axis_deg (float degrees, float x, float y, float z) {
- return quat_from_axis_rad (ONE_DEG_IN_RAD * degrees, x, y, z);
- }
-
- mat4 quat_to_mat4 (const versor& q) {
- float w = q.q[0];
- float x = q.q[1];
- float y = q.q[2];
- float z = q.q[3];
- return mat4 (
- 1.0f - 2.0f * y * y - 2.0f * z * z,
- 2.0f * x * y + 2.0f * w * z,
- 2.0f * x * z - 2.0f * w * y,
- 0.0f,
- 2.0f * x * y - 2.0f * w * z,
- 1.0f - 2.0f * x * x - 2.0f * z * z,
- 2.0f * y * z + 2.0f * w * x,
- 0.0f,
- 2.0f * x * z + 2.0f * w * y,
- 2.0f * y * z - 2.0f * w * x,
- 1.0f - 2.0f * x * x - 2.0f * y * y,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f
- );
- }
-
- versor normalise (versor& q) {
- // norm(q) = q / magnitude (q)
- // magnitude (q) = sqrt (w*w + x*x...)
- // only compute sqrt if interior sum != 1.0
- float sum =
- q.q[0] * q.q[0] + q.q[1] * q.q[1] +
- q.q[2] * q.q[2] + q.q[3] * q.q[3];
- // NB: floats have min 6 digits of precision
- const float thresh = 0.0001f;
- if (fabs (1.0f - sum) < thresh) {
- return q;
- }
- float mag = sqrt (sum);
- return q / mag;
- }
-
- float dot (const versor& q, const versor& r) {
- return q.q[0] * r.q[0] + q.q[1] * r.q[1] + q.q[2] * r.q[2] + q.q[3] * r.q[3];
- }
-
- versor slerp (versor& q, versor& r, float t) {
- // angle between q0-q1
- float cos_half_theta = dot (q, r);
- // as found here http://stackoverflow.com/questions/2886606/flipping-issue-when-interpolating-rotations-using-quaternions
- // if dot product is negative then one quaternion should be negated, to make
- // it take the short way around, rather than the long way
- // yeah! and furthermore Susan, I had to recalculate the d.p. after this
- if (cos_half_theta < 0.0f) {
- for (int i = 0; i < 4; i++) {
- q.q[i] *= -1.0f;
- }
- cos_half_theta = dot (q, r);
- }
- // if qa=qb or qa=-qb then theta = 0 and we can return qa
- if (fabs (cos_half_theta) >= 1.0f) {
- return q;
- }
- // Calculate temporary values
- float sin_half_theta = sqrt (1.0f - cos_half_theta * cos_half_theta);
- // if theta = 180 degrees then result is not fully defined
- // we could rotate around any axis normal to qa or qb
- versor result;
- if (fabs (sin_half_theta) < 0.001f) {
- for (int i = 0; i < 4; i++) {
- result.q[i] = (1.0f - t) * q.q[i] + t * r.q[i];
- }
- return result;
- }
- float half_theta = acos (cos_half_theta);
- float a = sin ((1.0f - t) * half_theta) / sin_half_theta;
- float b = sin (t * half_theta) / sin_half_theta;
- for (int i = 0; i < 4; i++) {
- result.q[i] = q.q[i] * a + r.q[i] * b;
- }
- return result;
- }
|