diff --git a/src/game/chr.c b/src/game/chr.c index 8a581e69a..b7a8079da 100644 --- a/src/game/chr.c +++ b/src/game/chr.c @@ -1395,7 +1395,7 @@ void chr_remove(struct prop *prop, bool free) wallhit_fade_splats_for_removed_chr(prop); ps_stop_sound(prop, PSTYPE_GENERAL, 0xffff); shieldhits_remove_by_prop(prop); - model_free_vertices(VTXSTORETYPE_CHRVTX, model); + model_free_vtxstores(VTXSTORETYPE_CHRVTX, model); prop_deregister_rooms(prop); if (g_Vars.stagenum == STAGE_CITRAINING) { @@ -4271,11 +4271,9 @@ void chr_bruise(struct model *model, s32 hitpart, struct modelnode *node, struct /** * Disfigure and darken a chr due to them dying from explosion damage. * - * Vertices and colours are typically stored in the model definition which is - * shared between all instances of that model. To have different vertices and - * colours for a single instance requires copying that information out of the - * model definition and into a vtx store. If the vtx store is full, the chr will - * not become disfigured. + * Vertices and colours are copied from the modeldef into new vtxstore + * allocations. If the vtxstore is full, the chr will not become disfigured + * or will only be partially disfigured. * * The function looks for displaylist nodes in the chr's model. For each DL node * found, its vertex and colour information is copied to the vtx store. The GBI diff --git a/src/game/propobj.c b/src/game/propobj.c index 8a06a03c4..c05067d17 100644 --- a/src/game/propobj.c +++ b/src/game/propobj.c @@ -2560,7 +2560,7 @@ void obj_free(struct defaultobj *obj, bool freeprop, bool canregen) prop_deregister_rooms(obj->prop); if (obj->prop->type != PROPTYPE_DOOR) { - model_free_vertices(1, obj->model); + model_free_vtxstores(VTXSTORETYPE_OBJVTX, obj->model); } modelmgr_free_model(obj->model); @@ -10926,7 +10926,7 @@ u32 obj_tick(struct prop *prop) obj->hidden &= ~OBJHFLAG_GONE; } } else { - // Object was previously damaged. Probably glass. + // Object was previously damaged. Probably glass or deformed object. if (obj->hidden2 & OBJH2FLAG_CORE_GEO_EXISTS) { obj->flags |= OBJFLAG_CORE_GEO_INUSE; } else { @@ -10935,7 +10935,8 @@ u32 obj_tick(struct prop *prop) obj->damage = 0; obj->hidden2 &= ~OBJH2FLAG_DESTROYED; - model_free_vertices(1, obj->model); + + model_free_vtxstores(VTXSTORETYPE_OBJVTX, obj->model); } if (obj->type == OBJTYPE_SHIELD) { @@ -12420,7 +12421,7 @@ void obj_render_prop(struct prop *prop, struct modelrenderdata *renderdata, bool if (renderdata->unk30 == 9) { renderdata->envcolour &= 0xffffff00; } - } else if ((obj->hidden2 & OBJH2FLAG_80) == 0) { + } else if ((obj->hidden2 & OBJH2FLAG_DEFORMED) == 0) { renderdata->cullmode = CULLMODE_BACK; if (renderdata->unk30 == 9) { @@ -13118,11 +13119,11 @@ void obj_deform(struct defaultobj *obj, s32 level) } } - if ((obj->hidden2 & OBJH2FLAG_80) == 0) { + if ((obj->hidden2 & OBJH2FLAG_DEFORMED) == 0) { if (!ok) { - model_free_vertices(VTXSTORETYPE_OBJVTX, model); + model_free_vtxstores(VTXSTORETYPE_OBJVTX, model); } else { - obj->hidden2 |= OBJH2FLAG_80; + obj->hidden2 |= OBJH2FLAG_DEFORMED; } } } @@ -16697,7 +16698,7 @@ bool func0f0899dc(struct prop *prop, struct coord *arg1, f32 *xrange, f32 *yrang return false; } -void model_free_vertices(s32 vtxstoretype, struct model *model) +void model_free_vtxstores(s32 vtxstoretype, struct model *model) { struct modeldef *modeldef = model->definition; struct modelnode *node = modeldef->rootnode; @@ -16706,7 +16707,6 @@ void model_free_vertices(s32 vtxstoretype, struct model *model) u32 type = node->type & 0xff; union modelrodata *rodata; union modelrwdata *rwdata; - s32 newtype; switch (type) { case MODELNODETYPE_DL: @@ -16720,14 +16720,7 @@ void model_free_vertices(s32 vtxstoretype, struct model *model) } if ((uintptr_t)rwdata->dl.colours != ALIGN8((uintptr_t)rodata->dl.vertices + rodata->dl.numvertices * sizeof(Vtx))) { - if (vtxstoretype == VTXSTORETYPE_OBJVTX) { - newtype = VTXSTORETYPE_OBJCOL; - } else { - newtype = VTXSTORETYPE_CHRCOL; - } - - vtxstore_free(newtype, rwdata->dl.colours); - + vtxstore_free(vtxstoretype == VTXSTORETYPE_OBJVTX ? VTXSTORETYPE_OBJCOL : VTXSTORETYPE_CHRCOL, rwdata->dl.colours); rwdata->dl.colours = (Col *)ALIGN8((uintptr_t)rodata->dl.vertices + rodata->dl.numvertices * sizeof(Vtx)); } } @@ -20040,7 +20033,7 @@ void alarm_tick(void) g_PlayersDetonatingMines = 0; } -void func0f091030(void) +void obj_free_all_offscreen_deformed_objs(void) { struct prop *prop = g_Vars.activeprops; @@ -20048,7 +20041,7 @@ void func0f091030(void) if (prop->type == PROPTYPE_OBJ && (prop->flags & (PROPFLAG_ONTHISSCREENTHISTICK | PROPFLAG_ONANYSCREENTHISTICK | PROPFLAG_ONANYSCREENPREVTICK)) == 0 && (prop->obj->hidden2 & OBJH2FLAG_DESTROYED) - && (prop->obj->hidden2 & OBJH2FLAG_80)) { + && (prop->obj->hidden2 & OBJH2FLAG_DEFORMED)) { obj_free_permanently(prop->obj, true); return; } diff --git a/src/game/vtxstore.c b/src/game/vtxstore.c index 09791afbb..58ffcbd42 100644 --- a/src/game/vtxstore.c +++ b/src/game/vtxstore.c @@ -12,45 +12,52 @@ #include "data.h" #include "types.h" -const char var7f1b5230[] = "VTXSTORE : vtxfixrefs -> Start - p1=%x, p2=%x\n"; -const char var7f1b5260[] = "vtxfixrefs : Part=%x -- Mapping ptr %x -> %x\n"; -const char var7f1b5290[] = "VTXSTORE : vtxfixrefs -> End - Done=%d\n"; -const char var7f1b52b8[] = "vtxstorecheck : memaFree -> %u bytes at Ptr=%x(%x)\n"; -const char var7f1b52ec[] = "vtxstorecheck : At block 1 %d -> Ref1=%x, Ref2=%x\n"; -const char var7f1b5320[] = "vtxstorecheck : At block 2 %d -> Ref1=%x, Ref2=%x\n"; -const char var7f1b5354[] = "vtx buffer low, need to delete objects\n"; -const char var7f1b537c[] = "getfreevertices : %d of type %d -> ref1=%x, ref2=%x\n"; -const char var7f1b53b4[] = "vtxstore: 1st mema alloc of %u bytes\n"; +/** + * Vtxstores are used for: + * - deforming objects when destroyed (obj vtx) + * - darkening objects when destroyed (obj col) + * - disfiguring chrs when damaged by explosions (chr vtx) + * - darkening chrs when damaged by explosions (chr col) + * - bruising chrs when shot or stabbed (chr col) + * + * Model vertices and colours are typically stored in the model definition, + * which is shared between all instances of that model. To have different + * vertices or colours for a single instance, this data has to be copied out of + * the model definition and into its own allocation before it can be customised. + * These allocations are managed using vtxstores. + * + * Despite the name, vtxstores are also used for colours. + * + * Vtxstores are allocated out of mema. They are freed by the caller when the + * object or chr is deleted. The vtxstore system will force free offscreen + * chrs and objects if it is low on memory. + */ -#if VERSION < VERSION_NTSC_1_0 -const char var7f1af8ecnb[] = "vtxstore: Trying to free %d from mema (bgRooms)\n"; -#endif - -const char var7f1b53dc[] = "getfreevertices : Return ptr = %x\n"; -const char var7f1b5400[] = "vtxstore: Out of mema (returning NULL)\n"; -const char var7f1b5428[] = "vtxstore: GROSS! CorspeCount > MAX_CORPSES corpses! Freeing corpse %x\n"; -const char var7f1b5470[] = "vtxstore: CorpseCount %d, Trying to free %d\n"; -const char var7f1b54a0[] = "vtxstore: Freeing corpse %x\n"; -const char var7f1b54c0[] = "vtxstore: Out of vertices type %d wanted %d free %d (returning NULL)\n"; -const char var7f1b5508[] = "vtxstore: freevertices type %d, list %x\n"; -const char var7f1b5534[] = "freevertices: address not found in array %x\n"; +// Vertices are 12 bytes while colours are 4 bytes. +// The game allocates 12 bytes regardless of whether it's +// for a vertex or a colour. This is wasteful for colours. +#define UNIT_SIZE MAX(sizeof(Vtx), sizeof(Col)) struct vtxstoretype g_VtxstoreTypes[] = { - { 3000, 120, 3000, 80, 0, 0, 500, 20, 12, 0, 0, 0, 0 }, - { 1500, 40, 500, 20, 0, 0, 500, 20, 12, 0, 0, 0, 0 }, - { 6000, 120, 6000, 80, 0, 0, 1000, 20, 4, 0, 0, 0, 0 }, - { 1500, 40, 500, 20, 0, 0, 500, 20, 4, 0, 0, 0, 0 }, + // |------ sp -------| |------ mp -------| |----- other -----| |- unused -| + // maxunits numbatches maxunits numbatches maxunits numbatches + /* chr vtx */ { 3000, 120, 3000, 80, 0, 0, 500, 20, 12 }, + /* obj vtx */ { 1500, 40, 500, 20, 0, 0, 500, 20, 12 }, + /* chr col */ { 6000, 120, 6000, 80, 0, 0, 1000, 20, 4 }, + /* obj col */ { 1500, 40, 500, 20, 0, 0, 500, 20, 4 }, }; /** - * Search all props and their model data for something, and replace it with - * something else. + * Search all props and their model data for references to the `find` address + * and replace it with the `replacement` address. */ void vtxstore_fix_refs(void *find, void *replacement) { - u32 stack; + s32 count = 0; struct prop *prop = g_Vars.activeprops; + osSyncPrintf("VTXSTORE : vtxfixrefs -> Start - p1=%x, p2=%x\n", find, replacement); + while (prop) { if (prop->type == PROPTYPE_OBJ) { struct defaultobj *obj = prop->obj; @@ -64,8 +71,10 @@ void vtxstore_fix_refs(void *find, void *replacement) case MODELNODETYPE_DL: rodata = &node->rodata->dl; - if (model->rwdatas[rodata->rwdataindex] == (u32) find) { - model->rwdatas[rodata->rwdataindex] = (u32) replacement; + if (model->rwdatas[rodata->rwdataindex] == (uintptr_t) find) { + osSyncPrintf("vtxfixrefs : Part=%x -- Mapping ptr %x -> %x\n", rodata->rwdataindex, model->rwdatas[rodata->rwdataindex], replacement); + model->rwdatas[rodata->rwdataindex] = (uintptr_t) replacement; + count++; } break; case MODELNODETYPE_DISTANCE: @@ -96,6 +105,8 @@ void vtxstore_fix_refs(void *find, void *replacement) prop = prop->next; } + + osSyncPrintf("VTXSTORE : vtxfixrefs -> End - Done=%d\n", count); } void vtxstore_tick(void) @@ -103,38 +114,53 @@ void vtxstore_tick(void) s32 i; s32 j; - if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].val2 < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].val1 >> 2) { - for (i = 0; i < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numallocated - 1; i++) { - if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[i].unk0e > 0) { - for (j = i + 1; j < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numallocated; j++) { - if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].unk0e > 0 - && g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[i].node == g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].node - && g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[i].level == g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].level) { - s32 size = ALIGN16(g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].count * 0x0c); - vtxstore_fix_refs(g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].unk00, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[i].unk00); - g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[i].unk0e += g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].unk0e; - mema_free(g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].unk00, size); - g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].unk0e = 0; - g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].val2 += g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].unk24[j].count; + // If the obj vtx stores are at least 75% full then iterate them and try to + // find duplicates. Merge duplicates into the original. + // I don't think it's possible for there to be duplicates though. + if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numunitsfree < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numunitsmax >> 2) { + for (i = 0; i < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numbatches - 1; i++) { + if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].refcount > 0) { + for (j = i + 1; j < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numbatches; j++) { + if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].refcount > 0 + && g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].node == g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].node + && g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].level == g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].level) { + s32 size = ALIGN16(g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].numunitsalloced * UNIT_SIZE); + + vtxstore_fix_refs(g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].allocation, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].allocation); + + g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].refcount += g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].refcount; + + osSyncPrintf("vtxstorecheck : memaFree -> %u bytes at Ptr=%x(%x)\n", size, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].allocation); + + mema_free(g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].allocation, size); + + g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].refcount = 0; + g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numunitsfree += g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].numunitsalloced; } + + osSyncPrintf("vtxstorecheck : At block 1 %d -> Ref1=%x, Ref2=%x\n", i, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].node, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[i].level); + osSyncPrintf("vtxstorecheck : At block 2 %d -> Ref1=%x, Ref2=%x\n", j, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].node, g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].batches[j].level); } } } } - if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].val2 < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].val1 >> 2) { - func0f091030(); + // If the obj vtx stores are still at least 75% full + // then free all the offscreen and deformed objects. + if (g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numunitsfree < g_VtxstoreTypes[VTXSTORETYPE_OBJVTX].numunitsmax >> 2) { + osSyncPrintf("vtx buffer low, need to delete objects\n"); + obj_free_all_offscreen_deformed_objs(); } } -void *vtxstore_allocate(s32 count, s32 index, struct modelnode *node, s32 level) +void *vtxstore_allocate(s32 count, s32 type, struct modelnode *node, s32 level) { s32 i; s32 numchrs; - s32 tally; + s32 corpsecount; s32 rand; u32 size; - struct chrdata *chrs[6]; + struct chrdata *corpses[6]; #if VERSION >= VERSION_NTSC_1_0 if (IS4MB()) { @@ -142,29 +168,39 @@ void *vtxstore_allocate(s32 count, s32 index, struct modelnode *node, s32 level) } #endif - if (count <= g_VtxstoreTypes[index].val2) { - for (i = 0; i < g_VtxstoreTypes[index].numallocated; i++) { - if (g_VtxstoreTypes[index].unk24[i].unk0e == 0) { - size = ALIGN16(count * 0xc); - g_VtxstoreTypes[index].unk24[i].unk00 = mema_alloc(size); + osSyncPrintf("getfreevertices : %d of type %d -> ref1=%x, ref2=%x\n", count, type, node, level); + + if (count <= g_VtxstoreTypes[type].numunitsfree) { + for (i = 0; i < g_VtxstoreTypes[type].numbatches; i++) { + if (g_VtxstoreTypes[type].batches[i].refcount == 0) { + size = ALIGN16(count * UNIT_SIZE); + + osSyncPrintf("vtxstore: 1st mema alloc of %u bytes\n", size); + + g_VtxstoreTypes[type].batches[i].allocation = mema_alloc(size); #if VERSION < VERSION_NTSC_1_0 - if (!g_VtxstoreTypes[index].unk24[i].unk00) { + if (g_VtxstoreTypes[type].batches[i].allocation == NULL) { + osSyncPrintf("vtxstore: Trying to free %d from mema (bgRooms)\n", size); bg_garbage_collect_rooms(size, false); - g_VtxstoreTypes[index].unk24[i].unk00 = mema_alloc(size); + g_VtxstoreTypes[type].batches[i].allocation = mema_alloc(size); } #endif - if (g_VtxstoreTypes[index].unk24[i].unk00) { - g_VtxstoreTypes[index].unk24[i].count = count; - g_VtxstoreTypes[index].unk24[i].unk0e = 1; - g_VtxstoreTypes[index].unk24[i].node = node; - g_VtxstoreTypes[index].unk24[i].level = level; - g_VtxstoreTypes[index].val2 -= count; + osSyncPrintf("getfreevertices : Return ptr = %x\n", g_VtxstoreTypes[type].batches[i].allocation); - return g_VtxstoreTypes[index].unk24[i].unk00; + if (g_VtxstoreTypes[type].batches[i].allocation != NULL) { + g_VtxstoreTypes[type].batches[i].numunitsalloced = count; + g_VtxstoreTypes[type].batches[i].refcount = 1; + g_VtxstoreTypes[type].batches[i].node = node; + g_VtxstoreTypes[type].batches[i].level = level; + g_VtxstoreTypes[type].numunitsfree -= count; + + return g_VtxstoreTypes[type].batches[i].allocation; } + osSyncPrintf("vtxstore: Out of mema (returning NULL)\n"); + return NULL; } } @@ -175,7 +211,7 @@ void *vtxstore_allocate(s32 count, s32 index, struct modelnode *node, s32 level) // So at the end, we'll have an array of up to six unreapable corpses and // all other corpses will be flagged for reaping. numchrs = chrs_get_num_slots(); - tally = 0; + corpsecount = 0; for (i = 0; i < numchrs; i++) { struct chrdata *chr = &g_ChrSlots[i]; @@ -185,13 +221,14 @@ void *vtxstore_allocate(s32 count, s32 index, struct modelnode *node, s32 level) && (chr->prop->flags & PROPFLAG_ONANYSCREENPREVTICK) == 0 && chr->actiontype == ACT_DEAD && chr->act_dead.fadewheninvis == false) { - if (tally < 6) { - chrs[tally] = chr; - tally++; + if (corpsecount < ARRAYCOUNT(corpses)) { + corpses[corpsecount] = chr; + corpsecount++; } else { - rand = random() % tally; - chr_fade_corpse_when_off_screen(chrs[rand]); - chrs[rand] = chr; + rand = random() % corpsecount; + osSyncPrintf("vtxstore: GROSS! CorspeCount > MAX_CORPSES corpses! Freeing corpse %x\n", &corpses[rand]); + chr_fade_corpse_when_off_screen(corpses[rand]); + corpses[rand] = chr; } } } @@ -199,37 +236,45 @@ void *vtxstore_allocate(s32 count, s32 index, struct modelnode *node, s32 level) // Enable reaping on half the remaining corpses. // I'm reusing the rand and i variables here in order to get a match. // The original code likely didn't reuse them. - rand = tally >> 1; + rand = corpsecount >> 1; + + osSyncPrintf("vtxstore: CorpseCount %d, Trying to free %d\n", corpsecount, rand); while (rand) { - i = random() % tally; + i = random() % corpsecount; - if (chrs[i]) { - chr_fade_corpse_when_off_screen(chrs[i]); - chrs[i] = NULL; + if (corpses[i]) { + osSyncPrintf("vtxstore: Freeing corpse %x\n", &corpses[i]); + chr_fade_corpse_when_off_screen(corpses[i]); + corpses[i] = NULL; rand--; } } + osSyncPrintf("vtxstore: Out of vertices type %d wanted %d free %d (returning NULL)\n", type, count, g_VtxstoreTypes[type].numunitsfree); + return NULL; } -void vtxstore_free(s32 type, void *arg1) +void vtxstore_free(s32 type, void *allocation) { s32 i; - for (i = 0; i < g_VtxstoreTypes[type].numallocated; i++) { - if (g_VtxstoreTypes[type].unk24[i].unk0e > 0 && arg1 == g_VtxstoreTypes[type].unk24[i].unk00) { - g_VtxstoreTypes[type].unk24[i].unk0e--; + osSyncPrintf("vtxstore: freevertices type %d, list %x\n", type, allocation); - if (g_VtxstoreTypes[type].unk24[i].unk0e) { - return; + for (i = 0; i < g_VtxstoreTypes[type].numbatches; i++) { + if (g_VtxstoreTypes[type].batches[i].refcount > 0 && g_VtxstoreTypes[type].batches[i].allocation == allocation) { + g_VtxstoreTypes[type].batches[i].refcount--; + + if (g_VtxstoreTypes[type].batches[i].refcount == 0) { + mema_free(g_VtxstoreTypes[type].batches[i].allocation, ALIGN16(g_VtxstoreTypes[type].batches[i].numunitsalloced * UNIT_SIZE)); + + g_VtxstoreTypes[type].numunitsfree += g_VtxstoreTypes[type].batches[i].numunitsalloced; } - mema_free(g_VtxstoreTypes[type].unk24[i].unk00, ALIGN16(g_VtxstoreTypes[type].unk24[i].count * 0xc)); - - g_VtxstoreTypes[type].val2 += g_VtxstoreTypes[type].unk24[i].count; return; } } + + osSyncPrintf("freevertices: address not found in array %x\n", allocation); } diff --git a/src/game/vtxstorereset.c b/src/game/vtxstorereset.c index bd12e51af..d3d55d717 100644 --- a/src/game/vtxstorereset.c +++ b/src/game/vtxstorereset.c @@ -9,31 +9,31 @@ void vtxstore_reset(void) { s32 i; s32 j; - s32 num; - s32 val; + s32 numbatches; + s32 maxunits; for (i = 0; i < ARRAYCOUNT(g_VtxstoreTypes); i++) { if (PLAYERCOUNT() >= 2) { - val = g_VtxstoreTypes[i].valifmp; - num = g_VtxstoreTypes[i].numifmp; + maxunits = g_VtxstoreTypes[i].mpmaxunits; + numbatches = g_VtxstoreTypes[i].mpnumbatches; } else if (g_Vars.stagenum >= STAGE_TITLE) { - val = g_VtxstoreTypes[i].valifspecial; - num = g_VtxstoreTypes[i].numifspecial; + maxunits = g_VtxstoreTypes[i].othermaxunits; + numbatches = g_VtxstoreTypes[i].othernumbatches; } else { - val = g_VtxstoreTypes[i].valifsp; - num = g_VtxstoreTypes[i].numifsp; + maxunits = g_VtxstoreTypes[i].spmaxunits; + numbatches = g_VtxstoreTypes[i].spnumbatches; } - if (num > 0) { - g_VtxstoreTypes[i].unk24 = memp_alloc(num * sizeof(struct var8007e3d0_data), MEMPOOL_STAGE); + if (numbatches > 0) { + g_VtxstoreTypes[i].batches = memp_alloc(numbatches * sizeof(struct vtxstorebatch), MEMPOOL_STAGE); } - for (j = 0; j < num; j++) { - g_VtxstoreTypes[i].unk24[j].unk0e = 0; + for (j = 0; j < numbatches; j++) { + g_VtxstoreTypes[i].batches[j].refcount = 0; } - g_VtxstoreTypes[i].numallocated = num; - g_VtxstoreTypes[i].val1 = val; - g_VtxstoreTypes[i].val2 = val; + g_VtxstoreTypes[i].numbatches = numbatches; + g_VtxstoreTypes[i].numunitsmax = maxunits; + g_VtxstoreTypes[i].numunitsfree = maxunits; } } diff --git a/src/include/constants.h b/src/include/constants.h index b20ff0da6..438cdb08d 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -3170,13 +3170,13 @@ #define OBJHFLAG_GRABBED 0x08000000 // obj->hidden2 -#define OBJH2FLAG_HASOPA 0x01 // obj has opaque polygons (ie. most objects) -#define OBJH2FLAG_HASXLU 0x02 // obj has translucent polygons -#define OBJH2FLAG_CANREGEN 0x04 -#define OBJH2FLAG_CORE_GEO_EXISTS 0x08 -#define OBJH2FLAG_10 0x10 -#define OBJH2FLAG_DESTROYED 0x40 -#define OBJH2FLAG_80 0x80 +#define OBJH2FLAG_HASOPA 0x01 // obj has opaque polygons (ie. most objects) +#define OBJH2FLAG_HASXLU 0x02 // obj has translucent polygons +#define OBJH2FLAG_CANREGEN 0x04 +#define OBJH2FLAG_CORE_GEO_EXISTS 0x08 +#define OBJH2FLAG_10 0x10 +#define OBJH2FLAG_DESTROYED 0x40 +#define OBJH2FLAG_DEFORMED 0x80 #define OBJTYPE_DOOR 0x01 #define OBJTYPE_DOORSCALE 0x02 diff --git a/src/include/game/propobj.h b/src/include/game/propobj.h index f4de6a066..c2fe06a65 100644 --- a/src/include/game/propobj.h +++ b/src/include/game/propobj.h @@ -130,7 +130,7 @@ void current_player_queue_pickup_weapon_hudmsg(u32 weaponnum, bool dual); s32 prop_pickup_by_player(struct prop *prop, bool showhudmsg); s32 obj_test_for_pickup(struct prop *prop); bool func0f0899dc(struct prop *prop, struct coord *arg1, f32 *xrange, f32 *yrange); -void model_free_vertices(s32 vtxstoretype, struct model *model); +void model_free_vtxstores(s32 vtxstoretype, struct model *model); void hat_assign_to_chr(struct hatobj *hat, struct chrdata *chr); struct prop *hat_create_for_chr(struct chrdata *chr, s32 modelnum, u32 flags); void player_activate_remote_mine_detonator(s32 playernum); @@ -172,7 +172,7 @@ bool gas_is_active(void); Gfx *countdown_timer_render(Gfx *gdl); void projectiles_debug(void); void alarm_tick(void); -void func0f091030(void); +void obj_free_all_offscreen_deformed_objs(void); void current_player_drop_all_items(void); void weapon_create_for_player_drop(s32 weaponnum); void projectile_create(struct prop *fromprop, struct fireslotthing *arg1, struct coord *pos, struct coord *direction, u8 weaponnum, struct prop *targetprop); diff --git a/src/include/game/vtxstore.h b/src/include/game/vtxstore.h index 6c1c4580e..964d15bb0 100644 --- a/src/include/game/vtxstore.h +++ b/src/include/game/vtxstore.h @@ -7,7 +7,7 @@ void vtxstore_reset(void); void vtxstore_tick(void); -void *vtxstore_allocate(s32 count, s32 index, struct modelnode *node, s32 level); -void vtxstore_free(s32 type, void *arg1); +void *vtxstore_allocate(s32 count, s32 type, struct modelnode *node, s32 level); +void vtxstore_free(s32 type, void *allocation); #endif diff --git a/src/include/types.h b/src/include/types.h index 82a2a7912..aab13ed02 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -5359,28 +5359,28 @@ struct pschannel { #endif }; -struct var8007e3d0_data { - void *unk00; - struct modelnode *node; - s32 level; - s16 count; - s16 unk0e; +struct vtxstoretype { + s32 spmaxunits; + s32 spnumbatches; + s32 mpmaxunits; + s32 mpnumbatches; + s32 othermaxunits; + s32 othernumbatches; + s32 unused18; + s32 unused1c; + s32 unused20; + struct vtxstorebatch *batches; + s32 numunitsmax; + s32 numunitsfree; + s32 numbatches; }; -struct vtxstoretype { - s32 valifsp; - s32 numifsp; - s32 valifmp; - s32 numifmp; - s32 valifspecial; - s32 numifspecial; - s32 unk18; - s32 unk1c; - s32 unk20; - struct var8007e3d0_data *unk24; - s32 val1; - s32 val2; - s32 numallocated; +struct vtxstorebatch { + void *allocation; + struct modelnode *node; + s32 level; + s16 numunitsalloced; + s16 refcount; }; struct wallhit {