Skip to content

Instantly share code, notes, and snippets.

@warmwaffles
Last active November 8, 2015 17:32
Show Gist options
  • Save warmwaffles/af0a67a7bba1196b4c54 to your computer and use it in GitHub Desktop.
Save warmwaffles/af0a67a7bba1196b4c54 to your computer and use it in GitHub Desktop.
#ifndef _COMMON_H
#define _COMMON_H
#include <math.h>
#define square(v) ((v) * (v))
#define cube(v) ((v) * (v) * (v))
#define deg_to_rad(deg) ((deg) * (M_PI / 180.0))
#define rad_to_deg(rad) ((rad) * (180.0 / M_PI))
#define dbl_is_near(expected, actual, epsilon) ((fabs((expected) - (actual)) <= (epsilon)) ? 1 : 0)
typedef enum
{
VX = 0, VY = 1, VZ = 2, VU = 3, VV = 4, VW = 5
} vertex_e;
#endif
#ifndef GL_MATRIX_H
#define GL_MATRIX_H
#include "vec3.h"
#include "mat3.h"
#include "mat4.h"
#include "quat.h"
#include "vec4.h"
#endif
#include <stdlib.h>
#include <math.h>
#include "mat3.h"
//
// 3 x 3 matrix
//
// double b00 = mat[M3_00];
// double b01 = mat[M3_01];
// double b02 = mat[M3_02];
// double b10 = mat[M3_10];
// double b11 = mat[M3_11];
// double b12 = mat[M3_12];
// double b20 = mat[M3_20];
// double b21 = mat[M3_21];
// double b22 = mat[M3_22];
//
mat3_t mat3_create(mat3_t mat)
{
mat3_t dest = calloc(9, sizeof(double_t));
if (!dest) {
return NULL;
}
if (mat) {
mat3_set(mat, dest);
}
return dest;
}
void mat3_free(mat3_t mat)
{
free(mat);
}
void mat3_set(mat3_t mat, mat3_t dest)
{
dest[M3_00] = mat[M3_00];
dest[M3_01] = mat[M3_01];
dest[M3_02] = mat[M3_02];
dest[M3_10] = mat[M3_10];
dest[M3_11] = mat[M3_11];
dest[M3_12] = mat[M3_12];
dest[M3_20] = mat[M3_20];
dest[M3_21] = mat[M3_21];
dest[M3_22] = mat[M3_22];
}
mat3_t mat3_identity(mat3_t dest)
{
if (!dest) {
dest = mat3_create(NULL);
}
dest[M3_00] = 1;
dest[M3_01] = 0;
dest[M3_02] = 0;
dest[M3_10] = 0;
dest[M3_11] = 1;
dest[M3_12] = 0;
dest[M3_20] = 0;
dest[M3_21] = 0;
dest[M3_22] = 1;
return dest;
}
void mat3_transpose(mat3_t mat, mat3_t dest)
{
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (!dest || mat == dest) {
double a01 = mat[M3_01];
double a02 = mat[M3_02];
double a12 = mat[M3_12];
mat[M3_01] = mat[M3_10];
mat[M3_02] = mat[M3_20];
mat[M3_10] = a01;
mat[M3_12] = mat[M3_21];
mat[M3_20] = a02;
mat[M3_21] = a12;
return;
}
dest[M3_00] = mat[M3_00];
dest[M3_01] = mat[M3_10];
dest[M3_02] = mat[M3_20];
dest[M3_10] = mat[M3_01];
dest[M3_11] = mat[M3_11];
dest[M3_12] = mat[M3_21];
dest[M3_20] = mat[M3_02];
dest[M3_21] = mat[M3_12];
dest[M3_22] = mat[M3_22];
}
mat4_t mat3_to_mat4(mat3_t mat, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
dest[15] = 1;
dest[14] = 0;
dest[13] = 0;
dest[12] = 0;
dest[11] = 0;
dest[10] = mat[M3_22];
dest[9] = mat[M3_21];
dest[M3_22] = mat[M3_20];
dest[M3_21] = 0;
dest[M3_20] = mat[M3_12];
dest[M3_12] = mat[M3_11];
dest[M3_11] = mat[M3_10];
dest[M3_10] = 0;
dest[M3_02] = mat[M3_02];
dest[M3_01] = mat[M3_01];
dest[M3_00] = mat[M3_00];
return dest;
}
void mat3_mul_mat3(mat3_t mata, mat3_t matb, mat3_t dest)
{
if (!dest) {
dest = mata;
}
double v00 = mata[M3_00] * matb[M3_00] + mata[M3_01] * matb[M3_10] + mata[M3_02] * matb[M3_20];
double v01 = mata[M3_00] * matb[M3_01] + mata[M3_01] * matb[M3_11] + mata[M3_02] * matb[M3_21];
double v02 = mata[M3_00] * matb[M3_02] + mata[M3_01] * matb[M3_12] + mata[M3_02] * matb[M3_22];
double v10 = mata[M3_10] * matb[M3_00] + mata[M3_11] * matb[M3_10] + mata[M3_12] * matb[M3_20];
double v11 = mata[M3_10] * matb[M3_01] + mata[M3_11] * matb[M3_11] + mata[M3_12] * matb[M3_21];
double v12 = mata[M3_10] * matb[M3_02] + mata[M3_11] * matb[M3_12] + mata[M3_12] * matb[M3_22];
double v20 = mata[M3_20] * matb[M3_00] + mata[M3_21] * matb[M3_10] + mata[M3_22] * matb[M3_20];
double v21 = mata[M3_20] * matb[M3_01] + mata[M3_21] * matb[M3_11] + mata[M3_22] * matb[M3_21];
double v22 = mata[M3_20] * matb[M3_02] + mata[M3_21] * matb[M3_12] + mata[M3_22] * matb[M3_22];
dest[M3_00] = v00;
dest[M3_10] = v10;
dest[M3_20] = v20;
dest[M3_01] = v01;
dest[M3_11] = v11;
dest[M3_21] = v21;
dest[M3_02] = v02;
dest[M3_12] = v12;
dest[M3_22] = v22;
}
#ifndef _MAT3_H
#define _MAT3_H
typedef double *mat3_t;
typedef enum
{
M3_00 = 0, M3_01 = 1, M3_02 = 2, M3_10 = 3, M3_11 = 4, M3_12 = 5, M3_20 = 6, M3_21 = 7, M3_22 = 8
} mat3_pos;
#include "mat4.h"
#include "common.h"
/**
* Creates a new instance of a mat3_t
*
* Params:
* mat - Optional, mat3_t containing values to initialize with. If NULL the result
* will be initialized with zeroes.
*
* Returns:
* New mat3
*/
mat3_t mat3_create(mat3_t mat);
/**
* Frees a mat3_t
*
* @param mat
* The 3x3 matrix
*/
void mat3_free(mat3_t mat);
/**
* Copies the values of one mat3_t to another
*
* @param mat
* mat3_t containing values to copy
* @param dest
* mat3_t receiving copied values
*
*/
void mat3_set(mat3_t mat, mat3_t dest);
/**
* Sets a mat3_t to an identity matrix
*
* @param dest
* mat3_t to set
*
* @return If dest is NULL a new identity matrix is returned.
*/
mat3_t mat3_identity(mat3_t dest);
/**
* Transposes a mat3_t (flips the values over the diagonal)
*
* Params:
* mat - mat3_t to transpose
* dest - Optional, mat3_t receiving transposed values. If NULL, result is written to mat
*
*/
void mat3_transpose(mat3_t mat, mat3_t dest);
/**
* Copies the elements of a mat3_t into the upper 3x3 elements of a mat4
*
* Params:
* mat - mat3_t containing values to copy
* dest - Optional, mat4_t receiving copied values
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
mat4_t mat3_to_mat4(mat3_t mat, mat4_t dest);
void mat3_mul_mat3(mat3_t mata, mat3_t matb, mat3_t dest);
#endif
#include <stdlib.h>
#include <math.h>
#include "mat4.h"
//
// 4 x 4 matrix
//
// double a00 = mat[M4_00];
// double a01 = mat[M4_01];
// double a02 = mat[M4_02];
// double a03 = mat[M4_03];
// double a10 = mat[M4_10];
// double a11 = mat[M4_11];
// double a12 = mat[M4_12];
// double a13 = mat[M4_13];
// double a20 = mat[M4_20];
// double a21 = mat[M4_21];
// double a22 = mat[M4_22];
// double a23 = mat[M4_23];
// double a30 = mat[M4_30];
// double a31 = mat[M4_31];
// double a32 = mat[M4_32];
// double a33 = mat[M4_33];
//
mat4_t mat4_create(mat4_t mat)
{
mat4_t dest = calloc(16, sizeof(double_t));
if (mat) {
dest[M4_00] = mat[M4_00];
dest[M4_01] = mat[M4_01];
dest[M4_02] = mat[M4_02];
dest[M4_03] = mat[M4_03];
dest[M4_10] = mat[M4_10];
dest[M4_11] = mat[M4_11];
dest[M4_12] = mat[M4_12];
dest[M4_13] = mat[M4_13];
dest[M4_20] = mat[M4_20];
dest[M4_21] = mat[M4_21];
dest[M4_22] = mat[M4_22];
dest[M4_23] = mat[M4_23];
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
}
return dest;
}
void mat4_free(mat4_t mat)
{
free(mat);
}
mat4_t mat4_set(mat4_t mat, mat4_t dest)
{
dest[M4_00] = mat[M4_00];
dest[M4_01] = mat[M4_01];
dest[M4_02] = mat[M4_02];
dest[M4_03] = mat[M4_03];
dest[M4_10] = mat[M4_10];
dest[M4_11] = mat[M4_11];
dest[M4_12] = mat[M4_12];
dest[M4_13] = mat[M4_13];
dest[M4_20] = mat[M4_20];
dest[M4_21] = mat[M4_21];
dest[M4_22] = mat[M4_22];
dest[M4_23] = mat[M4_23];
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
return dest;
}
mat4_t mat4_identity(mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
dest[M4_00] = 1;
dest[M4_01] = 0;
dest[M4_02] = 0;
dest[M4_03] = 0;
dest[M4_10] = 0;
dest[M4_11] = 1;
dest[M4_12] = 0;
dest[M4_13] = 0;
dest[M4_20] = 0;
dest[M4_21] = 0;
dest[M4_22] = 1;
dest[M4_23] = 0;
dest[M4_30] = 0;
dest[M4_31] = 0;
dest[M4_32] = 0;
dest[M4_33] = 1;
return dest;
}
mat4_t mat4_transpose(mat4_t mat, mat4_t dest)
{
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (!dest || mat == dest) {
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a03 = mat[M4_03];
double a12 = mat[M4_12];
double a13 = mat[M4_13];
double a23 = mat[M4_23];
mat[M4_01] = mat[M4_10];
mat[M4_02] = mat[M4_20];
mat[M4_03] = mat[M4_30];
mat[M4_10] = a01;
mat[M4_12] = mat[M4_21];
mat[M4_13] = mat[M4_31];
mat[M4_20] = a02;
mat[M4_21] = a12;
mat[M4_23] = mat[M4_32];
mat[M4_30] = a03;
mat[M4_31] = a13;
mat[M4_32] = a23;
return mat;
}
dest[M4_00] = mat[M4_00];
dest[M4_01] = mat[M4_10];
dest[M4_02] = mat[M4_20];
dest[M4_03] = mat[M4_30];
dest[M4_10] = mat[M4_01];
dest[M4_11] = mat[M4_11];
dest[M4_12] = mat[M4_21];
dest[M4_13] = mat[M4_31];
dest[M4_20] = mat[M4_02];
dest[M4_21] = mat[M4_12];
dest[M4_22] = mat[M4_22];
dest[M4_23] = mat[M4_32];
dest[M4_30] = mat[M4_03];
dest[M4_31] = mat[M4_13];
dest[M4_32] = mat[M4_23];
dest[M4_33] = mat[M4_33];
return dest;
}
double mat4_determinant(mat4_t mat)
{
// Cache the matrix values (makes for huge speed increases!)
double a00 = mat[M4_00];
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a03 = mat[M4_03];
double a10 = mat[M4_10];
double a11 = mat[M4_11];
double a12 = mat[M4_12];
double a13 = mat[M4_13];
double a20 = mat[M4_20];
double a21 = mat[M4_21];
double a22 = mat[M4_22];
double a23 = mat[M4_23];
double a30 = mat[M4_30];
double a31 = mat[M4_31];
double a32 = mat[M4_32];
double a33 = mat[M4_33];
return (a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 +
a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 +
a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 +
a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 +
a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 +
a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33);
}
mat4_t mat4_inverse(mat4_t mat, mat4_t dest)
{
if (!dest) {
dest = mat;
}
// Cache the matrix values (makes for huge speed increases!)
double a00 = mat[M4_00];
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a03 = mat[M4_03];
double a10 = mat[M4_10];
double a11 = mat[M4_11];
double a12 = mat[M4_12];
double a13 = mat[M4_13];
double a20 = mat[M4_20];
double a21 = mat[M4_21];
double a22 = mat[M4_22];
double a23 = mat[M4_23];
double a30 = mat[M4_30];
double a31 = mat[M4_31];
double a32 = mat[M4_32];
double a33 = mat[M4_33];
double b00 = a00 * a11 - a01 * a10;
double b01 = a00 * a12 - a02 * a10;
double b02 = a00 * a13 - a03 * a10;
double b03 = a01 * a12 - a02 * a11;
double b04 = a01 * a13 - a03 * a11;
double b05 = a02 * a13 - a03 * a12;
double b06 = a20 * a31 - a21 * a30;
double b07 = a20 * a32 - a22 * a30;
double b08 = a20 * a33 - a23 * a30;
double b09 = a21 * a32 - a22 * a31;
double b10 = a21 * a33 - a23 * a31;
double b11 = a22 * a33 - a23 * a32;
double d = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
double inv_det;
// Calculate the determinant
if (!d) {
return NULL;
}
inv_det = 1 / d;
dest[M4_00] = (a11 * b11 - a12 * b10 + a13 * b09) * inv_det;
dest[M4_01] = (-a01 * b11 + a02 * b10 - a03 * b09) * inv_det;
dest[M4_02] = (a31 * b05 - a32 * b04 + a33 * b03) * inv_det;
dest[M4_03] = (-a21 * b05 + a22 * b04 - a23 * b03) * inv_det;
dest[M4_10] = (-a10 * b11 + a12 * b08 - a13 * b07) * inv_det;
dest[M4_11] = (a00 * b11 - a02 * b08 + a03 * b07) * inv_det;
dest[M4_12] = (-a30 * b05 + a32 * b02 - a33 * b01) * inv_det;
dest[M4_13] = (a20 * b05 - a22 * b02 + a23 * b01) * inv_det;
dest[M4_20] = (a10 * b10 - a11 * b08 + a13 * b06) * inv_det;
dest[M4_21] = (-a00 * b10 + a01 * b08 - a03 * b06) * inv_det;
dest[M4_22] = (a30 * b04 - a31 * b02 + a33 * b00) * inv_det;
dest[M4_23] = (-a20 * b04 + a21 * b02 - a23 * b00) * inv_det;
dest[M4_30] = (-a10 * b09 + a11 * b07 - a12 * b06) * inv_det;
dest[M4_31] = (a00 * b09 - a01 * b07 + a02 * b06) * inv_det;
dest[M4_32] = (-a30 * b03 + a31 * b01 - a32 * b00) * inv_det;
dest[M4_33] = (a20 * b03 - a21 * b01 + a22 * b00) * inv_det;
return dest;
}
mat4_t mat4_toRotationMat(mat4_t mat, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
dest[M4_00] = mat[M4_00];
dest[M4_01] = mat[M4_01];
dest[M4_02] = mat[M4_02];
dest[M4_03] = mat[M4_03];
dest[M4_10] = mat[M4_10];
dest[M4_11] = mat[M4_11];
dest[M4_12] = mat[M4_12];
dest[M4_13] = mat[M4_13];
dest[M4_20] = mat[M4_20];
dest[M4_21] = mat[M4_21];
dest[M4_22] = mat[M4_22];
dest[M4_23] = mat[M4_23];
dest[M4_30] = 0;
dest[M4_31] = 0;
dest[M4_32] = 0;
dest[M4_33] = 1;
return dest;
}
mat3_t mat4_to_mat3(mat4_t mat, mat3_t dest)
{
if (!dest) {
dest = mat3_create(NULL);
}
dest[M4_00] = mat[M4_00];
dest[M4_01] = mat[M4_01];
dest[M4_02] = mat[M4_02];
dest[M4_03] = mat[M4_10];
dest[M4_10] = mat[M4_11];
dest[M4_11] = mat[M4_12];
dest[M4_12] = mat[M4_20];
dest[M4_13] = mat[M4_21];
dest[M4_20] = mat[M4_22];
return dest;
}
mat3_t mat4_to_inverse_mat3(mat4_t mat, mat3_t dest)
{
// Cache the matrix values (makes for huge speed increases!)
double a00 = mat[M4_00];
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a10 = mat[M4_10];
double a11 = mat[M4_11];
double a12 = mat[M4_12];
double a20 = mat[M4_20];
double a21 = mat[M4_21];
double a22 = mat[M4_22];
double b01 = a22 * a11 - a12 * a21;
double b11 = -a22 * a10 + a12 * a20;
double b21 = a21 * a10 - a11 * a20;
double d = a00 * b01 + a01 * b11 + a02 * b21;
double id;
if (!d) {
return NULL;
}
id = 1 / d;
if (!dest) {
dest = mat3_create(NULL);
}
dest[M4_00] = b01 * id;
dest[M4_01] = (-a22 * a01 + a02 * a21) * id;
dest[M4_02] = (a12 * a01 - a02 * a11) * id;
dest[M4_03] = b11 * id;
dest[M4_10] = (a22 * a00 - a02 * a20) * id;
dest[M4_11] = (-a12 * a00 + a02 * a10) * id;
dest[M4_12] = b21 * id;
dest[M4_13] = (-a21 * a00 + a01 * a20) * id;
dest[M4_20] = (a11 * a00 - a01 * a10) * id;
return dest;
}
mat4_t mat4_multiply(mat4_t mat, mat4_t mat2, mat4_t dest)
{
if (!dest) {
dest = mat;
}
// Cache the matrix values (makes for huge speed increases!)
double a00 = mat[M4_00];
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a03 = mat[M4_03];
double a10 = mat[M4_10];
double a11 = mat[M4_11];
double a12 = mat[M4_12];
double a13 = mat[M4_13];
double a20 = mat[M4_20];
double a21 = mat[M4_21];
double a22 = mat[M4_22];
double a23 = mat[M4_23];
double a30 = mat[M4_30];
double a31 = mat[M4_31];
double a32 = mat[M4_32];
double a33 = mat[M4_33];
double b00 = mat2[M4_00];
double b01 = mat2[M4_01];
double b02 = mat2[M4_02];
double b03 = mat2[M4_03];
double b10 = mat2[M4_10];
double b11 = mat2[M4_11];
double b12 = mat2[M4_12];
double b13 = mat2[M4_13];
double b20 = mat2[M4_20];
double b21 = mat2[M4_21];
double b22 = mat2[M4_22];
double b23 = mat2[M4_23];
double b30 = mat2[M4_30];
double b31 = mat2[M4_31];
double b32 = mat2[M4_32];
double b33 = mat2[M4_33];
dest[M4_00] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
dest[M4_01] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
dest[M4_02] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
dest[M4_03] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
dest[M4_10] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
dest[M4_11] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
dest[M4_12] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
dest[M4_13] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
dest[M4_20] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
dest[M4_21] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
dest[M4_22] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
dest[M4_23] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
dest[M4_30] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
dest[M4_31] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
dest[M4_32] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
dest[M4_33] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
return dest;
}
mat4_t mat4_multiply_vec3(mat4_t mat, vec3_t vec, mat4_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[0], y = vec[1], z = vec[2];
dest[M4_00] = mat[M4_00] * x + mat[M4_10] * y + mat[M4_20] * z + mat[M4_30];
dest[M4_01] = mat[M4_01] * x + mat[M4_11] * y + mat[M4_21] * z + mat[M4_31];
dest[M4_02] = mat[M4_02] * x + mat[M4_12] * y + mat[M4_22] * z + mat[M4_32];
return dest;
}
mat4_t mat4_multiply_vec4(mat4_t mat, vec4_t vec, mat4_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[0];
double y = vec[1];
double z = vec[2];
double w = vec[4];
dest[M4_00] = mat[M4_00] * x + mat[M4_10] * y + mat[M4_20] * z + mat[M4_30] * w;
dest[M4_01] = mat[M4_01] * x + mat[M4_11] * y + mat[M4_21] * z + mat[M4_31] * w;
dest[M4_02] = mat[M4_02] * x + mat[M4_12] * y + mat[M4_22] * z + mat[M4_32] * w;
dest[M4_03] = mat[M4_03] * x + mat[M4_13] * y + mat[M4_23] * z + mat[M4_33] * w;
return dest;
}
mat4_t mat4_translate(mat4_t mat, vec3_t vec, mat4_t dest)
{
double x = vec[0];
double y = vec[1];
double z = vec[2];
double a00, a01, a02, a03, a10, a11, a12, a13, a20, a21, a22, a23;
if (!dest || mat == dest) {
mat[M4_30] = mat[M4_00] * x + mat[M4_10] * y + mat[M4_20] * z + mat[M4_30];
mat[M4_31] = mat[M4_01] * x + mat[M4_11] * y + mat[M4_21] * z + mat[M4_31];
mat[M4_32] = mat[M4_02] * x + mat[M4_12] * y + mat[M4_22] * z + mat[M4_32];
mat[M4_33] = mat[M4_03] * x + mat[M4_13] * y + mat[M4_23] * z + mat[M4_33];
return mat;
}
a00 = mat[M4_00];
a01 = mat[M4_01];
a02 = mat[M4_02];
a03 = mat[M4_03];
a10 = mat[M4_10];
a11 = mat[M4_11];
a12 = mat[M4_12];
a13 = mat[M4_13];
a20 = mat[M4_20];
a21 = mat[M4_21];
a22 = mat[M4_22];
a23 = mat[M4_23];
dest[M4_00] = a00;
dest[M4_01] = a01;
dest[M4_02] = a02;
dest[M4_03] = a03;
dest[M4_10] = a10;
dest[M4_11] = a11;
dest[M4_12] = a12;
dest[M4_13] = a13;
dest[M4_20] = a20;
dest[M4_21] = a21;
dest[M4_22] = a22;
dest[M4_23] = a23;
dest[M4_30] = a00 * x + a10 * y + a20 * z + mat[M4_30];
dest[M4_31] = a01 * x + a11 * y + a21 * z + mat[M4_31];
dest[M4_32] = a02 * x + a12 * y + a22 * z + mat[M4_32];
dest[M4_33] = a03 * x + a13 * y + a23 * z + mat[M4_33];
return dest;
}
mat4_t mat4_scale(mat4_t mat, vec3_t vec, mat4_t dest)
{
double x = vec[0];
double y = vec[1];
double z = vec[2];
if (!dest || mat == dest) {
mat[M4_00] *= x;
mat[M4_01] *= x;
mat[M4_02] *= x;
mat[M4_03] *= x;
mat[M4_10] *= y;
mat[M4_11] *= y;
mat[M4_12] *= y;
mat[M4_13] *= y;
mat[M4_20] *= z;
mat[M4_21] *= z;
mat[M4_22] *= z;
mat[M4_23] *= z;
return mat;
}
dest[M4_00] = mat[M4_00] * x;
dest[M4_01] = mat[M4_01] * x;
dest[M4_02] = mat[M4_02] * x;
dest[M4_03] = mat[M4_03] * x;
dest[M4_10] = mat[M4_10] * y;
dest[M4_11] = mat[M4_11] * y;
dest[M4_12] = mat[M4_12] * y;
dest[M4_13] = mat[M4_13] * y;
dest[M4_20] = mat[M4_20] * z;
dest[M4_21] = mat[M4_21] * z;
dest[M4_22] = mat[M4_22] * z;
dest[M4_23] = mat[M4_23] * z;
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
return dest;
}
mat4_t mat4_rotate(mat4_t mat, double angle, vec3_t axis, mat4_t dest)
{
double a00, a01, a02, a03, a10, a11, a12, a13, a20, a21, a22, a23;
double b00, b01, b02, b10, b11, b12, b20, b21, b22;
double x = axis[M4_00];
double y = axis[M4_01];
double z = axis[M4_02];
double len = sqrt(x * x + y * y + z * z);
double s, c, t;
if (!len) {
return NULL;
}
if (len != 1) {
len = 1 / len;
x *= len;
y *= len;
z *= len;
}
s = sin(angle);
c = cos(angle);
t = 1 - c;
a00 = mat[M4_00];
a01 = mat[M4_01];
a02 = mat[M4_02];
a03 = mat[M4_03];
a10 = mat[M4_10];
a11 = mat[M4_11];
a12 = mat[M4_12];
a13 = mat[M4_13];
a20 = mat[M4_20];
a21 = mat[M4_21];
a22 = mat[M4_22];
a23 = mat[M4_23];
// Construct the elements of the rotation matrix
b00 = x * x * t + c;
b01 = y * x * t + z * s;
b02 = z * x * t - y * s;
b10 = x * y * t - z * s;
b11 = y * y * t + c;
b12 = z * y * t + x * s;
b20 = x * z * t + y * s;
b21 = y * z * t - x * s;
b22 = z * z * t + c;
if (!dest) {
dest = mat;
} else if (mat != dest) { // If the source and destination differ, copy the unchanged last row
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
}
// Perform rotation-specific matrix multiplication
dest[M4_00] = a00 * b00 + a10 * b01 + a20 * b02;
dest[M4_01] = a01 * b00 + a11 * b01 + a21 * b02;
dest[M4_02] = a02 * b00 + a12 * b01 + a22 * b02;
dest[M4_03] = a03 * b00 + a13 * b01 + a23 * b02;
dest[M4_10] = a00 * b10 + a10 * b11 + a20 * b12;
dest[M4_11] = a01 * b10 + a11 * b11 + a21 * b12;
dest[M4_12] = a02 * b10 + a12 * b11 + a22 * b12;
dest[M4_13] = a03 * b10 + a13 * b11 + a23 * b12;
dest[M4_20] = a00 * b20 + a10 * b21 + a20 * b22;
dest[M4_21] = a01 * b20 + a11 * b21 + a21 * b22;
dest[M4_22] = a02 * b20 + a12 * b21 + a22 * b22;
dest[M4_23] = a03 * b20 + a13 * b21 + a23 * b22;
return dest;
}
mat4_t mat4_rotate_x(mat4_t mat, double angle, mat4_t dest)
{
double s = sin(angle);
double c = cos(angle);
double a10 = mat[M4_10];
double a11 = mat[M4_11];
double a12 = mat[M4_12];
double a13 = mat[M4_13];
double a20 = mat[M4_20];
double a21 = mat[M4_21];
double a22 = mat[M4_22];
double a23 = mat[M4_23];
if (!dest) {
dest = mat;
} else if (mat != dest) { // If the source and destination differ, copy the unchanged rows
dest[M4_00] = mat[M4_00];
dest[M4_01] = mat[M4_01];
dest[M4_02] = mat[M4_02];
dest[M4_03] = mat[M4_03];
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
}
// Perform axis-specific matrix multiplication
dest[M4_10] = a10 * c + a20 * s;
dest[M4_11] = a11 * c + a21 * s;
dest[M4_12] = a12 * c + a22 * s;
dest[M4_13] = a13 * c + a23 * s;
dest[M4_20] = a10 * -s + a20 * c;
dest[M4_21] = a11 * -s + a21 * c;
dest[M4_22] = a12 * -s + a22 * c;
dest[M4_23] = a13 * -s + a23 * c;
return dest;
}
mat4_t mat4_rotate_y(mat4_t mat, double angle, mat4_t dest)
{
double s = sin(angle);
double c = cos(angle);
double a00 = mat[M4_00];
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a03 = mat[M4_03];
double a20 = mat[M4_20];
double a21 = mat[M4_21];
double a22 = mat[M4_22];
double a23 = mat[M4_23];
if (!dest) {
dest = mat;
} else if (mat != dest) { // If the source and destination differ, copy the unchanged rows
dest[M4_10] = mat[M4_10];
dest[M4_11] = mat[M4_11];
dest[M4_12] = mat[M4_12];
dest[M4_13] = mat[M4_13];
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
}
// Perform axis-specific matrix multiplication
dest[M4_00] = a00 * c + a20 * -s;
dest[M4_01] = a01 * c + a21 * -s;
dest[M4_02] = a02 * c + a22 * -s;
dest[M4_03] = a03 * c + a23 * -s;
dest[M4_20] = a00 * s + a20 * c;
dest[M4_21] = a01 * s + a21 * c;
dest[M4_22] = a02 * s + a22 * c;
dest[M4_23] = a03 * s + a23 * c;
return dest;
}
mat4_t mat4_rotate_z(mat4_t mat, double angle, mat4_t dest)
{
double s = sin(angle);
double c = cos(angle);
double a00 = mat[M4_00];
double a01 = mat[M4_01];
double a02 = mat[M4_02];
double a03 = mat[M4_03];
double a10 = mat[M4_10];
double a11 = mat[M4_11];
double a12 = mat[M4_12];
double a13 = mat[M4_13];
if (!dest) {
dest = mat;
} else if (mat != dest) { // If the source and destination differ, copy the unchanged last row
dest[M4_20] = mat[M4_20];
dest[M4_21] = mat[M4_21];
dest[M4_22] = mat[M4_22];
dest[M4_23] = mat[M4_23];
dest[M4_30] = mat[M4_30];
dest[M4_31] = mat[M4_31];
dest[M4_32] = mat[M4_32];
dest[M4_33] = mat[M4_33];
}
// Perform axis-specific matrix multiplication
dest[M4_00] = a00 * c + a10 * s;
dest[M4_01] = a01 * c + a11 * s;
dest[M4_02] = a02 * c + a12 * s;
dest[M4_03] = a03 * c + a13 * s;
dest[M4_10] = a00 * -s + a10 * c;
dest[M4_11] = a01 * -s + a11 * c;
dest[M4_12] = a02 * -s + a12 * c;
dest[M4_13] = a03 * -s + a13 * c;
return dest;
}
mat4_t mat4_frustum(double left, double right, double bottom, double top, double near, double far, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
double rl = (right - left);
double tb = (top - bottom);
double fn = (far - near);
dest[M4_00] = (near * 2) / rl;
dest[M4_01] = 0;
dest[M4_02] = 0;
dest[M4_03] = 0;
dest[M4_10] = 0;
dest[M4_11] = (near * 2) / tb;
dest[M4_12] = 0;
dest[M4_13] = 0;
dest[M4_20] = (right + left) / rl;
dest[M4_21] = (top + bottom) / tb;
dest[M4_22] = -(far + near) / fn;
dest[M4_23] = -1;
dest[M4_30] = 0;
dest[M4_31] = 0;
dest[M4_32] = -(far * near * 2) / fn;
dest[M4_33] = 0;
return dest;
}
mat4_t mat4_perspective(double fovy, double aspect, double near, double far, mat4_t dest)
{
double top = near * tan(fovy * M_PI / 360.0);
double right = top * aspect;
return mat4_frustum(-right, right, -top, top, near, far, dest);
}
mat4_t mat4_ortho(double left, double right, double bottom, double top, double near, double far, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
double rl = (right - left);
double tb = (top - bottom);
double fn = (far - near);
dest[M4_00] = 2 / rl;
dest[M4_01] = 0;
dest[M4_02] = 0;
dest[M4_03] = 0;
dest[M4_10] = 0;
dest[M4_11] = 2 / tb;
dest[M4_12] = 0;
dest[M4_13] = 0;
dest[M4_20] = 0;
dest[M4_21] = 0;
dest[M4_22] = -2 / fn;
dest[M4_23] = 0;
dest[M4_30] = -(left + right) / rl;
dest[M4_31] = -(top + bottom) / tb;
dest[M4_32] = -(far + near) / fn;
dest[M4_33] = 1;
return dest;
}
mat4_t mat4_look_at(vec3_t eye, vec3_t center, vec3_t up, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
double x0, x1, x2, y0, y1, y2, z0, z1, z2;
double len;
double eyex = eye[0];
double eyey = eye[1];
double eyez = eye[2];
double upx = up[0];
double upy = up[1];
double upz = up[2];
double centerx = center[0];
double centery = center[1];
double centerz = center[2];
if (eyex == centerx && eyey == centery && eyez == centerz) {
return mat4_identity(dest);
}
//vec3.direction(eye, center, z);
z0 = eyex - centerx;
z1 = eyey - centery;
z2 = eyez - centerz;
// normalize (no check needed for 0 because of early return)
len = 1 / sqrt(z0 * z0 + z1 * z1 + z2 * z2);
z0 *= len;
z1 *= len;
z2 *= len;
//vec3.normalize(vec3.cross(up, z, x));
x0 = upy * z2 - upz * z1;
x1 = upz * z0 - upx * z2;
x2 = upx * z1 - upy * z0;
len = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
//vec3.normalize(vec3.cross(z, x, y));
y0 = z1 * x2 - z2 * x1;
y1 = z2 * x0 - z0 * x2;
y2 = z0 * x1 - z1 * x0;
len = sqrt(y0 * y0 + y1 * y1 + y2 * y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
dest[M4_00] = x0;
dest[M4_01] = y0;
dest[M4_02] = z0;
dest[M4_03] = 0;
dest[M4_10] = x1;
dest[M4_11] = y1;
dest[M4_12] = z1;
dest[M4_13] = 0;
dest[M4_20] = x2;
dest[M4_21] = y2;
dest[M4_22] = z2;
dest[M4_23] = 0;
dest[M4_30] = -(x0 * eyex + x1 * eyey + x2 * eyez);
dest[M4_31] = -(y0 * eyex + y1 * eyey + y2 * eyez);
dest[M4_32] = -(z0 * eyex + z1 * eyey + z2 * eyez);
dest[M4_33] = 1;
return dest;
}
mat4_t mat4_from_rotation_translation(quat_t quat, vec3_t vec, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
// Quaternion math
double x = quat[0];
double y = quat[1];
double z = quat[2];
double w = quat[3];
double x2 = x + x;
double y2 = y + y;
double z2 = z + z;
double xx = x * x2;
double xy = x * y2;
double xz = x * z2;
double yy = y * y2;
double yz = y * z2;
double zz = z * z2;
double wx = w * x2;
double wy = w * y2;
double wz = w * z2;
dest[M4_00] = 1 - (yy + zz);
dest[M4_01] = xy + wz;
dest[M4_02] = xz - wy;
dest[M4_03] = 0;
dest[M4_10] = xy - wz;
dest[M4_11] = 1 - (xx + zz);
dest[M4_12] = yz + wx;
dest[M4_13] = 0;
dest[M4_20] = xz + wy;
dest[M4_21] = yz - wx;
dest[M4_22] = 1 - (xx + yy);
dest[M4_23] = 0;
dest[M4_30] = vec[0];
dest[M4_31] = vec[1];
dest[M4_32] = vec[2];
dest[M4_33] = 1;
return dest;
}
#ifndef _MAT4_H
#define _MAT4_H
typedef double *mat4_t;
typedef enum
{
M4_00 = 0,
M4_01 = 1,
M4_02 = 2,
M4_03 = 3,
M4_10 = 4,
M4_11 = 5,
M4_12 = 6,
M4_13 = 7,
M4_20 = 8,
M4_21 = 9,
M4_22 = 10,
M4_23 = 11,
M4_30 = 12,
M4_31 = 13,
M4_32 = 14,
M4_33 = 15
} mat4_pos;
#include "vec3.h"
#include "mat3.h"
#include "vec4.h"
#include "quat.h"
#include "common.h"
/*
* mat4_t - 4x4 Matrix
*/
/*
* mat4_create
* Creates a new instance of a mat4_t
*
* Params:
* mat - Optional, mat4_t containing values to initialize with
*
* Returns:
* New mat4
*/
mat4_t mat4_create(mat4_t mat);
void mat4_free(mat4_t mat);
/*
* mat4_set
* Copies the values of one mat4_t to another
*
* Params:
* mat - mat4_t containing values to copy
* dest - mat4_t receiving copied values
*
* Returns:
* dest
*/
mat4_t mat4_set(mat4_t mat, mat4_t dest);
/*
* mat4_identity
* Sets a mat4_t to an identity matrix
*
* Params:
* dest - mat4_t to set
*
* Returns:
* dest
*/
mat4_t mat4_identity(mat4_t dest);
/*
* mat4_transpose
* Transposes a mat4_t (flips the values over the diagonal)
*
* Params:
* mat - mat4_t to transpose
* dest - Optional, mat4_t receiving transposed values. If NULL, result is written to mat
*
* Returns:
* dest is specified, mat otherwise
*/
mat4_t mat4_transpose(mat4_t mat, mat4_t dest);
/*
* mat4_determinant
* Calculates the determinant of a mat4
*
* Params:
* mat - mat4_t to calculate determinant of
*
* Returns:
* determinant of mat
*/
double mat4_determinant(mat4_t mat);
/*
* mat4_inverse
* Calculates the inverse matrix of a mat4
*
* Params:
* mat - mat4_t to calculate inverse of
* dest - Optional, mat4_t receiving inverse matrix. If NULL, result is written to mat
*
* Returns:
* dest is specified, mat otherwise, NULL if matrix cannot be inverted
*/
mat4_t mat4_inverse(mat4_t mat, mat4_t dest);
/*
* mat4_toRotationMat
* Copies the upper 3x3 elements of a mat4_t into another mat4
*
* Params:
* mat - mat4_t containing values to copy
* dest - Optional, mat4_t receiving copied values
*
* Returns:
* dest is specified, a new mat4_t otherwise
*/
mat4_t mat4_to_rotation_mat(mat4_t mat, mat4_t dest);
/*
* mat4_to_mat3
* Copies the upper 3x3 elements of a mat4_t into a mat3
*
* Params:
* mat - mat4_t containing values to copy
* dest - Optional, mat3_t receiving copied values
*
* Returns:
* dest is specified, a new mat3_t otherwise
*/
mat3_t mat4_to_mat3(mat4_t mat, mat3_t dest);
/*
* mat4_to_inverse_mat3
* Calculates the inverse of the upper 3x3 elements of a mat4_t and copies the result into a mat3
* The resulting matrix is useful for calculating transformed normals
*
* Params:
* mat - mat4_t containing values to invert and copy
* dest - Optional, mat3_t receiving values
*
* Returns:
* dest is specified, a new mat3_t otherwise, NULL if the matrix cannot be inverted
*/
mat3_t mat4_to_inverse_mat3(mat4_t mat, mat3_t dest);
/*
* mat4_multiply
* Performs a matrix multiplication
*
* Params:
* mat - mat4, first operand
* mat2 - mat4, second operand
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_multiply(mat4_t mat, mat4_t mat2, mat4_t dest);
/*
* mat4_multiply_vec3
* Transforms a vec3_t with the given matrix
* 4th vector component is implicitly '1'
*
* Params:
* mat - mat4_t to transform the vector with
* vec - vec3_t to transform
* dest - Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* Returns:
* dest if not NULL, vec otherwise
*/
mat4_t mat4_multiply_vec3(mat4_t mat, vec3_t vec, mat4_t dest);
/*
* mat4_multiply_vec4
* Transforms a vec4 with the given matrix
*
* Params:
* mat - mat4_t to transform the vector with
* vec - vec4 to transform
* dest - Optional, vec4 receiving operation result. If NULL, result is written to vec
*
* Returns:
* dest if not NULL, vec otherwise
*/
mat4_t mat4_multiply_vec4(mat4_t mat, vec4_t vec, mat4_t dest);
/*
* mat4_translate
* Translates a matrix by the given vector
*
* Params:
* mat - mat4_t to translate
* vec - vec3_t specifying the translation
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_translate(mat4_t mat, vec3_t vec, mat4_t dest);
/*
* mat4_scale
* Scales a matrix by the given vector
*
* Params:
* mat - mat4_t to scale
* vec - vec3_t specifying the scale for each axis
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_scale(mat4_t mat, vec3_t vec, mat4_t dest);
/*
* mat4_rotate
* Rotates a matrix by the given angle around the specified axis
* If rotating around a primary axis (X,Y,Z) one of the specialized rotation functions should be used instead for performance
*
* Params:
* mat - mat4_t to rotate
* angle - angle (in radians) to rotate
* axis - vec3_t representing the axis to rotate around
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_rotate(mat4_t mat, double angle, vec3_t axis, mat4_t dest);
/*
* mat4_rotate_x
* Rotates a matrix by the given angle around the X axis
*
* Params:
* mat - mat4_t to rotate
* angle - angle (in radians) to rotate
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_rotate_x(mat4_t mat, double angle, mat4_t dest);
/*
* mat4_rotate_y
* Rotates a matrix by the given angle around the Y axis
*
* Params:
* mat - mat4_t to rotate
* angle - angle (in radians) to rotate
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_rotate_y(mat4_t mat, double angle, mat4_t dest);
/*
* mat4_rotate_z
* Rotates a matrix by the given angle around the Z axis
*
* Params:
* mat - mat4_t to rotate
* angle - angle (in radians) to rotate
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to mat
*
* Returns:
* dest if not NULL, mat otherwise
*/
mat4_t mat4_rotate_z(mat4_t mat, double angle, mat4_t dest);
/*
* mat4_frustum
* Generates a frustum matrix with the given bounds
*
* Params:
* left, right - scalar, left and right bounds of the frustum
* bottom, top - scalar, bottom and top bounds of the frustum
* near, far - scalar, near and far bounds of the frustum
* dest - Optional, mat4_t frustum matrix will be written into
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
mat4_t mat4_frustum(double left, double right, double bottom, double top, double near, double far, mat4_t dest);
/*
* mat4_perspective
* Generates a perspective projection matrix with the given bounds
*
* Params:
* fovy - scalar, vertical field of view
* aspect - scalar, aspect ratio. typically viewport width/height
* near, far - scalar, near and far bounds of the frustum
* dest - Optional, mat4_t frustum matrix will be written into
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
mat4_t mat4_perspective(double fovy, double aspect, double near, double far, mat4_t dest);
/*
* mat4_ortho
* Generates a orthogonal projection matrix with the given bounds
*
* Params:
* left, right - scalar, left and right bounds of the frustum
* bottom, top - scalar, bottom and top bounds of the frustum
* near, far - scalar, near and far bounds of the frustum
* dest - Optional, mat4_t frustum matrix will be written into
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
mat4_t mat4_ortho(double left, double right, double bottom, double top, double near, double far, mat4_t dest);
/*
* mat4_look_at
* Generates a look-at matrix with the given eye position, focal point, and up axis
*
* Params:
* eye - vec3, position of the viewer
* center - vec3, point the viewer is looking at
* up - vec3_t pointing "up"
* dest - Optional, mat4_t frustum matrix will be written into
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
mat4_t mat4_look_at(vec3_t eye, vec3_t center, vec3_t up, mat4_t dest);
/*
* mat4_from_rotation_translation
* Creates a matrix from a quaternion rotation and vector translation
* This is equivalent to (but much faster than):
*
* mat4_identity(dest);
* mat4_translate(dest, vec);
* mat4_t quatMat = mat4_create();
* quat_to_mat4(quat, quatMat);
* mat4_multiply(dest, quatMat);
*
* Params:
* quat - quat specifying the rotation by
* vec - vec3_t specifying the translation
* dest - Optional, mat4_t receiving operation result. If NULL, result is written to a new mat4
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
mat4_t mat4_from_rotation_translation(quat_t quat, vec3_t vec, mat4_t dest);
#endif
#include <stdlib.h>
#include <math.h>
#include "quat.h"
quat_t quat_create(quat_t quat)
{
quat_t dest = calloc(4, sizeof(double_t));
if (quat) {
dest[0] = quat[0];
dest[1] = quat[1];
dest[2] = quat[2];
dest[3] = quat[3];
}
return dest;
}
void quat_free(quat_t *quat)
{
free(quat);
}
quat_t quat_set(quat_t quat, quat_t dest)
{
dest[0] = quat[0];
dest[1] = quat[1];
dest[2] = quat[2];
dest[3] = quat[3];
return dest;
}
quat_t quat_calculate_w(quat_t quat, quat_t dest)
{
double x = quat[0];
double y = quat[1];
double z = quat[2];
if (!dest || quat == dest) {
quat[3] = -sqrt(fabs(1.0 - x * x - y * y - z * z));
return quat;
}
dest[0] = x;
dest[1] = y;
dest[2] = z;
dest[3] = -sqrt(fabs(1.0 - x * x - y * y - z * z));
return dest;
}
double quat_dot(quat_t quat, quat_t quat2)
{
return quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3];
}
quat_t quat_inverse(quat_t quat, quat_t dest)
{
double dot = quat_dot(quat, quat), invDot = 1.0 / dot;
if (!dest || quat == dest) {
quat[0] *= -invDot;
quat[1] *= -invDot;
quat[2] *= -invDot;
quat[3] *= invDot;
return quat;
}
dest[0] = -quat[0] * invDot;
dest[1] = -quat[1] * invDot;
dest[2] = -quat[2] * invDot;
dest[3] = quat[3] * invDot;
return dest;
}
quat_t quat_conjugate(quat_t quat, quat_t dest)
{
if (!dest || quat == dest) {
quat[0] *= -1;
quat[1] *= -1;
quat[2] *= -1;
return quat;
}
dest[0] = -quat[0];
dest[1] = -quat[1];
dest[2] = -quat[2];
dest[3] = quat[3];
return dest;
}
double quat_length(quat_t quat)
{
double x = quat[0];
double y = quat[1];
double z = quat[2];
double w = quat[3];
return sqrt(x * x + y * y + z * z + w * w);
}
quat_t quat_normalize(quat_t quat, quat_t dest)
{
if (!dest) {
dest = quat;
}
double x = quat[0], y = quat[1], z = quat[2], w = quat[3], len = sqrt(x * x + y * y + z * z + w * w);
if (len == 0) {
dest[0] = 0;
dest[1] = 0;
dest[2] = 0;
dest[3] = 0;
return dest;
}
len = 1 / len;
dest[0] = x * len;
dest[1] = y * len;
dest[2] = z * len;
dest[3] = w * len;
return dest;
}
quat_t quat_multiply(quat_t quat, quat_t quat2, quat_t dest)
{
if (!dest) {
dest = quat;
}
double qax = quat[0];
double qay = quat[1];
double qaz = quat[2];
double qaw = quat[3];
double qbx = quat2[0];
double qby = quat2[1];
double qbz = quat2[2];
double qbw = quat2[3];
dest[0] = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
dest[1] = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
dest[2] = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
dest[3] = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
return dest;
}
quat_t quat_multiply_vec3(quat_t quat, vec3_t vec, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[0];
double y = vec[1];
double z = vec[2];
double qx = quat[0];
double qy = quat[1];
double qz = quat[2];
double qw = quat[3];
// calculate quat * vec
double ix = qw * x + qy * z - qz * y;
double iy = qw * y + qz * x - qx * z;
double iz = qw * z + qx * y - qy * x;
double iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
dest[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
dest[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
dest[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return dest;
}
mat3_t quat_to_mat3(quat_t quat, mat3_t dest)
{
if (!dest) {
dest = mat3_create(NULL);
}
double x = quat[0];
double y = quat[1];
double z = quat[2];
double w = quat[3];
double x2 = x + x;
double y2 = y + y;
double z2 = z + z;
double xx = x * x2;
double xy = x * y2;
double xz = x * z2;
double yy = y * y2;
double yz = y * z2;
double zz = z * z2;
double wx = w * x2;
double wy = w * y2;
double wz = w * z2;
dest[0] = 1 - (yy + zz);
dest[1] = xy + wz;
dest[2] = xz - wy;
dest[3] = xy - wz;
dest[4] = 1 - (xx + zz);
dest[5] = yz + wx;
dest[6] = xz + wy;
dest[7] = yz - wx;
dest[8] = 1 - (xx + yy);
return dest;
}
quat_t quat_to_mat4(quat_t quat, mat4_t dest)
{
if (!dest) {
dest = mat4_create(NULL);
}
double x = quat[0];
double y = quat[1];
double z = quat[2];
double w = quat[3];
double x2 = x + x;
double y2 = y + y;
double z2 = z + z;
double xx = x * x2;
double xy = x * y2;
double xz = x * z2;
double yy = y * y2;
double yz = y * z2;
double zz = z * z2;
double wx = w * x2;
double wy = w * y2;
double wz = w * z2;
dest[0] = 1 - (yy + zz);
dest[1] = xy + wz;
dest[2] = xz - wy;
dest[3] = 0;
dest[4] = xy - wz;
dest[5] = 1 - (xx + zz);
dest[6] = yz + wx;
dest[7] = 0;
dest[8] = xz + wy;
dest[9] = yz - wx;
dest[10] = 1 - (xx + yy);
dest[11] = 0;
dest[12] = 0;
dest[13] = 0;
dest[14] = 0;
dest[15] = 1;
return dest;
}
quat_t quat_slerp(quat_t quat, quat_t quat2, double slerp, quat_t dest)
{
if (!dest) {
dest = quat;
}
double cosHalfTheta = quat[0] * quat2[0] + quat[1] * quat2[1] + quat[2] * quat2[2] + quat[3] * quat2[3];
double halfTheta, sinHalfTheta, ratioA, ratioB;
if (fabs(cosHalfTheta) >= 1.0) {
if (dest != quat) {
dest[0] = quat[0];
dest[1] = quat[1];
dest[2] = quat[2];
dest[3] = quat[3];
}
return dest;
}
halfTheta = acos(cosHalfTheta);
sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta);
if (fabs(sinHalfTheta) < 0.001) {
dest[0] = (quat[0] * 0.5 + quat2[0] * 0.5);
dest[1] = (quat[1] * 0.5 + quat2[1] * 0.5);
dest[2] = (quat[2] * 0.5 + quat2[2] * 0.5);
dest[3] = (quat[3] * 0.5 + quat2[3] * 0.5);
return dest;
}
ratioA = sin((1 - slerp) * halfTheta) / sinHalfTheta;
ratioB = sin(slerp * halfTheta) / sinHalfTheta;
dest[0] = (quat[0] * ratioA + quat2[0] * ratioB);
dest[1] = (quat[1] * ratioA + quat2[1] * ratioB);
dest[2] = (quat[2] * ratioA + quat2[2] * ratioB);
dest[3] = (quat[3] * ratioA + quat2[3] * ratioB);
return dest;
}
#ifndef _QUAT_H
#define _QUAT_H
typedef double *quat_t;
#include "mat4.h"
#include "mat3.h"
#include "common.h"
/*
* quat - Quaternions
*/
/*
* quat_create
* Creates a new instance of a quat_t
*
* Params:
* quat - Optional, quat_t containing values to initialize with
*
* Returns:
* New quat_t
*/
quat_t quat_create(quat_t quat);
void quat_free(quat_t *quat);
/*
* quat_set
* Copies the values of one quat_t to another
*
* Params:
* quat - quat_t containing values to copy
* dest - quat_t receiving copied values
*
* Returns:
* dest
*/
quat_t quat_set(quat_t quat, quat_t dest);
/*
* quat_calculate_w
* Calculates the W component of a quat_t from the X, Y, and Z components.
* Assumes that quaternion is 1 unit in length.
* Any existing W component will be ignored.
*
* Params:
* quat - quat_t to calculate W component of
* dest - Optional, quat_t receiving calculated values. If NULL, result is written to quat
*
* Returns:
* dest if not NULL, quat otherwise
*/
quat_t quat_calculate_w(quat_t quat, quat_t dest);
/**
* quat_dot
* Calculates the dot product of two quaternions
*
* @param {quat4} quat First operand
* @param {quat4} quat2 Second operand
*
* @return {number} Dot product of quat and quat2
*/
double quat_dot(quat_t quat, quat_t quat2);
/*
* quat_inverse
* Calculates the inverse of a quat_t
*
* Params:
* quat - quat_t to calculate inverse of
* dest - Optional, quat_t receiving inverse values. If NULL, result is written to quat
*
* Returns:
* dest if not NULL, quat otherwise
*/
quat_t quat_inverse(quat_t quat, quat_t dest);
/*
* quat_conjugate
* Calculates the conjugate of a quat_t
*
* Params:
* quat - quat_t to calculate conjugate of
* dest - Optional, quat_t receiving conjugate values. If NULL, result is written to quat
*
* Returns:
* dest if not NULL, quat otherwise
*/
quat_t quat_conjugate(quat_t quat, quat_t dest);
/*
* quat_length
* Calculates the length of a quat_t
*
* Params:
* quat - quat_t to calculate length of
*
* Returns:
* Length of quat
*/
double quat_length(quat_t quat);
/*
* quat_normalize
* Generates a unit quaternion of the same direction as the provided quat_t
* If quaternion length is 0, returns [0, 0, 0, 0]
*
* Params:
* quat - quat_t to normalize
* dest - Optional, quat_ receiving operation result. If NULL, result is written to quat
*
* Returns:
* dest if not NULL, quat otherwise
*/
quat_t quat_normalize(quat_t quat, quat_t dest);
/*
* quat_multiply
* Performs a quaternion multiplication
*
* Params:
* quat - quat_t, first operand
* quat2 - quat_t, second operand
* dest - Optional, quat_t receiving operation result. If NULL, result is written to quat
*
* Returns:
* dest if not NULL, quat otherwise
*/
quat_t quat_multiply(quat_t quat, quat_t quat2, quat_t dest);
/*
* quat_multiply_vec3
* Transforms a vec3_t with the given quaternion
*
* Params:
* quat - quat_t to transform the vector with
* vec - vec3_t to transform
* dest - Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* Returns:
* dest if not NULL, vec otherwise
*/
quat_t quat_multiply_vec3(quat_t quat, vec3_t vec, vec3_t dest);
/*
* quat_to_mat3
* Calculates a 3x3 matrix from the given quat_t
*
* Params:
* quat - quat_t to create matrix from
* dest - Optional, mat3_t receiving operation result
*
* Returns:
* dest if not NULL, a new mat3_t otherwise
*/
mat3_t quat_to_mat3(quat_t quat, mat3_t dest);
/*
* quat_to_mat4
* Calculates a 4x4 matrix from the given quat_t
*
* Params:
* quat - quat_t to create matrix from
* dest - Optional, mat4_t receiving operation result
*
* Returns:
* dest if not NULL, a new mat4_t otherwise
*/
quat_t quat_to_mat4(quat_t quat, mat4_t dest);
/*
* quat_slerp
* Performs a spherical linear interpolation between two quat_t
*
* Params:
* quat - quat_t, first quaternion
* quat2 - quat_t, second quaternion
* slerp - interpolation amount between the two inputs
* dest - Optional, quat_t receiving operation result. If NULL, result is written to quat
*
* Returns:
* dest if not NULL, quat otherwise
*/
quat_t quat_slerp(quat_t quat, quat_t quat2, double slerp, quat_t dest);
#endif
#include <stdlib.h>
#include <math.h>
#include "common.h"
#include "vec2.h"
vec2_t vec2_create(vec2_t vec)
{
vec2_t dest = calloc(2, sizeof(double_t));
if (!dest) {
return NULL;
}
if (vec) {
dest[VX] = vec[VX];
dest[VY] = vec[VY];
} else {
dest[VX] = 0;
dest[VY] = 0;
}
return dest;
}
void vec2_free(vec2_t vec)
{
free(vec);
}
void vec2_set(vec2_t vec, vec2_t dest)
{
dest[VX] = vec[VX];
dest[VY] = vec[VY];
}
void vec2_add(vec2_t vec, vec2_t vec2, vec2_t dest)
{
if (!dest || vec == dest) {
vec[VX] += vec2[VX];
vec[VY] += vec2[VY];
return;
}
dest[VX] = vec[VX] + vec2[VX];
dest[VY] = vec[VY] + vec2[VY];
}
void vec2_subtract(vec2_t vec, vec2_t vec2, vec2_t dest)
{
if (!dest || vec == dest) {
vec[VX] -= vec2[VX];
vec[VY] -= vec2[VY];
return;
}
dest[VX] = vec[VX] - vec2[VX];
dest[VY] = vec[VY] - vec2[VY];
return;
}
void vec2_multiply(vec2_t vec, vec2_t vec2, vec2_t dest)
{
if (!dest || vec == dest) {
vec[VX] *= vec2[VX];
vec[VY] *= vec2[VY];
return;
}
dest[VX] = vec[VX] * vec2[VX];
dest[VY] = vec[VY] * vec2[VY];
}
void vec2_negate(vec2_t vec, vec2_t dest)
{
if (!dest) {
dest = vec;
}
dest[VX] = -vec[VX];
dest[VY] = -vec[VY];
}
void vec2_scale(vec2_t vec, double scalar, vec2_t dest)
{
if (!dest || vec == dest) {
vec[VX] *= scalar;
vec[VY] *= scalar;
return;
}
dest[VX] = vec[VX] * scalar;
dest[VY] = vec[VY] * scalar;
}
void vec2_normalize(vec2_t vec, vec2_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[VX];
double y = vec[VY];
double len = sqrt(square(x) + square(y));
if (!len) {
dest[VX] = 0;
dest[VY] = 0;
return;
} else if (len == 1) {
dest[VX] = x;
dest[VY] = y;
return;
}
len = 1 / len;
dest[VX] = x * len;
dest[VY] = y * len;
}
double vec2_cross(vec2_t vec, vec2_t vec2)
{
return vec[VX] * vec2[VY] - vec[VY] * vec2[VX];
}
double vec2_length(vec2_t vec)
{
double x = vec[VX];
double y = vec[VY];
return sqrt(square(x) + square(y));
}
double vec2_dot(vec2_t vec, vec2_t vec2)
{
return vec[VX] * vec2[VX] + vec[VY] * vec2[VY];
}
void vec2_direction(vec2_t vec, vec2_t vec2, vec2_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[VX] - vec2[VX];
double y = vec[VY] - vec2[VY];
double len = sqrt(square(x) + square(y));
if (!len) {
dest[VX] = 0;
dest[VY] = 0;
return;
}
len = 1 / len;
dest[VX] = x * len;
dest[VY] = y * len;
}
void vec2_lerp(vec2_t vec, vec2_t vec2, double lerp, vec2_t dest)
{
if (!dest) {
dest = vec;
}
dest[VX] = vec[VX] + lerp * (vec2[VX] - vec[VX]);
dest[VY] = vec[VY] + lerp * (vec2[VY] - vec[VY]);
}
double vec2_dist(vec2_t vec, vec2_t vec2)
{
double x = vec2[VX] - vec[VX];
double y = vec2[VY] - vec[VY];
return sqrt(square(x) + square(y));
}
void vec2_rotate(vec2_t vec, double rad, vec2_t dest)
{
if (!dest) {
dest = vec;
}
dest[VX] = (cos(rad) * vec[VX]) - (sin(rad) * vec[VY]);
dest[VY] = (sin(rad) * vec[VX]) - (cos(rad) * vec[VY]);
}
double vec2_angle(vec2_t vec)
{
return atan2(vec[VY], vec[VX]);
}
void vec2_zero(vec2_t vec)
{
vec[VX] = 0;
vec[VY] = 0;
}
void vec2_translate(vec2_t vec, double dx, double dy)
{
vec[VX] += dx;
vec[VY] += dy;
}
#ifndef _VEC3_H
#define _VEC3_H
/**
* vec2_t - 2 Dimensional Vector
*/
typedef double *vec2_t;
#include "common.h"
/**
* Creates a new instance of a vec2_t
*
* @param vec
* Optional, vec2_t containing values to initialize with. If NULL, the
* vector will be initialized with zeroes.
*
* @return New vec
*/
vec2_t vec2_create(vec2_t vec);
/**
* Frees a vec2_t instance
*
* @param vec
* Vector to free
*/
void vec2_free(vec2_t vec);
/**
* Copies the values of one vec2_t to another
*
* @param vec
* vec2_t containing values to copy
* @param dest
* vec2_t receiving copied values
*
* @return dest
*/
void vec2_set(vec2_t vec, vec2_t dest);
/**
* Performs a vector addition
*
* @param vec
* first operand
* @param vec2
* second operand
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_add(vec2_t vec, vec2_t vec2, vec2_t dest);
/**
* Performs a vector subtraction
*
* @param vec
* first operand
* @param vec2
* second operand
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_subtract(vec2_t vec, vec2_t vec2, vec2_t dest);
/**
* Performs a vector multiplication
*
* @param vec
* first operand
* @param vec2
* second operand
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_multiply(vec2_t vec, vec2_t vec2, vec2_t dest);
/**
* Negates the components of a vec
*
* @param vec
* vec2_t to negate
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_negate(vec2_t vec, vec2_t dest);
/**
* Multiplies the components of a vec2_t by a scalar value
*
* @param vec
* vec2_t to scale
* @param val
* Numeric value to scale by
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_scale(vec2_t vec, double scalar, vec2_t dest);
/**
* Generates a unit vector of the same direction as the provided vec
* If vector length is 0, returns [0, 0, 0]
*
* @param vec
* vec2_t to normalize
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_normalize(vec2_t vec, vec2_t dest);
/**
* Generates the cross product of two vecs
*
* @param vec
* first operand
* @param vec2
* second operand
*
* @return the cross product of both vectors
*/
double vec2_cross(vec2_t vec, vec2_t vec2);
/**
* Caclulates the length of a vec
*
* vec - vec2_t to calculate length of
*
* @return Length of vec
*/
double vec2_length(vec2_t vec);
/**
* Caclulates the dot product of two vecs
*
* @param vec
* first operand
* @param vec2
* second operand
*
* @return Dot product of vec and vec2
*/
double vec2_dot(vec2_t vec, vec2_t vec2);
/**
* Generates a unit vector pointing from one vector to another
*
* @param vec
* origin vec
* @param vec2
* t to point to
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_direction(vec2_t vec, vec2_t vec2, vec2_t dest);
/**
* Performs a linear interpolation between two vec
*
* @param vec
* first vector
* @param vec2
* second vector
* @param lerp
* interpolation amount between the two inputs
* @param dest
* Optional, vec2_t receiving operation result. If NULL, result is written
* to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec2_lerp(vec2_t vec, vec2_t vec2, double lerp, vec2_t dest);
/**
* Calculates the euclidian distance between two vec
*
* @param vec
* first vector
* @param vec2
* second vector
*
* @return distance between vec and vec2
*/
double vec2_dist(vec2_t vec, vec2_t vec2);
void vec2_rotate(vec2_t vec, double rad, vec2_t dest);
double vec2_angle(vec2_t vec);
void vec2_zero(vec2_t vec);
void vec2_translate(vec2_t vec, double dx, double dy);
#endif
#include <stdlib.h>
#include <math.h>
#include "vec3.h"
#include "common.h"
vec3_t vec3_create(vec3_t vec)
{
vec3_t dest = calloc(3, sizeof(double_t));
if (vec) {
dest[VX] = vec[VX];
dest[VY] = vec[VY];
dest[VZ] = vec[VZ];
} else {
dest[VX] = 0;
dest[VY] = 0;
dest[VZ] = 0;
}
return dest;
}
void vec3_free(vec3_t vec)
{
free(vec);
}
void vec3_set(vec3_t vec, vec3_t dest)
{
dest[VX] = vec[VX];
dest[VY] = vec[VY];
dest[VZ] = vec[VZ];
}
void vec3_add(vec3_t vec, vec3_t other, vec3_t dest)
{
if (!dest || vec == dest) {
vec[VX] += other[VX];
vec[VY] += other[VY];
vec[VZ] += other[VZ];
return;
}
dest[VX] = vec[VX] + other[VX];
dest[VY] = vec[VY] + other[VY];
dest[VZ] = vec[VZ] + other[VZ];
}
void vec3_subtract(vec3_t vec, vec3_t other, vec3_t dest)
{
if (!dest || vec == dest) {
vec[VX] -= other[VX];
vec[VY] -= other[VY];
vec[VZ] -= other[VZ];
return;
}
dest[VX] = vec[VX] - other[VX];
dest[VY] = vec[VY] - other[VY];
dest[VZ] = vec[VZ] - other[VZ];
}
void vec3_multiply(vec3_t vec, vec3_t other, vec3_t dest)
{
if (!dest || vec == dest) {
vec[VX] *= other[VX];
vec[VY] *= other[VY];
vec[VZ] *= other[VZ];
return;
}
dest[VX] = vec[VX] * other[VX];
dest[VY] = vec[VY] * other[VY];
dest[VZ] = vec[VZ] * other[VZ];
}
void vec3_negate(vec3_t vec, vec3_t dest)
{
if (!dest) {
dest = vec;
}
dest[VX] = -vec[VX];
dest[VY] = -vec[VY];
dest[VZ] = -vec[VZ];
}
void vec3_scale(vec3_t vec, double val, vec3_t dest)
{
if (!dest || vec == dest) {
vec[VX] *= val;
vec[VY] *= val;
vec[VZ] *= val;
return;
}
dest[VX] = vec[VX] * val;
dest[VY] = vec[VY] * val;
dest[VZ] = vec[VZ] * val;
return;
}
void vec3_normalize(vec3_t vec, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
double len = sqrt(square(x) + square(y) + square(z));
if (!len) {
dest[VX] = 0;
dest[VY] = 0;
dest[VZ] = 0;
return;
} else if (len == 1) {
dest[VX] = x;
dest[VY] = y;
dest[VZ] = z;
return;
}
len = 1 / len;
dest[VX] = x * len;
dest[VY] = y * len;
dest[VZ] = z * len;
}
void vec3_cross(vec3_t vec, vec3_t other, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
double x2 = other[VX];
double y2 = other[VY];
double z2 = other[VZ];
dest[VX] = y * z2 - z * y2;
dest[VY] = z * x2 - x * z2;
dest[VZ] = x * y2 - y * x2;
}
double vec3_length(vec3_t vec)
{
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
return sqrt(square(x) + square(y) + square(z));
}
double vec3_dot(vec3_t vec, vec3_t other)
{
return vec[VX] * other[VX] + vec[VY] * other[VY] + vec[VZ] * other[VZ];
}
void vec3_direction(vec3_t vec, vec3_t other, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double x = vec[VX] - other[VX];
double y = vec[VY] - other[VY];
double z = vec[VZ] - other[VZ];
double len = sqrt(square(x) + square(y) + square(z));
if (!len) {
dest[VX] = 0;
dest[VY] = 0;
dest[VZ] = 0;
return;
}
len = 1 / len;
dest[VX] = x * len;
dest[VY] = y * len;
dest[VZ] = z * len;
}
void vec3_lerp(vec3_t vec, vec3_t vec2, double lerp, vec3_t dest)
{
if (!dest) {
dest = vec;
}
dest[VX] = vec[VX] + lerp * (vec2[VX] - vec[VX]);
dest[VY] = vec[VY] + lerp * (vec2[VY] - vec[VY]);
dest[VZ] = vec[VZ] + lerp * (vec2[VZ] - vec[VZ]);
}
double vec3_dist(vec3_t vec, vec3_t other)
{
double x = other[VX] - vec[VX];
double y = other[VY] - vec[VY];
double z = other[VZ] - vec[VZ];
return sqrt(square(x) + square(y) + square(z));
}
int vec3_identical(vec3_t vec, vec3_t other)
{
return (vec[VX] == other[VX]) && (vec[VY] == other[VY]) && (vec[VZ] == other[VZ]);
}
/**
* Left-multiplies the vector by the given mat3_t
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector
*/
void vec3_left_mul_mat3(vec3_t vec, mat3_t mat, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double a00 = mat[0];
double a01 = mat[3];
double a02 = mat[6];
double a10 = mat[1];
double a11 = mat[4];
double a12 = mat[7];
double a20 = mat[2];
double a21 = mat[5];
double a22 = mat[8];
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
dest[VX] = x * a00 + y * a01 + z * a02;
dest[VY] = x * a10 + y * a11 + z * a12;
dest[VZ] = x * a20 + y * a21 + z * a22;
}
/**
* Multiplies the vector by the transpose of the given matrix.
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector
*/
void vec3_tra_mul_mat3(vec3_t vec, mat3_t mat, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double a00 = mat[0];
double a01 = mat[3];
double a02 = mat[6];
double a10 = mat[1];
double a11 = mat[4];
double a12 = mat[7];
double a20 = mat[2];
double a21 = mat[5];
double a22 = mat[8];
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
dest[VX] = x * a00 + y * a10 + z * a20;
dest[VY] = x * a01 + y * a11 + z * a21;
dest[VZ] = x * a02 + y * a12 + z * a22;
}
/**
* Left-multiplies the vector by the given matrix, assuming the
* fourth (w) component of the vector is 1.
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector. If not specified, the first
* vec will be the destination.
*/
void vec3_left_mul_mat4(vec3_t vec, mat4_t mat, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double a00 = mat[0];
double a01 = mat[4];
double a02 = mat[8];
double a03 = mat[12];
double a10 = mat[1];
double a11 = mat[5];
double a12 = mat[9];
double a13 = mat[13];
double a20 = mat[2];
double a21 = mat[6];
double a22 = mat[10];
double a23 = mat[14];
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
dest[VX] = x * a00 + y * a01 + z * a02 + a03;
dest[VY] = x * a10 + y * a11 + z * a12 + a13;
dest[VZ] = x * a20 + y * a21 + z * a22 + a23;
}
/**
* Multiplies the vector by the transpose of the given matrix, assuming the
* fourth (w) component of the vector is 1.
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector. If not specified, the first
* vec will be the destination.
*/
void vec3_tra_mul_mat4(vec3_t vec, mat4_t mat, vec3_t dest)
{
if (!dest) {
dest = vec;
}
double a00 = mat[0];
double a01 = mat[4];
double a02 = mat[8];
double a10 = mat[1];
double a11 = mat[5];
double a12 = mat[9];
double a20 = mat[2];
double a21 = mat[6];
double a22 = mat[10];
double a30 = mat[3];
double a31 = mat[7];
double a32 = mat[11];
double x = vec[VX];
double y = vec[VY];
double z = vec[VZ];
dest[VX] = x * a00 + y * a10 + z * a20 + a30;
dest[VY] = x * a01 + y * a11 + z * a21 + a31;
dest[VZ] = x * a02 + y * a12 + z * a22 + a32;
}
void vec3_zero(vec3_t vec)
{
vec[VX] = 0;
vec[VY] = 0;
vec[VZ] = 0;
}
vec3_t vec3_unproject(vec3_t vec, mat4_t view, mat4_t proj, vec4_t viewport, vec3_t dest)
{
if (!dest) {
dest = vec;
}
mat4_t m = mat4_create(NULL);
double *v = malloc(sizeof(double) * 4);
v[VX] = (vec[VX] - viewport[0]) * 2.0 / viewport[2] - 1.0;
v[VY] = (vec[VY] - viewport[1]) * 2.0 / viewport[3] - 1.0;
v[VZ] = 2.0 * vec[VZ] - 1.0;
v[VU] = 1.0;
mat4_multiply(proj, view, m);
if (!mat4_inverse(m, NULL)) {
return NULL;
}
mat4_multiply_vec4(m, v, NULL);
if (v[VU] == 0.0) {
return NULL;
}
dest[VX] = v[VX] / v[VU];
dest[VY] = v[VY] / v[VU];
dest[VZ] = v[VZ] / v[VU];
return dest;
}
#ifndef _VEC3_H
#define _VEC3_H
/**
* vec3_t - 3 Dimensional Vector
*/
typedef double *vec3_t;
#include "mat4.h"
#include "mat3.h"
#include "vec4.h"
#include "common.h"
/*
* vec3_create
* Creates a new instance of a vec3_t
*
* Params:
* vec - Optional, vec3_t containing values to initialize with. If NULL, the
* vector will be initialized with zeroes.
*
* Returns:
* New vec3
*/
vec3_t vec3_create(vec3_t vec);
/**
* Frees a vec3_t instance
*
* @param vec
* Vector to free
*/
void vec3_free(vec3_t vec);
/**
* Copies the values of one vec3_t to another
*
* @param vec
* containing values to copy
* @param dest
* receiving copied values
*
* @return dest
*/
void vec3_set(vec3_t vec, vec3_t dest);
/**
* Performs a vector addition
*
* @param vec
* first operand
* @param vec2
* second operand
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_add(vec3_t vec, vec3_t other, vec3_t dest);
/**
* Performs a vector subtraction
*
* @param vec
* vec3, first operand
* @param vec2
* vec3, second operand
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_subtract(vec3_t vec, vec3_t other, vec3_t dest);
/**
* Performs a vector multiplication
*
* @param vec
* first operand
* @param vec2
* second operand
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_multiply(vec3_t vec, vec3_t other, vec3_t dest);
/**
* Negates the components of a vec3
*
* @param vec
* vec3_t to negate
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_negate(vec3_t vec, vec3_t dest);
/**
* Multiplies the components of a vec3_t by a scalar value
*
* @param vec
* vec3_t to scale
* @param val
* Numeric value to scale by
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_scale(vec3_t vec, double val, vec3_t dest);
/**
* Generates a unit vector of the same direction as the provided vec3
* If vector length is 0, returns [0, 0, 0]
*
* @param vec
* vec3_t to normalize
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_normalize(vec3_t vec, vec3_t dest);
/**
* Generates the cross product of two vec3s
*
* @param vec
* vec3, first operand
* @param vec2
* vec3, second operand
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_cross(vec3_t vec, vec3_t other, vec3_t dest);
/**
* Calculates the length of a vec3
*
* @param vec
* to calculate length of
*
* @return Length of vec
*/
double vec3_length(vec3_t vec);
/**
* Calculates the dot product of two vec3s
*
* @param vec - vec3, first operand
* @param vec2 - vec3, second operand
*
* @return Dot product of vec and vec2
*/
double vec3_dot(vec3_t vec, vec3_t other);
/**
* Generates a unit vector pointing from one vector to another
*
* @param vec
* origin vec3
* @param vec2
* vec3_t to point to
* @param dest
* Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_direction(vec3_t vec, vec3_t other, vec3_t dest);
/**
* Performs a linear interpolation between two vec3
*
* @param vec - vec3, first vector
* @param vec2 - vec3, second vector
* @param lerp - interpolation amount between the two inputs
* @param dest - Optional, vec3_t receiving operation result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
void vec3_lerp(vec3_t vec, vec3_t vec2, double lerp, vec3_t dest);
/**
* Calculates the euclidian distance between two vec3
*
* Params:
* vec - vec3, first vector
* vec2 - vec3, second vector
*
* distance between vec and vec2
*/
double vec3_dist(vec3_t vec, vec3_t other);
/**
* Projects the specified vec3_t from screen space into object space.
*
* Based on Mesa gluUnProject implementation
*
* @see http://webcvs.freedesktop.org/mesa/Mesa/src/glu/mesa/project.c?revision=1.4&view=markup
*
* @param vec
* screen-space vector to project
* @param view
* View matrix
* @param proj
* Projection matrix
* @param viewport
* Viewport as given to gl.viewport [x, y, width, height]
* @param dest
* Optional, vec3_t receiving unprojected result. If NULL, result is written to vec
*
* @return dest if not NULL, vec otherwise
*/
vec3_t vec3_unproject(vec3_t vec, mat4_t view, mat4_t proj, vec4_t viewport, vec3_t dest);
/**
* Left-multiplies the vector by the given mat3_t
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector
*/
void vec3_left_mul_mat3(vec3_t vec, mat3_t mat, vec3_t dest);
/**
* Multiplies the vector by the transpose of the given matrix.
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector
*/
void vec3_tra_mul_mat3(vec3_t vec, mat3_t mat, vec3_t dest);
/**
* Left-multiplies the vector by the given matrix, assuming the
* fourth (w) component of the vector is 1.
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector. If not specified, the first
* vec will be the destination.
*/
void vec3_left_mul_mat4(vec3_t vec, mat4_t mat, vec3_t dest);
/**
* Multiplies the vector by the transpose of the given matrix, assuming the
* fourth (w) component of the vector is 1.
*
* @param vec
* The base vector
* @param mat
* The matrix to multiply by
* @param dest
* Optional, the destination vector. If not specified, the first
* vec will be the destination.
*/
void vec3_tra_mul_mat4(vec3_t vec, mat4_t mat, vec3_t dest);
void vec3_zero(vec3_t vec);
#endif
#include <stdlib.h>
#include <math.h>
#include "vec4.h"
vec4_t vec4_create(vec4_t vec)
{
vec4_t dest = calloc(4, sizeof(double_t));
if (vec) {
dest[0] = vec[0];
dest[1] = vec[1];
dest[2] = vec[2];
dest[3] = vec[3];
} else {
dest[0] = 0;
dest[1] = 0;
dest[2] = 0;
dest[3] = 0;
}
return dest;
}
void vec4_free(vec4_t vec)
{
free(vec);
}
#ifndef _VEC4_H
#define _VEC4_H
typedef double *vec4_t;
vec4_t vec4_create(vec4_t vec);
void vec4_free(vec4_t vec);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment