mirror of https://github.com/bjornbytes/lovr.git
2020 lines
56 KiB
C
2020 lines
56 KiB
C
#include "api.h"
|
|
#include "core/maf.h"
|
|
#include "util.h"
|
|
#include <lua.h>
|
|
#include <lauxlib.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_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;
|
|
case LUA_TNUMBER:
|
|
v[0] = luax_optfloat(L, index++, 0.f);
|
|
v[1] = luax_optfloat(L, index++, 0.f);
|
|
v[2] = luax_optfloat(L, index++, 0.f);
|
|
return index;
|
|
default:
|
|
vec3_init(v, luax_checkvector(L, index++, V_VEC3, expected ? expected : "vec3 or number"));
|
|
return index;
|
|
}
|
|
}
|
|
|
|
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_optfloat(L, index++, 0.f);
|
|
} else {
|
|
v[0] = 1.f;
|
|
for (int i = 0; i < components; i++) {
|
|
v[i] = luax_optfloat(L, index++, v[0]);
|
|
}
|
|
}
|
|
return index;
|
|
default: {
|
|
VectorType 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: {
|
|
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[4];
|
|
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);
|
|
m[15] = 1.f;
|
|
mat4_rotateQuat(m, R);
|
|
mat4_scale(m, S[0], S[1], S[2]);
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
|
|
// vec2
|
|
|
|
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);
|
|
float dx = v[0] - u[0];
|
|
float dy = v[1] - u[1];
|
|
float distance2 = dx * dx + dy * dy;
|
|
bool equal = distance2 < EQ_THRESHOLD;
|
|
lua_pushboolean(L, equal);
|
|
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);
|
|
if (lua_isnoneornil(L, 2) || lua_type(L, 2) == LUA_TNUMBER) {
|
|
v[0] = luax_optfloat(L, 2, 0.f);
|
|
v[1] = luax_optfloat(L, 3, v[0]);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
v[0] = u[0];
|
|
v[1] = u[1];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Add(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] += x;
|
|
v[1] += luax_optfloat(L, 3, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
v[0] += u[0];
|
|
v[1] += u[1];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Sub(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] -= x;
|
|
v[1] -= luax_optfloat(L, 3, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
v[0] -= u[0];
|
|
v[1] -= u[1];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Mul(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] *= x;
|
|
v[1] *= luax_optfloat(L, 3, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
v[0] *= u[0];
|
|
v[1] *= u[1];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Div(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] /= x;
|
|
v[1] /= luax_optfloat(L, 3, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
v[0] /= u[0];
|
|
v[1] /= u[1];
|
|
}
|
|
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, sqrtf(v[0] * v[0] + v[1] * v[1]));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Normalize(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float length = v[0] * v[0] + v[1] * v[1];
|
|
if (length != 0.f) {
|
|
length = 1.f / sqrtf(length);
|
|
v[0] *= length;
|
|
v[1] *= length;
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Distance(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u;
|
|
float uvec[2];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
}
|
|
float dx = v[0] - u[0];
|
|
float dy = v[1] - u[1];
|
|
lua_pushnumber(L, sqrtf(dx * dx + dy * dy));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Dot(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u;
|
|
float uvec[2];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
}
|
|
lua_pushnumber(L, v[0] * u[0] + v[1] * u[1]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Lerp(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u;
|
|
float uvec[2];
|
|
float t;
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
u = uvec;
|
|
t = luax_checkfloat(L, 4);
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
t = luax_checkfloat(L, 3);
|
|
}
|
|
v[0] = v[0] + (u[0] - v[0]) * t;
|
|
v[1] = v[1] + (u[1] - v[1]) * t;
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2Angle(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* u;
|
|
float uvec[2];
|
|
float dot, length_v, length_u;
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC2, "vec2 or number");
|
|
}
|
|
length_v = sqrtf(v[0] * v[0] + v[1] * v[1]);
|
|
length_u = sqrtf(u[0] * u[0] + u[1] * u[1]);
|
|
if ((length_v == 0.f) || (length_u == 0.f)) {
|
|
lua_pushnumber(L, (float) M_PI / 2.f);
|
|
} else {
|
|
dot = v[0] * u[0] + v[1] * u[1];
|
|
lua_pushnumber(L, acosf(dot / (length_v * length_u)));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__add(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] + x;
|
|
out[1] = u[1] + x;
|
|
} 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");
|
|
out[0] = v[0] + u[0];
|
|
out[1] = v[1] + u[1];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__sub(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] - x;
|
|
out[1] = u[1] - x;
|
|
} 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");
|
|
out[0] = v[0] - u[0];
|
|
out[1] = v[1] - u[1];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__mul(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] * x;
|
|
out[1] = u[1] * x;
|
|
} 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");
|
|
out[0] = v[0] * u[0];
|
|
out[1] = v[1] * u[1];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__div(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] / x;
|
|
out[1] = u[1] / x;
|
|
} 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");
|
|
out[0] = v[0] / u[0];
|
|
out[1] = v[1] / u[1];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__unm(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
float* out = luax_newtempvector(L, V_VEC2);
|
|
out[0] = -v[0];
|
|
out[1] = -v[1];
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec2__len(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC2, NULL);
|
|
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1]));
|
|
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) {
|
|
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* 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_newtempvector(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_newtempvector(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_newtempvector(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));
|
|
}
|
|
|
|
const luaL_Reg lovrVec2[] = {
|
|
{ "equals", l_lovrVec2Equals },
|
|
{ "unpack", l_lovrVec2Unpack },
|
|
{ "set", l_lovrVec2Set },
|
|
{ "add", l_lovrVec2Add },
|
|
{ "sub", l_lovrVec2Sub },
|
|
{ "mul", l_lovrVec2Mul },
|
|
{ "div", l_lovrVec2Div },
|
|
{ "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_lovrVec3Equals(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
float dx = v[0] - u[0];
|
|
float dy = v[1] - u[1];
|
|
float dz = v[2] - u[2];
|
|
float distance2 = dx * dx + dy * dy + dz * dz;
|
|
bool equal = distance2 < EQ_THRESHOLD;
|
|
lua_pushboolean(L, equal);
|
|
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 {
|
|
VectorType 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{
|
|
luax_typeerror(L, 2, "vec3, mat4, or number");
|
|
}
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Add(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] += x;
|
|
v[1] += luax_optfloat(L, 3, x);
|
|
v[2] += luax_optfloat(L, 4, x);
|
|
v[3] += 0.f;
|
|
} else {
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
vec3_add(v, u);
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Sub(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] -= x;
|
|
v[1] -= luax_optfloat(L, 3, x);
|
|
v[2] -= luax_optfloat(L, 4, x);
|
|
v[3] -= 0.f;
|
|
} else {
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
vec3_sub(v, u);
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Mul(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] *= x;
|
|
v[1] *= luax_optfloat(L, 3, x);
|
|
v[2] *= luax_optfloat(L, 4, x);
|
|
} else {
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
v[0] *= u[0];
|
|
v[1] *= u[1];
|
|
v[2] *= u[2];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Div(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] /= x;
|
|
v[1] /= luax_optfloat(L, 3, x);
|
|
v[2] /= luax_optfloat(L, 4, x);
|
|
} else {
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
v[0] /= u[0];
|
|
v[1] /= u[1];
|
|
v[2] /= u[2];
|
|
}
|
|
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);
|
|
vec3_normalize(v);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Distance(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u;
|
|
float uvec[4];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
}
|
|
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);
|
|
vec3 u;
|
|
float uvec[4];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
}
|
|
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);
|
|
vec3 u;
|
|
float uvec[4];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
}
|
|
vec3_cross(v, u);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Lerp(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u;
|
|
float uvec[4];
|
|
float t;
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
u = uvec;
|
|
t = luax_checkfloat(L, 5);
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
t = luax_checkfloat(L, 3);
|
|
}
|
|
vec3_lerp(v, u, t);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3Angle(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u;
|
|
float uvec[4];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
}
|
|
lua_pushnumber(L, vec3_angle(v, u));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__add(lua_State* L) {
|
|
vec3 out = luax_newtempvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
vec3 v = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
out[0] = v[0] + x;
|
|
out[1] = v[1] + x;
|
|
out[2] = v[2] + x;
|
|
out[3] = v[3] + x;
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, 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 {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
out[0] = v[0] + u[0], out[1] = v[1] + u[1], out[2] = v[2] + u[2], out[3] = v[3] + u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__sub(lua_State* L) {
|
|
vec3 out = luax_newtempvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 1);
|
|
vec3 v = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
out[0] = v[0] - x;
|
|
out[1] = v[1] - x;
|
|
out[2] = v[2] - x;
|
|
out[3] = v[3] - x;
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, 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 {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
out[0] = v[0] - u[0], out[1] = v[1] - u[1], out[2] = v[2] - u[2], out[3] = v[3] - u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__mul(lua_State* L) {
|
|
vec3 out = luax_newtempvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3_scale(vec3_init(out, u), lua_tonumber(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), lua_tonumber(L, 2));
|
|
} else {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
out[0] = v[0] * u[0], out[1] = v[1] * u[1], out[2] = v[2] * u[2], out[3] = v[3] * u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__div(lua_State* L) {
|
|
vec3 out = luax_newtempvector(L, V_VEC3);
|
|
if (lua_type(L, 1) == LUA_TNUMBER) {
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, NULL);
|
|
vec3_init(out, u);
|
|
vec3_scale(out, 1. / lua_tonumber(L, 1));
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3_init(out, v);
|
|
vec3_scale(out, 1. / lua_tonumber(L, 2));
|
|
} else {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 u = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
out[0] = v[0] / u[0], out[1] = v[1] / u[1], out[2] = v[2] / u[2], out[3] = v[3] / u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec3__unm(lua_State* L) {
|
|
vec3 v = luax_checkvector(L, 1, V_VEC3, NULL);
|
|
vec3 out = luax_newtempvector(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];
|
|
}
|
|
}
|
|
}
|
|
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) {
|
|
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* 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_newtempvector(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_newtempvector(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_newtempvector(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));
|
|
}
|
|
|
|
const luaL_Reg lovrVec3[] = {
|
|
{ "equals", l_lovrVec3Equals },
|
|
{ "unpack", l_lovrVec3Unpack },
|
|
{ "set", l_lovrVec3Set },
|
|
{ "add", l_lovrVec3Add },
|
|
{ "sub", l_lovrVec3Sub },
|
|
{ "mul", l_lovrVec3Mul },
|
|
{ "div", l_lovrVec3Div },
|
|
{ "length", l_lovrVec3Length },
|
|
{ "normalize", l_lovrVec3Normalize },
|
|
{ "distance", l_lovrVec3Distance },
|
|
{ "dot", l_lovrVec3Dot },
|
|
{ "cross", l_lovrVec3Cross },
|
|
{ "lerp", l_lovrVec3Lerp },
|
|
{ "angle", l_lovrVec3Angle },
|
|
{ "__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_lovrVec4Equals(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u = luax_checkvector(L, 2, V_VEC4, NULL);
|
|
float dx = v[0] - u[0];
|
|
float dy = v[1] - u[1];
|
|
float dz = v[2] - u[2];
|
|
float dw = v[3] - u[3];
|
|
float distance2 = dx * dx + dy * dy + dz * dz + dw * dw;
|
|
bool equal = distance2 < EQ_THRESHOLD;
|
|
lua_pushboolean(L, equal);
|
|
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);
|
|
if (lua_isnoneornil(L, 2) || lua_type(L, 2) == LUA_TNUMBER) {
|
|
v[0] = luax_optfloat(L, 2, 0.f);
|
|
v[1] = luax_optfloat(L, 3, v[0]);
|
|
v[2] = luax_optfloat(L, 4, v[0]);
|
|
v[3] = luax_optfloat(L, 5, v[0]);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
v[0] = u[0];
|
|
v[1] = u[1];
|
|
v[2] = u[2];
|
|
v[3] = u[3];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Add(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] += x;
|
|
v[1] += luax_optfloat(L, 3, x);
|
|
v[2] += luax_optfloat(L, 4, x);
|
|
v[3] += luax_optfloat(L, 5, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
v[0] += u[0];
|
|
v[1] += u[1];
|
|
v[2] += u[2];
|
|
v[3] += u[3];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Sub(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] -= x;
|
|
v[1] -= luax_optfloat(L, 3, x);
|
|
v[2] -= luax_optfloat(L, 4, x);
|
|
v[3] -= luax_optfloat(L, 5, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
v[0] -= u[0];
|
|
v[1] -= u[1];
|
|
v[2] -= u[2];
|
|
v[3] -= u[3];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Mul(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] *= x;
|
|
v[1] *= luax_optfloat(L, 3, x);
|
|
v[2] *= luax_optfloat(L, 4, x);
|
|
v[3] *= luax_optfloat(L, 5, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
v[0] *= u[0];
|
|
v[1] *= u[1];
|
|
v[2] *= u[2];
|
|
v[3] *= u[3];
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Div(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = lua_tonumber(L, 2);
|
|
v[0] /= x;
|
|
v[1] /= luax_optfloat(L, 3, x);
|
|
v[2] /= luax_optfloat(L, 4, x);
|
|
v[3] /= luax_optfloat(L, 5, x);
|
|
} else {
|
|
float* u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
v[0] /= u[0];
|
|
v[1] /= u[1];
|
|
v[2] /= u[2];
|
|
v[3] /= u[3];
|
|
}
|
|
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, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Normalize(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
|
|
if (length != 0.f) {
|
|
length = 1.f / sqrtf(length);
|
|
v[0] *= length;
|
|
v[1] *= length;
|
|
v[2] *= length;
|
|
v[3] *= length;
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Distance(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u;
|
|
float uvec[4];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);;
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
uvec[3] = luax_checkfloat(L, 5);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
}
|
|
float dx = v[0] - u[0];
|
|
float dy = v[1] - u[1];
|
|
float dz = v[2] - u[2];
|
|
float dw = v[3] - u[3];
|
|
lua_pushnumber(L, sqrtf(dx * dx + dy * dy + dz * dz + dw * dw));
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Dot(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u;
|
|
float uvec[4];
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
uvec[3] = luax_checkfloat(L, 5);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
}
|
|
lua_pushnumber(L, v[0] * u[0] + v[1] * u[1] + v[2] * u[2] + v[3] * u[3]);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Lerp(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u;
|
|
float uvec[4];
|
|
float t;
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
uvec[3] = luax_checkfloat(L, 5);
|
|
u = uvec;
|
|
t = luax_checkfloat(L, 6);
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
t = luax_checkfloat(L, 3);
|
|
}
|
|
v[0] = v[0] + (u[0] - v[0]) * t;
|
|
v[1] = v[1] + (u[1] - v[1]) * t;
|
|
v[2] = v[2] + (u[2] - v[2]) * t;
|
|
v[3] = v[3] + (u[3] - v[3]) * t;
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4Angle(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* u;
|
|
float uvec[4];
|
|
float dot, length_v, length_u;
|
|
if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
uvec[0] = lua_tonumber(L, 2);
|
|
uvec[1] = luax_checkfloat(L, 3);
|
|
uvec[2] = luax_checkfloat(L, 4);
|
|
uvec[3] = luax_checkfloat(L, 5);
|
|
u = uvec;
|
|
} else {
|
|
u = luax_checkvector(L, 2, V_VEC4, "vec4 or number");
|
|
}
|
|
length_v = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
|
length_u = sqrtf(u[0] * u[0] + u[1] * u[1] + u[2] * u[2] + u[3] * u[3]);
|
|
if ((length_v == 0.f) || (length_u == 0.f)) {
|
|
lua_pushnumber(L, (float) M_PI / 2);
|
|
} else {
|
|
dot = v[0] * u[0] + v[1] * u[1] + v[2] * u[2] + v[3] * u[3];
|
|
lua_pushnumber(L, acosf(dot / (length_v * length_u)));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__add(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] + x;
|
|
out[1] = u[1] + x;
|
|
out[2] = u[2] + x;
|
|
out[3] = u[3] + x;
|
|
} 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");
|
|
out[0] = v[0] + u[0];
|
|
out[1] = v[1] + u[1];
|
|
out[2] = v[2] + u[2];
|
|
out[3] = v[3] + u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__sub(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] - x;
|
|
out[1] = u[1] - x;
|
|
out[2] = u[2] - x;
|
|
out[3] = u[3] - x;
|
|
} 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");
|
|
out[0] = v[0] - u[0];
|
|
out[1] = v[1] - u[1];
|
|
out[2] = v[2] - u[2];
|
|
out[3] = v[3] - u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__mul(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] * x;
|
|
out[1] = u[1] * x;
|
|
out[2] = u[2] * x;
|
|
out[3] = u[3] * x;
|
|
} 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");
|
|
out[0] = v[0] * u[0];
|
|
out[1] = v[1] * u[1];
|
|
out[2] = v[2] * u[2];
|
|
out[3] = v[3] * u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__div(lua_State* L) {
|
|
float* out = luax_newtempvector(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] = u[0] / x;
|
|
out[1] = u[1] / x;
|
|
out[2] = u[2] / x;
|
|
out[3] = u[3] / x;
|
|
} 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");
|
|
out[0] = v[0] / u[0];
|
|
out[1] = v[1] / u[1];
|
|
out[2] = v[2] / u[2];
|
|
out[3] = v[3] / u[3];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__unm(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
float* out = luax_newtempvector(L, V_VEC4);
|
|
out[0] = -v[0];
|
|
out[1] = -v[1];
|
|
out[2] = -v[2];
|
|
out[3] = -v[3];
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrVec4__len(lua_State* L) {
|
|
float* v = luax_checkvector(L, 1, V_VEC4, NULL);
|
|
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]));
|
|
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) {
|
|
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* 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_newtempvector(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_newtempvector(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_newtempvector(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));
|
|
}
|
|
|
|
const luaL_Reg lovrVec4[] = {
|
|
{ "equals", l_lovrVec4Equals },
|
|
{ "unpack", l_lovrVec4Unpack },
|
|
{ "set", l_lovrVec4Set },
|
|
{ "add", l_lovrVec4Add },
|
|
{ "sub", l_lovrVec4Sub },
|
|
{ "mul", l_lovrVec4Mul },
|
|
{ "div", l_lovrVec4Div },
|
|
{ "length", l_lovrVec4Length },
|
|
{ "normalize", l_lovrVec4Normalize },
|
|
{ "distance", l_lovrVec4Distance },
|
|
{ "dot", l_lovrVec4Dot },
|
|
{ "lerp", l_lovrVec4Lerp },
|
|
{ "angle", l_lovrVec4Angle },
|
|
{ "__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_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 {
|
|
VectorType 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 {
|
|
quat_between(q, (float[4]) { 0.f, 0.f, -1.f }, 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_lovrQuatMul(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
VectorType type;
|
|
float* r = luax_tovector(L, 2, &type);
|
|
if (!r || (type != V_VEC3 && type != V_QUAT)) return luax_typeerror(L, 2, "quat or vec3");
|
|
if (type == V_VEC3) {
|
|
quat_rotate(q, r);
|
|
lua_settop(L, 2);
|
|
} else {
|
|
quat_mul(q, q, r);
|
|
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);
|
|
quat_normalize(q);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuatDirection(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
vec3 v = luax_newtempvector(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);
|
|
quat_conjugate(q);
|
|
lua_settop(L, 1);
|
|
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);
|
|
quat_slerp(q, r, t);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrQuat__mul(lua_State* L) {
|
|
quat q = luax_checkvector(L, 1, V_QUAT, NULL);
|
|
VectorType 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_newtempvector(L, V_VEC3);
|
|
quat_rotate(q, vec3_init(out, r));
|
|
} else {
|
|
quat out = luax_newtempvector(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) {
|
|
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* 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));
|
|
}
|
|
|
|
const luaL_Reg lovrQuat[] = {
|
|
{ "equals", l_lovrQuatEquals },
|
|
{ "unpack", l_lovrQuatUnpack },
|
|
{ "set", l_lovrQuatSet },
|
|
{ "mul", l_lovrQuatMul },
|
|
{ "length", l_lovrQuatLength },
|
|
{ "normalize", l_lovrQuatNormalize },
|
|
{ "direction", l_lovrQuatDirection },
|
|
{ "conjugate", l_lovrQuatConjugate },
|
|
{ "slerp", l_lovrQuatSlerp },
|
|
{ "__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_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[4], scale[4], 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;
|
|
}
|
|
}
|
|
|
|
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 {
|
|
VectorType 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[4];
|
|
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 {
|
|
if (vectorType == V_VEC3) {
|
|
m[0] = v[0];
|
|
m[5] = v[1];
|
|
m[10] = v[2];
|
|
index++;
|
|
} else if (lua_type(L, index) == LUA_TNUMBER) {
|
|
m[0] = luax_checkfloat(L, index++);
|
|
m[5] = luax_checkfloat(L, index++);
|
|
m[10] = luax_checkfloat(L, index++);
|
|
}
|
|
|
|
float rotation[4];
|
|
luax_readquat(L, index, rotation, NULL);
|
|
mat4_rotateQuat(m, rotation);
|
|
}
|
|
}
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
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);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
} else if (n && type == V_VEC3) {
|
|
mat4_transform(m, n);
|
|
lua_settop(L, 2);
|
|
return 1;
|
|
} else if (n && type == V_VEC4) {
|
|
mat4_mulVec4(m, n);
|
|
lua_settop(L, 2);
|
|
return 1;
|
|
} else if (lua_type(L, 2) == LUA_TNUMBER) {
|
|
float x = luaL_checknumber(L, 2);
|
|
float y = luaL_optnumber(L, 3, 0.f);
|
|
float z = luaL_optnumber(L, 4, 0.f);
|
|
float v[4] = { x, y, z };
|
|
mat4_transform(m, v);
|
|
lua_pushnumber(L, v[0]);
|
|
lua_pushnumber(L, v[1]);
|
|
lua_pushnumber(L, v[2]);
|
|
return 3;
|
|
} else {
|
|
return luax_typeerror(L, 2, "mat4, vec3, or number");
|
|
}
|
|
}
|
|
|
|
static int l_lovrMat4Identity(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
mat4_identity(m);
|
|
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);
|
|
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);
|
|
lua_settop(L, 1);
|
|
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) {
|
|
mat4_translate(m, luax_checkfloat(L, 2), luax_checkfloat(L, 3), luax_checkfloat(L, 4));
|
|
} else {
|
|
float* v = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
mat4_translate(m, v[0], v[1], v[2]);
|
|
}
|
|
lua_settop(L, 1);
|
|
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) {
|
|
mat4_rotate(m, luax_checkfloat(L, 2), luax_optfloat(L, 3, 0.f), luax_optfloat(L, 4, 1.f), luax_optfloat(L, 5, 0.f));
|
|
} else {
|
|
float* q = luax_checkvector(L, 2, V_QUAT, "quat or number");
|
|
mat4_rotateQuat(m, q);
|
|
}
|
|
lua_settop(L, 1);
|
|
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);
|
|
mat4_scale(m, x, luax_optfloat(L, 3, x), luax_optfloat(L, 4, x));
|
|
} else {
|
|
float* s = luax_checkvector(L, 2, V_VEC3, "vec3 or number");
|
|
mat4_scale(m, s[0], s[1], s[2]);
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Orthographic(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float left = luax_checkfloat(L, 2);
|
|
float right = luax_checkfloat(L, 3);
|
|
float top = luax_checkfloat(L, 4);
|
|
float bottom = luax_checkfloat(L, 5);
|
|
float clipNear = luax_checkfloat(L, 6);
|
|
float clipFar = luax_checkfloat(L, 7);
|
|
mat4_orthographic(m, left, right, top, bottom, clipNear, clipFar);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Perspective(lua_State* L) {
|
|
mat4 m = luax_checkvector(L, 1, V_MAT4, NULL);
|
|
float clipNear = luax_checkfloat(L, 2);
|
|
float clipFar = luax_checkfloat(L, 3);
|
|
float fov = luax_checkfloat(L, 4);
|
|
float aspect = luax_checkfloat(L, 5);
|
|
mat4_perspective(m, clipNear, clipFar, fov, aspect);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Fov(lua_State* L) {
|
|
mat4 m = 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 clipNear = luax_checkfloat(L, 6);
|
|
float clipFar = luax_checkfloat(L, 7);
|
|
mat4_fov(m, left, right, up, down, clipNear, clipFar);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4LookAt(lua_State* L) {
|
|
mat4 m = 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[4]) { 0.f, 1.f, 0.f } : luax_checkvector(L, 4, V_VEC3, NULL);
|
|
mat4_lookAt(m, from, to, up);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4Target(lua_State* L) {
|
|
mat4 m = 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[4]) { 0.f, 1.f, 0.f } : luax_checkvector(L, 4, V_VEC3, NULL);
|
|
mat4_target(m, from, to, up);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4__mul(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_VEC2 || type == V_QUAT)) return luax_typeerror(L, 2, "mat4, vec3, or vec4");
|
|
if (type == V_MAT4) {
|
|
mat4 out = luax_newtempvector(L, V_MAT4);
|
|
mat4_mul(mat4_init(out, m), n);
|
|
} else if (type == V_VEC3) {
|
|
vec3 out = luax_newtempvector(L, V_VEC3);
|
|
vec3_init(out, n);
|
|
mat4_transform(m, out);
|
|
} else if (type == V_VEC4) {
|
|
float* out = luax_newtempvector(L, V_VEC4);
|
|
memcpy(out, n, 4 * sizeof(float));
|
|
mat4_mulVec4(m, out);
|
|
} else {
|
|
lovrThrow("Unreachable");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int l_lovrMat4__tostring(lua_State* L) {
|
|
luax_checkvector(L, 1, V_MAT4, NULL);
|
|
lua_pushliteral(L, "mat4");
|
|
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) {
|
|
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);
|
|
return luaL_error(L, "attempt to index field %s of mat4 (invalid property)", lua_tostring(L, -1));
|
|
}
|
|
|
|
const luaL_Reg lovrMat4[] = {
|
|
{ "equals", l_lovrMat4Equals },
|
|
{ "unpack", l_lovrMat4Unpack },
|
|
{ "set", l_lovrMat4Set },
|
|
{ "mul", l_lovrMat4Mul },
|
|
{ "identity", l_lovrMat4Identity },
|
|
{ "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 },
|
|
{ "__mul", l_lovrMat4__mul },
|
|
{ "__tostring", l_lovrMat4__tostring },
|
|
{ "__newindex", l_lovrMat4__newindex },
|
|
{ "__index", l_lovrMat4__index },
|
|
{ NULL, NULL }
|
|
};
|