This commit is contained in:
bjorn 2024-06-07 10:18:33 -07:00
parent 40e2d2bf2b
commit cdf6063355
18 changed files with 329 additions and 618 deletions

View File

@ -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()

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -1,4 +1,5 @@
#include "api.h"
#include "math/math.h"
#include "util.h"
static int l_lovrCurveEvaluate(lua_State* L) {

View File

@ -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 }
};

View File

@ -1,4 +1,5 @@
#include "api.h"
#include "math/math.h"
#include "util.h"
#include <math.h>

View File

@ -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;
}
}

View File

@ -37,9 +37,7 @@ typedef enum {
TYPE_STRING,
TYPE_MINISTRING,
TYPE_POINTER,
TYPE_OBJECT,
TYPE_VECTOR,
TYPE_MATRIX
TYPE_OBJECT
} VariantType;
typedef union {

View File

@ -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)

View File

@ -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