mirror of https://github.com/bjornbytes/lovr.git
1876 lines
53 KiB
C
1876 lines
53 KiB
C
#include "api.h"
|
|
#include "core/maf.h"
|
|
#include "util.h"
|
|
|
|
#define EQ_THRESHOLD 1e-10f
|
|
|
|
static const uint32_t* swizzles[5] = {
|
|
[2] = (uint32_t[]) {
|
|
['x'] = 1,
|
|
['y'] = 2,
|
|
['r'] = 1,
|
|
['g'] = 2,
|
|
['s'] = 1,
|
|
['t'] = 2
|
|
},
|
|
[3] = (uint32_t[]) {
|
|
['x'] = 1,
|
|
['y'] = 2,
|
|
['z'] = 3,
|
|
['r'] = 1,
|
|
['g'] = 2,
|
|
['b'] = 3,
|
|
['s'] = 1,
|
|
['t'] = 2,
|
|
['p'] = 3
|
|
},
|
|
[4] = (uint32_t[]) {
|
|
['x'] = 1,
|
|
['y'] = 2,
|
|
['z'] = 3,
|
|
['w'] = 4,
|
|
['r'] = 1,
|
|
['g'] = 2,
|
|
['b'] = 3,
|
|
['a'] = 4,
|
|
['s'] = 1,
|
|
['t'] = 2,
|
|
['p'] = 3,
|
|
['q'] = 4
|
|
}
|
|
};
|
|
|
|
// Helpers
|
|
|
|
int luax_readvec2(lua_State* L, int index, vec2 v, const char* expected) {
|
|
switch (lua_type(L, index)) {
|
|
case LUA_TNIL:
|
|
case LUA_TNONE:
|
|
v[0] = v[1] = 0.f;
|
|
return index + 1;
|
|
case LUA_TNUMBER:
|
|
v[0] = luax_tofloat(L, index++);
|
|
v[1] = luax_optfloat(L, index++, v[0]);
|
|
return index;
|
|
default:
|
|
vec2_init(v, luax_checkvector(L, index, V_VEC2, expected ? expected : "vec2 or number"));
|
|
return index + 1;
|
|
}
|
|
}
|
|
|
|
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++, v[0]);
|
|
v[2] = luax_optfloat(L, index++, v[0]);
|
|
return index;
|
|
default:
|
|
vec3_init(v, luax_checkvector(L, index, V_VEC3, expected ? expected : "vec3 or number"));
|
|
return index + 1;
|
|
}
|
|
}
|
|
|
|
int luax_readvec4(lua_State* L, int index, vec4 v, const char* expected) {
|
|
switch (lua_type(L, index)) {
|
|
case LUA_TNIL:
|
|
case LUA_TNONE:
|
|
v[0] = v[1] = v[2] = v[3] = 0.f;
|
|
return index + 1;
|
|
case LUA_TNUMBER:
|
|
v[0] = luax_tofloat(L, index++);
|
|
v[1] = luax_optfloat(L, index++, v[0]);
|
|
v[2] = luax_optfloat(L, index++, v[0]);
|
|
v[3] = luax_optfloat(L, index++, v[0]);
|
|
return index;
|
|
default:
|
|
vec4_init(v, luax_checkvector(L, index, V_VEC4, expected ? expected : "vec4 or number"));
|
|
return index + 1;
|
|
}
|
|
}
|
|
|
|
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++, v[0]);
|
|
}
|
|
}
|
|
return index;
|
|
default: {
|
|
int type;
|
|
float* u = luax_tovector(L, index++, &type);
|
|
if (type == V_VEC2) {
|
|
v[0] = u[0];
|
|
v[1] = u[1];
|
|
v[2] = 1.f;
|
|
} else if (type == V_VEC3) {
|
|
vec3_init(v, u);
|
|
} else {
|
|
return luax_typeerror(L, index, "vec2, vec3, or number");
|
|
}
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
case LUA_TNUMBER:
|
|
angle = luax_optfloat(L, index++, 0.f);
|
|
ax = luax_optfloat(L, index++, 0.f);
|
|
ay = luax_optfloat(L, index++, 1.f);
|
|
az = luax_optfloat(L, index++, 0.f);
|
|
quat_fromAngleAxis(q, angle, ax, ay, az);
|
|
return index;
|
|
default:
|
|
quat_init(q, luax_checkvector(L, index++, V_QUAT, expected ? expected : "quat or number"));
|
|
return index;
|
|
}
|
|
}
|
|
|
|
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: {
|
|
int 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// vec2
|
|
|
|
static int l_lovrVec2Type(lua_State* L) {
|
|
lua_pushliteral(L, "Vec2");
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Equals(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, NULL);
|
|
lua_pushboolean(L, vec2_distance2(v, u) < EQ_THRESHOLD);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Unpack(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
lua_pushnumber(L, v[0]);
|
|
lua_pushnumber(L, v[1]);
|
|
return 2;
|
|
}
|
|
|
|
int l_lovrVec2Set(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
luax_readvec2(L, 2, v, NULL);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Length(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
lua_pushnumber(L, vec2_length(v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Normalize(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
vec2_normalize(vec2_init(out, v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Distance(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float u[2];
|
|
luax_readvec2(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec2_distance(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Dot(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float u[2];
|
|
luax_readvec2(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec2_dot(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Lerp(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float u[2];
|
|
int index = luax_readvec2(L, 2, u, NULL);
|
|
float t = luax_checkfloat(L, index);
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
vec2_lerp(vec2_init(out, v), u, t);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Angle(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float u[2];
|
|
luax_readvec2(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec2_angle(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__add(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, NULL);
|
|
out[0] = x + u[0];
|
|
out[1] = x + u[1];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] + x;
|
|
out[1] = v[1] + x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
vec2_add(vec2_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__sub(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, NULL);
|
|
out[0] = x - u[0];
|
|
out[1] = x - u[1];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] - x;
|
|
out[1] = v[1] - x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
vec2_sub(vec2_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__mul(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, NULL);
|
|
out[0] = x * u[0];
|
|
out[1] = x * u[1];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] * x;
|
|
out[1] = v[1] * x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
vec2_mul(vec2_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__div(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, NULL);
|
|
out[0] = x / u[0];
|
|
out[1] = x / u[1];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] / x;
|
|
out[1] = v[1] / x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
vec2_div(vec2_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__unm(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
vec2_scale(vec2_init(out, v), -1.f);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__len(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
lua_pushnumber(L, vec2_length(v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__tostring(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
lua_pushfstring(L, "(%f, %f)", v[0], v[1]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__newindex(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index == 1 || index == 2) {
|
|
float x = luax_checkfloat(L, 3);
|
|
v[index - 1] = x;
|
|
return 0;
|
|
}
|
|
} else if (lua_type(L, 2) == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* str = lua_tolstring(L, 2, &length);
|
|
const unsigned char* key = (const unsigned char*) str;
|
|
|
|
if (length == 1 && swizzles[2][key[0]]) {
|
|
v[swizzles[2][key[0]] - 1] = luax_checkfloat(L, 3);
|
|
return 0;
|
|
} else if (length == 2 && swizzles[2][key[0]] && swizzles[2][key[1]]) {
|
|
float* u = luax_checkvector(L, 3, V_VEC2, NULL);
|
|
for (size_t i = 0; i < length; i++) {
|
|
v[swizzles[2][key[i]] - 1] = u[i];
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to assign property %s of vec2 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
static int l_lovrVec2__index(lua_State* L) {
|
|
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* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
int type = lua_type(L, 2);
|
|
if (type == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index == 1 || index == 2) {
|
|
lua_pushnumber(L, v[index - 1]);
|
|
return 1;
|
|
}
|
|
} else if (type == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* str = lua_tolstring(L, 2, &length);
|
|
const unsigned char* key = (const unsigned char*) str;
|
|
|
|
if (length == 1 && swizzles[2][key[0]]) {
|
|
lua_pushnumber(L, v[swizzles[2][key[0]] - 1]);
|
|
return 1;
|
|
} else if (length == 2 && swizzles[2][key[0]] && swizzles[2][key[1]]) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
out[0] = v[swizzles[2][key[0]] - 1];
|
|
out[1] = v[swizzles[2][key[1]] - 1];
|
|
return 1;
|
|
} else if (length == 3 && swizzles[2][key[0]] && swizzles[2][key[1]] && swizzles[2][key[2]]) {
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
out[0] = v[swizzles[2][key[0]] - 1];
|
|
out[1] = v[swizzles[2][key[1]] - 1];
|
|
out[2] = v[swizzles[2][key[2]] - 1];
|
|
return 1;
|
|
} else if (length == 4 && swizzles[2][key[0]] && swizzles[2][key[1]] && swizzles[2][key[2]] && swizzles[2][key[3]]) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
out[0] = v[swizzles[2][key[0]] - 1];
|
|
out[1] = v[swizzles[2][key[1]] - 1];
|
|
out[2] = v[swizzles[2][key[2]] - 1];
|
|
out[3] = v[swizzles[2][key[3]] - 1];
|
|
return 1;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to index field %s of vec2 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
int l_lovrVec2__metaindex(lua_State* L) {
|
|
if (lua_type(L, 2) != LUA_TSTRING) {
|
|
return 0;
|
|
}
|
|
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
|
|
static const struct { StringEntry name; float x, y; } properties[] = {
|
|
{ ENTRY("one"), 1.f, 1.f },
|
|
{ ENTRY("zero"), 0.f, 0.f }
|
|
};
|
|
|
|
for (uint32_t i = 0; i < COUNTOF(properties); i++) {
|
|
if (length == properties[i].name.length && !memcmp(key, properties[i].name.string, length)) {
|
|
float* v = luax_newvector(L, V_VEC2);
|
|
v[0] = properties[i].x;
|
|
v[1] = properties[i].y;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const luaL_Reg lovrVec2[] = {
|
|
{ "type", l_lovrVec2Type },
|
|
{ "equals", l_lovrVec2Equals },
|
|
{ "unpack", l_lovrVec2Unpack },
|
|
{ "set", l_lovrVec2Set },
|
|
{ "length", l_lovrVec2Length },
|
|
{ "normalize", l_lovrVec2Normalize },
|
|
{ "distance", l_lovrVec2Distance },
|
|
{ "dot", l_lovrVec2Dot },
|
|
{ "lerp", l_lovrVec2Lerp },
|
|
{ "angle", l_lovrVec2Angle },
|
|
{ "__add", l_lovrVec2__add },
|
|
{ "__sub", l_lovrVec2__sub },
|
|
{ "__mul", l_lovrVec2__mul },
|
|
{ "__div", l_lovrVec2__div },
|
|
{ "__unm", l_lovrVec2__unm },
|
|
{ "__len", l_lovrVec2__len },
|
|
{ "__tostring", l_lovrVec2__tostring },
|
|
{ "__newindex", l_lovrVec2__newindex },
|
|
{ "__index", l_lovrVec2__index },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
// vec3
|
|
|
|
static int l_lovrVec3Type(lua_State* L) {
|
|
lua_pushliteral(L, "Vec3");
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Equals(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
lua_pushboolean(L, vec3_distance2(v, u) < EQ_THRESHOLD);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Unpack(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
lua_pushnumber(L, v[0]);
|
|
lua_pushnumber(L, v[1]);
|
|
lua_pushnumber(L, v[2]);
|
|
return 3;
|
|
}
|
|
|
|
int l_lovrVec3Set(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
if (lua_isnoneornil(L, 2) || lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = luax_optfloat(L, 2, 0.f);
|
|
vec3_set(v, x, luax_optfloat(L, 3, x), luax_optfloat(L, 4, x));
|
|
} else {
|
|
int t;
|
|
float* p = luax_tovector(L, 2, &t);
|
|
if (p && t == V_VEC3) {
|
|
vec3_init(v, p);
|
|
} else if (p && t == V_MAT4) {
|
|
vec3_set(v, p[12], p[13], p[14]);
|
|
} else if (p && t == V_QUAT) {
|
|
quat_getDirection(p, v);
|
|
} else{
|
|
luax_typeerror(L, 2, "vec3, quat, mat4, or number");
|
|
}
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Length(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
lua_pushnumber(L, vec3_length(v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Normalize(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
vec3_normalize(vec3_init(out, v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Distance(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float u[3];
|
|
luax_readvec3(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec3_distance(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Dot(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float u[3];
|
|
luax_readvec3(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec3_dot(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Cross(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float u[3];
|
|
luax_readvec3(L, 2, u, NULL);
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
vec3_cross(vec3_init(out, v), u);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Lerp(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float u[3];
|
|
int index = luax_readvec3(L, 2, u, NULL);
|
|
float t = luax_checkfloat(L, index);
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
vec3_lerp(vec3_init(out, v), u, t);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Angle(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float u[3];
|
|
luax_readvec3(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec3_angle(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Transform(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float m[16];
|
|
luax_readmat4(L, 2, m, 1);
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
mat4_mulPoint(m, vec3_init(out, v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Rotate(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float q[4];
|
|
luax_readquat(L, 2, q, NULL);
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
quat_rotate(q, vec3_init(out, v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__add(lua_State* L) {
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = luax_tofloat(L, 1);
|
|
vec3 v = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
out[0] = x + v[0];
|
|
out[1] = x + v[1];
|
|
out[2] = x + v[2];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float x = luax_tofloat(L, 2);
|
|
out[0] = v[0] + x;
|
|
out[1] = v[1] + x;
|
|
out[2] = v[2] + x;
|
|
} else {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
vec3_add(vec3_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__sub(lua_State* L) {
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = luax_tofloat(L, 1);
|
|
vec3 v = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
out[0] = x - v[0];
|
|
out[1] = x - v[1];
|
|
out[2] = x - v[2];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float x = luax_tofloat(L, 2);
|
|
out[0] = v[0] - x;
|
|
out[1] = v[1] - x;
|
|
out[2] = v[2] - x;
|
|
} else {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
vec3_sub(vec3_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__mul(lua_State* L) {
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3_scale(vec3_init(out, v), luax_tofloat(L, 1));
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3_scale(vec3_init(out, v), luax_tofloat(L, 2));
|
|
} else {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
vec3_mul(vec3_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__div(lua_State* L) {
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3_scale(vec3_init(out, v), 1.f / luax_tofloat(L, 1));
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3_scale(vec3_init(out, v), 1.f / luax_tofloat(L, 2));
|
|
} else {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
vec3_div(vec3_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__unm(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
vec3_scale(vec3_init(out, v), -1.f);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__len(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
lua_pushnumber(L, vec3_length(v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__tostring(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
lua_pushfstring(L, "(%f, %f, %f)", v[0], v[1], v[2]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__newindex(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index == 1 || index == 2 || index == 3) {
|
|
float x = luax_checkfloat(L, 3);
|
|
v[index - 1] = x;
|
|
return 0;
|
|
}
|
|
} else if (lua_type(L, 2) == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* str = lua_tolstring(L, 2, &length);
|
|
const unsigned char* key = (const unsigned char*) str;
|
|
|
|
if (length == 1 && swizzles[3][key[0]]) {
|
|
v[swizzles[3][key[0]] - 1] = luax_checkfloat(L, 3);
|
|
return 0;
|
|
} else if (length == 2 && swizzles[3][key[0]] && swizzles[3][key[1]]) {
|
|
float* u = luax_checkvector(L, 3, V_VEC2, NULL);
|
|
for (size_t i = 0; i < length; i++) {
|
|
v[swizzles[3][key[i]] - 1] = u[i];
|
|
}
|
|
return 0;
|
|
} else if (length == 3 && swizzles[3][key[0]] && swizzles[3][key[1]] && swizzles[3][key[2]]) {
|
|
float* u = luax_checkvector(L, 3, V_VEC3, NULL);
|
|
for (size_t i = 0; i < length; i++) {
|
|
v[swizzles[3][key[i]] - 1] = u[i];
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to assign property %s of vec3 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
static int l_lovrVec3__index(lua_State* L) {
|
|
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* v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
int type = lua_type(L, 2);
|
|
if (type == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index == 1 || index == 2 || index == 3) {
|
|
lua_pushnumber(L, v[index - 1]);
|
|
return 1;
|
|
}
|
|
} else if (type == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* str = lua_tolstring(L, 2, &length);
|
|
const unsigned char* key = (const unsigned char*) str;
|
|
|
|
if (length == 1 && swizzles[3][key[0]]) {
|
|
lua_pushnumber(L, v[swizzles[3][key[0]] - 1]);
|
|
return 1;
|
|
} else if (length == 2 && swizzles[3][key[0]] && swizzles[3][key[1]]) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
out[0] = v[swizzles[3][key[0]] - 1];
|
|
out[1] = v[swizzles[3][key[1]] - 1];
|
|
return 1;
|
|
} else if (length == 3 && swizzles[3][key[0]] && swizzles[3][key[1]] && swizzles[3][key[2]]) {
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
out[0] = v[swizzles[3][key[0]] - 1];
|
|
out[1] = v[swizzles[3][key[1]] - 1];
|
|
out[2] = v[swizzles[3][key[2]] - 1];
|
|
return 1;
|
|
} else if (length == 4 && swizzles[3][key[0]] && swizzles[3][key[1]] && swizzles[3][key[2]] && swizzles[3][key[3]]) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
out[0] = v[swizzles[3][key[0]] - 1];
|
|
out[1] = v[swizzles[3][key[1]] - 1];
|
|
out[2] = v[swizzles[3][key[2]] - 1];
|
|
out[3] = v[swizzles[3][key[3]] - 1];
|
|
return 1;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to index field %s of vec3 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
int l_lovrVec3__metaindex(lua_State* L) {
|
|
if (lua_type(L, 2) != LUA_TSTRING) {
|
|
return 0;
|
|
}
|
|
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
|
|
static const struct { StringEntry name; float x, y, z; } properties[] = {
|
|
{ ENTRY("one"), 1.f, 1.f, 1.f },
|
|
{ ENTRY("zero"), 0.f, 0.f, 0.f },
|
|
{ ENTRY("left"), -1.f, 0.f, 0.f },
|
|
{ ENTRY("right"), 1.f, 0.f, 0.f },
|
|
{ ENTRY("up"), 0.f, 1.f, 0.f },
|
|
{ ENTRY("down"), 0.f, -1.f, 0.f },
|
|
{ ENTRY("back"), 0.f, 0.f, 1.f },
|
|
{ ENTRY("forward"), 0.f, 0.f, -1.f }
|
|
};
|
|
|
|
for (uint32_t i = 0; i < COUNTOF(properties); i++) {
|
|
if (length == properties[i].name.length && !memcmp(key, properties[i].name.string, length)) {
|
|
float* v = luax_newvector(L, V_VEC3);
|
|
vec3_set(v, properties[i].x, properties[i].y, properties[i].z);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const luaL_Reg lovrVec3[] = {
|
|
{ "type", l_lovrVec3Type },
|
|
{ "equals", l_lovrVec3Equals },
|
|
{ "unpack", l_lovrVec3Unpack },
|
|
{ "set", l_lovrVec3Set },
|
|
{ "length", l_lovrVec3Length },
|
|
{ "normalize", l_lovrVec3Normalize },
|
|
{ "distance", l_lovrVec3Distance },
|
|
{ "dot", l_lovrVec3Dot },
|
|
{ "cross", l_lovrVec3Cross },
|
|
{ "lerp", l_lovrVec3Lerp },
|
|
{ "angle", l_lovrVec3Angle },
|
|
{ "transform", l_lovrVec3Transform },
|
|
{ "rotate", l_lovrVec3Rotate },
|
|
{ "__add", l_lovrVec3__add },
|
|
{ "__sub", l_lovrVec3__sub },
|
|
{ "__mul", l_lovrVec3__mul },
|
|
{ "__div", l_lovrVec3__div },
|
|
{ "__unm", l_lovrVec3__unm },
|
|
{ "__len", l_lovrVec3__len },
|
|
{ "__tostring", l_lovrVec3__tostring },
|
|
{ "__newindex", l_lovrVec3__newindex },
|
|
{ "__index", l_lovrVec3__index },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
// vec4
|
|
|
|
static int l_lovrVec4Type(lua_State* L) {
|
|
lua_pushliteral(L, "Vec4");
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Equals(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, NULL);
|
|
lua_pushboolean(L, vec4_distance2(v, u) < EQ_THRESHOLD);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Unpack(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
lua_pushnumber(L, v[0]);
|
|
lua_pushnumber(L, v[1]);
|
|
lua_pushnumber(L, v[2]);
|
|
lua_pushnumber(L, v[3]);
|
|
return 4;
|
|
}
|
|
|
|
int l_lovrVec4Set(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float u[4];
|
|
luax_readvec4(L, 2, u, NULL);
|
|
vec4_init(v, u);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Length(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
lua_pushnumber(L, vec4_length(v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Normalize(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
vec4_normalize(vec4_init(out, v));
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Distance(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float u[4];
|
|
luax_readvec4(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec4_distance(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Dot(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float u[4];
|
|
luax_readvec4(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec4_dot(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Lerp(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float u[4];
|
|
int index = luax_readvec4(L, 2, u, NULL);
|
|
float t = luax_checkfloat(L, index);
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
vec4_lerp(vec4_init(out, v), u, t);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Angle(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float u[4];
|
|
luax_readvec4(L, 2, u, NULL);
|
|
lua_pushnumber(L, vec4_angle(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Transform(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float m[16];
|
|
luax_readmat4(L, 2, m, 1);
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
mat4_mulVec4(m, vec4_init(out, v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__add(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, NULL);
|
|
out[0] = x + u[0];
|
|
out[1] = x + u[1];
|
|
out[2] = x + u[2];
|
|
out[3] = x + u[3];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] + x;
|
|
out[1] = v[1] + x;
|
|
out[2] = v[2] + x;
|
|
out[3] = v[3] + x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
vec4_add(vec4_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__sub(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, NULL);
|
|
out[0] = x - u[0];
|
|
out[1] = x - u[1];
|
|
out[2] = x - u[2];
|
|
out[3] = x - u[3];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] - x;
|
|
out[1] = v[1] - x;
|
|
out[2] = v[2] - x;
|
|
out[3] = v[3] - x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
vec4_sub(vec4_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__mul(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, NULL);
|
|
out[0] = x * u[0];
|
|
out[1] = x * u[1];
|
|
out[2] = x * u[2];
|
|
out[3] = x * u[3];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] * x;
|
|
out[1] = v[1] * x;
|
|
out[2] = v[2] * x;
|
|
out[3] = v[3] * x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
vec4_mul(vec4_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__div(lua_State* L) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, NULL);
|
|
out[0] = x / u[0];
|
|
out[1] = x / u[1];
|
|
out[2] = x / u[2];
|
|
out[3] = x / u[3];
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float x = lua_tonumber(L, 2);
|
|
out[0] = v[0] / x;
|
|
out[1] = v[1] / x;
|
|
out[2] = v[2] / x;
|
|
out[3] = v[3] / x;
|
|
} else {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
vec4_div(vec4_init(out, v), u);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__unm(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
vec4_scale(vec4_init(out, v), -1.f);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__len(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
lua_pushnumber(L, vec4_length(v));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__tostring(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
lua_pushfstring(L, "(%f, %f, %f, %f)", v[0], v[1], v[2], v[3]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__newindex(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index >= 1 && index <= 4) {
|
|
float x = luax_checkfloat(L, 3);
|
|
v[index - 1] = x;
|
|
return 0;
|
|
}
|
|
} else if (lua_type(L, 2) == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* str = lua_tolstring(L, 2, &length);
|
|
const unsigned char* key = (const unsigned char*) str;
|
|
|
|
if (length == 1 && swizzles[4][key[0]]) {
|
|
v[swizzles[4][key[0]] - 1] = luax_checkfloat(L, 3);
|
|
return 0;
|
|
} else if (length == 2 && swizzles[4][key[0]] && swizzles[4][key[1]]) {
|
|
float* u = luax_checkvector(L, 3, V_VEC2, NULL);
|
|
for (size_t i = 0; i < length; i++) {
|
|
v[swizzles[4][key[i]] - 1] = u[i];
|
|
}
|
|
return 0;
|
|
} else if (length == 3 && swizzles[4][key[0]] && swizzles[4][key[1]] && swizzles[4][key[2]]) {
|
|
float* u = luax_checkvector(L, 3, V_VEC3, NULL);
|
|
for (size_t i = 0; i < length; i++) {
|
|
v[swizzles[4][key[i]] - 1] = u[i];
|
|
}
|
|
return 0;
|
|
} else if (length == 4 && swizzles[4][key[0]] && swizzles[4][key[1]] && swizzles[4][key[2]] && swizzles[4][key[3]]) {
|
|
float* u = luax_checkvector(L, 3, V_VEC4, NULL);
|
|
for (size_t i = 0; i < length; i++) {
|
|
v[swizzles[4][key[i]] - 1] = u[i];
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to assign property %s of vec4 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
static int l_lovrVec4__index(lua_State* L) {
|
|
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* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
int type = lua_type(L, 2);
|
|
if (type == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index >= 1 && index <= 4) {
|
|
lua_pushnumber(L, v[index - 1]);
|
|
return 1;
|
|
}
|
|
} else if (type == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* str = lua_tolstring(L, 2, &length);
|
|
const unsigned char* key = (const unsigned char*) str;
|
|
|
|
if (length == 1 && swizzles[4][key[0]]) {
|
|
lua_pushnumber(L, v[swizzles[4][key[0]] - 1]);
|
|
return 1;
|
|
} else if (length == 2 && swizzles[4][key[0]] && swizzles[4][key[1]]) {
|
|
float* out = luax_newvector(L, V_VEC2);
|
|
out[0] = v[swizzles[4][key[0]] - 1];
|
|
out[1] = v[swizzles[4][key[1]] - 1];
|
|
return 1;
|
|
} else if (length == 3 && swizzles[4][key[0]] && swizzles[4][key[1]] && swizzles[4][key[2]]) {
|
|
float* out = luax_newvector(L, V_VEC3);
|
|
out[0] = v[swizzles[4][key[0]] - 1];
|
|
out[1] = v[swizzles[4][key[1]] - 1];
|
|
out[2] = v[swizzles[4][key[2]] - 1];
|
|
return 1;
|
|
} else if (length == 4 && swizzles[4][key[0]] && swizzles[4][key[1]] && swizzles[4][key[2]] && swizzles[4][key[3]]) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
out[0] = v[swizzles[4][key[0]] - 1];
|
|
out[1] = v[swizzles[4][key[1]] - 1];
|
|
out[2] = v[swizzles[4][key[2]] - 1];
|
|
out[3] = v[swizzles[4][key[3]] - 1];
|
|
return 1;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to index field %s of vec4 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
int l_lovrVec4__metaindex(lua_State* L) {
|
|
if (lua_type(L, 2) != LUA_TSTRING) {
|
|
return 0;
|
|
}
|
|
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
|
|
static const struct { StringEntry name; float x, y, z, w; } properties[] = {
|
|
{ ENTRY("one"), 1.f, 1.f, 1.f, 1.f },
|
|
{ ENTRY("zero"), 0.f, 0.f, 0.f, 0.f }
|
|
};
|
|
|
|
for (uint32_t i = 0; i < COUNTOF(properties); i++) {
|
|
if (length == properties[i].name.length && !memcmp(key, properties[i].name.string, length)) {
|
|
float* v = luax_newvector(L, V_VEC4);
|
|
v[0] = properties[i].x;
|
|
v[1] = properties[i].y;
|
|
v[2] = properties[i].z;
|
|
v[3] = properties[i].w;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const luaL_Reg lovrVec4[] = {
|
|
{ "type", l_lovrVec4Type },
|
|
{ "equals", l_lovrVec4Equals },
|
|
{ "unpack", l_lovrVec4Unpack },
|
|
{ "set", l_lovrVec4Set },
|
|
{ "length", l_lovrVec4Length },
|
|
{ "normalize", l_lovrVec4Normalize },
|
|
{ "distance", l_lovrVec4Distance },
|
|
{ "dot", l_lovrVec4Dot },
|
|
{ "lerp", l_lovrVec4Lerp },
|
|
{ "angle", l_lovrVec4Angle },
|
|
{ "transform", l_lovrVec4Transform },
|
|
{ "__add", l_lovrVec4__add },
|
|
{ "__sub", l_lovrVec4__sub },
|
|
{ "__mul", l_lovrVec4__mul },
|
|
{ "__div", l_lovrVec4__div },
|
|
{ "__unm", l_lovrVec4__unm },
|
|
{ "__len", l_lovrVec4__len },
|
|
{ "__tostring", l_lovrVec4__tostring },
|
|
{ "__newindex", l_lovrVec4__newindex },
|
|
{ "__index", l_lovrVec4__index },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
// quat
|
|
|
|
static int l_lovrQuatType(lua_State* L) {
|
|
lua_pushliteral(L, "Quat");
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatEquals(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
quat r = luax_checkvector(L, 2, V_QUAT, NULL);
|
|
float dot = q[0] * r[0] + q[1] * r[1] + q[2] * r[2] + q[3] * r[3];
|
|
bool equal = fabsf(dot) >= 1.f - 1e-5f;
|
|
lua_pushboolean(L, equal);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatUnpack(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
bool raw = lua_toboolean(L, 2);
|
|
if (raw) {
|
|
lua_pushnumber(L, q[0]);
|
|
lua_pushnumber(L, q[1]);
|
|
lua_pushnumber(L, q[2]);
|
|
lua_pushnumber(L, q[3]);
|
|
} else {
|
|
float angle, ax, ay, az;
|
|
quat_getAngleAxis(q, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
}
|
|
return 4;
|
|
}
|
|
|
|
int l_lovrQuatSet(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
if (lua_isnoneornil(L, 2)) {
|
|
quat_identity(q);
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
float y = luax_checkfloat(L, 3);
|
|
float z = luax_checkfloat(L, 4);
|
|
float w = luax_checkfloat(L, 5);
|
|
bool raw = lua_toboolean(L, 6);
|
|
if (raw) {
|
|
quat_set(q, x, y, z, w);
|
|
} else {
|
|
quat_fromAngleAxis(q, x, y, z, w);
|
|
}
|
|
} else {
|
|
int type;
|
|
float* p = luax_tovector(L, 2, &type);
|
|
if (!p) return luax_typeerror(L, 2, "vec3, quat, or number");
|
|
|
|
if (type == V_VEC3) {
|
|
if (lua_gettop(L) > 2) {
|
|
vec3 u = luax_checkvector(L, 3, V_VEC3, "vec3");
|
|
quat_between(q, p, u);
|
|
} else {
|
|
float forward[3] = { 0.f, 0.f, -1.f };
|
|
quat_between(q, forward, p);
|
|
}
|
|
} else if (type == V_QUAT) {
|
|
quat_init(q, p);
|
|
} else if (type == V_MAT4) {
|
|
quat_fromMat4(q, p);
|
|
} else {
|
|
return luax_typeerror(L, 2, "vec3, quat, mat4, or number");
|
|
}
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatLength(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
lua_pushnumber(L, quat_length(q));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatNormalize(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
float* out = luax_newvector(L, V_QUAT);
|
|
quat_normalize(quat_init(out, q));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatDirection(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
vec3 v = luax_newvector(L, V_VEC3);
|
|
quat_getDirection(q, v);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatConjugate(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
float* out = luax_newvector(L, V_QUAT);
|
|
quat_conjugate(quat_init(out, q));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatSlerp(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
quat r = luax_checkvector(L, 2, V_QUAT, NULL);
|
|
float t = luax_checkfloat(L, 3);
|
|
float* out = luax_newvector(L, V_QUAT);
|
|
quat_slerp(quat_init(out, q), r, t);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatGetEuler(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
float pitch, yaw, roll;
|
|
quat_getEuler(q, &pitch, &yaw, &roll);
|
|
lua_pushnumber(L, pitch);
|
|
lua_pushnumber(L, yaw);
|
|
lua_pushnumber(L, roll);
|
|
return 3;
|
|
}
|
|
|
|
static int l_lovrQuatSetEuler(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
float pitch = luax_checkfloat(L, 2);
|
|
float yaw = luax_checkfloat(L, 3);
|
|
float roll = luax_checkfloat(L, 4);
|
|
quat_setEuler(q, pitch, yaw, roll);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuat__mul(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
int type;
|
|
float* r = luax_tovector(L, 2, &type);
|
|
if (!r) return luax_typeerror(L, 2, "quat or vec3");
|
|
if (type == V_VEC3) {
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
quat_rotate(q, vec3_init(out, r));
|
|
} else {
|
|
quat out = luax_newvector(L, V_QUAT);
|
|
quat_mul(out, q, r);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuat__len(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
lua_pushnumber(L, quat_length(q));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuat__tostring(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
lua_pushfstring(L, "(%f, %f, %f, %f)", q[0], q[1], q[2], q[3]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuat__newindex(lua_State* L) {
|
|
float* q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index == 1 || index == 2 || index == 3 || index == 4) {
|
|
float x = luax_checkfloat(L, 3);
|
|
q[index - 1] = x;
|
|
return 0;
|
|
}
|
|
} else if (lua_type(L, 2) == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
float x = luax_checkfloat(L, 3);
|
|
if (length == 1 && key[0] >= 'w' && key[0] <= 'z') {
|
|
int index = key[0] == 'w' ? 3 : key[0] - 'x';
|
|
q[index] = x;
|
|
return 0;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to assign property %s of quat (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
static int l_lovrQuat__index(lua_State* L) {
|
|
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* q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
int type = lua_type(L, 2);
|
|
if (type == LUA_TNUMBER) {
|
|
int index = lua_tointeger(L, 2);
|
|
if (index == 1 || index == 2 || index == 3 || index == 4) {
|
|
lua_pushnumber(L, q[index - 1]);
|
|
return 1;
|
|
}
|
|
} else if (type == LUA_TSTRING) {
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
if (length == 1 && key[0] >= 'w' && key[0] <= 'z') {
|
|
int index = key[0] == 'w' ? 3 : key[0] - 'x';
|
|
lua_pushnumber(L, q[index]);
|
|
return 1;
|
|
}
|
|
}
|
|
lua_getglobal(L, "tostring");
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
return luaL_error(L, "attempt to index field %s of quat (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
int l_lovrQuat__metaindex(lua_State* L) {
|
|
if (lua_type(L, 2) != LUA_TSTRING) {
|
|
return 0;
|
|
}
|
|
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
|
|
static const struct { StringEntry name; float x, y, z, w; } properties[] = {
|
|
{ ENTRY("identity"), 0.f, 0.f, 0.f, 1.f }
|
|
};
|
|
|
|
for (uint32_t i = 0; i < COUNTOF(properties); i++) {
|
|
if (length == properties[i].name.length && !memcmp(key, properties[i].name.string, length)) {
|
|
float* q = luax_newvector(L, V_QUAT);
|
|
quat_set(q, properties[i].x, properties[i].y, properties[i].z, properties[i].w);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const luaL_Reg lovrQuat[] = {
|
|
{ "type", l_lovrQuatType },
|
|
{ "equals", l_lovrQuatEquals },
|
|
{ "unpack", l_lovrQuatUnpack },
|
|
{ "set", l_lovrQuatSet },
|
|
{ "length", l_lovrQuatLength },
|
|
{ "normalize", l_lovrQuatNormalize },
|
|
{ "direction", l_lovrQuatDirection },
|
|
{ "conjugate", l_lovrQuatConjugate },
|
|
{ "slerp", l_lovrQuatSlerp },
|
|
{ "getEuler", l_lovrQuatGetEuler },
|
|
{ "setEuler", l_lovrQuatSetEuler },
|
|
{ "__mul", l_lovrQuat__mul },
|
|
{ "__len", l_lovrQuat__len },
|
|
{ "__tostring", l_lovrQuat__tostring },
|
|
{ "__newindex", l_lovrQuat__newindex },
|
|
{ "__index", l_lovrQuat__index },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
// 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 > EQ_THRESHOLD) {
|
|
lua_pushboolean(L, false);
|
|
return 1;
|
|
}
|
|
}
|
|
lua_pushboolean(L, true);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Unpack(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
if (lua_toboolean(L, 2)) {
|
|
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);
|
|
lua_pushnumber(L, position[0]);
|
|
lua_pushnumber(L, position[1]);
|
|
lua_pushnumber(L, position[2]);
|
|
lua_pushnumber(L, scale[0]);
|
|
lua_pushnumber(L, scale[1]);
|
|
lua_pushnumber(L, scale[2]);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
return 10;
|
|
}
|
|
}
|
|
|
|
static int l_lovrMat4GetPosition(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float position[3];
|
|
mat4_getPosition(m, position);
|
|
lua_pushnumber(L, position[0]);
|
|
lua_pushnumber(L, position[1]);
|
|
lua_pushnumber(L, position[2]);
|
|
return 3;
|
|
}
|
|
|
|
static int l_lovrMat4GetOrientation(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float angle, ax, ay, az;
|
|
mat4_getAngleAxis(m, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
return 4;
|
|
}
|
|
|
|
static int l_lovrMat4GetScale(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float scale[3];
|
|
mat4_getScale(m, scale);
|
|
lua_pushnumber(L, scale[0]);
|
|
lua_pushnumber(L, scale[1]);
|
|
lua_pushnumber(L, scale[2]);
|
|
return 3;
|
|
}
|
|
|
|
static int l_lovrMat4GetPose(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float position[3], angle, ax, ay, az;
|
|
mat4_getPosition(m, position);
|
|
mat4_getAngleAxis(m, &angle, &ax, &ay, &az);
|
|
lua_pushnumber(L, position[0]);
|
|
lua_pushnumber(L, position[1]);
|
|
lua_pushnumber(L, position[2]);
|
|
lua_pushnumber(L, angle);
|
|
lua_pushnumber(L, ax);
|
|
lua_pushnumber(L, ay);
|
|
lua_pushnumber(L, az);
|
|
return 7;
|
|
}
|
|
|
|
int l_lovrMat4Set(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
int top = lua_gettop(L);
|
|
int type = lua_type(L, 2);
|
|
if (type == LUA_TNONE || type == LUA_TNIL || (top == 2 && type == LUA_TNUMBER)) {
|
|
float x = luax_optfloat(L, 2, 1.f);
|
|
memset(m, 0, 16 * sizeof(float));
|
|
m[0] = m[5] = m[10] = m[15] = x;
|
|
} else if (top == 17) {
|
|
for (int i = 2; i <= 17; i++) {
|
|
*m++ = luax_checkfloat(L, i);
|
|
}
|
|
} else {
|
|
int vectorType;
|
|
float* n = luax_tovector(L, 2, &vectorType);
|
|
if (vectorType == V_MAT4) {
|
|
mat4_init(m, n);
|
|
} else {
|
|
int index = 2;
|
|
mat4_identity(m);
|
|
|
|
float position[3];
|
|
index = luax_readvec3(L, index, position, "nil, number, vec3, or mat4");
|
|
m[12] = position[0];
|
|
m[13] = position[1];
|
|
m[14] = position[2];
|
|
|
|
float* v = luax_tovector(L, index, &vectorType);
|
|
if (vectorType == V_QUAT) {
|
|
mat4_rotateQuat(m, v);
|
|
} else if ((top - index) == 3 && lua_type(L, top) == LUA_TNUMBER) {
|
|
float angle = luax_checkfloat(L, index++);
|
|
float ax = luax_checkfloat(L, index++);
|
|
float ay = luax_checkfloat(L, index++);
|
|
float az = luax_checkfloat(L, index++);
|
|
mat4_rotate(m, angle, ax, ay, az);
|
|
} else {
|
|
float sx, sy, sz;
|
|
|
|
if (vectorType == V_VEC3) {
|
|
sx = v[0];
|
|
sy = v[1];
|
|
sz = v[2];
|
|
index++;
|
|
} else if (lua_type(L, index) == LUA_TNUMBER) {
|
|
sx = luax_checkfloat(L, index++);
|
|
sy = luax_checkfloat(L, index++);
|
|
sz = luax_checkfloat(L, index++);
|
|
} else {
|
|
sx = sy = sz = 1.f;
|
|
}
|
|
|
|
float rotation[4];
|
|
luax_readquat(L, index, rotation, NULL);
|
|
mat4_rotateQuat(m, rotation);
|
|
mat4_scale(m, sx, sy, sz);
|
|
}
|
|
}
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Invert(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_invert(mat4_init(out, m));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Transpose(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_transpose(mat4_init(out, m));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Translate(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = luax_checkfloat(L, 2);
|
|
float y = luax_checkfloat(L, 3);
|
|
float z = luax_checkfloat(L, 4);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_translate(mat4_init(out, m), x, y, z);
|
|
} else {
|
|
float* v = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_translate(mat4_init(out, m), v[0], v[1], v[2]);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Rotate(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float angle = luax_checkfloat(L, 2);
|
|
float ax = luax_optfloat(L, 3, 0.f);
|
|
float ay = luax_optfloat(L, 4, 1.f);
|
|
float az = luax_optfloat(L, 5, 0.f);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_rotate(mat4_init(out, m), angle, ax, ay, az);
|
|
} else {
|
|
float* q = luax_checkvector(L, 2, V_QUAT, "quat or number");
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_rotateQuat(mat4_init(out, m), q);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Scale(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = luax_checkfloat(L, 2);
|
|
float y = luax_optfloat(L, 3, x);
|
|
float z = luax_optfloat(L, 4, x);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_scale(mat4_init(out, m), x, y, z);
|
|
} else {
|
|
float* s = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_scale(mat4_init(out, m), s[0], s[1], s[2]);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Orthographic(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
if (lua_gettop(L) <= 5) {
|
|
float width = luax_checkfloat(L, 2);
|
|
float height = luax_checkfloat(L, 3);
|
|
float n = luax_optfloat(L, 4, -1.f);
|
|
float f = luax_optfloat(L, 5, 1.f);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_orthographic(out, 0.f, width, 0.f, height, n, f);
|
|
} else {
|
|
float left = luax_checkfloat(L, 2);
|
|
float right = luax_checkfloat(L, 3);
|
|
float bottom = luax_checkfloat(L, 4);
|
|
float top = luax_checkfloat(L, 5);
|
|
float n = luax_checkfloat(L, 6);
|
|
float f = luax_checkfloat(L, 7);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_orthographic(out, left, right, bottom, top, n, f);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Perspective(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float fovy = luax_checkfloat(L, 2);
|
|
float aspect = luax_checkfloat(L, 3);
|
|
float n = luax_checkfloat(L, 4);
|
|
float f = luax_optfloat(L, 5, 0.);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_perspective(out, fovy, aspect, n, f);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Fov(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float left = luax_checkfloat(L, 2);
|
|
float right = luax_checkfloat(L, 3);
|
|
float up = luax_checkfloat(L, 4);
|
|
float down = luax_checkfloat(L, 5);
|
|
float n = luax_checkfloat(L, 6);
|
|
float f = luax_optfloat(L, 7, 0.);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_fov(out, left, right, up, down, n, f);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4LookAt(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
vec3 from = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3 to = luax_checkvector(L, 3, V_VEC3, NULL);
|
|
vec3 up = lua_isnoneornil(L, 4) ? (float[3]) { 0.f, 1.f, 0.f } : luax_checkvector(L, 4, V_VEC3, NULL);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_lookAt(out, from, to, up);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Target(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
vec3 from = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3 to = luax_checkvector(L, 3, V_VEC3, NULL);
|
|
vec3 up = lua_isnoneornil(L, 4) ? (float[3]) { 0.f, 1.f, 0.f } : luax_checkvector(L, 4, V_VEC3, NULL);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_target(out, from, to, up);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Reflect(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
vec3 position = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3 normal = luax_checkvector(L, 3, V_VEC3, NULL);
|
|
float* out = luax_newvector(L, V_MAT4);
|
|
mat4_reflect(out, position, normal);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4__mul(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
int type;
|
|
float* n = luax_tovector(L, 2, &type);
|
|
if (!n || (type == V_VEC2 || type == V_QUAT)) return luax_typeerror(L, 2, "mat4, vec3, or vec4");
|
|
if (type == V_MAT4) {
|
|
mat4 out = luax_newvector(L, V_MAT4);
|
|
mat4_mul(mat4_init(out, m), n);
|
|
} else if (type == V_VEC3) {
|
|
vec3 out = luax_newvector(L, V_VEC3);
|
|
vec3_init(out, n);
|
|
mat4_mulPoint(m, out);
|
|
} else if (type == V_VEC4) {
|
|
float* out = luax_newvector(L, V_VEC4);
|
|
memcpy(out, n, 4 * sizeof(float));
|
|
mat4_mulVec4(m, out);
|
|
} else {
|
|
lovrUnreachable();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4__tostring(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
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],
|
|
m[1], m[5], m[9], m[13],
|
|
m[2], m[6], m[10], m[14],
|
|
m[3], m[7], m[11], m[15]);
|
|
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);
|
|
return luaL_error(L, "attempt to assign property %s of mat4 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
static int l_lovrMat4__index(lua_State* L) {
|
|
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);
|
|
return luaL_error(L, "attempt to index field %s of mat4 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
int l_lovrMat4__metaindex(lua_State* L) {
|
|
if (lua_type(L, 2) != LUA_TSTRING) {
|
|
return 0;
|
|
}
|
|
|
|
size_t length;
|
|
const char* key = lua_tolstring(L, 2, &length);
|
|
|
|
static struct { StringEntry name; float m[16]; } properties[] = {
|
|
{ ENTRY("identity"), MAT4_IDENTITY }
|
|
};
|
|
|
|
for (uint32_t i = 0; i < COUNTOF(properties); i++) {
|
|
if (length == properties[i].name.length && !memcmp(key, properties[i].name.string, length)) {
|
|
float* m = luax_newvector(L, V_MAT4);
|
|
mat4_set(m, properties[i].m);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const luaL_Reg lovrMat4[] = {
|
|
{ "type", l_lovrMat4Type },
|
|
{ "equals", l_lovrMat4Equals },
|
|
{ "unpack", l_lovrMat4Unpack },
|
|
{ "getPosition", l_lovrMat4GetPosition },
|
|
{ "getOrientation", l_lovrMat4GetOrientation },
|
|
{ "getScale", l_lovrMat4GetScale },
|
|
{ "getPose", l_lovrMat4GetPose },
|
|
{ "set", l_lovrMat4Set },
|
|
{ "invert", l_lovrMat4Invert },
|
|
{ "transpose", l_lovrMat4Transpose },
|
|
{ "translate", l_lovrMat4Translate },
|
|
{ "rotate", l_lovrMat4Rotate },
|
|
{ "scale", l_lovrMat4Scale },
|
|
{ "orthographic", l_lovrMat4Orthographic },
|
|
{ "perspective", l_lovrMat4Perspective },
|
|
{ "fov", l_lovrMat4Fov },
|
|
{ "lookAt", l_lovrMat4LookAt },
|
|
{ "target", l_lovrMat4Target },
|
|
{ "reflect", l_lovrMat4Reflect },
|
|
{ "__mul", l_lovrMat4__mul },
|
|
{ "__tostring", l_lovrMat4__tostring },
|
|
{ "__newindex", l_lovrMat4__newindex },
|
|
{ "__index", l_lovrMat4__index },
|
|
{ NULL, NULL }
|
|
};
|