static void NQD_LerpPlayerinfo (float f) { if (cl.intermission) { // just stay there return; } if (nq_player_teleported) { VectorCopy (nq_mvelocity[0], cl.simvel); VectorCopy (nq_mviewangles[0], cl.viewangles); if (cls.demoplayback) VectorCopy (nq_mviewangles[0], cl.simangles); return; } LerpVector (nq_mvelocity[1], nq_mvelocity[0], f, cl.simvel); if (cls.demoplayback) { LerpAngles (nq_mviewangles[1], nq_mviewangles[0], f, cl.simangles); VectorCopy (cl.simangles, cl.viewangles); } }
// for .qwd demo playback static void CL_LerpMove (float msgtime) { static int lastsequence = 0; static vec3_t lerp_angles[3]; static vec3_t lerp_origin[3]; static float lerp_times[3]; static qbool nolerp[2]; static float demo_latency = 0.01; float frac; float simtime; int i; int from, to; if (cl_nolerp.value) return; if (cls.netchan.outgoing_sequence < lastsequence) { // reset lastsequence = -1; lerp_times[0] = -1; demo_latency = 0.01; } if (cls.netchan.outgoing_sequence > lastsequence) { lastsequence = cls.netchan.outgoing_sequence; // move along lerp_times[2] = lerp_times[1]; lerp_times[1] = lerp_times[0]; lerp_times[0] = msgtime; VectorCopy (lerp_origin[1], lerp_origin[2]); VectorCopy (lerp_origin[0], lerp_origin[1]); VectorCopy (cl.simorg, lerp_origin[0]); VectorCopy (lerp_angles[1], lerp_angles[2]); VectorCopy (lerp_angles[0], lerp_angles[1]); VectorCopy (cl.simangles, lerp_angles[0]); nolerp[1] = nolerp[0]; nolerp[0] = false; for (i = 0; i < 3; i++) if (fabs(lerp_origin[0][i] - lerp_origin[1][i]) > 40) break; if (i < 3) nolerp[0] = true; // a teleport or something } simtime = cls.realtime - demo_latency; // adjust latency if (simtime > lerp_times[0]) { // Com_DPrintf ("HIGH clamp\n"); demo_latency = cls.realtime - lerp_times[0]; } else if (simtime < lerp_times[2]) { // Com_DPrintf (" low clamp\n"); demo_latency = cls.realtime - lerp_times[2]; } else { // drift towards ideal latency float ideal_latency = (lerp_times[0] - lerp_times[2]) * 0.6; if (demo_latency > ideal_latency) demo_latency = max(demo_latency - cls.frametime * 0.1, ideal_latency); } // decide where to lerp from if (simtime > lerp_times[1]) { from = 1; to = 0; } else { from = 2; to = 1; } if (nolerp[to]) return; frac = (simtime - lerp_times[from]) / (lerp_times[to] - lerp_times[from]); frac = bound (0, frac, 1); LerpVector (lerp_origin[from], lerp_origin[to], frac, cl.simorg); LerpAngles (lerp_angles[from], lerp_angles[to], frac, cl.simangles); }
void NQD_LinkEntities (void) { entity_t ent; centity_t *cent; entity_state_t *state; float f; struct model_s *model; int modelflags; vec3_t cur_origin; vec3_t old_origin; float autorotate; int i; int num; f = NQD_LerpPoint (); NQD_LerpPlayerinfo (f); autorotate = anglemod (100*cl.time); memset (&ent, 0, sizeof(ent)); for (num = 1; num < nq_num_entities; num++) { cent = &cl_entities[num]; state = ¢->current; if (cent->lastframe != cl_entframecount) continue; // not present in this frame MSG_UnpackOrigin (state->s_origin, cur_origin); if (state->effects & EF_BRIGHTFIELD) CL_EntityParticles (cur_origin); // spawn light flashes, even ones coming from invisible objects if (state->effects & EF_MUZZLEFLASH) { vec3_t angles, forward; cdlight_t *dl; dl = CL_AllocDlight (-num); MSG_UnpackAngles (state->s_angles, angles); AngleVectors (angles, forward, NULL, NULL); VectorMA (cur_origin, 18, forward, dl->origin); dl->origin[2] += 16; dl->radius = 200 + (rand()&31); dl->minlight = 32; dl->die = cl.time + 0.1; dl->type = lt_muzzleflash; } if (state->effects & EF_BRIGHTLIGHT) { if (state->modelindex != cl_playerindex || r_powerupglow.value) { vec3_t tmp; VectorCopy (cur_origin, tmp); tmp[2] += 16; V_AddDlight (state->number, tmp, 400 + (rand()&31), 0, lt_default); } } if (state->effects & EF_DIMLIGHT) if (state->modelindex != cl_playerindex || r_powerupglow.value) V_AddDlight (state->number, cur_origin, 200 + (rand()&31), 0, lt_default); // if set to invisible, skip if (!state->modelindex) continue; cent->current = *state; ent.model = model = cl.model_precache[state->modelindex]; if (!model) Host_Error ("CL_LinkPacketEntities: bad modelindex"); if (cl_r2g.value && cl_grenadeindex != -1) if (state->modelindex == cl_rocketindex) ent.model = cl.model_precache[cl_grenadeindex]; modelflags = R_ModelFlags (model); // rotate binary objects locally if (modelflags & MF_ROTATE) { ent.angles[0] = 0; ent.angles[1] = autorotate; ent.angles[2] = 0; } else { vec3_t old, cur; MSG_UnpackAngles (cent->current.s_angles, old); MSG_UnpackAngles (cent->previous.s_angles, cur); LerpAngles (old, cur, f, ent.angles); } if (num == nq_viewentity) { extern float nq_speed; float f; nq_speed = 0; for (i = 0; i < 3; i++) { f = (cent->current.s_origin[i] - cent->previous.s_origin[i]) * 0.125; nq_speed += f * f; } if (nq_speed) nq_speed = sqrt(nq_speed); nq_speed /= nq_mtime[0] - nq_mtime[1]; } // calculate origin for (i = 0; i < 3; i++) { if (abs(cent->current.s_origin[i] - cent->previous.s_origin[i]) > 128 * 8) { // teleport or something, don't lerp VectorCopy (cur_origin, ent.origin); if (num == nq_viewentity) nq_player_teleported = true; break; } ent.origin[i] = cent->previous.s_origin[i] * 0.125 + f * (cur_origin[i] - cent->previous.s_origin[i] * 0.125); } if (num == nq_viewentity) { VectorCopy (ent.origin, cent->trail_origin); // FIXME? continue; // player entity } if (cl_deadbodyfilter.value && state->modelindex == cl_playerindex && ( (i=state->frame)==49 || i==60 || i==69 || i==84 || i==93 || i==102) ) continue; if (cl_gibfilter.value && cl.modelinfos[state->modelindex] == mi_gib) continue; // set colormap if (state->colormap && state->colormap <= MAX_CLIENTS && state->modelindex == cl_playerindex ) ent.colormap = state->colormap; else ent.colormap = 0; // set skin ent.skinnum = state->skinnum; // set frame ent.frame = state->frame; // add automatic particle trails if ((modelflags & ~MF_ROTATE)) { if (false /*cl_entframecount == 1 || cent->lastframe != cl_entframecount-1*/) { // not in last message VectorCopy (ent.origin, old_origin); } else { VectorCopy (cent->trail_origin, old_origin); for (i=0 ; i<3 ; i++) if ( abs(old_origin[i] - ent.origin[i]) > 128) { // no trail if too far VectorCopy (ent.origin, old_origin); break; } } if (modelflags & MF_ROCKET) { if (r_rockettrail.value) { if (r_rockettrail.value == 2) CL_GrenadeTrail (old_origin, ent.origin, cent->trail_origin); else CL_RocketTrail (old_origin, ent.origin, cent->trail_origin); } else VectorCopy (ent.origin, cent->trail_origin); if (r_rocketlight.value) CL_NewDlight (state->number, ent.origin, 200, 0.1, lt_rocket); } else if (modelflags & MF_GRENADE && r_grenadetrail.value) CL_GrenadeTrail (old_origin, ent.origin, cent->trail_origin); else if (modelflags & MF_GIB) CL_BloodTrail (old_origin, ent.origin, cent->trail_origin); else if (modelflags & MF_ZOMGIB) CL_SlightBloodTrail (old_origin, ent.origin, cent->trail_origin); else if (modelflags & MF_TRACER) CL_TracerTrail (old_origin, ent.origin, cent->trail_origin, 52); else if (modelflags & MF_TRACER2) CL_TracerTrail (old_origin, ent.origin, cent->trail_origin, 230); else if (modelflags & MF_TRACER3) CL_VoorTrail (old_origin, ent.origin, cent->trail_origin); } cent->lastframe = cl_entframecount; V_AddEntity (&ent); } if (nq_viewentity == 0) Host_Error ("viewentity == 0"); VectorCopy (cl_entities[nq_viewentity].trail_origin, cl.simorg); }
static void demoFrameInterpolate( demoFrame_t frames[], int frameCount, int index ) { int i; demoFrame_t *workFrame; workFrame = &frames[index % frameCount]; // return; for (i=0; i<MAX_CLIENTS; i++) { entityState_t *workEntity; workEntity = &workFrame->entities[i]; if (workEntity->number != ENTITYNUM_NONE && !workFrame->entityData[i]) { int m; demoFrame_t *prevFrame, *nextFrame; prevFrame = nextFrame = 0; for (m = index - 1; (m > (index - frameCount)) && m >0 ; m--) { demoFrame_t *testFrame = &frames[ m % frameCount]; if ( !testFrame->entityData[i]) continue; if (!testFrame->serverTime || testFrame->serverTime >= workFrame->serverTime) break; if ( testFrame->entities[i].number != i) break; if ( (testFrame->entities[i].eFlags ^ workEntity->eFlags) & EF_TELEPORT_BIT ) break; prevFrame = testFrame; break; } for (m = index + 1; (m < (index + frameCount)); m++) { demoFrame_t *testFrame = &frames[ m % frameCount]; if ( !testFrame->entityData[i]) continue; if (!testFrame->serverTime || testFrame->serverTime <= workFrame->serverTime) break; if ( testFrame->entities[i].number != i) break; if ( (testFrame->entities[i].eFlags ^ workEntity->eFlags) & EF_TELEPORT_BIT ) break; nextFrame = testFrame; break; } if (prevFrame && nextFrame) { const entityState_t *prevEntity = &prevFrame->entities[i]; const entityState_t *nextEntity = &nextFrame->entities[i]; float lerp; int posDelta; float posLerp; int prevTime, nextTime; prevTime = prevFrame->serverTime; nextTime = nextFrame->serverTime; lerp = (workFrame->serverTime - prevTime) / (float)( nextTime - prevTime ); posDelta = nextEntity->pos.trTime - prevEntity->pos.trTime; if ( posDelta ) { workEntity->pos.trTime = prevEntity->pos.trTime + posDelta * lerp; posLerp = (workEntity->pos.trTime - prevEntity->pos.trTime) / (float) posDelta; } else { posLerp = lerp; } LerpOrigin( prevEntity->pos.trBase, nextEntity->pos.trBase, workEntity->pos.trBase, posLerp ); LerpOrigin( prevEntity->pos.trDelta, nextEntity->pos.trDelta, workEntity->pos.trDelta, posLerp ); LerpAngles( prevEntity->apos.trBase, nextEntity->apos.trBase, workEntity->apos.trBase, lerp ); } } } }