From 11b3bca5555e8dd1fb73081ae27f34c46edfed1e Mon Sep 17 00:00:00 2001 From: Zack Middleton Date: Sun, 10 Sep 2017 19:16:47 -0500 Subject: [PATCH] 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). --- code/q3_ui/ui_local.h | 3 ++ code/q3_ui/ui_players.c | 72 ++++++++++++++++++++++++++++++++++----- code/ui/ui_local.h | 3 ++ code/ui/ui_players.c | 74 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 135 insertions(+), 17 deletions(-) diff --git a/code/q3_ui/ui_local.h b/code/q3_ui/ui_local.h index 72979a9e..6bb0fb31 100644 --- a/code/q3_ui/ui_local.h +++ b/code/q3_ui/ui_local.h @@ -486,6 +486,9 @@ typedef struct { 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 barrelModel; qhandle_t flashModel; diff --git a/code/q3_ui/ui_players.c b/code/q3_ui/ui_players.c index b40ec90f..cf2730a7 100644 --- a/code/q3_ui/ui_players.c +++ b/code/q3_ui/ui_players.c @@ -363,7 +363,7 @@ UI_RunLerpFrame =============== */ static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { - int f; + int f, numFrames; animation_t *anim; // 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 anim = lf->animation; + if ( !anim->frameLerp ) { + return; // shouldn't happen + } if ( dp_realtime < lf->animationTime ) { lf->frameTime = lf->animationTime; // initial lerp } else { lf->frameTime = lf->oldFrameTime + 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 ) { f %= anim->loopFrames; f += anim->numFrames - anim->loopFrames; } else { - f = anim->numFrames - 1; + f = numFrames - 1; // the animation is stuck at the end, so it // can immediately transition to another sequence 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 ) { 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 ); 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 AnglesSubtract( headAngles, torsoAngles, headAngles ); AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); @@ -930,7 +956,7 @@ static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, 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; int len; int i; @@ -939,9 +965,15 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat int skip; char text[20000]; fileHandle_t f; + animation_t *animations; + + animations = pi->animations; memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS ); + pi->fixedlegs = qfalse; + pi->fixedtorso = qfalse; + // load the file len = trap_FS_FOpenFile( filename, &f, FS_READ ); if ( len <= 0 ) { @@ -987,6 +1019,12 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat break; } 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 @@ -1003,6 +1041,16 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat token = COM_Parse( &text_p ); 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; } animations[i].firstFrame = atoi( token ); @@ -1010,7 +1058,7 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat if ( i == LEGS_WALKCR ) { skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; } - if ( i >= LEGS_WALKCR ) { + if ( i >= LEGS_WALKCR && ianimations ) ) { + if ( !UI_ParseAnimationFile( filename, pi ) ) { Com_Printf( "Failed to load animation file %s\n", filename ); return qfalse; } diff --git a/code/ui/ui_local.h b/code/ui/ui_local.h index cb41362a..f6354821 100644 --- a/code/ui/ui_local.h +++ b/code/ui/ui_local.h @@ -533,6 +533,9 @@ typedef struct { 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 barrelModel; qhandle_t flashModel; diff --git a/code/ui/ui_players.c b/code/ui/ui_players.c index 87812ef3..7f7ff0e7 100644 --- a/code/ui/ui_players.c +++ b/code/ui/ui_players.c @@ -364,7 +364,7 @@ UI_RunLerpFrame =============== */ static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { - int f; + int f, numFrames; animation_t *anim; // 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 anim = lf->animation; + if ( !anim->frameLerp ) { + return; // shouldn't happen + } if ( dp_realtime < lf->animationTime ) { lf->frameTime = lf->animationTime; // initial lerp } else { lf->frameTime = lf->oldFrameTime + 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 ) { f %= anim->loopFrames; f += anim->numFrames - anim->loopFrames; } else { - f = anim->numFrames - 1; + f = numFrames - 1; // the animation is stuck at the end, so it // can immediately transition to another sequence 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 ) { 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 ); 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 AnglesSubtract( headAngles, torsoAngles, headAngles ); AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); @@ -1015,7 +1041,7 @@ static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, 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; int len; int i; @@ -1024,9 +1050,15 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat int skip; char text[20000]; fileHandle_t f; + animation_t *animations; + + animations = pi->animations; memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS ); + pi->fixedlegs = qfalse; + pi->fixedtorso = qfalse; + // load the file len = trap_FS_FOpenFile( filename, &f, FS_READ ); if ( len <= 0 ) { @@ -1074,6 +1106,12 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat break; } 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 @@ -1090,6 +1128,16 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat token = COM_Parse( &text_p ); 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; } animations[i].firstFrame = atoi( token ); @@ -1097,7 +1145,7 @@ static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animat if ( i == LEGS_WALKCR ) { skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame; } - if ( i >= LEGS_WALKCR ) { + if ( i >= LEGS_WALKCR && ianimations ) ) { + if ( !UI_ParseAnimationFile( filename, pi ) ) { 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 ); return qfalse; }