05 Apr 2010

This commit is contained in:
g-cont 2010-04-05 00:00:00 +04:00 committed by Alibek Omarov
parent 9f0fb3da32
commit 432fa48d5d
17 changed files with 379 additions and 330 deletions

View File

@ -207,7 +207,6 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti
// copy state to progs
ent->v.modelindex = state->modelindex;
ent->v.weaponmodel = state->weaponmodel;
ent->v.frame = state->frame;
ent->v.sequence = state->sequence;
ent->v.gaitsequence = state->gaitsequence;
ent->v.body = state->body;
@ -215,7 +214,7 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti
ent->v.effects = state->effects;
ent->v.velocity = state->velocity;
ent->v.basevelocity = state->basevelocity;
ent->v.oldorigin = ent->v.origin;
ent->v.oldorigin = ent->v.origin; // previous origin holds
ent->v.mins = state->mins;
ent->v.maxs = state->maxs;
ent->v.framerate = state->framerate;
@ -231,7 +230,6 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti
ent->v.movetype = state->movetype;
ent->v.flags = state->flags;
ent->v.ideal_pitch = state->idealpitch;
ent->v.oldangles = ent->v.angles; // just a delta between frames
ent->v.animtime = state->animtime;
if( state->groundent != -1 )
@ -245,99 +243,36 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti
switch( ent->v.movetype )
{
case MOVETYPE_NONE:
case MOVETYPE_STEP:
// monster's steps will be interpolated on render-side
ent->v.origin = state->origin;
ent->v.angles = state->angles;
break;
default:
ent->v.angles = LerpAngle( prev->angles, state->angles, m_fLerp );
ent->v.origin = LerpPoint( prev->origin, state->origin, m_fLerp );
ent->v.basevelocity = LerpPoint( prev->basevelocity, state->basevelocity, m_fLerp );
break;
}
// lerping some fields
for( i = 0; i < 3; i++ )
// interpolate scale, renderamount etc
ent->v.scale = LerpPoint( prev->scale, state->scale, m_fLerp );
ent->v.rendercolor = LerpPoint( prev->rendercolor, state->rendercolor, m_fLerp );
ent->v.renderamt = LerpPoint( prev->renderamt, state->renderamt, m_fLerp );
// auto-animation uses v.frame for hold ending frame
if(!( ent->v.effects & EF_ANIMATE ))
{
ent->v.angles[i] = LerpAngle( prev->angles[i], state->angles[i], m_fLerp );
ent->v.rendercolor[i] = LerpPoint( prev->rendercolor[i], state->rendercolor[i], m_fLerp );
}
if( ent->v.movetype == MOVETYPE_STEP )
{
float f = 0;
float d;
// don't do it if the goalstarttime hasn't updated in a while.
// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
// was increased to 1.0 s., which is 2x the max lag we are accounting for.
if(( gpGlobals->time < state->animtime + 1.0f ) && ( state->animtime != prev->animtime ))
if( ent->v.animtime )
{
f = (gpGlobals->time - state->animtime) / (state->animtime - prev->animtime);
//ALERT( at_console, "%4.2f %.2f %.2f\n", f, state->animtime, gpGlobals->time );
}
if(!( ent->v.flags & EF_NOINTERP ))
{
// ugly hack to interpolate angle, position.
// current is reached 0.1 seconds after being set
f = f - 1.0;
// use normal studio lerping
ent->v.frame = state->frame;
}
else
{
f = 0;
// sprite frames will be interpolated in other place
ent->v.frame = Q_rint( state->frame );
}
for( i = 0; i < 3; i++ )
{
ent->v.origin[i] += (ent->v.origin[i] - prev->origin[i]) * f;
}
// NOTE: Because multiplayer lag can be relatively large, we don't want to cap
// f at 1.5 anymore.
//if( f > -1.0 && f < 1.5 ) {}
for( i = 0; i < 3; i++ )
{
float ang1, ang2;
ang1 = ent->v.angles[i];
ang2 = prev->angles[i];
d = ang1 - ang2;
if( d > 180 )
{
d -= 360;
}
else if( d < -180 )
{
d += 360;
}
ent->v.angles[i] += d * f;
}
//ALERT( at_console, "%.3f \n", f );
}
// interpolate scale, renderamount etc
ent->v.renderamt = LerpPoint( prev->renderamt, state->renderamt, m_fLerp );
ent->v.scale = LerpPoint( prev->scale, state->scale, m_fLerp );
if(!( ent->v.effects & EF_ANIMATE )) // auto-animation uses v.frame for hold ending frame
{
float frame = state->frame;
float prevframe = prev->frame;
float lerpTime = (frame - prevframe);
if( ent->v.animtime )
{
if(!( ent->v.effects & EF_NOINTERP ))
{
// adjust lerping values if animation restarted
if( lerpTime < 0 ) prevframe = 1.001;
ent->v.frame = LerpPoint( prevframe, frame, m_fLerp );
}
else ent->v.frame = state->frame; // use normal studio lerping
}
else ent->v.frame = Q_rint( state->frame ); // sprite frames will be interpolated in other place
}
switch( state->ed_type )
@ -390,26 +325,27 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti
if( state->owner != -1 )
ent->v.owner = GetEntityByIndex( state->owner );
else ent->v.owner = NULL;
// add server beam now
g_pViewRenderBeams->AddServerBeam( ent );
break;
default:
ent->v.movedir = Vector( 0, 0, 0 );
break;
}
// add env_beam to drawing list
if( state->ed_type == ED_BEAM )
g_pViewRenderBeams->AddServerBeam( ent );
for( i = 0; i < MAXSTUDIOBLENDS; i++ )
{
ent->v.blending[i] = LerpByte( prev->blending[i], state->blending[i], m_fLerp );
}
for( i = 0; i < MAXSTUDIOCONTROLLERS; i++ )
{
if( abs( prev->controller[i] - state->controller[i] ) > 128 )
ent->v.controller[i] = state->controller[i];
else ent->v.controller[i] = LerpByte( prev->controller[i], state->controller[i], m_fLerp );
}
// g-cont. moved here because we may needs apply null scale to skyportal
if( ent->v.scale == 0.0f ) ent->v.scale = 1.0f;
ent->v.pContainingEntity = ent;

View File

@ -153,4 +153,13 @@ void HUD_StudioFxTransform( edict_t *ent, float transform[4][4] )
transform[2][1] *= scale;
break;
}
}
int HUD_StudioDoInterp( edict_t *e )
{
if( r_studio_lerping->integer )
{
return (e->v.flags & EF_NOINTERP) ? false : true;
}
return false;
}

View File

@ -44,6 +44,7 @@ extern void HUD_CreateEntities( void );
extern int HUD_AddVisibleEntity( edict_t *pEnt, int ed_type );
extern void HUD_StudioEvent( const dstudioevent_t *event, edict_t *entity );
extern void HUD_StudioFxTransform( edict_t *ent, float transform[4][4] );
extern int HUD_StudioDoInterp( edict_t *e );
extern void HUD_ParseTempEntity( void );
extern void V_CalcRefdef( ref_params_t *parms );
extern void V_StartPitchDrift( void );
@ -126,6 +127,17 @@ inline float LerpAngle( float a2, float a1, float frac )
return a2 + frac * (a1 - a2);
}
inline Vector LerpAngle( Vector a2, Vector a1, float frac )
{
Vector a3;
a3.x = LerpAngle( a2.x, a1.x, frac );
a3.y = LerpAngle( a2.y, a1.y, frac );
a3.z = LerpAngle( a2.z, a1.z, frac );
return a3;
}
inline float LerpView( float org1, float org2, float ofs1, float ofs2, float frac )
{
return org1 + ofs1 + frac * (org2 + ofs2 - (org1 + ofs1));
@ -211,6 +223,7 @@ extern int g_iAlive; // indicates alive local client or not
// input.cpp
extern cvar_t *v_centerspeed;
extern cvar_t *v_centermove;
extern cvar_t *r_studio_lerping;
extern cvar_t *cl_forwardspeed;
extern cvar_t *cl_particlelod;
extern cvar_t *cl_particles;

View File

@ -56,6 +56,7 @@ cvar_t *cl_bobup;
cvar_t *cl_waterdist;
cvar_t *cl_chasedist;
cvar_t *r_studio_lerping;
cvar_t *v_iyaw_cycle;
cvar_t *v_iroll_cycle;
cvar_t *v_ipitch_cycle;
@ -131,6 +132,7 @@ void V_Init( void )
scr_ofsx = g_engfuncs.pfnRegisterVariable( "scr_ofsx", "0", 0, "screen offset by X" );
scr_ofsy = g_engfuncs.pfnRegisterVariable( "scr_ofsy", "0", 0, "screen offset by Y" );
scr_ofsz = g_engfuncs.pfnRegisterVariable( "scr_ofsz", "0", 0, "screen offset by Z" );
r_studio_lerping = g_engfuncs.pfnRegisterVariable( "r_studio_lerping", "1", FCVAR_ARCHIVE, "enables studio model animation lerping" ); // get copy of engine cvar
cl_vsmoothing = g_engfuncs.pfnRegisterVariable( "cl_vsmoothing", "0.05", 0, "enables lepring in multiplayer" );
cl_stairsmooth = g_engfuncs.pfnRegisterVariable( "cl_vstairsmooth", "100", FCVAR_ARCHIVE, "how fast your view moves upward/downward when running up/down stairs" );

View File

@ -29,7 +29,6 @@ typedef struct entvars_s
vec3_t movedir;
vec3_t angles; // ENG [all], NET [all]
vec3_t oldangles; // ENG [all], NET [all]
vec3_t avelocity; // angular velocity (degrees per second)
vec3_t punchangle; // NET [player], auto-decaying view angle adjustment
vec3_t viewangles; // NET [player], viewing angle (old name was v_angle)

View File

@ -148,7 +148,7 @@ byte CL_GetMouthOpen( int entityIndex )
return ed->pvClientData->mouth.open;
}
studioframe_t *CL_GetStudioFrame( int entityIndex )
lerpframe_t *CL_GetLerpFrame( int entityIndex )
{
edict_t *pEnt = CL_GetEdictByIndex( entityIndex );
@ -793,7 +793,7 @@ void CL_InitWorld( void )
}
// clear viewmodel prevstate
Mem_Set( &clgame.viewent.pvClientData->frame, 0, sizeof( studioframe_t ));
Mem_Set( &clgame.viewent.pvClientData->frame, 0, sizeof( lerpframe_t ));
}
void CL_InitEdicts( void )

View File

@ -39,7 +39,7 @@ int CL_AddTempEntity( TEMPENTITY *pTemp, shader_t customShader )
if( type == mod_studio || type == mod_sprite )
{
// alloc engine data to holds lerping values for studiomdls and sprites
pTemp->pvEngineData = Mem_Alloc( cls.mempool, sizeof( studioframe_t ));
pTemp->pvEngineData = Mem_Alloc( cls.mempool, sizeof( lerpframe_t ));
}
else
{

View File

@ -173,7 +173,7 @@ struct cl_priv_s
entity_state_t current;
entity_state_t prev; // will always be valid, but might just be a copy of current
studioframe_t frame; // holds the studio values for right lerping
lerpframe_t frame; // holds the studio values for right lerping
// studiomodels attachments
vec3_t origin[MAXSTUDIOATTACHMENTS];

View File

@ -224,7 +224,7 @@ bool CL_GetAttachment( int entityIndex, int number, vec3_t origin, vec3_t angles
bool CL_SetAttachment( int entityIndex, int number, vec3_t origin, vec3_t angles );
void CL_StudioEvent( dstudioevent_t *event, edict_t *ent );
bool CL_GetComment( const char *demoname, char *comment );
studioframe_t *CL_GetStudioFrame( int entityIndex );
lerpframe_t *CL_GetLerpFrame( int entityIndex );
edict_t *CL_GetEdictByIndex( int index );
edict_t *CL_GetLocalPlayer( void );
int CL_GetMaxClients( void );

View File

@ -174,7 +174,7 @@ bool Host_InitRender( void )
ri.GetAttachment = CL_GetAttachment;
ri.SetAttachment = CL_SetAttachment;
ri.GetClientEdict = CL_GetEdictByIndex;
ri.GetStudioFrame = CL_GetStudioFrame;
ri.GetLerpFrame = CL_GetLerpFrame;
ri.GetMouthOpen = CL_GetMouthOpen;
ri.GetLocalPlayer = CL_GetLocalPlayer;
ri.GetMaxClients = CL_GetMaxClients;

View File

@ -60,37 +60,48 @@ typedef struct
vec3_t normal;
} fragment_t;
// hold values that needs for right studio lerping
typedef struct
{
float frame;
float animtime;
int sequence;
float sequencetime;
float animtime; // curstate.animtime
int sequence; // curstate.sequence
float frame; // curstate.frame
vec3_t origin; // curstate.origin
vec3_t angles; // curstate.angles
byte blending[16]; // curstate.blending
byte controller[16]; // curstate.controller
} currentvars_t;
typedef struct
{
float animtime; // latched.prevanimtime
float sequencetime; // latechd.prevsequencetime
byte seqblending[16]; // blending between sequence when it's changed
vec3_t origin; // latched.prevorigin
vec3_t angles; // latched.prevangles
int sequence; // latched.prevsequence
float frame; // latched.prevframe
byte controller[16]; // latched.prevcontroller
byte blending[16]; // latched.prevblending
} latchedvars_t;
// hold values that needs for right studio and sprite lerping
typedef struct
{
currentvars_t curstate;
latchedvars_t latched;
// CLIENT SPECIFIC
vec3_t gaitorigin; // client oldorigin used to calc velocity
float gaitframe; // client->frame + yaw
float gaityaw; // local value
vec3_t gaitorigin; // client oldorigin used to calc velocity
float gaitframe; // client->frame + yaw
float gaityaw; // local value
// EF_ANIMATE stuff
int m_fSequenceLoops; // sequence is looped
int m_fSequenceFinished; // sequence is finished
float m_flFrameRate; // looped sequence framerate
float m_flGroundSpeed; // looped sequence ground speed (movement)
float m_flLastEventCheck; // last time when event is checked
float curanimtime; // HACKHACK current animtime
float curframe; // HACKHACK current frame
int cursequence; // HACKHACK current sequence
byte curblending[16]; // HACKHACK current blending
byte curcontroller[16]; // HACKHACL current blending
byte blending[16]; // previous blending values
byte controller[16]; // previous controller values
byte seqblending[16]; // blending between sequence when it's changed
} studioframe_t;
int m_fSequenceLoops; // sequence is looped
int m_fSequenceFinished;// sequence is finished
float m_flFrameRate; // looped sequence framerate
float m_flGroundSpeed; // looped sequence ground speed (movement)
float m_flLastEventCheck; // last time when event is checked
} lerpframe_t;
typedef struct
{
@ -204,7 +215,7 @@ typedef struct render_imp_s
bool (*GetAttachment)( int entityIndex, int number, vec3_t origin, vec3_t angles );
bool (*SetAttachment)( int entityIndex, int number, vec3_t origin, vec3_t angles );
edict_t *(*GetClientEdict)( int index );
studioframe_t *(*GetStudioFrame)( int entityIndex );
lerpframe_t *(*GetLerpFrame)( int entityIndex );
byte (*GetMouthOpen)( int entityIndex );
edict_t *(*GetLocalPlayer)( void );
int (*GetMaxClients)( void );

View File

@ -30,7 +30,6 @@ TYPEDESCRIPTION gEntvarsDescription[] =
DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( oldangles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( viewangles, FIELD_VECTOR ),

View File

@ -458,7 +458,6 @@ TYPEDESCRIPTION gEntvarsDescription[] =
DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( oldangles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( viewangles, FIELD_VECTOR ),

View File

@ -215,8 +215,7 @@ typedef struct ref_entity_s
struct ref_model_s *model; // opaque type outside refresh
struct ref_entity_s *parent; // link to parent entity (FOLLOW or weaponmodel)
studioframe_t *prev; // previous frame values for lerping
lerpframe_t *lerp; // pointer to client entity lerpingdata (holds two frames)
float framerate; // custom framerate
float frame;

View File

@ -722,7 +722,7 @@ static void R_AddSpriteModelToList( ref_entity_t *e )
if( R_SpriteOccluded( e )) return;
frame = R_GetSpriteFrame( e->model, e->prev->curframe, e->angles[YAW] );
frame = R_GetSpriteFrame( e->model, e->lerp->curstate.frame, e->angles[YAW] );
if( e->customShader ) shader = e->customShader;
else shader = &r_shaders[frame->shader];
@ -2348,11 +2348,11 @@ bool R_AddGenericEntity( edict_t *pRefEntity, ref_entity_t *refent )
break;
}
refent->prev = ri.GetStudioFrame( refent->index ); // setup prevframe data
refent->lerp = ri.GetLerpFrame( refent->index ); // get pointer to lerping frame data
if( refent->prev == NULL )
if( refent->lerp == NULL )
{
MsgDev( D_ERROR, "Rejected entity %i (model %s) -- no prevframe data\n", refent->index, refent->model->name );
MsgDev( D_ERROR, "Rejected entity %i (model %s) -- no lerpframe data\n", refent->index, refent->model->name );
return false;
}
@ -2372,9 +2372,9 @@ bool R_AddGenericEntity( edict_t *pRefEntity, ref_entity_t *refent )
{
float numframes = ((msprite_t *)refent->model->extradata)->numframes;
refent->prev->curframe += (pRefEntity->v.framerate * RI.refdef.frametime);
if( refent->prev->curframe > numframes && numframes > 0 )
refent->prev->curframe = fmod( refent->prev->curframe, numframes );
refent->lerp->curstate.frame += (pRefEntity->v.framerate * RI.refdef.frametime);
if( refent->lerp->curstate.frame > numframes && numframes > 0 )
refent->lerp->curstate.frame = fmod( refent->lerp->curstate.frame, numframes );
}
break;
case mod_studio:
@ -2385,16 +2385,10 @@ bool R_AddGenericEntity( edict_t *pRefEntity, ref_entity_t *refent )
}
else
{
refent->prev->frame = refent->prev->curframe; // save oldframe
refent->prev->curframe = pRefEntity->v.frame;
refent->lerp->latched.frame = refent->lerp->curstate.frame; // save oldframe
refent->lerp->curstate.frame = pRefEntity->v.frame;
}
if( refent->ent_type == ED_MOVER || refent->ent_type == ED_BSPBRUSH )
{
VectorNormalize2( pRefEntity->v.movedir, refent->movedir );
}
else VectorClear( refent->movedir );
// calculate angles
if( refent->flags & EF_ROTATE )
{
@ -2408,6 +2402,20 @@ bool R_AddGenericEntity( edict_t *pRefEntity, ref_entity_t *refent )
Matrix3x3_FromAngles( refent->angles, refent->axis );
VectorClear( refent->origin2 );
if( refent->ent_type == ED_CLIENT )
{
refent->gaitsequence = pRefEntity->v.gaitsequence;
refent->flags |= EF_OCCLUSIONTEST;
refent->lightingOrigin[2] += refent->model->maxs[2] - 2; // drop shadow to floor
}
else refent->gaitsequence = 0;
if( refent->ent_type == ED_MOVER || refent->ent_type == ED_BSPBRUSH )
{
VectorNormalize2( pRefEntity->v.movedir, refent->movedir );
}
else VectorClear( refent->movedir );
if( refent->ent_type == ED_VIEWMODEL )
{
if( r_lefthand->integer == 1 )
@ -2425,14 +2433,6 @@ bool R_AddGenericEntity( edict_t *pRefEntity, ref_entity_t *refent )
refent->extradata = NULL;
}
if( refent->ent_type == ED_CLIENT )
{
refent->gaitsequence = pRefEntity->v.gaitsequence;
refent->flags |= EF_OCCLUSIONTEST;
refent->lightingOrigin[2] += refent->model->maxs[2] - 2; // drop shadow to floor
}
else refent->gaitsequence = 0;
// because entity without models never added to scene
if( !refent->ent_type )
{
@ -2538,7 +2538,7 @@ bool R_AddEntityToScene( edict_t *pRefEntity, int ed_type, shader_t customShader
refent->movetype = pRefEntity->v.movetype;
refent->framerate = pRefEntity->v.framerate;
refent->parent = NULL;
refent->prev = NULL;
refent->lerp = NULL;
if( pRefEntity->v.rendermode == kRenderGlow && !pRefEntity->v.renderfx )
refent->flags |= EF_OCCLUSIONTEST;
@ -2637,7 +2637,7 @@ bool R_AddTeEntToScene( TEMPENTITY *pTempEntity, int ed_type, shader_t customSha
refent->flags = EF_NOSHADOW;
refent->gaitsequence = 0;
refent->parent = NULL;
refent->prev = NULL;
refent->lerp = NULL;
refent->renderamt = R_ComputeFxBlend( refent );
@ -2665,11 +2665,11 @@ bool R_AddTeEntToScene( TEMPENTITY *pTempEntity, int ed_type, shader_t customSha
break;
}
refent->prev = pTempEntity->pvEngineData; // setup prevframe data
refent->lerp = pTempEntity->pvEngineData; // setup lerpframe data
if( refent->prev == NULL )
if( refent->lerp == NULL )
{
MsgDev( D_ERROR, "Rejected temp entity (model %s) -- no prevframe data\n", refent->model->name );
MsgDev( D_ERROR, "Rejected temp entity (model %s) -- no lerpframe data\n", refent->model->name );
return false;
}
@ -2680,8 +2680,8 @@ bool R_AddTeEntToScene( TEMPENTITY *pTempEntity, int ed_type, shader_t customSha
refent->rtype = RT_MODEL;
refent->prev->frame = refent->prev->curframe; // save oldframe
refent->prev->curframe = pTempEntity->m_flFrame;
refent->lerp->latched.frame = refent->lerp->curstate.frame; // save oldframe
refent->lerp->curstate.frame = pTempEntity->m_flFrame;
// setup light origin
if( refent->model ) VectorAverage( refent->model->mins, refent->model->maxs, center );

View File

@ -325,7 +325,7 @@ float R_GetSpriteFrameInterpolant( ref_entity_t *ent, mspriteframe_t **oldframe,
int m_fDoInterp;
psprite = ent->model->extradata;
frame = (int)ent->prev->curframe;
frame = (int)ent->lerp->curstate.frame;
lerpFrac = 1.0f;
// misc info
@ -343,49 +343,49 @@ float R_GetSpriteFrameInterpolant( ref_entity_t *ent, mspriteframe_t **oldframe,
{
if( m_fDoInterp )
{
if( ent->prev->sequence >= psprite->numframes || psprite->frames[ent->prev->sequence].type != FRAME_SINGLE )
if( ent->lerp->latched.sequence >= psprite->numframes || psprite->frames[ent->lerp->latched.sequence].type != FRAME_SINGLE )
{
// this can be happens when rendering switched between single and angled frames
// or change model on replace delta-entity
ent->prev->sequence = ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 1.0f;
}
if( ent->prev->curanimtime < RI.refdef.time )
if( ent->lerp->curstate.animtime < RI.refdef.time )
{
if( frame != ent->prev->cursequence )
if( frame != ent->lerp->curstate.sequence )
{
ent->prev->sequence = ent->prev->cursequence;
ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence;
ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 0.0f;
}
else lerpFrac = (RI.refdef.time - ent->prev->curanimtime) * ent->framerate;
else lerpFrac = (RI.refdef.time - ent->lerp->curstate.animtime) * ent->framerate;
}
else
{
ent->prev->sequence = ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 0.0f;
}
}
else
{
ent->prev->sequence = ent->prev->cursequence = frame;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
lerpFrac = 1.0f;
}
if( ent->prev->sequence >= psprite->numframes )
if( ent->lerp->latched.sequence >= psprite->numframes )
{
// reset interpolation on change model
ent->prev->sequence = ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 0.0f;
}
// get the interpolated frames
if( oldframe ) *oldframe = psprite->frames[ent->prev->sequence].frameptr;
if( oldframe ) *oldframe = psprite->frames[ent->lerp->latched.sequence].frameptr;
if( curframe ) *curframe = psprite->frames[frame].frameptr;
}
else if( psprite->frames[frame].type == FRAME_GROUP )
@ -429,40 +429,40 @@ float R_GetSpriteFrameInterpolant( ref_entity_t *ent, mspriteframe_t **oldframe,
if( m_fDoInterp )
{
if( ent->prev->sequence >= psprite->numframes || psprite->frames[ent->prev->sequence].type != FRAME_ANGLED )
if( ent->lerp->latched.sequence >= psprite->numframes || psprite->frames[ent->lerp->latched.sequence].type != FRAME_ANGLED )
{
// this can be happens when rendering switched between single and angled frames
// or change model on replace delta-entity
ent->prev->sequence = ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 1.0f;
}
if( ent->prev->curanimtime < RI.refdef.time )
if( ent->lerp->curstate.animtime < RI.refdef.time )
{
if( frame != ent->prev->cursequence )
if( frame != ent->lerp->curstate.sequence )
{
ent->prev->sequence = ent->prev->cursequence;
ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence;
ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 0.0f;
}
else lerpFrac = (RI.refdef.time - ent->prev->curanimtime) * ent->framerate;
else lerpFrac = (RI.refdef.time - ent->lerp->curstate.animtime) * ent->framerate;
}
else
{
ent->prev->sequence = ent->prev->cursequence = frame;
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
ent->lerp->curstate.animtime = RI.refdef.time;
lerpFrac = 0.0f;
}
}
else
{
ent->prev->sequence = ent->prev->cursequence = frame;
ent->lerp->latched.sequence = ent->lerp->curstate.sequence = frame;
lerpFrac = 1.0f;
}
pspritegroup = (mspritegroup_t *)psprite->frames[ent->prev->sequence].frameptr;
pspritegroup = (mspritegroup_t *)psprite->frames[ent->lerp->latched.sequence].frameptr;
if( oldframe ) *oldframe = pspritegroup->frames[angleframe];
pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;
@ -566,7 +566,7 @@ void R_DrawSpriteModel( const meshbuffer_t *mb )
case kRenderNormal:
case kRenderTransColor:
case kRenderTransAlpha:
frame = oldframe = R_GetSpriteFrame( e->model, e->prev->curframe, e->angles[YAW] );
frame = oldframe = R_GetSpriteFrame( e->model, e->lerp->curstate.frame, e->angles[YAW] );
break;
case kRenderTransTexture:
case kRenderTransAdd:

View File

@ -62,7 +62,7 @@ typedef struct studioverts_s
typedef struct studiovars_s
{
studioframe_t *prev; // duplcate e->prev for consistency
lerpframe_t *lerp; // duplicate e->lerp pointer for consistency
// cached values, valid only for CURRENT frame
char bonenames[MAXSTUDIOBONES][32];// used for attached entities
@ -119,50 +119,50 @@ void R_StudioAllocTentExtradata( TEMPENTITY *in, ref_entity_t *e )
if( !e->mempool ) e->mempool = Mem_AllocPool( va( "TempEntity Pool %i", e - r_entities ));
if( !e->extradata ) e->extradata = (void *)Mem_Alloc( e->mempool, sizeof( studiovars_t ));
studio = (studiovars_t *)e->extradata;
studio->prev = e->prev;
studio->lerp = e->lerp;
// any stuidio model MUST have previous data for lerping
Com_Assert( studio->prev == NULL );
// any stuidio model MUST have lerpframe data for lerping
Com_Assert( studio->lerp == NULL );
// copy controllers
for( i = 0; i < MAXSTUDIOCONTROLLERS; i++ )
{
studio->prev->controller[i] = studio->prev->curcontroller[i];
studio->prev->curcontroller[i] = 0x7F; // tempents doesn't have bonecontrollers
studio->lerp->latched.controller[i] = studio->lerp->curstate.controller[i];
studio->lerp->curstate.controller[i] = 0x7F; // tempents doesn't have bonecontrollers
}
// copy blends
for( i = 0; i < MAXSTUDIOBLENDS; i++ )
{
studio->prev->blending[i] = studio->prev->curblending[i];
studio->prev->curblending[i] = 0x7F; // tempents doesn't have blendings
studio->lerp->latched.blending[i] = studio->lerp->curstate.blending[i];
studio->lerp->curstate.blending[i] = 0x7F; // tempents doesn't have blendings
}
// sequence has changed, hold the previous sequence info
if( in->m_iSequence != e->prev->cursequence )
if( in->m_iSequence != studio->lerp->curstate.sequence )
{
studio->prev->sequencetime = e->prev->animtime + 0.01f;
studio->prev->sequence = e->prev->cursequence;
studio->lerp->latched.sequencetime = e->lerp->latched.animtime + 0.01f;
e->lerp->latched.sequence = studio->lerp->curstate.sequence;
// save current blendings
for( i = 0; i < MAXSTUDIOBLENDS; i++ )
studio->prev->blending[i] = studio->prev->curblending[i];
studio->lerp->latched.blending[i] = studio->lerp->curstate.blending[i];
}
if( in->flags & FTENT_SPRANIMATE )
{
if( in->m_flFrame == -1 )
{
in->m_flFrame = e->prev->curframe = 0;
e->prev->cursequence = in->m_iSequence;
in->m_flFrame = e->lerp->curstate.frame = 0;
studio->lerp->curstate.sequence = in->m_iSequence;
R_StudioResetSequenceInfo( e );
}
else
{
if( !studio->prev->m_fSequenceFinished )
if( !studio->lerp->m_fSequenceFinished )
R_StudioFrameAdvance( e, 0 );
if( studio->prev->m_fSequenceFinished )
if( studio->lerp->m_fSequenceFinished )
{
if( in->flags & FTENT_SPRANIMATELOOP )
in->m_flFrame = -1;
@ -171,15 +171,21 @@ void R_StudioAllocTentExtradata( TEMPENTITY *in, ref_entity_t *e )
else
{
// copy current frame back to let user grab it on a client-side
in->m_flFrame = e->prev->curframe;
in->m_flFrame = e->lerp->curstate.frame;
}
}
}
else
{
e->prev->cursequence = in->m_iSequence;
e->prev->animtime = e->prev->curanimtime; // must be update each frame!
e->prev->curanimtime = in->m_flFrameMax; // HACKHACK: used m_flFrameMax as animtime
studio->lerp->curstate.sequence = in->m_iSequence;
e->lerp->latched.animtime = e->lerp->curstate.animtime; // must be update each frame!
e->lerp->curstate.animtime = in->m_flFrameMax; // HACKHACK: used m_flFrameMax as animtime
// push position and angles
VectorCopy( e->lerp->curstate.origin, e->lerp->latched.origin );
VectorCopy( in->origin, e->lerp->curstate.origin );
VectorCopy( e->lerp->curstate.angles, e->lerp->latched.angles );
VectorCopy( in->angles, e->lerp->curstate.angles );
}
if( studio->numbones != numbones )
@ -221,67 +227,81 @@ void R_StudioAllocExtradata( edict_t *in, ref_entity_t *e )
if( !e->mempool ) e->mempool = Mem_AllocPool( va( "Entity Pool %i", e - r_entities ));
if( !e->extradata ) e->extradata = (void *)Mem_Alloc( e->mempool, sizeof( studiovars_t ));
studio = (studiovars_t *)e->extradata;
studio->prev = e->prev;
studio->lerp = e->lerp;
// any stuidio model MUST have previous data for lerping
Com_Assert( studio->prev == NULL );
Com_Assert( studio->lerp == NULL );
// copy controllers
for( i = 0; i < MAXSTUDIOCONTROLLERS; i++ )
{
studio->prev->controller[i] = studio->prev->curcontroller[i];
studio->prev->curcontroller[i] = in->v.controller[i];
studio->lerp->latched.controller[i] = studio->lerp->curstate.controller[i];
studio->lerp->curstate.controller[i] = in->v.controller[i];
}
// copy blends
for( i = 0; i < MAXSTUDIOBLENDS; i++ )
{
studio->prev->blending[i] = studio->prev->curblending[i];
studio->prev->curblending[i] = in->v.blending[i];
studio->lerp->latched.blending[i] = studio->lerp->curstate.blending[i];
studio->lerp->curstate.blending[i] = in->v.blending[i];
}
// sequence has changed, hold the previous sequence info
if( in->v.sequence != e->prev->cursequence )
if( in->v.sequence != studio->lerp->curstate.sequence )
{
studio->prev->sequencetime = e->prev->animtime + 0.01f;
studio->prev->sequence = e->prev->cursequence;
studio->lerp->latched.sequencetime = e->lerp->latched.animtime + 0.01f;
e->lerp->latched.sequence = studio->lerp->curstate.sequence;
e->lerp->curstate.sequence = in->v.sequence;
// save current blendings
for( i = 0; i < MAXSTUDIOBLENDS; i++ )
studio->prev->blending[i] = studio->prev->curblending[i];
studio->lerp->latched.blending[i] = studio->lerp->curstate.blending[i];
}
if( e->flags & EF_ANIMATE )
{
if( in->v.frame == -1 )
{
in->v.frame = e->prev->curframe = 0;
e->prev->cursequence = in->v.sequence;
in->v.frame = e->lerp->curstate.frame = 0;
studio->lerp->curstate.sequence = in->v.sequence;
R_StudioResetSequenceInfo( e );
}
else
{
if( !studio->prev->m_fSequenceFinished )
if( !studio->lerp->m_fSequenceFinished )
R_StudioFrameAdvance( e, 0 );
if( studio->prev->m_fSequenceFinished )
if( studio->lerp->m_fSequenceFinished )
{
if( studio->prev->m_fSequenceLoops )
if( studio->lerp->m_fSequenceLoops )
in->v.frame = -1;
// hold at last frame
}
else
{
// copy current frame back to let user grab it on a client-side
in->v.frame = e->prev->curframe;
in->v.frame = e->lerp->curstate.frame;
}
}
}
else
{
e->prev->cursequence = in->v.sequence;
e->prev->animtime = e->prev->curanimtime; // must be update each frame!
e->prev->curanimtime = in->v.animtime;
if( in->v.animtime != e->lerp->curstate.animtime )
{
// client got new packet, shuffle animtimes
e->lerp->latched.animtime = e->lerp->curstate.animtime;
e->lerp->curstate.animtime = in->v.animtime;
}
if( !VectorCompare( in->v.origin, e->lerp->curstate.origin ))
{
// push position and angles
VectorCopy( e->lerp->curstate.origin, e->lerp->latched.origin );
VectorCopy( in->v.origin, e->lerp->curstate.origin );
}
VectorCopy( e->lerp->curstate.angles, e->lerp->latched.angles );
VectorCopy( in->v.angles, e->lerp->curstate.angles );
}
if( studio->numbones != numbones )
@ -390,7 +410,7 @@ void R_StudioModelBBox( ref_entity_t *e, vec3_t mins, vec3_t maxs )
hdr = ((mstudiomodel_t *)e->model->extradata)->phdr;
if( !hdr ) return;
R_StudioExtractBbox( hdr, e->prev->cursequence, mins, maxs );
R_StudioExtractBbox( hdr, e->lerp->curstate.sequence, mins, maxs );
}
/*
@ -637,10 +657,10 @@ float R_StudioSequenceDuration( dstudiohdr_t *hdr, ref_entity_t *ent )
{
dstudioseqdesc_t *pseqdesc;
if( !hdr || ent->prev->cursequence >= hdr->numseq )
if( !hdr || ent->lerp->curstate.sequence >= hdr->numseq )
return 0.0f;
pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + ent->prev->cursequence;
pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + ent->lerp->curstate.sequence;
return pseqdesc->numframes / pseqdesc->fps;
}
@ -648,10 +668,10 @@ int R_StudioGetSequenceFlags( dstudiohdr_t *hdr, ref_entity_t *ent )
{
dstudioseqdesc_t *pseqdesc;
if( !hdr || ent->prev->cursequence >= hdr->numseq )
if( !hdr || ent->lerp->curstate.sequence >= hdr->numseq )
return 0;
pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + (int)ent->prev->cursequence;
pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + (int)ent->lerp->curstate.sequence;
return pseqdesc->flags;
}
@ -659,14 +679,14 @@ void R_StuioGetSequenceInfo( dstudiohdr_t *hdr, ref_entity_t *ent, float *pflFra
{
dstudioseqdesc_t *pseqdesc;
if( !hdr || ent->prev->cursequence >= hdr->numseq )
if( !hdr || ent->lerp->curstate.sequence >= hdr->numseq )
{
*pflFrameRate = 0.0;
*pflGroundSpeed = 0.0;
return;
}
pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + ent->prev->cursequence;
pseqdesc = (dstudioseqdesc_t *)((byte *)hdr + hdr->seqindex) + ent->lerp->curstate.sequence;
if( pseqdesc->numframes > 1 )
{
@ -690,24 +710,26 @@ float R_StudioFrameAdvance( ref_entity_t *ent, float flInterval )
if( flInterval == 0.0 )
{
flInterval = ( RI.refdef.time - ent->prev->curanimtime );
flInterval = ( RI.refdef.time - ent->lerp->curstate.animtime );
if( flInterval <= 0.001 )
{
ent->prev->curanimtime = RI.refdef.time;
ent->lerp->curstate.animtime = RI.refdef.time;
return 0.0;
}
}
if( !ent->prev->curanimtime ) flInterval = 0.0;
ent->prev->curframe += flInterval * pstudio->prev->m_flFrameRate * ent->framerate;
ent->prev->curanimtime = RI.refdef.time;
if( !ent->lerp->curstate.animtime )
flInterval = 0.0;
if( ent->prev->curframe < 0.0 || ent->prev->curframe >= 256.0 )
ent->lerp->curstate.frame += flInterval * pstudio->lerp->m_flFrameRate * ent->framerate;
ent->lerp->curstate.animtime = RI.refdef.time;
if( ent->lerp->curstate.frame < 0.0 || ent->lerp->curstate.frame >= 256.0 )
{
if( pstudio->prev->m_fSequenceLoops )
ent->prev->curframe -= (int)(ent->prev->curframe / 256.0) * 256.0;
else ent->prev->curframe = (ent->prev->curframe < 0.0) ? 0 : 255;
pstudio->prev->m_fSequenceFinished = true;
if( pstudio->lerp->m_fSequenceLoops )
ent->lerp->curstate.frame -= (int)(ent->lerp->curstate.frame / 256.0) * 256.0;
else ent->lerp->curstate.frame = (ent->lerp->curstate.frame < 0.0) ? 0 : 255;
pstudio->lerp->m_fSequenceFinished = true;
}
return flInterval;
}
@ -717,18 +739,18 @@ void R_StudioResetSequenceInfo( ref_entity_t *ent )
dstudiohdr_t *hdr;
studiovars_t *pstudio = (studiovars_t *)ent->extradata;
if( !ent || !ent->prev || !ent->extradata || !ent->model || !ent->model->extradata )
if( !ent || !ent->lerp || !ent->extradata || !ent->model || !ent->model->extradata )
return;
hdr = ((mstudiomodel_t *)ent->model->extradata)->phdr;
if( !hdr ) return;
R_StuioGetSequenceInfo( hdr, ent, &pstudio->prev->m_flFrameRate, &pstudio->prev->m_flGroundSpeed );
pstudio->prev->m_fSequenceLoops = ((R_StudioGetSequenceFlags( hdr, ent ) & STUDIO_LOOPING) != 0 );
ent->prev->animtime = ent->prev->curanimtime;
ent->prev->curanimtime = RI.refdef.time;
pstudio->prev->m_fSequenceFinished = false;
pstudio->prev->m_flLastEventCheck = RI.refdef.time;
R_StuioGetSequenceInfo( hdr, ent, &pstudio->lerp->m_flFrameRate, &pstudio->lerp->m_flGroundSpeed );
pstudio->lerp->m_fSequenceLoops = ((R_StudioGetSequenceFlags( hdr, ent ) & STUDIO_LOOPING) != 0 );
ent->lerp->latched.animtime = ent->lerp->curstate.animtime;
ent->lerp->curstate.animtime = RI.refdef.time;
pstudio->lerp->m_fSequenceFinished = false;
pstudio->lerp->m_flLastEventCheck = RI.refdef.time;
}
int R_StudioGetEvent( ref_entity_t *e, dstudioevent_t *pcurrent, float flStart, float flEnd, int index )
@ -737,7 +759,7 @@ int R_StudioGetEvent( ref_entity_t *e, dstudioevent_t *pcurrent, float flStart,
dstudioevent_t *pevent;
int events = 0;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->prev->cursequence;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence;
pevent = (dstudioevent_t *)((byte *)m_pStudioHeader + pseqdesc->eventindex);
if( pseqdesc->numevents == 0 || index > pseqdesc->numevents )
@ -819,7 +841,7 @@ void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, cons
value = bound( 0.0f, value, 1.0f );
value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
}
// Msg( "%d %d %f : %f\n", RI.currententity->curstate.controller[j], RI.currententity->prev->prevcontroller[j], value, dadt );
// Msg( "%d %d %f : %f\n", RI.currententity->lerp->curstate.controller[j], RI.currententity->lerp->latched.controller[j], value, dadt );
}
switch( pbonecontroller[j].type & STUDIO_TYPES )
@ -943,7 +965,7 @@ void R_StudioCalcBonePosition( int frame, float s, dstudiobone_t *pbone, dstudio
{
panimvalue = (dstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
//if (j == 0) Msg("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s );
//if( j == 0 ) Msg( "%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s );
k = frame;
// debug
@ -1075,9 +1097,9 @@ dstudioanim_t *R_StudioGetAnim( ref_model_t *m_pRefModel, dstudioseqdesc_t *pseq
com.snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
buf = FS_LoadFile( filepath, &filesize );
if( !buf || !filesize ) Host_Error( "R_StudioGetAnim: can't load %s\n", modelpath );
if( !buf || !filesize ) Host_Error( "R_StudioGetAnim: can't load %s\n", filepath );
if( IDSEQGRPHEADER != LittleLong(*(uint *)buf ))
Host_Error( "R_StudioGetAnim: %s is corrpted\n", modelpath );
Host_Error( "R_StudioGetAnim: %s is corrupted\n", filepath );
MsgDev( D_LOAD, "R_StudioGetAnim: %s\n", filepath );
@ -1135,6 +1157,7 @@ StudioSetUpTransform
void R_StudioSetUpTransform( ref_entity_t *e, bool trivial_accept )
{
vec3_t angles, origin;
int i;
if( trivial_accept )
{
@ -1155,6 +1178,65 @@ void R_StudioSetUpTransform( ref_entity_t *e, bool trivial_accept )
VectorCopy( e->origin, origin );
VectorCopy( e->angles, angles );
if( e->movetype == MOVETYPE_STEP )
{
float d, f = 0.0f;
// don't do it if the goalstarttime hasn't updated in a while.
// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
// was increased to 1.0 s., which is 2x the max lag we are accounting for.
if(( RI.refdef.time < e->lerp->curstate.animtime + 1.0f ) && ( e->lerp->curstate.animtime != e->lerp->latched.animtime ))
{
f = ( RI.refdef.time - e->lerp->curstate.animtime ) / ( e->lerp->curstate.animtime - e->lerp->latched.animtime );
//Msg( "%4.2f %.2f %.2f\n", f, e->lerp->curstate.animtime, RI.refdef.time );
}
else Msg( "skip f\n" );
if( m_fDoInterp )
{
// ugly hack to interpolate angle, position.
// current is reached 0.1 seconds after being set
f = f - 1.0f;
}
else
{
f = 0.0f;
}
for( i = 0; i < 3; i++ )
{
origin[i] += ( e->lerp->curstate.origin[i] - e->lerp->latched.origin[i] ) * f;
}
// NOTE: Because multiplayer lag can be relatively large, we don't want to cap f at 1.5 anymore.
// if( f > -1.0 && f < 1.5 ) {}
for( i = 0; i < 3; i++ )
{
float ang1, ang2;
ang1 = e->angles[i];
ang2 = e->lerp->latched.angles[i];
d = ang1 - ang2;
if( d > 180 )
{
d -= 360;
}
else if( d < -180 )
{
d += 360;
}
angles[i] += d * f;
}
//Msg( "%.3f \n", f );
}
else if( e->movetype != MOVETYPE_NONE )
{
VectorCopy( e->angles, angles );
}
if( e->ent_type == ED_CLIENT ) angles[PITCH] = 0; // don't rotate player model, only aim
if( e->ent_type == ED_VIEWMODEL ) angles[PITCH] = -angles[PITCH]; // stupid Half-Life bug
@ -1180,12 +1262,12 @@ StudioEstimateInterpolant
*/
float R_StudioEstimateInterpolant( void )
{
float dadt = 1.0;
float dadt = 1.0f;
if( m_fDoInterp && ( RI.currententity->prev->curanimtime >= RI.currententity->prev->animtime + 0.01 ))
if( m_fDoInterp && ( RI.currententity->lerp->curstate.animtime >= RI.currententity->lerp->latched.animtime + 0.01f ))
{
dadt = (RI.refdef.time - RI.currententity->prev->curanimtime) / 0.1;
if( dadt > 2.0 ) dadt = 2.0;
dadt = ( RI.refdef.time - RI.currententity->lerp->curstate.animtime ) / 0.1f;
if( dadt > 2.0f ) dadt = 2.0f;
}
return dadt;
}
@ -1222,9 +1304,9 @@ void R_StudioCalcRotations( float pos[][3], vec4_t *q, dstudioseqdesc_t *pseqdes
pstudio = RI.currententity->extradata;
Com_Assert( pstudio == NULL );
// Msg("%d %.4f %.4f %.4f %.4f %d\n", RI.currententity->curstate.sequence, m_clTime, RI.currententity->prev->curanimtime, RI.currententity->prev->curframe, f, frame );
// Msg( "%d %.4f %.4f %.4f %.4f %d\n", RI.currententity->lerp->curstate.sequence, RI.refdef.time, RI.currententity->lerp->curstate.animtime, RI.currententity->lerp->curstate.frame, f, frame );
// Msg( "%f %f %f\n", RI.currententity->angles[ROLL], RI.currententity->angles[PITCH], RI.currententity->angles[YAW] );
// Msg("frame %d %d\n", frame1, frame2 );
// Msg( "frame %d %d\n", frame1, frame2 );
dadt = R_StudioEstimateInterpolant();
s = (f - frame);
@ -1233,13 +1315,13 @@ void R_StudioCalcRotations( float pos[][3], vec4_t *q, dstudioseqdesc_t *pseqdes
pbone = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
mouthopen = ri.GetMouthOpen( RI.currententity->index );
R_StudioCalcBoneAdj( dadt, adj, pstudio->prev->curcontroller, pstudio->prev->controller, mouthopen );
R_StudioCalcBoneAdj( dadt, adj, pstudio->lerp->curstate.controller, pstudio->lerp->latched.controller, mouthopen );
for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++)
{
R_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] );
R_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] );
// if( 0 && i == 0 ) Msg("%d %d %d %d\n", RI.currententity->prev->cursequence, frame, j, k );
// if( 0 && i == 0 ) Msg( "%d %d %d %d\n", RI.currententity->lerp->curstate.sequence, frame, j, k );
}
if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f;
@ -1265,13 +1347,13 @@ float R_StudioEstimateFrame( dstudioseqdesc_t *pseqdesc )
if( m_fDoInterp )
{
if( RI.refdef.time < RI.currententity->prev->curanimtime ) dfdt = 0;
else dfdt = (RI.refdef.time - RI.currententity->prev->curanimtime) * RI.currententity->framerate * pseqdesc->fps;
if( RI.refdef.time < RI.currententity->lerp->curstate.animtime ) dfdt = 0;
else dfdt = (RI.refdef.time - RI.currententity->lerp->curstate.animtime) * RI.currententity->framerate * pseqdesc->fps;
}
else dfdt = 0;
if( pseqdesc->numframes <= 1 ) f = 0;
else f = (RI.currententity->prev->curframe * (pseqdesc->numframes - 1)) / 256.0;
else f = (RI.currententity->lerp->curstate.frame * (pseqdesc->numframes - 1)) / 256.0;
f += dfdt;
@ -1321,12 +1403,12 @@ float R_StudioSetupBones( ref_entity_t *e )
return 0.0f;
cl_entity = ri.GetClientEdict( e->index );
if( e->prev->cursequence >= m_pStudioHeader->numseq ) e->prev->cursequence = 0;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->prev->cursequence;
if( e->lerp->curstate.sequence >= m_pStudioHeader->numseq ) e->lerp->curstate.sequence = 0;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence;
f = R_StudioEstimateFrame( pseqdesc );
// if( e->prev->frame > f ) Msg( "%f %f\n", e->prev->frame, f );
// if( e->lerp->curstate.frame > f ) Msg( "%f %f\n", e->lerp->curstate.frame, f );
pstudio = RI.currententity->extradata;
Com_Assert( pstudio == NULL );
@ -1343,7 +1425,7 @@ float R_StudioSetupBones( ref_entity_t *e )
R_StudioCalcRotations( pos2, q2, pseqdesc, panim, f );
dadt = R_StudioEstimateInterpolant();
s = (pstudio->prev->curblending[0] * dadt + pstudio->prev->blending[0] * (1.0 - dadt)) / 255.0;
s = (pstudio->lerp->curstate.blending[0] * dadt + pstudio->lerp->latched.blending[0] * (1.0 - dadt)) / 255.0;
R_StudioSlerpBones( q, pos, q2, pos2, s );
@ -1355,57 +1437,57 @@ float R_StudioSetupBones( ref_entity_t *e )
panim += m_pStudioHeader->numbones;
R_StudioCalcRotations( pos4, q4, pseqdesc, panim, f );
s = (pstudio->prev->curblending[0] * dadt + pstudio->prev->blending[0] * (1.0 - dadt)) / 255.0;
s = (pstudio->lerp->curstate.blending[0] * dadt + pstudio->lerp->latched.blending[0] * (1.0 - dadt)) / 255.0;
R_StudioSlerpBones( q3, pos3, q4, pos4, s );
s = (pstudio->prev->curblending[1] * dadt + pstudio->prev->blending[1] * (1.0 - dadt)) / 255.0;
s = (pstudio->lerp->curstate.blending[1] * dadt + pstudio->lerp->latched.blending[1] * (1.0 - dadt)) / 255.0;
R_StudioSlerpBones( q, pos, q3, pos3, s );
}
}
if( m_fDoInterp && pstudio->prev->sequencetime && ( pstudio->prev->sequencetime + 0.2 > RI.refdef.time) && ( pstudio->prev->sequence < m_pStudioHeader->numseq ))
if( m_fDoInterp && pstudio->lerp->latched.sequencetime && ( pstudio->lerp->latched.sequencetime + 0.2 > RI.refdef.time) && ( pstudio->lerp->latched.sequence < m_pStudioHeader->numseq ))
{
// blend from last sequence
static float pos1b[MAXSTUDIOBONES][3];
static vec4_t q1b[MAXSTUDIOBONES];
float s;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pstudio->prev->sequence;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pstudio->lerp->latched.sequence;
panim = R_StudioGetAnim( RI.currentmodel, pseqdesc );
// clip prevframe
R_StudioCalcRotations( pos1b, q1b, pseqdesc, panim, pstudio->prev->frame );
R_StudioCalcRotations( pos1b, q1b, pseqdesc, panim, pstudio->lerp->latched.frame );
if( pseqdesc->numblends > 1 )
{
panim += m_pStudioHeader->numbones;
R_StudioCalcRotations( pos2, q2, pseqdesc, panim, pstudio->prev->frame );
R_StudioCalcRotations( pos2, q2, pseqdesc, panim, pstudio->lerp->latched.frame );
s = (pstudio->prev->blending[0]) / 255.0;
s = (pstudio->lerp->latched.blending[0]) / 255.0;
R_StudioSlerpBones( q1b, pos1b, q2, pos2, s );
if( pseqdesc->numblends == 4 )
{
panim += m_pStudioHeader->numbones;
R_StudioCalcRotations( pos3, q3, pseqdesc, panim, pstudio->prev->frame );
R_StudioCalcRotations( pos3, q3, pseqdesc, panim, pstudio->lerp->latched.frame );
panim += m_pStudioHeader->numbones;
R_StudioCalcRotations( pos4, q4, pseqdesc, panim, pstudio->prev->frame );
R_StudioCalcRotations( pos4, q4, pseqdesc, panim, pstudio->lerp->latched.frame );
s = (pstudio->prev->blending[0]) / 255.0;
s = (pstudio->lerp->latched.blending[0]) / 255.0;
R_StudioSlerpBones( q3, pos3, q4, pos4, s );
s = (pstudio->prev->blending[1]) / 255.0;
s = (pstudio->lerp->latched.blending[1]) / 255.0;
R_StudioSlerpBones( q1b, pos1b, q3, pos3, s );
}
}
s = 1.0 - (RI.refdef.time - pstudio->prev->sequencetime) / 0.2;
s = 1.0 - (RI.refdef.time - pstudio->lerp->latched.sequencetime) / 0.2;
R_StudioSlerpBones( q, pos, q1b, pos1b, s );
}
else
{
// MsgDev( D_INFO, "prevframe = %4.2f\n", f );
pstudio->prev->frame = f;
// Msg( "prevframe = %4.2f\n", f );
pstudio->lerp->latched.frame = f;
}
pbones = (dstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
@ -1419,7 +1501,7 @@ float R_StudioSetupBones( ref_entity_t *e )
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->gaitsequence;
panim = R_StudioGetAnim( RI.currentmodel, pseqdesc );
R_StudioCalcRotations( pos2, q2, pseqdesc, panim, pstudio->prev->gaitframe );
R_StudioCalcRotations( pos2, q2, pseqdesc, panim, pstudio->lerp->gaitframe );
for( i = 0; i < m_pStudioHeader->numbones; i++ )
{
@ -1471,7 +1553,7 @@ float R_StudioMergeBones( ref_entity_t *e, ref_model_t *m_pSubModel )
{
int i, j;
double f;
int sequence = e->prev->cursequence;
int sequence = e->lerp->curstate.sequence;
dstudiobone_t *pbones;
dstudioseqdesc_t *pseqdesc;
dstudioanim_t *panim;
@ -1497,7 +1579,7 @@ float R_StudioMergeBones( ref_entity_t *e, ref_model_t *m_pSubModel )
f = R_StudioEstimateFrame( pseqdesc );
// if( e->prev->frame > f ) Msg("%f %f\n", e->prev->frame, f );
// if( e->lerp->curstate.frame > f ) Msg( "%f %f\n", e->prev->frame, f );
panim = R_StudioGetAnim( m_pSubModel, pseqdesc );
R_StudioCalcRotations( pos, q, pseqdesc, panim, f );
@ -1588,7 +1670,7 @@ bool R_StudioComputeBBox( vec3_t bbox[8] )
vec3_t vectors[3];
ref_entity_t *e = RI.currententity;
vec3_t tmp, angles;
int i, seq = RI.currententity->prev->cursequence;
int i, seq = RI.currententity->lerp->curstate.sequence;
if(!R_ExtractBbox( seq, studio_mins, studio_maxs ))
return false;
@ -2035,8 +2117,8 @@ void R_StudioEstimateGait( ref_entity_t *e, edict_t *pplayer )
// VectorAdd( pplayer->v.velocity, pplayer->v.prediction_error, est_velocity );
if( m_fGaitEstimation )
{
VectorSubtract( e->origin, pstudio->prev->gaitorigin, est_velocity );
VectorCopy( e->origin, pstudio->prev->gaitorigin );
VectorSubtract( e->origin, pstudio->lerp->gaitorigin, est_velocity );
VectorCopy( e->origin, pstudio->lerp->gaitorigin );
m_flGaitMovement = VectorLength( est_velocity );
if( dt <= 0 || m_flGaitMovement / dt < 5 )
@ -2054,7 +2136,7 @@ void R_StudioEstimateGait( ref_entity_t *e, edict_t *pplayer )
if( est_velocity[1] == 0 && est_velocity[0] == 0 )
{
float flYawDiff = e->angles[YAW] - pstudio->prev->gaityaw;
float flYawDiff = e->angles[YAW] - pstudio->lerp->gaityaw;
flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
if( flYawDiff > 180 ) flYawDiff -= 360;
@ -2063,15 +2145,15 @@ void R_StudioEstimateGait( ref_entity_t *e, edict_t *pplayer )
if( dt < 0.25 ) flYawDiff *= dt * 4;
else flYawDiff *= dt;
pstudio->prev->gaityaw += flYawDiff;
pstudio->prev->gaityaw = pstudio->prev->gaityaw - (int)(pstudio->prev->gaityaw / 360) * 360;
pstudio->lerp->gaityaw += flYawDiff;
pstudio->lerp->gaityaw = pstudio->lerp->gaityaw - (int)(pstudio->lerp->gaityaw / 360) * 360;
m_flGaitMovement = 0;
}
else
{
pstudio->prev->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
if( pstudio->prev->gaityaw > 180 ) pstudio->prev->gaityaw = 180;
if( pstudio->prev->gaityaw < -180 ) pstudio->prev->gaityaw = -180;
pstudio->lerp->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
if( pstudio->lerp->gaityaw > 180 ) pstudio->lerp->gaityaw = 180;
if( pstudio->lerp->gaityaw < -180 ) pstudio->lerp->gaityaw = -180;
}
}
@ -2088,54 +2170,54 @@ void R_StudioProcessGait( ref_entity_t *e, edict_t *pplayer, studiovars_t *pstud
float dt, flYaw; // view direction relative to movement
int iBlend;
if( e->prev->cursequence >= m_pStudioHeader->numseq )
e->prev->cursequence = 0;
if( e->lerp->curstate.sequence >= m_pStudioHeader->numseq )
e->lerp->curstate.sequence = 0;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->prev->cursequence;
pseqdesc = (dstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence;
R_StudioPlayerBlend( pseqdesc, &iBlend, &e->angles[PITCH] );
pstudio->prev->curblending[0] = iBlend;
pstudio->prev->blending[0] = pstudio->prev->curblending[0];
pstudio->prev->seqblending[0] = pstudio->prev->curblending[0];
pstudio->lerp->curstate.blending[0] = iBlend;
pstudio->lerp->latched.blending[0] = pstudio->lerp->curstate.blending[0];
pstudio->lerp->latched.seqblending[0] = pstudio->lerp->curstate.blending[0];
// MsgDev( D_INFO, "%f %d\n", e->angles[PITCH], pstudio->prev->curblending[0] );
// Msg( "%f %d\n", e->angles[PITCH], pstudio->lerp->curstate.blending[0] );
dt = bound( 0.0f, RI.refdef.frametime, 1.0f );
R_StudioEstimateGait( e, pplayer );
// MsgDev( D_INFO, "%f %f\n", e->angles[YAW], m_pPlayerInfo->gaityaw );
// Msg( "%f %f\n", e->angles[YAW], pstudio->lerp->gaityaw );
// calc side to side turning
flYaw = e->angles[YAW] - pstudio->prev->gaityaw;
flYaw = e->angles[YAW] - pstudio->lerp->gaityaw;
flYaw = flYaw - (int)(flYaw / 360) * 360;
if( flYaw < -180 ) flYaw = flYaw + 360;
if( flYaw > 180 ) flYaw = flYaw - 360;
if( flYaw > 120 )
{
pstudio->prev->gaityaw = pstudio->prev->gaityaw - 180;
pstudio->lerp->gaityaw = pstudio->lerp->gaityaw - 180;
m_flGaitMovement = -m_flGaitMovement;
flYaw = flYaw - 180;
}
else if( flYaw < -120 )
{
pstudio->prev->gaityaw = pstudio->prev->gaityaw + 180;
pstudio->lerp->gaityaw = pstudio->lerp->gaityaw + 180;
m_flGaitMovement = -m_flGaitMovement;
flYaw = flYaw + 180;
}
// adjust torso
pstudio->prev->curcontroller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->prev->curcontroller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->prev->curcontroller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->prev->curcontroller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->prev->controller[0] = pstudio->prev->curcontroller[0];
pstudio->prev->controller[1] = pstudio->prev->curcontroller[1];
pstudio->prev->controller[2] = pstudio->prev->curcontroller[2];
pstudio->prev->controller[3] = pstudio->prev->curcontroller[3];
pstudio->lerp->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->lerp->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->lerp->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->lerp->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
pstudio->lerp->latched.controller[0] = pstudio->lerp->curstate.controller[0];
pstudio->lerp->latched.controller[1] = pstudio->lerp->curstate.controller[1];
pstudio->lerp->latched.controller[2] = pstudio->lerp->curstate.controller[2];
pstudio->lerp->latched.controller[3] = pstudio->lerp->curstate.controller[3];
e->angles[YAW] = pstudio->prev->gaityaw;
e->angles[YAW] = pstudio->lerp->gaityaw;
if( e->angles[YAW] < -0 ) e->angles[YAW] += 360;
if( pplayer->v.gaitsequence >= m_pStudioHeader->numseq )
@ -2146,16 +2228,16 @@ void R_StudioProcessGait( ref_entity_t *e, edict_t *pplayer, studiovars_t *pstud
// calc gait frame
if( pseqdesc->linearmovement[0] > 0 )
{
pstudio->prev->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes;
pstudio->lerp->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes;
}
else
{
pstudio->prev->gaitframe += pseqdesc->fps * dt;
pstudio->lerp->gaitframe += pseqdesc->fps * dt;
}
// do modulo
pstudio->prev->gaitframe = pstudio->prev->gaitframe - (int)(pstudio->prev->gaitframe / pseqdesc->numframes) * pseqdesc->numframes;
if( pstudio->prev->gaitframe < 0 ) pstudio->prev->gaitframe += pseqdesc->numframes;
pstudio->lerp->gaitframe = pstudio->lerp->gaitframe - (int)(pstudio->lerp->gaitframe / pseqdesc->numframes) * pseqdesc->numframes;
if( pstudio->lerp->gaitframe < 0 ) pstudio->lerp->gaitframe += pseqdesc->numframes;
}
static bool R_StudioSetupModel( ref_entity_t *e, ref_model_t *mod )
@ -2173,9 +2255,9 @@ static bool R_StudioSetupModel( ref_entity_t *e, ref_model_t *mod )
// special handle for player model
if( e->ent_type == ED_CLIENT || e->renderfx == kRenderFxDeadPlayer )
{
// MsgDev( D_INFO, "DrawPlayer %d\n", pstudio->blending[0] );
// MsgDev( D_INFO, "DrawPlayer %d %d (%d)\n", r_framecount2, m_pEntity->serialnumber, e->prev->cursequence );
// MsgDev( D_INFO, "Player %.2f %.2f %.2f\n", m_pEntity->v.velocity[0], m_pEntity->v.velocity[1], m_pEntity->v.velocity[2] );
// Msg( "DrawPlayer %d\n", pstudio->lerp->blending[0] );
// Msg( "DrawPlayer %d %d (%d)\n", r_framecount2, m_pEntity->serialnumber, e->lerp->curstate.sequence );
// Msg( "Player %.2f %.2f %.2f\n", m_pEntity->v.velocity[0], m_pEntity->v.velocity[1], m_pEntity->v.velocity[2] );
if( e->renderfx == kRenderFxDeadPlayer )
{
@ -2193,7 +2275,7 @@ static bool R_StudioSetupModel( ref_entity_t *e, ref_model_t *mod )
if( m_pEntity->v.gaitsequence <= 0 )
{
for( i = 0; i < 4; i++ ) // clear torso controllers
pstudio->prev->controller[i] = pstudio->prev->curcontroller[i] = 0x7F;
pstudio->lerp->latched.controller[i] = pstudio->lerp->curstate.controller[i] = 0x7F;
e->gaitsequence = 0; // StudioSetupBones() issuses
R_StudioSetUpTransform ( e, false );
@ -2227,18 +2309,18 @@ static bool R_StudioSetupModel( ref_entity_t *e, ref_model_t *mod )
if( m_pEntity && e->movetype != MOVETYPE_FOLLOW && !RI.refdef.paused && e->m_nCachedFrameCount != r_framecount2 )
{
float flInterval = 0.1f;
float flStart = e->prev->curframe + (pstudio->prev->m_flLastEventCheck - e->prev->curanimtime) * pstudio->prev->m_flFrameRate * e->framerate;
float flEnd = e->prev->curframe + flInterval * pstudio->prev->m_flFrameRate * e->framerate;
float flStart = e->lerp->curstate.frame + (pstudio->lerp->m_flLastEventCheck - e->lerp->curstate.animtime) * pstudio->lerp->m_flFrameRate * e->framerate;
float flEnd = e->lerp->curstate.frame + flInterval * pstudio->lerp->m_flFrameRate * e->framerate;
int index = 0;
dstudioevent_t event;
Mem_Set( &event, 0, sizeof( event ));
R_StudioCalcAttachments( e );
pstudio->prev->m_flLastEventCheck = e->prev->curanimtime + flInterval;
pstudio->prev->m_fSequenceFinished = false;
pstudio->lerp->m_flLastEventCheck = e->lerp->curstate.animtime + flInterval;
pstudio->lerp->m_fSequenceFinished = false;
if( flEnd >= 256.0f || flEnd <= 0.0f )
pstudio->prev->m_fSequenceFinished = true;
pstudio->lerp->m_fSequenceFinished = true;
while(( index = R_StudioGetEvent( e, &event, flStart, flEnd, index )) != 0 )
ri.StudioEvent( &event, m_pEntity );
@ -2420,12 +2502,12 @@ bool R_CullStudioModel( ref_entity_t *e )
{
// cull child entities with parent volume
R_StudioSetupRender( e->parent, e->parent->model );
sequence = e->parent->prev->cursequence;
sequence = e->parent->lerp->curstate.sequence;
}
else
{
R_StudioSetupRender( e, e->model );
sequence = e->prev->cursequence;
sequence = e->lerp->curstate.sequence;
}
if(!R_ExtractBbox( sequence, studio_mins, studio_maxs ))
@ -2491,12 +2573,12 @@ void R_AddStudioModelToList( ref_entity_t *e )
{
// cull child entities with parent volume
R_StudioSetupRender( e->parent, e->parent->model );
sequence = e->parent->prev->cursequence;
sequence = e->parent->lerp->curstate.sequence;
}
else
{
R_StudioSetupRender( e, e->model );
sequence = e->prev->cursequence;
sequence = e->lerp->curstate.sequence;
}
if(!R_ExtractBbox( sequence, studio_mins, studio_maxs )) return; // invalid sequence