Merge pull request #9 from bjornbytes/math

Math
This commit is contained in:
Bjorn Swenson 2017-01-20 20:44:05 -08:00 committed by GitHub
commit a3a3a368c0
37 changed files with 832 additions and 494 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ deps
data
src/obj
src/Tupfile
/watch.sh
*.lua
*.glsl
.DS_Store

View File

@ -1,5 +1,7 @@
#include "audio/audio.h"
#include "loaders/source.h"
#include "math/vec3.h"
#include "math/quat.h"
#include "util.h"
#include <stdlib.h>
#include <math.h>
@ -8,12 +10,6 @@ static AudioState state;
static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
static void cross(float ux, float uy, float uz, float vx, float vy, float vz, float* x, float* y, float* z) {
*x = uy * vz - uz * vy;
*y = ux * vz - uz * vx;
*z = ux * vy - uy * vx;
}
void lovrAudioInit() {
ALCdevice* device = alcOpenDevice(NULL);
if (!device) {
@ -35,6 +31,9 @@ void lovrAudioInit() {
state.device = device;
state.context = context;
vec_init(&state.sources);
vec3_set(state.position, 0, 0, 0);
quat_set(state.orientation, 0, 0, 0, -1);
}
void lovrAudioDestroy() {
@ -73,33 +72,13 @@ void lovrAudioAdd(Source* source) {
}
void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az) {
float v[6];
alGetListenerfv(AL_ORIENTATION, v);
float cx, cy, cz;
cross(v[0], v[1], v[2], v[3], v[4], v[5], &cx, &cy, &cz);
float w = 1 + v[0] * v[3] + v[1] * v[4] + v[2] * v[5];
float len = sqrt(cx * cx + cy * cy + cz * cz + w * w);
if (len != 1) {
cx /= len;
cy /= len;
cz /= len;
w /= len;
}
*angle = 2 * acos(w);
float s = sqrt(1 - w * w);
if (s < .001) {
*ax = cx;
*ay = cy;
*az = cz;
} else {
*ax = cx / s;
*ay = cy / s;
*az = cz / s;
}
quat_getAngleAxis(state.orientation, angle, ax, ay, az);
}
void lovrAudioGetPosition(float* x, float* y, float* z) {
alGetListener3f(AL_POSITION, x, y, z);
*x = state.position[0];
*y = state.position[1];
*z = state.position[2];
}
float lovrAudioGetVolume() {
@ -135,52 +114,23 @@ void lovrAudioRewind() {
}
}
// Help
void lovrAudioSetOrientation(float angle, float ax, float ay, float az) {
// Quaternion
float cos2 = cos(angle / 2.f);
float sin2 = sin(angle / 2.f);
float qx = sin2 * ax;
float qy = sin2 * ay;
float qz = sin2 * az;
float s = cos2;
// Rotate the unit forward/up vectors by the quaternion derived from the specified angle/axis
float f[3] = { 0, 0, -1 };
float u[3] = { 0, 1, 0 };
float axis[3] = { ax, ay, az };
quat_fromAngleAxis(state.orientation, angle, axis);
quat_rotate(state.orientation, f);
quat_rotate(state.orientation, u);
float vx, vy, vz, qdotv, qdotq, a, b, c, cx, cy, cz;
// Forward
vx = 0;
vy = 0;
vz = -1;
qdotv = qx * vx + qy * vy + qz * vz;
qdotq = qx * qx + qy * qy + qz * qz;
a = 2 * qdotv;
b = s * s - qdotq;
c = 2 * s;
cross(qx, qy, qz, vx, vy, vz, &cx, &cy, &cz);
float fx = a * qx + b * vx + c * cx;
float fy = a * qy + b * vy + c * cy;
float fz = a * qz + b * vz + c * cz;
// Up
vx = 0;
vy = 1;
vz = 0;
qdotv = qx * vx + qy * vy + qz * vz;
qdotq = qx * qx + qy * qy + qz * qz;
a = 2 * qdotv;
b = s * s - qdotq;
c = 2 * s;
cross(qx, qy, qz, vx, vy, vz, &cx, &cy, &cz);
float ux = a * qx + b * vx + c * cx;
float uy = a * qy + b * vy + c * cy;
float uz = a * qz + b * vz + c * cz;
ALfloat orientation[6] = { fx, fy, fz, ux, uy, uz };
// Pass the rotated orientation vectors to OpenAL
ALfloat orientation[6] = { f[0], f[1], f[2], u[0], u[1], u[2] };
alListenerfv(AL_ORIENTATION, orientation);
}
void lovrAudioSetPosition(float x, float y, float z) {
vec3_set(state.position, x, y, z);
alListener3f(AL_POSITION, x, y, z);
}

View File

@ -11,6 +11,8 @@ typedef struct {
ALCdevice* device;
ALCcontext* context;
vec_void_t sources;
float position[3];
float orientation[4];
} AudioState;
#endif

View File

@ -1,5 +1,7 @@
#include "graphics/graphics.h"
#include "loaders/texture.h"
#include "math/mat4.h"
#include "math/vec3.h"
#include "util.h"
#include "glfw.h"
#define _USE_MATH_DEFINES
@ -14,9 +16,6 @@ static GraphicsState state;
// Base
void lovrGraphicsInit() {
for (int i = 0; i < MAX_TRANSFORMS; i++) {
state.transforms[i] = mat4_init();
}
for (int i = 0; i < MAX_CANVASES; i++) {
state.canvases[i] = malloc(sizeof(CanvasState));
}
@ -38,9 +37,6 @@ void lovrGraphicsInit() {
void lovrGraphicsDestroy() {
lovrGraphicsSetShader(NULL);
glUseProgram(0);
for (int i = 0; i < MAX_TRANSFORMS; i++) {
mat4_deinit(state.transforms[i]);
}
for (int i = 0; i < MAX_CANVASES; i++) {
free(state.canvases[i]);
}
@ -203,7 +199,7 @@ mat4 lovrGraphicsGetProjection() {
void lovrGraphicsSetProjection(float near, float far, float fov) {
int width, height;
glfwGetWindowSize(window, &width, &height);
mat4_setPerspective(state.canvases[state.canvas]->projection, near, far, fov, (float) width / height);
mat4_perspective(state.canvases[state.canvas]->projection, near, far, fov, (float) width / height);
}
void lovrGraphicsSetProjectionRaw(mat4 projection) {
@ -333,7 +329,7 @@ int lovrGraphicsPop() {
}
void lovrGraphicsOrigin() {
mat4_setIdentity(state.transforms[state.transform]);
mat4_identity(state.transforms[state.transform]);
}
void lovrGraphicsTranslate(float x, float y, float z) {
@ -348,16 +344,6 @@ void lovrGraphicsScale(float x, float y, float z) {
mat4_scale(state.transforms[state.transform], x, y, z);
}
void lovrGraphicsTransform(float tx, float ty, float tz, float sx, float sy, float sz, float angle, float ax, float ay, float az) {
// M *= T * S * R
float transform[16];
mat4_setTranslation(transform, tx, ty, tz);
mat4_scale(transform, sx, sy, sz);
mat4_rotate(transform, angle, ax, ay, az);
lovrGraphicsMatrixTransform(transform);
}
void lovrGraphicsMatrixTransform(mat4 transform) {
mat4_multiply(state.transforms[state.transform], transform);
}
@ -420,16 +406,13 @@ void lovrGraphicsTriangle(DrawMode mode, float* points) {
vec_pusharr(&state.shapeData, points, 9);
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 0, 0, 0);
} else {
float n[3] = {
points[1] * points[5] - points[2] * points[4],
points[2] * points[3] - points[0] * points[5],
points[0] * points[4] - points[1] * points[3]
};
float normal[3];
vec3_cross(vec3_init(normal, &points[0]), &points[3]);
float data[18] = {
points[0], points[1], points[2], n[0], n[1], n[2],
points[3], points[4], points[5], n[0], n[1], n[2],
points[6], points[7], points[8], n[0], n[1], n[2]
points[0], points[1], points[2], normal[0], normal[1], normal[2],
points[3], points[4], points[5], normal[0], normal[1], normal[2],
points[6], points[7], points[8], normal[0], normal[1], normal[2]
};
vec_clear(&state.shapeData);
@ -442,7 +425,7 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float
// Normalize the normal vector
float len = sqrt(nx * nx + ny * ny + nz + nz);
if (len != 1) {
if (len != 0) {
len = 1 / len;
nx *= len;
ny *= len;
@ -457,8 +440,11 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float
// Angle between normal vector and the normal vector of the default geometry (dot product)
float theta = acos(nz);
float transform[16];
mat4_setTransform(transform, x, y, z, size, theta, cx, cy, cz);
lovrGraphicsPush();
lovrGraphicsTransform(x, y, z, size, size, size, theta, cx, cy, cz);
lovrGraphicsMatrixTransform(transform);
if (mode == DRAW_MODE_LINE) {
float points[] = {
@ -507,9 +493,9 @@ void lovrGraphicsPlaneFullscreen(Texture* texture) {
lovrRelease(&lastShader->ref);
}
void lovrGraphicsCube(DrawMode mode, Texture* texture, float x, float y, float z, float size, float angle, float axisX, float axisY, float axisZ) {
void lovrGraphicsCube(DrawMode mode, Texture* texture, mat4 transform) {
lovrGraphicsPush();
lovrGraphicsTransform(x, y, z, size, size, size, angle, axisX, axisY, axisZ);
lovrGraphicsMatrixTransform(transform);
if (mode == DRAW_MODE_LINE) {
float points[] = {

View File

@ -3,7 +3,7 @@
#include "graphics/shader.h"
#include "graphics/skybox.h"
#include "graphics/texture.h"
#include "matrix.h"
#include "math/math.h"
#ifndef LOVR_GRAPHICS_TYPES
#define LOVR_GRAPHICS_TYPES
@ -50,10 +50,10 @@ typedef struct {
Shader* skyboxShader;
Shader* fullscreenShader;
Texture* defaultTexture;
int transform;
mat4 transforms[MAX_TRANSFORMS];
int canvas;
float transforms[MAX_TRANSFORMS][16];
CanvasState* canvases[MAX_CANVASES];
int transform;
int canvas;
unsigned int color;
char colorMask;
int isScissorEnabled;
@ -124,7 +124,6 @@ void lovrGraphicsOrigin();
void lovrGraphicsTranslate(float x, float y, float z);
void lovrGraphicsRotate(float angle, float ax, float ay, float az);
void lovrGraphicsScale(float x, float y, float z);
void lovrGraphicsTransform(float tx, float ty, float tz, float sx, float sy, float sz, float angle, float ax, float ay, float az);
void lovrGraphicsMatrixTransform(mat4 transform);
// Primitives
@ -134,5 +133,5 @@ void lovrGraphicsLine(float* points, int count);
void lovrGraphicsTriangle(DrawMode mode, float* points);
void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float z, float size, float nx, float ny, float nz);
void lovrGraphicsPlaneFullscreen(Texture* texture);
void lovrGraphicsCube(DrawMode mode, Texture* texture, float x, float y, float z, float size, float angle, float axisX, float axisY, float axisZ);
void lovrGraphicsCube(DrawMode mode, Texture* texture, mat4 transform);
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az);

View File

@ -1,14 +1,16 @@
#include "graphics/model.h"
#include "graphics/graphics.h"
#include "math/mat4.h"
#include "math/vec3.h"
#include <stdlib.h>
static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) {
mat4 newTransform;
float newTransform[16];
if (!transform) {
newTransform = mat4_init();
if (transform) {
mat4_set(newTransform, transform);
} else {
newTransform = mat4_copy(transform);
mat4_identity(newTransform);
}
mat4_multiply(newTransform, node->transform);
@ -23,15 +25,9 @@ static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec
for (int v = 0; v < mesh->vertices.length; v++) {
ModelVertex vertex = mesh->vertices.data[v];
float transformedVertex[4] = {
vertex.x,
vertex.y,
vertex.z,
1.f
};
mat4_multiplyVector(newTransform, transformedVertex);
vec_pusharr(vertices, transformedVertex, 3);
float vec[3] = { vertex.x, vertex.y, vertex.z };
mat4_transform(newTransform, vec);
vec_pusharr(vertices, vec, 3);
if (modelData->hasNormals) {
ModelVertex normal = mesh->normals.data[v];
@ -59,8 +55,6 @@ static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec
for (int c = 0; c < node->children.length; c++) {
visitNode(modelData, node->children.data[c], newTransform, vertices, indices);
}
mat4_deinit(newTransform);
}
Model* lovrModelCreate(ModelData* modelData) {
@ -136,7 +130,6 @@ void lovrModelDataDestroy(ModelData* modelData) {
while (nodes.length > 0) {
ModelNode* node = vec_first(&nodes);
vec_extend(&nodes, &node->children);
mat4_deinit(node->transform);
vec_deinit(&node->meshes);
vec_deinit(&node->children);
vec_splice(&nodes, 0, 1);
@ -148,9 +141,9 @@ void lovrModelDataDestroy(ModelData* modelData) {
free(modelData);
}
void lovrModelDraw(Model* model, float x, float y, float z, float scale, float angle, float ax, float ay, float az) {
void lovrModelDraw(Model* model, mat4 transform) {
lovrGraphicsPush();
lovrGraphicsTransform(x, y, z, scale, scale, scale, angle, ax, ay, az);
lovrGraphicsMatrixTransform(transform);
lovrBufferDraw(model->buffer);
lovrGraphicsPop();
}

View File

@ -1,6 +1,6 @@
#include "graphics/buffer.h"
#include "graphics/texture.h"
#include "matrix.h"
#include "math/math.h"
#include "glfw.h"
#include "util.h"
#include "vendor/vec/vec.h"
@ -32,7 +32,7 @@ typedef struct {
typedef vec_t(ModelMesh*) vec_model_mesh_t;
typedef struct ModelNode {
mat4 transform;
float transform[16];
vec_uint_t meshes;
vec_void_t children;
} ModelNode;
@ -57,6 +57,6 @@ typedef struct {
Model* lovrModelCreate(ModelData* modelData);
void lovrModelDestroy(const Ref* ref);
void lovrModelDataDestroy(ModelData* modelData);
void lovrModelDraw(Model* model, float x, float y, float z, float scale, float angle, float ax, float ay, float az);
void lovrModelDraw(Model* model, mat4 transform);
Texture* lovrModelGetTexture(Model* model);
void lovrModelSetTexture(Model* model, Texture* texture);

View File

@ -1,4 +1,5 @@
#include "graphics/shader.h"
#include "math/mat4.h"
#include "util.h"
#include <stdlib.h>
@ -162,8 +163,8 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
// Initial state
shader->id = id;
shader->transform = mat4_init();
shader->projection = mat4_init();
mat4_identity(shader->transform);
mat4_identity(shader->projection);
shader->color = 0;
// Send initial uniform values to shader
@ -175,8 +176,6 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
void lovrShaderDestroy(const Ref* ref) {
Shader* shader = containerof(ref, Shader);
glDeleteProgram(shader->id);
mat4_deinit(shader->transform);
mat4_deinit(shader->projection);
map_deinit(&shader->uniforms);
free(shader);
}

View File

@ -1,5 +1,5 @@
#include "glfw.h"
#include "matrix.h"
#include "math/math.h"
#include "vendor/map/map.h"
#include "util.h"
@ -26,8 +26,8 @@ typedef struct {
Ref ref;
int id;
map_uniform_t uniforms;
mat4 transform;
mat4 projection;
float transform[16];
float projection[16];
unsigned int color;
} Shader;
#endif

View File

@ -1,5 +1,6 @@
#include "graphics/texture.h"
#include "graphics/graphics.h"
#include "math/mat4.h"
#include "util.h"
#include <math.h>
#include <stdlib.h>
@ -109,7 +110,7 @@ void lovrTextureBindFramebuffer(Texture* texture) {
if (texture->projection == PROJECTION_ORTHOGRAPHIC) {
float projection[16];
mat4_setOrthographic(projection, 0, w, 0, h, -1, 1);
mat4_orthographic(projection, 0, w, 0, h, -1, 1);
lovrGraphicsSetProjectionRaw(projection);
} else if (texture->projection == PROJECTION_PERSPECTIVE) {
mat4 projection = lovrGraphicsGetProjection();
@ -122,7 +123,7 @@ void lovrTextureBindFramebuffer(Texture* texture) {
float far = k * near;
float fov = 2.f * atan(1.f / b);
float newProjection[16];
mat4_setPerspective(newProjection, near, far, fov, aspect);
mat4_perspective(newProjection, near, far, fov, aspect);
lovrGraphicsSetProjectionRaw(newProjection);
}
}

View File

@ -108,13 +108,13 @@ void lovrHeadsetGetPosition(float* x, float* y, float* z) {
headset->getPosition(headset, x, y, z);
}
void lovrHeadsetGetOrientation(float* w, float* x, float* y, float* z) {
void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z) {
if (!headset) {
*w = *x = *y = *z = 0.f;
*angle = *x = *y = *z = 0.f;
return;
}
headset->getOrientation(headset, w, x, y, z);
headset->getOrientation(headset, angle, x, y, z);
}
void lovrHeadsetGetVelocity(float* x, float* y, float* z) {
@ -160,13 +160,13 @@ void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y
headset->controllerGetPosition(headset, controller, x, y, z);
}
void lovrHeadsetControllerGetOrientation(Controller* controller, float* w, float* x, float* y, float* z) {
void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) {
if (!headset || !controller) {
*w = *x = *y = *z = 0.f;
*angle = *x = *y = *z = 0.f;
return;
}
headset->controllerGetOrientation(headset, controller, w, x, y, z);
headset->controllerGetOrientation(headset, controller, angle, x, y, z);
}
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) {

View File

@ -44,13 +44,13 @@ typedef struct {
char (*isBoundsVisible)(void* headset);
void (*setBoundsVisible)(void* headset, char visible);
void (*getPosition)(void* headset, float* x, float* y, float* z);
void (*getOrientation)(void* headset, float* w, float* x, float* y, float* z);
void (*getOrientation)(void* headset, float* angle, float* x, float* y, float* z);
void (*getVelocity)(void* headset, float* x, float* y, float* z);
void (*getAngularVelocity)(void* headset, float* x, float* y, float* z);
vec_controller_t* (*getControllers)(void* headset);
char (*controllerIsPresent)(void* headset, Controller* controller);
void (*controllerGetPosition)(void* headset, Controller* controller, float* x, float* y, float* z);
void (*controllerGetOrientation)(void* headset, Controller* controller, float* w, float* x, float* y, float* z);
void (*controllerGetOrientation)(void* headset, Controller* controller, float* angle, float* x, float* y, float* z);
float (*controllerGetAxis)(void* headset, Controller* controller, ControllerAxis axis);
int (*controllerIsDown)(void* headset, Controller* controller, ControllerButton button);
void (*controllerVibrate)(void* headset, Controller* controller, float duration);
@ -73,13 +73,13 @@ void lovrHeadsetGetBoundsGeometry(float* geometry);
char lovrHeadsetIsBoundsVisible();
void lovrHeadsetSetBoundsVisible(char visible);
void lovrHeadsetGetPosition(float* x, float* y, float* z);
void lovrHeadsetGetOrientation(float* w, float* x, float* y, float* z);
void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z);
void lovrHeadsetGetVelocity(float* x, float* y, float* z);
void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z);
vec_controller_t* lovrHeadsetGetControllers();
char lovrHeadsetControllerIsPresent(Controller* controller);
void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z);
void lovrHeadsetControllerGetOrientation(Controller* controller, float* w, float* x, float* y, float* z);
void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z);
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis);
int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button);
void lovrHeadsetControllerVibrate(Controller* controller, float duration);

View File

@ -2,6 +2,8 @@
#include "event/event.h"
#include "graphics/graphics.h"
#include "loaders/texture.h"
#include "math/mat4.h"
#include "math/quat.h"
#include "util.h"
#include <stdlib.h>
#include <stdint.h>
@ -255,17 +257,19 @@ void viveGetPosition(void* headset, float* x, float* y, float* z) {
*z = pose.mDeviceToAbsoluteTracking.m[2][3];
}
void viveGetOrientation(void* headset, float* w, float* x, float* y, float *z) {
void viveGetOrientation(void* headset, float* angle, float* x, float* y, float *z) {
Vive* vive = (Vive*) headset;
TrackedDevicePose_t pose = viveGetPose(vive, vive->headsetIndex);
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*w = *x = *y = *z = 0.f;
*angle = *x = *y = *z = 0.f;
return;
}
float matrix[16];
mat4_getRotation(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), w, x, y, z);
float rotation[4];
quat_fromMat4(rotation, mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m));
quat_getAngleAxis(rotation, angle, x, y, z);
}
void viveGetVelocity(void* headset, float* x, float* y, float* z) {
@ -339,17 +343,19 @@ void viveControllerGetPosition(void* headset, Controller* controller, float* x,
*z = pose.mDeviceToAbsoluteTracking.m[2][3];
}
void viveControllerGetOrientation(void* headset, Controller* controller, float* w, float* x, float* y, float* z) {
void viveControllerGetOrientation(void* headset, Controller* controller, float* angle, float* x, float* y, float* z) {
Vive* vive = (Vive*) headset;
TrackedDevicePose_t pose = viveGetPose(vive, controller->id);
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*w = *x = *y = *z = 0.f;
*angle = *x = *y = *z = 0.f;
return;
}
float matrix[16];
mat4_getRotation(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), w, x, y, z);
float rotation[4];
quat_fromMat4(rotation, mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m));
quat_getAngleAxis(rotation, angle, x, y, z);
}
float viveControllerGetAxis(void* headset, Controller* controller, ControllerAxis axis) {
@ -449,7 +455,7 @@ void* viveControllerGetModel(void* headset, Controller* controller, ControllerMo
void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) {
Vive* vive = (Vive*) headset;
float headMatrix[16], eyeMatrix[16], projectionMatrix[16];
float head[16], transform[16], projection[16];
float (*matrix)[4];
lovrGraphicsPushCanvas();
@ -458,28 +464,27 @@ void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata)
// Head transform
matrix = vive->renderPoses[vive->headsetIndex].mDeviceToAbsoluteTracking.m;
mat4_invert(mat4_fromMat34(headMatrix, matrix));
mat4_invert(mat4_fromMat34(head, matrix));
for (int i = 0; i < 2; i++) {
EVREye eye = (i == 0) ? EVREye_Eye_Left : EVREye_Eye_Right;
for (EVREye eye = EYE_LEFT; eye <= EYE_RIGHT; eye++) {
// Eye transform
matrix = vive->system->GetEyeToHeadTransform(eye).m;
mat4_invert(mat4_fromMat34(eyeMatrix, matrix));
mat4 transformMatrix = mat4_multiply(eyeMatrix, headMatrix);
mat4_invert(mat4_fromMat34(transform, matrix));
mat4_multiply(transform, head);
// Projection
matrix = vive->system->GetProjectionMatrix(eye, vive->clipNear, vive->clipFar).m;
mat4_fromMat44(projectionMatrix, matrix);
mat4_fromMat44(projection, matrix);
// Render
lovrTextureBindFramebuffer(vive->texture);
lovrGraphicsPush();
lovrGraphicsOrigin();
lovrGraphicsMatrixTransform(transformMatrix);
lovrGraphicsSetProjectionRaw(projectionMatrix);
lovrGraphicsMatrixTransform(transform);
lovrGraphicsSetProjectionRaw(projection);
lovrGraphicsClear(1, 1);
callback(i, userdata);
callback(eye - EYE_LEFT, userdata);
lovrGraphicsPop();
lovrTextureResolveMSAA(vive->texture);
@ -493,6 +498,5 @@ void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata)
vive->isRendering = 0;
lovrGraphicsPopCanvas();
lovrGraphicsPlaneFullscreen(vive->texture);
}

View File

@ -6,6 +6,9 @@
#ifndef LOVR_VIVE_TYPES
#define LOVR_VIVE_TYPES
#define EYE_LEFT EVREye_Eye_Left
#define EYE_RIGHT EVREye_Eye_Right
typedef struct {
Headset headset;
@ -47,14 +50,14 @@ void viveGetBoundsGeometry(void* headset, float* geometry);
char viveIsBoundsVisible(void* headset);
void viveSetBoundsVisible(void* headset, char visible);
void viveGetPosition(void* headset, float* x, float* y, float* z);
void viveGetOrientation(void* headset, float* w, float* x, float* y, float* z);
void viveGetOrientation(void* headset, float* angle, float* x, float* y, float* z);
void viveGetVelocity(void* headset, float* x, float* y, float* z);
void viveGetAngularVelocity(void* headset, float* x, float* y, float* z);
Controller* viveAddController(void* headset, unsigned int deviceIndex);
vec_controller_t* viveGetControllers(void* headset);
char viveControllerIsPresent(void* headset, Controller* controller);
void viveControllerGetPosition(void* headset, Controller* controller, float* x, float* y, float* z);
void viveControllerGetOrientation(void* headset, Controller* controller, float* w, float* x, float* y, float* z);
void viveControllerGetOrientation(void* headset, Controller* controller, float* angle, float* x, float* y, float* z);
float viveControllerGetAxis(void* headset, Controller* controller, ControllerAxis axis);
int viveControllerIsDown(void* headset, Controller* controller, ControllerButton button);
void viveControllerVibrate(void* headset, Controller* controller, float duration);

View File

@ -1,4 +1,5 @@
#include "loaders/model.h"
#include "math/mat4.h"
#include <stdlib.h>
#include <assimp/scene.h>
#include <assimp/cimport.h>
@ -9,7 +10,7 @@ static void assimpNodeTraversal(ModelNode* node, struct aiNode* assimpNode) {
// Transform
struct aiMatrix4x4 m = assimpNode->mTransformation;
aiTransposeMatrix4(&m);
node->transform = mat4_copy((float*) &m);
mat4_set(node->transform, (float*) &m);
// Meshes
vec_init(&node->meshes);
@ -148,7 +149,6 @@ ModelData* lovrModelDataFromOpenVRModel(OpenVRModel* vrModel) {
}
ModelNode* root = malloc(sizeof(ModelNode));
root->transform = mat4_init();
vec_init(&root->meshes);
vec_push(&root->meshes, 0);
vec_init(&root->children);

View File

@ -4,6 +4,7 @@
#include "lovr/filesystem.h"
#include "lovr/graphics.h"
#include "lovr/headset.h"
#include "lovr/math.h"
#include "lovr/timer.h"
#include "glfw.h"
#include "util.h"
@ -62,6 +63,7 @@ void lovrInit(lua_State* L, int argc, char** argv) {
luax_preloadmodule(L, "lovr.filesystem", l_lovrFilesystemInit);
luax_preloadmodule(L, "lovr.graphics", l_lovrGraphicsInit);
luax_preloadmodule(L, "lovr.headset", l_lovrHeadsetInit);
luax_preloadmodule(L, "lovr.math", l_lovrMathInit);
luax_preloadmodule(L, "lovr.timer", l_lovrTimerInit);
// Bootstrap
@ -73,6 +75,7 @@ void lovrInit(lua_State* L, int argc, char** argv) {
" event = true, "
" graphics = true, "
" headset = true, "
" math = true, "
" timer = true "
" } "
"} "
@ -88,7 +91,7 @@ void lovrInit(lua_State* L, int argc, char** argv) {
" success, err = pcall(lovr.conf, conf) "
"end "
"local modules = { 'audio', 'event', 'graphics', 'headset', 'timer' } "
"local modules = { 'audio', 'event', 'graphics', 'headset', 'math', 'timer' } "
"for _, module in ipairs(modules) do "
" if conf.modules[module] then "
" lovr[module] = require('lovr.' .. module) "

View File

@ -2,6 +2,8 @@
#include "event/event.h"
#include "util.h"
static int pollRef;
static int nextEvent(lua_State* L) {
Event* event = lovrEventPoll();
@ -44,6 +46,11 @@ const luaL_Reg lovrEvent[] = {
int l_lovrEventInit(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrEvent);
// Store nextEvent in the registry to avoid creating a closure every time we poll for events.
lua_pushcfunction(L, nextEvent);
pollRef = luaL_ref(L, LUA_REGISTRYINDEX);
map_init(&EventTypes);
map_set(&EventTypes, "quit", EVENT_QUIT);
lovrEventInit();
@ -56,7 +63,7 @@ int l_lovrEventClear(lua_State* L) {
}
int l_lovrEventPoll(lua_State* L) {
lua_pushcclosure(L, nextEvent, 0);
lua_rawgeti(L, LUA_REGISTRYINDEX, pollRef);
return 1;
}

View File

@ -4,6 +4,7 @@
#include "lovr/types/shader.h"
#include "lovr/types/skybox.h"
#include "lovr/types/texture.h"
#include "lovr/types/transform.h"
#include "graphics/graphics.h"
#include "loaders/model.h"
#include "loaders/texture.h"
@ -74,6 +75,7 @@ const luaL_Reg lovrGraphics[] = {
{ "translate", l_lovrGraphicsTranslate },
{ "rotate", l_lovrGraphicsRotate },
{ "scale", l_lovrGraphicsScale },
{ "transform", l_lovrGraphicsTransform },
{ "points", l_lovrGraphicsPoints },
{ "line", l_lovrGraphicsLine },
{ "triangle", l_lovrGraphicsTriangle },
@ -442,6 +444,13 @@ int l_lovrGraphicsScale(lua_State* L) {
return 0;
}
int l_lovrGraphicsTransform(lua_State* L) {
float transform[16];
luax_readtransform(L, 1, transform);
lovrGraphicsMatrixTransform(transform);
return 0;
}
// Primitives
int l_lovrGraphicsPoints(lua_State* L) {
@ -509,15 +518,9 @@ int l_lovrGraphicsCube(lua_State* L) {
drawMode = DRAW_MODE_FILL;
texture = luax_checktype(L, 1, Texture);
}
float x = luaL_optnumber(L, 2, 0.f);
float y = luaL_optnumber(L, 3, 0.f);
float z = luaL_optnumber(L, 4, 0.f);
float s = luaL_optnumber(L, 5, 1.f);
float angle = luaL_optnumber(L, 6, 0.f);
float axisX = luaL_optnumber(L, 7, 0.f);
float axisY = luaL_optnumber(L, 8, 1.f);
float axisZ = luaL_optnumber(L, 9, 0.f);
lovrGraphicsCube(drawMode, texture, x, y, z, s, angle, axisX, axisY, axisZ);
float transform[16];
luax_readtransform(L, 2, transform);
lovrGraphicsCube(drawMode, texture, transform);
return 0;
}

View File

@ -56,6 +56,7 @@ int l_lovrGraphicsOrigin(lua_State* L);
int l_lovrGraphicsTranslate(lua_State* L);
int l_lovrGraphicsRotate(lua_State* L);
int l_lovrGraphicsScale(lua_State* L);
int l_lovrGraphicsTransform(lua_State* L);
// Primitives
int l_lovrGraphicsPoints(lua_State* L);

View File

@ -155,9 +155,9 @@ int l_lovrHeadsetGetPosition(lua_State* L) {
}
int l_lovrHeadsetGetOrientation(lua_State* L) {
float w, x, y, z;
lovrHeadsetGetOrientation(&w, &x, &y, &z);
lua_pushnumber(L, w);
float angle, x, y, z;
lovrHeadsetGetOrientation(&angle, &x, &y, &z);
lua_pushnumber(L, angle);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);

23
src/lovr/math.c Normal file
View File

@ -0,0 +1,23 @@
#include "lovr/math.h"
#include "lovr/types/transform.h"
#include "math/mat4.h"
#include "util.h"
const luaL_Reg lovrMath[] = {
{ "newTransform", l_lovrMathNewTransform },
{ NULL, NULL }
};
int l_lovrMathInit(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrMath);
luax_registertype(L, "Transform", lovrTransform);
return 1;
}
int l_lovrMathNewTransform(lua_State* L) {
float transfrom[16];
luax_readtransform(L, 1, transfrom);
luax_pushtype(L, Transform, lovrTransformCreate(transfrom));
return 1;
}

7
src/lovr/math.h Normal file
View File

@ -0,0 +1,7 @@
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
extern const luaL_Reg lovrMath[];
int l_lovrMathInit(lua_State* L);
int l_lovrMathNewTransform(lua_State* L);

View File

@ -34,9 +34,9 @@ int l_lovrControllerGetPosition(lua_State* L) {
int l_lovrControllerGetOrientation(lua_State* L) {
Controller* controller = luax_checktype(L, 1, Controller);
float w, x, y, z;
lovrHeadsetControllerGetOrientation(controller, &w, &x, &y, &z);
lua_pushnumber(L, w);
float angle, x, y, z;
lovrHeadsetControllerGetOrientation(controller, &angle, &x, &y, &z);
lua_pushnumber(L, angle);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);

View File

@ -1,5 +1,6 @@
#include "lovr/types/model.h"
#include "lovr/types/texture.h"
#include "lovr/types/transform.h"
const luaL_Reg lovrModel[] = {
{ "draw", l_lovrModelDraw },
@ -10,15 +11,9 @@ const luaL_Reg lovrModel[] = {
int l_lovrModelDraw(lua_State* L) {
Model* model = luax_checktype(L, 1, Model);
float x = luaL_optnumber(L, 2, 0.f);
float y = luaL_optnumber(L, 3, 0.f);
float z = luaL_optnumber(L, 4, 0.f);
float scale = luaL_optnumber(L, 5, 1.f);
float angle = luaL_optnumber(L, 6, 0.f);
float ax = luaL_optnumber(L, 7, 0.f);
float ay = luaL_optnumber(L, 8, 1.f);
float az = luaL_optnumber(L, 9, 0.f);
lovrModelDraw(model, x, y, z, scale, angle, ax, ay, az);
float transform[16];
luax_readtransform(L, 2, transform);
lovrModelDraw(model, transform);
return 0;
}

129
src/lovr/types/transform.c Normal file
View File

@ -0,0 +1,129 @@
#include "lovr/types/transform.h"
#include "util.h"
void luax_readtransform(lua_State* L, int i, mat4 m) {
if (lua_isnumber(L, i)) {
float x = luaL_optnumber(L, i++, 0);
float y = luaL_optnumber(L, i++, 0);
float z = luaL_optnumber(L, i++, 0);
float s = luaL_optnumber(L, i++, 1);
float angle = luaL_optnumber(L, i++, 0);
float ax = luaL_optnumber(L, i++, 0);
float ay = luaL_optnumber(L, i++, 1);
float az = luaL_optnumber(L, i++, 0);
mat4_setTransform(m, x, y, z, s, angle, ax, ay, az);
} else if (lua_isnoneornil(L, i)) {
mat4_identity(m);
} else {
Transform* transform = luax_checktype(L, i, Transform);
mat4_init(m, transform->matrix);
}
}
const luaL_Reg lovrTransform[] = {
{ "clone", l_lovrTransformClone },
{ "inverse", l_lovrTransformInverse },
{ "apply", l_lovrTransformApply },
{ "origin", l_lovrTransformOrigin },
{ "translate", l_lovrTransformTranslate },
{ "rotate", l_lovrTransformRotate },
{ "scale", l_lovrTransformScale },
{ "setTransformation", l_lovrTransformSetTransformation },
{ "transformPoint", l_lovrTransformTransformPoint },
{ "inverseTransformPoint", l_lovrTransformInverseTransformPoint },
{ NULL, NULL }
};
int l_lovrTransformClone(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
luax_pushtype(L, Transform, lovrTransformCreate(transform->matrix));
return 1;
}
int l_lovrTransformInverse(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
Transform* inverse = lovrTransformCreate(lovrTransformInverse(transform));
luax_pushtype(L, Transform, inverse);
return 1;
}
int l_lovrTransformApply(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
Transform* other = luax_checktype(L, 2, Transform);
lovrTransformApply(transform, other);
lua_pushvalue(L, 1);
return 1;
}
int l_lovrTransformOrigin(lua_State* L) {
lovrTransformOrigin(luax_checktype(L, 1, Transform));
lua_pushvalue(L, 1);
return 1;
}
int l_lovrTransformTranslate(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
float x = luaL_checknumber(L, 2);
float y = luaL_checknumber(L, 3);
float z = luaL_checknumber(L, 4);
lovrTransformTranslate(transform, x, y, z);
lua_pushvalue(L, 1);
return 1;
}
int l_lovrTransformRotate(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
float angle = luaL_checknumber(L, 2);
float x = luaL_checknumber(L, 3);
float y = luaL_checknumber(L, 4);
float z = luaL_checknumber(L, 5);
lovrTransformRotate(transform, angle, x, y, z);
lua_pushvalue(L, 1);
return 1;
}
int l_lovrTransformScale(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
float x = luaL_checknumber(L, 2);
float y = lua_gettop(L) > 2 ? luaL_checknumber(L, 3) : x;
float z = lua_gettop(L) > 2 ? luaL_checknumber(L, 4) : x;
lovrTransformScale(transform, x, y, z);
lua_pushvalue(L, 1);
return 1;
}
int l_lovrTransformSetTransformation(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
lovrTransformOrigin(transform); // Dirty the Transform
luax_readtransform(L, 2, transform->matrix);
lua_pushvalue(L, 1);
return 1;
}
int l_lovrTransformTransformPoint(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
float point[3] = {
luaL_checknumber(L, 2),
luaL_checknumber(L, 3),
luaL_checknumber(L, 4)
};
lovrTransformTransformPoint(transform, point);
lua_pushnumber(L, point[0]);
lua_pushnumber(L, point[1]);
lua_pushnumber(L, point[2]);
return 3;
}
int l_lovrTransformInverseTransformPoint(lua_State* L) {
Transform* transform = luax_checktype(L, 1, Transform);
float point[3] = {
luaL_checknumber(L, 2),
luaL_checknumber(L, 3),
luaL_checknumber(L, 4)
};
lovrTransformInverseTransformPoint(transform, point);
lua_pushnumber(L, point[0]);
lua_pushnumber(L, point[1]);
lua_pushnumber(L, point[2]);
return 3;
}

View File

@ -0,0 +1,19 @@
#include "math/transform.h"
#include "math/mat4.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
void luax_readtransform(lua_State* L, int i, mat4 transform);
extern const luaL_Reg lovrTransform[];
int l_lovrTransformClone(lua_State* L);
int l_lovrTransformInverse(lua_State* L);
int l_lovrTransformApply(lua_State* L);
int l_lovrTransformOrigin(lua_State* L);
int l_lovrTransformTranslate(lua_State* L);
int l_lovrTransformRotate(lua_State* L);
int l_lovrTransformScale(lua_State* L);
int l_lovrTransformSetTransformation(lua_State* L);
int l_lovrTransformTransformPoint(lua_State* L);
int l_lovrTransformInverseTransformPoint(lua_State* L);

235
src/math/mat4.c Normal file
View File

@ -0,0 +1,235 @@
#include "math/mat4.h"
#include "math/quat.h"
#include "math/vec3.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
// m0 m4 m8 m12
// m1 m5 m9 m13
// m2 m6 m10 m14
// m3 m7 m11 m15
mat4 mat4_set(mat4 m, mat4 n) {
return memcpy(m, n, 16 * sizeof(float));
}
mat4 mat4_fromMat34(mat4 m, float (*n)[4]) {
m[0] = n[0][0];
m[1] = n[1][0];
m[2] = n[2][0];
m[3] = 0.f;
m[4] = n[0][1];
m[5] = n[1][1];
m[6] = n[2][1];
m[7] = 0.f;
m[8] = n[0][2];
m[9] = n[1][2];
m[10] = n[2][2];
m[11] = 0.f;
m[12] = n[0][3];
m[13] = n[1][3];
m[14] = n[2][3];
m[15] = 1.f;
return m;
}
mat4 mat4_fromMat44(mat4 m, float (*n)[4]) {
m[0] = n[0][0];
m[1] = n[1][0];
m[2] = n[2][0];
m[3] = n[3][0];
m[4] = n[0][1];
m[5] = n[1][1];
m[6] = n[2][1];
m[7] = n[3][1];
m[8] = n[0][2];
m[9] = n[1][2];
m[10] = n[2][2];
m[11] = n[3][2];
m[12] = n[0][3];
m[13] = n[1][3];
m[14] = n[2][3];
m[15] = n[3][3];
return m;
}
mat4 mat4_identity(mat4 m) {
memset(m, 0, 16 * sizeof(float));
m[0] = m[5] = m[10] = m[15] = 1.f;
return m;
}
// Modified from gl-matrix.c
mat4 mat4_invert(mat4 m) {
float a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3],
a10 = m[4], a11 = m[5], a12 = m[6], a13 = m[7],
a20 = m[8], a21 = m[9], a22 = m[10], a23 = m[11],
a30 = m[12], a31 = m[13], a32 = m[14], a33 = m[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06),
invDet;
if (!d) { return NULL; }
invDet = 1 / d;
m[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
m[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
m[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
m[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
m[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
m[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
m[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
m[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
m[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
m[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
m[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
m[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
m[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
m[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
m[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
m[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;
return m;
}
// Modified from gl-matrix.c
mat4 mat4_multiply(mat4 m, mat4 n) {
float m00 = m[0], m01 = m[1], m02 = m[2], m03 = m[3],
m10 = m[4], m11 = m[5], m12 = m[6], m13 = m[7],
m20 = m[8], m21 = m[9], m22 = m[10], m23 = m[11],
m30 = m[12], m31 = m[13], m32 = m[14], m33 = m[15],
n00 = n[0], n01 = n[1], n02 = n[2], n03 = n[3],
n10 = n[4], n11 = n[5], n12 = n[6], n13 = n[7],
n20 = n[8], n21 = n[9], n22 = n[10], n23 = n[11],
n30 = n[12], n31 = n[13], n32 = n[14], n33 = n[15];
m[0] = n00 * m00 + n01 * m10 + n02 * m20 + n03 * m30;
m[1] = n00 * m01 + n01 * m11 + n02 * m21 + n03 * m31;
m[2] = n00 * m02 + n01 * m12 + n02 * m22 + n03 * m32;
m[3] = n00 * m03 + n01 * m13 + n02 * m23 + n03 * m33;
m[4] = n10 * m00 + n11 * m10 + n12 * m20 + n13 * m30;
m[5] = n10 * m01 + n11 * m11 + n12 * m21 + n13 * m31;
m[6] = n10 * m02 + n11 * m12 + n12 * m22 + n13 * m32;
m[7] = n10 * m03 + n11 * m13 + n12 * m23 + n13 * m33;
m[8] = n20 * m00 + n21 * m10 + n22 * m20 + n23 * m30;
m[9] = n20 * m01 + n21 * m11 + n22 * m21 + n23 * m31;
m[10] = n20 * m02 + n21 * m12 + n22 * m22 + n23 * m32;
m[11] = n20 * m03 + n21 * m13 + n22 * m23 + n23 * m33;
m[12] = n30 * m00 + n31 * m10 + n32 * m20 + n33 * m30;
m[13] = n30 * m01 + n31 * m11 + n32 * m21 + n33 * m31;
m[14] = n30 * m02 + n31 * m12 + n32 * m22 + n33 * m32;
m[15] = n30 * m03 + n31 * m13 + n32 * m23 + n33 * m33;
return m;
}
mat4 mat4_translate(mat4 m, float x, float y, float z) {
m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
return m;
}
mat4 mat4_rotate(mat4 m, float angle, float x, float y, float z) {
float q[4];
float v[3];
quat_fromAngleAxis(q, angle, vec3_set(v, x, y, z));
return mat4_rotateQuat(m, q);
}
mat4 mat4_rotateQuat(mat4 m, quat q) {
float x = q[0];
float y = q[1];
float z = q[2];
float w = q[3];
float rotation[16];
mat4_identity(rotation);
rotation[0] = 1 - 2 * y * y - 2 * z * z;
rotation[1] = 2 * x * y + 2 * w * z;
rotation[2] = 2 * x * z - 2 * w * y;
rotation[4] = 2 * x * y - 2 * w * z;
rotation[5] = 1 - 2 * x * x - 2 * z * z;
rotation[6] = 2 * y * z + 2 * w * x;
rotation[8] = 2 * x * z + 2 * w * y;
rotation[9] = 2 * y * z - 2 * w * x;
rotation[10] = 1 - 2 * x * x - 2 * y * y;
return mat4_multiply(m, rotation);
}
mat4 mat4_scale(mat4 m, float x, float y, float z) {
m[0] *= x;
m[1] *= x;
m[2] *= x;
m[3] *= x;
m[4] *= y;
m[5] *= y;
m[6] *= y;
m[7] *= y;
m[8] *= z;
m[9] *= z;
m[10] *= z;
m[11] *= z;
return m;
}
mat4 mat4_setTransform(mat4 m, float x, float y, float z, float s, float angle, float ax, float ay, float az) {
mat4_identity(m);
mat4_translate(m, x, y, z);
mat4_scale(m, s, s, s);
return mat4_rotate(m, angle, ax, ay, az);
}
mat4 mat4_orthographic(mat4 m, float left, float right, float top, float bottom, float near, float far) {
float rl = right - left;
float tb = top - bottom;
float fn = far - near;
mat4_identity(m);
m[0] = 2 / rl;
m[5] = 2 / tb;
m[10] = -2 / fn;
m[12] = -(left + right) / rl;
m[13] = -(top + bottom) / tb;
m[14] = -(far + near) / fn;
m[15] = 1;
return m;
}
mat4 mat4_perspective(mat4 m, float near, float far, float fovy, float aspect) {
float range = tan(fovy * .5f) * 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_identity(m);
m[0] = sx;
m[5] = sy;
m[10] = sz;
m[11] = -1.0f;
m[14] = pz;
m[15] = 0.0f;
return m;
}
void mat4_transform(mat4 m, vec3 v) {
vec3_set(v,
v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + m[12],
v[0] * m[1] + v[1] * m[5] + v[2] * m[9] + m[13],
v[0] * m[2] + v[1] * m[6] + v[2] * m[10] + m[14]
);
}

17
src/math/mat4.h Normal file
View File

@ -0,0 +1,17 @@
#include "math/math.h"
#define mat4_init mat4_set
mat4 mat4_set(mat4 m, mat4 n);
mat4 mat4_fromMat34(mat4 m, float (*n)[4]);
mat4 mat4_fromMat44(mat4 m, float (*n)[4]);
mat4 mat4_identity(mat4 m);
mat4 mat4_invert(mat4 m);
mat4 mat4_multiply(mat4 m, mat4 n);
mat4 mat4_translate(mat4 m, float x, float y, float z);
mat4 mat4_rotate(mat4 m, float angle, float x, float y, float z);
mat4 mat4_rotateQuat(mat4 m, quat q);
mat4 mat4_scale(mat4 m, float x, float y, float z);
mat4 mat4_setTransform(mat4 m, float x, float y, float z, float s, float angle, float ax, float ay, float az);
mat4 mat4_orthographic(mat4 m, float left, float right, float top, float bottom, float near, float far);
mat4 mat4_perspective(mat4 m, float near, float far, float fov, float aspect);
void mat4_transform(mat4 m, vec3 v);

9
src/math/math.h Normal file
View File

@ -0,0 +1,9 @@
#include "vendor/vec/vec.h"
#ifndef LOVR_MATH_TYPES
#define LOVR_MATH_TYPES
typedef float* vec3;
typedef float* quat;
typedef float* mat4;
typedef vec_t(mat4) vec_mat4_t;
#endif

98
src/math/quat.c Normal file
View File

@ -0,0 +1,98 @@
#include "math/quat.h"
#include "math/vec3.h"
#include "util.h"
#include <math.h>
#include <stdlib.h>
quat quat_init(quat q, quat r) {
return quat_set(q, r[0], r[1], r[2], r[3]);
}
quat quat_set(quat q, float x, float y, float z, float w) {
q[0] = x;
q[1] = y;
q[2] = z;
q[3] = w;
return q;
}
quat quat_fromAngleAxis(quat q, float angle, vec3 axis) {
vec3_normalize(axis);
float s = sin(angle * .5f);
float c = cos(angle * .5f);
q[0] = s * axis[0];
q[1] = s * axis[1];
q[2] = s * axis[2];
q[3] = c;
return q;
}
quat quat_fromDirection(quat q, vec3 forward, vec3 up) {
vec3 qq = (vec3) q;
vec3_init(qq, forward);
vec3_normalize(qq);
q[3] = 1 + vec3_dot(qq, up);
vec3_cross(qq, up);
return q;
}
quat quat_fromMat4(quat q, mat4 m) {
float x = sqrt(MAX(0, 1 + m[0] - m[5] - m[10])) / 2;
float y = sqrt(MAX(0, 1 - m[0] + m[5] - m[10])) / 2;
float z = sqrt(MAX(0, 1 - m[0] - m[5] + m[10])) / 2;
float w = sqrt(MAX(0, 1 + m[0] + m[5] + m[10])) / 2;
x = (m[9] - m[6]) > 0 ? -x : x;
y = (m[2] - m[8]) > 0 ? -y : y;
z = (m[4] - m[1]) > 0 ? -z : z;
q[0] = x;
q[1] = y;
q[2] = z;
q[3] = w;
return q;
}
quat quat_normalize(quat q) {
float len = quat_length(q);
if (len == 0) {
return q;
}
len = 1 / len;
q[0] *= len;
q[1] *= len;
q[2] *= len;
q[3] *= len;
return q;
}
float quat_length(quat q) {
return sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
}
void quat_rotate(quat q, vec3 v) {
float s = q[3];
float u[3];
float c[3];
vec3_init(u, q);
vec3_cross(vec3_init(c, u), v);
float uu = vec3_dot(u, u);
float uv = vec3_dot(u, v);
vec3_scale(u, 2 * uv);
vec3_scale(v, s * s - uu);
vec3_scale(c, 2 * s);
vec3_add(v, vec3_add(u, c));
}
void quat_getAngleAxis(quat q, float* angle, float* x, float* y, float* z) {
if (q[3] > 1 || q[3] < -1) {
quat_normalize(q);
}
float qw = q[3];
float s = sqrt(1 - qw * qw);
s = s < .0001 ? 1 : 1 / s;
*angle = 2 * acos(qw);
*x = q[0] * s;
*y = q[1] * s;
*z = q[2] * s;
}

10
src/math/quat.h Normal file
View File

@ -0,0 +1,10 @@
#include "math/math.h"
quat quat_init(quat q, quat r);
quat quat_set(quat q, float x, float y, float z, float w);
quat quat_fromAngleAxis(quat q, float angle, vec3 axis);
quat quat_fromMat4(quat q, mat4 m);
quat quat_normalize(quat q);
float quat_length(quat q);
void quat_rotate(quat q, vec3 v);
void quat_getAngleAxis(quat q, float* angle, float* x, float* y, float* z);

64
src/math/transform.c Normal file
View File

@ -0,0 +1,64 @@
#include "transform.h"
#include "math/mat4.h"
Transform* lovrTransformCreate(mat4 transfrom) {
Transform* transform = lovrAlloc(sizeof(Transform), lovrTransformDestroy);
if (!transform) return NULL;
transform->isDirty = 1;
if (transfrom) {
mat4_set(transform->matrix, transfrom);
} else {
mat4_identity(transform->matrix);
}
return transform;
}
void lovrTransformDestroy(const Ref* ref) {
Transform* transform = containerof(ref, Transform);
free(transform);
}
mat4 lovrTransformInverse(Transform* transform) {
if (transform->isDirty) {
transform->isDirty = 0;
mat4_invert(mat4_set(transform->inverse, transform->matrix));
}
return transform->inverse;
}
void lovrTransformApply(Transform* transform, Transform* other) {
transform->isDirty = 1;
mat4_multiply(transform->matrix, other->matrix);
}
void lovrTransformOrigin(Transform* transform) {
transform->isDirty = 1;
mat4_identity(transform->matrix);
}
void lovrTransformTranslate(Transform* transform, float x, float y, float z) {
transform->isDirty = 1;
mat4_translate(transform->matrix, x, y, z);
}
void lovrTransformRotate(Transform* transform, float angle, float x, float y, float z) {
transform->isDirty = 1;
mat4_rotate(transform->matrix, angle, x, y, z);
}
void lovrTransformScale(Transform* transform, float x, float y, float z) {
transform->isDirty = 1;
mat4_scale(transform->matrix, x, y, z);
}
void lovrTransformTransformPoint(Transform* transform, vec3 point) {
mat4_transform(transform->matrix, point);
}
void lovrTransformInverseTransformPoint(Transform* transform, vec3 point) {
mat4_transform(lovrTransformInverse(transform), point);
}

23
src/math/transform.h Normal file
View File

@ -0,0 +1,23 @@
#include "util.h"
#include "math/math.h"
#ifndef LOVR_TRANSFORM_TYPES
#define LOVR_TRANSFORM_TYPES
typedef struct Transform {
Ref ref;
float matrix[16];
float inverse[16];
int isDirty;
} Transform;
#endif
Transform* lovrTransformCreate(mat4 transfrom);
void lovrTransformDestroy(const Ref* ref);
void lovrTransformApply(Transform* transform, Transform* other);
mat4 lovrTransformInverse(Transform* transform);
void lovrTransformOrigin(Transform* transform);
void lovrTransformTranslate(Transform* transform, float x, float y, float z);
void lovrTransformRotate(Transform* transform, float angle, float x, float y, float z);
void lovrTransformScale(Transform* transform, float x, float y, float z);
void lovrTransformTransformPoint(Transform* transform, vec3 point);
void lovrTransformInverseTransformPoint(Transform* transform, vec3 point);

49
src/math/vec3.c Normal file
View File

@ -0,0 +1,49 @@
#include "math/vec3.h"
#include <math.h>
#include <stdlib.h>
vec3 vec3_init(vec3 v, vec3 u) {
return vec3_set(v, u[0], u[1], u[2]);
}
vec3 vec3_set(vec3 v, float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
return v;
}
vec3 vec3_add(vec3 v, vec3 u) {
v[0] += u[0];
v[1] += u[1];
v[2] += u[2];
return v;
}
vec3 vec3_scale(vec3 v, float s) {
v[0] *= s;
v[1] *= s;
v[2] *= s;
return v;
}
vec3 vec3_normalize(vec3 v) {
float len = vec3_length(v);
return len == 0 ? v : vec3_scale(v, 1 / len);
}
float vec3_length(vec3 v) {
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
float vec3_dot(vec3 v, vec3 u) {
return v[0] * u[0] + v[1] * u[1] + v[2] * u[2];
}
vec3 vec3_cross(vec3 v, vec3 u) {
return vec3_set(v,
v[1] * u[2] - v[2] * u[1],
v[2] * u[0] - v[0] * u[2],
v[0] * u[1] - v[1] * u[0]
);
}

10
src/math/vec3.h Normal file
View File

@ -0,0 +1,10 @@
#include "math/math.h"
vec3 vec3_init(vec3 v, vec3 u);
vec3 vec3_set(vec3 v, float x, float y, float z);
vec3 vec3_add(vec3 v, vec3 u);
vec3 vec3_scale(vec3 v, float s);
vec3 vec3_normalize(vec3 v);
float vec3_length(vec3 v);
float vec3_dot(vec3 v, vec3 u);
vec3 vec3_cross(vec3 v, vec3 u);

View File

@ -1,276 +0,0 @@
#include "matrix.h"
#include "util.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
/*
m0 m4 m8 m12
m1 m5 m9 m13
m2 m6 m10 m14
m3 m7 m11 m15
*/
mat4 mat4_init() {
mat4 matrix = malloc(16 * sizeof(float));
return mat4_setIdentity(matrix);
}
void mat4_deinit(mat4 matrix) {
free(matrix);
}
mat4 mat4_copy(mat4 source) {
mat4 matrix = mat4_init();
memcpy(matrix, source, 16 * sizeof(float));
return matrix;
}
mat4 mat4_fromMat34(mat4 matrix, float (*source)[4]) {
matrix[0] = source[0][0];
matrix[1] = source[1][0];
matrix[2] = source[2][0];
matrix[3] = 0.f;
matrix[4] = source[0][1];
matrix[5] = source[1][1];
matrix[6] = source[2][1];
matrix[7] = 0.f;
matrix[8] = source[0][2];
matrix[9] = source[1][2];
matrix[10] = source[2][2];
matrix[11] = 0.f;
matrix[12] = source[0][3];
matrix[13] = source[1][3];
matrix[14] = source[2][3];
matrix[15] = 1.f;
return matrix;
}
mat4 mat4_fromMat44(mat4 matrix, float (*source)[4]) {
matrix[0] = source[0][0];
matrix[1] = source[1][0];
matrix[2] = source[2][0];
matrix[3] = source[3][0];
matrix[4] = source[0][1];
matrix[5] = source[1][1];
matrix[6] = source[2][1];
matrix[7] = source[3][1];
matrix[8] = source[0][2];
matrix[9] = source[1][2];
matrix[10] = source[2][2];
matrix[11] = source[3][2];
matrix[12] = source[0][3];
matrix[13] = source[1][3];
matrix[14] = source[2][3];
matrix[15] = source[3][3];
return matrix;
}
mat4 mat4_setIdentity(mat4 matrix) {
memset(matrix, 0, 16 * sizeof(float));
matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.f;
return matrix;
}
mat4 mat4_setTranslation(mat4 matrix, float x, float y, float z) {
mat4_setIdentity(matrix);
matrix[12] = x;
matrix[13] = y;
matrix[14] = z;
return matrix;
}
mat4 mat4_setRotation(mat4 matrix, float angle, float ax, float ay, float az) {
// Normalize rotation vector
float len = sqrtf(ax * ax + ay * ay + az * az);
if (len != 1 && len != 0) {
len = 1 / len;
ax *= len;
ay *= len;
az *= len;
}
// Convert angle-axis to quaternion
float cos2 = cos(angle / 2.f);
float sin2 = sin(angle / 2.f);
float w = cos2;
float x = sin2 * ax;
float y = sin2 * ay;
float z = sin2 * az;
mat4_setIdentity(matrix);
matrix[0] = 1 - 2 * y * y - 2 * z * z;
matrix[1] = 2 * x * y + 2 * w * z;
matrix[2] = 2 * x * z - 2 * w * y;
matrix[4] = 2 * x * y - 2 * w * z;
matrix[5] = 1 - 2 * x * x - 2 * z * z;
matrix[6] = 2 * y * z + 2 * w * x;
matrix[8] = 2 * x * z + 2 * w * y;
matrix[9] = 2 * y * z - 2 * w * x;
matrix[10] = 1 - 2 * x * x - 2 * y * y;
return matrix;
}
mat4 mat4_setScale(mat4 matrix, float x, float y, float z) {
mat4_setIdentity(matrix);
matrix[0] = x;
matrix[5] = y;
matrix[10] = z;
return matrix;
}
mat4 mat4_setOrthographic(mat4 matrix, float left, float right, float top, float bottom, float near, float far) {
float rl = right - left;
float tb = top - bottom;
float fn = far - near;
mat4_setIdentity(matrix);
matrix[0] = 2 / rl;
matrix[5] = 2 / tb;
matrix[10] = -2 / fn;
matrix[12] = -(left + right) / rl;
matrix[13] = -(top + bottom) / tb;
matrix[14] = -(far + near) / fn;
matrix[15] = 1;
return matrix;
}
mat4 mat4_setPerspective(mat4 matrix, float near, float far, float fov, float aspect) {
float range = tan(fov * .5f) * 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_setIdentity(matrix);
matrix[0] = sx;
matrix[5] = sy;
matrix[10] = sz;
matrix[11] = -1.0f;
matrix[14] = pz;
matrix[15] = 0.0f;
return matrix;
}
void mat4_getRotation(mat4 matrix, float* w, float* x, float* y, float* z) {
float qw = sqrt(MAX(0, 1 + matrix[0] + matrix[5] + matrix[10])) / 2;
float qx = sqrt(MAX(0, 1 + matrix[0] - matrix[5] - matrix[10])) / 2;
float qy = sqrt(MAX(0, 1 - matrix[0] + matrix[5] - matrix[10])) / 2;
float qz = sqrt(MAX(0, 1 - matrix[0] - matrix[5] + matrix[10])) / 2;
qx = (matrix[9] - matrix[6]) > 0 ? -qx : qx;
qy = (matrix[2] - matrix[8]) > 0 ? -qy : qy;
qz = (matrix[4] - matrix[1]) > 0 ? -qz : qz;
float s = sqrt(1 - qw * qw);
s = s < .001 ? 1 : s;
*w = 2 * acos(qw);
*x = qx / s;
*y = qy / s;
*z = qz / s;
}
mat4 mat4_translate(mat4 matrix, float x, float y, float z) {
float translation[16];
mat4_setTranslation(translation, x, y, z);
return mat4_multiply(matrix, translation);
}
mat4 mat4_rotate(mat4 matrix, float angle, float ax, float ay, float az) {
float rotation[16];
mat4_setRotation(rotation, angle, ax, ay, az);
return mat4_multiply(matrix, rotation);
}
mat4 mat4_scale(mat4 matrix, float x, float y, float z) {
float scale[16];
mat4_setScale(scale, x, y, z);
return mat4_multiply(matrix, scale);
}
// Modified from gl-matrix.c
mat4 mat4_multiply(mat4 a, mat4 b) {
float a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = b[0], b01 = b[1], b02 = b[2], b03 = b[3],
b10 = b[4], b11 = b[5], b12 = b[6], b13 = b[7],
b20 = b[8], b21 = b[9], b22 = b[10], b23 = b[11],
b30 = b[12], b31 = b[13], b32 = b[14], b33 = b[15];
a[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
a[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
a[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
a[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
a[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
a[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
a[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
a[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
a[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
a[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
a[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
a[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
a[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
a[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
a[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
a[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
return a;
}
void mat4_multiplyVector(mat4 m, float* v) {
float v0 = v[0];
float v1 = v[1];
float v2 = v[2];
float v3 = v[3];
v[0] = v0 * m[0] + v1 * m[4] + v2 * m[8] + v3 * m[12];
v[1] = v0 * m[1] + v1 * m[5] + v2 * m[9] + v3 * m[13];
v[2] = v0 * m[2] + v1 * m[6] + v2 * m[10] + v3 * m[14];
v[3] = v0 * m[3] + v1 * m[7] + v2 * m[11] + v3 * m[15];
}
// Modified from gl-matrix.c
mat4 mat4_invert(mat4 m) {
float a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3],
a10 = m[4], a11 = m[5], a12 = m[6], a13 = m[7],
a20 = m[8], a21 = m[9], a22 = m[10], a23 = m[11],
a30 = m[12], a31 = m[13], a32 = m[14], a33 = m[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06),
invDet;
if (!d) { return NULL; }
invDet = 1 / d;
m[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
m[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
m[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
m[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
m[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
m[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
m[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
m[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
m[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
m[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
m[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
m[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
m[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
m[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
m[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
m[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;
return m;
}

View File

@ -1,26 +0,0 @@
#include "vendor/vec/vec.h"
#ifndef LOVR_MATRIX_TYPES
#define LOVR_MATRIX_TYPES
typedef float* mat4;
typedef vec_t(mat4) vec_mat4_t;
#endif
mat4 mat4_init();
void mat4_deinit(mat4 matrix);
mat4 mat4_copy(mat4 source);
mat4 mat4_fromMat34(mat4 matrix, float (*source)[4]);
mat4 mat4_fromMat44(mat4 matrix, float (*source)[4]);
mat4 mat4_setIdentity(mat4 matrix);
mat4 mat4_setTranslation(mat4 matrix, float x, float y, float z);
mat4 mat4_setRotation(mat4 matrix, float angle, float ax, float ay, float az);
mat4 mat4_setScale(mat4 matrix, float x, float y, float z);
mat4 mat4_setOrthographic(mat4 matrix, float left, float right, float top, float bottom, float near, float far);
mat4 mat4_setPerspective(mat4 matrix, float near, float far, float fov, float aspect);
void mat4_getRotation(mat4 matrix, float* w, float* x, float* y, float* z);
mat4 mat4_translate(mat4 matrix, float x, float y, float z);
mat4 mat4_rotate(mat4 matrix, float angle, float ax, float ay, float az);
mat4 mat4_scale(mat4 matrix, float x, float y, float z);
mat4 mat4_multiply(mat4 a, mat4 b);
void mat4_multiplyVector(mat4 m, float* v);
mat4 mat4_invert(mat4 m);