Document vtxstores

This commit is contained in:
Ryan Dwyer 2024-10-07 21:55:22 +10:00
parent 62e9f4d1a6
commit b7c4828289
8 changed files with 190 additions and 154 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 {