From 8990e415d3178074f80b3ac5bf7d687794710a3e Mon Sep 17 00:00:00 2001 From: mid <> Date: Sat, 10 May 2025 19:16:20 +0300 Subject: [PATCH] Many API additions --- src/game.c | 48 +++++++- src/game.h | 15 +++ src/luaapi.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/main.c | 83 +------------- 4 files changed, 376 insertions(+), 83 deletions(-) diff --git a/src/game.c b/src/game.c index f8c65e7..8dd7d49 100644 --- a/src/game.c +++ b/src/game.c @@ -150,13 +150,25 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) { int triggerType = activate_pair(g1, g2); if(e1 != ENT_ID_INVALID) { - if(game_getcomponent(e1, physics)->dynamics & CPHYSICS_GHOST) { + struct CPhysics *cp = game_getcomponent(e1, physics); + if(!cp) { + // Entity being killed + return; + } + + if(cp->dynamics & CPHYSICS_GHOST) { ghost = 1; } } if(e2 != ENT_ID_INVALID) { - if(game_getcomponent(e2, physics)->dynamics & CPHYSICS_GHOST) { + struct CPhysics *cp = game_getcomponent(e2, physics); + if(!cp) { + // Entity being killed + return; + } + + if(cp->dynamics & CPHYSICS_GHOST) { ghost = 1; } } @@ -896,3 +908,35 @@ void game_cleanup() { Game.contactgroup = dJointGroupCreate(0); } + +void game_killentity(uint16_t eid) { + // XXX: Go over ALL component types! + + struct CPhysics *cp = game_getcomponent(eid, physics); + if(cp) { + dBodyID bid = dGeomGetBody(cp->geom); + + dGeomDestroy(cp->geom); + + if(bid) { + dBodyDestroy(bid); + } + + game_killcomponent_ptr(cp, physics); + } + + struct CRender *cr = game_getcomponent(eid, render); + if(cr) { + if(cr->cache) { + if(resman_rev(cr->cache)) { + resman_unref(RESMAN_MODEL, cr->cache); + } + } + + game_killcomponent_ptr(cr, render); + } + + game_killcomponent(eid, movement); + game_killcomponent(eid, playerctrl); + game_killcomponent(eid, boned); +} diff --git a/src/game.h b/src/game.h index 6aa0f93..4a66259 100644 --- a/src/game.h +++ b/src/game.h @@ -248,7 +248,22 @@ static inline void *game_ensurecomponent_(uint16_t eid, void *array, size_t comp return ptr; } +#define game_killcomponent_ptr(c, arr) do { \ + size_t idx = c - Game.entities.arr; \ + memmove(c, c + 1, sizeof(*c) * (Game.entities.arr##Count - idx - 1)); \ + Game.entities.arr##Count--; \ +} while(0); + +#define game_killcomponent(eid, arr) do { \ + typeof(&Game.entities.arr[0]) c = game_getcomponent(eid, arr); \ + if(c) { \ + game_killcomponent_ptr(c, arr); \ + } \ +} while(0); + // An artifact of using a third-party physics engine void game_synccphysics(); void game_cleanup(); + +void game_killentity(uint16_t eid); diff --git a/src/luaapi.c b/src/luaapi.c index f28042e..6aeb16e 100644 --- a/src/luaapi.c +++ b/src/luaapi.c @@ -2348,12 +2348,277 @@ static int dagame_mdl_desc_append(lua_State *L) { return 0; } -#include static int os_time(lua_State *L) { lua_pushnumber(L, glfwGetTime() - LuaapiStartTime); return 1; } +static int dagame_particle_system(lua_State *L) { + struct k3CPUQuadParticles *qp = calloc(1, sizeof(*qp)); + qp->capacity = lua_tointeger(L, 1); + + qp->origin[0] = 0; + qp->origin[1] = 0; + qp->origin[2] = 0; + + qp->emissionEnabled = true; + qp->emissionRate = 100; + qp->emissionConeDirection[0] = 0; + qp->emissionConeDirection[1] = 1; + qp->emissionConeDirection[2] = 0; + qp->emissionConeAngle = M_PI / 2; + qp->gravity[0] = 0; + qp->gravity[1] = 0.03; + qp->gravity[2] = 0; + qp->particleLifetime = 4; + + qp->colorStart[0] = 1; + qp->colorStart[1] = 1; + qp->colorStart[2] = 1; + qp->colorStart[3] = 1; + + qp->colorEnd[0] = 1; + qp->colorEnd[1] = 1; + qp->colorEnd[2] = 1; + qp->colorEnd[3] = 0; + + struct k3Mat *mat = *(struct k3Mat**) lua_touserdata(L, 2); + /*struct k3Mat mat = { + .primitive = { + .diffuse = {1, 1, 1, 1}, + .specular = {0, 0, 0, 0}, + .emission = {0, 0, 0, 0}, + .shininess = 16, + }, + .passes = { + { + .unitsUsed = 0, + .aabb = NAN, + .transparent = true, + .nocull = false, + .alphatest = false, + .depthwrite = false, + } + }, + };*/ + + k3CPUQuadParticlesInit(qp, mat); + + void **z = lua_newuserdata(L, sizeof(*z)); + *z = qp; + luaL_setmetatable(L, "k3cpuparticles"); + + return 1; +} + +static int dagame_k3cpuparticles_update(lua_State *L) { + struct k3CPUQuadParticles *qp = *(void**) lua_touserdata(L, 1); + k3CPUQuadParticlesUpdate(qp, lua_tonumber(L, 2), &LuaapiCamMatrix[0], &LuaapiCamMatrix[1], &LuaapiCamMatrix[2]); + lua_pushvalue(L, 1); + return 1; +} + +static int dagame_k3cpuparticles_set(lua_State *L) { + struct k3CPUQuadParticles *qp = *(void**) lua_touserdata(L, 1); + + const char *key = lua_tostring(L, 2); + + if(!strcmp(key, "origin")) { + lua_geti(L, 3, 1); + lua_geti(L, 3, 2); + lua_geti(L, 3, 3); + qp->origin[0] = lua_tonumber(L, -3); + qp->origin[1] = lua_tonumber(L, -2); + qp->origin[2] = lua_tonumber(L, -1); + lua_pop(L, 3); + } else if(!strcmp(key, "enabled")) { + qp->emissionEnabled = lua_toboolean(L, 3); + } else if(!strcmp(key, "rate")) { + qp->emissionRate = lua_tonumber(L, 3); + } else if(!strcmp(key, "cone_direction")) { + lua_geti(L, 3, 1); + lua_geti(L, 3, 2); + lua_geti(L, 3, 3); + qp->emissionConeDirection[0] = lua_tonumber(L, -3); + qp->emissionConeDirection[1] = lua_tonumber(L, -2); + qp->emissionConeDirection[2] = lua_tonumber(L, -1); + lua_pop(L, 3); + } else if(!strcmp(key, "cone_angle")) { + qp->emissionConeAngle = lua_tonumber(L, 3); + } else if(!strcmp(key, "gravity")) { + lua_geti(L, 3, 1); + lua_geti(L, 3, 2); + lua_geti(L, 3, 3); + qp->gravity[0] = lua_tonumber(L, -3); + qp->gravity[1] = lua_tonumber(L, -2); + qp->gravity[2] = lua_tonumber(L, -1); + lua_pop(L, 3); + } else if(!strcmp(key, "lifetime")) { + qp->particleLifetime = lua_tonumber(L, 3); + } else if(!strcmp(key, "remaining")) { + qp->emissionLifetime = lua_tonumber(L, 3); + } else if(!strcmp(key, "color_start")) { + lua_geti(L, 3, 1); + lua_geti(L, 3, 2); + lua_geti(L, 3, 3); + lua_geti(L, 3, 4); + qp->colorStart[0] = lua_tonumber(L, -4); + qp->colorStart[1] = lua_tonumber(L, -3); + qp->colorStart[2] = lua_tonumber(L, -2); + qp->colorStart[3] = lua_tonumber(L, -1); + lua_pop(L, 4); + } else if(!strcmp(key, "color_end")) { + lua_geti(L, 3, 1); + lua_geti(L, 3, 2); + lua_geti(L, 3, 3); + lua_geti(L, 3, 4); + qp->colorEnd[0] = lua_tonumber(L, -4); + qp->colorEnd[1] = lua_tonumber(L, -3); + qp->colorEnd[2] = lua_tonumber(L, -2); + qp->colorEnd[3] = lua_tonumber(L, -1); + lua_pop(L, 4); + } + + return 0; +} + +static int dagame_k3cpuparticles_get(lua_State *L) { + struct k3CPUQuadParticles *qp = *(void**) lua_touserdata(L, 1); + + const char *key = lua_tostring(L, 2); + + if(!strcmp(key, "update")) { + lua_pushcfunction(L, dagame_k3cpuparticles_update); + return 1; + } else if(!strcmp(key, "remaining")) { + lua_pushnumber(L, qp->emissionLifetime); + return 1; + } else if(!strcmp(key, "count")) { + lua_pushinteger(L, qp->count); + return 1; + } + + return 0; +} + +#include"noise1234.h" +static int dagame_perlin3(lua_State *L) { + lua_pushnumber(L, noise3(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tonumber(L, 3))); + + return 1; +} + +static int dagame_fbm(lua_State *L) { + float x = lua_tonumber(L, 1); + float y = lua_tonumber(L, 2); + float z = lua_tonumber(L, 3); + int octaves = lua_type(L, 4) == LUA_TNIL ? 8 : lua_tointeger(L, 4); + float lacunarity = lua_type(L, 5) == LUA_TNIL ? 2 : lua_tonumber(L, 5); + float gain = lua_type(L, 6) == LUA_TNIL ? 0.5 : lua_tonumber(L, 6); + float sum = 0; + float freq = 1; + float amp = 1; + for(int o = 0; o < octaves; o++) { + sum += amp * noise3(x * freq, y * freq, z * freq); + amp *= gain; + freq *= lacunarity; + } + lua_pushnumber(L, sum); + return 1; +} + +static int dagame_kill(lua_State *L) { + if(lua_type(L, 1) != LUA_TNUMBER) { + return luaL_error(L, "Invalid entity ID"); + } + + game_killentity(lua_tointeger(L, 1)); +} + +static int dagame_animator(lua_State *L) { + struct Animator *this = lua_newuserdata(L, sizeof(*this)); + + this->mdl = *(struct k3Mdl**) lua_touserdata(L, 1); + memset(&this->animator, 0, sizeof(this->animator)); + + size_t boneCount = k3MdlGetBoneCount(this->mdl); + this->bones = _mm_malloc(boneCount * sizeof(*this->bones), 16); + for(size_t b = 0; b < boneCount; b++) { + this->bones[b].translation[0] = 0; + this->bones[b].translation[1] = 0; + this->bones[b].translation[2] = 0; + this->bones[b].translation[3] = 1; + + this->bones[b].rotation[0] = 0; + this->bones[b].rotation[1] = 0; + this->bones[b].rotation[2] = 0; + this->bones[b].rotation[3] = 1; + } + + luaL_setmetatable(L, "k4animator"); + + return 1; +} + +static int dagame_animator_set(lua_State *L) { + struct Animator *this = lua_touserdata(L, 1); + + size_t animIdx = lua_tointeger(L, 2); + + this->animator.base = k3MdlGetAnim(this->mdl, animIdx); + this->animator.loop = false; + + this->playStartTime = glfwGetTime(); + k3AnimatorSet(&this->animator, 0); + + lua_pushvalue(L, 1); + + return 1; +} + +static int dagame_animator_play(lua_State *L) { + struct Animator *this = lua_touserdata(L, 1); + + this->playing = true; + this->playStartTime = glfwGetTime(); +} + +static int dagame_animator_index(lua_State *L) { + struct Animator *this = lua_touserdata(L, 1); + + const char *key = lua_tostring(L, 2); + + if(!strcmp(key, "set")) { + lua_pushcfunction(L, dagame_animator_set); + return 1; + } else if(!strcmp(key, "play")) { + lua_pushcfunction(L, dagame_animator_play); + return 1; + } else if(!strcmp(key, "time")) { + lua_pushnumber(L, this->animator.time); + return 1; + } else if(!strcmp(key, "loop")) { + lua_pushboolean(L, this->animator.loop); + return 1; + } + + return 0; +} + +static int dagame_animator_newindex(lua_State *L) { + struct Animator *this = lua_touserdata(L, 1); + + const char *key = lua_tostring(L, 2); + + if(!strcmp(key, "time")) { + k3AnimatorSet(&this->animator, lua_tonumber(L, 3)); + } else if(!strcmp(key, "loop")) { + this->animator.loop = lua_toboolean(L, 3); + } + + return 0; +} + void luaapi_init() { k3Log(k3_DEBUG, "Creating Lua environment"); @@ -2496,6 +2761,21 @@ void luaapi_init() { lua_pushcfunction(L, dagame_set_texture_reduction); lua_setfield(L, -2, "set_texture_reduction"); + lua_pushcfunction(L, dagame_particle_system); + lua_setfield(L, -2, "particle_system"); + + lua_pushcfunction(L, dagame_perlin3); + lua_setfield(L, -2, "perlin3"); + + lua_pushcfunction(L, dagame_fbm); + lua_setfield(L, -2, "fbm3"); + + lua_pushcfunction(L, dagame_kill); + lua_setfield(L, -2, "kill"); + + lua_pushcfunction(L, dagame_animator); + lua_setfield(L, -2, "animator"); + k3Log(k3_DEBUG, "Creating table game.ui"); lua_newtable(L); lua_pushcfunction(L, dagame_ui_screen); @@ -2753,6 +3033,28 @@ void luaapi_init() { lua_pushcfunction(L, os_time); lua_setfield(L, -2, "time"); lua_setglobal(L, "os"); + + luaL_newmetatable(L, "k3cpuparticles"); + lua_pushcfunction(L, dagame_k3cpuparticles_set); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, dagame_k3cpuparticles_get); + lua_setfield(L, -2, "__index"); + + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + lua_pop(L, 1); + + luaL_newmetatable(L, "k4animator"); + lua_pushcfunction(L, dagame_animator_index); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, dagame_animator_newindex); + lua_setfield(L, -2, "__newindex"); + + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + lua_pop(L, 1); } void luaapi_load(const char *name) { @@ -3211,6 +3513,10 @@ void luaapi_fillmaterial_direct(struct k3Mat *mat) { mat->passes[0].alphatest = lua_toboolean(L, -1); lua_pop(L, 1); + lua_getfield(L, -1, "depthwrite"); + mat->passes[0].depthwrite = lua_isnil(L, -1) ? true : 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); @@ -3417,6 +3723,9 @@ struct k3Light *luaapi_getlights(size_t *count) { ret[i].dir.direction[3] = lua_tonumber(L, -1); glm_vec3_normalize(ret[i].dir.direction); lua_pop(L, 5); + lua_getfield(L, -1, "cascades"); + ret[i].dir.cascadeCount = lua_tointeger(L, -1); + lua_pop(L, 1); } lua_pop(L, 1); } @@ -3428,6 +3737,8 @@ struct k3Light *luaapi_getlights(size_t *count) { } void luaapi_cleanup() { + LuaapiCamFocus = false; + game_cleanup(); lua_getglobal(L, "game"); diff --git a/src/main.c b/src/main.c index cbd0064..a5fc860 100644 --- a/src/main.c +++ b/src/main.c @@ -46,6 +46,7 @@ static int TextureResolutionReduction = 0; static int IrregularShadows = 0; +static int InstantCamShift = 5; static float CamPitch, CamYaw; static vec3 CamPos; static int ThirdPerson = 1; @@ -169,8 +170,10 @@ static void charcallback(GLFWwindow *window, unsigned int codepoint) { } } +static void fix_resol(); static void resizecallback(GLFWwindow *window, int width, int height) { k3Resize(width, height); + fix_resol(); } static int argc; @@ -184,86 +187,6 @@ const char *k4_get_arg(const char *name) { return NULL; } -/*static void netwrap_step() { - if(NetWrap.stage && CurrentTime >= NetWrap.timeout) { - if(NetWrap.stage == 1) { - if(stoon_req(&NetWrap.stoon)) { - if(stoon_listen(&NetWrap.stoon)) { - uint8_t conndata[STOON_CONN_INFO_SIZE] = {}; - stoon_serialize(&NetWrap.stoon, conndata); - - char str[STOON_CONN_INFO_SIZE * 2 + 1] = {}; - for(int i = 0; i < sizeof(conndata); i++) { - snprintf(str + i * 2, 3, "%02x", conndata[i]); - } - - luaapi_peercode_found(str); - - NetWrap.stage = 2; - } else { - k3Log(k3_INFO, "Stoon listen timeout."); - NetWrap.timeout = CurrentTime + 0.5; - } - } else { - k3Log(k3_INFO, "Stoon request failed."); - NetWrap.timeout = CurrentTime + 0.5; - } - } else if(NetWrap.stage == 2) { - stoon_keepalive(&NetWrap.stoon); - NetWrap.timeout = CurrentTime + 1; - } else if(NetWrap.stage == 3) { - if(NetWrap.isHost) { - stoon_kill(&NetWrap.stoon); - net_server_init(); - NetWrap.stage = 4; - } - } else if(NetWrap.stage == 4) { - if(NetWrap.isHost) { - ENetBuffer buf = {.data = "Punch!", .dataLength = 6}; - - ENetHost *h = net_server_get_enethost(); - - for(size_t i = 0; i < NETWRAP_BACKLOG; i++) { - if(NetWrap.otherpeersActive[i]) { - ENetAddress v4 = {}, v6 = {}; - stoonpeer_to_enets(NetWrap.otherpeers[i], &v4, &v6); - - enet_socket_send(h->socket, &v4, &buf, 1); - enet_socket_send(h->socket, &v6, &buf, 1); - } - } - } else { - stoon_keepalive(&NetWrap.stoon); - } - - NetWrap.timeout = CurrentTime + 1; - } else if(NetWrap.stage == 5) { - if(!NetWrap.isHost) { - char ip[64]; - int port; - if(*(uint16_t*) (NetWrap.otherpeer + 22) == 0) { - inet_ntop(AF_INET, NetWrap.otherpeer, ip, sizeof(ip)); - port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 4)); - } else { - inet_ntop(AF_INET6, NetWrap.otherpeer + 6, ip, sizeof(ip)); - port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 22)); - } - - printf("Trying [%s]:%u\n", ip, port); - - net_client_init(); - if(net_client_connect(ip, port)) { - NetWrap.stage = 5; - } - } - - NetWrap.timeout = CurrentTime + 0.5; - } else { - NetWrap.timeout = CurrentTime + 1; - } - } -}*/ - #include void k4k3LogCallback(enum k3LogLevel lvl, const char *str, size_t len) { static const char *prefixes[] = {