From e8e2a99e5b3b553e08e60b98201453ced403b3c4 Mon Sep 17 00:00:00 2001 From: bjorn Date: Wed, 18 Jan 2017 00:51:09 -0800 Subject: [PATCH] Finish internal math library; --- src/graphics/graphics.c | 20 ++- src/graphics/graphics.h | 2 +- src/graphics/model.c | 21 ++- src/graphics/model.h | 3 +- src/graphics/shader.c | 4 +- src/graphics/shader.h | 2 +- src/graphics/texture.c | 4 +- src/headset/vive.c | 10 +- src/loaders/model.c | 2 +- src/math/mat4.c | 257 +++++++++++++++++++++++++++++++++++++ src/math/mat4.h | 16 +++ src/math/math.h | 9 ++ src/math/quat.c | 144 +++++++++++++++++++++ src/math/quat.h | 12 ++ src/math/vec3.c | 40 +++++- src/math/vec3.h | 12 +- src/matrix.c | 276 ---------------------------------------- src/matrix.h | 26 ---- 18 files changed, 520 insertions(+), 340 deletions(-) create mode 100644 src/math/mat4.c create mode 100644 src/math/mat4.h create mode 100644 src/math/math.h create mode 100644 src/math/quat.c create mode 100644 src/math/quat.h delete mode 100644 src/matrix.c delete mode 100644 src/matrix.h diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 7f005a03..b583ae94 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -1,5 +1,6 @@ #include "graphics/graphics.h" #include "loaders/texture.h" +#include "math/quat.h" #include "util.h" #include "glfw.h" #define _USE_MATH_DEFINES @@ -39,7 +40,7 @@ void lovrGraphicsDestroy() { lovrGraphicsSetShader(NULL); glUseProgram(0); for (int i = 0; i < MAX_TRANSFORMS; i++) { - mat4_deinit(state.transforms[i]); + free(state.transforms[i]); } for (int i = 0; i < MAX_CANVASES; i++) { free(state.canvases[i]); @@ -203,7 +204,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 +334,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) { @@ -341,7 +342,10 @@ void lovrGraphicsTranslate(float x, float y, float z) { } void lovrGraphicsRotate(float angle, float ax, float ay, float az) { - mat4_rotate(state.transforms[state.transform], angle, ax, ay, az); + float rotation[4]; + float axis[3] = { ax, ay, az }; + quat_fromAngleAxis(rotation, angle, axis); + mat4_rotate(state.transforms[state.transform], rotation); } void lovrGraphicsScale(float x, float y, float z) { @@ -349,12 +353,16 @@ 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) { + float rotation[4]; + float axis[3] = { ax, ay, az }; + quat_fromAngleAxis(rotation, angle, axis); // M *= T * S * R float transform[16]; - mat4_setTranslation(transform, tx, ty, tz); + mat4_identity(transform); + mat4_translate(transform, tx, ty, tz); mat4_scale(transform, sx, sy, sz); - mat4_rotate(transform, angle, ax, ay, az); + mat4_rotate(transform, rotation); lovrGraphicsMatrixTransform(transform); } diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 2af33d15..22f77a85 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -3,7 +3,7 @@ #include "graphics/shader.h" #include "graphics/skybox.h" #include "graphics/texture.h" -#include "matrix.h" +#include "math/mat4.h" #ifndef LOVR_GRAPHICS_TYPES #define LOVR_GRAPHICS_TYPES diff --git a/src/graphics/model.c b/src/graphics/model.c index 91a8532e..d4362051 100644 --- a/src/graphics/model.c +++ b/src/graphics/model.c @@ -3,12 +3,10 @@ #include static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) { - mat4 newTransform; + mat4 newTransform = mat4_init(); - if (!transform) { - newTransform = mat4_init(); - } else { - newTransform = mat4_copy(transform); + if (transform) { + mat4_set(newTransform, transform); } mat4_multiply(newTransform, node->transform); @@ -23,15 +21,14 @@ 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] = { + float vec[3] = { vertex.x, vertex.y, - vertex.z, - 1.f + vertex.z }; - mat4_multiplyVector(newTransform, transformedVertex); - vec_pusharr(vertices, transformedVertex, 3); + vec3_transform(vec, newTransform); + vec_pusharr(vertices, vec, 3); if (modelData->hasNormals) { ModelVertex normal = mesh->normals.data[v]; @@ -60,7 +57,7 @@ static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec visitNode(modelData, node->children.data[c], newTransform, vertices, indices); } - mat4_deinit(newTransform); + free(newTransform); } Model* lovrModelCreate(ModelData* modelData) { @@ -136,7 +133,7 @@ void lovrModelDataDestroy(ModelData* modelData) { while (nodes.length > 0) { ModelNode* node = vec_first(&nodes); vec_extend(&nodes, &node->children); - mat4_deinit(node->transform); + free(node->transform); vec_deinit(&node->meshes); vec_deinit(&node->children); vec_splice(&nodes, 0, 1); diff --git a/src/graphics/model.h b/src/graphics/model.h index a8894827..835fda52 100644 --- a/src/graphics/model.h +++ b/src/graphics/model.h @@ -1,6 +1,7 @@ #include "graphics/buffer.h" #include "graphics/texture.h" -#include "matrix.h" +#include "math/mat4.h" +#include "math/vec3.h" #include "glfw.h" #include "util.h" #include "vendor/vec/vec.h" diff --git a/src/graphics/shader.c b/src/graphics/shader.c index 37d0f84f..f3883b41 100644 --- a/src/graphics/shader.c +++ b/src/graphics/shader.c @@ -175,8 +175,8 @@ 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); + free(shader->transform); + free(shader->projection); map_deinit(&shader->uniforms); free(shader); } diff --git a/src/graphics/shader.h b/src/graphics/shader.h index 30dd02ab..751062f1 100644 --- a/src/graphics/shader.h +++ b/src/graphics/shader.h @@ -1,5 +1,5 @@ #include "glfw.h" -#include "matrix.h" +#include "math/mat4.h" #include "vendor/map/map.h" #include "util.h" diff --git a/src/graphics/texture.c b/src/graphics/texture.c index 4e93e5f0..dc1fbe41 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -109,7 +109,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 +122,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); } } diff --git a/src/headset/vive.c b/src/headset/vive.c index 322deb10..2b4b2ab8 100644 --- a/src/headset/vive.c +++ b/src/headset/vive.c @@ -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 #include @@ -265,7 +267,9 @@ void viveGetOrientation(void* headset, float* w, float* x, float* y, float *z) { } float matrix[16]; - mat4_getRotation(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), w, x, y, z); + float rotation[4]; + mat4_toQuat(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), rotation); + quat_toAngleAxis(rotation, w, x, y, z); } void viveGetVelocity(void* headset, float* x, float* y, float* z) { @@ -349,7 +353,9 @@ void viveControllerGetOrientation(void* headset, Controller* controller, float* } float matrix[16]; - mat4_getRotation(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), w, x, y, z); + float rotation[4]; + mat4_toQuat(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), rotation); + quat_toAngleAxis(rotation, w, x, y, z); } float viveControllerGetAxis(void* headset, Controller* controller, ControllerAxis axis) { diff --git a/src/loaders/model.c b/src/loaders/model.c index a0e3751f..b06a9a7f 100644 --- a/src/loaders/model.c +++ b/src/loaders/model.c @@ -9,7 +9,7 @@ static void assimpNodeTraversal(ModelNode* node, struct aiNode* assimpNode) { // Transform struct aiMatrix4x4 m = assimpNode->mTransformation; aiTransposeMatrix4(&m); - node->transform = mat4_copy((float*) &m); + node->transform = mat4_set(mat4_init(), (float*) &m); // Meshes vec_init(&node->meshes); diff --git a/src/math/mat4.c b/src/math/mat4.c new file mode 100644 index 00000000..0be059ae --- /dev/null +++ b/src/math/mat4.c @@ -0,0 +1,257 @@ +#include "math/mat4.h" +#include "util.h" +#include +#include +#include + +// m0 m4 m8 m12 +// m1 m5 m9 m13 +// m2 m6 m10 m14 +// m3 m7 m11 m15 + +mat4 mat4_init() { + mat4 m = malloc(16 * sizeof(float)); + return mat4_identity(m); +} + +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_set(mat4 m, mat4 n) { + return memcpy(m, n, 16 * sizeof(float)); +} + +mat4 mat4_identity(mat4 m) { + memset(m, 0, 16 * sizeof(float)); + m[0] = m[5] = m[10] = m[15] = 1.f; + return m; +} + +mat4 mat4_transpose(mat4 m) { + float m1 = m[1]; + float m2 = m[2]; + float m3 = m[3]; + float m6 = m[6]; + float m7 = m[7]; + float m11 = m[11]; + m[1] = m[4]; + m[2] = m[8]; + m[3] = m[12]; + m[4] = m1; + m[6] = m[9]; + m[7] = m[13]; + m[8] = m2; + m[9] = m6; + m[11] = m[14]; + m[12] = m3; + m[13] = m7; + m[14] = m11; + 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_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_rotate(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_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; +} + +quat mat4_toQuat(mat4 m, quat q) { + 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; +} diff --git a/src/math/mat4.h b/src/math/mat4.h new file mode 100644 index 00000000..b92eeab1 --- /dev/null +++ b/src/math/mat4.h @@ -0,0 +1,16 @@ +#include "math/math.h" + +mat4 mat4_init(); +mat4 mat4_fromMat34(mat4 m, float (*n)[4]); +mat4 mat4_fromMat44(mat4 m, float (*n)[4]); +mat4 mat4_set(mat4 m, mat4 n); +mat4 mat4_identity(mat4 m); +mat4 mat4_transpose(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_scale(mat4 m, float x, float y, float z); +mat4 mat4_rotate(mat4 m, quat q); +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); +quat mat4_toQuat(mat4 m, quat q); diff --git a/src/math/math.h b/src/math/math.h new file mode 100644 index 00000000..f530080e --- /dev/null +++ b/src/math/math.h @@ -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 diff --git a/src/math/quat.c b/src/math/quat.c new file mode 100644 index 00000000..b5913b63 --- /dev/null +++ b/src/math/quat.c @@ -0,0 +1,144 @@ +#include "math/quat.h" +#include "math/vec3.h" +#include +#include + +quat quat_init(float x, float y, float z, float w) { + quat q = malloc(4 * sizeof(float)); + 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_set(qq, forward); + vec3_normalize(qq); + vec3_normalize(up); + q[3] = 1 + vec3_dot(qq, up); + vec3_cross(qq, up); + return q; +} + +quat quat_set(quat q, quat r) { + q[0] = r[0]; + q[1] = r[1]; + q[2] = r[2]; + q[3] = r[3]; + return q; +} + +quat quat_multiply(quat q, quat r) { + float qx = q[0]; + float qy = q[1]; + float qz = q[2]; + float qw = q[3]; + float rx = r[0]; + float ry = r[1]; + float rz = r[2]; + float rw = r[3]; + q[0] = qx * rw + qw * rx - qy * rz - qz * ry; + q[1] = qy * rw + qw * ry - qz * rx - qx * rz; + q[2] = qz * rw + qw * rz - qx * ry - qy * rx; + q[3] = qw * rw - qx * rx - qy * ry - qz * rz; + 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]); +} + +// From gl-matrix +quat quat_slerp(quat q, quat r, float t) { + float dot = q[0] * r[0] + q[1] * r[1] + q[2] * r[2] + q[3] * r[3]; + if (fabs(dot) >= 1.f) { + return q; + } + + float halfTheta = acos(dot); + float sinHalfTheta = sqrt(1.f - dot * dot); + + if (fabs(sinHalfTheta) < .001) { + q[0] = q[0] * .5 + r[0] * .5; + q[1] = q[1] * .5 + r[1] * .5; + q[2] = q[2] * .5 + r[2] * .5; + q[3] = q[3] * .5 + r[3] * .5; + return q; + } + + float a = sin((1 - t) * halfTheta) / sinHalfTheta; + float b = sin(t * halfTheta) / sinHalfTheta; + + q[0] = q[0] * a + r[0] * b; + q[1] = q[1] * a + r[1] * b; + q[2] = q[2] * a + r[2] * b; + q[3] = q[3] * a + r[3] * b; + + return q; +} + +quat quat_between(quat q, vec3 u, vec3 v) { + float dot = vec3_dot(u, v); + if (dot > .99999) { + q[0] = q[1] = q[2] = 0.f; + q[3] = 1.f; + return q; + } else if (dot < -.99999) { + float axis[3] = { 1, 0, 0 }; + vec3_cross(axis, u); + if (vec3_length(axis) < .00001) { + axis[0] = 0; + axis[1] = 1; + axis[2] = 0; + vec3_cross(axis, u); + } + vec3_normalize(axis); + quat_fromAngleAxis(q, M_PI, axis); + return q; + } + + vec3_cross(vec3_set(q, u), v); + q[3] = 1 + dot; + return quat_normalize(q); +} + +void quat_toAngleAxis(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; +} diff --git a/src/math/quat.h b/src/math/quat.h new file mode 100644 index 00000000..cfbc67bd --- /dev/null +++ b/src/math/quat.h @@ -0,0 +1,12 @@ +#include "math/math.h" + +quat quat_init(float x, float y, float z, float w); +quat quat_fromAngleAxis(quat q, float angle, vec3 axis); +quat quat_fromDirection(quat q, vec3 forward, vec3 up); +quat quat_set(quat q, quat r); +quat quat_multiply(quat q, quat r); +quat quat_normalize(quat q); +float quat_length(quat q); +quat quat_slerp(quat q, quat r, float t); +quat quat_between(quat q, vec3 u, vec3 v); +void quat_toAngleAxis(quat q, float* angle, float* x, float* y, float* z); diff --git a/src/math/vec3.c b/src/math/vec3.c index 40f8e91e..9e7db735 100644 --- a/src/math/vec3.c +++ b/src/math/vec3.c @@ -1,4 +1,5 @@ #include "math/vec3.h" +#include "math/quat.h" #include #include @@ -45,8 +46,15 @@ vec3 vec3_div(vec3 v, vec3 u) { 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_len(v); + float len = vec3_length(v); if (len == 0) { return v; } @@ -58,11 +66,11 @@ vec3 vec3_normalize(vec3 v) { return v; } -float vec3_len(vec3 v) { +float vec3_length(vec3 v) { return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); } -float vec3_dist(vec3 v, vec3 u) { +float vec3_distance(vec3 v, vec3 u) { float dx = v[0] - u[0]; float dy = v[1] - u[1]; float dz = v[2] - u[2]; @@ -70,7 +78,7 @@ float vec3_dist(vec3 v, vec3 u) { } float vec3_angle(vec3 v, vec3 u) { - return acos(vec3_dot(v, u) / (vec3_len(v) * vec3_len(u))); + return acos(vec3_dot(v, u) / (vec3_length(v) * vec3_length(u))); } float vec3_dot(vec3 v, vec3 u) { @@ -87,6 +95,30 @@ vec3 vec3_cross(vec3 v, vec3 u) { return v; } +vec3 vec3_rotate(vec3 v, quat q) { + float s = q[3]; + float u[3]; + float c[3]; + vec3_set(u, q); + vec3_cross(vec3_set(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); + return vec3_add(v, vec3_add(u, c)); +} + +vec3 vec3_transform(vec3 v, mat4 m) { + float v0 = v[0]; + float v1 = v[1]; + float v2 = v[2]; + v[0] = v0 * m[0] + v1 * m[4] + v2 * m[8] + m[12]; + v[1] = v0 * m[1] + v1 * m[5] + v2 * m[9] + m[13]; + v[2] = v0 * m[2] + v1 * m[6] + v2 * m[10] + m[14]; + return v; +} + vec3 vec3_lerp(vec3 v, vec3 u, float t) { v[0] += (u[0] - v[0]) * t; v[1] += (u[1] - v[1]) * t; diff --git a/src/math/vec3.h b/src/math/vec3.h index 879c1c11..a3fef7de 100644 --- a/src/math/vec3.h +++ b/src/math/vec3.h @@ -1,7 +1,4 @@ -#ifndef LOVR_VECTOR_TYPES -#define LOVR_VECTOR_TYPES -typedef float* vec3; -#endif +#include "math/math.h" vec3 vec3_init(float x, float y, float z); vec3 vec3_set(vec3 v, vec3 u); @@ -9,10 +6,13 @@ vec3 vec3_add(vec3 v, vec3 u); vec3 vec3_sub(vec3 v, vec3 u); vec3 vec3_mul(vec3 v, vec3 u); vec3 vec3_div(vec3 v, vec3 u); +vec3 vec3_scale(vec3 v, float s); vec3 vec3_normalize(vec3 v); -float vec3_len(vec3 v); -float vec3_dist(vec3 v, vec3 u); +float vec3_length(vec3 v); +float vec3_distance(vec3 v, vec3 u); float vec3_angle(vec3 v, vec3 u); float vec3_dot(vec3 v, vec3 u); vec3 vec3_cross(vec3 v, vec3 u); +vec3 vec3_rotate(vec3 v, quat q); +vec3 vec3_transform(vec3 v, mat4 m); vec3 vec3_lerp(vec3 v, vec3 u, float t); diff --git a/src/matrix.c b/src/matrix.c deleted file mode 100644 index 5521d33d..00000000 --- a/src/matrix.c +++ /dev/null @@ -1,276 +0,0 @@ -#include "matrix.h" -#include "util.h" -#include -#include -#include - -/* - 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; -} diff --git a/src/matrix.h b/src/matrix.h deleted file mode 100644 index 3bd5c75c..00000000 --- a/src/matrix.h +++ /dev/null @@ -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);