mirror of https://github.com/bjornbytes/lovr.git
Mat4;
This commit is contained in:
parent
40e2d2bf2b
commit
cdf6063355
|
@ -538,7 +538,7 @@ if(LOVR_ENABLE_MATH)
|
|||
src/api/l_math.c
|
||||
src/api/l_math_curve.c
|
||||
src/api/l_math_randomGenerator.c
|
||||
src/api/l_math_vectors.c
|
||||
src/api/l_math_mat4.c
|
||||
src/lib/noise/simplexnoise1234.c
|
||||
)
|
||||
else()
|
||||
|
|
|
@ -177,7 +177,6 @@ function lovr.run()
|
|||
lovr.graphics.present()
|
||||
end
|
||||
if lovr.headset then lovr.headset.submit() end
|
||||
if lovr.math then lovr.math.drain() end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -255,7 +254,7 @@ function lovr.errhand(message)
|
|||
local pass = lovr.graphics.getWindowPass()
|
||||
if pass then
|
||||
local w, h = lovr.system.getWindowDimensions()
|
||||
pass:setProjection(1, lovr.math.mat4():orthographic(w, h))
|
||||
pass:setProjection(1, lovr.math.newMat4():orthographic(w, h))
|
||||
font:setPixelDensity(1)
|
||||
|
||||
local scale = .6
|
||||
|
@ -273,8 +272,6 @@ function lovr.errhand(message)
|
|||
lovr.graphics.present()
|
||||
end
|
||||
end
|
||||
|
||||
lovr.math.drain()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
116
src/api/api.c
116
src/api/api.c
|
@ -1,4 +1,6 @@
|
|||
#include "api.h"
|
||||
#include "core/maf.h"
|
||||
#include "math/math.h"
|
||||
#include "util.h"
|
||||
#include "lib/lua/lutf8lib.h"
|
||||
#include <stdlib.h>
|
||||
|
@ -600,3 +602,117 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou
|
|||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luax_pushvec3(lua_State* L, float* v) {
|
||||
lua_createtable(L, 3, 0);
|
||||
lua_pushnumber(L, v[0]);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushnumber(L, v[1]);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushnumber(L, v[2]);
|
||||
lua_rawseti(L, -2, 3);
|
||||
luaL_newmetatable(L, "vec3");
|
||||
return lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
int luax_readvec3(lua_State* L, int index, vec3 v, const char* expected) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
v[0] = v[1] = v[2] = 0.f;
|
||||
return index + 1;
|
||||
case LUA_TNUMBER:
|
||||
v[0] = luax_tofloat(L, index);
|
||||
v[1] = luax_optfloat(L, index + 1, v[0]);
|
||||
v[2] = luax_optfloat(L, index + 2, v[0]);
|
||||
return index + 3;
|
||||
case LUA_TTABLE:
|
||||
for (int i = 0; i < 3; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
v[i] = luax_tofloat(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return index + 1;
|
||||
default: return luax_typeerror(L, index, "table or number");
|
||||
}
|
||||
}
|
||||
|
||||
int luax_readscale(lua_State* L, int index, vec3 v, int components, const char* expected) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
v[0] = v[1] = v[2] = 1.f;
|
||||
return index + components;
|
||||
case LUA_TNUMBER:
|
||||
if (components == 1) {
|
||||
v[0] = v[1] = v[2] = luax_tofloat(L, index);
|
||||
} else if (components == -2) { // -2 is special and means "2 components: xy and z"
|
||||
v[0] = v[1] = luax_tofloat(L, index);
|
||||
v[2] = luax_optfloat(L, index, 1.f);
|
||||
} else {
|
||||
v[0] = v[1] = v[2] = 1.f;
|
||||
for (int i = 0; i < components; i++) {
|
||||
v[i] = luax_optfloat(L, index + i, v[0]);
|
||||
}
|
||||
}
|
||||
return index + components;
|
||||
case LUA_TTABLE:
|
||||
v[0] = 1.f;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
v[i] = luax_optfloat(L, -1, v[0]);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return index + 1;
|
||||
default: return luax_typeerror(L, index, "table or number");
|
||||
}
|
||||
}
|
||||
|
||||
int luax_readquat(lua_State* L, int index, quat q, const char* expected) {
|
||||
float angle, ax, ay, az;
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
quat_identity(q);
|
||||
return index + 1;
|
||||
case LUA_TNUMBER:
|
||||
angle = luax_optfloat(L, index, 0.f);
|
||||
ax = luax_optfloat(L, index + 1, 0.f);
|
||||
ay = luax_optfloat(L, index + 2, 1.f);
|
||||
az = luax_optfloat(L, index + 3, 0.f);
|
||||
quat_fromAngleAxis(q, angle, ax, ay, az);
|
||||
return index + 4;
|
||||
case LUA_TTABLE:
|
||||
for (int i = 0; i < 4; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
q[i] = luax_tofloat(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return index + 1;
|
||||
default: return luax_typeerror(L, index, "table or number");
|
||||
}
|
||||
}
|
||||
|
||||
int luax_readmat4(lua_State* L, int index, mat4 m, int scaleComponents) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
mat4_identity(m);
|
||||
return index + 1;
|
||||
case LUA_TNUMBER: {
|
||||
float S[3], R[4];
|
||||
mat4_identity(m);
|
||||
index = luax_readvec3(L, index, m + 12, "table, number, or Mat4");
|
||||
index = luax_readscale(L, index, S, scaleComponents, NULL);
|
||||
index = luax_readquat(L, index, R, NULL);
|
||||
mat4_rotateQuat(m, R);
|
||||
mat4_scale(m, S[0], S[1], S[2]);
|
||||
return index;
|
||||
}
|
||||
default: {
|
||||
Mat4* matrix = luax_checktype(L, index, Mat4);
|
||||
mat4_init(m, lovrMat4GetPointer(matrix));
|
||||
return index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,6 +133,11 @@ uint32_t _luax_optu32(lua_State* L, int index, uint32_t fallback);
|
|||
void luax_readcolor(lua_State* L, int index, float color[4]);
|
||||
void luax_optcolor(lua_State* L, int index, float color[4]);
|
||||
int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCount, uint32_t** indices, uint32_t* indexCount, bool* shouldFree);
|
||||
int luax_pushvec3(lua_State* L, float* v);
|
||||
int luax_readvec3(lua_State* L, int index, float* v, const char* expected);
|
||||
int luax_readscale(lua_State* L, int index, float* v, int components, const char* expected);
|
||||
int luax_readquat(lua_State* L, int index, float* q, const char* expected);
|
||||
int luax_readmat4(lua_State* L, int index, float* m, int scaleComponents);
|
||||
|
||||
// Module helpers
|
||||
|
||||
|
@ -173,14 +178,6 @@ struct ColoredString* luax_checkcoloredstrings(lua_State* L, int index, uint32_t
|
|||
#endif
|
||||
|
||||
#ifndef LOVR_DISABLE_MATH
|
||||
#include "math/math.h" // TODO
|
||||
float* luax_tovector(lua_State* L, int index, VectorType* type);
|
||||
float* luax_checkvector(lua_State* L, int index, VectorType type, const char* expected);
|
||||
float* luax_newtempvector(lua_State* L, VectorType type);
|
||||
int luax_readvec3(lua_State* L, int index, float* v, const char* expected);
|
||||
int luax_readscale(lua_State* L, int index, float* v, int components, const char* expected);
|
||||
int luax_readquat(lua_State* L, int index, float* q, const char* expected);
|
||||
int luax_readmat4(lua_State* L, int index, float* m, int scaleComponents);
|
||||
uint64_t luax_checkrandomseed(lua_State* L, int index);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -83,32 +83,13 @@ void luax_checkvariant(lua_State* L, int index, Variant* variant) {
|
|||
lua_pop(L, 1);
|
||||
break;
|
||||
} else {
|
||||
lua_pop(L, 2);
|
||||
lovrThrow("Variant userdata is not a LÖVR object!");
|
||||
}
|
||||
/* fallthrough */
|
||||
|
||||
case LUA_TLIGHTUSERDATA: {
|
||||
VectorType type;
|
||||
float* v = luax_tovector(L, index, &type);
|
||||
if (v) {
|
||||
if (type == V_MAT4) {
|
||||
variant->type = TYPE_MATRIX;
|
||||
variant->value.matrix.data = lovrMalloc(16 * sizeof(float));
|
||||
memcpy(variant->value.matrix.data, v, 16 * sizeof(float));
|
||||
break;
|
||||
} else {
|
||||
variant->type = TYPE_VECTOR;
|
||||
variant->value.vector.type = type;
|
||||
memcpy(variant->value.vector.data, v, 4 * sizeof(float));
|
||||
break;
|
||||
}
|
||||
} else if (lua_type(L, index) == LUA_TLIGHTUSERDATA) {
|
||||
variant->type = TYPE_POINTER;
|
||||
variant->value.pointer = lua_touserdata(L, index);
|
||||
break;
|
||||
}
|
||||
lovrThrow("Bad userdata variant for argument %d (expected object, vector, or lightuserdata)", index);
|
||||
}
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
variant->type = TYPE_POINTER;
|
||||
variant->value.pointer = lua_touserdata(L, index);
|
||||
break;
|
||||
|
||||
default:
|
||||
lovrThrow("Bad variant type for argument %d: %s", index, lua_typename(L, type));
|
||||
|
@ -125,8 +106,6 @@ int luax_pushvariant(lua_State* L, Variant* variant) {
|
|||
case TYPE_MINISTRING: lua_pushlstring(L, variant->value.ministring.data, variant->value.ministring.length); return 1;
|
||||
case TYPE_POINTER: lua_pushlightuserdata(L, variant->value.pointer); return 1;
|
||||
case TYPE_OBJECT: _luax_pushtype(L, variant->value.object.type, hash64(variant->value.object.type, strlen(variant->value.object.type)), variant->value.object.pointer); return 1;
|
||||
case TYPE_VECTOR: memcpy(luax_newtempvector(L, variant->value.vector.type), variant->value.vector.data, 4 * sizeof(float)); return 1;
|
||||
case TYPE_MATRIX: memcpy(luax_newtempvector(L, V_MAT4), variant->value.vector.data, 16 * sizeof(float)); return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "data/image.h"
|
||||
#include "data/modelData.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "math/math.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -736,7 +737,7 @@ static int l_lovrGraphicsNewBuffer(lua_State* L) {
|
|||
info.size = (uint32_t) blob->size;
|
||||
format->length = info.size / format->stride;
|
||||
break;
|
||||
} else if (luax_tovector(L, 2, NULL)) {
|
||||
} else if (luax_totype(L, 2, Mat4)) {
|
||||
format->length = 0;
|
||||
hasData = true;
|
||||
break;
|
||||
|
|
|
@ -43,10 +43,6 @@ static const uint32_t typeComponents[] = {
|
|||
[TYPE_INDEX32] = 1
|
||||
};
|
||||
|
||||
static const uint32_t vectorComponents[] = {
|
||||
[V_MAT4] = 16
|
||||
};
|
||||
|
||||
typedef union {
|
||||
void* raw;
|
||||
int8_t* i8;
|
||||
|
@ -160,47 +156,7 @@ static void luax_checkfieldn(lua_State* L, int index, const DataField* field, vo
|
|||
}
|
||||
|
||||
static void luax_checkfieldv(lua_State* L, int index, const DataField* field, void* data) {
|
||||
DataPointer p = { .raw = data };
|
||||
VectorType vectorType;
|
||||
float* v = luax_tovector(L, index, &vectorType);
|
||||
uint32_t n = typeComponents[field->type];
|
||||
luax_fieldcheck(L, v && n > 1, index, field, false);
|
||||
if (field->type >= TYPE_MAT2 && field->type <= TYPE_MAT4) {
|
||||
lovrCheck(vectorType == V_MAT4, "Tried to send a non-matrix to a matrix type");
|
||||
} else {
|
||||
lovrCheck(vectorComponents[vectorType] == n, "Expected %d vector components, got %d", n, vectorComponents[vectorType]);
|
||||
}
|
||||
switch (field->type) {
|
||||
case TYPE_I8x4: for (int i = 0; i < 4; i++) p.i8[i] = (int8_t) v[i]; break;
|
||||
case TYPE_U8x4: for (int i = 0; i < 4; i++) p.u8[i] = (uint8_t) v[i]; break;
|
||||
case TYPE_SN8x4: for (int i = 0; i < 4; i++) p.i8[i] = (int8_t) CLAMP(v[i], -1.f, 1.f) * INT8_MAX; break;
|
||||
case TYPE_UN8x4: for (int i = 0; i < 4; i++) p.u8[i] = (uint8_t) CLAMP(v[i], 0.f, 1.f) * UINT8_MAX; break;
|
||||
case TYPE_SN10x3: for (int i = 0; i < 3; i++) p.u32[0] |= (((uint32_t) (int32_t) (CLAMP(v[i], -1.f, 1.f) * 511.f)) & 0x3ff) << (10 * i); break;
|
||||
case TYPE_UN10x3: for (int i = 0; i < 3; i++) p.u32[0] |= (((uint32_t) (CLAMP(v[i], 0.f, 1.f) * 1023.f)) & 0x3ff) << (10 * i); break;
|
||||
case TYPE_I16x2: for (int i = 0; i < 2; i++) p.i16[i] = (int16_t) v[i]; break;
|
||||
case TYPE_I16x4: for (int i = 0; i < 4; i++) p.i16[i] = (int16_t) v[i]; break;
|
||||
case TYPE_U16x2: for (int i = 0; i < 2; i++) p.u16[i] = (uint16_t) v[i]; break;
|
||||
case TYPE_U16x4: for (int i = 0; i < 4; i++) p.u16[i] = (uint16_t) v[i]; break;
|
||||
case TYPE_SN16x2: for (int i = 0; i < 2; i++) p.i16[i] = (int16_t) CLAMP(v[i], -1.f, 1.f) * INT16_MAX; break;
|
||||
case TYPE_SN16x4: for (int i = 0; i < 4; i++) p.i16[i] = (int16_t) CLAMP(v[i], -1.f, 1.f) * INT16_MAX; break;
|
||||
case TYPE_UN16x2: for (int i = 0; i < 2; i++) p.u16[i] = (uint16_t) CLAMP(v[i], 0.f, 1.f) * UINT16_MAX; break;
|
||||
case TYPE_UN16x4: for (int i = 0; i < 4; i++) p.u16[i] = (uint16_t) CLAMP(v[i], 0.f, 1.f) * UINT16_MAX; break;
|
||||
case TYPE_I32x2: for (int i = 0; i < 2; i++) p.i32[i] = (int32_t) v[i]; break;
|
||||
case TYPE_I32x3: for (int i = 0; i < 3; i++) p.i32[i] = (int32_t) v[i]; break;
|
||||
case TYPE_I32x4: for (int i = 0; i < 4; i++) p.i32[i] = (int32_t) v[i]; break;
|
||||
case TYPE_U32x2: for (int i = 0; i < 2; i++) p.u32[i] = (uint32_t) v[i]; break;
|
||||
case TYPE_U32x3: for (int i = 0; i < 3; i++) p.u32[i] = (uint32_t) v[i]; break;
|
||||
case TYPE_U32x4: for (int i = 0; i < 4; i++) p.u32[i] = (uint32_t) v[i]; break;
|
||||
case TYPE_F16x2: for (int i = 0; i < 2; i++) p.u16[i] = float32to16(v[i]); break;
|
||||
case TYPE_F16x4: for (int i = 0; i < 4; i++) p.u16[i] = float32to16(v[i]); break;
|
||||
case TYPE_F32x2: memcpy(data, v, 2 * sizeof(float)); break;
|
||||
case TYPE_F32x3: memcpy(data, v, 3 * sizeof(float)); break;
|
||||
case TYPE_F32x4: memcpy(data, v, 4 * sizeof(float)); break;
|
||||
case TYPE_MAT2: for (int i = 0; i < 2; i++) memcpy(p.f32 + 2 * i, v + 4 * i, 2 * sizeof(float)); break;
|
||||
case TYPE_MAT3: for (int i = 0; i < 3; i++) memcpy(p.f32 + 4 * i, v + 4 * i, 3 * sizeof(float)); break;
|
||||
case TYPE_MAT4: memcpy(data, v, 16 * sizeof(float)); break;
|
||||
default: lovrUnreachable();
|
||||
}
|
||||
lovrThrow("TODO");
|
||||
}
|
||||
|
||||
static void luax_checkfieldt(lua_State* L, int index, const DataField* field, void* data) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "api.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "data/modelData.h"
|
||||
#include "math/math.h"
|
||||
#include "core/maf.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -198,13 +199,12 @@ static int l_lovrModelSetNodeTransform(lua_State* L) {
|
|||
Model* model = luax_checktype(L, 1, Model);
|
||||
uint32_t node = luax_checknodeindex(L, 2, lovrModelGetInfo(model)->data);
|
||||
int index = 3;
|
||||
VectorType type;
|
||||
float position[3], scale[3], rotation[4];
|
||||
float* m = luax_tovector(L, index, &type);
|
||||
if (m && type == V_MAT4) {
|
||||
mat4_getPosition(m, position);
|
||||
mat4_getScale(m, scale);
|
||||
mat4_getOrientation(m, rotation);
|
||||
Mat4* matrix = luax_totype(L, index, Mat4);
|
||||
if (matrix) {
|
||||
lovrMat4GetPosition(matrix, position);
|
||||
lovrMat4GetOrientation(matrix, rotation);
|
||||
lovrMat4GetScale(matrix, scale);
|
||||
index = 4;
|
||||
} else {
|
||||
index = luax_readvec3(L, index, position, NULL);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "graphics/graphics.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/image.h"
|
||||
#include "math/math.h"
|
||||
#include "core/maf.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
|
@ -233,10 +234,11 @@ static int l_lovrPassGetViewPose(lua_State* L) {
|
|||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
if (lua_gettop(L) > 2) {
|
||||
float* matrix = luax_checkvector(L, 3, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 3, Mat4);
|
||||
bool invert = lua_toboolean(L, 4);
|
||||
lovrPassGetViewMatrix(pass, view, matrix);
|
||||
if (!invert) mat4_invert(matrix);
|
||||
float* m = lovrMat4GetPointer(matrix);
|
||||
lovrPassGetViewMatrix(pass, view, m);
|
||||
if (!invert) mat4_invert(m);
|
||||
lua_settop(L, 3);
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -258,14 +260,13 @@ static int l_lovrPassGetViewPose(lua_State* L) {
|
|||
static int l_lovrPassSetViewPose(lua_State* L) {
|
||||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
VectorType type;
|
||||
float* p = luax_tovector(L, 3, &type);
|
||||
if (p && type == V_MAT4) {
|
||||
float matrix[16];
|
||||
mat4_init(matrix, p);
|
||||
Mat4* matrix = luax_totype(L, 3, Mat4);
|
||||
if (matrix) {
|
||||
float m[16];
|
||||
mat4_init(m, lovrMat4GetPointer(matrix));
|
||||
bool inverted = lua_toboolean(L, 4);
|
||||
if (!inverted) mat4_invert(matrix);
|
||||
lovrPassSetViewMatrix(pass, view, matrix);
|
||||
if (!inverted) mat4_invert(m);
|
||||
lovrPassSetViewMatrix(pass, view, m);
|
||||
} else {
|
||||
int index = 3;
|
||||
float position[3], orientation[4], matrix[16];
|
||||
|
@ -282,8 +283,9 @@ static int l_lovrPassGetProjection(lua_State* L) {
|
|||
Pass* pass = luax_checktype(L, 1, Pass);
|
||||
uint32_t view = luaL_checkinteger(L, 2) - 1;
|
||||
if (lua_gettop(L) > 2) {
|
||||
float* matrix = luax_checkvector(L, 3, V_MAT4, NULL);
|
||||
lovrPassGetProjection(pass, view, matrix);
|
||||
Mat4* matrix = luax_checktype(L, 3, Mat4);
|
||||
float* m = lovrMat4GetPointer(matrix);
|
||||
lovrPassGetProjection(pass, view, m);
|
||||
lua_settop(L, 3);
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -312,8 +314,8 @@ static int l_lovrPassSetProjection(lua_State* L) {
|
|||
mat4_fov(matrix, left, right, up, down, clipNear, clipFar);
|
||||
lovrPassSetProjection(pass, view, matrix);
|
||||
} else {
|
||||
float* matrix = luax_checkvector(L, 3, V_MAT4, "mat4 or number");
|
||||
lovrPassSetProjection(pass, view, matrix);
|
||||
Mat4* matrix = luax_checktype(L, 3, Mat4);
|
||||
lovrPassSetProjection(pass, view, lovrMat4GetPointer(matrix));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
212
src/api/l_math.c
212
src/api/l_math.c
|
@ -2,77 +2,9 @@
|
|||
#include "math/math.h"
|
||||
#include "l_math.lua.h"
|
||||
#include "util.h"
|
||||
#include <threads.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int l_lovrRandomGeneratorRandom(lua_State* L);
|
||||
int l_lovrRandomGeneratorRandomNormal(lua_State* L);
|
||||
int l_lovrRandomGeneratorGetSeed(lua_State* L);
|
||||
int l_lovrRandomGeneratorSetSeed(lua_State* L);
|
||||
int l_lovrMat4Set(lua_State* L);
|
||||
int l_lovrMat4__metaindex(lua_State* L);
|
||||
static int l_lovrMathMat4(lua_State* L);
|
||||
extern const luaL_Reg lovrCurve[];
|
||||
extern const luaL_Reg lovrRandomGenerator[];
|
||||
extern const luaL_Reg lovrMat4[];
|
||||
|
||||
static thread_local Pool* pool;
|
||||
static thread_local int metaref[MAX_VECTOR_TYPES];
|
||||
|
||||
static struct { const char* name; lua_CFunction constructor, indexer; const luaL_Reg* api; } lovrVectorInfo[] = {
|
||||
[V_MAT4] = { "mat4", l_lovrMathMat4, l_lovrMat4__metaindex, lovrMat4 }
|
||||
};
|
||||
|
||||
static void luax_destroypool(void) {
|
||||
lovrRelease(pool, lovrPoolDestroy);
|
||||
}
|
||||
|
||||
float* luax_tovector(lua_State* L, int index, VectorType* type) {
|
||||
void* p = lua_touserdata(L, index);
|
||||
|
||||
if (p) {
|
||||
if (lua_type(L, index) == LUA_TLIGHTUSERDATA) {
|
||||
Vector v = { .pointer = p };
|
||||
if (v.handle.type > V_NONE && v.handle.type < MAX_VECTOR_TYPES) {
|
||||
if (type) *type = v.handle.type;
|
||||
return lovrPoolResolve(pool, v);
|
||||
}
|
||||
} else {
|
||||
VectorType* t = p;
|
||||
if (*t > V_NONE && *t < MAX_VECTOR_TYPES) {
|
||||
if (type) *type = *t;
|
||||
return (float*) (t + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type) *type = V_NONE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float* luax_checkvector(lua_State* L, int index, VectorType type, const char* expected) {
|
||||
VectorType t;
|
||||
float* p = luax_tovector(L, index, &t);
|
||||
if (!p || t != type) luax_typeerror(L, index, expected ? expected : lovrVectorInfo[type].name);
|
||||
return p;
|
||||
}
|
||||
|
||||
static float* luax_newvector(lua_State* L, VectorType type, size_t components) {
|
||||
VectorType* p = lua_newuserdata(L, sizeof(VectorType) + components * sizeof(float));
|
||||
*p = type;
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
|
||||
lua_setmetatable(L, -2);
|
||||
return (float*) (p + 1);
|
||||
}
|
||||
|
||||
float* luax_newtempvector(lua_State* L, VectorType type) {
|
||||
float* data;
|
||||
Vector vector = lovrPoolAllocate(pool, type, &data);
|
||||
lua_pushlightuserdata(L, vector.pointer);
|
||||
return data;
|
||||
}
|
||||
|
||||
static int l_lovrMathNewCurve(lua_State* L) {
|
||||
Curve* curve = lovrCurveCreate();
|
||||
int top = lua_gettop(L);
|
||||
|
@ -111,6 +43,15 @@ static int l_lovrMathNewCurve(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
extern int l_lovrMat4Set(lua_State* L);
|
||||
static int l_lovrMathNewMat4(lua_State* L) {
|
||||
Mat4* matrix = lovrMat4Create();
|
||||
luax_pushtype(L, Mat4, matrix);
|
||||
lua_insert(L, 1);
|
||||
lovrRelease(matrix, lovrMat4Destroy);
|
||||
return l_lovrMat4Set(L);
|
||||
}
|
||||
|
||||
static int l_lovrMathNewRandomGenerator(lua_State* L) {
|
||||
RandomGenerator* generator = lovrRandomGeneratorCreate();
|
||||
if (lua_gettop(L) > 0){
|
||||
|
@ -135,24 +76,28 @@ static int l_lovrMathNoise(lua_State* L) {
|
|||
}
|
||||
}
|
||||
|
||||
extern int l_lovrRandomGeneratorRandom(lua_State* L);
|
||||
static int l_lovrMathRandom(lua_State* L) {
|
||||
luax_pushtype(L, RandomGenerator, lovrMathGetRandomGenerator());
|
||||
lua_insert(L, 1);
|
||||
return l_lovrRandomGeneratorRandom(L);
|
||||
}
|
||||
|
||||
extern int l_lovrRandomGeneratorRandomNormal(lua_State* L);
|
||||
static int l_lovrMathRandomNormal(lua_State* L) {
|
||||
luax_pushtype(L, RandomGenerator, lovrMathGetRandomGenerator());
|
||||
lua_insert(L, 1);
|
||||
return l_lovrRandomGeneratorRandomNormal(L);
|
||||
}
|
||||
|
||||
extern int l_lovrRandomGeneratorGetSeed(lua_State* L);
|
||||
static int l_lovrMathGetRandomSeed(lua_State* L) {
|
||||
luax_pushtype(L, RandomGenerator, lovrMathGetRandomGenerator());
|
||||
lua_insert(L, 1);
|
||||
return l_lovrRandomGeneratorGetSeed(L);
|
||||
}
|
||||
|
||||
extern int l_lovrRandomGeneratorSetSeed(lua_State* L);
|
||||
static int l_lovrMathSetRandomSeed(lua_State* L) {
|
||||
luax_pushtype(L, RandomGenerator, lovrMathGetRandomGenerator());
|
||||
lua_insert(L, 1);
|
||||
|
@ -195,25 +140,9 @@ static int l_lovrMathLinearToGamma(lua_State* L) {
|
|||
}
|
||||
}
|
||||
|
||||
static int l_lovrMathNewMat4(lua_State* L) {
|
||||
luax_newvector(L, V_MAT4, 16);
|
||||
lua_insert(L, 1);
|
||||
return l_lovrMat4Set(L);
|
||||
}
|
||||
|
||||
static int l_lovrMathMat4(lua_State* L) {
|
||||
luax_newtempvector(L, V_MAT4);
|
||||
lua_replace(L, 1);
|
||||
return l_lovrMat4Set(L);
|
||||
}
|
||||
|
||||
static int l_lovrMathDrain(lua_State* L) {
|
||||
lovrPoolDrain(pool);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg lovrMath[] = {
|
||||
{ "newCurve", l_lovrMathNewCurve },
|
||||
{ "newMat4", l_lovrMathNewMat4 },
|
||||
{ "newRandomGenerator", l_lovrMathNewRandomGenerator },
|
||||
{ "noise", l_lovrMathNoise },
|
||||
{ "random", l_lovrMathRandom },
|
||||
|
@ -222,110 +151,24 @@ static const luaL_Reg lovrMath[] = {
|
|||
{ "setRandomSeed", l_lovrMathSetRandomSeed },
|
||||
{ "gammaToLinear", l_lovrMathGammaToLinear },
|
||||
{ "linearToGamma", l_lovrMathLinearToGamma },
|
||||
{ "newMat4", l_lovrMathNewMat4 },
|
||||
{ "drain", l_lovrMathDrain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static int l_lovrLightUserdata__index(lua_State* L) {
|
||||
VectorType type;
|
||||
if (!luax_tovector(L, 1, &type)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
lua_pushliteral(L, "__index");
|
||||
lua_rawget(L, -2);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_call(L, 2, 1);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrLightUserdataOp(lua_State* L) {
|
||||
VectorType type;
|
||||
if (!luax_tovector(L, lua_islightuserdata(L, 1) ? 1 : 2, &type)) {
|
||||
lua_pushliteral(L, "__tostring");
|
||||
if (lua_rawequal(L, -1, lua_upvalueindex(1))) {
|
||||
lua_pop(L, 1);
|
||||
lua_pushfstring(L, "%s: %p", lua_typename(L, lua_type(L, 1)), lua_topointer(L, 1));
|
||||
return 1;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
luaL_error(L, "Unsupported lightuserdata operator %q", lua_tostring(L, lua_upvalueindex(1)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_gettable(L, -2);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_pushvalue(L, 3);
|
||||
lua_call(L, 3, 1);
|
||||
return 1;
|
||||
}
|
||||
extern const luaL_Reg lovrCurve[];
|
||||
extern const luaL_Reg lovrRandomGenerator[];
|
||||
extern const luaL_Reg lovrMat4[];
|
||||
|
||||
int luaopen_lovr_math(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
luax_register(L, lovrMath);
|
||||
luax_registertype(L, Curve);
|
||||
luax_registertype(L, Mat4);
|
||||
luax_registertype(L, RandomGenerator);
|
||||
|
||||
for (size_t i = V_MAT4; i < MAX_VECTOR_TYPES; i++) {
|
||||
lua_newtable(L);
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushcfunction(L, lovrVectorInfo[i].constructor);
|
||||
lua_setfield(L, -2, "__call");
|
||||
lua_pushcfunction(L, lovrVectorInfo[i].indexer);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
lua_pushstring(L, lovrVectorInfo[i].name);
|
||||
lua_setfield(L, -2, "__name");
|
||||
|
||||
// lovr.math[__name] = metatable
|
||||
lua_pushstring(L, lovrVectorInfo[i].name);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, -4);
|
||||
|
||||
luax_register(L, lovrVectorInfo[i].api);
|
||||
metaref[i] = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
// Global lightuserdata metatable
|
||||
lua_pushlightuserdata(L, NULL);
|
||||
lua_newtable(L);
|
||||
lua_pushcfunction(L, l_lovrLightUserdata__index);
|
||||
lua_setfield(L, -2, "__index");
|
||||
const char* ops[] = { "__add", "__sub", "__mul", "__div", "__unm", "__len", "__tostring", "__newindex" };
|
||||
for (size_t i = 0; i < COUNTOF(ops); i++) {
|
||||
lua_pushstring(L, ops[i]);
|
||||
lua_pushcclosure(L, l_lovrLightUserdataOp, 1);
|
||||
lua_setfield(L, -2, ops[i]);
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Module
|
||||
lovrMathInit();
|
||||
luax_atexit(L, lovrMathDestroy);
|
||||
|
||||
// Each Lua state gets its own thread-local Pool
|
||||
pool = lovrPoolCreate();
|
||||
luax_atexit(L, luax_destroypool);
|
||||
|
||||
// Lua vectors
|
||||
if (!luaL_loadbuffer(L, (const char*) src_api_l_math_lua, src_api_l_math_lua_len, "@math.lua")) {
|
||||
luaL_newmetatable(L, "vec2");
|
||||
|
@ -365,20 +208,6 @@ int luaopen_lovr_math(lua_State* L) {
|
|||
if (lua_istable(L, -1)) {
|
||||
lua_getfield(L, -1, "globals");
|
||||
if (lua_toboolean(L, -1)) {
|
||||
for (size_t i = V_MAT4; i < MAX_VECTOR_TYPES; i++) {
|
||||
lua_getfield(L, -4, lovrVectorInfo[i].name);
|
||||
lua_setglobal(L, lovrVectorInfo[i].name);
|
||||
|
||||
// Capitalized global is permanent vector constructor
|
||||
char constructor[8];
|
||||
memcpy(constructor, "new", 3);
|
||||
memcpy(constructor + 3, lovrVectorInfo[i].name, 4);
|
||||
constructor[3] -= 32;
|
||||
constructor[7] = '\0';
|
||||
lua_getfield(L, -4, constructor);
|
||||
lua_setglobal(L, constructor + 3);
|
||||
}
|
||||
|
||||
lua_getfield(L, -4, "vec2");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, "vec2");
|
||||
|
@ -398,6 +227,11 @@ int luaopen_lovr_math(lua_State* L) {
|
|||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, "quat");
|
||||
lua_setglobal(L, "Quat");
|
||||
|
||||
lua_getfield(L, -4, "newMat4");
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setglobal(L, "mat4");
|
||||
lua_setglobal(L, "Mat4");
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
local vec2, vec3, vec4, quat = ...
|
||||
|
||||
local function ismat4(m)
|
||||
return type(m) == 'table' and m.type and m:type() == 'Mat4'
|
||||
end
|
||||
|
||||
local EQ_THRESHOLD = 1e-10
|
||||
|
||||
----------------
|
||||
|
@ -305,7 +309,7 @@ function vec3.set(v, x, y, z)
|
|||
elseif x == nil or type(x) == 'number' then
|
||||
x = x or 0
|
||||
v[1], v[2], v[3] = x, y or x, z or x
|
||||
elseif type(x) == 'userdata' and x.type and x:type() == 'Mat4' then
|
||||
elseif ismat4(x) then
|
||||
v[1], v[2], v[3] = x:getPosition()
|
||||
end
|
||||
return v
|
||||
|
@ -700,7 +704,7 @@ function quat.set(q, x, y, z, w, raw)
|
|||
else
|
||||
q[1], q[2], q[3], q[4] = quat_between(vec3.forward, x)
|
||||
end
|
||||
elseif type(x) == 'userdata' and x.type and x:type() == 'Mat4' then
|
||||
elseif ismat4(x) then
|
||||
q[1], q[2], q[3], q[4] = quat_fromAngleAxis(x:getOrientation())
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "api.h"
|
||||
#include "math/math.h"
|
||||
#include "util.h"
|
||||
|
||||
static int l_lovrCurveEvaluate(lua_State* L) {
|
||||
|
|
|
@ -1,167 +1,31 @@
|
|||
#include "api.h"
|
||||
#include "math/math.h"
|
||||
#include "core/maf.h"
|
||||
|
||||
// Helpers
|
||||
|
||||
static int luax_pushvec3(lua_State* L, float* v) {
|
||||
lua_createtable(L, 3, 0);
|
||||
lua_pushnumber(L, v[0]);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushnumber(L, v[1]);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushnumber(L, v[2]);
|
||||
lua_rawseti(L, -2, 3);
|
||||
luaL_newmetatable(L, "vec3");
|
||||
return lua_setmetatable(L, -2);
|
||||
}
|
||||
|
||||
int luax_readvec3(lua_State* L, int index, vec3 v, const char* expected) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
v[0] = v[1] = v[2] = 0.f;
|
||||
return index + 1;
|
||||
case LUA_TNUMBER:
|
||||
v[0] = luax_tofloat(L, index);
|
||||
v[1] = luax_optfloat(L, index + 1, v[0]);
|
||||
v[2] = luax_optfloat(L, index + 2, v[0]);
|
||||
return index + 3;
|
||||
case LUA_TTABLE:
|
||||
for (int i = 0; i < 3; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
v[i] = luax_tofloat(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return index + 1;
|
||||
default: return luax_typeerror(L, index, "table or number");
|
||||
}
|
||||
}
|
||||
|
||||
int luax_readscale(lua_State* L, int index, vec3 v, int components, const char* expected) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
v[0] = v[1] = v[2] = 1.f;
|
||||
return index + components;
|
||||
case LUA_TNUMBER:
|
||||
if (components == 1) {
|
||||
v[0] = v[1] = v[2] = luax_tofloat(L, index);
|
||||
} else if (components == -2) { // -2 is special and means "2 components: xy and z"
|
||||
v[0] = v[1] = luax_tofloat(L, index);
|
||||
v[2] = luax_optfloat(L, index, 1.f);
|
||||
} else {
|
||||
v[0] = v[1] = v[2] = 1.f;
|
||||
for (int i = 0; i < components; i++) {
|
||||
v[i] = luax_optfloat(L, index + i, v[0]);
|
||||
}
|
||||
}
|
||||
return index + components;
|
||||
case LUA_TTABLE:
|
||||
v[0] = 1.f;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
v[i] = luax_optfloat(L, -1, v[0]);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return index + 1;
|
||||
default: return luax_typeerror(L, index, "table or number");
|
||||
}
|
||||
}
|
||||
|
||||
int luax_readquat(lua_State* L, int index, quat q, const char* expected) {
|
||||
float angle, ax, ay, az;
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
quat_identity(q);
|
||||
return index + 1;
|
||||
case LUA_TNUMBER:
|
||||
angle = luax_optfloat(L, index, 0.f);
|
||||
ax = luax_optfloat(L, index + 1, 0.f);
|
||||
ay = luax_optfloat(L, index + 2, 1.f);
|
||||
az = luax_optfloat(L, index + 3, 0.f);
|
||||
quat_fromAngleAxis(q, angle, ax, ay, az);
|
||||
return index + 4;
|
||||
case LUA_TTABLE:
|
||||
for (int i = 0; i < 4; i++) {
|
||||
lua_rawgeti(L, index, i + 1);
|
||||
q[i] = luax_tofloat(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return index + 1;
|
||||
default: return luax_typeerror(L, index, "table or number");
|
||||
}
|
||||
}
|
||||
|
||||
int luax_readmat4(lua_State* L, int index, mat4 m, int scaleComponents) {
|
||||
switch (lua_type(L, index)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNONE:
|
||||
mat4_identity(m);
|
||||
return index + 1;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
case LUA_TUSERDATA:
|
||||
default: {
|
||||
VectorType type;
|
||||
float* p = luax_tovector(L, index, &type);
|
||||
if (type == V_MAT4) {
|
||||
mat4_init(m, p);
|
||||
return index + 1;
|
||||
}
|
||||
} // Fall through
|
||||
|
||||
case LUA_TNUMBER: {
|
||||
float S[3];
|
||||
float R[4];
|
||||
mat4_identity(m);
|
||||
index = luax_readvec3(L, index, m + 12, "mat4, vec3, or number");
|
||||
index = luax_readscale(L, index, S, scaleComponents, NULL);
|
||||
index = luax_readquat(L, index, R, NULL);
|
||||
mat4_rotateQuat(m, R);
|
||||
mat4_scale(m, S[0], S[1], S[2]);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "util.h"
|
||||
|
||||
// mat4
|
||||
|
||||
static int l_lovrMat4Type(lua_State* L) {
|
||||
lua_pushliteral(L, "Mat4");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Equals(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 n = luax_checkvector(L, 2, V_MAT4, NULL);
|
||||
for (int i = 0; i < 16; i += 4) {
|
||||
float dx = m[i + 0] - n[i + 0];
|
||||
float dy = m[i + 1] - n[i + 1];
|
||||
float dz = m[i + 2] - n[i + 2];
|
||||
float dw = m[i + 3] - n[i + 3];
|
||||
float distance2 = dx * dx + dy * dy + dz * dz + dw * dw;
|
||||
if (distance2 > 1e-10f) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua_pushboolean(L, true);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
Mat4* other = luax_checktype(L, 2, Mat4);
|
||||
bool equal = lovrMat4Equals(matrix, other);
|
||||
lua_pushboolean(L, equal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Unpack(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
if (lua_toboolean(L, 2)) {
|
||||
float* m = lovrMat4GetPointer(matrix);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
lua_pushnumber(L, m[i]);
|
||||
}
|
||||
return 16;
|
||||
} else {
|
||||
float position[3], scale[3], angle, ax, ay, az;
|
||||
mat4_getPosition(m, position);
|
||||
mat4_getScale(m, scale);
|
||||
mat4_getAngleAxis(m, &angle, &ax, &ay, &az);
|
||||
lovrMat4GetPosition(matrix, position);
|
||||
lovrMat4GetScale(matrix, scale);
|
||||
lovrMat4GetAngleAxis(matrix, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
|
@ -177,9 +41,9 @@ static int l_lovrMat4Unpack(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4GetPosition(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float position[3];
|
||||
mat4_getPosition(m, position);
|
||||
lovrMat4GetPosition(matrix, position);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
|
@ -187,9 +51,9 @@ static int l_lovrMat4GetPosition(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4GetOrientation(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float angle, ax, ay, az;
|
||||
mat4_getAngleAxis(m, &angle, &ax, &ay, &az);
|
||||
lovrMat4GetAngleAxis(matrix, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, angle);
|
||||
lua_pushnumber(L, ax);
|
||||
lua_pushnumber(L, ay);
|
||||
|
@ -198,9 +62,9 @@ static int l_lovrMat4GetOrientation(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4GetScale(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float scale[3];
|
||||
mat4_getScale(m, scale);
|
||||
lovrMat4GetScale(matrix, scale);
|
||||
lua_pushnumber(L, scale[0]);
|
||||
lua_pushnumber(L, scale[1]);
|
||||
lua_pushnumber(L, scale[2]);
|
||||
|
@ -208,10 +72,10 @@ static int l_lovrMat4GetScale(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4GetPose(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float position[3], angle, ax, ay, az;
|
||||
mat4_getPosition(m, position);
|
||||
mat4_getAngleAxis(m, &angle, &ax, &ay, &az);
|
||||
lovrMat4GetPosition(matrix, position);
|
||||
lovrMat4GetAngleAxis(matrix, &angle, &ax, &ay, &az);
|
||||
lua_pushnumber(L, position[0]);
|
||||
lua_pushnumber(L, position[1]);
|
||||
lua_pushnumber(L, position[2]);
|
||||
|
@ -223,7 +87,7 @@ static int l_lovrMat4GetPose(lua_State* L) {
|
|||
}
|
||||
|
||||
int l_lovrMat4Set(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
int top = lua_gettop(L);
|
||||
int type = lua_type(L, 2);
|
||||
if (type == LUA_TNONE || type == LUA_TNIL || (top == 2 && type == LUA_TNUMBER)) {
|
||||
|
@ -235,10 +99,9 @@ int l_lovrMat4Set(lua_State* L) {
|
|||
*m++ = luax_checkfloat(L, i);
|
||||
}
|
||||
} else {
|
||||
VectorType vectorType;
|
||||
float* n = luax_tovector(L, 2, &vectorType);
|
||||
if (vectorType == V_MAT4) {
|
||||
mat4_init(m, n);
|
||||
Mat4* other = luax_totype(L, 2, Mat4);
|
||||
if (other) {
|
||||
mat4_init(m, lovrMat4GetPointer(other));
|
||||
} else {
|
||||
int index = 2;
|
||||
mat4_identity(m);
|
||||
|
@ -270,11 +133,10 @@ int l_lovrMat4Set(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4Mul(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
VectorType type;
|
||||
float* n = luax_tovector(L, 2, &type);
|
||||
if (n && type == V_MAT4) {
|
||||
mat4_mul(m, n);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
Mat4* other = luax_totype(L, 2, Mat4);
|
||||
if (other) {
|
||||
mat4_mul(m, lovrMat4GetPointer(other));
|
||||
lua_settop(L, 1);
|
||||
} else if (lua_isnumber(L, 2) || (lua_istable(L, 2) && luax_len(L, 2) == 3)) {
|
||||
float v[3];
|
||||
|
@ -309,55 +171,55 @@ static int l_lovrMat4Mul(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4Identity(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4_identity(m);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
lovrMat4Identity(matrix);
|
||||
lua_settop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Invert(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4_invert(m);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
lovrMat4Invert(matrix);
|
||||
lua_settop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Transpose(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4_transpose(m);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
lovrMat4Transpose(matrix);
|
||||
lua_settop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Translate(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
float v[3];
|
||||
luax_readvec3(L, 2, v, NULL);
|
||||
mat4_translate(m, v[0], v[1], v[2]);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float translation[3];
|
||||
luax_readvec3(L, 2, translation, NULL);
|
||||
lovrMat4Translate(matrix, translation);
|
||||
lua_settop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Rotate(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
float q[4];
|
||||
luax_readquat(L, 2, q, NULL);
|
||||
mat4_rotateQuat(m, q);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float rotation[4];
|
||||
luax_readquat(L, 2, rotation, NULL);
|
||||
lovrMat4Rotate(matrix, rotation);
|
||||
lua_settop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Scale(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
float v[3];
|
||||
luax_readvec3(L, 2, v, NULL);
|
||||
mat4_scale(m, v[0], v[1], v[2]);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float scale[3];
|
||||
luax_readscale(L, 2, scale, 3, NULL);
|
||||
lovrMat4Scale(matrix, scale);
|
||||
lua_settop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4Orthographic(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
if (lua_gettop(L) <= 5) {
|
||||
float width = luax_checkfloat(L, 2);
|
||||
float height = luax_checkfloat(L, 3);
|
||||
|
@ -378,7 +240,7 @@ static int l_lovrMat4Orthographic(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4Perspective(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
float fovy = luax_checkfloat(L, 2);
|
||||
float aspect = luax_checkfloat(L, 3);
|
||||
float n = luax_checkfloat(L, 4);
|
||||
|
@ -389,7 +251,7 @@ static int l_lovrMat4Perspective(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4Fov(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
float left = luax_checkfloat(L, 2);
|
||||
float right = luax_checkfloat(L, 3);
|
||||
float up = luax_checkfloat(L, 4);
|
||||
|
@ -402,7 +264,7 @@ static int l_lovrMat4Fov(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4LookAt(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
float from[3], to[3], up[3];
|
||||
int index = 2;
|
||||
index = luax_readvec3(L, index, from, NULL);
|
||||
|
@ -418,7 +280,7 @@ static int l_lovrMat4LookAt(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4Target(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
float from[3], to[3], up[3];
|
||||
int index = 2;
|
||||
index = luax_readvec3(L, index, from, NULL);
|
||||
|
@ -434,7 +296,7 @@ static int l_lovrMat4Target(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4Reflect(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
mat4 m = lovrMat4GetPointer(luax_checktype(L, 1, Mat4));
|
||||
float position[3], normal[3];
|
||||
int index = 2;
|
||||
index = luax_readvec3(L, index, position, NULL);
|
||||
|
@ -445,7 +307,8 @@ static int l_lovrMat4Reflect(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrMat4__mul(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float* m = lovrMat4GetPointer(matrix);
|
||||
if (lua_type(L, 2) == LUA_TTABLE && luax_len(L, 2) == 4) {
|
||||
float v[4];
|
||||
lua_rawgeti(L, 2, 1);
|
||||
|
@ -475,14 +338,17 @@ static int l_lovrMat4__mul(lua_State* L) {
|
|||
luax_pushvec3(L, v);
|
||||
return 1;
|
||||
}
|
||||
float* n = luax_checkvector(L, 2, V_MAT4, "vec3, vec4, or mat4");
|
||||
mat4 out = luax_newtempvector(L, V_MAT4);
|
||||
mat4_mul(mat4_init(out, m), n);
|
||||
Mat4* other = luax_checktype(L, 2, Mat4);
|
||||
Mat4* result = lovrMat4Clone(matrix);
|
||||
mat4_mul(lovrMat4GetPointer(result), lovrMat4GetPointer(other));
|
||||
luax_pushtype(L, Mat4, result);
|
||||
lovrRelease(result, lovrMat4Destroy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4__tostring(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
Mat4* matrix = luax_checktype(L, 1, Mat4);
|
||||
float* m = lovrMat4GetPointer(matrix);
|
||||
const char* format = "(%f, %f, %f, %f,\n %f, %f, %f, %f,\n %f, %f, %f, %f,\n %f, %f, %f, %f)";
|
||||
lua_pushfstring(L, format,
|
||||
m[0], m[4], m[8], m[12],
|
||||
|
@ -492,55 +358,7 @@ static int l_lovrMat4__tostring(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrMat4__newindex(lua_State* L) {
|
||||
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
if (lua_type(L, 2) == LUA_TNUMBER) {
|
||||
int index = lua_tointeger(L, 2);
|
||||
if (index >= 1 && index <= 16) {
|
||||
m[index - 1] = luax_checkfloat(L, 3);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
lua_getglobal(L, "tostring");
|
||||
lua_pushvalue(L, 2);
|
||||
lua_call(L, 1, 1);
|
||||
luaL_error(L, "attempt to assign property %s of mat4 (invalid property)", lua_tostring(L, -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_lovrMat4__index(lua_State* L) {
|
||||
if (lua_type(L, 1) == LUA_TUSERDATA) {
|
||||
lua_getmetatable(L, 1);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawget(L, -2);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
return 1;
|
||||
} else {
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
}
|
||||
|
||||
float* m = luax_checkvector(L, 1, V_MAT4, NULL);
|
||||
if (lua_type(L, 2) == LUA_TNUMBER) {
|
||||
int index = lua_tointeger(L, 2);
|
||||
if (index >= 1 && index <= 16) {
|
||||
lua_pushnumber(L, m[index - 1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua_getglobal(L, "tostring");
|
||||
lua_pushvalue(L, 2);
|
||||
lua_call(L, 1, 1);
|
||||
luaL_error(L, "attempt to index field %s of mat4 (invalid property)", lua_tostring(L, -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMat4__metaindex(lua_State* L) {
|
||||
return 0; // No properties currently, 'identity' is already taken
|
||||
}
|
||||
|
||||
const luaL_Reg lovrMat4[] = {
|
||||
{ "type", l_lovrMat4Type },
|
||||
{ "equals", l_lovrMat4Equals },
|
||||
{ "unpack", l_lovrMat4Unpack },
|
||||
{ "getPosition", l_lovrMat4GetPosition },
|
||||
|
@ -563,7 +381,5 @@ const luaL_Reg lovrMat4[] = {
|
|||
{ "reflect", l_lovrMat4Reflect },
|
||||
{ "__mul", l_lovrMat4__mul },
|
||||
{ "__tostring", l_lovrMat4__tostring },
|
||||
{ "__newindex", l_lovrMat4__newindex },
|
||||
{ "__index", l_lovrMat4__index },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
#include "api.h"
|
||||
#include "math/math.h"
|
||||
#include "util.h"
|
||||
#include <math.h>
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ void lovrVariantDestroy(Variant* variant) {
|
|||
switch (variant->type) {
|
||||
case TYPE_STRING: lovrFree(variant->value.string.pointer); return;
|
||||
case TYPE_OBJECT: lovrRelease(variant->value.object.pointer, variant->value.object.destructor); return;
|
||||
case TYPE_MATRIX: lovrFree(variant->value.matrix.data); return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,9 +37,7 @@ typedef enum {
|
|||
TYPE_STRING,
|
||||
TYPE_MINISTRING,
|
||||
TYPE_POINTER,
|
||||
TYPE_OBJECT,
|
||||
TYPE_VECTOR,
|
||||
TYPE_MATRIX
|
||||
TYPE_OBJECT
|
||||
} VariantType;
|
||||
|
||||
typedef union {
|
||||
|
|
|
@ -16,12 +16,9 @@ struct Curve {
|
|||
arr_t(float) points;
|
||||
};
|
||||
|
||||
struct Pool {
|
||||
struct Mat4 {
|
||||
uint32_t ref;
|
||||
float* data;
|
||||
uint32_t count;
|
||||
uint32_t cursor;
|
||||
uint32_t generation;
|
||||
float m[16];
|
||||
};
|
||||
|
||||
struct RandomGenerator {
|
||||
|
@ -215,63 +212,83 @@ void lovrCurveRemovePoint(Curve* curve, size_t index) {
|
|||
arr_splice(&curve->points, index * 4, 4);
|
||||
}
|
||||
|
||||
// Pool
|
||||
// Mat4
|
||||
|
||||
static const size_t vectorComponents[] = {
|
||||
[V_MAT4] = 16
|
||||
};
|
||||
|
||||
Pool* lovrPoolCreate(void) {
|
||||
Pool* pool = lovrCalloc(sizeof(Pool));
|
||||
pool->ref = 1;
|
||||
pool->data = os_vm_init((1 << 24) * sizeof(float));
|
||||
lovrPoolGrow(pool, 1 << 12);
|
||||
return pool;
|
||||
Mat4* lovrMat4Create(void) {
|
||||
Mat4* matrix = lovrCalloc(sizeof(Mat4));
|
||||
matrix->ref = 1;
|
||||
mat4_identity(matrix->m);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void lovrPoolDestroy(void* ref) {
|
||||
Pool* pool = ref;
|
||||
os_vm_free(pool->data, (1 << 24) * sizeof(float));
|
||||
lovrFree(pool);
|
||||
void lovrMat4Destroy(void* ref) {
|
||||
Mat4* matrix = ref;
|
||||
lovrFree(matrix);
|
||||
}
|
||||
|
||||
void lovrPoolGrow(Pool* pool, size_t count) {
|
||||
lovrAssert(count <= (1 << 24), "Temporary vector space exhausted. Try using lovr.math.drain to drain the vector pool periodically.");
|
||||
pool->count = (uint32_t) count; // Assert guarantees safe
|
||||
bool result = os_vm_commit(pool->data, count * sizeof(float));
|
||||
lovrAssert(result, "Out of memory");
|
||||
Mat4* lovrMat4Clone(Mat4* matrix) {
|
||||
Mat4* clone = lovrCalloc(sizeof(Mat4));
|
||||
clone->ref = 1;
|
||||
mat4_init(clone->m, matrix->m);
|
||||
return clone;
|
||||
}
|
||||
|
||||
Vector lovrPoolAllocate(Pool* pool, VectorType type, float** data) {
|
||||
lovrCheck(pool, "The math module must be initialized to create vectors");
|
||||
float* lovrMat4GetPointer(Mat4* matrix) {
|
||||
return matrix->m;
|
||||
}
|
||||
|
||||
size_t count = vectorComponents[type];
|
||||
|
||||
if (pool->cursor + count > pool->count) {
|
||||
lovrPoolGrow(pool, pool->count * 2);
|
||||
}
|
||||
|
||||
Vector v = {
|
||||
.handle = {
|
||||
.type = type,
|
||||
.generation = pool->generation,
|
||||
.index = pool->cursor
|
||||
bool lovrMat4Equals(Mat4* matrix, Mat4* other) {
|
||||
for (int i = 0; i < 16; i += 4) {
|
||||
float dx = matrix->m[i + 0] - other->m[i + 0];
|
||||
float dy = matrix->m[i + 1] - other->m[i + 1];
|
||||
float dz = matrix->m[i + 2] - other->m[i + 2];
|
||||
float dw = matrix->m[i + 3] - other->m[i + 3];
|
||||
float distance2 = dx * dx + dy * dy + dz * dz + dw * dw;
|
||||
if (distance2 > 1e-10f) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
*data = pool->data + pool->cursor;
|
||||
pool->cursor += (uint32_t) count; // Cast safe because vectorComponents members are known
|
||||
return v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float* lovrPoolResolve(Pool* pool, Vector vector) {
|
||||
lovrCheck(vector.handle.generation == pool->generation, "Attempt to use a temporary vector from a previous frame");
|
||||
return pool->data + vector.handle.index;
|
||||
void lovrMat4GetPosition(Mat4* matrix, float* position) {
|
||||
mat4_getPosition(matrix->m, position);
|
||||
}
|
||||
|
||||
void lovrPoolDrain(Pool* pool) {
|
||||
pool->cursor = 0;
|
||||
pool->generation = (pool->generation + 1) & 0xf;
|
||||
void lovrMat4GetOrientation(Mat4* matrix, float* orientation) {
|
||||
mat4_getOrientation(matrix->m, orientation);
|
||||
}
|
||||
|
||||
void lovrMat4GetAngleAxis(Mat4* matrix, float* angle, float* ax, float* ay, float* az) {
|
||||
mat4_getAngleAxis(matrix->m, angle, ax, ay, az);
|
||||
}
|
||||
|
||||
void lovrMat4GetScale(Mat4* matrix, float* scale) {
|
||||
mat4_getScale(matrix->m, scale);
|
||||
}
|
||||
|
||||
void lovrMat4Identity(Mat4* matrix) {
|
||||
mat4_identity(matrix->m);
|
||||
}
|
||||
|
||||
void lovrMat4Invert(Mat4* matrix) {
|
||||
mat4_invert(matrix->m);
|
||||
}
|
||||
|
||||
void lovrMat4Transpose(Mat4* matrix) {
|
||||
mat4_transpose(matrix->m);
|
||||
}
|
||||
|
||||
void lovrMat4Translate(Mat4* matrix, float* translation) {
|
||||
mat4_translate(matrix->m, translation[0], translation[1], translation[2]);
|
||||
}
|
||||
|
||||
void lovrMat4Rotate(Mat4* matrix, float* rotation) {
|
||||
mat4_rotateQuat(matrix->m, rotation);
|
||||
}
|
||||
|
||||
void lovrMat4Scale(Mat4* matrix, float* scale) {
|
||||
mat4_scale(matrix->m, scale[0], scale[1], scale[2]);
|
||||
}
|
||||
|
||||
// RandomGenerator (compatible with LÖVE's)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct Curve Curve;
|
||||
typedef struct Pool Pool;
|
||||
typedef struct Mat4 Mat4;
|
||||
typedef struct RandomGenerator RandomGenerator;
|
||||
|
||||
bool lovrMathInit(void);
|
||||
|
@ -31,30 +31,23 @@ void lovrCurveSetPoint(Curve* curve, size_t index, float* point);
|
|||
void lovrCurveAddPoint(Curve* curve, float* point, size_t index);
|
||||
void lovrCurveRemovePoint(Curve* curve, size_t index);
|
||||
|
||||
// Pool
|
||||
// Mat4
|
||||
|
||||
typedef enum {
|
||||
V_NONE,
|
||||
V_MAT4,
|
||||
MAX_VECTOR_TYPES
|
||||
} VectorType;
|
||||
|
||||
typedef union {
|
||||
void* pointer;
|
||||
struct {
|
||||
unsigned type : 4;
|
||||
unsigned generation : 4;
|
||||
unsigned index : 24;
|
||||
unsigned padding : 32;
|
||||
} handle;
|
||||
} Vector;
|
||||
|
||||
Pool* lovrPoolCreate(void);
|
||||
void lovrPoolDestroy(void* ref);
|
||||
void lovrPoolGrow(Pool* pool, size_t count);
|
||||
Vector lovrPoolAllocate(Pool* pool, VectorType type, float** data);
|
||||
float* lovrPoolResolve(Pool* pool, Vector vector);
|
||||
void lovrPoolDrain(Pool* pool);
|
||||
Mat4* lovrMat4Create(void);
|
||||
void lovrMat4Destroy(void* ref);
|
||||
Mat4* lovrMat4Clone(Mat4* matrix);
|
||||
float* lovrMat4GetPointer(Mat4* matrix);
|
||||
bool lovrMat4Equals(Mat4* matrix, Mat4* other);
|
||||
void lovrMat4GetPosition(Mat4* matrix, float* position);
|
||||
void lovrMat4GetOrientation(Mat4* matrix, float* orientation);
|
||||
void lovrMat4GetAngleAxis(Mat4* matrix, float* angle, float* ax, float* ay, float* az);
|
||||
void lovrMat4GetScale(Mat4* matrix, float* scale);
|
||||
void lovrMat4Identity(Mat4* matrix);
|
||||
void lovrMat4Invert(Mat4* matrix);
|
||||
void lovrMat4Transpose(Mat4* matrix);
|
||||
void lovrMat4Translate(Mat4* matrix, float* translation);
|
||||
void lovrMat4Rotate(Mat4* matrix, float* rotation);
|
||||
void lovrMat4Scale(Mat4* matrix, float* scale);
|
||||
|
||||
// RandomGenerator
|
||||
|
||||
|
|
Loading…
Reference in New Issue