mirror of
https://github.com/bjornbytes/lovr.git
synced 2024-07-04 21:43:34 +00:00
commit
a3a3a368c0
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@ deps
|
||||||
data
|
data
|
||||||
src/obj
|
src/obj
|
||||||
src/Tupfile
|
src/Tupfile
|
||||||
|
/watch.sh
|
||||||
*.lua
|
*.lua
|
||||||
*.glsl
|
*.glsl
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "audio/audio.h"
|
#include "audio/audio.h"
|
||||||
#include "loaders/source.h"
|
#include "loaders/source.h"
|
||||||
|
#include "math/vec3.h"
|
||||||
|
#include "math/quat.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -8,12 +10,6 @@ static AudioState state;
|
||||||
|
|
||||||
static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
|
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() {
|
void lovrAudioInit() {
|
||||||
ALCdevice* device = alcOpenDevice(NULL);
|
ALCdevice* device = alcOpenDevice(NULL);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
|
@ -35,6 +31,9 @@ void lovrAudioInit() {
|
||||||
state.device = device;
|
state.device = device;
|
||||||
state.context = context;
|
state.context = context;
|
||||||
vec_init(&state.sources);
|
vec_init(&state.sources);
|
||||||
|
|
||||||
|
vec3_set(state.position, 0, 0, 0);
|
||||||
|
quat_set(state.orientation, 0, 0, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioDestroy() {
|
void lovrAudioDestroy() {
|
||||||
|
@ -73,33 +72,13 @@ void lovrAudioAdd(Source* source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az) {
|
void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az) {
|
||||||
float v[6];
|
quat_getAngleAxis(state.orientation, angle, ax, ay, az);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioGetPosition(float* x, float* y, float* z) {
|
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() {
|
float lovrAudioGetVolume() {
|
||||||
|
@ -135,52 +114,23 @@ void lovrAudioRewind() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help
|
|
||||||
void lovrAudioSetOrientation(float angle, float ax, float ay, float az) {
|
void lovrAudioSetOrientation(float angle, float ax, float ay, float az) {
|
||||||
|
|
||||||
// Quaternion
|
// Rotate the unit forward/up vectors by the quaternion derived from the specified angle/axis
|
||||||
float cos2 = cos(angle / 2.f);
|
float f[3] = { 0, 0, -1 };
|
||||||
float sin2 = sin(angle / 2.f);
|
float u[3] = { 0, 1, 0 };
|
||||||
float qx = sin2 * ax;
|
float axis[3] = { ax, ay, az };
|
||||||
float qy = sin2 * ay;
|
quat_fromAngleAxis(state.orientation, angle, axis);
|
||||||
float qz = sin2 * az;
|
quat_rotate(state.orientation, f);
|
||||||
float s = cos2;
|
quat_rotate(state.orientation, u);
|
||||||
|
|
||||||
float vx, vy, vz, qdotv, qdotq, a, b, c, cx, cy, cz;
|
// Pass the rotated orientation vectors to OpenAL
|
||||||
|
ALfloat orientation[6] = { f[0], f[1], f[2], u[0], u[1], u[2] };
|
||||||
// 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 };
|
|
||||||
alListenerfv(AL_ORIENTATION, orientation);
|
alListenerfv(AL_ORIENTATION, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrAudioSetPosition(float x, float y, float z) {
|
void lovrAudioSetPosition(float x, float y, float z) {
|
||||||
|
vec3_set(state.position, x, y, z);
|
||||||
alListener3f(AL_POSITION, x, y, z);
|
alListener3f(AL_POSITION, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ typedef struct {
|
||||||
ALCdevice* device;
|
ALCdevice* device;
|
||||||
ALCcontext* context;
|
ALCcontext* context;
|
||||||
vec_void_t sources;
|
vec_void_t sources;
|
||||||
|
float position[3];
|
||||||
|
float orientation[4];
|
||||||
} AudioState;
|
} AudioState;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "loaders/texture.h"
|
#include "loaders/texture.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
|
#include "math/vec3.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "glfw.h"
|
#include "glfw.h"
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
|
@ -14,9 +16,6 @@ static GraphicsState state;
|
||||||
// Base
|
// Base
|
||||||
|
|
||||||
void lovrGraphicsInit() {
|
void lovrGraphicsInit() {
|
||||||
for (int i = 0; i < MAX_TRANSFORMS; i++) {
|
|
||||||
state.transforms[i] = mat4_init();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < MAX_CANVASES; i++) {
|
for (int i = 0; i < MAX_CANVASES; i++) {
|
||||||
state.canvases[i] = malloc(sizeof(CanvasState));
|
state.canvases[i] = malloc(sizeof(CanvasState));
|
||||||
}
|
}
|
||||||
|
@ -38,9 +37,6 @@ void lovrGraphicsInit() {
|
||||||
void lovrGraphicsDestroy() {
|
void lovrGraphicsDestroy() {
|
||||||
lovrGraphicsSetShader(NULL);
|
lovrGraphicsSetShader(NULL);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
for (int i = 0; i < MAX_TRANSFORMS; i++) {
|
|
||||||
mat4_deinit(state.transforms[i]);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < MAX_CANVASES; i++) {
|
for (int i = 0; i < MAX_CANVASES; i++) {
|
||||||
free(state.canvases[i]);
|
free(state.canvases[i]);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +199,7 @@ mat4 lovrGraphicsGetProjection() {
|
||||||
void lovrGraphicsSetProjection(float near, float far, float fov) {
|
void lovrGraphicsSetProjection(float near, float far, float fov) {
|
||||||
int width, height;
|
int width, height;
|
||||||
glfwGetWindowSize(window, &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) {
|
void lovrGraphicsSetProjectionRaw(mat4 projection) {
|
||||||
|
@ -333,7 +329,7 @@ int lovrGraphicsPop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrGraphicsOrigin() {
|
void lovrGraphicsOrigin() {
|
||||||
mat4_setIdentity(state.transforms[state.transform]);
|
mat4_identity(state.transforms[state.transform]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrGraphicsTranslate(float x, float y, float z) {
|
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);
|
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) {
|
void lovrGraphicsMatrixTransform(mat4 transform) {
|
||||||
mat4_multiply(state.transforms[state.transform], transform);
|
mat4_multiply(state.transforms[state.transform], transform);
|
||||||
}
|
}
|
||||||
|
@ -420,16 +406,13 @@ void lovrGraphicsTriangle(DrawMode mode, float* points) {
|
||||||
vec_pusharr(&state.shapeData, points, 9);
|
vec_pusharr(&state.shapeData, points, 9);
|
||||||
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 0, 0, 0);
|
lovrGraphicsDrawPrimitive(GL_LINE_LOOP, NULL, 0, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
float n[3] = {
|
float normal[3];
|
||||||
points[1] * points[5] - points[2] * points[4],
|
vec3_cross(vec3_init(normal, &points[0]), &points[3]);
|
||||||
points[2] * points[3] - points[0] * points[5],
|
|
||||||
points[0] * points[4] - points[1] * points[3]
|
|
||||||
};
|
|
||||||
|
|
||||||
float data[18] = {
|
float data[18] = {
|
||||||
points[0], points[1], points[2], n[0], n[1], n[2],
|
points[0], points[1], points[2], normal[0], normal[1], normal[2],
|
||||||
points[3], points[4], points[5], n[0], n[1], n[2],
|
points[3], points[4], points[5], normal[0], normal[1], normal[2],
|
||||||
points[6], points[7], points[8], n[0], n[1], n[2]
|
points[6], points[7], points[8], normal[0], normal[1], normal[2]
|
||||||
};
|
};
|
||||||
|
|
||||||
vec_clear(&state.shapeData);
|
vec_clear(&state.shapeData);
|
||||||
|
@ -442,7 +425,7 @@ void lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float
|
||||||
|
|
||||||
// Normalize the normal vector
|
// Normalize the normal vector
|
||||||
float len = sqrt(nx * nx + ny * ny + nz + nz);
|
float len = sqrt(nx * nx + ny * ny + nz + nz);
|
||||||
if (len != 1) {
|
if (len != 0) {
|
||||||
len = 1 / len;
|
len = 1 / len;
|
||||||
nx *= len;
|
nx *= len;
|
||||||
ny *= 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)
|
// Angle between normal vector and the normal vector of the default geometry (dot product)
|
||||||
float theta = acos(nz);
|
float theta = acos(nz);
|
||||||
|
|
||||||
|
float transform[16];
|
||||||
|
mat4_setTransform(transform, x, y, z, size, theta, cx, cy, cz);
|
||||||
|
|
||||||
lovrGraphicsPush();
|
lovrGraphicsPush();
|
||||||
lovrGraphicsTransform(x, y, z, size, size, size, theta, cx, cy, cz);
|
lovrGraphicsMatrixTransform(transform);
|
||||||
|
|
||||||
if (mode == DRAW_MODE_LINE) {
|
if (mode == DRAW_MODE_LINE) {
|
||||||
float points[] = {
|
float points[] = {
|
||||||
|
@ -507,9 +493,9 @@ void lovrGraphicsPlaneFullscreen(Texture* texture) {
|
||||||
lovrRelease(&lastShader->ref);
|
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();
|
lovrGraphicsPush();
|
||||||
lovrGraphicsTransform(x, y, z, size, size, size, angle, axisX, axisY, axisZ);
|
lovrGraphicsMatrixTransform(transform);
|
||||||
|
|
||||||
if (mode == DRAW_MODE_LINE) {
|
if (mode == DRAW_MODE_LINE) {
|
||||||
float points[] = {
|
float points[] = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "graphics/shader.h"
|
#include "graphics/shader.h"
|
||||||
#include "graphics/skybox.h"
|
#include "graphics/skybox.h"
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "matrix.h"
|
#include "math/math.h"
|
||||||
|
|
||||||
#ifndef LOVR_GRAPHICS_TYPES
|
#ifndef LOVR_GRAPHICS_TYPES
|
||||||
#define LOVR_GRAPHICS_TYPES
|
#define LOVR_GRAPHICS_TYPES
|
||||||
|
@ -50,10 +50,10 @@ typedef struct {
|
||||||
Shader* skyboxShader;
|
Shader* skyboxShader;
|
||||||
Shader* fullscreenShader;
|
Shader* fullscreenShader;
|
||||||
Texture* defaultTexture;
|
Texture* defaultTexture;
|
||||||
int transform;
|
float transforms[MAX_TRANSFORMS][16];
|
||||||
mat4 transforms[MAX_TRANSFORMS];
|
|
||||||
int canvas;
|
|
||||||
CanvasState* canvases[MAX_CANVASES];
|
CanvasState* canvases[MAX_CANVASES];
|
||||||
|
int transform;
|
||||||
|
int canvas;
|
||||||
unsigned int color;
|
unsigned int color;
|
||||||
char colorMask;
|
char colorMask;
|
||||||
int isScissorEnabled;
|
int isScissorEnabled;
|
||||||
|
@ -124,7 +124,6 @@ void lovrGraphicsOrigin();
|
||||||
void lovrGraphicsTranslate(float x, float y, float z);
|
void lovrGraphicsTranslate(float x, float y, float z);
|
||||||
void lovrGraphicsRotate(float angle, float ax, float ay, float az);
|
void lovrGraphicsRotate(float angle, float ax, float ay, float az);
|
||||||
void lovrGraphicsScale(float x, float y, float z);
|
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);
|
void lovrGraphicsMatrixTransform(mat4 transform);
|
||||||
|
|
||||||
// Primitives
|
// Primitives
|
||||||
|
@ -134,5 +133,5 @@ void lovrGraphicsLine(float* points, int count);
|
||||||
void lovrGraphicsTriangle(DrawMode mode, float* points);
|
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 lovrGraphicsPlane(DrawMode mode, Texture* texture, float x, float y, float z, float size, float nx, float ny, float nz);
|
||||||
void lovrGraphicsPlaneFullscreen(Texture* texture);
|
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);
|
void lovrGraphicsSkybox(Skybox* skybox, float angle, float ax, float ay, float az);
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
#include "graphics/model.h"
|
#include "graphics/model.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
|
#include "math/vec3.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) {
|
static void visitNode(ModelData* modelData, ModelNode* node, mat4 transform, vec_float_t* vertices, vec_uint_t* indices) {
|
||||||
mat4 newTransform;
|
float newTransform[16];
|
||||||
|
|
||||||
if (!transform) {
|
if (transform) {
|
||||||
newTransform = mat4_init();
|
mat4_set(newTransform, transform);
|
||||||
} else {
|
} else {
|
||||||
newTransform = mat4_copy(transform);
|
mat4_identity(newTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_multiply(newTransform, node->transform);
|
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++) {
|
for (int v = 0; v < mesh->vertices.length; v++) {
|
||||||
ModelVertex vertex = mesh->vertices.data[v];
|
ModelVertex vertex = mesh->vertices.data[v];
|
||||||
|
|
||||||
float transformedVertex[4] = {
|
float vec[3] = { vertex.x, vertex.y, vertex.z };
|
||||||
vertex.x,
|
mat4_transform(newTransform, vec);
|
||||||
vertex.y,
|
vec_pusharr(vertices, vec, 3);
|
||||||
vertex.z,
|
|
||||||
1.f
|
|
||||||
};
|
|
||||||
|
|
||||||
mat4_multiplyVector(newTransform, transformedVertex);
|
|
||||||
vec_pusharr(vertices, transformedVertex, 3);
|
|
||||||
|
|
||||||
if (modelData->hasNormals) {
|
if (modelData->hasNormals) {
|
||||||
ModelVertex normal = mesh->normals.data[v];
|
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++) {
|
for (int c = 0; c < node->children.length; c++) {
|
||||||
visitNode(modelData, node->children.data[c], newTransform, vertices, indices);
|
visitNode(modelData, node->children.data[c], newTransform, vertices, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4_deinit(newTransform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* lovrModelCreate(ModelData* modelData) {
|
Model* lovrModelCreate(ModelData* modelData) {
|
||||||
|
@ -136,7 +130,6 @@ void lovrModelDataDestroy(ModelData* modelData) {
|
||||||
while (nodes.length > 0) {
|
while (nodes.length > 0) {
|
||||||
ModelNode* node = vec_first(&nodes);
|
ModelNode* node = vec_first(&nodes);
|
||||||
vec_extend(&nodes, &node->children);
|
vec_extend(&nodes, &node->children);
|
||||||
mat4_deinit(node->transform);
|
|
||||||
vec_deinit(&node->meshes);
|
vec_deinit(&node->meshes);
|
||||||
vec_deinit(&node->children);
|
vec_deinit(&node->children);
|
||||||
vec_splice(&nodes, 0, 1);
|
vec_splice(&nodes, 0, 1);
|
||||||
|
@ -148,9 +141,9 @@ void lovrModelDataDestroy(ModelData* modelData) {
|
||||||
free(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();
|
lovrGraphicsPush();
|
||||||
lovrGraphicsTransform(x, y, z, scale, scale, scale, angle, ax, ay, az);
|
lovrGraphicsMatrixTransform(transform);
|
||||||
lovrBufferDraw(model->buffer);
|
lovrBufferDraw(model->buffer);
|
||||||
lovrGraphicsPop();
|
lovrGraphicsPop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "graphics/buffer.h"
|
#include "graphics/buffer.h"
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "matrix.h"
|
#include "math/math.h"
|
||||||
#include "glfw.h"
|
#include "glfw.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "vendor/vec/vec.h"
|
#include "vendor/vec/vec.h"
|
||||||
|
@ -32,7 +32,7 @@ typedef struct {
|
||||||
typedef vec_t(ModelMesh*) vec_model_mesh_t;
|
typedef vec_t(ModelMesh*) vec_model_mesh_t;
|
||||||
|
|
||||||
typedef struct ModelNode {
|
typedef struct ModelNode {
|
||||||
mat4 transform;
|
float transform[16];
|
||||||
vec_uint_t meshes;
|
vec_uint_t meshes;
|
||||||
vec_void_t children;
|
vec_void_t children;
|
||||||
} ModelNode;
|
} ModelNode;
|
||||||
|
@ -57,6 +57,6 @@ typedef struct {
|
||||||
Model* lovrModelCreate(ModelData* modelData);
|
Model* lovrModelCreate(ModelData* modelData);
|
||||||
void lovrModelDestroy(const Ref* ref);
|
void lovrModelDestroy(const Ref* ref);
|
||||||
void lovrModelDataDestroy(ModelData* modelData);
|
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);
|
Texture* lovrModelGetTexture(Model* model);
|
||||||
void lovrModelSetTexture(Model* model, Texture* texture);
|
void lovrModelSetTexture(Model* model, Texture* texture);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "graphics/shader.h"
|
#include "graphics/shader.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@ -162,8 +163,8 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
|
||||||
|
|
||||||
// Initial state
|
// Initial state
|
||||||
shader->id = id;
|
shader->id = id;
|
||||||
shader->transform = mat4_init();
|
mat4_identity(shader->transform);
|
||||||
shader->projection = mat4_init();
|
mat4_identity(shader->projection);
|
||||||
shader->color = 0;
|
shader->color = 0;
|
||||||
|
|
||||||
// Send initial uniform values to shader
|
// Send initial uniform values to shader
|
||||||
|
@ -175,8 +176,6 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
|
||||||
void lovrShaderDestroy(const Ref* ref) {
|
void lovrShaderDestroy(const Ref* ref) {
|
||||||
Shader* shader = containerof(ref, Shader);
|
Shader* shader = containerof(ref, Shader);
|
||||||
glDeleteProgram(shader->id);
|
glDeleteProgram(shader->id);
|
||||||
mat4_deinit(shader->transform);
|
|
||||||
mat4_deinit(shader->projection);
|
|
||||||
map_deinit(&shader->uniforms);
|
map_deinit(&shader->uniforms);
|
||||||
free(shader);
|
free(shader);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "glfw.h"
|
#include "glfw.h"
|
||||||
#include "matrix.h"
|
#include "math/math.h"
|
||||||
#include "vendor/map/map.h"
|
#include "vendor/map/map.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ typedef struct {
|
||||||
Ref ref;
|
Ref ref;
|
||||||
int id;
|
int id;
|
||||||
map_uniform_t uniforms;
|
map_uniform_t uniforms;
|
||||||
mat4 transform;
|
float transform[16];
|
||||||
mat4 projection;
|
float projection[16];
|
||||||
unsigned int color;
|
unsigned int color;
|
||||||
} Shader;
|
} Shader;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "graphics/texture.h"
|
#include "graphics/texture.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -109,7 +110,7 @@ void lovrTextureBindFramebuffer(Texture* texture) {
|
||||||
|
|
||||||
if (texture->projection == PROJECTION_ORTHOGRAPHIC) {
|
if (texture->projection == PROJECTION_ORTHOGRAPHIC) {
|
||||||
float projection[16];
|
float projection[16];
|
||||||
mat4_setOrthographic(projection, 0, w, 0, h, -1, 1);
|
mat4_orthographic(projection, 0, w, 0, h, -1, 1);
|
||||||
lovrGraphicsSetProjectionRaw(projection);
|
lovrGraphicsSetProjectionRaw(projection);
|
||||||
} else if (texture->projection == PROJECTION_PERSPECTIVE) {
|
} else if (texture->projection == PROJECTION_PERSPECTIVE) {
|
||||||
mat4 projection = lovrGraphicsGetProjection();
|
mat4 projection = lovrGraphicsGetProjection();
|
||||||
|
@ -122,7 +123,7 @@ void lovrTextureBindFramebuffer(Texture* texture) {
|
||||||
float far = k * near;
|
float far = k * near;
|
||||||
float fov = 2.f * atan(1.f / b);
|
float fov = 2.f * atan(1.f / b);
|
||||||
float newProjection[16];
|
float newProjection[16];
|
||||||
mat4_setPerspective(newProjection, near, far, fov, aspect);
|
mat4_perspective(newProjection, near, far, fov, aspect);
|
||||||
lovrGraphicsSetProjectionRaw(newProjection);
|
lovrGraphicsSetProjectionRaw(newProjection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,13 +108,13 @@ void lovrHeadsetGetPosition(float* x, float* y, float* z) {
|
||||||
headset->getPosition(headset, x, y, 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) {
|
if (!headset) {
|
||||||
*w = *x = *y = *z = 0.f;
|
*angle = *x = *y = *z = 0.f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
headset->getOrientation(headset, w, x, y, z);
|
headset->getOrientation(headset, angle, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrHeadsetGetVelocity(float* x, float* y, float* 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);
|
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) {
|
if (!headset || !controller) {
|
||||||
*w = *x = *y = *z = 0.f;
|
*angle = *x = *y = *z = 0.f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
headset->controllerGetOrientation(headset, controller, w, x, y, z);
|
headset->controllerGetOrientation(headset, controller, angle, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) {
|
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) {
|
||||||
|
|
|
@ -44,13 +44,13 @@ typedef struct {
|
||||||
char (*isBoundsVisible)(void* headset);
|
char (*isBoundsVisible)(void* headset);
|
||||||
void (*setBoundsVisible)(void* headset, char visible);
|
void (*setBoundsVisible)(void* headset, char visible);
|
||||||
void (*getPosition)(void* headset, float* x, float* y, float* z);
|
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 (*getVelocity)(void* headset, float* x, float* y, float* z);
|
||||||
void (*getAngularVelocity)(void* headset, float* x, float* y, float* z);
|
void (*getAngularVelocity)(void* headset, float* x, float* y, float* z);
|
||||||
vec_controller_t* (*getControllers)(void* headset);
|
vec_controller_t* (*getControllers)(void* headset);
|
||||||
char (*controllerIsPresent)(void* headset, Controller* controller);
|
char (*controllerIsPresent)(void* headset, Controller* controller);
|
||||||
void (*controllerGetPosition)(void* headset, Controller* controller, float* x, float* y, float* z);
|
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);
|
float (*controllerGetAxis)(void* headset, Controller* controller, ControllerAxis axis);
|
||||||
int (*controllerIsDown)(void* headset, Controller* controller, ControllerButton button);
|
int (*controllerIsDown)(void* headset, Controller* controller, ControllerButton button);
|
||||||
void (*controllerVibrate)(void* headset, Controller* controller, float duration);
|
void (*controllerVibrate)(void* headset, Controller* controller, float duration);
|
||||||
|
@ -73,13 +73,13 @@ void lovrHeadsetGetBoundsGeometry(float* geometry);
|
||||||
char lovrHeadsetIsBoundsVisible();
|
char lovrHeadsetIsBoundsVisible();
|
||||||
void lovrHeadsetSetBoundsVisible(char visible);
|
void lovrHeadsetSetBoundsVisible(char visible);
|
||||||
void lovrHeadsetGetPosition(float* x, float* y, float* z);
|
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 lovrHeadsetGetVelocity(float* x, float* y, float* z);
|
||||||
void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z);
|
void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z);
|
||||||
vec_controller_t* lovrHeadsetGetControllers();
|
vec_controller_t* lovrHeadsetGetControllers();
|
||||||
char lovrHeadsetControllerIsPresent(Controller* controller);
|
char lovrHeadsetControllerIsPresent(Controller* controller);
|
||||||
void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z);
|
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);
|
float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis);
|
||||||
int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button);
|
int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button);
|
||||||
void lovrHeadsetControllerVibrate(Controller* controller, float duration);
|
void lovrHeadsetControllerVibrate(Controller* controller, float duration);
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "loaders/texture.h"
|
#include "loaders/texture.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
|
#include "math/quat.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -255,17 +257,19 @@ void viveGetPosition(void* headset, float* x, float* y, float* z) {
|
||||||
*z = pose.mDeviceToAbsoluteTracking.m[2][3];
|
*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;
|
Vive* vive = (Vive*) headset;
|
||||||
TrackedDevicePose_t pose = viveGetPose(vive, vive->headsetIndex);
|
TrackedDevicePose_t pose = viveGetPose(vive, vive->headsetIndex);
|
||||||
|
|
||||||
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
|
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
|
||||||
*w = *x = *y = *z = 0.f;
|
*angle = *x = *y = *z = 0.f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float matrix[16];
|
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) {
|
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];
|
*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;
|
Vive* vive = (Vive*) headset;
|
||||||
TrackedDevicePose_t pose = viveGetPose(vive, controller->id);
|
TrackedDevicePose_t pose = viveGetPose(vive, controller->id);
|
||||||
|
|
||||||
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
|
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
|
||||||
*w = *x = *y = *z = 0.f;
|
*angle = *x = *y = *z = 0.f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float matrix[16];
|
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) {
|
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) {
|
void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) {
|
||||||
Vive* vive = (Vive*) headset;
|
Vive* vive = (Vive*) headset;
|
||||||
float headMatrix[16], eyeMatrix[16], projectionMatrix[16];
|
float head[16], transform[16], projection[16];
|
||||||
float (*matrix)[4];
|
float (*matrix)[4];
|
||||||
|
|
||||||
lovrGraphicsPushCanvas();
|
lovrGraphicsPushCanvas();
|
||||||
|
@ -458,28 +464,27 @@ void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata)
|
||||||
|
|
||||||
// Head transform
|
// Head transform
|
||||||
matrix = vive->renderPoses[vive->headsetIndex].mDeviceToAbsoluteTracking.m;
|
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++) {
|
for (EVREye eye = EYE_LEFT; eye <= EYE_RIGHT; eye++) {
|
||||||
EVREye eye = (i == 0) ? EVREye_Eye_Left : EVREye_Eye_Right;
|
|
||||||
|
|
||||||
// Eye transform
|
// Eye transform
|
||||||
matrix = vive->system->GetEyeToHeadTransform(eye).m;
|
matrix = vive->system->GetEyeToHeadTransform(eye).m;
|
||||||
mat4_invert(mat4_fromMat34(eyeMatrix, matrix));
|
mat4_invert(mat4_fromMat34(transform, matrix));
|
||||||
mat4 transformMatrix = mat4_multiply(eyeMatrix, headMatrix);
|
mat4_multiply(transform, head);
|
||||||
|
|
||||||
// Projection
|
// Projection
|
||||||
matrix = vive->system->GetProjectionMatrix(eye, vive->clipNear, vive->clipFar).m;
|
matrix = vive->system->GetProjectionMatrix(eye, vive->clipNear, vive->clipFar).m;
|
||||||
mat4_fromMat44(projectionMatrix, matrix);
|
mat4_fromMat44(projection, matrix);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
lovrTextureBindFramebuffer(vive->texture);
|
lovrTextureBindFramebuffer(vive->texture);
|
||||||
lovrGraphicsPush();
|
lovrGraphicsPush();
|
||||||
lovrGraphicsOrigin();
|
lovrGraphicsOrigin();
|
||||||
lovrGraphicsMatrixTransform(transformMatrix);
|
lovrGraphicsMatrixTransform(transform);
|
||||||
lovrGraphicsSetProjectionRaw(projectionMatrix);
|
lovrGraphicsSetProjectionRaw(projection);
|
||||||
lovrGraphicsClear(1, 1);
|
lovrGraphicsClear(1, 1);
|
||||||
callback(i, userdata);
|
callback(eye - EYE_LEFT, userdata);
|
||||||
lovrGraphicsPop();
|
lovrGraphicsPop();
|
||||||
lovrTextureResolveMSAA(vive->texture);
|
lovrTextureResolveMSAA(vive->texture);
|
||||||
|
|
||||||
|
@ -493,6 +498,5 @@ void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata)
|
||||||
|
|
||||||
vive->isRendering = 0;
|
vive->isRendering = 0;
|
||||||
lovrGraphicsPopCanvas();
|
lovrGraphicsPopCanvas();
|
||||||
|
|
||||||
lovrGraphicsPlaneFullscreen(vive->texture);
|
lovrGraphicsPlaneFullscreen(vive->texture);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#ifndef LOVR_VIVE_TYPES
|
#ifndef LOVR_VIVE_TYPES
|
||||||
#define LOVR_VIVE_TYPES
|
#define LOVR_VIVE_TYPES
|
||||||
|
|
||||||
|
#define EYE_LEFT EVREye_Eye_Left
|
||||||
|
#define EYE_RIGHT EVREye_Eye_Right
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Headset headset;
|
Headset headset;
|
||||||
|
|
||||||
|
@ -47,14 +50,14 @@ void viveGetBoundsGeometry(void* headset, float* geometry);
|
||||||
char viveIsBoundsVisible(void* headset);
|
char viveIsBoundsVisible(void* headset);
|
||||||
void viveSetBoundsVisible(void* headset, char visible);
|
void viveSetBoundsVisible(void* headset, char visible);
|
||||||
void viveGetPosition(void* headset, float* x, float* y, float* z);
|
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 viveGetVelocity(void* headset, float* x, float* y, float* z);
|
||||||
void viveGetAngularVelocity(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);
|
Controller* viveAddController(void* headset, unsigned int deviceIndex);
|
||||||
vec_controller_t* viveGetControllers(void* headset);
|
vec_controller_t* viveGetControllers(void* headset);
|
||||||
char viveControllerIsPresent(void* headset, Controller* controller);
|
char viveControllerIsPresent(void* headset, Controller* controller);
|
||||||
void viveControllerGetPosition(void* headset, Controller* controller, float* x, float* y, float* z);
|
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);
|
float viveControllerGetAxis(void* headset, Controller* controller, ControllerAxis axis);
|
||||||
int viveControllerIsDown(void* headset, Controller* controller, ControllerButton button);
|
int viveControllerIsDown(void* headset, Controller* controller, ControllerButton button);
|
||||||
void viveControllerVibrate(void* headset, Controller* controller, float duration);
|
void viveControllerVibrate(void* headset, Controller* controller, float duration);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "loaders/model.h"
|
#include "loaders/model.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
#include <assimp/cimport.h>
|
#include <assimp/cimport.h>
|
||||||
|
@ -9,7 +10,7 @@ static void assimpNodeTraversal(ModelNode* node, struct aiNode* assimpNode) {
|
||||||
// Transform
|
// Transform
|
||||||
struct aiMatrix4x4 m = assimpNode->mTransformation;
|
struct aiMatrix4x4 m = assimpNode->mTransformation;
|
||||||
aiTransposeMatrix4(&m);
|
aiTransposeMatrix4(&m);
|
||||||
node->transform = mat4_copy((float*) &m);
|
mat4_set(node->transform, (float*) &m);
|
||||||
|
|
||||||
// Meshes
|
// Meshes
|
||||||
vec_init(&node->meshes);
|
vec_init(&node->meshes);
|
||||||
|
@ -148,7 +149,6 @@ ModelData* lovrModelDataFromOpenVRModel(OpenVRModel* vrModel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelNode* root = malloc(sizeof(ModelNode));
|
ModelNode* root = malloc(sizeof(ModelNode));
|
||||||
root->transform = mat4_init();
|
|
||||||
vec_init(&root->meshes);
|
vec_init(&root->meshes);
|
||||||
vec_push(&root->meshes, 0);
|
vec_push(&root->meshes, 0);
|
||||||
vec_init(&root->children);
|
vec_init(&root->children);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "lovr/filesystem.h"
|
#include "lovr/filesystem.h"
|
||||||
#include "lovr/graphics.h"
|
#include "lovr/graphics.h"
|
||||||
#include "lovr/headset.h"
|
#include "lovr/headset.h"
|
||||||
|
#include "lovr/math.h"
|
||||||
#include "lovr/timer.h"
|
#include "lovr/timer.h"
|
||||||
#include "glfw.h"
|
#include "glfw.h"
|
||||||
#include "util.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.filesystem", l_lovrFilesystemInit);
|
||||||
luax_preloadmodule(L, "lovr.graphics", l_lovrGraphicsInit);
|
luax_preloadmodule(L, "lovr.graphics", l_lovrGraphicsInit);
|
||||||
luax_preloadmodule(L, "lovr.headset", l_lovrHeadsetInit);
|
luax_preloadmodule(L, "lovr.headset", l_lovrHeadsetInit);
|
||||||
|
luax_preloadmodule(L, "lovr.math", l_lovrMathInit);
|
||||||
luax_preloadmodule(L, "lovr.timer", l_lovrTimerInit);
|
luax_preloadmodule(L, "lovr.timer", l_lovrTimerInit);
|
||||||
|
|
||||||
// Bootstrap
|
// Bootstrap
|
||||||
|
@ -73,6 +75,7 @@ void lovrInit(lua_State* L, int argc, char** argv) {
|
||||||
" event = true, "
|
" event = true, "
|
||||||
" graphics = true, "
|
" graphics = true, "
|
||||||
" headset = true, "
|
" headset = true, "
|
||||||
|
" math = true, "
|
||||||
" timer = true "
|
" timer = true "
|
||||||
" } "
|
" } "
|
||||||
"} "
|
"} "
|
||||||
|
@ -88,7 +91,7 @@ void lovrInit(lua_State* L, int argc, char** argv) {
|
||||||
" success, err = pcall(lovr.conf, conf) "
|
" success, err = pcall(lovr.conf, conf) "
|
||||||
"end "
|
"end "
|
||||||
|
|
||||||
"local modules = { 'audio', 'event', 'graphics', 'headset', 'timer' } "
|
"local modules = { 'audio', 'event', 'graphics', 'headset', 'math', 'timer' } "
|
||||||
"for _, module in ipairs(modules) do "
|
"for _, module in ipairs(modules) do "
|
||||||
" if conf.modules[module] then "
|
" if conf.modules[module] then "
|
||||||
" lovr[module] = require('lovr.' .. module) "
|
" lovr[module] = require('lovr.' .. module) "
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
static int pollRef;
|
||||||
|
|
||||||
static int nextEvent(lua_State* L) {
|
static int nextEvent(lua_State* L) {
|
||||||
Event* event = lovrEventPoll();
|
Event* event = lovrEventPoll();
|
||||||
|
|
||||||
|
@ -44,6 +46,11 @@ const luaL_Reg lovrEvent[] = {
|
||||||
int l_lovrEventInit(lua_State* L) {
|
int l_lovrEventInit(lua_State* L) {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
luaL_register(L, NULL, lovrEvent);
|
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_init(&EventTypes);
|
||||||
map_set(&EventTypes, "quit", EVENT_QUIT);
|
map_set(&EventTypes, "quit", EVENT_QUIT);
|
||||||
lovrEventInit();
|
lovrEventInit();
|
||||||
|
@ -56,7 +63,7 @@ int l_lovrEventClear(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrEventPoll(lua_State* L) {
|
int l_lovrEventPoll(lua_State* L) {
|
||||||
lua_pushcclosure(L, nextEvent, 0);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, pollRef);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "lovr/types/shader.h"
|
#include "lovr/types/shader.h"
|
||||||
#include "lovr/types/skybox.h"
|
#include "lovr/types/skybox.h"
|
||||||
#include "lovr/types/texture.h"
|
#include "lovr/types/texture.h"
|
||||||
|
#include "lovr/types/transform.h"
|
||||||
#include "graphics/graphics.h"
|
#include "graphics/graphics.h"
|
||||||
#include "loaders/model.h"
|
#include "loaders/model.h"
|
||||||
#include "loaders/texture.h"
|
#include "loaders/texture.h"
|
||||||
|
@ -74,6 +75,7 @@ const luaL_Reg lovrGraphics[] = {
|
||||||
{ "translate", l_lovrGraphicsTranslate },
|
{ "translate", l_lovrGraphicsTranslate },
|
||||||
{ "rotate", l_lovrGraphicsRotate },
|
{ "rotate", l_lovrGraphicsRotate },
|
||||||
{ "scale", l_lovrGraphicsScale },
|
{ "scale", l_lovrGraphicsScale },
|
||||||
|
{ "transform", l_lovrGraphicsTransform },
|
||||||
{ "points", l_lovrGraphicsPoints },
|
{ "points", l_lovrGraphicsPoints },
|
||||||
{ "line", l_lovrGraphicsLine },
|
{ "line", l_lovrGraphicsLine },
|
||||||
{ "triangle", l_lovrGraphicsTriangle },
|
{ "triangle", l_lovrGraphicsTriangle },
|
||||||
|
@ -442,6 +444,13 @@ int l_lovrGraphicsScale(lua_State* L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int l_lovrGraphicsTransform(lua_State* L) {
|
||||||
|
float transform[16];
|
||||||
|
luax_readtransform(L, 1, transform);
|
||||||
|
lovrGraphicsMatrixTransform(transform);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Primitives
|
// Primitives
|
||||||
|
|
||||||
int l_lovrGraphicsPoints(lua_State* L) {
|
int l_lovrGraphicsPoints(lua_State* L) {
|
||||||
|
@ -509,15 +518,9 @@ int l_lovrGraphicsCube(lua_State* L) {
|
||||||
drawMode = DRAW_MODE_FILL;
|
drawMode = DRAW_MODE_FILL;
|
||||||
texture = luax_checktype(L, 1, Texture);
|
texture = luax_checktype(L, 1, Texture);
|
||||||
}
|
}
|
||||||
float x = luaL_optnumber(L, 2, 0.f);
|
float transform[16];
|
||||||
float y = luaL_optnumber(L, 3, 0.f);
|
luax_readtransform(L, 2, transform);
|
||||||
float z = luaL_optnumber(L, 4, 0.f);
|
lovrGraphicsCube(drawMode, texture, transform);
|
||||||
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);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ int l_lovrGraphicsOrigin(lua_State* L);
|
||||||
int l_lovrGraphicsTranslate(lua_State* L);
|
int l_lovrGraphicsTranslate(lua_State* L);
|
||||||
int l_lovrGraphicsRotate(lua_State* L);
|
int l_lovrGraphicsRotate(lua_State* L);
|
||||||
int l_lovrGraphicsScale(lua_State* L);
|
int l_lovrGraphicsScale(lua_State* L);
|
||||||
|
int l_lovrGraphicsTransform(lua_State* L);
|
||||||
|
|
||||||
// Primitives
|
// Primitives
|
||||||
int l_lovrGraphicsPoints(lua_State* L);
|
int l_lovrGraphicsPoints(lua_State* L);
|
||||||
|
|
|
@ -155,9 +155,9 @@ int l_lovrHeadsetGetPosition(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrHeadsetGetOrientation(lua_State* L) {
|
int l_lovrHeadsetGetOrientation(lua_State* L) {
|
||||||
float w, x, y, z;
|
float angle, x, y, z;
|
||||||
lovrHeadsetGetOrientation(&w, &x, &y, &z);
|
lovrHeadsetGetOrientation(&angle, &x, &y, &z);
|
||||||
lua_pushnumber(L, w);
|
lua_pushnumber(L, angle);
|
||||||
lua_pushnumber(L, x);
|
lua_pushnumber(L, x);
|
||||||
lua_pushnumber(L, y);
|
lua_pushnumber(L, y);
|
||||||
lua_pushnumber(L, z);
|
lua_pushnumber(L, z);
|
||||||
|
|
23
src/lovr/math.c
Normal file
23
src/lovr/math.c
Normal 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
7
src/lovr/math.h
Normal 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);
|
|
@ -34,9 +34,9 @@ int l_lovrControllerGetPosition(lua_State* L) {
|
||||||
|
|
||||||
int l_lovrControllerGetOrientation(lua_State* L) {
|
int l_lovrControllerGetOrientation(lua_State* L) {
|
||||||
Controller* controller = luax_checktype(L, 1, Controller);
|
Controller* controller = luax_checktype(L, 1, Controller);
|
||||||
float w, x, y, z;
|
float angle, x, y, z;
|
||||||
lovrHeadsetControllerGetOrientation(controller, &w, &x, &y, &z);
|
lovrHeadsetControllerGetOrientation(controller, &angle, &x, &y, &z);
|
||||||
lua_pushnumber(L, w);
|
lua_pushnumber(L, angle);
|
||||||
lua_pushnumber(L, x);
|
lua_pushnumber(L, x);
|
||||||
lua_pushnumber(L, y);
|
lua_pushnumber(L, y);
|
||||||
lua_pushnumber(L, z);
|
lua_pushnumber(L, z);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "lovr/types/model.h"
|
#include "lovr/types/model.h"
|
||||||
#include "lovr/types/texture.h"
|
#include "lovr/types/texture.h"
|
||||||
|
#include "lovr/types/transform.h"
|
||||||
|
|
||||||
const luaL_Reg lovrModel[] = {
|
const luaL_Reg lovrModel[] = {
|
||||||
{ "draw", l_lovrModelDraw },
|
{ "draw", l_lovrModelDraw },
|
||||||
|
@ -10,15 +11,9 @@ const luaL_Reg lovrModel[] = {
|
||||||
|
|
||||||
int l_lovrModelDraw(lua_State* L) {
|
int l_lovrModelDraw(lua_State* L) {
|
||||||
Model* model = luax_checktype(L, 1, Model);
|
Model* model = luax_checktype(L, 1, Model);
|
||||||
float x = luaL_optnumber(L, 2, 0.f);
|
float transform[16];
|
||||||
float y = luaL_optnumber(L, 3, 0.f);
|
luax_readtransform(L, 2, transform);
|
||||||
float z = luaL_optnumber(L, 4, 0.f);
|
lovrModelDraw(model, transform);
|
||||||
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);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
129
src/lovr/types/transform.c
Normal file
129
src/lovr/types/transform.c
Normal 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;
|
||||||
|
}
|
19
src/lovr/types/transform.h
Normal file
19
src/lovr/types/transform.h
Normal 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
235
src/math/mat4.c
Normal 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
17
src/math/mat4.h
Normal 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
9
src/math/math.h
Normal 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
98
src/math/quat.c
Normal 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
10
src/math/quat.h
Normal 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
64
src/math/transform.c
Normal 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
23
src/math/transform.h
Normal 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
49
src/math/vec3.c
Normal 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
10
src/math/vec3.h
Normal 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);
|
276
src/matrix.c
276
src/matrix.c
|
@ -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;
|
|
||||||
}
|
|
26
src/matrix.h
26
src/matrix.h
|
@ -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);
|
|
Loading…
Reference in a new issue