3472 lines
81 KiB
C
3472 lines
81 KiB
C
#include"luaapi.h"
|
|
|
|
#include"resman.h"
|
|
#include<lua.h>
|
|
#include<lualib.h>
|
|
#include<lauxlib.h>
|
|
#include"game.h"
|
|
#include"k3mix.h"
|
|
#include"k3water.h"
|
|
#include"net_server.h"
|
|
#include"net_client.h"
|
|
#include"gl.h"
|
|
#include"k4.h"
|
|
#include"net.h"
|
|
#include"k3menu.h"
|
|
#include<assert.h>
|
|
|
|
/*
|
|
* This is by far the least clean or well-maintained source in the
|
|
* entire project. Touch it as little as possible to minimize loss
|
|
* of sanity.
|
|
* */
|
|
|
|
static lua_State *L;
|
|
|
|
#define seti(src, dst) \
|
|
lua_getfield(L, -1, src);\
|
|
li = lua_tointegerx(L, -1, &i);\
|
|
if(i) {\
|
|
dst = li;\
|
|
}\
|
|
lua_pop(L, 1);
|
|
|
|
#define setf(src, dst) \
|
|
lua_getfield(L, -1, src);\
|
|
dst = lua_tonumber(L, -1);\
|
|
lua_pop(L, 1);
|
|
|
|
#define setv3(src, dst) \
|
|
lua_getfield(L, -1, src);\
|
|
if(lua_istable(L, -1)) {\
|
|
lua_geti(L, -1, 1);\
|
|
lua_geti(L, -2, 2);\
|
|
lua_geti(L, -3, 3);\
|
|
dst[0] = lua_tonumber(L, -3);\
|
|
dst[1] = lua_tonumber(L, -2);\
|
|
dst[2] = lua_tonumber(L, -1);\
|
|
lua_pop(L, 3);\
|
|
}\
|
|
lua_pop(L, 1);
|
|
|
|
#define setv4(src, dst) \
|
|
lua_getfield(L, -1, src);\
|
|
if(lua_istable(L, -1)) {\
|
|
lua_geti(L, -1, 1);\
|
|
lua_geti(L, -2, 2);\
|
|
lua_geti(L, -3, 3);\
|
|
lua_geti(L, -3, 4);\
|
|
dst[0] = lua_tonumber(L, -4);\
|
|
dst[1] = lua_tonumber(L, -3);\
|
|
dst[2] = lua_tonumber(L, -2);\
|
|
dst[3] = lua_tonumber(L, -1);\
|
|
lua_pop(L, 4);\
|
|
}\
|
|
lua_pop(L, 1);
|
|
|
|
#define setstrstatic(src, dst, maxlen) \
|
|
lua_getfield(L, -1, src);\
|
|
if(lua_isstring(L, -1)) {\
|
|
size_t len;\
|
|
const char *s = lua_tolstring(L, -1, &len);\
|
|
strncpy(dst, s, (maxlen) - 1);\
|
|
}\
|
|
lua_pop(L, 1);
|
|
|
|
static int serialize(struct bstr *b) {
|
|
int top = lua_gettop(L);
|
|
|
|
if(lua_type(L, -1) == LUA_TNIL) {
|
|
b_wu8(b, 0);
|
|
} else if(lua_type(L, -1) == LUA_TNUMBER) {
|
|
if(lua_isinteger(L, -1)) {
|
|
b_wu8(b, 1);
|
|
b_wu64(b, lua_tointeger(L, -1));
|
|
} else {
|
|
b_wu8(b, 2);
|
|
b_wf64(b, lua_tonumber(L, -1));
|
|
}
|
|
} else if(lua_type(L, -1) == LUA_TSTRING) {
|
|
b_wu8(b, 3);
|
|
|
|
size_t len;
|
|
const uint8_t *data = lua_tolstring(L, -1, &len);
|
|
|
|
b_wu32(b, len);
|
|
b_wraw(b, data, len);
|
|
} else if(lua_type(L, -1) == LUA_TBOOLEAN) {
|
|
b_wu8(b, lua_toboolean(L, -1) ? 5 : 4);
|
|
} else if(lua_type(L, -1) == LUA_TTABLE) {
|
|
b_wu8(b, 6);
|
|
|
|
lua_pushnil(L);
|
|
|
|
while(lua_next(L, -2)) {
|
|
|
|
lua_pushvalue(L, -2);
|
|
if(!serialize(b)) goto error;
|
|
lua_pop(L, 1);
|
|
|
|
if(!serialize(b)) goto error;
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
b_wu8(b, 0);
|
|
} else goto error;
|
|
|
|
return 1;
|
|
|
|
error:
|
|
|
|
lua_settop(L, top);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int deserialize(struct bstr *b) {
|
|
uint8_t type = b_ru8(b);
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
if(type == 0) {
|
|
lua_pushnil(L);
|
|
} else if(type == 1) {
|
|
lua_pushinteger(L, b_ru64(b));
|
|
} else if(type == 2) {
|
|
lua_pushnumber(L, b_rf64(b));
|
|
} else if(type == 3) {
|
|
size_t len = b_ru32(b);
|
|
|
|
lua_pushlstring(L, b_rraw(b, len), len);
|
|
} else if(type == 4) {
|
|
lua_pushboolean(L, 0);
|
|
} else if(type == 5) {
|
|
lua_pushboolean(L, 1);
|
|
} else if(type == 6) {
|
|
lua_newtable(L);
|
|
|
|
while(1) {
|
|
deserialize(b);
|
|
|
|
if(lua_type(L, -1) == LUA_TNIL) {
|
|
lua_pop(L, 1);
|
|
break;
|
|
}
|
|
|
|
deserialize(b);
|
|
|
|
lua_rawset(L, -3);
|
|
}
|
|
} else goto error;
|
|
|
|
return 1;
|
|
|
|
error:
|
|
|
|
lua_settop(L, top);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_addentity(lua_State *L) {
|
|
lua_Integer li;
|
|
int i;
|
|
|
|
uint16_t id;
|
|
|
|
lua_getfield(L, 1, "id");
|
|
if(lua_isnil(L, -1)) {
|
|
id = game_nextid();
|
|
} else {
|
|
id = lua_tointeger(L, -1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
game_claimentid(id);
|
|
|
|
lua_getfield(L, 1, "physics");
|
|
if(lua_istable(L, -1)) {
|
|
struct CPhysics c;
|
|
memset(&c, 0, sizeof(c));
|
|
|
|
c.entity = id;
|
|
|
|
seti("trigger", c.trigger);
|
|
|
|
c.dynamics = CPHYSICS_STATIC;
|
|
lua_getfield(L, -1, "dynamics");
|
|
if(lua_tostring(L, -1)) {
|
|
if(!strcmp("dynamic", lua_tostring(L, -1))) {
|
|
c.dynamics = CPHYSICS_DYNAMIC;
|
|
} else if(!strcmp("static", lua_tostring(L, -1))) {
|
|
c.dynamics = CPHYSICS_STATIC;
|
|
} else if(!strcmp("kinematic", lua_tostring(L, -1))) {
|
|
c.dynamics = CPHYSICS_KINEMATIC;
|
|
} else {
|
|
k3Log(k3_WARN, "Invalid \"dynamics\" field %s", lua_tostring(L, -1));
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "ghost");
|
|
if(lua_toboolean(L, -1)) {
|
|
c.dynamics |= CPHYSICS_GHOST;
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
// Default
|
|
c.type = CPHYSICS_SPHERE;
|
|
c.sphere.radius = 0.25;
|
|
bool found_shape = false;
|
|
|
|
lua_getfield(L, -1, "capsule");
|
|
if(lua_type(L, -1) == LUA_TTABLE) {
|
|
found_shape = true;
|
|
c.type = CPHYSICS_CAPSULE;
|
|
setf("radius", c.capsule.radius);
|
|
setf("length", c.capsule.length);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "box");
|
|
if(lua_type(L, -1) == LUA_TTABLE) {
|
|
found_shape = true;
|
|
c.type = CPHYSICS_BOX;
|
|
setf("w", c.box.w);
|
|
setf("h", c.box.h);
|
|
setf("l", c.box.l);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "sphere");
|
|
if(lua_type(L, -1) == LUA_TTABLE) {
|
|
found_shape = true;
|
|
c.type = CPHYSICS_SPHERE;
|
|
setf("radius", c.sphere.radius);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "trimesh");
|
|
if(lua_type(L, -1) != LUA_TNIL) {
|
|
found_shape = true;
|
|
c.type = CPHYSICS_TRIMESH;
|
|
if(lua_type(L, -1) == LUA_TSTRING) {
|
|
strncpy(c.trimesh.name, lua_tostring(L, -1), sizeof(c.trimesh.name) - 1);
|
|
} else {
|
|
struct TrimeshData *tmd = *(struct TrimeshData**) luaL_checkudata(L, -1, "k3physics");
|
|
|
|
struct ResManRes *res = resman_rev(tmd);
|
|
if(res) {
|
|
res->refs++;
|
|
}
|
|
|
|
c.trimesh.cache = tmd;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
if(!found_shape) {
|
|
k3Log(k3_INFO, "Entity with invalid shape. Falling back to sphere.");
|
|
}
|
|
|
|
setf("speed", c.speed);
|
|
|
|
lua_getfield(L, -1, "mass");
|
|
c.mass = lua_isnil(L, -1) ? 1 : lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "friction");
|
|
c.friction = lua_isnil(L, -1) ? 1.414 : lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
setv3("pos", c.start);
|
|
|
|
c.collide = CATEGORY_STATIC | CATEGORY_ENTITY;
|
|
lua_getfield(L, -1, "collide");
|
|
if(!lua_isnil(L, -1)) {
|
|
c.collide = lua_tointeger(L, -1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "rot");
|
|
if(lua_istable(L, -1)) {
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
c.rot[0] = lua_tonumber(L, -4);
|
|
c.rot[1] = lua_tonumber(L, -3);
|
|
c.rot[2] = lua_tonumber(L, -2);
|
|
c.rot[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 4);
|
|
} else {
|
|
c.rot[0] = 0;
|
|
c.rot[1] = 0;
|
|
c.rot[2] = 0;
|
|
c.rot[3] = 1;
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
game_addcomponent(physics, &c);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "render");
|
|
if(lua_istable(L, -1)) {
|
|
struct CRender c;
|
|
memset(&c, 0, sizeof(c));
|
|
|
|
c.entity = id;
|
|
|
|
setv4("pos", c.pos);
|
|
setv4("rot", c.rot);
|
|
|
|
setstrstatic("mdl", c.mdl, sizeof(c.mdl));
|
|
|
|
//c.animator.base = NULL;
|
|
|
|
game_addcomponent(render, &c);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "movement");
|
|
if(lua_istable(L, -1)) {
|
|
struct CMovement c;
|
|
memset(&c, 0, sizeof(c));
|
|
|
|
c.entity = id;
|
|
|
|
setv3("dir", c.dir);
|
|
|
|
setf("pointing", c.pointing);
|
|
|
|
seti("jump", c.jump);
|
|
seti("canjump", c.canJump);
|
|
|
|
c.holding = ENT_ID_INVALID;
|
|
|
|
game_addcomponent(movement, &c);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "boned");
|
|
if(lua_istable(L, -1)) {
|
|
struct CBoned c;
|
|
memset(&c, 0, sizeof(c));
|
|
|
|
c.entity = id;
|
|
|
|
lua_getfield(L, -1, "size");
|
|
if(lua_isnil(L, -1)) {
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "bones");
|
|
c.size = lua_isnil(L, -1) ? 0 : luaL_len(L, -1);
|
|
} else {
|
|
c.size = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "bones");
|
|
}
|
|
|
|
c.bones = _mm_malloc(sizeof(*c.bones) * c.size, 16);
|
|
|
|
if(lua_isnil(L, -1)) {
|
|
glm_quat_identity_array((versor*) c.bones, c.size * 2);
|
|
} else {
|
|
for(size_t i = 0; i < c.size; i++) {
|
|
lua_rawgeti(L, -1, i + 1); // bone
|
|
|
|
if(lua_isnil(L, -1)) {
|
|
c.bones[i].translation[0] = 0;
|
|
c.bones[i].translation[1] = 0;
|
|
c.bones[i].translation[2] = 0;
|
|
c.bones[i].translation[3] = 1;
|
|
|
|
c.bones[i].rotation[0] = 0;
|
|
c.bones[i].rotation[1] = 0;
|
|
c.bones[i].rotation[2] = 0;
|
|
c.bones[i].rotation[3] = 1;
|
|
} else {
|
|
lua_rawgeti(L, -1, 1); // translation
|
|
lua_rawgeti(L, -1, 1); // x
|
|
lua_rawgeti(L, -2, 2); // y
|
|
lua_rawgeti(L, -3, 3); // z
|
|
lua_rawgeti(L, -4, 4); // w
|
|
c.bones[i].translation[0] = lua_tonumber(L, -4);
|
|
c.bones[i].translation[1] = lua_tonumber(L, -3);
|
|
c.bones[i].translation[2] = lua_tonumber(L, -2);
|
|
c.bones[i].translation[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
|
|
lua_rawgeti(L, -1, 2); // rotation
|
|
lua_rawgeti(L, -1, 1); // x
|
|
lua_rawgeti(L, -2, 2); // y
|
|
lua_rawgeti(L, -3, 3); // z
|
|
lua_rawgeti(L, -4, 4); // w
|
|
c.bones[i].rotation[0] = lua_tonumber(L, -4);
|
|
c.bones[i].rotation[1] = lua_tonumber(L, -3);
|
|
c.bones[i].rotation[2] = lua_tonumber(L, -2);
|
|
c.bones[i].rotation[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "anim");
|
|
if(lua_istable(L, -1)) {
|
|
lua_getfield(L, -1, "id");
|
|
c.anim.id = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "standard");
|
|
c.anim.standard = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
game_addcomponent(boned, &c);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_pushinteger(L, id);
|
|
return 1;
|
|
}
|
|
|
|
double LuaapiStartTime;
|
|
float LuaapiFov = 75;
|
|
|
|
static int gametriggersref;
|
|
static int luaapi_triggerfunc(size_t id, uint16_t ethis, uint16_t ethat, uint8_t event) {
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, gametriggersref);
|
|
lua_rawgeti(L, -1, id);
|
|
|
|
lua_pushinteger(L, id);
|
|
|
|
if(ethis == ENT_ID_INVALID)
|
|
lua_pushnil(L);
|
|
else
|
|
lua_pushinteger(L, ethis);
|
|
|
|
if(ethat == ENT_ID_INVALID)
|
|
lua_pushnil(L);
|
|
else
|
|
lua_pushinteger(L, ethat);
|
|
|
|
lua_pushinteger(L, event);
|
|
|
|
if(lua_pcall(L, 4, 0, 0) != LUA_OK) {
|
|
puts(lua_tolstring(L, -1, NULL));
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
static int game_triggers_set(lua_State *L) {
|
|
size_t idx = lua_tointeger(L, 2);
|
|
if(idx >= 1 && idx <= MAX_TRIGGERS) {
|
|
lua_pushvalue(L, 2);
|
|
lua_pushvalue(L, 3);
|
|
lua_rawset(L, 1);
|
|
|
|
if(idx > Game.triggerCount) {
|
|
Game.triggers = realloc(Game.triggers, sizeof(*Game.triggers) * idx);
|
|
for(size_t j = Game.triggerCount; j < idx; j++) {
|
|
Game.triggers[j] = NULL;
|
|
}
|
|
Game.triggerCount = idx;
|
|
}
|
|
Game.triggers[idx - 1] = luaapi_triggerfunc;
|
|
}
|
|
return 0;
|
|
}
|
|
static int game_triggers_get(lua_State *L) {
|
|
lua_pushvalue(L, 2);
|
|
lua_rawget(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int gameconveyorsref;
|
|
static int game_conveyors_set(lua_State *L) {
|
|
size_t idx = lua_tointeger(L, 2);
|
|
if(idx >= 1 && idx <= MAX_CONVEYORS) {
|
|
if(Game.conveyorCount < idx) {
|
|
Game.conveyors = realloc(Game.conveyors, sizeof(*Game.conveyors) * idx);
|
|
for(size_t i = Game.conveyorCount; i < idx; i++) {
|
|
Game.conveyors[i] = NULL;
|
|
}
|
|
Game.conveyorCount = idx;
|
|
}
|
|
|
|
struct Conveyor *c = Game.conveyors[idx - 1];
|
|
if(!c) {
|
|
c = calloc(sizeof(*c), 1);
|
|
}
|
|
|
|
lua_getfield(L, 3, "entity");
|
|
c->entity = lua_isnil(L, -1) ? ENT_ID_INVALID : lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 3, "active");
|
|
c->active = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 3, "type");
|
|
c->type = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 3, "speed");
|
|
c->speed = lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 3, "position");
|
|
c->position = lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 3, "points");
|
|
c->pointCount = lua_rawlen(L, -1);
|
|
c->points = realloc(c->points, sizeof(*c->points) * c->pointCount);
|
|
for(size_t i = 0; i < c->pointCount; i++) {
|
|
lua_rawgeti(L, -1, i + 1);
|
|
lua_rawgeti(L, -1, 1);
|
|
lua_rawgeti(L, -2, 2);
|
|
lua_rawgeti(L, -3, 3);
|
|
c->points[i][0] = lua_tonumber(L, -3);
|
|
c->points[i][1] = lua_tonumber(L, -2);
|
|
c->points[i][2] = lua_tonumber(L, -1);
|
|
lua_pop(L, 4);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 3, "trigger");
|
|
c->trigger = lua_isnil(L, -1) ? TRIGGER_INVALID : lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
Game.conveyors[idx - 1] = c;
|
|
}
|
|
return 0;
|
|
}
|
|
static int game_conveyors_get(lua_State *L) {
|
|
size_t idx = lua_tointeger(L, 2);
|
|
if(idx >= 1 && idx <= Game.conveyorCount && Game.conveyors[idx - 1]) {
|
|
size_t *z = lua_newuserdata(L, sizeof(*z));
|
|
*z = idx;
|
|
luaL_setmetatable(L, "k3conveyor");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int game_conveyor_set(lua_State *L) {
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
size_t *idxptr = lua_touserdata(L, 1);
|
|
size_t idx = *idxptr;
|
|
|
|
if(idx == 0 || idx > Game.conveyorCount || !Game.conveyors[idx - 1]) {
|
|
return 0;
|
|
}
|
|
|
|
struct Conveyor *conv = Game.conveyors[idx - 1];
|
|
|
|
if(!strcmp(k, "entity")) {
|
|
conv->entity = lua_isnil(L, 3) ? ENT_ID_INVALID : lua_tointeger(L, 3);
|
|
} else if(!strcmp(k, "active")) {
|
|
conv->active = lua_tointeger(L, 3);
|
|
} else if(!strcmp(k, "type")) {
|
|
conv->type = lua_tointeger(L, 3);
|
|
} else if(!strcmp(k, "speed")) {
|
|
conv->speed = lua_tonumber(L, 3);
|
|
} else if(!strcmp(k, "position")) {
|
|
conv->position = lua_tonumber(L, 3);
|
|
} else if(!strcmp(k, "points")) {
|
|
// TODO
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_conveyor_get(lua_State *L) {
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
size_t *idxptr = lua_touserdata(L, 1);
|
|
size_t idx = *idxptr;
|
|
|
|
if(idx == 0 || idx > Game.conveyorCount || !Game.conveyors[idx - 1]) {
|
|
return 0;
|
|
}
|
|
|
|
struct Conveyor *conv = Game.conveyors[idx - 1];
|
|
|
|
if(!strcmp(k, "entity")) {
|
|
if(conv->entity == ENT_ID_INVALID) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushinteger(L, conv->entity);
|
|
}
|
|
} else if(!strcmp(k, "active")) {
|
|
lua_pushinteger(L, conv->active);
|
|
} else if(!strcmp(k, "type")) {
|
|
lua_pushinteger(L, conv->type);
|
|
} else if(!strcmp(k, "speed")) {
|
|
lua_pushnumber(L, conv->speed);
|
|
} else if(!strcmp(k, "position")) {
|
|
lua_pushnumber(L, conv->position);
|
|
} else if(!strcmp(k, "points")) {
|
|
lua_newtable(L);
|
|
for(size_t i = 0; i < conv->pointCount; i++) {
|
|
lua_newtable(L);
|
|
|
|
lua_pushnumber(L, conv->points[i][0]);
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushnumber(L, conv->points[i][1]);
|
|
lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushnumber(L, conv->points[i][2]);
|
|
lua_rawseti(L, -2, 3);
|
|
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
} else return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_water(lua_State *L) {
|
|
void **mat = lua_touserdata(L, 4);
|
|
|
|
struct k3Water **w = lua_newuserdata(L, sizeof(*w));
|
|
*w = k3WaterCreate(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tointeger(L, 3), *mat);
|
|
|
|
luaL_setmetatable(L, "k3water");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_water_simulate(lua_State *L) {
|
|
void **w = lua_touserdata(L, 1);
|
|
k3WaterSimulate(*w, lua_tonumber(L, 2), lua_tonumber(L, 3), lua_tonumber(L, 4), lua_tointeger(L, 5));
|
|
return 0;
|
|
}
|
|
|
|
static int game_water_update(lua_State *L) {
|
|
void **w = lua_touserdata(L, 1);
|
|
k3WaterUpdate(*w);
|
|
return 0;
|
|
}
|
|
|
|
static int game_water_disturb(lua_State *L) {
|
|
void **w = lua_touserdata(L, 1);
|
|
k3WaterDisturb(*w, lua_tonumber(L, 2), lua_tonumber(L, 3), lua_tonumber(L, 4), lua_tonumber(L, 5));
|
|
return 0;
|
|
}
|
|
|
|
struct mixitem {
|
|
void *thing;
|
|
#define MIXITEM_SOURCE 0
|
|
#define MIXITEM_SOUND 1
|
|
#define MIXITEM_QUEUE 2
|
|
#define MIXITEM_POWER 3
|
|
int type;
|
|
};
|
|
|
|
static int dagame_mixsound(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
assert(i->type == MIXITEM_SOURCE);
|
|
|
|
struct mixitem *r = lua_newuserdata(L, sizeof(*r));
|
|
r->type = MIXITEM_SOUND;
|
|
r->thing = k3MixSimple(i->thing);
|
|
|
|
luaL_setmetatable(L, "k3mixwave");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_mixplay(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
assert(i->type != MIXITEM_SOURCE);
|
|
k3MixPlay(i->thing);
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_mixstop(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
assert(i->type != MIXITEM_SOURCE);
|
|
k3MixStop(i->thing);
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_mixpower(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
assert(i->type != MIXITEM_SOURCE);
|
|
|
|
struct k3MixWave *wav = k3MixPowerMeasurement(i->thing);
|
|
|
|
struct mixitem *r = lua_newuserdata(L, sizeof(*r));
|
|
r->thing = wav;
|
|
r->type = MIXITEM_POWER;
|
|
|
|
luaL_setmetatable(L, "k3mixwave");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_mixwave_set(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
assert(i->type != MIXITEM_SOURCE);
|
|
|
|
if(!strcmp(lua_tostring(L, 2), "volume")) {
|
|
((struct k3MixWave*) i->thing)->volume = lua_tonumber(L, 3);
|
|
} else if(!strcmp(lua_tostring(L, 2), "loop")) {
|
|
((struct k3MixWave*) i->thing)->loop = lua_toboolean(L, 3);
|
|
} else if(i->type == MIXITEM_SOUND && !strcmp(lua_tostring(L, 2), "time")) {
|
|
k3MixSimpleSeek((struct k3MixWave*) i->thing, lua_tonumber(L, 3));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_mixwave_get(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
if(!strcmp(lua_tostring(L, 2), "volume")) {
|
|
lua_pushnumber(L, ((struct k3MixWave*) i->thing)->volume);
|
|
return 1;
|
|
} else if(!strcmp(lua_tostring(L, 2), "loop")) {
|
|
lua_pushboolean(L, ((struct k3MixWave*) i->thing)->loop);
|
|
return 1;
|
|
} else if(i->type == MIXITEM_POWER && !strcmp(lua_tostring(L, 2), "rms")) {
|
|
lua_pushnumber(L, k3MixPowerMeasurementGetRMS(((struct k3MixWave*) i->thing)));
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_mixwave_gc(lua_State *L) {
|
|
struct mixitem *i = lua_touserdata(L, 1);
|
|
|
|
if(i->type != MIXITEM_SOURCE) {
|
|
struct k3MixWave *wav = i->thing;
|
|
wav->close(wav);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_mixqueue(lua_State *L) {
|
|
struct mixitem *i = lua_newuserdata(L, sizeof(*i));
|
|
i->thing = k3MixQueue();
|
|
i->type = MIXITEM_QUEUE;
|
|
|
|
luaL_setmetatable(L, "k3mixqueue");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_queue_add(lua_State *L) {
|
|
struct mixitem *i1 = lua_touserdata(L, 1);
|
|
struct mixitem *i2 = lua_touserdata(L, 2);
|
|
|
|
if(i1->type != MIXITEM_QUEUE) {
|
|
lua_pushliteral(L, "Not queue.");
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
|
|
if(lua_gettop(L) > 2) {
|
|
lua_getfield(L, 3, "loop");
|
|
((struct k3MixWave*) i2->thing)->loop = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
} else {
|
|
((struct k3MixWave*) i2->thing)->loop = 0;
|
|
}
|
|
|
|
k3MixQueueAdd(i1->thing, i2->thing);
|
|
}
|
|
|
|
static int game_queue_clear(lua_State *L) {
|
|
struct k3MixWave **ud = lua_touserdata(L, 1);
|
|
k3MixQueueClear(*ud);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_queue_gc(lua_State *L) {
|
|
struct k3MixWave **ud = lua_touserdata(L, 1);
|
|
(*ud)->close(*ud);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_ref(lua_State *L) {
|
|
enum ResManType type;
|
|
const char *ltype = lua_tolstring(L, 1, NULL);
|
|
|
|
const char *meta = NULL;
|
|
|
|
int sz;
|
|
|
|
if(!strcmp(ltype, "stream")) {
|
|
type = RESMAN_STREAM;
|
|
meta = "k3mixwave";
|
|
sz = sizeof(struct mixitem);
|
|
} else if(!strcmp(ltype, "mat")) {
|
|
type = RESMAN_MATERIAL;
|
|
meta = "k3mat";
|
|
sz = sizeof(void*);
|
|
} else if(!strcmp(ltype, "mdl")) {
|
|
type = RESMAN_MODEL;
|
|
meta = "k3mdl";
|
|
sz = sizeof(void*);
|
|
} else if(!strcmp(ltype, "tex")) {
|
|
type = RESMAN_TEXTURE;
|
|
meta = "k3tex";
|
|
sz = sizeof(void*);
|
|
} else if(!strcmp(ltype, "physics")) {
|
|
type = RESMAN_PHYSICS;
|
|
meta = "k3physics";
|
|
sz = sizeof(void*);
|
|
} else if(!strcmp(ltype, "font")) {
|
|
type = RESMAN_FONT;
|
|
meta = NULL;
|
|
sz = sizeof(void*);
|
|
} else return 0;
|
|
|
|
const char *lname = lua_tostring(L, 2);
|
|
|
|
void **ref = lua_newuserdata(L, sz);
|
|
|
|
*ref = resman_ref(type, lname);
|
|
|
|
if(type == RESMAN_STREAM) {
|
|
((struct mixitem*) ref)->type = MIXITEM_SOURCE;
|
|
}
|
|
|
|
if(meta) luaL_setmetatable(L, meta);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_batch(lua_State *L) {
|
|
void **r = lua_touserdata(L, 1);
|
|
|
|
struct k3Mdl *mdl;
|
|
if(luaL_testudata(L, 1, "k3water")) {
|
|
mdl = ((struct k3Water*) *r)->mdl;
|
|
} else if(luaL_testudata(L, 1, "k3mdl")) {
|
|
mdl = *r;
|
|
} else return 0;
|
|
|
|
lua_rawgeti(L, 2, 1);
|
|
lua_rawgeti(L, 2, 2);
|
|
lua_rawgeti(L, 2, 3);
|
|
|
|
mat4 m = GLM_MAT4_IDENTITY_INIT;
|
|
glm_translate(m, (vec3) {lua_tonumber(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1)});
|
|
|
|
lua_pop(L, 3);
|
|
|
|
if(lua_gettop(L) == 3) {
|
|
mat4 anchor;
|
|
for(int i = 0; i < 16; i++) {
|
|
lua_rawgeti(L, 3, i + 1);
|
|
((float*) anchor)[i] = lua_tonumber(L, -1);
|
|
}
|
|
lua_pop(L, 16);
|
|
|
|
glm_mat4_mul(anchor, m, m);
|
|
}
|
|
|
|
k3Batch(mdl, m, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_get_component(lua_State *L) {
|
|
if(!lua_isinteger(L, 1)) {
|
|
return 0;
|
|
}
|
|
|
|
size_t idx = lua_tointeger(L, 1);
|
|
const char *type = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(type, "physics")) {
|
|
struct CPhysics *c = game_getcomponent(idx, physics);
|
|
|
|
if(c) {
|
|
struct CPhysics **lc = lua_newuserdata(L, sizeof(*lc));
|
|
*lc = c;
|
|
luaL_setmetatable(L, "k3cphysics");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
|
|
return 1;
|
|
} else if(!strcmp(type, "render")) {
|
|
struct CRender *c = game_getcomponent(idx, render);
|
|
|
|
if(c) {
|
|
struct CRender **lc = lua_newuserdata(L, sizeof(*lc));
|
|
*lc = c;
|
|
luaL_setmetatable(L, "k3crender");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
|
|
return 1;
|
|
} else if(!strcmp(type, "boned")) {
|
|
struct CBoned *c = game_getcomponent(idx, boned);
|
|
|
|
if(c) {
|
|
struct CBoned **lc = lua_newuserdata(L, sizeof(*lc));
|
|
*lc = c;
|
|
luaL_setmetatable(L, "k3cboned");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_submissive_assign(lua_State *L) {
|
|
ENetPeer **ud = lua_touserdata(L, 1);
|
|
|
|
net_server_assign(*ud, lua_tointeger(L, 2));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_submissive_load(lua_State *L) {
|
|
ENetPeer **ud = lua_touserdata(L, 1);
|
|
|
|
net_server_force_load(*ud, lua_tostring(L, 2));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_submissive_send(lua_State *L) {
|
|
ENetPeer **ud = lua_touserdata(L, 1);
|
|
|
|
struct bstr b;
|
|
bstr(&b, 64);
|
|
|
|
lua_pushvalue(L, 2);
|
|
if(!serialize(&b)) {
|
|
lua_pushliteral(L, "Object not serializable.");
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
net_server_send_msg(*ud, &b);
|
|
|
|
free(b.data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_cphysics_get(lua_State *L) {
|
|
struct CPhysics *c = *(struct CPhysics**) lua_touserdata(L, 1);
|
|
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "trigger")) {
|
|
lua_pushinteger(L, c->trigger);
|
|
return 1;
|
|
} else if(!strcmp(k, "type")) {
|
|
lua_pushinteger(L, c->type);
|
|
return 1;
|
|
} else if(!strcmp(k, "dynamics")) {
|
|
lua_pushinteger(L, c->dynamics);
|
|
return 1;
|
|
} else if(!strcmp(k, "pos")) {
|
|
|
|
if(c->geom) {
|
|
lua_newtable(L);
|
|
|
|
const float *p = dGeomGetPosition(c->geom);
|
|
lua_pushnumber(L, p[0]);
|
|
lua_pushnumber(L, p[1]);
|
|
lua_pushnumber(L, p[2]);
|
|
|
|
lua_rawseti(L, -4, 3);
|
|
lua_rawseti(L, -3, 2);
|
|
lua_rawseti(L, -2, 1);
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
|
|
return 1;
|
|
} else if(!strcmp(k, "vel")) {
|
|
lua_newtable(L);
|
|
|
|
dBodyID bid = dGeomGetBody(c->geom);
|
|
if(bid) {
|
|
const float *v = dBodyGetLinearVel(bid);
|
|
|
|
lua_pushnumber(L, v[0]);
|
|
lua_pushnumber(L, v[1]);
|
|
lua_pushnumber(L, v[2]);
|
|
} else {
|
|
lua_pushnumber(L, 0);
|
|
lua_pushnumber(L, 0);
|
|
lua_pushnumber(L, 0);
|
|
}
|
|
|
|
lua_rawseti(L, -4, 3);
|
|
lua_rawseti(L, -3, 2);
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
return 1;
|
|
} else if(!strcmp(k, "body")) {
|
|
if(c->geom) {
|
|
dGeomID *g = lua_newuserdata(L, sizeof(*g));
|
|
*g = c->geom;
|
|
luaL_setmetatable(L, "k3body");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
return 1;
|
|
} else if(!strcmp(k, "speed")) {
|
|
lua_pushnumber(L, c->speed);
|
|
return 1;
|
|
} else if(!strcmp(k, "add_force")) {
|
|
//lua_pushcfunction(L, );
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_cphysics_set(lua_State *L) {
|
|
struct CPhysics *c = *(struct CPhysics**) lua_touserdata(L, 1);
|
|
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "dynamics")) {
|
|
// Only allow ghost changes, not static/kinematic
|
|
if((c->dynamics ^ lua_tointeger(L, 3)) & CPHYSICS_GHOST) {
|
|
c->dynamics = (c->dynamics & ~CPHYSICS_GHOST) | (lua_tointeger(L, 3) & CPHYSICS_GHOST);
|
|
}
|
|
} else if(!strcmp(k, "pos")) {
|
|
lua_rawgeti(L, 3, 1);
|
|
lua_rawgeti(L, 3, 2);
|
|
lua_rawgeti(L, 3, 3);
|
|
|
|
dGeomSetPosition(c->geom, lua_tonumber(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1));
|
|
|
|
lua_pop(L, 3);
|
|
} else if(!strcmp(k, "rot")) {
|
|
lua_rawgeti(L, 3, 1);
|
|
lua_rawgeti(L, 3, 2);
|
|
lua_rawgeti(L, 3, 3);
|
|
lua_rawgeti(L, 3, 4);
|
|
|
|
dGeomSetQuaternion(c->geom, (dQuaternion) {lua_tonumber(L, -1), lua_tonumber(L, -4), lua_tonumber(L, -3), lua_tonumber(L, -2)});
|
|
|
|
lua_pop(L, 4);
|
|
} else if(!strcmp(k, "vel")) {
|
|
dBodyID bid = dGeomGetBody(c->geom);
|
|
|
|
if(bid) {
|
|
lua_rawgeti(L, 3, 1);
|
|
lua_rawgeti(L, 3, 2);
|
|
lua_rawgeti(L, 3, 3);
|
|
|
|
dBodySetLinearVel(bid, lua_tonumber(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1));
|
|
|
|
lua_pop(L, 3);
|
|
}
|
|
} else if(!strcmp(k, "speed")) {
|
|
c->speed = lua_tonumber(L, 3);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_crender_get(lua_State *L) {
|
|
struct CRender *c = *(struct CRender**) lua_touserdata(L, 1);
|
|
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "mdl")) {
|
|
lua_pushlstring(L, c->mdl, strnlen(c->mdl, MODELNAME_LENGTH));
|
|
return 1;
|
|
} else if(!strcmp(k, "mdlcache")) {
|
|
struct k3Mdl **cache = lua_newuserdata(L, sizeof(*cache));
|
|
*cache = c->cache;
|
|
luaL_setmetatable(L, "k3mdl");
|
|
return 1;
|
|
} else if(!strcmp(k, "bones")) {
|
|
lua_newtable(L);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_cboned_get(lua_State *L) {
|
|
struct CBoned *c = *(struct CBoned**) lua_touserdata(L, 1);
|
|
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "bones")) {
|
|
lua_newtable(L);
|
|
|
|
for(size_t i = 0; i < c->size; i++) {
|
|
lua_newtable(L);
|
|
lua_newtable(L);
|
|
lua_pushnumber(L, c->bones[i].translation[0]);
|
|
lua_pushnumber(L, c->bones[i].translation[1]);
|
|
lua_pushnumber(L, c->bones[i].translation[2]);
|
|
lua_pushnumber(L, c->bones[i].translation[3]);
|
|
lua_rawseti(L, -5, 4);
|
|
lua_rawseti(L, -4, 3);
|
|
lua_rawseti(L, -3, 2);
|
|
lua_rawseti(L, -2, 1);
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
lua_newtable(L);
|
|
lua_pushnumber(L, c->bones[i].rotation[0]);
|
|
lua_pushnumber(L, c->bones[i].rotation[1]);
|
|
lua_pushnumber(L, c->bones[i].rotation[2]);
|
|
lua_pushnumber(L, c->bones[i].rotation[3]);
|
|
lua_rawseti(L, -5, 4);
|
|
lua_rawseti(L, -4, 3);
|
|
lua_rawseti(L, -3, 2);
|
|
lua_rawseti(L, -2, 1);
|
|
lua_rawseti(L, -2, 2);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
|
|
return 1;
|
|
} else if(!strcmp(k, "anim")) {
|
|
struct CBoned **c2 = lua_newuserdata(L, sizeof(*c2));
|
|
*c2 = c;
|
|
luaL_setmetatable(L, "k3cbonedanim");
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_cboned_set(lua_State *L) {
|
|
struct CBoned *c = *(struct CBoned**) lua_touserdata(L, 1);
|
|
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "bones")) {
|
|
size_t newlen = luaL_len(L, 3);
|
|
|
|
if(newlen != c->size) {
|
|
c->bones = realloc(c->bones, sizeof(*c->bones) * newlen);
|
|
}
|
|
|
|
for(size_t i = 0; i < newlen; i++) {
|
|
lua_rawgeti(L, 3, i + 1);
|
|
|
|
lua_rawgeti(L, -1, 1);
|
|
lua_rawgeti(L, -1, 1);
|
|
lua_rawgeti(L, -2, 2);
|
|
lua_rawgeti(L, -3, 3);
|
|
lua_rawgeti(L, -4, 4);
|
|
c->bones[i].translation[0] = lua_tonumber(L, -4);
|
|
c->bones[i].translation[1] = lua_tonumber(L, -3);
|
|
c->bones[i].translation[2] = lua_tonumber(L, -2);
|
|
c->bones[i].translation[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
|
|
lua_rawgeti(L, -1, 2);
|
|
lua_rawgeti(L, -1, 1);
|
|
lua_rawgeti(L, -2, 2);
|
|
lua_rawgeti(L, -3, 3);
|
|
lua_rawgeti(L, -4, 4);
|
|
c->bones[i].rotation[0] = lua_tonumber(L, -4);
|
|
c->bones[i].rotation[1] = lua_tonumber(L, -3);
|
|
c->bones[i].rotation[2] = lua_tonumber(L, -2);
|
|
c->bones[i].rotation[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_cbonedanim_set(lua_State *L) {
|
|
struct CBoned *c = *(struct CBoned**) lua_touserdata(L, 1);
|
|
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "id")) {
|
|
c->anim.id = lua_tointeger(L, 3);
|
|
c->anim.cache.base = NULL;
|
|
} else if(!strcmp(k, "standard")) {
|
|
c->anim.standard = lua_toboolean(L, 3);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int LuaapiCamFocus;
|
|
vec3 LuaapiCamFocusPos;
|
|
vec3 LuaapiCamFocusDir;
|
|
int LuaapiFirstPerson;
|
|
|
|
static int game_camfocus(lua_State *L) {
|
|
if(lua_gettop(L) < 3 || lua_isnil(L, 2) || lua_isnil(L, 3)) {
|
|
LuaapiCamFocus = 0;
|
|
} else if(lua_gettop(L) == 3) {
|
|
LuaapiCamFocus = 1;
|
|
|
|
lua_rawgeti(L, 2, 1);
|
|
lua_rawgeti(L, 2, 2);
|
|
lua_rawgeti(L, 2, 3);
|
|
|
|
LuaapiCamFocusPos[0] = lua_tonumber(L, -3);
|
|
LuaapiCamFocusPos[1] = lua_tonumber(L, -2);
|
|
LuaapiCamFocusPos[2] = lua_tonumber(L, -1);
|
|
|
|
lua_rawgeti(L, 3, 1);
|
|
lua_rawgeti(L, 3, 2);
|
|
lua_rawgeti(L, 3, 3);
|
|
|
|
LuaapiCamFocusDir[0] = lua_tonumber(L, -3);
|
|
LuaapiCamFocusDir[1] = lua_tonumber(L, -2);
|
|
LuaapiCamFocusDir[2] = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 6);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define MENUITEM_SCREEN 0
|
|
#define MENUITEM_LABEL 1
|
|
#define MENUITEM_TEXTBUTTON 2
|
|
#define MENUITEM_TEXTINPUT 3
|
|
struct menuitem {
|
|
int type;
|
|
struct k3MObj *ptr;
|
|
};
|
|
|
|
mat4 LuaapiCamMatrix;
|
|
static int game_get(lua_State *L) {
|
|
const char *i = lua_tostring(L, 2);
|
|
if(!strcmp(i, "mp")) {
|
|
lua_pushboolean(L, Game.isMultiplayer);
|
|
} else if(!strcmp(i, "authority")) {
|
|
lua_pushboolean(L, Game.isAuthority);
|
|
} else if(!strcmp(i, "spectated")) {
|
|
lua_pushinteger(L, Game.spectated);
|
|
} else if(!strcmp(i, "fov")) {
|
|
lua_pushnumber(L, LuaapiFov);
|
|
} else if(!strcmp(i, "rate")) {
|
|
lua_pushinteger(L, GAME_TPS);
|
|
} else if(!strcmp(i, "camera")) {
|
|
lua_newtable(L);
|
|
for(int i = 0; i < 16; i++) {
|
|
lua_pushnumber(L, ((float*) LuaapiCamMatrix)[i]);
|
|
lua_rawseti(L, -2, i + 1);
|
|
}
|
|
} else if(!strcmp(i, "menu")) {
|
|
if(UiActive) {
|
|
struct menuitem *item = lua_newuserdata(L, sizeof(*item));
|
|
item->type = MENUITEM_SCREEN;
|
|
item->ptr = UiActive;
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
} else {
|
|
lua_pushvalue(L, 2);
|
|
lua_rawget(L, 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int game_set(lua_State *L) {
|
|
const char *i = lua_tostring(L, 2);
|
|
if(!strcmp(i, "spectated")) {
|
|
Game.spectated = lua_isnil(L, 3) ? ENT_ID_INVALID : lua_tointeger(L, 3);
|
|
} else if(!strcmp(i, "fov")) {
|
|
LuaapiFov = lua_tonumber(L, 3);
|
|
} else if(!strcmp(i, "menu")) {
|
|
struct menuitem *item = lua_touserdata(L, 3);
|
|
UiActive = item ? item->ptr : NULL;
|
|
set_ui_mode(!!UiActive);
|
|
} else {
|
|
lua_pushvalue(L, 2);
|
|
lua_pushvalue(L, 3);
|
|
lua_rawset(L, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int game_k3mdl_addmesh(lua_State *L) {
|
|
struct k3Mdl *mdl = *(struct k3Mdl**) lua_touserdata(L, 1);
|
|
|
|
lua_getfield(L, 2, "material");
|
|
struct k3Mat mat;
|
|
memset(&mat, 0, sizeof(mat));
|
|
luaapi_fillmaterial_direct(&mat);
|
|
|
|
lua_getfield(L, 2, "start");
|
|
size_t start = lua_tointeger(L, -1);
|
|
|
|
lua_getfield(L, 2, "count");
|
|
size_t count = lua_tointeger(L, -1);
|
|
|
|
lua_pop(L, 3);
|
|
|
|
k3MdlAddMesh(mdl, &mat, start, count);
|
|
}
|
|
|
|
static int game_k3mdl_get(lua_State *L) {
|
|
struct k3Mdl *mdl = *(struct k3Mdl**) lua_touserdata(L, 1);
|
|
|
|
size_t count;
|
|
struct k3Mesh *meshes = k3MdlGetMeshes(mdl, &count);
|
|
|
|
if(lua_type(L, 2) == LUA_TNUMBER) {
|
|
lua_Integer i = lua_tointeger(L, 2);
|
|
if(i >= 1 && i <= count) {
|
|
struct k3Mat **m = lua_newuserdata(L, sizeof(*m));
|
|
*m = &meshes[i - 1].mat;
|
|
luaL_setmetatable(L, "k3mat");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
} else if(!strcmp(lua_tostring(L, 2), "addmesh")) {
|
|
lua_pushcfunction(L, game_k3mdl_addmesh);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_k3mat_get(lua_State *L) {
|
|
struct k3Mat *mat = *(struct k3Mat**) lua_touserdata(L, 1);
|
|
const char *k = lua_tostring(L, 2);
|
|
if(!strcmp(k, "uniforms")) {
|
|
if(mat->passes[0].glsl.hp) {
|
|
struct k3Mat **again = lua_newuserdata(L, sizeof(*again));
|
|
*again = mat;
|
|
luaL_setmetatable(L, "k3matuniforms");
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int game_k3matuniforms_set(lua_State *L) {
|
|
struct k3Mat *mat = *(struct k3Mat**) lua_touserdata(L, 1);
|
|
|
|
const char *key = lua_tostring(L, 2);
|
|
|
|
for(int i = 0; i < mat->passes[0].glsl.uCount; i++) {
|
|
if(!strncmp(key, mat->passes[0].glsl.u[i].name, sizeof(mat->passes[0].glsl.u[i].name))) {
|
|
if(mat->passes[0].glsl.u[i].type == k3_MAT_UNIFORM_I1) {
|
|
mat->passes[0].glsl.u[i].i1 = lua_tointeger(L, 3);
|
|
} else if(mat->passes[0].glsl.u[i].type == k3_MAT_UNIFORM_F1) {
|
|
mat->passes[0].glsl.u[i].f1 = lua_tonumber(L, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int game_k3matuniforms_get(lua_State *L) {
|
|
struct k3Mat *mat = *(struct k3Mat**) lua_touserdata(L, 1);
|
|
|
|
const char *key = lua_tostring(L, 2);
|
|
|
|
for(int i = 0; i < mat->passes[0].glsl.uCount; i++) {
|
|
if(!strncmp(key, mat->passes[0].glsl.u[i].name, sizeof(mat->passes[0].glsl.u[i].name))) {
|
|
if(mat->passes[0].glsl.u[i].type == k3_MAT_UNIFORM_I1) {
|
|
lua_pushinteger(L, mat->passes[0].glsl.u[i].i1);
|
|
return 1;
|
|
} else if(mat->passes[0].glsl.u[i].type == k3_MAT_UNIFORM_F1) {
|
|
lua_pushnumber(L, mat->passes[0].glsl.u[i].f1);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static size_t moduleCount;
|
|
static struct Module {
|
|
//uint64_t hash;
|
|
char *name;
|
|
int ref;
|
|
} *modules;
|
|
static int luaapi_require(lua_State *L) {
|
|
const char *name = lua_tostring(L, 1);
|
|
|
|
for(size_t i = 0; i < moduleCount; i++) {
|
|
if(!strcmp(modules[i].name, name)) {
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, modules[i].ref);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
char buf[128];
|
|
snprintf(buf, sizeof(buf), "%s.lua", name);
|
|
buf[127] = 0;
|
|
for(size_t i = 0; buf[i] && i < strlen(buf) - 4; i++) {
|
|
if(buf[i] == '.') buf[i] = '/';
|
|
}
|
|
|
|
struct ResManBin *bin = resman_ref(RESMAN_BIN, buf);
|
|
|
|
if(luaL_dostring(L, bin->data)) {
|
|
puts(lua_tolstring(L, -1, NULL));
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
resman_unref(RESMAN_BIN, buf);
|
|
|
|
lua_pushvalue(L, -1);
|
|
modules = realloc(modules, sizeof(*modules) * (moduleCount + 1));
|
|
modules[moduleCount++] = (struct Module) {
|
|
.name = strdup(name),
|
|
.ref = luaL_ref(L, LUA_REGISTRYINDEX),
|
|
};
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int game_load(lua_State *L) {
|
|
luaapi_load(lua_tostring(L, 1));
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_cleanup(lua_State *L) {
|
|
luaapi_cleanup();
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_joint(lua_State *L) {
|
|
lua_getfield(L, 1, "type");
|
|
const char *type = lua_tostring(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
if(!strcmp(type, "ballsocket")) {
|
|
lua_geti(L, 1, 1);
|
|
lua_geti(L, 1, 2);
|
|
dGeomID *gid1 = lua_touserdata(L, -2);
|
|
dGeomID *gid2 = lua_touserdata(L, -1);
|
|
lua_pop(L, 2);
|
|
|
|
dBodyID bid1 = dGeomGetBody(*gid1);
|
|
dBodyID bid2 = dGeomGetBody(*gid2);
|
|
|
|
if(bid1 && bid2) {
|
|
dJointID jid = dJointCreateBall(Game.phys, 0);
|
|
lua_getfield(L, 1, "anchor");
|
|
lua_rawgeti(L, -1, 1);
|
|
lua_rawgeti(L, -2, 2);
|
|
lua_rawgeti(L, -3, 3);
|
|
dJointSetBallAnchor(jid, lua_tonumber(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1));
|
|
lua_pop(L, 4);
|
|
dJointAttach(jid, bid1, bid2);
|
|
}
|
|
} else if(!strcmp(type, "slider")) {
|
|
lua_geti(L, 1, 1);
|
|
lua_geti(L, 1, 2);
|
|
dGeomID *gid1 = lua_touserdata(L, -2);
|
|
dGeomID *gid2 = lua_touserdata(L, -1);
|
|
lua_pop(L, 2);
|
|
|
|
dBodyID bid1 = dGeomGetBody(*gid1);
|
|
dBodyID bid2 = dGeomGetBody(*gid2);
|
|
|
|
if(bid1 && bid2) {
|
|
dJointID jid = dJointCreateSlider(Game.phys, 0);
|
|
dJointAttach(jid, bid1, bid2);
|
|
|
|
lua_getfield(L, 1, "axis");
|
|
lua_rawgeti(L, -1, 1);
|
|
lua_rawgeti(L, -2, 2);
|
|
lua_rawgeti(L, -3, 3);
|
|
dJointSetSliderAxis(jid, lua_tonumber(L, -3), lua_tonumber(L, -2), lua_tonumber(L, -1));
|
|
lua_pop(L, 4);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_setphys(lua_State *L) {
|
|
game_setphys(*(struct TrimeshData**) lua_touserdata(L, 1));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_controls_get(lua_State *L) {
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
int btn = k4_control_get_by_name(k);
|
|
|
|
if(btn == -1) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushinteger(L, btn);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_controls_set(lua_State *L) {
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
int btn;
|
|
|
|
// lua_isstring returns true for numbers because yes
|
|
if(lua_type(L, 3) == LUA_TSTRING) {
|
|
btn = lua_tostring(L, 3)[0];
|
|
} else {
|
|
btn = lua_tointeger(L, 3);
|
|
}
|
|
|
|
k4_control_set(k, btn);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_mdl(lua_State *L) {
|
|
vec3 *positions = NULL;
|
|
int8_t *normals = NULL;
|
|
uint16_t *indices = NULL;
|
|
vec2 *uvs = NULL;
|
|
|
|
size_t vertexCount = 0;
|
|
size_t indexCount = 0;
|
|
|
|
lua_getfield(L, 1, "positions");
|
|
lua_len(L, -1);
|
|
vertexCount = lua_tointeger(L, -1) / 3;
|
|
lua_pop(L, 1);
|
|
|
|
positions = malloc(sizeof(*positions) * vertexCount);
|
|
|
|
for(size_t i = 0; i < vertexCount; i++) {
|
|
lua_geti(L, -1, i * 3 + 1);
|
|
lua_geti(L, -2, i * 3 + 2);
|
|
lua_geti(L, -3, i * 3 + 3);
|
|
positions[i][0] = lua_tonumber(L, -3);
|
|
positions[i][1] = lua_tonumber(L, -2);
|
|
positions[i][2] = lua_tonumber(L, -1);
|
|
lua_pop(L, 3);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "indices");
|
|
lua_len(L, -1);
|
|
indexCount = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
indices = malloc(sizeof(*indices) * indexCount);
|
|
|
|
for(size_t i = 0; i < indexCount; i++) {
|
|
lua_geti(L, -1, i + 1);
|
|
indices[i] = lua_tointeger(L, -1);
|
|
if(indices[i] >= vertexCount) {
|
|
k3Log(k3_ERR, "Index goes over vertex count!");
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "normals");
|
|
lua_len(L, -1);
|
|
size_t c = lua_tointeger(L, -1) / 3;
|
|
lua_pop(L, 1);
|
|
|
|
if(c != vertexCount) {
|
|
// TODO: free
|
|
return 0;
|
|
}
|
|
|
|
normals = malloc(sizeof(*normals) * 3 * vertexCount);
|
|
|
|
for(size_t i = 0; i < vertexCount; i++) {
|
|
lua_geti(L, -1, i * 3 + 1);
|
|
lua_geti(L, -2, i * 3 + 2);
|
|
lua_geti(L, -3, i * 3 + 3);
|
|
normals[i * 3 + 0] = lua_tonumber(L, -3) * 127;
|
|
normals[i * 3 + 1] = lua_tonumber(L, -2) * 127;
|
|
normals[i * 3 + 2] = lua_tonumber(L, -1) * 127;
|
|
lua_pop(L, 3);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "uvs");
|
|
lua_len(L, -1);
|
|
c = lua_tointeger(L, -1) / 2;
|
|
lua_pop(L, 1);
|
|
|
|
if(c != vertexCount) {
|
|
// TODO: free
|
|
return 0;
|
|
}
|
|
|
|
uvs = malloc(sizeof(*uvs) * vertexCount);
|
|
|
|
for(size_t i = 0; i < vertexCount; i++) {
|
|
lua_geti(L, -1, i * 2 + 1);
|
|
lua_geti(L, -2, i * 2 + 2);
|
|
uvs[i][0] = lua_tonumber(L, -2);
|
|
uvs[i][1] = lua_tonumber(L, -1);
|
|
lua_pop(L, 2);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
struct k3Mdl *mdl = k3MdlCreate(vertexCount, indexCount, 0, positions, normals, uvs, NULL, NULL, NULL, indices, NULL, NULL);
|
|
|
|
struct k3Mdl **ud = lua_newuserdata(L, sizeof(*ud));
|
|
*ud = mdl;
|
|
luaL_setmetatable(L, "k3mdl");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_trimesh(lua_State *L) {
|
|
lua_getfield(L, 1, "indices");
|
|
lua_len(L, -1);
|
|
size_t indexCount = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
int *indices = malloc(sizeof(*indices) * indexCount);
|
|
|
|
for(size_t i = 0; i < indexCount; i++) {
|
|
lua_geti(L, -1, i + 1);
|
|
indices[i] = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "positions");
|
|
lua_len(L, -1);
|
|
size_t vertexCount = lua_tointeger(L, -1) / 3;
|
|
lua_pop(L, 1);
|
|
|
|
vec3 *positions = malloc(sizeof(*positions) * vertexCount);
|
|
|
|
for(size_t i = 0; i < vertexCount; i++) {
|
|
lua_geti(L, -1, i * 3 + 1);
|
|
lua_geti(L, -2, i * 3 + 2);
|
|
lua_geti(L, -3, i * 3 + 3);
|
|
positions[i][0] = lua_tonumber(L, -3);
|
|
positions[i][1] = lua_tonumber(L, -2);
|
|
positions[i][2] = lua_tonumber(L, -1);
|
|
lua_pop(L, 3);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
dTriMeshDataID trid = dGeomTriMeshDataCreate();
|
|
dGeomTriMeshDataBuildSingle(trid, positions, sizeof(vec3), vertexCount, indices, indexCount, 3 * sizeof(int));
|
|
|
|
struct TrimeshData *ret = malloc(sizeof(*ret));
|
|
ret->vdata = positions;
|
|
ret->idata = indices;
|
|
ret->trid = trid;
|
|
|
|
struct TrimeshData **ud = lua_newuserdata(L, sizeof(*ud));
|
|
*ud = ret;
|
|
|
|
luaL_setmetatable(L, "k3physics");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_firstperson(lua_State *L) {
|
|
LuaapiFirstPerson = lua_toboolean(L, 1);
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_ray(lua_State *L) {
|
|
struct LocalRay *lr = lua_newuserdata(L, sizeof(*lr));
|
|
luaL_setmetatable(L, "k4ray");
|
|
|
|
struct CPhysics *cp = game_getcomponent(Game.spectated, physics);
|
|
struct CPlayerCtrl *cc = game_getcomponent(Game.spectated, playerctrl);
|
|
|
|
memcpy(lr->pos, dGeomGetPosition(cp->geom), sizeof(vec3));
|
|
|
|
lr->dir[0] = 0;
|
|
lr->dir[1] = 0;
|
|
lr->dir[2] = -1;
|
|
|
|
glm_vec3_rotate(lr->dir, cc->pitch, (vec3) {1, 0, 0});
|
|
glm_vec3_rotate(lr->dir, cc->yaw, (vec3) {0, 1, 0});
|
|
|
|
lr->ignore = Game.spectated;
|
|
|
|
lr->hit = ENT_ID_INVALID;
|
|
lr->out[0] = NAN;
|
|
lr->out[1] = NAN;
|
|
lr->out[2] = NAN;
|
|
|
|
lr->maxlen = lua_type(L, 1) == LUA_TNUMBER ? lua_tonumber(L, 1) : 3;
|
|
|
|
game_raycast(lr, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_ray_get(lua_State *L) {
|
|
struct LocalRay *lr = luaL_checkudata(L, 1, "k4ray");
|
|
|
|
const char *key = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(key, "pos")) {
|
|
lua_newtable(L);
|
|
|
|
lua_pushnumber(L, lr->out[0]);
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushnumber(L, lr->out[1]);
|
|
lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushnumber(L, lr->out[2]);
|
|
lua_rawseti(L, -2, 3);
|
|
|
|
return 1;
|
|
} else if(!strcmp(key, "dir")) {
|
|
lua_newtable(L);
|
|
|
|
lua_pushnumber(L, lr->dir[0]);
|
|
lua_rawseti(L, -2, 1);
|
|
|
|
lua_pushnumber(L, lr->dir[1]);
|
|
lua_rawseti(L, -2, 2);
|
|
|
|
lua_pushnumber(L, lr->dir[2]);
|
|
lua_rawseti(L, -2, 3);
|
|
|
|
return 1;
|
|
} else if(!strcmp(key, "hit")) {
|
|
if(lr->hit == ENT_ID_INVALID) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushinteger(L, lr->hit);
|
|
}
|
|
|
|
return 1;
|
|
} else if(!strcmp(key, "ready")) {
|
|
lua_pushboolean(L, !isnanf(lr->out[0]));
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#include"k3font.h"
|
|
static int dagame_draw(lua_State *L) {
|
|
lua_getfield(L, 1, "fill");
|
|
|
|
if(lua_toboolean(L, -1)) {
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "tex");
|
|
|
|
lua_getfield(L, 1, "sx");
|
|
lua_getfield(L, 1, "sy");
|
|
|
|
lua_getfield(L, 1, "sw");
|
|
lua_getfield(L, 1, "sh");
|
|
|
|
lua_getfield(L, 1, "x");
|
|
lua_getfield(L, 1, "y");
|
|
|
|
lua_getfield(L, 1, "w");
|
|
lua_getfield(L, 1, "h");
|
|
|
|
lua_getfield(L, 1, "r");
|
|
lua_getfield(L, 1, "g");
|
|
lua_getfield(L, 1, "b");
|
|
lua_getfield(L, 1, "a");
|
|
|
|
void *texptr = lua_touserdata(L, -13);
|
|
struct k3Tex *tex = texptr ? *(void**)texptr : NULL;
|
|
|
|
float sx = lua_type(L, -12) == LUA_TNUMBER ? lua_tonumber(L, -12) : 0;
|
|
float sy = lua_type(L, -11) == LUA_TNUMBER ? lua_tonumber(L, -11) : 0;
|
|
|
|
float sw = lua_type(L, -10) == LUA_TNUMBER ? lua_tonumber(L, -10) : 1;
|
|
float sh = lua_type(L, -9) == LUA_TNUMBER ? lua_tonumber(L, -9) : 1;
|
|
|
|
float x = lua_tonumber(L, -8);
|
|
float y = lua_tonumber(L, -7);
|
|
|
|
float w = lua_tonumber(L, -6);
|
|
float h = lua_tonumber(L, -5);
|
|
|
|
float r = lua_type(L, -4) == LUA_TNUMBER ? lua_tonumber(L, -4) : 1;
|
|
float g = lua_type(L, -3) == LUA_TNUMBER ? lua_tonumber(L, -3) : 1;
|
|
float b = lua_type(L, -2) == LUA_TNUMBER ? lua_tonumber(L, -2) : 1;
|
|
float a = lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : 1;
|
|
|
|
k3BatchAdd(tex, (struct k3RectF) {.x = sx, .y = sy, .w = sw, .h = sh}, (struct k3RectF) {.x = x, .y = y, .w = w, .h = h}, 0, (vec4) {r, g, b, a});
|
|
|
|
lua_pop(L, 13);
|
|
} else {
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, 1, "align");
|
|
|
|
lua_getfield(L, 1, "r");
|
|
lua_getfield(L, 1, "g");
|
|
lua_getfield(L, 1, "b");
|
|
lua_getfield(L, 1, "a");
|
|
|
|
lua_getfield(L, 1, "sz");
|
|
|
|
lua_getfield(L, 1, "text");
|
|
|
|
lua_getfield(L, 1, "x");
|
|
lua_getfield(L, 1, "y");
|
|
|
|
lua_getfield(L, 1, "font");
|
|
struct k3Font *font = *(void**) lua_touserdata(L, 1);
|
|
|
|
struct k3RectF rect;
|
|
k3FontSz(font, lua_tonumber(L, -4), lua_tostring(L, -3), &rect);
|
|
|
|
if(!strcmp(lua_tostring(L, -9), "bottommiddle")) {
|
|
rect.x -= rect.w / 2;
|
|
} else if(!strcmp(lua_tostring(L, -9), "bottomright")) {
|
|
rect.x -= rect.w;
|
|
} else if(!strcmp(lua_tostring(L, -9), "middlemiddle")) {
|
|
rect.x -= rect.w / 2;
|
|
rect.y -= rect.h / 2;
|
|
}
|
|
|
|
k3FontDraw(font, lua_tonumber(L, -2) + rect.x, lua_tonumber(L, -1) + rect.y, lua_tonumber(L, -4), lua_tostring(L, -3), (vec4) {lua_tonumber(L, -8), lua_tonumber(L, -7), lua_tonumber(L, -6), lua_tonumber(L, -5)});
|
|
|
|
lua_pop(L, 9);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct k3Tex *LuaapiSkybox;
|
|
vec4 LuaapiSkyboxRotation;
|
|
bool LuaapiSkyboxRotationFunky;
|
|
static int dagame_skybox(lua_State *L) {
|
|
LuaapiSkybox = *(struct k3Tex**) lua_touserdata(L, 1);
|
|
|
|
if(lua_gettop(L) >= 2) {
|
|
lua_geti(L, 2, 1);
|
|
lua_geti(L, 2, 2);
|
|
lua_geti(L, 2, 3);
|
|
lua_geti(L, 2, 4);
|
|
|
|
LuaapiSkyboxRotation[0] = lua_tonumber(L, -4);
|
|
LuaapiSkyboxRotation[1] = lua_tonumber(L, -3);
|
|
LuaapiSkyboxRotation[2] = lua_tonumber(L, -2);
|
|
LuaapiSkyboxRotation[3] = lua_tonumber(L, -1);
|
|
|
|
lua_pop(L, 4);
|
|
|
|
if(lua_gettop(L) == 3) {
|
|
LuaapiSkyboxRotationFunky = lua_toboolean(L, 3);
|
|
}
|
|
} else {
|
|
glm_vec4_zero(LuaapiSkyboxRotation);
|
|
LuaapiSkyboxRotationFunky = false;
|
|
}
|
|
}
|
|
|
|
static int dagame_send(lua_State *L) {
|
|
struct bstr b;
|
|
bstr(&b, 64);
|
|
|
|
lua_pushvalue(L, 1);
|
|
if(!serialize(&b)) {
|
|
lua_pushliteral(L, "Object not serializable.");
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
if(Game.isAuthority) {
|
|
net_server_broadcast_msg(&b);
|
|
} else {
|
|
net_client_send_msg(&b);
|
|
}
|
|
|
|
free(b.data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_ui_screen(lua_State *L) {
|
|
struct menuitem *item = lua_newuserdata(L, sizeof(*item));
|
|
item->type = MENUITEM_SCREEN;
|
|
item->ptr = (void*) k3MScreen();
|
|
luaL_setmetatable(L, "k3menuitem");
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_ui_label(lua_State *L) {
|
|
struct menuitem *item = lua_newuserdata(L, sizeof(*item));
|
|
item->type = MENUITEM_LABEL;
|
|
item->ptr = (void*) k3MLabel(*(void**) lua_touserdata(L, 1), lua_tonumber(L, 2), strdup(lua_tostring(L, 3)));
|
|
luaL_setmetatable(L, "k3menuitem");
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_ui_textbutton(lua_State *L) {
|
|
struct menuitem *item = lua_newuserdata(L, sizeof(*item));
|
|
item->type = MENUITEM_TEXTBUTTON;
|
|
item->ptr = (void*) k3MTextButton(*(void**) lua_touserdata(L, 1), lua_tonumber(L, 2), strdup(lua_tostring(L, 3)));
|
|
luaL_setmetatable(L, "k3menuitem");
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_ui_textinput(lua_State *L) {
|
|
struct menuitem *item = lua_newuserdata(L, sizeof(*item));
|
|
item->type = MENUITEM_TEXTINPUT;
|
|
item->ptr = (void*) k3MTextInput(*(void**) lua_touserdata(L, 1), lua_tonumber(L, 2), strdup(lua_tostring(L, 3)), strdup(lua_tostring(L, 4)));
|
|
luaL_setmetatable(L, "k3menuitem");
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_k3menuitem_set_bounds(lua_State *L) {
|
|
struct menuitem *item = lua_touserdata(L, 1);
|
|
|
|
item->ptr->x = lua_tonumber(L, 2);
|
|
item->ptr->y = lua_tonumber(L, 3);
|
|
item->ptr->w = lua_tonumber(L, 4);
|
|
item->ptr->h = lua_tonumber(L, 5);
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_k3menuitem_add_child(lua_State *L) {
|
|
struct menuitem *parent = lua_touserdata(L, 1);
|
|
struct menuitem *child = lua_touserdata(L, 2);
|
|
|
|
k3MAddChild(parent->ptr, child->ptr);
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static bool k3menuitem_event_callback(struct k3MEvent *ev, uint8_t *ud_) {
|
|
void **ud = ud_;
|
|
|
|
lua_State *L = ud[0];
|
|
intptr_t luaref = (intptr_t) ud[1];
|
|
|
|
int oldtop = lua_gettop(L);
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, luaref);
|
|
|
|
if(lua_pcall(L, 0, 1, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
return false;
|
|
}
|
|
|
|
bool handled = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
assert(lua_gettop(L) == oldtop);
|
|
|
|
return handled;
|
|
}
|
|
static int dagame_k3menuitem_on(lua_State *L) {
|
|
struct menuitem *item = lua_touserdata(L, 1);
|
|
|
|
uint16_t evcode = 0xFFFF;
|
|
|
|
if(!strcmp(lua_tostring(L, 2), "mouse_enter")) {
|
|
evcode = k3M_EVENT_MOUSE_ENTER;
|
|
} else if(!strcmp(lua_tostring(L, 2), "mouse_motion")) {
|
|
evcode = k3M_EVENT_MOUSE_MOTION;
|
|
} else if(!strcmp(lua_tostring(L, 2), "mouse_leave")) {
|
|
evcode = k3M_EVENT_MOUSE_RELEASE;
|
|
} else if(!strcmp(lua_tostring(L, 2), "mouse_press")) {
|
|
evcode = k3M_EVENT_MOUSE_PRESS;
|
|
} else if(!strcmp(lua_tostring(L, 2), "mouse_release")) {
|
|
evcode = k3M_EVENT_MOUSE_RELEASE;
|
|
} else if(!strcmp(lua_tostring(L, 2), "click")) {
|
|
evcode = k3M_EVENT_MOUSE_CLICK;
|
|
} else if(!strcmp(lua_tostring(L, 2), "key_press")) {
|
|
evcode = k3M_EVENT_KEY_PRESS;
|
|
} else if(!strcmp(lua_tostring(L, 2), "key_release")) {
|
|
evcode = k3M_EVENT_KEY_RELEASE;
|
|
} else if(!strcmp(lua_tostring(L, 2), "input")) {
|
|
evcode = k3M_EVENT_INPUT;
|
|
} else if(!strcmp(lua_tostring(L, 2), "draw")) {
|
|
evcode = k3M_EVENT_DRAW;
|
|
} else if(!strcmp(lua_tostring(L, 2), "complete")) {
|
|
evcode = k3M_EVENT_COMPLETE;
|
|
} else if(!strcmp(lua_tostring(L, 2), "all")) {
|
|
evcode = k3M_EVENT_ALL;
|
|
}
|
|
|
|
if(evcode != 0xFFFF) {
|
|
lua_pushvalue(L, 3);
|
|
void *ud[2] = {L, (intptr_t) luaL_ref(L, LUA_REGISTRYINDEX)};
|
|
|
|
k3MRegisterEventHandler(item->ptr, evcode, k3menuitem_event_callback, ud, sizeof(ud));
|
|
}
|
|
|
|
lua_pushvalue(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_k3menuitem_get(lua_State *L) {
|
|
struct menuitem *item = lua_touserdata(L, 1);
|
|
|
|
if(!strcmp(lua_tostring(L, 2), "invisible")) {
|
|
lua_pushboolean(L, item->ptr->invisible);
|
|
} else if(!strcmp(lua_tostring(L, 2), "disabled")) {
|
|
lua_pushboolean(L, item->ptr->disabled);
|
|
} else if(!strcmp(lua_tostring(L, 2), "set_bounds")) {
|
|
lua_pushcfunction(L, dagame_k3menuitem_set_bounds);
|
|
} else if(!strcmp(lua_tostring(L, 2), "add_child")) {
|
|
lua_pushcfunction(L, dagame_k3menuitem_add_child);
|
|
} else if(!strcmp(lua_tostring(L, 2), "on")) {
|
|
lua_pushcfunction(L, dagame_k3menuitem_on);
|
|
} else if(!strcmp(lua_tostring(L, 2), "text")) {
|
|
|
|
char *txt = NULL;
|
|
|
|
if(item->type == MENUITEM_LABEL) {
|
|
txt = ((struct k3MLabel*) item->ptr)->txt;
|
|
} else if(item->type == MENUITEM_TEXTBUTTON) {
|
|
txt = ((struct k3MTextButton*) item->ptr)->txt;
|
|
} else if(item->type == MENUITEM_TEXTINPUT) {
|
|
txt = ((struct k3MTextInput*) item->ptr)->txt;
|
|
}
|
|
|
|
if(txt) {
|
|
lua_pushstring(L, txt);
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
|
|
} else lua_pushnil(L);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_k3menuitem_set(lua_State *L) {
|
|
struct menuitem *item = lua_touserdata(L, 1);
|
|
|
|
if(!strcmp(lua_tostring(L, 2), "invisible")) {
|
|
item->ptr->invisible = lua_toboolean(L, 3);
|
|
} else if(!strcmp(lua_tostring(L, 2), "disabled")) {
|
|
item->ptr->disabled = lua_toboolean(L, 3);
|
|
} else if(!strcmp(lua_tostring(L, 2), "text")) {
|
|
char **txt = NULL;
|
|
|
|
if(item->type == MENUITEM_LABEL) {
|
|
txt = &((struct k3MLabel*) item->ptr)->txt;
|
|
} else if(item->type == MENUITEM_TEXTBUTTON) {
|
|
txt = &((struct k3MTextButton*) item->ptr)->txt;
|
|
} else if(item->type == MENUITEM_TEXTINPUT) {
|
|
txt = &((struct k3MTextInput*) item->ptr)->txt;
|
|
}
|
|
|
|
if(txt) {
|
|
if(*txt) {
|
|
free(*txt);
|
|
}
|
|
|
|
const char *new = lua_tostring(L, 3);
|
|
|
|
*txt = strdup(new ? new : "nil");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_set_reduction(lua_State *L) {
|
|
float f = lua_type(L, 1) == LUA_TNUMBER ? lua_tonumber(L, 1) : 1;
|
|
k4_set_reduction(f);
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_set_texture_reduction(lua_State *L) {
|
|
int i = lua_type(L, 1) == LUA_TNUMBER ? lua_tointeger(L, 1) : 1;
|
|
k4_set_texture_reduction(i);
|
|
return 0;
|
|
}
|
|
|
|
int PeercodeHandler = LUA_NOREF;
|
|
static int dagame_net_gen_peercode(lua_State *L) {
|
|
if(NetWrap.stage != 0 || PeercodeHandler != LUA_NOREF) {
|
|
lua_pushliteral(L, "Peercode generation already in progress");
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
|
|
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
|
|
NetWrap.stage = 1;
|
|
|
|
lua_pushvalue(L, 1);
|
|
PeercodeHandler = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_clipboard_set(lua_State *L) {
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "text")) {
|
|
k4_set_clipboard_text(lua_tostring(L, 3));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_clipboard_get(lua_State *L) {
|
|
const char *k = lua_tostring(L, 2);
|
|
|
|
if(!strcmp(k, "text")) {
|
|
const char *str = k4_get_clipboard_text();
|
|
|
|
if(str) {
|
|
lua_pushstring(L, str);
|
|
} else {
|
|
lua_pushnil(L);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define CONN_INVALID_PEERCODE 1
|
|
static int conn(const char *peercode, bool host) {
|
|
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
|
|
int b = 0;
|
|
|
|
if(peercode[i * 2 + 0] >= '0' && peercode[i * 2 + 0] <= '9') {
|
|
b |= (peercode[i * 2 + 0] - '0') << 4;
|
|
} else if(peercode[i * 2 + 0] >= 'a' && peercode[i * 2 + 0] <= 'f') {
|
|
b |= (peercode[i * 2 + 0] - 'a' + 10) << 4;
|
|
} else return CONN_INVALID_PEERCODE;
|
|
|
|
if(peercode[i * 2 + 1] >= '0' && peercode[i * 2 + 1] <= '9') {
|
|
b |= (peercode[i * 2 + 1] - '0') << 0;
|
|
} else if(peercode[i * 2 + 1] >= 'a' && peercode[i * 2 + 1] <= 'f') {
|
|
b |= (peercode[i * 2 + 1] - 'a' + 10) << 0;
|
|
} else return CONN_INVALID_PEERCODE;
|
|
|
|
NetWrap.otherpeer[i] = b;
|
|
}
|
|
|
|
NetWrap.isHost = host;
|
|
NetWrap.stage = 3;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dagame_net_host(lua_State *L) {
|
|
int status = conn(lua_tostring(L, 1), true);
|
|
|
|
lua_pushboolean(L, !status);
|
|
|
|
if(status) {
|
|
if(status == CONN_INVALID_PEERCODE) {
|
|
lua_pushliteral(L, "peercode");
|
|
} else {
|
|
lua_pushliteral(L, "unknown");
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int dagame_net_join(lua_State *L) {
|
|
int status = conn(lua_tostring(L, 1), false);
|
|
|
|
lua_pushboolean(L, !status);
|
|
|
|
if(status) {
|
|
if(status == CONN_INVALID_PEERCODE) {
|
|
lua_pushliteral(L, "peercode");
|
|
} else {
|
|
lua_pushliteral(L, "unknown");
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#include<GLFW/glfw3.h>
|
|
static int os_time(lua_State *L) {
|
|
lua_pushnumber(L, glfwGetTime() - LuaapiStartTime);
|
|
return 1;
|
|
}
|
|
|
|
void luaapi_init() {
|
|
k3Log(k3_DEBUG, "Creating Lua environment");
|
|
|
|
L = luaL_newstate();
|
|
|
|
/*lua_newtable(L);
|
|
lua_newtable(L);
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
|
|
lua_setfield(L, -2, "__index");
|
|
lua_setmetatable(L, -2);
|
|
consoleEnvironment = luaL_ref(L, LUA_REGISTRYINDEX);*/
|
|
|
|
k3Log(k3_DEBUG, "Loading Lua stdlib");
|
|
|
|
luaL_requiref(L, "_G", luaopen_base, 1);
|
|
luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
|
|
luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
|
|
luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
|
|
luaL_requiref(L, LUA_DBLIBNAME, luaopen_debug, 1);
|
|
lua_pop(L, 5);
|
|
|
|
k3Log(k3_DEBUG, "Setting custom require");
|
|
|
|
lua_pushcfunction(L, luaapi_require);
|
|
lua_setglobal(L, "require");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game");
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_pushcfunction(L, game_addentity);
|
|
lua_setfield(L, -2, "addentity");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.triggers");
|
|
lua_newtable(L);
|
|
lua_pushvalue(L, -1);
|
|
gametriggersref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, game_triggers_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushcfunction(L, game_triggers_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_setmetatable(L, -2);
|
|
lua_setfield(L, -2, "triggers");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.conveyors");
|
|
lua_newtable(L);
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, game_conveyors_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushcfunction(L, game_conveyors_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
|
|
lua_pushvalue(L, -1);
|
|
gameconveyorsref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
lua_setmetatable(L, -2);
|
|
lua_setfield(L, -2, "conveyors");
|
|
|
|
lua_pushcfunction(L, game_water);
|
|
lua_setfield(L, -2, "water");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.mix");
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, dagame_mixsound);
|
|
lua_setfield(L, -2, "sound");
|
|
|
|
lua_pushcfunction(L, game_mixplay);
|
|
lua_setfield(L, -2, "play");
|
|
|
|
lua_pushcfunction(L, dagame_mixstop);
|
|
lua_setfield(L, -2, "stop");
|
|
|
|
lua_pushcfunction(L, game_mixqueue);
|
|
lua_setfield(L, -2, "queue");
|
|
|
|
lua_pushcfunction(L, dagame_mixpower);
|
|
lua_setfield(L, -2, "power");
|
|
lua_setfield(L, -2, "mix");
|
|
|
|
lua_pushcfunction(L, game_ref);
|
|
lua_setfield(L, -2, "ref");
|
|
|
|
lua_pushcfunction(L, game_batch);
|
|
lua_setfield(L, -2, "batch");
|
|
|
|
lua_pushcfunction(L, game_get_component);
|
|
lua_setfield(L, -2, "getcomponent");
|
|
|
|
lua_pushcfunction(L, game_camfocus);
|
|
lua_setfield(L, -2, "camfocus");
|
|
|
|
lua_pushcfunction(L, game_load);
|
|
lua_setfield(L, -2, "load");
|
|
|
|
lua_pushcfunction(L, dagame_cleanup);
|
|
lua_setfield(L, -2, "cleanup");
|
|
|
|
lua_pushcfunction(L, dagame_joint);
|
|
lua_setfield(L, -2, "joint");
|
|
|
|
lua_pushcfunction(L, dagame_setphys);
|
|
lua_setfield(L, -2, "setphys");
|
|
|
|
lua_pushcfunction(L, dagame_mdl);
|
|
lua_setfield(L, -2, "mdl");
|
|
|
|
lua_pushcfunction(L, dagame_trimesh);
|
|
lua_setfield(L, -2, "trimesh");
|
|
|
|
lua_pushcfunction(L, dagame_firstperson);
|
|
lua_setfield(L, -2, "firstperson");
|
|
|
|
lua_pushcfunction(L, dagame_ray);
|
|
lua_setfield(L, -2, "ray");
|
|
|
|
lua_pushcfunction(L, dagame_draw);
|
|
lua_setfield(L, -2, "draw");
|
|
|
|
lua_pushcfunction(L, dagame_skybox);
|
|
lua_setfield(L, -2, "skybox");
|
|
|
|
lua_pushcfunction(L, dagame_send);
|
|
lua_setfield(L, -2, "send");
|
|
|
|
lua_pushcfunction(L, dagame_set_reduction);
|
|
lua_setfield(L, -2, "set_reduction");
|
|
|
|
lua_pushcfunction(L, dagame_set_texture_reduction);
|
|
lua_setfield(L, -2, "set_texture_reduction");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.ui");
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, dagame_ui_screen);
|
|
lua_setfield(L, -2, "screen");
|
|
|
|
lua_pushcfunction(L, dagame_ui_label);
|
|
lua_setfield(L, -2, "label");
|
|
|
|
lua_pushcfunction(L, dagame_ui_textbutton);
|
|
lua_setfield(L, -2, "textbutton");
|
|
|
|
lua_pushcfunction(L, dagame_ui_textinput);
|
|
lua_setfield(L, -2, "textinput");
|
|
lua_setfield(L, -2, "ui");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.net");
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, dagame_net_gen_peercode);
|
|
lua_setfield(L, -2, "gen_peercode");
|
|
|
|
lua_pushcfunction(L, dagame_net_host);
|
|
lua_setfield(L, -2, "host");
|
|
|
|
lua_pushcfunction(L, dagame_net_join);
|
|
lua_setfield(L, -2, "join");
|
|
lua_setfield(L, -2, "net");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.controls");
|
|
lua_newtable(L);
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, dagame_controls_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, dagame_controls_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_setmetatable(L, -2);
|
|
lua_setfield(L, -2, "controls");
|
|
|
|
k3Log(k3_DEBUG, "Creating table game.clipboard");
|
|
lua_newtable(L);
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, dagame_clipboard_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushcfunction(L, dagame_clipboard_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_setmetatable(L, -2);
|
|
lua_setfield(L, -2, "clipboard");
|
|
|
|
k3Log(k3_DEBUG, "Creating metatable for game");
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, game_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
|
|
lua_pushcfunction(L, game_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
lua_setmetatable(L, -2);
|
|
|
|
lua_setglobal(L, "game");
|
|
|
|
luaL_newmetatable(L, "k3water");
|
|
lua_pushcfunction(L, game_water_simulate);
|
|
lua_setfield(L, -2, "simulate");
|
|
|
|
lua_pushcfunction(L, game_water_update);
|
|
lua_setfield(L, -2, "update");
|
|
|
|
lua_pushcfunction(L, game_water_disturb);
|
|
lua_setfield(L, -2, "disturb");
|
|
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3mixwave");
|
|
lua_pushcfunction(L, game_mixwave_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushcfunction(L, game_mixwave_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, dagame_mixwave_gc);
|
|
lua_setfield(L, -2, "__gc");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3mixqueue");
|
|
lua_pushcfunction(L, game_queue_add);
|
|
lua_setfield(L, -2, "add");
|
|
|
|
lua_pushcfunction(L, game_queue_clear);
|
|
lua_setfield(L, -2, "clear");
|
|
|
|
lua_pushcfunction(L, game_queue_gc);
|
|
lua_setfield(L, -2, "__gc");
|
|
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, game_mixwave_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3submissive");
|
|
lua_pushcfunction(L, game_submissive_assign);
|
|
lua_setfield(L, -2, "assign");
|
|
|
|
lua_pushcfunction(L, game_submissive_load);
|
|
lua_setfield(L, -2, "load");
|
|
|
|
lua_pushcfunction(L, game_submissive_send);
|
|
lua_setfield(L, -2, "send");
|
|
|
|
lua_pushvalue(L, -1);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3cphysics");
|
|
lua_pushcfunction(L, game_cphysics_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, game_cphysics_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3crender");
|
|
lua_pushcfunction(L, game_crender_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
//lua_pushcfunction(L, game_crender_set);
|
|
//lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3cboned");
|
|
lua_pushcfunction(L, game_cboned_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, game_cboned_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3cbonedanim");
|
|
lua_pushcfunction(L, game_cbonedanim_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3mdl");
|
|
lua_pushcfunction(L, game_k3mdl_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3mat");
|
|
lua_pushcfunction(L, game_k3mat_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3physics");
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3matuniforms");
|
|
lua_pushcfunction(L, game_k3matuniforms_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushcfunction(L, game_k3matuniforms_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3body");
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3conveyor");
|
|
lua_pushcfunction(L, game_conveyor_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushcfunction(L, game_conveyor_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k4ray");
|
|
lua_pushcfunction(L, dagame_ray_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3menuitem");
|
|
lua_pushcfunction(L, dagame_k3menuitem_set);
|
|
lua_setfield(L, -2, "__newindex");
|
|
|
|
lua_pushcfunction(L, dagame_k3menuitem_get);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
luaL_newmetatable(L, "k3mixsource");
|
|
lua_pushboolean(L, 0);
|
|
lua_setfield(L, -2, "__metatable");
|
|
lua_pop(L, 1);
|
|
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, os_time);
|
|
lua_setfield(L, -2, "time");
|
|
lua_setglobal(L, "os");
|
|
}
|
|
|
|
void luaapi_load(const char *name) {
|
|
lua_getglobal(L, "require");
|
|
lua_pushstring(L, name);
|
|
if(lua_pcall(L, 1, 1, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
return;
|
|
}
|
|
|
|
lua_getfield(L, -1, "load");
|
|
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
return;
|
|
}
|
|
|
|
if(Game.isAuthority) {
|
|
luaapi_join(NULL, 0);
|
|
}
|
|
}
|
|
|
|
void luaapi_render(double dt, double alpha) {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "render");
|
|
if(!lua_isfunction(L, -1)) {
|
|
lua_pop(L, 1);
|
|
} else {
|
|
lua_pushnumber(L, dt);
|
|
lua_pushnumber(L, alpha);
|
|
if(lua_pcall(L, 2, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
static int game_me_assign(lua_State *L) {
|
|
Game.controlled = lua_tointeger(L, 2);
|
|
Game.spectated = lua_tointeger(L, 2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int luaapi_join(ENetPeer *peer, int oldlua) {
|
|
int ret;
|
|
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "join");
|
|
if(lua_isfunction(L, -1)) {
|
|
if(oldlua) {
|
|
ret = oldlua;
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, oldlua);
|
|
} else if (peer) {
|
|
ENetPeer **ud = lua_newuserdata(L, sizeof(peer));
|
|
*ud = peer;
|
|
luaL_setmetatable(L, "k3submissive");
|
|
lua_pushvalue(L, -1);
|
|
ret = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
} else {
|
|
lua_newtable(L);
|
|
lua_pushcfunction(L, game_me_assign);
|
|
lua_setfield(L, -2, "assign");
|
|
lua_pushvalue(L, -1);
|
|
ret = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
}
|
|
|
|
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
}
|
|
} else {
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
return ret;
|
|
}
|
|
|
|
void luaapi_leave(int ref) {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "leave");
|
|
if(lua_isfunction(L, -1)) {
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
|
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
}
|
|
} else {
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
static char *read_full_file(const char *prepend, const char *fnprefix, const char *fn, const char *append) {
|
|
char namebuf[256];
|
|
snprintf(namebuf, sizeof(namebuf), "%s%s", fnprefix, fn);
|
|
|
|
FILE *f = fopen(namebuf, "rb");
|
|
if(!f) return NULL;
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
size_t sz = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
char *ret = malloc(strlen(prepend) + sz + strlen(append) + 1);
|
|
strcpy(ret, prepend);
|
|
fread(ret + strlen(prepend), 1, sz, f);
|
|
strcpy(ret + strlen(prepend) + sz, append);
|
|
ret[strlen(prepend) + sz + strlen(append)] = 0;
|
|
|
|
fclose(f);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int glsl_version_supported(const char *gl, size_t lua) {
|
|
if((k3IsCore && lua < 330) || (!k3IsCore && lua >= 330)) {
|
|
return 0;
|
|
}
|
|
|
|
char buf[16];
|
|
snprintf(buf, sizeof(buf), "%u", lua);
|
|
|
|
if(gl[0] < buf[0]) {
|
|
return 0;
|
|
}
|
|
|
|
return strcmp(buf + 1, gl + 2) <= 0;
|
|
}
|
|
|
|
static const char *k3glslloader(const char *fn) {
|
|
char buf[512];
|
|
snprintf(buf, sizeof(buf), "assets/mdl/%s", fn);
|
|
|
|
FILE *f = fopen(buf, "rb");
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
|
|
size_t len = ftell(f);
|
|
|
|
char *data = malloc(len + 1);
|
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
fread(data, 1, len, f);
|
|
|
|
data[len] = 0;
|
|
|
|
fclose(f);
|
|
|
|
return data;
|
|
}
|
|
|
|
// The glsl field of a material table is cached and stored
|
|
// in the resource manager. This function generates its name.
|
|
static char *glsl_table_fullname() {
|
|
lua_getfield(L, -1, "vs");
|
|
lua_geti(L, -1, 1); // Version
|
|
size_t vsVer = lua_tointeger(L, -1);
|
|
lua_geti(L, -2, 2); // Filename
|
|
char *vsFile = strdup(lua_tostring(L, -1));
|
|
lua_pop(L, 3);
|
|
|
|
lua_getfield(L, -1, "fs");
|
|
lua_geti(L, -1, 1); // Version
|
|
size_t fsVer = lua_tointeger(L, -1);
|
|
lua_geti(L, -2, 2); // Filename
|
|
char *fsFile = strdup(lua_tostring(L, -1));
|
|
lua_pop(L, 3);
|
|
|
|
char ret[1024];
|
|
snprintf(ret, sizeof(ret), "\x1E%u\x1E%s\x1E%u\x1E%s\x1E", vsVer, vsFile, fsVer, fsFile);
|
|
|
|
lua_getfield(L, -1, "defs");
|
|
lua_pushnil(L);
|
|
while(lua_next(L, -2)) {
|
|
if(!lua_isstring(L, -2)) {
|
|
puts("Ignoring non-string define name.");
|
|
lua_pop(L, 1);
|
|
continue;
|
|
}
|
|
|
|
char def[128];
|
|
snprintf(def, sizeof(def), "%s\x1F%s\x1E", lua_tostring(L, -2), lua_tostring(L, -1));
|
|
|
|
strncat(ret, def, sizeof(ret) - strlen(ret) - 1);
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
free(vsFile);
|
|
free(fsFile);
|
|
|
|
return strdup(ret);
|
|
}
|
|
|
|
static int parse_glsl_table(struct k3Mat *mat) {
|
|
#ifdef k3_IRREGULAR_SHADOWS
|
|
static struct k3GLSLF *irreg1frag, *irreg2frag;
|
|
static struct k3GLSLG *irreg2geom;
|
|
|
|
if(!irreg1frag) {
|
|
char *src = read_full_file("", "", "assets/irregpass1.fs.glsl", "");
|
|
|
|
irreg1frag = k3ShaderGLSLF(src, k3glslloader);
|
|
|
|
free(src);
|
|
}
|
|
if(!irreg2frag) {
|
|
char *src = read_full_file("", "", "assets/irregpass2.fs.glsl", "");
|
|
|
|
irreg2frag = k3ShaderGLSLF(src, k3glslloader);
|
|
|
|
free(src);
|
|
}
|
|
if(!irreg2geom) {
|
|
char *src = read_full_file("", "", "assets/irregpass2.gs.glsl", "");
|
|
|
|
irreg2geom = k3ShaderGLSLG(src, k3glslloader);
|
|
|
|
free(src);
|
|
}
|
|
#endif
|
|
|
|
char *glslfullname = glsl_table_fullname();
|
|
|
|
struct ResManRes *res = resman_reffull(RESMAN_OTHER, glslfullname);
|
|
|
|
if(res->thing) {
|
|
mat->passes[0].glsl.hp = res->thing;
|
|
|
|
#ifdef k3_IRREGULAR_SHADOWS
|
|
glslfullname[0]--;
|
|
mat->passes[0].glsl.hpIrreg1 = resman_ref(RESMAN_OTHER, glslfullname);
|
|
|
|
glslfullname[0]--;
|
|
mat->passes[0].glsl.hpIrreg2 = resman_ref(RESMAN_OTHER, glslfullname);
|
|
#endif
|
|
} else {
|
|
const char *maxGLSL = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB);
|
|
|
|
int i;
|
|
|
|
lua_getfield(L, -1, "vs");
|
|
lua_geti(L, -1, 1); // Version
|
|
size_t vsVer = lua_tointeger(L, -1);
|
|
lua_geti(L, -2, 2); // Filename
|
|
char *vsFile = strdup(lua_tostring(L, -1));
|
|
i = glsl_version_supported(maxGLSL, vsVer);
|
|
lua_pop(L, 3);
|
|
|
|
if(!i) {
|
|
return 0;
|
|
}
|
|
|
|
lua_getfield(L, -1, "fs");
|
|
lua_geti(L, -1, 1); // Version
|
|
size_t fsVer = lua_tointeger(L, -1);
|
|
lua_geti(L, -2, 2); // Filename
|
|
char *fsFile = strdup(lua_tostring(L, -1));
|
|
i = glsl_version_supported(maxGLSL, fsVer);
|
|
lua_pop(L, 3);
|
|
|
|
if(!i) {
|
|
return 0;
|
|
}
|
|
|
|
char defs[512] = {};
|
|
|
|
lua_getfield(L, -1, "defs");
|
|
lua_pushnil(L);
|
|
while(lua_next(L, -2)) {
|
|
if(!lua_isstring(L, -2)) {
|
|
puts("Ignoring non-string define name.");
|
|
lua_pop(L, 1);
|
|
continue;
|
|
}
|
|
|
|
char def[128];
|
|
snprintf(def, sizeof(def), "#define %s %s\n", lua_tostring(L, -2), lua_tostring(L, -1));
|
|
|
|
strncat(defs, def, sizeof(defs) - strlen(defs) - 1);
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
char prefix[272];
|
|
|
|
snprintf(prefix, sizeof(prefix), "#version %lu\n%s", vsVer, defs);
|
|
char *vsSrc = read_full_file(prefix, "assets/mdl/", vsFile, "");
|
|
|
|
snprintf(prefix, sizeof(prefix), "#version %lu\n%s", fsVer, defs);
|
|
char *fsSrc = read_full_file(prefix, "assets/mdl/", fsFile, "");
|
|
|
|
k3Log(k3_INFO, "Attempting to compile \"%s\" & \"%s\"...", vsFile, fsFile);
|
|
|
|
free(vsFile);
|
|
free(fsFile);
|
|
|
|
struct k3GLSLV *vs = k3ShaderGLSLV(vsSrc, k3glslloader);
|
|
struct k3GLSLF *fs = k3ShaderGLSLF(fsSrc, k3glslloader);
|
|
|
|
free(vsSrc);
|
|
free(fsSrc);
|
|
|
|
// FIXME: mark shaders themselves for deletion?
|
|
|
|
struct k3GLSLP *p = k3ProgramGLSL(vs, fs, NULL);
|
|
|
|
res->thing = p;
|
|
|
|
mat->passes[0].glsl.hp = p;
|
|
|
|
#ifdef k3_IRREGULAR_SHADOWS
|
|
glslfullname[0]--;
|
|
mat->passes[0].glsl.hpIrreg1 = k3ProgramGLSL(vs, irreg1frag, NULL);
|
|
resman_reffull(RESMAN_OTHER, glslfullname)->thing = mat->passes[0].glsl.hpIrreg1;
|
|
|
|
glslfullname[0]--;
|
|
mat->passes[0].glsl.hpIrreg2 = k3ProgramGLSL(vs, irreg2frag, irreg2geom);
|
|
resman_reffull(RESMAN_OTHER, glslfullname)->thing = mat->passes[0].glsl.hpIrreg2;
|
|
#endif
|
|
}
|
|
|
|
lua_getfield(L, -1, "u"); // Uniforms
|
|
lua_pushnil(L);
|
|
while(lua_next(L, -2)) {
|
|
if(!lua_isstring(L, -2)) {
|
|
// Ignore non-string key
|
|
k3Log(k3_ERR, "Non-string uniform name in lua material definition.");
|
|
lua_pop(L, 1);
|
|
continue;
|
|
}
|
|
|
|
int u = mat->passes[0].glsl.uCount;
|
|
if(u == k3_MAX_GLSL_UNIFORMS) {
|
|
k3Log(k3_INFO, "Too many uniforms. Skipping.");
|
|
} else {
|
|
strncpy(mat->passes[0].glsl.u[u].name, lua_tostring(L, -2), sizeof(mat->passes[0].glsl.u[u].name));
|
|
mat->passes[0].glsl.u[u].id = k3ProgramGetUId(res->thing, lua_tostring(L, -2));
|
|
|
|
if(lua_isinteger(L, -1)) {
|
|
mat->passes[0].glsl.u[u].type = k3_MAT_UNIFORM_I1;
|
|
mat->passes[0].glsl.u[u].i1 = lua_tointeger(L, -1);
|
|
mat->passes[0].glsl.uCount++;
|
|
} else if(lua_isnumber(L, -1)) {
|
|
mat->passes[0].glsl.u[u].type = k3_MAT_UNIFORM_F1;
|
|
mat->passes[0].glsl.u[u].f1 = lua_tonumber(L, -1);
|
|
mat->passes[0].glsl.uCount++;
|
|
} else {
|
|
k3Log(k3_ERR, "Only i1 and f1 uniforms are supported at the moment.");
|
|
}
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void luaapi_fillmaterial_direct(struct k3Mat *mat) {
|
|
lua_getfield(L, -1, "primitive");
|
|
lua_getfield(L, -1, "diffuse");
|
|
if(lua_istable(L, -1)) {
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
mat->primitive.diffuse[0] = lua_tonumber(L, -4);
|
|
mat->primitive.diffuse[1] = lua_tonumber(L, -3);
|
|
mat->primitive.diffuse[2] = lua_tonumber(L, -2);
|
|
mat->primitive.diffuse[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 4);
|
|
}
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "specular");
|
|
if(lua_istable(L, -1)) {
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
mat->primitive.specular[0] = lua_tonumber(L, -4);
|
|
mat->primitive.specular[1] = lua_tonumber(L, -3);
|
|
mat->primitive.specular[2] = lua_tonumber(L, -2);
|
|
mat->primitive.specular[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 4);
|
|
}
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "emission");
|
|
if(lua_istable(L, -1)) {
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
mat->primitive.emission[0] = lua_tonumber(L, -4);
|
|
mat->primitive.emission[1] = lua_tonumber(L, -3);
|
|
mat->primitive.emission[2] = lua_tonumber(L, -2);
|
|
mat->primitive.emission[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 4);
|
|
}
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, -1, "shininess");
|
|
mat->primitive.shininess = lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
lua_pop(L, 1);
|
|
|
|
GLuint maxMTUnits = 0, maxGLSLUnits = 0;
|
|
if(k3IsCore) {
|
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxGLSLUnits);
|
|
} else {
|
|
if(GLAD_GL_ARB_shading_language_100) {
|
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &maxGLSLUnits);
|
|
}
|
|
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxMTUnits);
|
|
}
|
|
|
|
for(size_t i = 1; i <= 128; i++) {
|
|
int datop = lua_gettop(L);
|
|
|
|
lua_geti(L, -1, i);
|
|
|
|
if(lua_type(L, -1) != LUA_TTABLE) {
|
|
lua_pop(L, 1);
|
|
break;
|
|
}
|
|
|
|
// First pass
|
|
lua_geti(L, -1, 1);
|
|
|
|
lua_getfield(L, -1, "additive");
|
|
mat->passes[0].additive = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "transparent");
|
|
mat->passes[0].transparent = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "nocull");
|
|
mat->passes[0].nocull = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "alphatest");
|
|
mat->passes[0].alphatest = lua_toboolean(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "aabb");
|
|
mat->passes[0].aabb = lua_isnil(L, -1) ? NAN : lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "glsl");
|
|
lua_getfield(L, -2, "arbvp");
|
|
lua_getfield(L, -3, "arbfp");
|
|
if((lua_istable(L, -1) || lua_istable(L, -2)) + lua_istable(L, -3) > 1) {
|
|
k3Log(k3_ERR, "ARB programs and GLSL programs are mutually exclusive.");
|
|
lua_settop(L, datop);
|
|
continue;
|
|
}
|
|
lua_pop(L, 3);
|
|
|
|
int usesGLSL = 0;
|
|
lua_getfield(L, -1, "glsl"); {
|
|
if(lua_istable(L, -1)) {
|
|
if(!k3IsCore && !GLAD_GL_ARB_shading_language_100) {
|
|
// GLSL not supported.
|
|
lua_settop(L, datop);
|
|
continue;
|
|
} else {
|
|
if(!parse_glsl_table(mat)) {
|
|
lua_settop(L, datop);
|
|
continue;
|
|
}
|
|
}
|
|
usesGLSL = 1;
|
|
}
|
|
} lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "arbvp"); {
|
|
if(lua_istable(L, -1)) {
|
|
lua_geti(L, -1, 2);
|
|
char *src = read_full_file("", "assets/mdl/", lua_tostring(L, -1), "");
|
|
mat->passes[0].arbvp.vp = k3ProgramARBVP(src);
|
|
free(src);
|
|
lua_pop(L, 1);
|
|
}
|
|
} lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "arbfp"); {
|
|
if(lua_istable(L, -1)) {
|
|
lua_geti(L, -1, 2);
|
|
char *src = read_full_file("", "assets/mdl/", lua_tostring(L, -1), "");
|
|
mat->passes[0].arbfp.fp = k3ProgramARBFP(src);
|
|
free(src);
|
|
lua_pop(L, 1);
|
|
}
|
|
} lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "units"); {
|
|
size_t amountOfUnits = lua_rawlen(L, -1);
|
|
if(amountOfUnits > (usesGLSL ? maxGLSLUnits : maxMTUnits) || amountOfUnits > k3_MAX_GLSL_UNITS) {
|
|
// Too many texture units.
|
|
// FIXME: This actually isn't a correct test; it should be done per shader
|
|
lua_settop(L, datop);
|
|
continue;
|
|
}
|
|
for(size_t u = 0; u < amountOfUnits; u++) {
|
|
lua_geti(L, -1, u + 1);
|
|
lua_getfield(L, -1, "tex");
|
|
mat->passes[0].units[u] = resman_ref(RESMAN_TEXTURE, lua_tostring(L, -1));
|
|
lua_pop(L, 2);
|
|
}
|
|
mat->passes[0].unitsUsed = amountOfUnits;
|
|
} lua_pop(L, 1);
|
|
|
|
lua_pop(L, 1);
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void luaapi_fillmaterial(const char *fn, struct k3Mat *mat) {
|
|
memset(mat, 0, sizeof(*mat));
|
|
|
|
k3Log(k3_DEBUG, "Loading material %s", fn);
|
|
|
|
if(luaL_loadfilex(L, fn, "t") != LUA_OK || lua_pcall(L, 0, 1, 0) != LUA_OK) {
|
|
mat->primitive.diffuse[0] = (float) rand() / RAND_MAX;
|
|
mat->primitive.diffuse[1] = (float) rand() / RAND_MAX;
|
|
mat->primitive.diffuse[2] = (float) rand() / RAND_MAX;
|
|
mat->primitive.diffuse[3] = 1;
|
|
|
|
mat->passes[0].aabb = NAN;
|
|
|
|
puts(lua_tostring(L, -1));
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return;
|
|
}
|
|
|
|
luaapi_fillmaterial_direct(mat);
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
struct k3Light *luaapi_getlights(size_t *count) {
|
|
static struct k3Light *ret;
|
|
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "lights");
|
|
|
|
if(ret) {
|
|
_mm_free(ret);
|
|
ret = NULL;
|
|
}
|
|
|
|
if(!lua_isnil(L, -1)) {
|
|
lua_len(L, -1);
|
|
*count = lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
ret = _mm_malloc(sizeof(*ret) * *count, 16);
|
|
|
|
memset(ret, 0, sizeof(*ret) * *count);
|
|
|
|
for(size_t i = 0; i < *count; i++) {
|
|
lua_geti(L, -1, i + 1);
|
|
lua_geti(L, -1, 1); // TYPE
|
|
if(!strcmp(lua_tostring(L, -1), "dir")) {
|
|
ret[i].type = k3_DIRECTIONAL;
|
|
} else if(!strcmp(lua_tostring(L, -1), "spot")) {
|
|
ret[i].type = k3_SPOT;
|
|
} else if(!strcmp(lua_tostring(L, -1), "omni")) {
|
|
ret[i].type = k3_OMNI;
|
|
|
|
lua_getfield(L, -2, "direction");
|
|
if(!lua_isnil(L, -1)) {
|
|
ret[i].type = k3_HALF_OMNI;
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "radius");
|
|
ret[i].radius = lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
|
|
lua_getfield(L, -1, "color");
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
ret[i].color[0] = lua_tonumber(L, -4);
|
|
ret[i].color[1] = lua_tonumber(L, -3);
|
|
ret[i].color[2] = lua_tonumber(L, -2);
|
|
ret[i].color[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
|
|
if(ret[i].type == k3_OMNI) {
|
|
lua_getfield(L, -1, "position");
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
ret[i].omni.position[0] = lua_tonumber(L, -4);
|
|
ret[i].omni.position[1] = lua_tonumber(L, -3);
|
|
ret[i].omni.position[2] = lua_tonumber(L, -2);
|
|
ret[i].omni.position[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
} else if(ret[i].type == k3_HALF_OMNI || ret[i].type == k3_SPOT) {
|
|
lua_getfield(L, -1, "position");
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
ret[i].spot.position[0] = lua_tonumber(L, -4);
|
|
ret[i].spot.position[1] = lua_tonumber(L, -3);
|
|
ret[i].spot.position[2] = lua_tonumber(L, -2);
|
|
ret[i].spot.position[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
|
|
lua_getfield(L, -1, "direction");
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
ret[i].spot.direction[0] = lua_tonumber(L, -4);
|
|
ret[i].spot.direction[1] = lua_tonumber(L, -3);
|
|
ret[i].spot.direction[2] = lua_tonumber(L, -2);
|
|
ret[i].spot.direction[3] = lua_tonumber(L, -1);
|
|
lua_pop(L, 5);
|
|
|
|
lua_getfield(L, -1, "angle");
|
|
ret[i].spot.angle = lua_tonumber(L, -1);
|
|
|
|
if(ret[i].spot.angle == 0) {
|
|
ret[i].spot.angle = glm_rad(165);
|
|
}
|
|
lua_pop(L, 1);
|
|
} else if(ret[i].type == k3_DIRECTIONAL) {
|
|
lua_getfield(L, -1, "direction");
|
|
lua_geti(L, -1, 1);
|
|
lua_geti(L, -2, 2);
|
|
lua_geti(L, -3, 3);
|
|
lua_geti(L, -4, 4);
|
|
ret[i].dir.direction[0] = lua_tonumber(L, -4);
|
|
ret[i].dir.direction[1] = lua_tonumber(L, -3);
|
|
ret[i].dir.direction[2] = lua_tonumber(L, -2);
|
|
ret[i].dir.direction[3] = lua_tonumber(L, -1);
|
|
glm_vec3_normalize(ret[i].dir.direction);
|
|
lua_pop(L, 5);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
} else *count = 0;
|
|
|
|
lua_pop(L, 2);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void luaapi_cleanup() {
|
|
game_cleanup();
|
|
|
|
lua_getglobal(L, "game");
|
|
lua_pushnil(L);
|
|
lua_setfield(L, -2, "lights");
|
|
|
|
lua_pushnil(L);
|
|
lua_setfield(L, -2, "render");
|
|
|
|
lua_pushnil(L);
|
|
lua_setfield(L, -2, "render2d");
|
|
|
|
lua_pushnil(L);
|
|
lua_setfield(L, -2, "join");
|
|
|
|
lua_pushnil(L);
|
|
lua_setfield(L, -2, "leave");
|
|
|
|
lua_pushnil(L);
|
|
lua_setfield(L, -2, "ctrl");
|
|
lua_pop(L, 1);
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, gametriggersref);
|
|
while(1) {
|
|
lua_pushnil(L);
|
|
if(lua_next(L, -2) == 0) {
|
|
break;
|
|
}
|
|
lua_pop(L, 1);
|
|
lua_pushnil(L);
|
|
lua_rawset(L, -3);
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
/*void luaapi_perform(const char *statement) {
|
|
puts(statement);
|
|
if(luaL_loadstring(L, statement) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
return;
|
|
}
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, consoleEnvironment);
|
|
lua_setupvalue(L, -2, 1);
|
|
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
return;
|
|
}
|
|
}*/
|
|
|
|
void luaapi_ctrlev(int ctrl, int action) {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "ctrl");
|
|
if(lua_isnil(L, -1)) {
|
|
lua_pop(L, 2);
|
|
return;
|
|
} else {
|
|
lua_pushstring(L, k4_control_get_name_by_ctrl(ctrl));
|
|
lua_pushinteger(L, action);
|
|
if(lua_pcall(L, 2, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 2);
|
|
return;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
void luaapi_render2d() {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "render2d");
|
|
if(lua_isnil(L, -1)) {
|
|
lua_pop(L, 2);
|
|
return;
|
|
} else {
|
|
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 2);
|
|
return;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
int luaapi_recvmsg(struct bstr *b, int cli) {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "receive");
|
|
if(cli == LUA_NOREF) {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, cli);
|
|
}
|
|
if(!deserialize(b)) {
|
|
lua_pop(L, 3);
|
|
return 0;
|
|
}
|
|
if(lua_isnil(L, -3)) {
|
|
lua_pop(L, 4);
|
|
return 1;
|
|
} else {
|
|
if(lua_pcall(L, 2, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 2);
|
|
return 1;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void luaapi_escape() {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "escape");
|
|
if(lua_isnil(L, -1)) {
|
|
lua_pop(L, 2);
|
|
return;
|
|
} else {
|
|
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 2);
|
|
return;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
void luaapi_peercode_found(const char *peercode) {
|
|
if(PeercodeHandler == LUA_NOREF) {
|
|
puts("Peercode found but no handler");
|
|
return;
|
|
}
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, PeercodeHandler);
|
|
if(lua_isnil(L, -1)) {
|
|
lua_pop(L, 1);
|
|
return;
|
|
} else {
|
|
lua_pushstring(L, peercode);
|
|
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
return;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
|
|
luaL_unref(L, LUA_REGISTRYINDEX, PeercodeHandler);
|
|
PeercodeHandler = LUA_NOREF;
|
|
}
|
|
|
|
void luaapi_update() {
|
|
lua_getglobal(L, "game");
|
|
lua_getfield(L, -1, "update");
|
|
if(lua_isnil(L, -1)) {
|
|
lua_pop(L, 2);
|
|
return;
|
|
} else {
|
|
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
|
puts(lua_tostring(L, -1));
|
|
lua_pop(L, 2);
|
|
return;
|
|
}
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|