Introduce animation trees, remove "standard animations" from core

This commit is contained in:
mid 2025-08-10 15:42:45 +03:00
parent 96da001734
commit dbced43b2b
8 changed files with 505 additions and 168 deletions

View File

@ -115,6 +115,8 @@ def write_some_data(context, filepath, doExportEverything):
out.write(struct.pack("4f", m.col[c][0], m.col[c][1], m.col[c][2], m.col[c][3])) out.write(struct.pack("4f", m.col[c][0], m.col[c][1], m.col[c][2], m.col[c][3]))
for b in dabones: for b in dabones:
out.write(struct.pack("B", dabones.index(b.parent) if b.parent else 255)) out.write(struct.pack("B", dabones.index(b.parent) if b.parent else 255))
for b in dabones:
out.write(b.name.encode("UTF-8") + b'\x00')
for v in vertdict.keys(): for v in vertdict.keys():
out.write(struct.pack("3f", v[0][0], v[0][2], -v[0][1])) out.write(struct.pack("3f", v[0][0], v[0][2], -v[0][1]))

View File

@ -685,7 +685,7 @@ void game_update() {
size_t boneCount = Game.entities.render[ci].cache ? k3MdlGetBoneCount(Game.entities.render[ci].cache) : 0; size_t boneCount = Game.entities.render[ci].cache ? k3MdlGetBoneCount(Game.entities.render[ci].cache) : 0;
if(boneCount) { if(boneCount) {
struct CBoned *cb = game_getcomponent(Game.entities.render[ci].entity, boned); /*struct CBoned *cb = game_getcomponent(Game.entities.render[ci].entity, boned);
if(!cb) { if(!cb) {
cb = game_ensurecomponent(Game.entities.render[ci].entity, boned); cb = game_ensurecomponent(Game.entities.render[ci].entity, boned);
@ -741,7 +741,7 @@ void game_update() {
glm_decompose(cb->anim.cache.inter[m], cb->bones[m].translation, rot, scaleignore); glm_decompose(cb->anim.cache.inter[m], cb->bones[m].translation, rot, scaleignore);
glm_mat4_quat(cb->anim.cache.inter[m], cb->bones[m].rotation); glm_mat4_quat(cb->anim.cache.inter[m], cb->bones[m].rotation);
} }
} }*/
} }
dGeomID gid = cp->geom; dGeomID gid = cp->geom;
@ -776,7 +776,7 @@ void game_update() {
for(size_t cm = 0; cm < Game.entities.movementCount; cm++) { for(size_t cm = 0; cm < Game.entities.movementCount; cm++) {
struct CBoned *cb = game_getcomponent(Game.entities.movement[cm].entity, boned); struct CBoned *cb = game_getcomponent(Game.entities.movement[cm].entity, boned);
if(cb && cb->anim.standard) { /*if(cb && cb->anim.standard) {
struct CPhysics *cp = game_getcomponent(Game.entities.movement[cm].entity, physics); struct CPhysics *cp = game_getcomponent(Game.entities.movement[cm].entity, physics);
if(cp && cp->geom) { if(cp && cp->geom) {
dBodyID bid = dGeomGetBody(cp->geom); dBodyID bid = dGeomGetBody(cp->geom);
@ -789,7 +789,7 @@ void game_update() {
} }
} }
} }
} }*/
} }
for(size_t i = 0; i < Game.conveyorCount; i++) { for(size_t i = 0; i < Game.conveyorCount; i++) {
@ -876,7 +876,6 @@ void game_update() {
vec3 dif; vec3 dif;
glm_vec3_sub(conveyor->points[nextPoint], conveyor->points[currentPoint], dif); glm_vec3_sub(conveyor->points[nextPoint], conveyor->points[currentPoint], dif);
glm_vec3_scale_as(dif, conveyor->speed * (conveyor->active <= 0 ? -1 : 1), dif); glm_vec3_scale_as(dif, conveyor->speed * (conveyor->active <= 0 ? -1 : 1), dif);
//printf("set %f %f %f\n", dif[0], dif[1], dif[2]);
dBodySetLinearVel(bid, dif[0], dif[1], dif[2]); // doesn't affect movement, but necessary for proper collision response dBodySetLinearVel(bid, dif[0], dif[1], dif[2]); // doesn't affect movement, but necessary for proper collision response
} }
} }
@ -950,7 +949,7 @@ void game_cleanup() {
Game.entities.renderCount = 0; Game.entities.renderCount = 0;
for(size_t i = 0; i < Game.entities.bonedCount; i++) { for(size_t i = 0; i < Game.entities.bonedCount; i++) {
free(Game.entities.boned[i].bones); //free(Game.entities.boned[i].bones);
} }
Game.entities.bonedCount = 0; Game.entities.bonedCount = 0;

View File

@ -118,14 +118,7 @@ struct CPlayerCtrl {
struct CBoned { struct CBoned {
uint16_t entity; uint16_t entity;
size_t size; struct k3Animator animator;
struct k3AnimationBone *bones;
struct {
uint16_t id;
struct k3Animator cache;
bool standard;
} anim;
}; };
#define CONVEYOR_TYPE_LOOP 0 #define CONVEYOR_TYPE_LOOP 0

View File

@ -33,6 +33,17 @@ static int mdlloader(void *ud, struct ResManRes *res) {
uint8_t *boneParents = malloc(header.boneCount); uint8_t *boneParents = malloc(header.boneCount);
fread(boneParents, 1, header.boneCount, f); fread(boneParents, 1, header.boneCount, f);
char boneNames[1500] = {};
size_t boneNamesLen = 0;
for(size_t b = 0; b < header.boneCount; b++) {
while(1) {
fread(boneNames + boneNamesLen, 1, 1, f);
if(boneNames[boneNamesLen++] == 0) {
break;
}
}
}
vec3 *pos = malloc(sizeof(*pos) * header.vertCount); vec3 *pos = malloc(sizeof(*pos) * header.vertCount);
fread(pos, sizeof(vec3), header.vertCount, f); fread(pos, sizeof(vec3), header.vertCount, f);
@ -59,6 +70,8 @@ static int mdlloader(void *ud, struct ResManRes *res) {
struct k3Mdl *mdl = k3MdlCreate(header.vertCount, header.indCount, header.boneCount, pos, nrm, uvs, cols, boneIDs, boneWeights, inds, invBind, boneParents); struct k3Mdl *mdl = k3MdlCreate(header.vertCount, header.indCount, header.boneCount, pos, nrm, uvs, cols, boneIDs, boneWeights, inds, invBind, boneParents);
k3MdlSetBoneNames(mdl, boneNames);
k3MdlSetDebugName(mdl, res->name); k3MdlSetDebugName(mdl, res->name);
free(pos); free(pos);
@ -87,22 +100,19 @@ static int mdlloader(void *ud, struct ResManRes *res) {
for(size_t i = 0; i < header.animCount; i++) { for(size_t i = 0; i < header.animCount; i++) {
struct { struct {
uint16_t id; uint16_t id;
uint16_t frames; uint16_t frameCount;
uint16_t fps; uint16_t fps;
uint16_t zero; uint16_t zero;
} info; } info;
fread(&info, sizeof(info), 1, f); fread(&info, sizeof(info), 1, f);
struct k3Animation *anim = malloc(sizeof(*anim)); struct k3AnimationFountain *anim = _mm_malloc(sizeof(*anim) + sizeof(*anim->frames) * info.frameCount * header.boneCount, 16);
anim->frames = _mm_malloc(sizeof(*anim->frames) * info.frames * header.boneCount, 16);
anim->boneParents = boneParents;
anim->invBind = invBind;
anim->id = info.id; anim->id = info.id;
anim->fps = info.fps; anim->fps = info.fps;
anim->frameCount = info.frames; anim->frameCount = info.frameCount;
anim->boneCount = header.boneCount; anim->bones = header.boneCount;
fread(anim->frames, sizeof(*anim->frames), info.frames * header.boneCount, f); fread(anim->frames, sizeof(*anim->frames), info.frameCount * header.boneCount, f);
k3MdlAddAnim(mdl, anim); k3MdlAddAnim(mdl, anim);
} }

View File

@ -183,15 +183,6 @@ struct mixitem {
int type; int type;
}; };
struct Animator {
struct k3Mdl *mdl;
struct k3Animator animator;
struct k3AnimationBone *bones;
bool playing;
double playStartTime;
};
static int game_addentity(lua_State *L) { static int game_addentity(lua_State *L) {
lua_Integer li; lua_Integer li;
int i; int i;
@ -347,7 +338,7 @@ static int game_addentity(lua_State *L) {
setstrstatic("mdl", c.mdl, sizeof(c.mdl)); setstrstatic("mdl", c.mdl, sizeof(c.mdl));
//c.animator.base = NULL; c.cache = k3MdlCopySubs((struct k3Mdl*) resman_ref(RESMAN_MODEL, c.mdl));
game_addcomponent(render, &c); game_addcomponent(render, &c);
} }
@ -380,76 +371,7 @@ static int game_addentity(lua_State *L) {
c.entity = id; c.entity = id;
lua_getfield(L, -1, "size"); k3AnimatorInit(&c.animator, game_getcomponent(id, render)->cache);
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); game_addcomponent(boned, &c);
} }
@ -912,26 +834,15 @@ static int game_batch(lua_State *L) {
struct k3AnimationBone *bones = NULL; struct k3AnimationBone *bones = NULL;
if(lua_gettop(L) >= 4) { if(lua_type(L, 4) == LUA_TUSERDATA) {
struct Animator *anim = lua_touserdata(L, 4); struct k3Animator *animator = *(void**) lua_touserdata(L, 4);
if(animator->playing) {
if(anim->playing) { k3AnimatorSet(animator, glfwGetTime() - animator->playStartTime);
k3AnimatorSet(&anim->animator, glfwGetTime() - anim->playStartTime);
}
bones = anim->bones;
size_t boneCount = k3MdlGetBoneCount(anim->mdl);
for(size_t m = 0; m < boneCount; m++) {
vec3 scaleignore;
mat4 rot;
glm_decompose(anim->animator.inter[m], bones[m].translation, rot, scaleignore);
glm_mat4_quat(anim->animator.inter[m], bones[m].rotation);
} }
bones = animator->bones;
} }
if(lua_gettop(L) >= 3) { if(lua_type(L, 3) == LUA_TTABLE) {
mat4 anchor; mat4 anchor;
for(int i = 0; i < 16; i++) { for(int i = 0; i < 16; i++) {
lua_rawgeti(L, 3, i + 1); lua_rawgeti(L, 3, i + 1);
@ -1084,8 +995,8 @@ static int game_cphysics_get(lua_State *L) {
} else if(!strcmp(k, "vel")) { } else if(!strcmp(k, "vel")) {
lua_newtable(L); lua_newtable(L);
dBodyID bid = dGeomGetBody(c->geom); dBodyID bid;
if(bid) { if(c->geom && (bid = dGeomGetBody(c->geom))) {
const float *v = dBodyGetLinearVel(bid); const float *v = dBodyGetLinearVel(bid);
lua_pushnumber(L, v[0]); lua_pushnumber(L, v[0]);
@ -1196,7 +1107,7 @@ static int game_cboned_get(lua_State *L) {
const char *k = lua_tostring(L, 2); const char *k = lua_tostring(L, 2);
if(!strcmp(k, "bones")) { /*if(!strcmp(k, "bones")) {
lua_newtable(L); lua_newtable(L);
for(size_t i = 0; i < c->size; i++) { for(size_t i = 0; i < c->size; i++) {
@ -1231,6 +1142,13 @@ static int game_cboned_get(lua_State *L) {
*c2 = c; *c2 = c;
luaL_setmetatable(L, "k3cbonedanim"); luaL_setmetatable(L, "k3cbonedanim");
return 1;
}*/
if(!strcmp(k, "animator")) {
*(void**) lua_newuserdata(L, sizeof(struct k3Animator*)) = &c->animator;
luaL_setmetatable(L, "k4animatorptr");
return 1; return 1;
} }
@ -1242,7 +1160,7 @@ static int game_cboned_set(lua_State *L) {
const char *k = lua_tostring(L, 2); const char *k = lua_tostring(L, 2);
if(!strcmp(k, "bones")) { /*if(!strcmp(k, "bones")) {
size_t newlen = luaL_len(L, 3); size_t newlen = luaL_len(L, 3);
if(newlen != c->size) { if(newlen != c->size) {
@ -1276,7 +1194,7 @@ static int game_cboned_set(lua_State *L) {
lua_pop(L, 1); lua_pop(L, 1);
} }
} }*/
return 0; return 0;
} }
@ -1284,14 +1202,14 @@ static int game_cboned_set(lua_State *L) {
static int game_cbonedanim_set(lua_State *L) { static int game_cbonedanim_set(lua_State *L) {
struct CBoned *c = *(struct CBoned**) lua_touserdata(L, 1); struct CBoned *c = *(struct CBoned**) lua_touserdata(L, 1);
const char *k = lua_tostring(L, 2); /*const char *k = lua_tostring(L, 2);
if(!strcmp(k, "id")) { if(!strcmp(k, "id")) {
c->anim.id = lua_tointeger(L, 3); c->anim.id = lua_tointeger(L, 3);
c->anim.cache.base = NULL; //c->anim.cache.base = NULL;
} else if(!strcmp(k, "standard")) { } else if(!strcmp(k, "standard")) {
c->anim.standard = lua_toboolean(L, 3); c->anim.standard = lua_toboolean(L, 3);
} }*/
return 0; return 0;
} }
@ -1413,13 +1331,47 @@ static int game_k3mdl_addmesh(lua_State *L) {
k3MdlAddMesh(mdl, &mat, start, count); k3MdlAddMesh(mdl, &mat, start, count);
} }
static int game_k3mdl_query_weights(lua_State *L) {
struct k3Mdl *mdl = *(struct k3Mdl**) lua_touserdata(L, 1);
int qbone = k3MdlGetBoneFromName(mdl, lua_tostring(L, 2));
if(qbone < 0) {
return 0;
}
size_t bones = k3MdlGetBoneCount(mdl);
float w[bones];
memset(w, 0, sizeof(*w) * bones);
k3MdlQueryWeights(mdl, qbone, w);
// Inclusive
if(lua_toboolean(L, 3)) {
w[qbone] = 1.0f;
}
lua_newtable(L);
for(size_t b = 0; b < bones; b++) {
// Invert
if(lua_toboolean(L, 4)) {
w[b] = 1.0f - w[b];
}
lua_pushnumber(L, w[b]);
lua_rawseti(L, -2, b + 1);
}
return 1;
}
static int game_k3mdl_get(lua_State *L) { static int game_k3mdl_get(lua_State *L) {
struct k3Mdl *mdl = *(struct k3Mdl**) lua_touserdata(L, 1); 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) { if(lua_type(L, 2) == LUA_TNUMBER) {
size_t count;
struct k3Mesh *meshes = k3MdlGetMeshes(mdl, &count);
lua_Integer i = lua_tointeger(L, 2); lua_Integer i = lua_tointeger(L, 2);
if(i >= 1 && i <= count) { if(i >= 1 && i <= count) {
struct k3Mat **m = lua_newuserdata(L, sizeof(*m)); struct k3Mat **m = lua_newuserdata(L, sizeof(*m));
@ -1428,8 +1380,14 @@ static int game_k3mdl_get(lua_State *L) {
} else { } else {
lua_pushnil(L); lua_pushnil(L);
} }
} else if(!strcmp(lua_tostring(L, 2), "addmesh")) { } else {
lua_pushcfunction(L, game_k3mdl_addmesh); const char *key = lua_tostring(L, 2);
if(!strcmp(key, "addmesh")) {
lua_pushcfunction(L, game_k3mdl_addmesh);
} else if(!strcmp(key, "query_weights")) {
lua_pushcfunction(L, game_k3mdl_query_weights);
}
} }
return 1; return 1;
@ -2687,55 +2645,169 @@ static int dagame_kill(lua_State *L) {
} }
static int dagame_animator(lua_State *L) { static int dagame_animator(lua_State *L) {
struct Animator *this = lua_newuserdata(L, sizeof(*this)); struct k3Animator *this = (*(void**) lua_newuserdata(L, sizeof(void*)) = calloc(1, sizeof(struct k3Animator)));
this->mdl = *(struct k3Mdl**) lua_touserdata(L, 1); k3AnimatorInit(this, *(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"); luaL_setmetatable(L, "k4animator");
return 1; return 1;
} }
static struct k3Animation *parse_animation_table(struct k3Animator *this) {
enum k3AnimationOp op;
lua_getfield(L, -1, "type");
if(!strcmp(lua_tostring(L, -1), "base")) {
lua_pop(L, 1);
op = k3_ANIM_BASIC;
} else if(!strcmp(lua_tostring(L, -1), "blend")) {
lua_pop(L, 1);
op = k3_ANIM_BLEND;
} else if(!strcmp(lua_tostring(L, -1), "add")) {
lua_pop(L, 1);
op = k3_ANIM_ADD;
} else {
lua_pop(L, 1);
return NULL;
}
if(op == k3_ANIM_BASIC) {
lua_getfield(L, -1, "id");
size_t idx = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "loop");
bool loop = lua_toboolean(L, -1);
lua_pop(L, 1);
struct k3AnimationBasic *b = calloc(1, sizeof(*b));
b->op = op;
b->bones = k3MdlGetBoneCount(this->mdl);
b->fountain = k3MdlGetAnim(this->mdl, idx);
b->loop = loop;
if(!b->fountain) {
k3Log(k3_ERR, "Base %lu does not exist", idx);
}
return (struct k3Animation*) b;
} else if(op == k3_ANIM_BLEND) {
struct k3AnimationBlend *b = calloc(1, sizeof(*b));
b->op = op;
b->bones = k3MdlGetBoneCount(this->mdl);
lua_len(L, -1);
b->children = lua_tointeger(L, -1);
lua_pop(L, 1);
b->subs = calloc(b->children, sizeof(*b->subs));
b->weights = calloc(b->children * b->bones, sizeof(*b->weights));
b->offsets = calloc(b->children, sizeof(*b->offsets));
b->speeds = calloc(b->children, sizeof(*b->speeds));
for(size_t c = 0; c < b->children; c++) {
lua_geti(L, -1, c + 1);
lua_getfield(L, -1, "anim");
b->subs[c] = parse_animation_table(this);
if(!b->subs[c]) {
k3Log(k3_WARN, "Invalid child %lu in animation blend", c);
}
lua_pop(L, 1);
lua_getfield(L, -1, "w");
if(lua_type(L, -1) == LUA_TNUMBER) {
float f = lua_tonumber(L, -1);
for(size_t i = 0; i < b->bones; i++) {
b->weights[c * b->bones + i] = f;
}
} else if(lua_type(L, -1) == LUA_TTABLE) {
for(size_t i = 0; i < b->bones; i++) {
lua_geti(L, -1, i + 1);
b->weights[c * b->bones + i] = lua_tonumber(L, -1);
lua_pop(L, 1);
}
} else {
k3Log(k3_WARN, "Invalid weights in for child %lu", c);
}
lua_pop(L, 1);
lua_getfield(L, -1, "speed");
if(lua_type(L, -1) == LUA_TNUMBER) {
b->speeds[c] = lua_tonumber(L, -1);
} else {
b->speeds[c] = 1;
}
lua_pop(L, 1);
lua_getfield(L, -1, "offset");
if(lua_type(L, -1) == LUA_TNUMBER) {
b->offsets[c] = lua_tonumber(L, -1);
}
lua_pop(L, 1);
lua_pop(L, 1);
}
return (struct k3Animation*) b;
} else if(op == k3_ANIM_ADD) {
struct k3AnimationAdd *a = calloc(1, sizeof(*a));
a->op = op;
a->bones = k3MdlGetBoneCount(this->mdl);
lua_geti(L, -1, 1);
a->sub1 = parse_animation_table(this);
lua_pop(L, 1);
lua_geti(L, -1, 2);
a->sub2 = parse_animation_table(this);
lua_pop(L, 1);
lua_getfield(L, -1, "scale");
if(lua_type(L, -1) == LUA_TNUMBER) {
a->scale = lua_tonumber(L, -1);
} else {
a->scale = 1;
}
lua_pop(L, 1);
return (struct k3Animation*) a;
}
return NULL;
}
static int dagame_animator_set(lua_State *L) { static int dagame_animator_set(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1); struct k3Animator *this = *(void**) lua_touserdata(L, 1);
size_t animIdx = lua_tointeger(L, 2); k3AnimationFree(this->anim);
this->anim = parse_animation_table(this);
this->animator.base = k3MdlGetAnim(this->mdl, animIdx);
this->animator.loop = false;
this->playStartTime = glfwGetTime(); this->playStartTime = glfwGetTime();
k3AnimatorSet(&this->animator, 0); k3AnimatorSet(this, 0);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
return 1; return 1;
} }
static int dagame_animator_play(lua_State *L) { static int dagame_animator_play(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1); struct k3Animator *this = *(void**) lua_touserdata(L, 1);
this->playing = true; this->playing = true;
this->playStartTime = glfwGetTime(); this->playStartTime = glfwGetTime();
lua_pushvalue(L, 1);
return 1;
}
static int dagame_animator_get(lua_State *L) {
struct k3Animator *this = *(void**) lua_touserdata(L, 1);
*(void**) lua_newuserdata(L, sizeof(void*)) = this->anim;
this->anim->ref++;
luaL_setmetatable(L, "k3animation");
return 1;
} }
static int dagame_animator_index(lua_State *L) { static int dagame_animator_index(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1); struct k3Animator *this = *(void**) lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2); const char *key = lua_tostring(L, 2);
@ -2745,11 +2817,49 @@ static int dagame_animator_index(lua_State *L) {
} else if(!strcmp(key, "play")) { } else if(!strcmp(key, "play")) {
lua_pushcfunction(L, dagame_animator_play); lua_pushcfunction(L, dagame_animator_play);
return 1; return 1;
} else if(!strcmp(key, "time")) { } else if(!strcmp(key, "get")) {
lua_pushnumber(L, this->animator.time); lua_pushcfunction(L, dagame_animator_get);
return 1; return 1;
} else if(!strcmp(key, "loop")) { } else if(!strcmp(key, "time")) {
lua_pushboolean(L, this->animator.loop); lua_pushnumber(L, this->time);
return 1;
} else if(!strcmp(key, "model")) {
*(struct k3Mdl**) lua_newuserdata(L, sizeof(void*)) = this->mdl;
luaL_setmetatable(L, "k3mdl");
return 1;
} else if(!strcmp(key, "bones")) {
size_t bones = k3MdlGetBoneCount(this->mdl);
lua_newtable(L);
for(size_t i = 0; i < bones; i++) {
lua_newtable(L);
lua_newtable(L);
lua_pushnumber(L, this->bones[i].translation[0]);
lua_pushnumber(L, this->bones[i].translation[1]);
lua_pushnumber(L, this->bones[i].translation[2]);
lua_pushnumber(L, this->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_setfield(L, -2, "translation");
lua_newtable(L);
lua_pushnumber(L, this->bones[i].rotation[0]);
lua_pushnumber(L, this->bones[i].rotation[1]);
lua_pushnumber(L, this->bones[i].rotation[2]);
lua_pushnumber(L, this->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_setfield(L, -2, "rotation");
lua_rawseti(L, -2, i + 1);
}
return 1; return 1;
} }
@ -2757,14 +2867,197 @@ static int dagame_animator_index(lua_State *L) {
} }
static int dagame_animator_newindex(lua_State *L) { static int dagame_animator_newindex(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1); struct k3Animator *this = *(void**) lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2); const char *key = lua_tostring(L, 2);
if(!strcmp(key, "time")) { if(!strcmp(key, "time")) {
k3AnimatorSet(&this->animator, lua_tonumber(L, 3)); k3AnimatorSet(this, lua_tonumber(L, 3));
} else if(!strcmp(key, "loop")) { } else if(!strcmp(key, "loop")) {
this->animator.loop = lua_toboolean(L, 3); //this->animator.loop = lua_toboolean(L, 3);
} else if(!strcmp(key, "bones")) {
size_t bones = k3MdlGetBoneCount(this->mdl);
for(size_t i = 0; i < bones; i++) {
lua_rawgeti(L, 3, i + 1);
lua_getfield(L, -1, "translation");
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
lua_rawgeti(L, -4, 4);
this->bones[i].translation[0] = lua_tonumber(L, -4);
this->bones[i].translation[1] = lua_tonumber(L, -3);
this->bones[i].translation[2] = lua_tonumber(L, -2);
this->bones[i].translation[3] = lua_tonumber(L, -1);
lua_pop(L, 5);
lua_getfield(L, -1, "rotation");
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
lua_rawgeti(L, -4, 4);
this->bones[i].rotation[0] = lua_tonumber(L, -4);
this->bones[i].rotation[1] = lua_tonumber(L, -3);
this->bones[i].rotation[2] = lua_tonumber(L, -2);
this->bones[i].rotation[3] = lua_tonumber(L, -1);
lua_pop(L, 5);
lua_pop(L, 1);
}
}
return 0;
}
static int dagame_animator_gc(lua_State *L) {
struct k3Animator *this = *(void**) lua_touserdata(L, 1);
k3AnimationFree(this->anim);
free(this);
return 0;
}
struct AnimBlendSub {
struct k3AnimationBlend *blend;
size_t c;
};
static int dagame_animation_index(lua_State *L) {
struct k3Animation *anim = *(void**) lua_touserdata(L, 1);
const char *key = NULL;
size_t keyi = 0;
if(lua_type(L, 2) == LUA_TNUMBER) {
keyi = lua_tointeger(L, 2);
} else {
key = lua_tostring(L, 2);
}
if(key && !strcmp(key, "type")) {
switch(anim->op) {
case k3_ANIM_BASIC:
lua_pushstring(L, "base");
break;
case k3_ANIM_BLEND:
lua_pushstring(L, "blend");
break;
case k3_ANIM_ADD:
lua_pushstring(L, "add");
break;
default:
lua_pushnil(L);
break;
}
return 1;
}
if(anim->op == k3_ANIM_BASIC) {
struct k3AnimationBasic *basic = (void*) anim;
if(key && !strcmp(key, "loop")) {
lua_pushboolean(L, basic->loop);
return 1;
}
} else if(anim->op == k3_ANIM_BLEND) {
struct k3AnimationBlend *blend = (void*) anim;
if(keyi == 0 || keyi > blend->children) {
lua_pushnil(L);
} else {
struct AnimBlendSub *i = lua_newuserdata(L, sizeof(*i));
i->blend = blend;
i->blend->ref++;
i->c = keyi;
luaL_setmetatable(L, "k3animationblendsub");
}
return 1;
} else if(anim->op == k3_ANIM_ADD) {
struct k3AnimationAdd *add = (void*) anim;
if(key && !strcmp(key, "scale")) {
lua_pushnumber(L, add->scale);
} else if(keyi == 1 || keyi == 2) {
struct k3Animation** s = lua_newuserdata(L, sizeof(*s));
*s = keyi == 1 ? add->sub1 : add->sub2;
(*s)->ref++;
luaL_setmetatable(L, "k3animation");
}
return 1;
}
return 0;
}
static int dagame_animation_gc(lua_State *L) {
struct k3Animation *anim = *(void**) lua_touserdata(L, 1);
k3AnimationFree(anim);
return 0;
}
static int dagame_animationblendsub_index(lua_State *L) {
struct AnimBlendSub *i = lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if(!strcmp(key, "anim")) {
*(void**) lua_newuserdata(L, sizeof(void*)) = i->blend->subs[i->c - 1];
i->blend->subs[i->c - 1]->ref++;
luaL_setmetatable(L, "k3animation");
return 1;
} else if(!strcmp(key, "w")) {
lua_newtable(L);
for(size_t b = 0; b < i->blend->bones; b++) {
lua_pushnumber(L, i->blend->weights[i->blend->bones * (i->c - 1) + b]);
lua_rawseti(L, -2, b + 1);
}
return 1;
} else if(!strcmp(key, "speed")) {
lua_pushnumber(L, i->blend->speeds[i->c - 1]);
return 1;
} else if(!strcmp(key, "offset")) {
lua_pushnumber(L, i->blend->offsets[i->c - 1]);
return 1;
}
return 0;
}
static int dagame_animationblendsub_newindex(lua_State *L) {
struct AnimBlendSub *i = lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if(!strcmp(key, "anim")) {
return luaL_error(L, "Setting anim field is unsupported.");
} else if(!strcmp(key, "w")) {
if(lua_type(L, 3) == LUA_TNUMBER) {
float val = lua_tonumber(L, 3);
for(size_t b = 0; b < i->blend->bones; b++) {
i->blend->weights[i->blend->bones * (i->c - 1) + b] = val;
}
} else if(lua_type(L, 3) == LUA_TTABLE) {
for(size_t b = 0; b < i->blend->bones; b++) {
lua_rawgeti(L, 3, b + 1);
i->blend->weights[i->blend->bones * (i->c - 1) + b] = lua_tonumber(L, -1);
lua_pop(L, 1);
}
} else {
return luaL_error(L, "w field may be either number or table or numbers.");
}
} else if(!strcmp(key, "speed")) {
i->blend->speeds[i->c - 1] = lua_tonumber(L, 3);
} else if(!strcmp(key, "offset")) {
i->blend->offsets[i->c - 1] = lua_tonumber(L, 3);
} }
return 0; return 0;
@ -3209,9 +3502,45 @@ void luaapi_init() {
lua_pushcfunction(L, dagame_animator_newindex); lua_pushcfunction(L, dagame_animator_newindex);
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, dagame_animator_gc);
lua_setfield(L, -2, "__gc");
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
lua_setfield(L, -2, "__metatable"); lua_setfield(L, -2, "__metatable");
lua_pop(L, 1); lua_pop(L, 1);
luaL_newmetatable(L, "k4animatorptr");
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);
luaL_newmetatable(L, "k3animation");
lua_pushcfunction(L, dagame_animation_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, dagame_animation_gc);
lua_setfield(L, -2, "__gc");
lua_pushboolean(L, 0);
lua_setfield(L, -2, "__metatable");
lua_pop(L, 1);
luaL_newmetatable(L, "k3animationblendsub");
lua_pushcfunction(L, dagame_animationblendsub_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, dagame_animationblendsub_newindex);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, dagame_animation_gc);
lua_setfield(L, -2, "__gc");
lua_pop(L, 1);
} }
void luaapi_load(const char *name) { void luaapi_load(const char *name) {

View File

@ -590,7 +590,11 @@ int main(int argc_, char **argv_) {
if(c->cache) { if(c->cache) {
struct CBoned *b = game_getcomponent(c->entity, boned); struct CBoned *b = game_getcomponent(c->entity, boned);
k3Batch(c->cache, transform, b ? b->bones : NULL); if(b && b->animator.anim) {
k3AnimatorStep(&b->animator, dt);
}
k3Batch(c->cache, transform, b ? b->animator.bones : NULL);
} }
} }

View File

@ -114,7 +114,7 @@ static void interpret_pkt(ENetPacket *pkt) {
c->holding = b_ru16(&b); c->holding = b_ru16(&b);
} if(ctype == CMD_CTYPE_BONED) { } if(ctype == CMD_CTYPE_BONED) {
struct CBoned *c = game_ensurecomponent(ent, boned); struct CBoned *c = game_ensurecomponent(ent, boned);
c->anim.standard = b_ru8(&b); /*c->anim.standard =*/ b_ru8(&b);
} }
} else if(cmd == CMD_SC_POSUPDATE) { } else if(cmd == CMD_SC_POSUPDATE) {
uint16_t lastOurTick = b_ru16(&b); uint16_t lastOurTick = b_ru16(&b);

View File

@ -121,7 +121,7 @@ static void send_full_state(ENetPeer **peers, size_t peerCount) {
b_wu16(&b, c->entity); b_wu16(&b, c->entity);
b_wu8(&b, c->anim.standard); b_wu8(&b, 0/*c->anim.standard*/);
} }
if(peers) { if(peers) {