Rename remapped anim frames to repeat anim frames and improve documentation

This commit is contained in:
Ryan Dwyer 2022-12-04 13:57:04 +10:00
parent ac256277d2
commit 45524f06b2
6 changed files with 110 additions and 88 deletions

View File

@ -547,7 +547,7 @@ bool chr0f01f378(struct model *model, struct coord *arg1, struct coord *arg2, f3
#define VAR(property) g_Vars.property
#endif
if (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) {
if (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) {
if (chr->hidden & CHRHFLAG_00020000) {
func0f065e98(&prop->pos, prop->rooms, arg2, spfc);
} else {
@ -1917,7 +1917,7 @@ void chr0f0220ec(struct chrdata *chr, s32 lvupdate240, bool arg2)
}
if (model->anim
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_02)
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION)
&& lvupdate240 > 0
&& g_Vars.cutsceneskip60ths > 0) {
lvupdate240 += g_Vars.cutsceneskip60ths * 4;
@ -2346,7 +2346,7 @@ s32 chrTick(struct prop *prop)
struct modelrenderdata sp210 = {0, 1, 3};
struct chrdata *chr = prop->chr;
struct model *model = chr->model;
bool onscreen;
bool needsupdate;
bool hatvisible = true;
s32 lvupdate240 = g_Vars.lvupdate240;
struct prop *child;
@ -2356,8 +2356,8 @@ s32 chrTick(struct prop *prop)
s32 sp1e8;
Mtxf sp1a8;
s32 sp1a4;
bool invalidframe;
bool invalidframe2;
bool isrepeatframe;
bool isrepeatframe2;
struct coord sp190;
f32 angle;
struct player *player;
@ -2452,26 +2452,26 @@ s32 chrTick(struct prop *prop)
if (eyespy && eyespy->deployed) {
if (eyespy == g_Vars.currentplayer->eyespy && eyespy->active) {
onscreen = false;
needsupdate = false;
} else {
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
}
if (fulltick) {
chr0f0220ec(chr, lvupdate240, true);
}
} else {
onscreen = false;
needsupdate = false;
}
} else if (chr->chrflags & CHRCFLAG_HIDDEN) {
onscreen = false;
needsupdate = false;
} else if ((chr->chrflags & CHRCFLAG_UNPLAYABLE)
|| (prop->type == PROPTYPE_PLAYER
&& g_Vars.currentplayer == (player = g_Vars.players[playermgrGetPlayerNumByProp(prop)])
&& player->cameramode == CAMERAMODE_THIRDPERSON
&& player->visionmode != VISIONMODE_SLAYERROCKET)) {
// Cutscene chr?
invalidframe = false;
isrepeatframe = false;
if (fulltick) {
model->anim->average = false;
@ -2483,25 +2483,25 @@ s32 chrTick(struct prop *prop)
}
}
if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES)) {
if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREPEATFRAMES)) {
animLoadHeader(chr->model->anim->animnum);
invalidframe = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0
isrepeatframe = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0
|| (animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->frameb) < 0
&& chr->model->anim->frac != 0.0f);
}
if (invalidframe) {
onscreen = false;
if (isrepeatframe) {
needsupdate = false;
} else {
onscreen = posIsInDrawDistance(&prop->pos);
needsupdate = posIsInDrawDistance(&prop->pos);
}
} else if (chr->actiontype == ACT_PATROL || chr->actiontype == ACT_GOPOS) {
if ((chr->actiontype == ACT_PATROL && chr->act_patrol.waydata.mode == WAYMODE_MAGIC)
|| (chr->actiontype == ACT_GOPOS && chr->act_gopos.waydata.mode == WAYMODE_MAGIC)) {
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
if (onscreen) {
if (needsupdate) {
model->anim->average = false;
modelGetRootPosition(model, &chr->prevpos);
modelUpdateInfo(model);
@ -2511,9 +2511,9 @@ s32 chrTick(struct prop *prop)
chr0f0220ec(chr, lvupdate240, true);
}
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
if (onscreen) {
if (needsupdate) {
if (chr->actiontype == ACT_PATROL) {
chr->act_patrol.waydata.lastvisible60 = g_Vars.lvframe60;
} else if (chr->actiontype == ACT_GOPOS) {
@ -2521,16 +2521,16 @@ s32 chrTick(struct prop *prop)
}
}
model->anim->average = !onscreen
model->anim->average = !needsupdate
&& !((prop->flags & (PROPFLAG_ONANYSCREENTHISTICK | PROPFLAG_ONANYSCREENPREVTICK)) != 0);
}
} else if (chr->actiontype == ACT_ANIM && !chr->act_anim.movewheninvis) {
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
if (fulltick) {
model->anim->average = false;
if (onscreen && !chr->act_anim.lockpos) {
if (needsupdate && !chr->act_anim.lockpos) {
chr0f0220ec(chr, lvupdate240, true);
} else {
chr0f0220ec(chr, lvupdate240, false);
@ -2541,14 +2541,14 @@ s32 chrTick(struct prop *prop)
if (chr->chrflags & CHRCFLAG_00000001) {
chr0f0220ec(chr, lvupdate240, true);
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
} else {
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
if (g_Vars.mplayerisrunning) {
if (fulltick) {
if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
if (onscreen) {
if (needsupdate) {
chr0f0220ec(chr, lvupdate240, true);
} else if (model->anim->animnum2 != 0) {
chr0f0220ec(chr, lvupdate240, false);
@ -2557,7 +2557,7 @@ s32 chrTick(struct prop *prop)
chr0f0220ec(chr, lvupdate240, true);
}
}
} else if (onscreen) {
} else if (needsupdate) {
if (chr->act_stand.playwalkanim == true) {
chr0f0220ec(chr, lvupdate240, false);
} else {
@ -2568,34 +2568,34 @@ s32 chrTick(struct prop *prop)
}
}
} else if (chr->actiontype == ACT_DEAD) {
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
} else if (prop->type == PROPTYPE_PLAYER
&& (g_Vars.mplayerisrunning
|| (player = g_Vars.players[playermgrGetPlayerNumByProp(prop)], player->cameramode == CAMERAMODE_EYESPY)
|| (player->cameramode == CAMERAMODE_THIRDPERSON && player->visionmode == VISIONMODE_SLAYERROCKET))) {
model->anim->average = false;
chr0f0220ec(chr, lvupdate240, true);
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
} else {
invalidframe2 = false;
isrepeatframe2 = false;
if (fulltick) {
model->anim->average = false;
chr0f0220ec(chr, lvupdate240, true);
}
if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES)) {
if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREPEATFRAMES)) {
animLoadHeader(chr->model->anim->animnum);
invalidframe2 = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0
isrepeatframe2 = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0
|| (animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->frameb) < 0
&& chr->model->anim->frac != 0.0f);
}
if (invalidframe2) {
onscreen = false;
if (isrepeatframe2) {
needsupdate = false;
} else {
onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true);
}
}
@ -2612,17 +2612,17 @@ s32 chrTick(struct prop *prop)
}
if (prop->pos.y < -65536) {
onscreen = false;
needsupdate = false;
}
#if VERSION >= VERSION_NTSC_1_0
if (!g_Vars.normmplayerisrunning && onscreen) {
if (!g_Vars.normmplayerisrunning && needsupdate) {
if (chr->actiontype == ACT_DEAD
|| (chr->actiontype == ACT_DRUGGEDKO && (chr->chrflags & CHRCFLAG_KEEPCORPSEKO) == 0)) {
var8009cdac++;
if (var8009cdac > 10) {
onscreen = false;
needsupdate = false;
chrDropItemsForOwnerReap(chr);
chr->hidden |= CHRHFLAG_REAPED;
}
@ -2631,12 +2631,12 @@ s32 chrTick(struct prop *prop)
}
if (var8009cdb0 + var8009cdac > 30) {
onscreen = false;
needsupdate = false;
}
}
#endif
if (onscreen) {
if (needsupdate) {
#if VERSION == VERSION_NTSC_BETA || VERSION == VERSION_PAL_BETA
debug0f1199f0nb();
#endif

View File

@ -11015,7 +11015,7 @@ s32 objTickPlayer(struct prop *prop)
}
if (model->anim) {
if (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) {
if (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) {
if (g_Vars.tickmode != TICKMODE_CUTSCENE
&& modelGetCurAnimFrame(model) >= modelGetNumAnimFrames(model) - 1) {
modelmgrFreeAnim(model->anim);
@ -11040,7 +11040,7 @@ s32 objTickPlayer(struct prop *prop)
animLoadHeader(model->anim->animnum);
if ((g_Anims[model->anim->animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES)
if ((g_Anims[model->anim->animnum].flags & ANIMFLAG_HASREPEATFRAMES)
&& animGetRemappedFrame(model->anim->animnum, model->anim->framea) < 0) {
invalidframe = true;
} else {

View File

@ -247,10 +247,10 @@
#define AMMODE_VIEW 1
#define AMMODE_EDIT 2 // unused
#define ANIMFLAG_LOOP 0x01
#define ANIMFLAG_02 0x02
#define ANIMFLAG_HASREMAPPEDFRAMES 0x04
#define ANIMFLAG_HASCUTSKIPFRAMES 0x08
#define ANIMFLAG_LOOP 0x01
#define ANIMFLAG_ABSOLUTETRANSLATION 0x02
#define ANIMFLAG_HASREPEATFRAMES 0x04
#define ANIMFLAG_HASCUTSKIPFRAMES 0x08
#define ANIMFIELD_S16_ROTATE 0x01
#define ANIMFIELD_S16_TRANSLATE 0x02

View File

@ -12,7 +12,7 @@ bool animHasFrames(s16 animnum);
s32 animGetNumAnimations(void);
u8 *animDma(u8 *dst, u32 segoffset, u32 len);
s32 animGetRemappedFrame(s16 animnum, s32 frame);
bool animRemapFrame(s16 animnum, s32 frame, s32 *frameptr);
bool animRemapFrameForLoad(s16 animnum, s32 frame, s32 *frameptr);
bool animIsFrameCutSkipped(s16 animnum, s32 frame);
u8 animLoadFrame(s16 animnum, s32 framenum);
void animForgetFrameBirths(void);

View File

@ -144,59 +144,81 @@ u8 *animDma(u8 *dst, u32 segoffset, u32 len)
}
/**
* Get a remapped frame, or return -1 if the frame is removed.
* Return -1 if the given apparent frame is a repeat frame, or if not a repeat
* frame then remap the apparent frame to a real one and return it.
*
* The end of the header can contain a sequence of shorts such as:
* -1, 55, 30
*
* The values are iterated backwards in pairs of 2 and are terminated by -1.
*
* In each pair, the right value is the repeatfromframe and the left value is
* the repeattoframe. In the above example, apparent frames 30 to 55 are
* repeated, so the remapping looks like:
* 29 -> 29
* 30 -> -1
* ...
* 55 -> -1
* 56 -> 30
* 57 -> 31
*/
s32 animGetRemappedFrame(s16 animnum, s32 frame)
s32 animGetRemappedFrame(s16 animnum, s32 apparentframe)
{
u8 *ptr = (u8 *)(g_AnimHeaderBytes[g_AnimToHeaderSlot[animnum]] + g_Anims[animnum].headerlen - 2);
s32 result = frame;
s32 realframe = apparentframe;
while (true) {
s16 value1 = ptr[0] << 8 | ptr[1];
s16 value2;
s16 repeatfromframe = ptr[0] << 8 | ptr[1];
s16 repeattoframe;
if (value1 < 0) {
if (repeatfromframe < 0) {
break;
}
value2 = ptr[-2] << 8 | ptr[-1];
repeattoframe = ptr[-2] << 8 | ptr[-1];
ptr -= 4;
if (value1 <= frame) {
if (value2 < frame) {
result = result - value2 + value1 - 1;
if (repeatfromframe <= apparentframe) {
if (repeattoframe < apparentframe) {
realframe = realframe - repeattoframe + repeatfromframe - 1;
} else {
result = -1;
realframe = -1;
break;
}
}
}
return result;
return realframe;
}
bool animRemapFrame(s16 animnum, s32 frame, s32 *frameptr)
/**
* Similar to the above, but with the following differences:
* - Write the remapped frame to the frameptr pointer instead of returning it.
* - If the apparent frame is a repeat, write the original frame rather than -1.
* - Return true if the frame is original or false if it's a repeat.
*/
bool animRemapFrameForLoad(s16 animnum, s32 apparentframe, s32 *frameptr)
{
u8 *ptr = (u8 *)(g_AnimHeaderBytes[g_AnimToHeaderSlot[animnum]] + g_Anims[animnum].headerlen - 2);
s32 result = frame;
s32 result = apparentframe;
bool ret = true;
while (true) {
s16 value1 = ptr[0] << 8 | ptr[1];
s16 value2;
s16 repeatfromframe = ptr[0] << 8 | ptr[1];
s16 repeattoframe;
if (value1 < 0) {
if (repeatfromframe < 0) {
break;
}
value2 = ptr[-2] << 8 | ptr[-1];
repeattoframe = ptr[-2] << 8 | ptr[-1];
ptr -= 4;
if (value1 <= frame) {
if (value2 < frame) {
result = result - value2 + value1 - 1;
if (repeatfromframe <= apparentframe) {
if (repeattoframe < apparentframe) {
result = result - repeattoframe + repeatfromframe - 1;
} else {
result = result - frame + value1;
result = result - apparentframe + repeatfromframe;
ret = false;
break;
}
@ -214,19 +236,19 @@ bool animRemapFrame(s16 animnum, s32 frame, s32 *frameptr)
* Used by cutscenes.
*
* The skip frame numbers are stored at the tail end of the header, prior to the
* frame remapping data. The frame numbers are stored as a list of shorts.
* frame repeat data. The frame numbers are stored as a list of shorts.
* The list is terminated on the left side with a negative value.
*/
bool animIsFrameCutSkipped(s16 animnum, s32 frame)
{
u8 *ptr = (u8 *)(g_AnimHeaderBytes[g_AnimToHeaderSlot[animnum]] + g_Anims[animnum].headerlen - 2);
// Iterate past the ANIMFLAG_HASREMAPPEDFRAMES stuff
if (g_Anims[animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES) {
// Iterate past the repeat list
if (g_Anims[animnum].flags & ANIMFLAG_HASREPEATFRAMES) {
while (true) {
s16 value1 = ptr[0] << 8 | ptr[1];
s16 repeatfromframe = ptr[0] << 8 | ptr[1];
if (value1 < 0) {
if (repeatfromframe < 0) {
break;
}
@ -237,13 +259,13 @@ bool animIsFrameCutSkipped(s16 animnum, s32 frame)
}
while (true) {
s16 value2 = ptr[0] << 8 | ptr[1];
s16 skipframe = ptr[0] << 8 | ptr[1];
if (value2 < 0) {
if (skipframe < 0) {
break;
}
if (value2 == frame) {
if (skipframe == frame) {
return true;
}
@ -277,8 +299,8 @@ u8 animLoadFrame(s16 animnum, s32 framenum)
slot = (slot + 1) % ANIM_FRAME_CACHE_SIZE;
}
if (g_Anims[animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES) {
animRemapFrame(animnum, framenum, &loadframenum);
if (g_Anims[animnum].flags & ANIMFLAG_HASREPEATFRAMES) {
animRemapFrameForLoad(animnum, framenum, &loadframenum);
}
if (g_Anims[animnum].bytesperframe) {

View File

@ -791,7 +791,7 @@ void modelUpdateChrNodeMtx(struct modelrenderdata *arg0, struct model *model, st
modelTweenRot(&rot3, &rot4, anim->frac2);
}
if ((g_Anims[anim->animnum].flags & ANIMFLAG_02) && (g_Anims[anim->animnum2].flags & ANIMFLAG_02) == 0) {
if ((g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) && (g_Anims[anim->animnum2].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) {
mtx4LoadYRotation(rwdata->chrinfo.yrot, &sp78);
mtx4LoadRotation(&rot3, &sp38);
mtx00015be0(&sp78, &sp38);
@ -808,7 +808,7 @@ void modelUpdateChrNodeMtx(struct modelrenderdata *arg0, struct model *model, st
mtx4LoadRotation(&rot1, &sp1d8);
}
if (g_Anims[anim->animnum].flags & ANIMFLAG_02) {
if (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) {
mtx4LoadTranslation(sp254, &sp198);
} else {
if (rwdata->chrinfo.unk18 != 0.0f) {
@ -1082,7 +1082,7 @@ void modelUpdatePositionNodeMtx(struct modelrenderdata *renderdata, struct model
skel = model->definition->skel;
if (anim->animnum != 0) {
sp128 = (g_Anims[anim->animnum].flags & ANIMFLAG_02) && node == model->definition->rootnode;
sp128 = (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) && node == model->definition->rootnode;
animGetRotTranslateScale(animpart, anim->flip, skel, anim->animnum, anim->frameslot1, &rot1, &translate1, &scale1);
@ -1825,7 +1825,7 @@ void modelSetAnimation2(struct model *model, s16 animnum, s32 flip, f32 fstartfr
f32 x;
f32 z;
if (g_Anims[anim->animnum].flags & ANIMFLAG_02) {
if (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) {
sp64 = func0f15c888();
animLoadHeader(anim->animnum);
frameslot = animLoadFrame(anim->animnum, anim->framea);
@ -1951,8 +1951,8 @@ void modelSetAnimationWithMerge(struct model *model, s16 animnum, u32 flip, f32
{
if (model) {
if (model->anim && model->anim->animnum
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_02)
&& (g_Anims[animnum].flags & ANIMFLAG_02) == 0) {
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION)
&& (g_Anims[animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) {
timemerge = 0;
}
@ -1968,8 +1968,8 @@ void modelSetAnimation(struct model *model, s16 animnum, s32 flip, f32 startfram
{
if (model) {
if (model->anim && model->anim->animnum
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_02)
&& (g_Anims[animnum].flags & ANIMFLAG_02) == 0) {
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION)
&& (g_Anims[animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) {
merge = 0;
}
@ -2232,7 +2232,7 @@ void modelSetAnimFrame2WithChrStuff(struct model *model, f32 curframe, f32 endfr
floorend = ceil(endframe);
}
if (g_Anims[anim->animnum].flags & ANIMFLAG_02) {
if (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) {
f20 = func0f15c888();
if (floorend != anim->framea) {
@ -2463,7 +2463,7 @@ void modelSetAnimFrame2WithChrStuff(struct model *model, f32 curframe, f32 endfr
anim->frame = anim->frameb + (1.0f - anim->frac);
}
if (anim->animnum2 && (g_Anims[anim->animnum].flags & ANIMFLAG_02) == 0) {
if (anim->animnum2 && (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) {
s32 floorcur2 = floor(curframe2);
s32 floorend2 = floor(endframe2);