omicron/src/matrix.c

260 lines
6.8 KiB
C

#include <math.h>
#include "config.h"
#include "matrix.h"
#include "util.h"
void normalize(float *x, float *y, float *z) {
float d = sqrtf((*x) * (*x) + (*y) * (*y) + (*z) * (*z));
*x /= d; *y /= d; *z /= d;
}
void mat_identity(float *matrix) {
matrix[0] = 1;
matrix[1] = 0;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = 0;
matrix[5] = 1;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = 1;
matrix[11] = 0;
matrix[12] = 0;
matrix[13] = 0;
matrix[14] = 0;
matrix[15] = 1;
}
void mat_translate(float *matrix, float dx, float dy, float dz) {
matrix[0] = 1;
matrix[1] = 0;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = 0;
matrix[5] = 1;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = 1;
matrix[11] = 0;
matrix[12] = dx;
matrix[13] = dy;
matrix[14] = dz;
matrix[15] = 1;
}
void mat_rotate(float *matrix, float x, float y, float z, float angle) {
normalize(&x, &y, &z);
float s = sinf(angle);
float c = cosf(angle);
float m = 1 - c;
matrix[0] = m * x * x + c;
matrix[1] = m * x * y - z * s;
matrix[2] = m * z * x + y * s;
matrix[3] = 0;
matrix[4] = m * x * y + z * s;
matrix[5] = m * y * y + c;
matrix[6] = m * y * z - x * s;
matrix[7] = 0;
matrix[8] = m * z * x - y * s;
matrix[9] = m * y * z + x * s;
matrix[10] = m * z * z + c;
matrix[11] = 0;
matrix[12] = 0;
matrix[13] = 0;
matrix[14] = 0;
matrix[15] = 1;
}
void mat_vec_multiply(float *vector, float *a, float *b) {
float result[4];
for (int i = 0; i < 4; i++) {
float total = 0;
for (int j = 0; j < 4; j++) {
int p = j * 4 + i;
int q = j;
total += a[p] * b[q];
}
result[i] = total;
}
for (int i = 0; i < 4; i++) {
vector[i] = result[i];
}
}
void mat_multiply(float *matrix, float *a, float *b) {
float result[16];
for (int c = 0; c < 4; c++) {
for (int r = 0; r < 4; r++) {
int index = c * 4 + r;
float total = 0;
for (int i = 0; i < 4; i++) {
int p = i * 4 + r;
int q = c * 4 + i;
total += a[p] * b[q];
}
result[index] = total;
}
}
for (int i = 0; i < 16; i++) {
matrix[i] = result[i];
}
}
void mat_apply(float *data, float *matrix, int count, int offset, int stride) {
float vec[4] = {0, 0, 0, 1};
for (int i = 0; i < count; i++) {
float *d = data + offset + stride * i;
vec[0] = *(d++); vec[1] = *(d++); vec[2] = *(d++);
mat_vec_multiply(vec, matrix, vec);
d = data + offset + stride * i;
*(d++) = vec[0]; *(d++) = vec[1]; *(d++) = vec[2];
}
}
void frustum_planes(float planes[6][4], int radius, float *matrix) {
float znear = 0.125;
float zfar = radius * 32 + 64;
float *m = matrix;
planes[0][0] = m[3] + m[0];
planes[0][1] = m[7] + m[4];
planes[0][2] = m[11] + m[8];
planes[0][3] = m[15] + m[12];
planes[1][0] = m[3] - m[0];
planes[1][1] = m[7] - m[4];
planes[1][2] = m[11] - m[8];
planes[1][3] = m[15] - m[12];
planes[2][0] = m[3] + m[1];
planes[2][1] = m[7] + m[5];
planes[2][2] = m[11] + m[9];
planes[2][3] = m[15] + m[13];
planes[3][0] = m[3] - m[1];
planes[3][1] = m[7] - m[5];
planes[3][2] = m[11] - m[9];
planes[3][3] = m[15] - m[13];
planes[4][0] = znear * m[3] + m[2];
planes[4][1] = znear * m[7] + m[6];
planes[4][2] = znear * m[11] + m[10];
planes[4][3] = znear * m[15] + m[14];
planes[5][0] = zfar * m[3] - m[2];
planes[5][1] = zfar * m[7] - m[6];
planes[5][2] = zfar * m[11] - m[10];
planes[5][3] = zfar * m[15] - m[14];
}
void mat_frustum(
float *matrix, float left, float right, float bottom,
float top, float znear, float zfar)
{
float temp, temp2, temp3, temp4;
temp = 2.0 * znear;
temp2 = right - left;
temp3 = top - bottom;
temp4 = zfar - znear;
matrix[0] = temp / temp2;
matrix[1] = 0.0;
matrix[2] = 0.0;
matrix[3] = 0.0;
matrix[4] = 0.0;
matrix[5] = temp / temp3;
matrix[6] = 0.0;
matrix[7] = 0.0;
matrix[8] = (right + left) / temp2;
matrix[9] = (top + bottom) / temp3;
matrix[10] = (-zfar - znear) / temp4;
matrix[11] = -1.0;
matrix[12] = 0.0;
matrix[13] = 0.0;
matrix[14] = (-temp * zfar) / temp4;
matrix[15] = 0.0;
}
void mat_perspective(
float *matrix, float fov, float aspect,
float znear, float zfar)
{
float ymax, xmax;
ymax = znear * tanf(fov * PI / 360.0);
xmax = ymax * aspect;
mat_frustum(matrix, -xmax, xmax, -ymax, ymax, znear, zfar);
}
void mat_ortho(
float *matrix,
float left, float right, float bottom, float top, float near, float far)
{
matrix[0] = 2 / (right - left);
matrix[1] = 0;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = 0;
matrix[5] = 2 / (top - bottom);
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = -2 / (far - near);
matrix[11] = 0;
matrix[12] = -(right + left) / (right - left);
matrix[13] = -(top + bottom) / (top - bottom);
matrix[14] = -(far + near) / (far - near);
matrix[15] = 1;
}
void set_matrix_2d(float *matrix, int width, int height) {
mat_ortho(matrix, 0, width, 0, height, -1, 1);
}
void set_matrix_3d(
float *matrix, int width, int height,
float x, float y, float z, float rx, float ry,
float fov, int ortho, int radius)
{
float a[16];
float b[16];
float aspect = (float)width / height;
float znear = 0.125;
float zfar = radius * 32 + 64;
mat_identity(a);
mat_translate(b, -x, -y, -z);
mat_multiply(a, b, a);
mat_rotate(b, cosf(rx), 0, sinf(rx), ry);
mat_multiply(a, b, a);
mat_rotate(b, 0, 1, 0, -rx);
mat_multiply(a, b, a);
if (ortho) {
int size = ortho;
mat_ortho(b, -size * aspect, size * aspect, -size, size, -zfar, zfar);
}
else {
mat_perspective(b, fov, aspect, znear, zfar);
}
mat_multiply(a, b, a);
mat_identity(matrix);
mat_multiply(matrix, a, matrix);
}
void set_matrix_item(float *matrix, int width, int height, int scale) {
float a[16];
float b[16];
float aspect = (float)width / height;
float size = 32 * scale;
float box = height / size / 2;
float xoffset = 1 - size / width * 2;
float yoffset = 1 - size / height * 2;
mat_identity(a);
mat_rotate(b, 0, 1, 0, -PI / 4);
mat_multiply(a, b, a);
mat_rotate(b, 1, 0, 0, -PI / 10);
mat_multiply(a, b, a);
mat_ortho(b, -box * aspect, box * aspect, -box, box, -1, 1);
mat_multiply(a, b, a);
mat_translate(b, -xoffset + 1.75f, -yoffset, 0);
mat_multiply(a, b, a);
mat_identity(matrix);
mat_multiply(matrix, a, matrix);
}