cos2000v2/lib/matrix.c

654 lines
19 KiB
C
Raw Normal View History

/*******************************************************************************/
/* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas */
/* */
#include "matrix.h"
#include "types.h"
#include "math.h"
/*******************************************************************************/
/* Affiche un vecteur de 4 composantes */
void vector4_show(vector4 src)
{
printf("vecteur: X=%f Y=%f Z=%f W=%f \r\n", src.x, src.y, src.z,
src.w);
}
/*******************************************************************************/
/* Créé un vecteur de 4 composantes */
void vector4_create(float x, float y, float z, float w, vector4 * dst)
{
dst->x = x;
dst->y = y;
dst->z = z;
dst->w = w;
}
/*******************************************************************************/
/* Copie un vecteur de 4 composantes */
void vector4_copy(vector4 src, vector4 * dst)
{
vector4_create(src.x, src.y, src.z, src.w, dst);
}
/*******************************************************************************/
/* Ajoute deux vecteurs de 4 composantes */
void vector4_add(vector4 v1, vector4 v2, vector4 * dst)
{
dst->x = v1.x + v2.x;
dst->y = v1.y + v2.y;
dst->z = v1.z + v2.z;
}
/*******************************************************************************/
/* Soustrait un vecteur de 4 composantes depuis un autre*/
void vector4_sub(vector4 v1, vector4 v2, vector4 * dst)
{
dst->x = v1.x - v2.x;
dst->y = v1.y - v2.y;
dst->z = v1.z - v2.z;
}
/*******************************************************************************/
/* Redimensionne un vecteur de 4 composantes */
void vector4_scale(vector4 * dst, float factor)
{
dst->x *= factor;
dst->y *= factor;
dst->z *= factor;
dst->w *= factor;
}
/*******************************************************************************/
/* Calcule le produit vectoriel de deux vecteurs de 4 composantes */
void vector4_crossproduct(vector4 v1, vector4 v2, vector4 * dst)
{
dst->x = v1.y * v2.z - v1.z * v2.y;
dst->y = v1.z * v2.x - v1.x * v2.z;
dst->z = v1.x * v2.y - v1.y * v2.x;
}
/*******************************************************************************/
/* Normalise un vecteur de 4 composantes */
void vector4_normalize(vector4 * dst)
{
float len;
float norm;
norm = vector4_norm(*dst);
if (norm != 0)
{
len = 1 / norm;
dst->x = dst->x * len;
dst->y = dst->y * len;
dst->z = dst->z * len;
dst->w = 0;
}
}
/*******************************************************************************/
/* Divise un vecteur de 4 composantes depuis un autre*/
void vector4_divide(vector4 * v1, vector4 v2, vector4 * dst)
{
dst->x = v1->x / v2.x;
dst->y = v1->y / v2.y;
dst->z = v1->z / v2.z;
}
/*******************************************************************************/
/* Détermine le 3ème vecteur perpendiculaire au 2 autres */
void vector4_perpendicular(vector4 v1, vector4 v2, vector4 * dst)
{
float dot = vector4_dotproduct(v1, v2);
dst->x = v1.x - dot * v2.x;
dst->y = v1.y - dot * v2.y;
dst->z = v1.z - dot * v2.z;
}
/*******************************************************************************/
/* Tourne un vecteur à 4 composantes autour de X */
void vector4_rotate_x(vector4 * dst, float angle)
{
vector4 origin;
float sinus, cosinus;
sinus = sinf(angle);
cosinus = cosf(angle);
origin.x = dst->x;
origin.y = dst->y;
origin.z = dst->z;
dst->y = cosinus * origin.y + sinus * origin.z;
dst->z = cosinus * origin.z - sinus * origin.y;
}
/*******************************************************************************/
/* Tourne un vecteur à 4 composantes autour de Y */
void vector4_rotate_y(vector4 * dst, float angle)
{
vector4 origin;
float sinus, cosinus;
sinus = sinf(angle);
cosinus = cosf(angle);
origin.x = dst->x;
origin.y = dst->y;
origin.z = dst->z;
dst->x = cosinus * origin.x + sinus * origin.z;
dst->z = cosinus * origin.z - sinus * origin.x;
}
/*******************************************************************************/
/* Tourne un vecteur à 4 composantes autour de Z */
void vector4_rotate_z(vector4 * dst, float angle)
{
vector4 origin;
float sinus, cosinus;
sinus = sinf(angle);
cosinus = cosf(angle);
origin.x = dst->x;
origin.y = dst->y;
origin.z = dst->z;
dst->x = cosinus * origin.x + sinus * origin.y;
dst->y = cosinus * origin.y - sinus * origin.x;
}
/*******************************************************************************/
/* Donne la longueur d'un vecteur à 4 composantes */
float vector4_len(vector4 src)
{
return sqrtf((src.x * src.x) + (src.y * src.y) + (src.z * src.z));
}
/*******************************************************************************/
/* Retourne le produit scalaire de deux vecteurs à 4 composantes */
float vector4_dotproduct(vector4 v1, vector4 v2)
{
return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
}
/*******************************************************************************/
/* Retourne la norme d'un vecteur à 4 composantes */
float vector4_norm(vector4 src)
{
return sqrtf((src.x * src.x) + (src.y * src.y) + (src.z * src.z));
}
/*******************************************************************************/
/* Retourne la distance de deux vecteurs à 4 composantes */
float vector4_distance(vector4 v1, vector4 v2)
{
return sqrt(pow(v2.x - v1.x, 2) + pow(v2.y - v1.y, 2) +
pow(v2.z - v1.z, 2));
}
/*******************************************************************************/
/* Compare deux vecteurs à 4 composantes */
int vector4_isequals(vector4 v1, vector4 v2)
{
float x, y, z;
x = fabsf(v1.x - v2.x);
y = fabsf(v1.y - v2.y);
z = fabsf(v1.z - v2.z);
return (x < 0.000001 && y < 0.000001 && z < 0.000001);
}
/*******************************************************************************/
/* Définie le plan normal à 3 vecteurs à 4 composantes */
void vector4_planenormal(vector4 v1, vector4 v2, vector4 v3, vector4 * dst)
{
vector4 temp1, temp2;
vector4_sub(v2, v1, &temp1);
vector4_sub(v3, v1, &temp2);
vector4_crossproduct(temp1, temp2, dst);
vector4_normalize(dst);
}
/*******************************************************************************/
/* Créé une matrice d'identité */
void matrix44_homogen(matrix44 * matrix)
{
vector4_create(1, 0, 0, 0, &matrix->V[0]);
vector4_create(0, 1, 0, 0, &matrix->V[1]);
vector4_create(0, 0, 1, 0, &matrix->V[2]);
vector4_create(0, 0, 0, 1, &matrix->V[3]);
}
/*******************************************************************************/
/* Créé une matrice vide */
void matrix44_empty(matrix44 * matrix)
{
vector4_create(0, 0, 0, 0, &matrix->V[0]);
vector4_create(0, 0, 0, 0, &matrix->V[1]);
vector4_create(0, 0, 0, 0, &matrix->V[2]);
vector4_create(0, 0, 0, 0, &matrix->V[3]);
}
/*******************************************************************************/
/* Créé une matrice de redimensionnement (par un vecteur) */
void matrix44_scaling(vector4 v, matrix44 * dst)
{
matrix44_homogen(dst);
dst->V[0].x = v.x;
dst->V[1].y = v.y;
dst->V[2].z = v.z;
}
/*******************************************************************************/
/* Créé une matrice de déplacement */
void matrix44_translation(vector4 v, matrix44 * dst)
{
matrix44_homogen(dst);
dst->V[0].x = v.x;
dst->V[1].y = v.y;
dst->V[2].z = v.z;
}
/*******************************************************************************/
/* Créé une matrice de redimensionnement (par un facteur) */
void matrix44_scale(matrix44 * dst, float factor)
{
vector4_scale(&dst->V[0], factor);
vector4_scale(&dst->V[1], factor);
vector4_scale(&dst->V[2], factor);
vector4_scale(&dst->V[3], factor);
}
/*******************************************************************************/
/* Créé une matrice de redimensionnement et de déplacement */
void matrix44_scale_translation(vector4 scale, vector4 translation,
matrix44 * dst)
{
matrix44_homogen(dst);
dst->V[0].x = scale.x;
dst->V[1].y = scale.y;
dst->V[2].z = scale.z;
dst->V[3].x = translation.x;
dst->V[3].y = translation.y;
dst->V[3].z = translation.z;
}
/*******************************************************************************/
/* Créé une matrice de rotation autour de X */
void matrix44_rotation_x(float angle, matrix44 * dst)
{
float sinus, cosinus;
cosinus = cosf(angle);
sinus = sinf(angle);
matrix44_empty(dst);
dst->V[0].x = 1;
dst->V[1].y = cosinus;
dst->V[1].z = sinus;
dst->V[2].y = -1 * sinus;
dst->V[2].z = cosinus;
dst->V[3].w = 1;
}
/*******************************************************************************/
/* Créé une matrice de rotation autour de Y */
void matrix44_rotation_y(float angle, matrix44 * dst)
{
float sinus, cosinus;
cosinus = cosf(angle);
sinus = sinf(angle);
matrix44_empty(dst);
dst->V[0].x = cosinus;
dst->V[0].z = -1 * sinus;
dst->V[1].y = 1;
dst->V[2].x = sinus;
dst->V[2].z = cosinus;
dst->V[3].w = 1;
}
/*******************************************************************************/
/* Créé une matrice de rotation autour de Z */
void matrix44_rotation_z(float angle, matrix44 * dst)
{
float sinus, cosinus;
cosinus = cosf(angle);
sinus = sinf(angle);
matrix44_empty(dst);
dst->V[0].x = cosinus;
dst->V[0].y = sinus;
dst->V[1].x = -1 * sinus;
dst->V[1].y = cosinus;
dst->V[2].z = 1;
dst->V[3].w = 1;
}
/*******************************************************************************/
/* Créé une matrice de rotation multiple */
void matrix44_rotation(vector4 axis, float angle, matrix44 * dst)
{
float cosinus, sinus, minuscos;
sinus = sinf(angle);
cosinus = cosf(angle);
vector4_normalize(&axis);
minuscos = 1 - cosinus;
dst->V[0].x = (minuscos * axis.x * axis.x) + cosinus;
dst->V[0].y = (minuscos * axis.x * axis.y) - (axis.z * sinus);
dst->V[0].z = (minuscos * axis.z * axis.x) + (axis.y * sinus);
dst->V[0].w = 0;
dst->V[1].x = (minuscos * axis.x * axis.y) + (axis.z * sinus);
dst->V[1].y = (minuscos * axis.y * axis.y) + cosinus;
dst->V[1].z = (minuscos * axis.y * axis.z) - (axis.x * sinus);
dst->V[1].w = 0;
dst->V[2].x = (minuscos * axis.z * axis.x) - (axis.y * sinus);
dst->V[2].y = (minuscos * axis.y * axis.z) + (axis.x * sinus);
dst->V[2].z = (minuscos * axis.z * axis.z) + cosinus;
dst->V[2].w = 0;
dst->V[3].x = 0;
dst->V[3].y = 0;
dst->V[3].z = 0;
dst->V[3].w = 1;
}
/*******************************************************************************/
/* Multiplie deux matrices */
void matrix44_multiply(matrix44 * m1, matrix44 * m2, matrix44 * dst)
{
dst->V[0].x =
(m1->V[0].x * m2->V[0].x + m1->V[0].y * m2->V[1].x +
m1->V[0].z * m2->V[2].x + m1->V[0].w * m2->V[3].x);
dst->V[0].y =
(m1->V[0].x * m2->V[0].y + m1->V[0].y * m2->V[1].y +
m1->V[0].z * m2->V[2].y + m1->V[0].w * m2->V[3].y);
dst->V[0].z =
(m1->V[0].x * m2->V[0].z + m1->V[0].y * m2->V[1].z +
m1->V[0].z * m2->V[2].z + m1->V[0].w * m2->V[3].z);
dst->V[0].w =
(m1->V[0].x * m2->V[0].w + m1->V[0].y * m2->V[1].w +
m1->V[0].z * m2->V[2].w + m1->V[0].w * m2->V[3].w);
dst->V[1].x =
(m1->V[1].x * m2->V[0].x + m1->V[1].y * m2->V[1].x +
m1->V[1].z * m2->V[2].x + m1->V[1].w * m2->V[3].x);
dst->V[1].y =
(m1->V[1].x * m2->V[0].y + m1->V[1].y * m2->V[1].y +
m1->V[1].z * m2->V[2].y + m1->V[1].w * m2->V[3].y);
dst->V[1].z =
(m1->V[1].x * m2->V[0].z + m1->V[1].y * m2->V[1].z +
m1->V[1].z * m2->V[2].z + m1->V[1].w * m2->V[3].z);
dst->V[1].w =
(m1->V[1].x * m2->V[0].w + m1->V[1].y * m2->V[1].w +
m1->V[1].z * m2->V[2].w + m1->V[1].w * m2->V[3].w);
dst->V[2].x =
(m1->V[2].x * m2->V[0].x + m1->V[2].y * m2->V[1].x +
m1->V[2].z * m2->V[2].x + m1->V[2].w * m2->V[3].x);
dst->V[2].y =
(m1->V[2].x * m2->V[0].y + m1->V[2].y * m2->V[1].y +
m1->V[2].z * m2->V[2].y + m1->V[2].w * m2->V[3].y);
dst->V[2].z =
(m1->V[2].x * m2->V[0].z + m1->V[2].y * m2->V[1].z +
m1->V[2].z * m2->V[2].z + m1->V[2].w * m2->V[3].z);
dst->V[2].w =
(m1->V[2].x * m2->V[0].w + m1->V[2].y * m2->V[1].w +
m1->V[2].z * m2->V[2].w + m1->V[2].w * m2->V[3].w);
dst->V[3].x =
(m1->V[3].x * m2->V[0].x + m1->V[3].y * m2->V[1].x +
m1->V[3].z * m2->V[2].x + m1->V[3].w * m2->V[3].x);
dst->V[3].y =
(m1->V[3].x * m2->V[0].y + m1->V[3].y * m2->V[1].y +
m1->V[3].z * m2->V[2].y + m1->V[3].w * m2->V[3].y);
dst->V[3].z =
(m1->V[3].x * m2->V[0].z + m1->V[3].y * m2->V[1].z +
m1->V[3].z * m2->V[2].z + m1->V[3].w * m2->V[3].z);
dst->V[3].w =
(m1->V[3].x * m2->V[0].w + m1->V[3].y * m2->V[1].w +
m1->V[3].z * m2->V[2].w + m1->V[3].w * m2->V[3].w);
}
/*******************************************************************************/
/* Transforme une matrice avec un vecteur à 4 composantes */
void matrix44_transform(matrix44 * matrix, vector4 * dst)
{
vector4 origin;
origin.x = dst->x;
origin.y = dst->y;
origin.z = dst->z;
origin.w = dst->w;
dst->x = origin.x * matrix->V[0].x + origin.y * matrix->V[1].x +
origin.z * matrix->V[2].x + origin.w * matrix->V[3].x;
dst->y = origin.x * matrix->V[0].y + origin.y * matrix->V[1].y +
origin.z * matrix->V[2].y + origin.w * matrix->V[3].y;
dst->z = origin.x * matrix->V[0].z + origin.y * matrix->V[1].z +
origin.z * matrix->V[2].z + origin.w * matrix->V[3].z;
dst->w = origin.x * matrix->V[0].w + origin.y * matrix->V[1].w +
origin.z * matrix->V[2].w + origin.w * matrix->V[3].w;
}
/*******************************************************************************/
/* Calcule le déterminant d'une matrice */
float matrix44_determinant(matrix44 * matrix)
{
float a, b, c, d;
a = matrix->V[0].x * todeterminant(matrix->V[1].y, matrix->V[2].y,
matrix->V[3].y, matrix->V[1].z,
matrix->V[2].z, matrix->V[3].z,
matrix->V[1].w, matrix->V[2].w,
matrix->V[3].w);
b = matrix->V[0].y * todeterminant(matrix->V[1].x, matrix->V[2].x,
matrix->V[3].x, matrix->V[1].z,
matrix->V[2].z, matrix->V[3].z,
matrix->V[1].w, matrix->V[2].w,
matrix->V[3].w);
c = matrix->V[0].z * todeterminant(matrix->V[1].x, matrix->V[2].x,
matrix->V[3].x, matrix->V[1].y,
matrix->V[2].y, matrix->V[3].y,
matrix->V[1].w, matrix->V[2].w,
matrix->V[3].w);
d = matrix->V[0].w * todeterminant(matrix->V[1].x, matrix->V[2].x,
matrix->V[3].x, matrix->V[1].y,
matrix->V[2].y, matrix->V[3].y,
matrix->V[1].z, matrix->V[2].z,
matrix->V[3].z);
return a - b + c - d;
}
float todeterminant(float a1, float a2, float a3, float b1, float b2,
float b3, float c1, float c2, float c3)
{
return (a1 * ((b2 * c3) - (b3 * c2))) -
(b1 * ((a2 * c3) - (a3 * c2))) +
(c1 * ((a2 * b3) - (a3 * b2)));
}
/*******************************************************************************/
/* Crée une matrice adjointe */
void matrix44_adjoint(matrix44 * matrix)
{
float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3,
d4;
a1 = matrix->V[0].x;
b1 = matrix->V[0].y;
c1 = matrix->V[0].z;
d1 = matrix->V[0].w;
a2 = matrix->V[1].x;
b2 = matrix->V[1].y;
c2 = matrix->V[1].z;
d2 = matrix->V[1].w;
a3 = matrix->V[2].x;
b3 = matrix->V[2].y;
c3 = matrix->V[2].z;
d3 = matrix->V[2].w;
a4 = matrix->V[3].x;
b4 = matrix->V[3].y;
c4 = matrix->V[3].z;
d4 = matrix->V[3].w;
matrix->V[0].x = todeterminant(b2, b3, b4, c2, c3, c4, d2, d3, d4);
matrix->V[1].x =
-todeterminant(a2, a3, a4, c2, c3, c4, d2, d3, d4);
matrix->V[2].x = todeterminant(a2, a3, a4, b2, b3, b4, d2, d3, d4);
matrix->V[3].x =
-todeterminant(a2, a3, a4, b2, b3, b4, c2, c3, c4);
matrix->V[0].y =
-todeterminant(b1, b3, b4, c1, c3, c4, d1, d3, d4);
matrix->V[1].y = todeterminant(a1, a3, a4, c1, c3, c4, d1, d3, d4);
matrix->V[2].y =
-todeterminant(a1, a3, a4, b1, b3, b4, d1, d3, d4);
matrix->V[3].y = todeterminant(a1, a3, a4, b1, b3, b4, c1, c3, c4);
matrix->V[0].z = todeterminant(b1, b2, b4, c1, c2, c4, d1, d2, d4);
matrix->V[1].z =
-todeterminant(a1, a2, a4, c1, c2, c4, d1, d2, d4);
matrix->V[2].z = todeterminant(a1, a2, a4, b1, b2, b4, d1, d2, d4);
matrix->V[3].z =
-todeterminant(a1, a2, a4, b1, b2, b4, c1, c2, c4);
matrix->V[0].w =
-todeterminant(b1, b2, b3, c1, c2, c3, d1, d2, d3);
matrix->V[1].w = todeterminant(a1, a2, a3, c1, c2, c3, d1, d2, d3);
matrix->V[2].w =
-todeterminant(a1, a2, a3, b1, b2, b3, d1, d2, d3);
matrix->V[3].w = todeterminant(a1, a2, a3, b1, b2, b3, c1, c2, c3);
}
/*******************************************************************************/
/* Affiche une matrice */
void matrix44_show(matrix44 * matrix)
{
printf("Matrice: X=%f Y=%f Z=%f W=%f \r\n", matrix->V[0].x,
matrix->V[1].y, matrix->V[2].z, matrix->V[3].w);
printf(" X=%f Y=%f Z=%f W=%f \r\n", matrix->V[0].x,
matrix->V[1].y, matrix->V[2].z, matrix->V[3].w);
printf(" X=%f Y=%f Z=%f W=%f \r\n", matrix->V[0].x,
matrix->V[1].y, matrix->V[2].z, matrix->V[3].w);
}
/*******************************************************************************/
/* Inverse une matrice */
void matrix44_invert(matrix44 * matrix)
{
float det;
det = matrix44_determinant(matrix);
if (fabs(det) < EPSILON)
{
matrix44_homogen(matrix);
}
else
{
matrix44_adjoint(matrix);
matrix44_scale(matrix, 1.0 / det);
}
}
/*******************************************************************************/
/* Transpose une matrice */
void matrix44_transpose(matrix44 * matrix)
{
float f;
f = matrix->V[0].y;
matrix->V[0].y = matrix->V[1].x;
matrix->V[1].x = f;
f = matrix->V[0].z;
matrix->V[0].z = matrix->V[2].x;
matrix->V[2].x = f;
f = matrix->V[0].w;
matrix->V[0].w = matrix->V[3].x;
matrix->V[3].x = f;
f = matrix->V[1].z;
matrix->V[1].z = matrix->V[2].y;
matrix->V[2].y = f;
f = matrix->V[1].w;
matrix->V[1].w = matrix->V[3].y;
matrix->V[3].y = f;
f = matrix->V[2].w;
matrix->V[2].w = matrix->V[3].z;
matrix->V[3].z = f;
}
/*******************************************************************************/
/* Crée une matrice de camera */
void matrix44_lookat(vector4 eye, vector4 dst, vector4 up,
matrix44 * matrix)
{
vector4 xaxis, yaxis, zaxis, negeye;
vector4_sub(dst, eye, &zaxis);
vector4_normalize(&zaxis);
vector4_crossproduct(zaxis, up, &xaxis);
vector4_normalize(&xaxis);
vector4_crossproduct(xaxis, zaxis, &yaxis);
vector4_copy(xaxis, &matrix->V[0]);
vector4_copy(yaxis, &matrix->V[1]);
vector4_copy(zaxis, &matrix->V[2]);
matrix->V[2].x = -matrix->V[2].x;
matrix->V[2].y = -matrix->V[2].y;
matrix->V[2].z = -matrix->V[2].z;
vector4_create(0, 0, 0, 1, &matrix->V[3]);
matrix44_transpose(matrix);
vector4_create(-eye.x, -eye.y, -eye.z, 1, &negeye);
matrix44_transform(matrix, &negeye);
vector4_copy(negeye, &matrix->V[3]);
}
/*******************************************************************************/
/* Vérifie que deux matrices sont égales */
int matrix44_isequals(matrix44 * m1, matrix44 * m2)
{
return vector4_isequals(m1->V[0], m2->V[0])
&& vector4_isequals(m1->V[1], m2->V[1])
&& vector4_isequals(m1->V[2], m2->V[2])
&& vector4_isequals(m1->V[3], m2->V[3]);
}
/*******************************************************************************/
/* Transforme une matrice en tableau */
float *toarray(matrix44 * m)
{
return &m->v;
}