Update UI player animation handling to match CGame

Fix "Error parsing animation file" messages in UI. Caused by fixing the
handling of missing tokens in animation.cfg parser in a past commit.
Fix new Team Arena torso animation frame numbers in UI.
Add support for fixedtorso and fixedlegs keywords.
Add support for reversed animations (negative numframes).
This commit is contained in:
Zack Middleton 2017-09-10 19:16:47 -05:00
parent 098d97bdb0
commit 11b3bca555
4 changed files with 135 additions and 17 deletions

View File

@ -486,6 +486,9 @@ typedef struct {
animation_t animations[MAX_ANIMATIONS]; animation_t animations[MAX_ANIMATIONS];
qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
qboolean fixedtorso; // true if torso never changes yaw
qhandle_t weaponModel; qhandle_t weaponModel;
qhandle_t barrelModel; qhandle_t barrelModel;
qhandle_t flashModel; qhandle_t flashModel;

View File

@ -363,7 +363,7 @@ UI_RunLerpFrame
=============== ===============
*/ */
static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
int f; int f, numFrames;
animation_t *anim; animation_t *anim;
// see if the animation sequence is switching // see if the animation sequence is switching
@ -379,25 +379,41 @@ static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation
// get the next frame based on the animation // get the next frame based on the animation
anim = lf->animation; anim = lf->animation;
if ( !anim->frameLerp ) {
return; // shouldn't happen
}
if ( dp_realtime < lf->animationTime ) { if ( dp_realtime < lf->animationTime ) {
lf->frameTime = lf->animationTime; // initial lerp lf->frameTime = lf->animationTime; // initial lerp
} else { } else {
lf->frameTime = lf->oldFrameTime + anim->frameLerp; lf->frameTime = lf->oldFrameTime + anim->frameLerp;
} }
f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
if ( f >= anim->numFrames ) {
f -= anim->numFrames; numFrames = anim->numFrames;
if (anim->flipflop) {
numFrames *= 2;
}
if ( f >= numFrames ) {
f -= numFrames;
if ( anim->loopFrames ) { if ( anim->loopFrames ) {
f %= anim->loopFrames; f %= anim->loopFrames;
f += anim->numFrames - anim->loopFrames; f += anim->numFrames - anim->loopFrames;
} else { } else {
f = anim->numFrames - 1; f = numFrames - 1;
// the animation is stuck at the end, so it // the animation is stuck at the end, so it
// can immediately transition to another sequence // can immediately transition to another sequence
lf->frameTime = dp_realtime; lf->frameTime = dp_realtime;
} }
} }
lf->frame = anim->firstFrame + f; if ( anim->reversed ) {
lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
}
else if (anim->flipflop && f>=anim->numFrames) {
lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
}
else {
lf->frame = anim->firstFrame + f;
}
if ( dp_realtime > lf->frameTime ) { if ( dp_realtime > lf->frameTime ) {
lf->frameTime = dp_realtime; lf->frameTime = dp_realtime;
} }
@ -615,6 +631,16 @@ static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3],
UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching ); UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
torsoAngles[PITCH] = pi->torso.pitchAngle; torsoAngles[PITCH] = pi->torso.pitchAngle;
if ( pi->fixedtorso ) {
torsoAngles[PITCH] = 0.0f;
}
if ( pi->fixedlegs ) {
legsAngles[YAW] = torsoAngles[YAW];
legsAngles[PITCH] = 0.0f;
legsAngles[ROLL] = 0.0f;
}
// pull the angles back out of the hierarchial chain // pull the angles back out of the hierarchial chain
AnglesSubtract( headAngles, torsoAngles, headAngles ); AnglesSubtract( headAngles, torsoAngles, headAngles );
AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
@ -930,7 +956,7 @@ static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName,
UI_ParseAnimationFile UI_ParseAnimationFile
====================== ======================
*/ */
static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) { static qboolean UI_ParseAnimationFile( const char *filename, playerInfo_t *pi ) {
char *text_p, *prev; char *text_p, *prev;
int len; int len;
int i; int i;
@ -939,9 +965,15 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
int skip; int skip;
char text[20000]; char text[20000];
fileHandle_t f; fileHandle_t f;
animation_t *animations;
animations = pi->animations;
memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS ); memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
pi->fixedlegs = qfalse;
pi->fixedtorso = qfalse;
// load the file // load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ ); len = trap_FS_FOpenFile( filename, &f, FS_READ );
if ( len <= 0 ) { if ( len <= 0 ) {
@ -987,6 +1019,12 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
break; break;
} }
continue; continue;
} else if ( !Q_stricmp( token, "fixedlegs" ) ) {
pi->fixedlegs = qtrue;
continue;
} else if ( !Q_stricmp( token, "fixedtorso" ) ) {
pi->fixedtorso = qtrue;
continue;
} }
// if it is a number, start parsing animations // if it is a number, start parsing animations
@ -1003,6 +1041,16 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
token = COM_Parse( &text_p ); token = COM_Parse( &text_p );
if ( !token[0] ) { if ( !token[0] ) {
if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
animations[i].reversed = qfalse;
animations[i].flipflop = qfalse;
continue;
}
break; break;
} }
animations[i].firstFrame = atoi( token ); animations[i].firstFrame = atoi( token );
@ -1010,7 +1058,7 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
if ( i == LEGS_WALKCR ) { if ( i == LEGS_WALKCR ) {
skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
} }
if ( i >= LEGS_WALKCR ) { if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
animations[i].firstFrame -= skip; animations[i].firstFrame -= skip;
} }
@ -1020,6 +1068,14 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
} }
animations[i].numFrames = atoi( token ); animations[i].numFrames = atoi( token );
animations[i].reversed = qfalse;
animations[i].flipflop = qfalse;
// if numFrames is negative the animation is reversed
if (animations[i].numFrames < 0) {
animations[i].numFrames = -animations[i].numFrames;
animations[i].reversed = qtrue;
}
token = COM_Parse( &text_p ); token = COM_Parse( &text_p );
if ( !token[0] ) { if ( !token[0] ) {
break; break;
@ -1110,7 +1166,7 @@ qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName
// load the animations // load the animations
Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
if ( !UI_ParseAnimationFile( filename, pi->animations ) ) { if ( !UI_ParseAnimationFile( filename, pi ) ) {
Com_Printf( "Failed to load animation file %s\n", filename ); Com_Printf( "Failed to load animation file %s\n", filename );
return qfalse; return qfalse;
} }

View File

@ -533,6 +533,9 @@ typedef struct {
animation_t animations[MAX_TOTALANIMATIONS]; animation_t animations[MAX_TOTALANIMATIONS];
qboolean fixedlegs; // true if legs yaw is always the same as torso yaw
qboolean fixedtorso; // true if torso never changes yaw
qhandle_t weaponModel; qhandle_t weaponModel;
qhandle_t barrelModel; qhandle_t barrelModel;
qhandle_t flashModel; qhandle_t flashModel;

View File

@ -364,7 +364,7 @@ UI_RunLerpFrame
=============== ===============
*/ */
static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) {
int f; int f, numFrames;
animation_t *anim; animation_t *anim;
// see if the animation sequence is switching // see if the animation sequence is switching
@ -380,25 +380,41 @@ static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation
// get the next frame based on the animation // get the next frame based on the animation
anim = lf->animation; anim = lf->animation;
if ( !anim->frameLerp ) {
return; // shouldn't happen
}
if ( dp_realtime < lf->animationTime ) { if ( dp_realtime < lf->animationTime ) {
lf->frameTime = lf->animationTime; // initial lerp lf->frameTime = lf->animationTime; // initial lerp
} else { } else {
lf->frameTime = lf->oldFrameTime + anim->frameLerp; lf->frameTime = lf->oldFrameTime + anim->frameLerp;
} }
f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp;
if ( f >= anim->numFrames ) {
f -= anim->numFrames; numFrames = anim->numFrames;
if (anim->flipflop) {
numFrames *= 2;
}
if ( f >= numFrames ) {
f -= numFrames;
if ( anim->loopFrames ) { if ( anim->loopFrames ) {
f %= anim->loopFrames; f %= anim->loopFrames;
f += anim->numFrames - anim->loopFrames; f += anim->numFrames - anim->loopFrames;
} else { } else {
f = anim->numFrames - 1; f = numFrames - 1;
// the animation is stuck at the end, so it // the animation is stuck at the end, so it
// can immediately transition to another sequence // can immediately transition to another sequence
lf->frameTime = dp_realtime; lf->frameTime = dp_realtime;
} }
} }
lf->frame = anim->firstFrame + f; if ( anim->reversed ) {
lf->frame = anim->firstFrame + anim->numFrames - 1 - f;
}
else if (anim->flipflop && f>=anim->numFrames) {
lf->frame = anim->firstFrame + anim->numFrames - 1 - (f%anim->numFrames);
}
else {
lf->frame = anim->firstFrame + f;
}
if ( dp_realtime > lf->frameTime ) { if ( dp_realtime > lf->frameTime ) {
lf->frameTime = dp_realtime; lf->frameTime = dp_realtime;
} }
@ -616,6 +632,16 @@ static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3],
UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching ); UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching );
torsoAngles[PITCH] = pi->torso.pitchAngle; torsoAngles[PITCH] = pi->torso.pitchAngle;
if ( pi->fixedtorso ) {
torsoAngles[PITCH] = 0.0f;
}
if ( pi->fixedlegs ) {
legsAngles[YAW] = torsoAngles[YAW];
legsAngles[PITCH] = 0.0f;
legsAngles[ROLL] = 0.0f;
}
// pull the angles back out of the hierarchial chain // pull the angles back out of the hierarchial chain
AnglesSubtract( headAngles, torsoAngles, headAngles ); AnglesSubtract( headAngles, torsoAngles, headAngles );
AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); AnglesSubtract( torsoAngles, legsAngles, torsoAngles );
@ -1015,7 +1041,7 @@ static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName,
UI_ParseAnimationFile UI_ParseAnimationFile
====================== ======================
*/ */
static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) { static qboolean UI_ParseAnimationFile( const char *filename, playerInfo_t *pi ) {
char *text_p, *prev; char *text_p, *prev;
int len; int len;
int i; int i;
@ -1024,9 +1050,15 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
int skip; int skip;
char text[20000]; char text[20000];
fileHandle_t f; fileHandle_t f;
animation_t *animations;
animations = pi->animations;
memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS ); memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
pi->fixedlegs = qfalse;
pi->fixedtorso = qfalse;
// load the file // load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ ); len = trap_FS_FOpenFile( filename, &f, FS_READ );
if ( len <= 0 ) { if ( len <= 0 ) {
@ -1074,6 +1106,12 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
break; break;
} }
continue; continue;
} else if ( !Q_stricmp( token, "fixedlegs" ) ) {
pi->fixedlegs = qtrue;
continue;
} else if ( !Q_stricmp( token, "fixedtorso" ) ) {
pi->fixedtorso = qtrue;
continue;
} }
// if it is a number, start parsing animations // if it is a number, start parsing animations
@ -1090,6 +1128,16 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
token = COM_Parse( &text_p ); token = COM_Parse( &text_p );
if ( !token[0] ) { if ( !token[0] ) {
if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) {
animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
animations[i].initialLerp = animations[TORSO_GESTURE].initialLerp;
animations[i].loopFrames = animations[TORSO_GESTURE].loopFrames;
animations[i].numFrames = animations[TORSO_GESTURE].numFrames;
animations[i].reversed = qfalse;
animations[i].flipflop = qfalse;
continue;
}
break; break;
} }
animations[i].firstFrame = atoi( token ); animations[i].firstFrame = atoi( token );
@ -1097,7 +1145,7 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
if ( i == LEGS_WALKCR ) { if ( i == LEGS_WALKCR ) {
skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
} }
if ( i >= LEGS_WALKCR ) { if ( i >= LEGS_WALKCR && i<TORSO_GETFLAG) {
animations[i].firstFrame -= skip; animations[i].firstFrame -= skip;
} }
@ -1107,6 +1155,14 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat
} }
animations[i].numFrames = atoi( token ); animations[i].numFrames = atoi( token );
animations[i].reversed = qfalse;
animations[i].flipflop = qfalse;
// if numFrames is negative the animation is reversed
if (animations[i].numFrames < 0) {
animations[i].numFrames = -animations[i].numFrames;
animations[i].reversed = qtrue;
}
token = COM_Parse( &text_p ); token = COM_Parse( &text_p );
if ( !token[0] ) { if ( !token[0] ) {
break; break;
@ -1225,9 +1281,9 @@ qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName
// load the animations // load the animations
Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
if ( !UI_ParseAnimationFile( filename, pi->animations ) ) { if ( !UI_ParseAnimationFile( filename, pi ) ) {
Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName ); Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
if ( !UI_ParseAnimationFile( filename, pi->animations ) ) { if ( !UI_ParseAnimationFile( filename, pi ) ) {
Com_Printf( "Failed to load animation file %s\n", filename ); Com_Printf( "Failed to load animation file %s\n", filename );
return qfalse; return qfalse;
} }