/* ======================== CG_InterpolatePlayerState Generates cg.cur_lc->predictedPlayerState by interpolating between cg.snap->player_state and cg.nextFrame->player_state ======================== */ static void CG_InterpolatePlayerState( qboolean grabAngles ) { float f; int i; playerState_t *out; snapshot_t *prev, *next; playerState_t *prevPS, *nextPS; out = &cg.cur_lc->predictedPlayerState; prev = cg.snap; next = cg.nextSnap; *out = *cg.cur_ps; // if we are still allowing local input, short circuit the view angles if ( grabAngles ) { usercmd_t cmd; int cmdNum; cmdNum = trap_GetCurrentCmdNumber(); trap_GetUserCmd( cmdNum, &cmd, cg.cur_localPlayerNum ); PM_UpdateViewAngles( out, &cmd ); } // if the next frame is a teleport, we can't lerp to it if ( cg.nextFrameTeleport ) { return; } if ( !next || next->serverTime <= prev->serverTime ) { return; } if (prev->playerNums[cg.cur_localPlayerNum] == -1 || next->playerNums[cg.cur_localPlayerNum] == -1) { return; } prevPS = &prev->pss[cg.cur_localPlayerNum]; nextPS = &next->pss[cg.cur_localPlayerNum]; f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime ); i = nextPS->bobCycle; if ( i < prevPS->bobCycle ) { i += 256; // handle wraparound } out->bobCycle = prevPS->bobCycle + f * ( i - prevPS->bobCycle ); for ( i = 0 ; i < 3 ; i++ ) { out->origin[i] = prevPS->origin[i] + f * (nextPS->origin[i] - prevPS->origin[i] ); if ( !grabAngles ) { out->viewangles[i] = LerpAngle( prevPS->viewangles[i], nextPS->viewangles[i], f ); } out->velocity[i] = prevPS->velocity[i] + f * (nextPS->velocity[i] - prevPS->velocity[i] ); } }
void GS_TraceCurveLaserBeam( trace_t *trace, vec3_t origin, vec3_t angles, vec3_t blendPoint, int ignore, int timeDelta, void ( *impact )( trace_t *tr, vec3_t dir ) ) { float frac, subdivisions = CURVELASERBEAM_SUBDIVISIONS; float range = (float)GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.timeout; vec3_t from, dir, end; int passthrough = ignore; int i, j; vec3_t tmpangles, blendAngles; assert( trace ); VectorCopy( origin, from ); VectorSubtract( blendPoint, origin, dir ); VecToAngles( dir, blendAngles ); for( i = 1; i <= (int)subdivisions; i++ ) { frac = ( ( range/subdivisions )*(float)i ) / (float)range; for( j = 0; j < 3; j++ ) tmpangles[j] = LerpAngle( angles[j], blendAngles[j], frac ); AngleVectors( tmpangles, dir, NULL, NULL ); VectorMA( origin, range * frac, dir, end ); GS_TraceLaserBeam( trace, from, tmpangles, DistanceFast( from, end ), passthrough, timeDelta, impact ); if( trace->fraction != 1.0f ) break; passthrough = trace->ent; VectorCopy( end, from ); } }
/* ============================= CG_InterpolateEntityPosition ============================= */ static void CG_InterpolateEntityPosition( centity_t* cent ) { float f; // it would be an internal error to find an entity that interpolates without // a snapshot ahead of the current one if ( cg.nextSnap == NULL ) { CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" ); } //CG_Printf("CG_InterpolateEntityPosition: TODO\n"); f = cg.frameInterpolation; // this will linearize a sine or parabolic curve, but it is important // to not extrapolate player positions if more recent data is available //BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current ); //BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next ); const float* current = cent->currentState.origin; const float* next = cent->nextState.origin; cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] ); cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] ); cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] ); //BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current ); //BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next ); current = cent->currentState.angles; next = cent->nextState.angles; cent->lerpAngles[0] = LerpAngle( current[0], next[0], f ); cent->lerpAngles[1] = LerpAngle( current[1], next[1], f ); cent->lerpAngles[2] = LerpAngle( current[2], next[2], f ); // update render entity and/or render light CG_OnEntityOrientationChange( cent ); }
static c4clipedict_t *GClip_GetClipEdictForDeltaTime( int entNum, int deltaTime ) { static int index = 0; static c4clipedict_t clipEnts[8]; static c4clipedict_t *clipent; static c4clipedict_t clipentNewer; // for interpolation c4frame_t *cframe = NULL; unsigned int backTime, cframenum, backframes, i; edict_t *ent = game.edicts + entNum; // pick one of the 8 slots to prevent overwritings clipent = &clipEnts[index]; index = ( index + 1 )&7; if( !entNum || deltaTime >= 0 || !g_antilag->integer ) { // current time entity clipent->r = ent->r; clipent->s = ent->s; return clipent; } if( !ent->r.inuse || ent->r.solid == SOLID_NOT || ( ent->r.solid == SOLID_TRIGGER && !(entNum >= 1 && entNum <= gs.maxclients) ) ) { clipent->r = ent->r; clipent->s = ent->s; return clipent; } // clamp delta time inside the backed up limits backTime = abs( deltaTime ); if( g_antilag_maxtimedelta->integer ) { if( g_antilag_maxtimedelta->integer < 0 ) trap_Cvar_SetValue( "g_antilag_maxtimedelta", abs( g_antilag_maxtimedelta->integer ) ); if( backTime > (unsigned int)g_antilag_maxtimedelta->integer ) backTime = (unsigned int)g_antilag_maxtimedelta->integer; } // find the first snap with timestamp < than realtime - backtime cframenum = sv_collisionFrameNum; for( backframes = 1; backframes < CFRAME_UPDATE_BACKUP && backframes < sv_collisionFrameNum; backframes++ ) // never overpass limits { cframe = &sv_collisionframes[( cframenum-backframes ) & CFRAME_UPDATE_MASK]; // if solid has changed, we can't keep moving backwards if( ent->r.solid != cframe->clipEdicts[entNum].r.solid || ent->r.inuse != cframe->clipEdicts[entNum].r.inuse ) { backframes--; if( backframes == 0 ) { // we can't step back from first cframe = NULL; } else { cframe = &sv_collisionframes[( cframenum-backframes ) & CFRAME_UPDATE_MASK]; } break; } if( game.serverTime >= cframe->timestamp + backTime ) break; } if( !cframe ) { // current time entity clipent->r = ent->r; clipent->s = ent->s; return clipent; } // setup with older for the data that is not interpolated *clipent = cframe->clipEdicts[entNum]; // if we found an older than desired backtime frame, interpolate to find a more precise position. if( game.serverTime > cframe->timestamp+backTime ) { float lerpFrac; if( backframes == 1 ) { // interpolate from 1st backed up to current lerpFrac = (float)( ( game.serverTime - backTime ) - cframe->timestamp ) / (float)( game.serverTime - cframe->timestamp ); clipentNewer.r = ent->r; clipentNewer.s = ent->s; } else { // interpolate between 2 backed up c4frame_t *cframeNewer = &sv_collisionframes[( cframenum-( backframes-1 ) ) & CFRAME_UPDATE_MASK]; lerpFrac = (float)( ( game.serverTime - backTime ) - cframe->timestamp ) / (float)( cframeNewer->timestamp - cframe->timestamp ); clipentNewer = cframeNewer->clipEdicts[entNum]; } //G_Printf( "backTime:%i cframeBackTime:%i backFrames:%i lerfrac:%f\n", backTime, game.serverTime - cframe->timestamp, backframes, lerpFrac ); // interpolate VectorLerp( clipent->s.origin, lerpFrac, clipentNewer.s.origin, clipent->s.origin ); VectorLerp( clipent->r.mins, lerpFrac, clipentNewer.r.mins, clipent->r.mins ); VectorLerp( clipent->r.maxs, lerpFrac, clipentNewer.r.maxs, clipent->r.maxs ); for( i = 0; i < 3; i++ ) clipent->s.angles[i] = LerpAngle( clipent->s.angles[i], clipentNewer.s.angles[i], lerpFrac ); } //G_Printf( "backTime:%i cframeBackTime:%i backFrames:%i\n", backTime, game.serverTime - cframe->timestamp, backframes ); // back time entity return clipent; }
/* ================= G_TimeShiftClient Move a client back to where he was at the specified "time" ================= */ void G_TimeShiftClient( gentity_t *ent, int time ) { int j, k; if ( time > level.time ) { time = level.time; } // find two entries in the origin trail whose times sandwich "time" // assumes no two adjacent trail records have the same timestamp j = k = ent->client->trailHead; do { if ( ent->client->trail[j].time <= time ) break; k = j; j--; if ( j < 0 ) { j = NUM_CLIENT_TRAILS - 1; } } while ( j != ent->client->trailHead ); // if we got past the first iteration above, we've sandwiched (or wrapped) if ( j != k ) { // make sure it doesn't get re-saved if ( ent->client->saved.leveltime != level.time ) { // save the current origin and bounding box VectorCopy( &ent->r.mins, &ent->client->saved.mins ); VectorCopy( &ent->r.maxs, &ent->client->saved.maxs ); VectorCopy( &ent->r.currentOrigin, &ent->client->saved.currentOrigin ); VectorCopy( &ent->r.currentAngles, &ent->client->saved.currentAngles ); ent->client->saved.leveltime = level.time; } // if we haven't wrapped back to the head, we've sandwiched, so // we shift the client's position back to where he was at "time" if ( j != ent->client->trailHead ) { float frac = (float)(ent->client->trail[k].time - time) / (float)(ent->client->trail[k].time - ent->client->trail[j].time); // FOR TESTING ONLY // Com_Printf( "level time: %d, fire time: %d, j time: %d, k time: %d\n", level.time, time, ent->client->trail[j].time, ent->client->trail[k].time ); // interpolate between the two origins to give position at time index "time" TimeShiftLerp( frac, &ent->client->trail[k].currentOrigin, &ent->client->trail[j].currentOrigin, &ent->r.currentOrigin ); ent->r.currentAngles.yaw = LerpAngle( ent->client->trail[k].currentAngles.yaw, ent->r.currentAngles.yaw, frac ); // lerp these too, just for fun (and ducking) TimeShiftLerp( frac, &ent->client->trail[k].mins, &ent->client->trail[j].mins, &ent->r.mins ); TimeShiftLerp( frac, &ent->client->trail[k].maxs, &ent->client->trail[j].maxs, &ent->r.maxs ); // this will recalculate absmin and absmax trap->LinkEntity( (sharedEntity_t *)ent ); } else { // we wrapped, so grab the earliest VectorCopy( &ent->client->trail[k].currentAngles, &ent->r.currentAngles ); VectorCopy( &ent->client->trail[k].currentOrigin, &ent->r.currentOrigin ); VectorCopy( &ent->client->trail[k].mins, &ent->r.mins ); VectorCopy( &ent->client->trail[k].maxs, &ent->r.maxs ); // this will recalculate absmin and absmax trap->LinkEntity( (sharedEntity_t *)ent ); } } }
/* * CG_Democam_CalcView */ static int CG_Democam_CalcView( void ) { int i, viewType; float lerpfrac; vec3_t v; viewType = VIEWDEF_PLAYERVIEW; VectorClear( cam_velocity ); if( currentcam ) { if( !nextcam ) { lerpfrac = 0; } else { lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); } switch( currentcam->type ) { case DEMOCAM_FIRSTPERSON: VectorCopy( cg.view.origin, cam_origin ); VectorCopy( cg.view.angles, cam_angles ); VectorCopy( cg.view.velocity, cam_velocity ); cam_fov = cg.view.fov_y; break; case DEMOCAM_THIRDPERSON: VectorCopy( cg.view.origin, cam_origin ); VectorCopy( cg.view.angles, cam_angles ); VectorCopy( cg.view.velocity, cam_velocity ); cam_fov = cg.view.fov_y; cam_3dPerson = true; break; case DEMOCAM_POSITIONAL: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; VectorCopy( currentcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorCopy( currentcam->angles, cam_angles ); } cam_fov = currentcam->fov; break; case DEMOCAM_PATH_LINEAR: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; VectorCopy( cam_origin, v ); if( !nextcam || nextcam->type == DEMOCAM_FIRSTPERSON || nextcam->type == DEMOCAM_THIRDPERSON ) { CG_Printf( "Warning: CG_DemoCam: path_linear cam without a valid next cam\n" ); VectorCopy( currentcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorCopy( currentcam->angles, cam_angles ); } cam_fov = currentcam->fov; } else { VectorLerp( currentcam->origin, lerpfrac, nextcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { for( i = 0; i < 3; i++ ) cam_angles[i] = LerpAngle( currentcam->angles[i], nextcam->angles[i], lerpfrac ); } cam_fov = (float)currentcam->fov + (float)( nextcam->fov - currentcam->fov ) * lerpfrac; } // set velocity VectorSubtract( cam_origin, v, cam_velocity ); VectorScale( cam_velocity, 1.0f / (float)cg.frameTime, cam_velocity ); break; case DEMOCAM_PATH_SPLINE: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; clamp( lerpfrac, 0, 1 ); VectorCopy( cam_origin, v ); if( !nextcam || nextcam->type == DEMOCAM_FIRSTPERSON || nextcam->type == DEMOCAM_THIRDPERSON ) { CG_Printf( "Warning: CG_DemoCam: path_spline cam without a valid next cam\n" ); VectorCopy( currentcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorCopy( currentcam->angles, cam_angles ); } cam_fov = currentcam->fov; } else { // valid spline path #define VectorHermiteInterp( a, at, b, bt, c, v ) ( ( v )[0] = ( 2 * pow( c, 3 ) - 3 * pow( c, 2 ) + 1 ) * a[0] + ( pow( c, 3 ) - 2 * pow( c, 2 ) + c ) * 2 * at[0] + ( -2 * pow( c, 3 ) + 3 * pow( c, 2 ) ) * b[0] + ( pow( c, 3 ) - pow( c, 2 ) ) * 2 * bt[0], ( v )[1] = ( 2 * pow( c, 3 ) - 3 * pow( c, 2 ) + 1 ) * a[1] + ( pow( c, 3 ) - 2 * pow( c, 2 ) + c ) * 2 * at[1] + ( -2 * pow( c, 3 ) + 3 * pow( c, 2 ) ) * b[1] + ( pow( c, 3 ) - pow( c, 2 ) ) * 2 * bt[1], ( v )[2] = ( 2 * pow( c, 3 ) - 3 * pow( c, 2 ) + 1 ) * a[2] + ( pow( c, 3 ) - 2 * pow( c, 2 ) + c ) * 2 * at[2] + ( -2 * pow( c, 3 ) + 3 * pow( c, 2 ) ) * b[2] + ( pow( c, 3 ) - pow( c, 2 ) ) * 2 * bt[2] ) float lerpspline, A, B, C, n1, n2, n3; cg_democam_t *previouscam = NULL; cg_democam_t *secondnextcam = NULL; if( nextcam ) { secondnextcam = CG_Democam_FindNext( nextcam->timeStamp ); } if( currentcam->timeStamp > 0 ) { previouscam = CG_Democam_FindCurrent( currentcam->timeStamp - 1 ); } if( !previouscam && nextcam && !secondnextcam ) { lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = lerpfrac; } else if( !previouscam && nextcam && secondnextcam ) { n1 = nextcam->timeStamp - currentcam->timeStamp; n2 = secondnextcam->timeStamp - nextcam->timeStamp; A = n1 * ( n1 - n2 ) / ( pow( n1, 2 ) + n1 * n2 - n1 - n2 ); B = ( 2 * n1 * n2 - n1 - n2 ) / ( pow( n1, 2 ) + n1 * n2 - n1 - n2 ); lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = A * pow( lerpfrac, 2 ) + B * lerpfrac; } else if( previouscam && nextcam && !secondnextcam ) { n2 = currentcam->timeStamp - previouscam->timeStamp; n3 = nextcam->timeStamp - currentcam->timeStamp; A = n3 * ( n2 - n3 ) / ( -n2 - n3 + n2 * n3 + pow( n3, 2 ) ); B = -1 / ( -n2 - n3 + n2 * n3 + pow( n3, 2 ) ) * ( n2 + n3 - 2 * pow( n3, 2 ) ); lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = A * pow( lerpfrac, 2 ) + B * lerpfrac; } else if( previouscam && nextcam && secondnextcam ) { n1 = currentcam->timeStamp - previouscam->timeStamp; n2 = nextcam->timeStamp - currentcam->timeStamp; n3 = secondnextcam->timeStamp - nextcam->timeStamp; A = -2 * pow( n2, 2 ) * ( -pow( n2, 2 ) + n1 * n3 ) / ( 2 * n2 * n3 + pow( n2, 3 ) * n3 - 3 * pow( n2, 2 ) * n1 + n1 * pow( n2, 3 ) + 2 * n1 * n2 - 3 * pow( n2, 2 ) * n3 - 3 * pow( n2, 3 ) + 2 * pow( n2, 2 ) + pow( n2, 4 ) + n1 * pow( n2, 2 ) * n3 - 3 * n1 * n2 * n3 + 2 * n1 * n3 ); B = pow( n2, 2 ) * ( -2 * n1 - 3 * pow( n2, 2 ) - n2 * n3 + 2 * n3 + 3 * n1 * n3 + n1 * n2 ) / ( 2 * n2 * n3 + pow( n2, 3 ) * n3 - 3 * pow( n2, 2 ) * n1 + n1 * pow( n2, 3 ) + 2 * n1 * n2 - 3 * pow( n2, 2 ) * n3 - 3 * pow( n2, 3 ) + 2 * pow( n2, 2 ) + pow( n2, 4 ) + n1 * pow( n2, 2 ) * n3 - 3 * n1 * n2 * n3 + 2 * n1 * n3 ); C = -( pow( n2, 2 ) * n1 - 2 * n1 * n2 + 3 * n1 * n2 * n3 - 2 * n1 * n3 - 2 * pow( n2, 4 ) + 3 * pow( n2, 3 ) - 2 * pow( n2, 3 ) * n3 + 5 * pow( n2, 2 ) * n3 - 2 * pow( n2, 2 ) - 2 * n2 * n3 ) / ( 2 * n2 * n3 + pow( n2, 3 ) * n3 - 3 * pow( n2, 2 ) * n1 + n1 * pow( n2, 3 ) + 2 * n1 * n2 - 3 * pow( n2, 2 ) * n3 - 3 * pow( n2, 3 ) + 2 * pow( n2, 2 ) + pow( n2, 4 ) + n1 * pow( n2, 2 ) * n3 - 3 * n1 * n2 * n3 + 2 * n1 * n3 ); lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = A * pow( lerpfrac, 3 ) + B * pow( lerpfrac, 2 ) + C * lerpfrac; } else { lerpfrac = 0; lerpspline = 0; } VectorHermiteInterp( currentcam->origin, currentcam->tangent, nextcam->origin, nextcam->tangent, lerpspline, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorHermiteInterp( currentcam->angles, currentcam->angles_tangent, nextcam->angles, nextcam->angles_tangent, lerpspline, cam_angles ); } cam_fov = (float)currentcam->fov + (float)( nextcam->fov - currentcam->fov ) * lerpfrac; #undef VectorHermiteInterp } // set velocity VectorSubtract( cam_origin, v, cam_velocity ); VectorScale( cam_velocity, 1.0f / (float)cg.frameTime, cam_velocity ); break; case DEMOCAM_ORBITAL: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; cam_fov = currentcam->fov; VectorCopy( cam_origin, v ); if( !currentcam->trackEnt || currentcam->trackEnt >= MAX_EDICTS ) { CG_Printf( "Warning: CG_DemoCam: orbital cam needs a track entity set\n" ); VectorCopy( currentcam->origin, cam_origin ); VectorClear( cam_angles ); VectorClear( cam_velocity ); } else { vec3_t center, forward; struct cmodel_s *cmodel; const float ft = (float)cg.frameTime * 0.001f; // find the trackEnt origin VectorLerp( cg_entities[currentcam->trackEnt].prev.origin, cg.lerpfrac, cg_entities[currentcam->trackEnt].current.origin, center ); // if having a bounding box, look to its center if( ( cmodel = CG_CModelForEntity( currentcam->trackEnt ) ) != NULL ) { vec3_t mins, maxs; trap_CM_InlineModelBounds( cmodel, mins, maxs ); for( i = 0; i < 3; i++ ) center[i] += ( mins[i] + maxs[i] ); } if( !cam_orbital_radius ) { // cam is just started, find distance from cam to trackEnt and keep it as radius VectorSubtract( currentcam->origin, center, forward ); cam_orbital_radius = VectorNormalize( forward ); VecToAngles( forward, cam_orbital_angles ); } for( i = 0; i < 3; i++ ) { cam_orbital_angles[i] += currentcam->angles[i] * ft; cam_orbital_angles[i] = AngleNormalize360( cam_orbital_angles[i] ); } AngleVectors( cam_orbital_angles, forward, NULL, NULL ); VectorMA( center, cam_orbital_radius, forward, cam_origin ); // lookat VectorInverse( forward ); VecToAngles( forward, cam_angles ); } // set velocity VectorSubtract( cam_origin, v, cam_velocity ); VectorScale( cam_velocity, 1.0f / ( cg.frameTime * 1000.0f ), cam_velocity ); break; default: break; } if( currentcam->type != DEMOCAM_ORBITAL ) { VectorClear( cam_orbital_angles ); cam_orbital_radius = 0; } } return viewType; }
/** * @brief G_AdjustSingleClientPosition * @param[in,out] ent * @param[in] time */ static void G_AdjustSingleClientPosition(gentity_t *ent, int time) { int i, j; if (time > level.time) { time = level.time; } // no lerping forward.... if (!G_AntilagSafe(ent)) { return; } // find a pair of markers which bound the requested time i = j = ent->client->topMarker; do { if (ent->client->clientMarkers[i].time <= time) { break; } j = i; i--; if (i < 0) { i = MAX_CLIENT_MARKERS - 1; } } while (i != ent->client->topMarker); if (i == j) // oops, no valid stored markers { return; } // save current position to backup if (ent->client->backupMarker.time != level.time) { VectorCopy(ent->r.currentOrigin, ent->client->backupMarker.origin); VectorCopy(ent->r.mins, ent->client->backupMarker.mins); VectorCopy(ent->r.maxs, ent->client->backupMarker.maxs); // Head, Legs VectorCopy(ent->client->ps.viewangles, ent->client->backupMarker.viewangles); ent->client->backupMarker.eFlags = ent->client->ps.eFlags; ent->client->backupMarker.pm_flags = ent->client->ps.pm_flags; ent->client->backupMarker.viewheight = ent->client->ps.viewheight; ent->client->backupMarker.time = level.time; // Torso Markers ent->client->backupMarker.torsoOldFrameModel = ent->torsoFrame.oldFrameModel; ent->client->backupMarker.torsoFrameModel = ent->torsoFrame.frameModel; ent->client->backupMarker.torsoOldFrame = ent->torsoFrame.oldFrame; ent->client->backupMarker.torsoFrame = ent->torsoFrame.frame; ent->client->backupMarker.torsoOldFrameTime = ent->torsoFrame.oldFrameTime; ent->client->backupMarker.torsoFrameTime = ent->torsoFrame.frameTime; ent->client->backupMarker.torsoYawAngle = ent->torsoFrame.yawAngle; ent->client->backupMarker.torsoPitchAngle = ent->torsoFrame.pitchAngle; ent->client->backupMarker.torsoYawing = ent->torsoFrame.yawing; ent->client->backupMarker.torsoPitching = ent->torsoFrame.pitching; // Legs Markers ent->client->backupMarker.legsOldFrameModel = ent->legsFrame.oldFrameModel; ent->client->backupMarker.legsFrameModel = ent->legsFrame.frameModel; ent->client->backupMarker.legsOldFrame = ent->legsFrame.oldFrame; ent->client->backupMarker.legsFrame = ent->legsFrame.frame; ent->client->backupMarker.legsOldFrameTime = ent->legsFrame.oldFrameTime; ent->client->backupMarker.legsFrameTime = ent->legsFrame.frameTime; ent->client->backupMarker.legsYawAngle = ent->legsFrame.yawAngle; ent->client->backupMarker.legsPitchAngle = ent->legsFrame.pitchAngle; ent->client->backupMarker.legsYawing = ent->legsFrame.yawing; ent->client->backupMarker.legsPitching = ent->legsFrame.pitching; } if (i != ent->client->topMarker) { float frac = (float)(time - ent->client->clientMarkers[i].time) / (float)(ent->client->clientMarkers[j].time - ent->client->clientMarkers[i].time); //LerpPosition(ent->client->clientMarkers[i].origin, ent->client->clientMarkers[j].origin, frac, ent->r.currentOrigin); //LerpPosition(ent->client->clientMarkers[i].mins, ent->client->clientMarkers[j].mins, frac, ent->r.mins); //LerpPosition(ent->client->clientMarkers[i].maxs, ent->client->clientMarkers[j].maxs, frac, ent->r.maxs); // Using TimeShiftLerp since it follows the client exactly meaning less roundoff error TimeShiftLerp( ent->client->clientMarkers[i].origin, ent->client->clientMarkers[j].origin, frac, ent->r.currentOrigin); TimeShiftLerp( ent->client->clientMarkers[i].mins, ent->client->clientMarkers[j].mins, frac, ent->r.mins); TimeShiftLerp( ent->client->clientMarkers[i].maxs, ent->client->clientMarkers[j].maxs, frac, ent->r.maxs); // These are for Head / Legs ent->client->ps.viewangles[0] = LerpAngle( ent->client->clientMarkers[i].viewangles[0], ent->client->clientMarkers[j].viewangles[0], frac); ent->client->ps.viewangles[1] = LerpAngle( ent->client->clientMarkers[i].viewangles[1], ent->client->clientMarkers[j].viewangles[1], frac); ent->client->ps.viewangles[2] = LerpAngle( ent->client->clientMarkers[i].viewangles[2], ent->client->clientMarkers[j].viewangles[2], frac); // Set the ints to the closest ones in time since you can't lerp them. if ((ent->client->clientMarkers[j].time - time) < (time - ent->client->clientMarkers[i].time)) { ent->client->ps.eFlags = ent->client->clientMarkers[j].eFlags; ent->client->ps.pm_flags = ent->client->clientMarkers[j].pm_flags; ent->client->ps.viewheight = ent->client->clientMarkers[j].viewheight; // Torso Markers ent->torsoFrame.oldFrameModel = ent->client->clientMarkers[j].torsoOldFrameModel; ent->torsoFrame.frameModel = ent->client->clientMarkers[j].torsoFrameModel; ent->torsoFrame.oldFrame = ent->client->clientMarkers[j].torsoOldFrame; ent->torsoFrame.frame = ent->client->clientMarkers[j].torsoFrame; ent->torsoFrame.oldFrameTime = ent->client->clientMarkers[j].torsoOldFrameTime; ent->torsoFrame.frameTime = ent->client->clientMarkers[j].torsoFrameTime; ent->torsoFrame.yawAngle = ent->client->clientMarkers[j].torsoYawAngle; ent->torsoFrame.pitchAngle = ent->client->clientMarkers[j].torsoPitchAngle; ent->torsoFrame.yawing = ent->client->clientMarkers[j].torsoYawing; ent->torsoFrame.pitching = ent->client->clientMarkers[j].torsoPitching; // Legs Markers ent->legsFrame.oldFrameModel = ent->client->clientMarkers[j].legsOldFrameModel; ent->legsFrame.frameModel = ent->client->clientMarkers[j].legsFrameModel; ent->legsFrame.oldFrame = ent->client->clientMarkers[j].legsOldFrame; ent->legsFrame.frame = ent->client->clientMarkers[j].legsFrame; ent->legsFrame.oldFrameTime = ent->client->clientMarkers[j].legsOldFrameTime; ent->legsFrame.frameTime = ent->client->clientMarkers[j].legsFrameTime; ent->legsFrame.yawAngle = ent->client->clientMarkers[j].legsYawAngle; ent->legsFrame.pitchAngle = ent->client->clientMarkers[j].legsPitchAngle; ent->legsFrame.yawing = ent->client->clientMarkers[j].legsYawing; ent->legsFrame.pitching = ent->client->clientMarkers[j].legsPitching; // time stamp for BuildHead/Leg ent->timeShiftTime = ent->client->clientMarkers[j].time; } else { ent->client->ps.eFlags = ent->client->clientMarkers[i].eFlags; ent->client->ps.pm_flags = ent->client->clientMarkers[i].pm_flags; ent->client->ps.viewheight = ent->client->clientMarkers[i].viewheight; // Torso Markers ent->torsoFrame.oldFrameModel = ent->client->clientMarkers[i].torsoOldFrameModel; ent->torsoFrame.frameModel = ent->client->clientMarkers[i].torsoFrameModel; ent->torsoFrame.oldFrame = ent->client->clientMarkers[i].torsoOldFrame; ent->torsoFrame.frame = ent->client->clientMarkers[i].torsoFrame; ent->torsoFrame.oldFrameTime = ent->client->clientMarkers[i].torsoOldFrameTime; ent->torsoFrame.frameTime = ent->client->clientMarkers[i].torsoFrameTime; ent->torsoFrame.yawAngle = ent->client->clientMarkers[i].torsoYawAngle; ent->torsoFrame.pitchAngle = ent->client->clientMarkers[i].torsoPitchAngle; ent->torsoFrame.yawing = ent->client->clientMarkers[i].torsoYawing; ent->torsoFrame.pitching = ent->client->clientMarkers[i].torsoPitching; // Legs Markers ent->legsFrame.oldFrameModel = ent->client->clientMarkers[i].legsOldFrameModel; ent->legsFrame.frameModel = ent->client->clientMarkers[i].legsFrameModel; ent->legsFrame.oldFrame = ent->client->clientMarkers[i].legsOldFrame; ent->legsFrame.frame = ent->client->clientMarkers[i].legsFrame; ent->legsFrame.oldFrameTime = ent->client->clientMarkers[i].legsOldFrameTime; ent->legsFrame.frameTime = ent->client->clientMarkers[i].legsFrameTime; ent->legsFrame.yawAngle = ent->client->clientMarkers[i].legsYawAngle; ent->legsFrame.pitchAngle = ent->client->clientMarkers[i].legsPitchAngle; ent->legsFrame.yawing = ent->client->clientMarkers[i].legsYawing; ent->legsFrame.pitching = ent->client->clientMarkers[i].legsPitching; // time stamp for BuildHead/Leg ent->timeShiftTime = ent->client->clientMarkers[i].time; } /* FIXME if ( debugger && debugger->client) { // print some debugging stuff exactly like what the client does // it starts with "Rec:" to let you know it backward-reconciled char msg[2048]; Com_sprintf( msg, sizeof(msg), "print \"^1Rec: time: %d, j: %d, k: %d, origin: %0.2f %0.2f %0.2f\n" "^2frac: %0.4f, origin1: %0.2f %0.2f %0.2f, origin2: %0.2f %0.2f %0.2f\n" "^7level.time: %d, est time: %d, level.time delta: %d, est real ping: %d\n\"", time, ent->client->clientMarkers[i].time, ent->client->clientMarkers[j].time, ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2], frac, ent->client->clientMarkers[i].origin[0], ent->client->clientMarkers[i].origin[1], ent->client->clientMarkers[i].origin[2], ent->client->clientMarkers[j].origin[0], ent->client->clientMarkers[j].origin[1], ent->client->clientMarkers[j].origin[2], level.time, level.time + debugger->client->frameOffset, level.time - time, level.time + debugger->client->frameOffset - time); trap_SendServerCommand( debugger - g_entities, msg ); } */ } else { VectorCopy(ent->client->clientMarkers[j].origin, ent->r.currentOrigin); VectorCopy(ent->client->clientMarkers[j].mins, ent->r.mins); VectorCopy(ent->client->clientMarkers[j].maxs, ent->r.maxs); // BuildHead/Legs uses these VectorCopy(ent->client->clientMarkers[j].viewangles, ent->client->ps.viewangles); ent->client->ps.eFlags = ent->client->clientMarkers[j].eFlags; ent->client->ps.pm_flags = ent->client->clientMarkers[j].pm_flags; ent->client->ps.viewheight = ent->client->clientMarkers[j].viewheight; // Torso Markers ent->torsoFrame.oldFrameModel = ent->client->clientMarkers[j].torsoOldFrameModel; ent->torsoFrame.frameModel = ent->client->clientMarkers[j].torsoFrameModel; ent->torsoFrame.oldFrame = ent->client->clientMarkers[j].torsoOldFrame; ent->torsoFrame.frame = ent->client->clientMarkers[j].torsoFrame; ent->torsoFrame.oldFrameTime = ent->client->clientMarkers[j].torsoOldFrameTime; ent->torsoFrame.frameTime = ent->client->clientMarkers[j].torsoFrameTime; ent->torsoFrame.yawAngle = ent->client->clientMarkers[j].torsoYawAngle; ent->torsoFrame.pitchAngle = ent->client->clientMarkers[j].torsoPitchAngle; ent->torsoFrame.yawing = ent->client->clientMarkers[j].torsoYawing; ent->torsoFrame.pitching = ent->client->clientMarkers[j].torsoPitching; // Legs Markers ent->legsFrame.oldFrameModel = ent->client->clientMarkers[j].legsOldFrameModel; ent->legsFrame.frameModel = ent->client->clientMarkers[j].legsFrameModel; ent->legsFrame.oldFrame = ent->client->clientMarkers[j].legsOldFrame; ent->legsFrame.frame = ent->client->clientMarkers[j].legsFrame; ent->legsFrame.oldFrameTime = ent->client->clientMarkers[j].legsOldFrameTime; ent->legsFrame.frameTime = ent->client->clientMarkers[j].legsFrameTime; ent->legsFrame.yawAngle = ent->client->clientMarkers[j].legsYawAngle; ent->legsFrame.pitchAngle = ent->client->clientMarkers[j].legsPitchAngle; ent->legsFrame.yawing = ent->client->clientMarkers[j].legsYawing; ent->legsFrame.pitching = ent->client->clientMarkers[j].legsPitching; // time stamp for BuildHead/Leg ent->timeShiftTime = ent->client->clientMarkers[j].time; } trap_LinkEntity(ent); }
void G_AdjustSingleClientPosition( gentity_t* ent, int time, gentity_t* debugger) { int i, j; // unlagged analogies: antilag i = unlagged j, antilag j = unlagged k if( time > level.time ) { time = level.time; } // no lerping forward.... You mean extrapolating, not lerping (inter) if(!G_AntilagSafe(ent)) return; // find a pair of markers which bound the requested time i = j = ent->client->topMarker; do { if( ent->client->clientMarkers[i].time <= time ) { break; } j = i; i--; if( i < 0 ) { i = MAX_CLIENT_MARKERS - 1; } } while( i != ent->client->topMarker ); if( i == j ) { // oops, no valid stored markers return; } // josh: from unlagged make sure it doesn't get backed-up twice if ( ent->client->backupMarker.time != level.time ) { VectorCopy(ent->r.currentOrigin, ent->client->backupMarker.origin); VectorCopy(ent->r.mins, ent->client->backupMarker.mins); VectorCopy(ent->r.maxs, ent->client->backupMarker.maxs); //josh: for Head, Legs VectorCopy(ent->client->ps.viewangles, ent->client->backupMarker.viewangles); ent->client->backupMarker.eFlags = ent->client->ps.eFlags; ent->client->backupMarker.pm_flags = ent->client->ps.pm_flags; ent->client->backupMarker.viewheight = ent->client->ps.viewheight; // josh: This was missing, but needed or else no readjustment ent->client->backupMarker.time = level.time; // forty - realistic hitboxes - Torso Markers ent->client->backupMarker.torsoOldFrameModel = ent->torsoFrame.oldFrameModel; ent->client->backupMarker.torsoFrameModel = ent->torsoFrame.frameModel; ent->client->backupMarker.torsoOldFrame = ent->torsoFrame.oldFrame; ent->client->backupMarker.torsoFrame = ent->torsoFrame.frame; ent->client->backupMarker.torsoOldFrameTime = ent->torsoFrame.oldFrameTime; ent->client->backupMarker.torsoFrameTime = ent->torsoFrame.frameTime; ent->client->backupMarker.torsoYawAngle = ent->torsoFrame.yawAngle; ent->client->backupMarker.torsoPitchAngle = ent->torsoFrame.pitchAngle; ent->client->backupMarker.torsoYawing = ent->torsoFrame.yawing; ent->client->backupMarker.torsoPitching = ent->torsoFrame.pitching; // forty - realistic hitboxes - Legs Markers ent->client->backupMarker.legsOldFrameModel = ent->legsFrame.oldFrameModel; ent->client->backupMarker.legsFrameModel = ent->legsFrame.frameModel; ent->client->backupMarker.legsOldFrame = ent->legsFrame.oldFrame; ent->client->backupMarker.legsFrame = ent->legsFrame.frame; ent->client->backupMarker.legsOldFrameTime = ent->legsFrame.oldFrameTime; ent->client->backupMarker.legsFrameTime = ent->legsFrame.frameTime; ent->client->backupMarker.legsYawAngle = ent->legsFrame.yawAngle; ent->client->backupMarker.legsPitchAngle = ent->legsFrame.pitchAngle; ent->client->backupMarker.legsYawing = ent->legsFrame.yawing; ent->client->backupMarker.legsPitching = ent->legsFrame.pitching; } if(i != ent->client->topMarker) { //float frac = ((float)(ent->client->clientMarkers[j].time - time)) / (ent->client->clientMarkers[j].time - ent->client->clientMarkers[i].time); //josh: reversing the order to better match the client and prevent //roundoff error float frac = (float)(time - ent->client->clientMarkers[i].time) / (float)(ent->client->clientMarkers[j].time - ent->client->clientMarkers[i].time); //LerpPosition(ent->client->clientMarkers[i].origin, ent->client->clientMarkers[j].origin, frac, ent->r.currentOrigin); //LerpPosition(ent->client->clientMarkers[i].mins, ent->client->clientMarkers[j].mins, frac, ent->r.mins); //LerpPosition(ent->client->clientMarkers[i].maxs, ent->client->clientMarkers[j].maxs, frac, ent->r.maxs); //josh: Using TimeShiftLerp since it follows the client exactly //meaning less roundoff error TimeShiftLerp( ent->client->clientMarkers[i].origin, ent->client->clientMarkers[j].origin, frac, ent->r.currentOrigin); TimeShiftLerp( ent->client->clientMarkers[i].mins, ent->client->clientMarkers[j].mins, frac, ent->r.mins); TimeShiftLerp( ent->client->clientMarkers[i].maxs, ent->client->clientMarkers[j].maxs, frac, ent->r.maxs); // These are for Head / Legs ent->client->ps.viewangles[0] = LerpAngle( ent->client->clientMarkers[i].viewangles[0], ent->client->clientMarkers[j].viewangles[0], frac); ent->client->ps.viewangles[1] = LerpAngle( ent->client->clientMarkers[i].viewangles[1], ent->client->clientMarkers[j].viewangles[1], frac); ent->client->ps.viewangles[2] = LerpAngle( ent->client->clientMarkers[i].viewangles[2], ent->client->clientMarkers[j].viewangles[2], frac); // josh: Set the ints to the closest ones in time since you can't // lerp them. if((ent->client->clientMarkers[j].time - time) < (time - ent->client->clientMarkers[i].time)) { ent->client->ps.eFlags = ent->client->clientMarkers[j].eFlags; ent->client->ps.pm_flags = ent->client->clientMarkers[j].pm_flags; ent->client->ps.viewheight = ent->client->clientMarkers[j].viewheight; // forty - realistic hitboxes - Torso Markers ent->torsoFrame.oldFrameModel = ent->client->clientMarkers[j].torsoOldFrameModel; ent->torsoFrame.frameModel = ent->client->clientMarkers[j].torsoFrameModel; ent->torsoFrame.oldFrame = ent->client->clientMarkers[j].torsoOldFrame; ent->torsoFrame.frame = ent->client->clientMarkers[j].torsoFrame; ent->torsoFrame.oldFrameTime = ent->client->clientMarkers[j].torsoOldFrameTime; ent->torsoFrame.frameTime = ent->client->clientMarkers[j].torsoFrameTime; ent->torsoFrame.yawAngle = ent->client->clientMarkers[j].torsoYawAngle; ent->torsoFrame.pitchAngle = ent->client->clientMarkers[j].torsoPitchAngle; ent->torsoFrame.yawing = ent->client->clientMarkers[j].torsoYawing; ent->torsoFrame.pitching = ent->client->clientMarkers[j].torsoPitching; // forty - realistic hitboxes - Legs Markers ent->legsFrame.oldFrameModel = ent->client->clientMarkers[j].legsOldFrameModel; ent->legsFrame.frameModel = ent->client->clientMarkers[j].legsFrameModel; ent->legsFrame.oldFrame = ent->client->clientMarkers[j].legsOldFrame; ent->legsFrame.frame = ent->client->clientMarkers[j].legsFrame; ent->legsFrame.oldFrameTime = ent->client->clientMarkers[j].legsOldFrameTime; ent->legsFrame.frameTime = ent->client->clientMarkers[j].legsFrameTime; ent->legsFrame.yawAngle = ent->client->clientMarkers[j].legsYawAngle; ent->legsFrame.pitchAngle = ent->client->clientMarkers[j].legsPitchAngle; ent->legsFrame.yawing = ent->client->clientMarkers[j].legsYawing; ent->legsFrame.pitching = ent->client->clientMarkers[j].legsPitching; // forty - realistic hitboxes - time stamp for BuildHead/Leg ent->timeShiftTime = ent->client->clientMarkers[j].time; } else { ent->client->ps.eFlags = ent->client->clientMarkers[i].eFlags; ent->client->ps.pm_flags = ent->client->clientMarkers[i].pm_flags; ent->client->ps.viewheight = ent->client->clientMarkers[i].viewheight; // forty - realistic hitboxes - Torso Markers ent->torsoFrame.oldFrameModel = ent->client->clientMarkers[i].torsoOldFrameModel; ent->torsoFrame.frameModel = ent->client->clientMarkers[i].torsoFrameModel; ent->torsoFrame.oldFrame = ent->client->clientMarkers[i].torsoOldFrame; ent->torsoFrame.frame = ent->client->clientMarkers[i].torsoFrame; ent->torsoFrame.oldFrameTime = ent->client->clientMarkers[i].torsoOldFrameTime; ent->torsoFrame.frameTime = ent->client->clientMarkers[i].torsoFrameTime; ent->torsoFrame.yawAngle = ent->client->clientMarkers[i].torsoYawAngle; ent->torsoFrame.pitchAngle = ent->client->clientMarkers[i].torsoPitchAngle; ent->torsoFrame.yawing = ent->client->clientMarkers[i].torsoYawing; ent->torsoFrame.pitching = ent->client->clientMarkers[i].torsoPitching; // forty - realistic hitboxes - Legs Markers ent->legsFrame.oldFrameModel = ent->client->clientMarkers[i].legsOldFrameModel; ent->legsFrame.frameModel = ent->client->clientMarkers[i].legsFrameModel; ent->legsFrame.oldFrame = ent->client->clientMarkers[i].legsOldFrame; ent->legsFrame.frame = ent->client->clientMarkers[i].legsFrame; ent->legsFrame.oldFrameTime = ent->client->clientMarkers[i].legsOldFrameTime; ent->legsFrame.frameTime = ent->client->clientMarkers[i].legsFrameTime; ent->legsFrame.yawAngle = ent->client->clientMarkers[i].legsYawAngle; ent->legsFrame.pitchAngle = ent->client->clientMarkers[i].legsPitchAngle; ent->legsFrame.yawing = ent->client->clientMarkers[i].legsYawing; ent->legsFrame.pitching = ent->client->clientMarkers[i].legsPitching; // forty - realistic hitboxes - time stamp for BuildHead/Leg ent->timeShiftTime = ent->client->clientMarkers[i].time; } if ( debugger && debugger->client) { // print some debugging stuff exactly like what the client does // it starts with "Rec:" to let you know it backward-reconciled char msg[2048]; Com_sprintf( msg, sizeof(msg), "print \"^1Rec: time: %d, j: %d, k: %d, origin: %0.2f %0.2f %0.2f\n" "^2frac: %0.4f, origin1: %0.2f %0.2f %0.2f, origin2: %0.2f %0.2f %0.2f\n" "^7level.time: %d, est time: %d, level.time delta: %d, est real ping: %d\n\"", time, ent->client->clientMarkers[i].time, ent->client->clientMarkers[j].time, ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2], frac, ent->client->clientMarkers[i].origin[0], ent->client->clientMarkers[i].origin[1], ent->client->clientMarkers[i].origin[2], ent->client->clientMarkers[j].origin[0], ent->client->clientMarkers[j].origin[1], ent->client->clientMarkers[j].origin[2], level.time, level.time + debugger->client->frameOffset, level.time - time, level.time + debugger->client->frameOffset - time); trap_SendServerCommand( debugger - g_entities, msg ); } } else { VectorCopy( ent->client->clientMarkers[j].origin, ent->r.currentOrigin ); VectorCopy( ent->client->clientMarkers[j].mins, ent->r.mins ); VectorCopy( ent->client->clientMarkers[j].maxs, ent->r.maxs ); //// josh: BuildHead/Legs uses these VectorCopy(ent->client->clientMarkers[j].viewangles, ent->client->ps.viewangles); ent->client->ps.eFlags = ent->client->clientMarkers[j].eFlags; ent->client->ps.pm_flags = ent->client->clientMarkers[j].pm_flags; ent->client->ps.viewheight = ent->client->clientMarkers[j].viewheight; // forty - realistic hitboxes - Torso Markers ent->torsoFrame.oldFrameModel = ent->client->clientMarkers[j].torsoOldFrameModel; ent->torsoFrame.frameModel = ent->client->clientMarkers[j].torsoFrameModel; ent->torsoFrame.oldFrame = ent->client->clientMarkers[j].torsoOldFrame; ent->torsoFrame.frame = ent->client->clientMarkers[j].torsoFrame; ent->torsoFrame.oldFrameTime = ent->client->clientMarkers[j].torsoOldFrameTime; ent->torsoFrame.frameTime = ent->client->clientMarkers[j].torsoFrameTime; ent->torsoFrame.yawAngle = ent->client->clientMarkers[j].torsoYawAngle; ent->torsoFrame.pitchAngle = ent->client->clientMarkers[j].torsoPitchAngle; ent->torsoFrame.yawing = ent->client->clientMarkers[j].torsoYawing; ent->torsoFrame.pitching = ent->client->clientMarkers[j].torsoPitching; // forty - realistic hitboxes - Legs Markers ent->legsFrame.oldFrameModel = ent->client->clientMarkers[j].legsOldFrameModel; ent->legsFrame.frameModel = ent->client->clientMarkers[j].legsFrameModel; ent->legsFrame.oldFrame = ent->client->clientMarkers[j].legsOldFrame; ent->legsFrame.frame = ent->client->clientMarkers[j].legsFrame; ent->legsFrame.oldFrameTime = ent->client->clientMarkers[j].legsOldFrameTime; ent->legsFrame.frameTime = ent->client->clientMarkers[j].legsFrameTime; ent->legsFrame.yawAngle = ent->client->clientMarkers[j].legsYawAngle; ent->legsFrame.pitchAngle = ent->client->clientMarkers[j].legsPitchAngle; ent->legsFrame.yawing = ent->client->clientMarkers[j].legsYawing; ent->legsFrame.pitching = ent->client->clientMarkers[j].legsPitching; // forty - realistic hitboxes - time stamp for BuildHead/Leg ent->timeShiftTime = ent->client->clientMarkers[j].time; } trap_LinkEntity( ent ); }
void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const entity_state_t *prev ) { float m_fLerp; if( state->ed_type == ED_CLIENT && state->ed_flags & ESF_NO_PREDICTION ) m_fLerp = 1.0f; else m_fLerp = GetLerpFrac(); if( state->flags & FL_PROJECTILE && state->ed_flags & ( ESF_NO_PREDICTION|ESF_NODELTA )) { // cut rocket trail, dont pass it from teleport // FIXME: don't work g_pViewRenderBeams->KillDeadBeams( ent ); } // copy state to progs ent->v.modelindex = state->modelindex; ent->v.weaponmodel = state->weaponmodel; ent->v.sequence = state->sequence; ent->v.gaitsequence = state->gaitsequence; ent->v.body = state->body; ent->v.skin = state->skin; ent->v.effects = state->effects; ent->v.velocity = state->velocity; ent->v.basevelocity = state->basevelocity; ent->v.oldorigin = ent->v.origin; // previous origin holds ent->v.mins = state->mins; ent->v.maxs = state->maxs; ent->v.framerate = state->framerate; ent->v.colormap = state->colormap; ent->v.rendermode = state->rendermode; ent->v.renderfx = state->renderfx; ent->v.fov = state->fov; ent->v.scale = state->scale; ent->v.weapons = state->weapons; ent->v.gravity = state->gravity; ent->v.health = state->health; ent->v.solid = state->solid; ent->v.movetype = state->movetype; ent->v.flags = state->flags; ent->v.ideal_pitch = state->idealpitch; ent->v.animtime = state->animtime; ent->v.ltime = state->localtime; if( state->groundent != -1 ) ent->v.groundentity = GetEntityByIndex( state->groundent ); else ent->v.groundentity = NULL; if( state->aiment != -1 ) ent->v.aiment = GetEntityByIndex( state->aiment ); else ent->v.aiment = NULL; 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; ent->v.oldorigin = prev->origin; // used for lerp 'monster view' ent->v.oldangles = prev->angles; // used for lerp 'monster view' 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; } // 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 ); if( ent->v.animtime ) { // use normal studio lerping ent->v.frame = state->frame; } else { // round sprite and brushmodel frames ent->v.frame = Q_rint( state->frame ); } switch( state->ed_type ) { case ED_CLIENT: ent->v.punchangle = LerpAngle( prev->punch_angles, state->punch_angles, m_fLerp ); ent->v.viewangles = LerpAngle( prev->viewangles, state->viewangles, m_fLerp ); ent->v.view_ofs = LerpPoint( prev->viewoffset, state->viewoffset, m_fLerp ); if( prev->fov != 90.0f && state->fov == 90.0f ) ent->v.fov = state->fov; // fov is reset, so don't lerping else ent->v.fov = LerpPoint( prev->fov, state->fov, m_fLerp ); ent->v.maxspeed = state->maxspeed; ent->v.iStepLeft = state->iStepLeft; ent->v.flFallVelocity = state->flFallVelocity; if( ent == GetLocalPlayer()) { edict_t *viewent = GetViewModel(); // if viewmodel has changed update sequence here if( viewent->v.modelindex != state->viewmodel ) { // ALERT( at_console, "Viewmodel changed\n" ); SendWeaponAnim( viewent->v.sequence, viewent->v.body, viewent->v.framerate ); } // setup player viewmodel (only for local player!) viewent->v.modelindex = state->viewmodel; gHUD.m_flFOV = ent->v.fov; // keep client fov an actual } break; case ED_PORTAL: case ED_MOVER: case ED_BSPBRUSH: ent->v.movedir = BitsToDir( state->body ); ent->v.oldorigin = state->oldorigin; break; case ED_SKYPORTAL: { skyportal_t *sky = &gpViewParams->skyportal; // setup sky portal sky->vieworg = ent->v.origin; sky->viewanglesOffset.x = sky->viewanglesOffset.z = 0.0f; sky->viewanglesOffset.y = gHUD.m_flTime * ent->v.angles[1]; sky->scale = (ent->v.scale ? 1.0f / ent->v.scale : 0.0f ); // critical stuff sky->fov = ent->v.fov; } break; case ED_BEAM: ent->v.oldorigin = state->oldorigin; // beam endpoint ent->v.frags = state->gaitsequence; 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; } int i; // copy blendings for( i = 0; i < MAXSTUDIOBLENDS; i++ ) ent->v.blending[i] = state->blending[i]; // copy controllers for( i = 0; i < MAXSTUDIOCONTROLLERS; i++ ) ent->v.controller[i] = state->controller[i]; // g-cont. moved here because we may needs apply null scale to skyportal if( ent->v.scale == 0.0f && ent->v.skin >= 0 ) ent->v.scale = 1.0f; ent->v.pContainingEntity = ent; }
void CG_LaserBeamEffect( centity_t *cent ) { struct sfx_s *sound = NULL; float range; trace_t trace; orientation_t projectsource; vec4_t color; vec3_t laserOrigin, laserAngles, laserPoint; int i, j; if( cent->localEffects[LOCALEFFECT_LASERBEAM] <= cg.time ) return; laserOwner = cent; if( cg_teamColoredBeams->integer && ( cent->current.team == TEAM_ALPHA || cent->current.team == TEAM_BETA ) ) CG_TeamColor( cent->current.team, color ); else Vector4Set( color, 1, 1, 1, 1 ); // interpolate the positions if( ISVIEWERENTITY( cent->current.number ) && !cg.view.thirdperson ) { VectorCopy( cg.predictedPlayerState.pmove.origin, laserOrigin ); laserOrigin[2] += cg.predictedPlayerState.viewheight; VectorCopy( cg.predictedPlayerState.viewangles, laserAngles ); VectorLerp( cent->laserPointOld, cg.lerpfrac, cent->laserPoint, laserPoint ); } else { VectorLerp( cent->laserOriginOld, cg.lerpfrac, cent->laserOrigin, laserOrigin ); VectorLerp( cent->laserPointOld, cg.lerpfrac, cent->laserPoint, laserPoint ); if( !cent->laserCurved ) { vec3_t dir; // make up the angles from the start and end points (s->angles is not so precise) VectorSubtract( laserPoint, laserOrigin, dir ); VecToAngles( dir, laserAngles ); } else // use player entity angles { for( i = 0; i < 3; i++ ) laserAngles[i] = LerpAngle( cent->prev.angles[i], cent->current.angles[i], cg.lerpfrac ); } } if( !cent->laserCurved ) { range = GS_GetWeaponDef( WEAP_LASERGUN )->firedef.timeout; if( cent->current.effects & EF_QUAD ) sound = CG_MediaSfx( cgs.media.sfxLasergunStrongQuadHum ); else sound = CG_MediaSfx( cgs.media.sfxLasergunStrongHum ); // trace the beam: for tracing we use the real beam origin GS_TraceLaserBeam( &trace, laserOrigin, laserAngles, range, cent->current.number, 0, _LaserImpact ); // draw the beam: for drawing we use the weapon projection source (already handles the case of viewer entity) if( !CG_PModel_GetProjectionSource( cent->current.number, &projectsource ) ) VectorCopy( laserOrigin, projectsource.origin ); CG_KillPolyBeamsByTag( cent->current.number ); CG_LaserGunPolyBeam( projectsource.origin, trace.endpos, color, cent->current.number ); } else { float frac, subdivisions = cg_laserBeamSubdivisions->integer; vec3_t from, dir, end, blendPoint; int passthrough = cent->current.number; vec3_t tmpangles, blendAngles; range = GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.timeout; if( cent->current.effects & EF_QUAD ) sound = CG_MediaSfx( cgs.media.sfxLasergunWeakQuadHum ); else sound = CG_MediaSfx( cgs.media.sfxLasergunWeakHum ); // trace the beam: for tracing we use the real beam origin GS_TraceCurveLaserBeam( &trace, laserOrigin, laserAngles, laserPoint, cent->current.number, 0, _LaserImpact ); // draw the beam: for drawing we use the weapon projection source (already handles the case of viewer entity) if( !CG_PModel_GetProjectionSource( cent->current.number, &projectsource ) ) VectorCopy( laserOrigin, projectsource.origin ); if( subdivisions < CURVELASERBEAM_SUBDIVISIONS ) subdivisions = CURVELASERBEAM_SUBDIVISIONS; CG_KillPolyBeamsByTag( cent->current.number ); // we redraw the full beam again, and trace each segment for stop dead impact VectorCopy( laserPoint, blendPoint ); VectorCopy( projectsource.origin, from ); VectorSubtract( blendPoint, projectsource.origin, dir ); VecToAngles( dir, blendAngles ); for( i = 1; i <= (int)subdivisions; i++ ) { frac = ( ( range/subdivisions )*(float)i ) / (float)range; for( j = 0; j < 3; j++ ) tmpangles[j] = LerpAngle( laserAngles[j], blendAngles[j], frac ); AngleVectors( tmpangles, dir, NULL, NULL ); VectorMA( projectsource.origin, range * frac, dir, end ); GS_TraceLaserBeam( &trace, from, tmpangles, DistanceFast( from, end ), passthrough, 0, NULL ); CG_LaserGunPolyBeam( from, trace.endpos, color, cent->current.number ); if( trace.fraction != 1.0f ) break; passthrough = trace.ent; VectorCopy( trace.endpos, from ); } } // enable continuous flash on the weapon owner if( cg_weaponFlashes->integer ) cg_entPModels[cent->current.number].flash_time = cg.time + CG_GetWeaponInfo( WEAP_LASERGUN )->flashTime; if( sound ) { if( ISVIEWERENTITY( cent->current.number ) ) trap_S_AddLoopSound( sound, cent->current.number, 1.0, ATTN_NONE ); else trap_S_AddLoopSound( sound, cent->current.number, 1.0, ATTN_STATIC ); } laserOwner = NULL; }
void Wolfcam_CheckNoMove (void) { int clientNum; int i; const centity_t *cent; const entityState_t *es; entityState_t *nes; const entityState_t *nnes; qboolean inNextNextSnapshot; qboolean nextNextReset; cg.noMove = qfalse; cg.numNoMoveClients = 0; //if (cg.time < cgs.timeoutEndTime) { if (cg.snap->serverTime < cgs.timeoutEndTime) { return; } //FIXME other snaps as well? if (cg.snap->ps.pm_type == PM_INTERMISSION) { return; } #if 1 if (!cg.nextNextSnapValid) { //Com_Printf("FIXME Wolfcam_CheckNoMove() !cg.nextNextSnapValid\n"); //CG_Abort(); return; } #endif if ((cg.snap->snapFlags ^ cg.nextSnap->snapFlags) & SNAPFLAG_SERVERCOUNT) { return; } if ((cg.nextSnap->snapFlags ^ cg.nextNextSnap->snapFlags) & SNAPFLAG_SERVERCOUNT) { nextNextReset = qtrue; } else { nextNextReset = qfalse; } for (clientNum = 0; clientNum < MAX_CLIENTS; clientNum++) { cent = &cg_entities[clientNum]; if (!cent->inCurrentSnapshot) { continue; } // view switching if ((cg.snap->ps.clientNum != cg.nextSnap->ps.clientNum) && (clientNum == cg.snap->ps.clientNum || clientNum == cg.nextSnap->ps.clientNum)) { continue; } if (clientNum != cg.snap->ps.clientNum && !cent->inNextSnapshot) { continue; } #if 0 if (clientNum == cg.nextSnap->ps.clientNum && cg.snap->ps.clientNum != cg.nextSnap->ps.clientNum) { continue; } #endif if (clientNum == cg.snap->ps.clientNum) { if ((cg.snap->ps.eFlags ^ cg.nextSnap->ps.eFlags) & EF_TELEPORT_BIT) { continue; } if (Distance(cg.snap->ps.origin, cg.nextSnap->ps.origin) == 0.0f && VectorLength(cg.snap->ps.velocity) > 0.0 && VectorLength(cg.nextSnap->ps.velocity) > 0.0) { CG_LagometerMarkNoMove(); cg.noMove = qtrue; wclients[clientNum].noMoveCount++; if (cg.snap->ps.clientNum != cg.nextNextSnap->ps.clientNum) { continue; } if ((cg.nextSnap->ps.eFlags ^ cg.nextNextSnap->ps.eFlags) & EF_TELEPORT_BIT) { continue; } if (nextNextReset) { continue; } if (cg_demoSmoothing.integer == 1) { cg.nextSnap->ps.origin[0] = cg.snap->ps.origin[0] + (cg.nextNextSnap->ps.origin[0] - cg.snap->ps.origin[0]) / 2; cg.nextSnap->ps.origin[1] = cg.snap->ps.origin[1] + (cg.nextNextSnap->ps.origin[1] - cg.snap->ps.origin[1]) / 2; cg.nextSnap->ps.origin[2] = cg.snap->ps.origin[2] + (cg.nextNextSnap->ps.origin[2] - cg.snap->ps.origin[2]) / 2; cg.nextSnap->ps.viewangles[0] = LerpAngle(cg.snap->ps.viewangles[0], cg.nextNextSnap->ps.viewangles[0], 0.5); cg.nextSnap->ps.viewangles[1] = LerpAngle(cg.snap->ps.viewangles[1], cg.nextNextSnap->ps.viewangles[1], 0.5); cg.nextSnap->ps.viewangles[2] = LerpAngle(cg.snap->ps.viewangles[2], cg.nextNextSnap->ps.viewangles[2], 0.5); } } } else { qboolean inSnapshot; qboolean inNextSnapshot; inSnapshot = qfalse; for (i = 0; i < cg.snap->numEntities; i++) { es = &cg.snap->entities[i]; if (es->number == clientNum) { inSnapshot = qtrue; break; } } if (!inSnapshot) { CG_Printf("^1Wolfcam_CheckNoMove() not in snap %d\n", clientNum); //es = NULL; continue; // shouldn't get here } inNextSnapshot = qfalse; for (i = 0; i < cg.nextSnap->numEntities; i++) { nes = &cg.nextSnap->entities[i]; if (nes->number == clientNum) { inNextSnapshot = qtrue; break; } } if (!inNextSnapshot) { CG_Printf("^1Wolfcam_CheckNoMove() not in next snap %d : %d\n", clientNum, cent->inNextSnapshot); //nes = NULL; continue; // shouldn't get here } #if 0 if (!nes) { Com_Printf("^3wtf: clientNum %d cg.nextSnap->numEntities %d\n", clientNum, cg.nextSnap->numEntities); continue; } #endif inNextNextSnapshot = qfalse; for (i = 0; i < cg.nextNextSnap->numEntities; i++) { nnes = &cg.nextNextSnap->entities[i]; if (nnes->number == clientNum) { inNextNextSnapshot = qtrue; break; } } if (!inNextNextSnapshot) { nnes = NULL; } if ((es->eFlags ^ nes->eFlags) & EF_TELEPORT_BIT) { continue; } if (Distance(es->pos.trBase, nes->pos.trBase) == 0.0f && VectorLength(es->pos.trDelta) > 0.0 && VectorLength(nes->pos.trDelta) > 0.0) { wclients[clientNum].noMoveCount++; if (!inNextNextSnapshot) { continue; } if ((nes->eFlags ^ nnes->eFlags) & EF_TELEPORT_BIT) { continue; } if (nextNextReset) { continue; } if (cg_demoSmoothing.integer == 1) { nes->pos.trBase[0] = es->pos.trBase[0] + (nnes->pos.trBase[0] - es->pos.trBase[0]) / 2; nes->pos.trBase[1] = es->pos.trBase[1] + (nnes->pos.trBase[1] - es->pos.trBase[1]) / 2; nes->pos.trBase[2] = es->pos.trBase[2] + (nnes->pos.trBase[2] - es->pos.trBase[2]) / 2; nes->apos.trBase[0] = LerpAngle(es->apos.trBase[0], nnes->apos.trBase[0], 0.5f); nes->apos.trBase[1] = LerpAngle(es->apos.trBase[1], nnes->apos.trBase[1], 0.5f); nes->apos.trBase[2] = LerpAngle(es->apos.trBase[2], nnes->apos.trBase[2], 0.5f); } } } } }
void CGCam_FollowUpdate ( void ) { vec3_t center, dir, cameraAngles, vec, focus[MAX_CAMERA_GROUP_SUBJECTS];//No more than 16 subjects in a cameraGroup gentity_t *from = NULL; centity_t *fromCent = NULL; int num_subjects = 0, i; if ( client_camera.cameraGroup && client_camera.cameraGroup[0] ) { //Stay centered in my cameraGroup, if I have one while( NULL != (from = G_Find(from, FOFS(cameraGroup), client_camera.cameraGroup))) { /* if ( from->s.number == client_camera.aimEntNum ) {//This is the misc_camera_focus, we'll be removing this ent altogether eventually continue; } */ if ( num_subjects >= MAX_CAMERA_GROUP_SUBJECTS ) { gi.Printf(S_COLOR_RED"ERROR: Too many subjects in shot composition %s", client_camera.cameraGroup); break; } fromCent = &cg_entities[from->s.number]; if ( !fromCent ) { continue; } if ( from->s.pos.trType == TR_INTERPOLATE ) {//use interpolated origin? VectorCopy(fromCent->lerpOrigin, focus[num_subjects]); } else { VectorCopy(from->currentOrigin, focus[num_subjects]); } //FIXME: make a list here of their s.numbers instead so we can do other stuff with the list below if ( from->client ) {//Track to their eyes - FIXME: maybe go off a tag? //FIXME: //Based on FOV and distance to subject from camera, pick the point that //keeps eyes 3/4 up from bottom of screen... what about bars? focus[num_subjects][2] += from->client->ps.viewheight; } num_subjects++; } if ( !num_subjects ) // Bad cameragroup { gi.Printf(S_COLOR_RED"ERROR: Camera Focus unable to locate cameragroup: %s\n", client_camera.cameraGroup); return; } //Now average all points VectorCopy( focus[0], center ); for( i = 1; i < num_subjects; i++ ) { VectorAdd( focus[i], center, center ); } VectorScale( center, 1.0f/((float)num_subjects), center ); } else { return; } //Need to set a speed to keep a distance from //the subject- fixme: only do this if have a distance //set VectorSubtract( client_camera.subjectPos, center, vec ); client_camera.subjectSpeed = VectorLengthSquared( vec ) * 100.0f / cg.frametime; VectorCopy( center, client_camera.subjectPos ); VectorSubtract( center, cg.refdef.vieworg, dir );//can't use client_camera.origin because it's not updated until the end of the move. //Get desired angle vectoangles(dir, cameraAngles); if ( client_camera.followInitLerp ) {//Lerping for( i = 0; i < 3; i++ ) { cameraAngles[i] = LerpAngle( client_camera.angles[i], cameraAngles[i], cg.frametime/100.0f * client_camera.followSpeed/100.f ); } } else {//Snapping, should do this first time if follow_lerp_to_start_duration is zero //will lerp from this point on client_camera.followInitLerp = qtrue; //So tracker doesn't move right away thinking the first angle change //is the subject moving... FIXME: shouldn't set this until lerp done OR snapped? client_camera.subjectSpeed = 0; } //Point camera to lerp angles VectorCopy( cameraAngles, client_camera.angles ); }
/* * CG_InterpolatePlayerState */ static void CG_InterpolatePlayerState( player_state_t *playerState ) { int i; player_state_t *ps, *ops; bool teleported; ps = &cg.frame.playerState; ops = &cg.oldFrame.playerState; *playerState = *ps; teleported = ( ps->pmove.pm_flags & PMF_TIME_TELEPORT ) ? true : false; if( abs( (int)(ops->pmove.origin[0] - ps->pmove.origin[0]) ) > 256 || abs( (int)(ops->pmove.origin[1] - ps->pmove.origin[1]) ) > 256 || abs( (int)(ops->pmove.origin[2] - ps->pmove.origin[2]) ) > 256 ) teleported = true; #ifdef EXTRAPOLATE_PLAYERSTATE // isn't smooth enough for the 1st person view if( cgs.extrapolationTime ) { vec3_t newPosition, oldPosition; // if the player entity was teleported this frame use the final position if( !teleported ) { for( i = 0; i < 3; i++ ) { playerState->pmove.velocity[i] = ops->pmove.velocity[i] + cg.lerpfrac * ( ps->pmove.velocity[i] - ops->pmove.velocity[i] ); playerState->viewangles[i] = LerpAngle( ops->viewangles[i], ps->viewangles[i], cg.lerpfrac ); } } VectorMA( ps->pmove.origin, cg.xerpTime, ps->pmove.velocity, newPosition ); if( cg.xerpTime < 0.0f ) // smooth with the ending of oldsnap-newsnap interpolation { if( teleported ) VectorCopy( ps->pmove.origin, oldPosition ); else VectorMA( ops->pmove.origin, cg.oldXerpTime, ops->pmove.velocity, oldPosition ); } VectorLerp( oldPosition, cg.xerpSmoothFrac, newPosition, playerState->pmove.origin ); } else { #endif // if the player entity was teleported this frame use the final position if( !teleported ) { for( i = 0; i < 3; i++ ) { playerState->pmove.origin[i] = ops->pmove.origin[i] + cg.lerpfrac * ( ps->pmove.origin[i] - ops->pmove.origin[i] ); playerState->pmove.velocity[i] = ops->pmove.velocity[i] + cg.lerpfrac * ( ps->pmove.velocity[i] - ops->pmove.velocity[i] ); playerState->viewangles[i] = LerpAngle( ops->viewangles[i], ps->viewangles[i], cg.lerpfrac ); } } #ifdef EXTRAPOLATE_PLAYERSTATE } #endif // interpolate fov and viewheight if( !teleported ) { playerState->fov = ops->fov + cg.lerpfrac * ( ps->fov - ops->fov ); playerState->viewheight = ops->viewheight + cg.lerpfrac * ( ps->viewheight - ops->viewheight ); } }