/* * G_ClientAddDamageIndicatorImpact */ void G_ClientAddDamageIndicatorImpact( gclient_t *client, int damage, const vec3_t basedir ) { vec3_t dir; float frac; if( damage < 1 ) return; if( !client || client - game.clients < 0 || client - game.clients >= gs.maxclients ) return; if( !basedir ) { VectorCopy( vec3_origin, dir ); } else { VectorNormalize2( basedir, dir ); //#define ACCENT_SCALE 2.0f #ifdef ACCENT_SCALE // accent the vertical or horizontal aspect of the direction if( VectorLengthFast( tv( dir[0], dir[1], 0 ) ) > dir[2] ) { dir[0] *= ACCENT_SCALE; dir[1] *= ACCENT_SCALE; } else dir[2] *= ACCENT_SCALE; VectorNormalizeFast( dir ); #endif #undef ACCENT_SCALE } frac = (float)damage / ( damage + client->resp.snap.damageTaken ); VectorLerp( client->resp.snap.damageTakenDir, frac, dir, client->resp.snap.damageTakenDir ); client->resp.snap.damageTaken += damage; }
static void RestoreEntityTo(CAI_BaseNPC *pEntity, const Vector &vWantedPos) { // Try to move to the wanted position from our current position. trace_t tr; VPROF_BUDGET("RestoreEntityTo", "CLagCompensationManager"); UTIL_TraceEntity(pEntity, vWantedPos, vWantedPos, MASK_NPCSOLID, pEntity, COLLISION_GROUP_NPC, &tr); if (tr.startsolid || tr.allsolid) { if (sv_unlag_debug.GetBool()) { DevMsg("RestorepEntityTo() could not restore entity position for %s ( %.1f %.1f %.1f )\n", pEntity->GetClassname(), vWantedPos.x, vWantedPos.y, vWantedPos.z); } UTIL_TraceEntity(pEntity, pEntity->GetLocalOrigin(), vWantedPos, MASK_NPCSOLID, pEntity, COLLISION_GROUP_NPC, &tr); if (tr.startsolid || tr.allsolid) { // In this case, the guy got stuck back wherever we lag compensated him to. Nasty. if (sv_unlag_debug.GetBool()) DevMsg(" restore failed entirely\n"); } else { // We can get to a valid place, but not all the way back to where we were. Vector vPos; VectorLerp(pEntity->GetLocalOrigin(), vWantedPos, tr.fraction * g_flFractionScale, vPos); UTIL_SetOrigin(pEntity, vPos, true); if (sv_unlag_debug.GetBool()) DevMsg(" restore got most of the way\n"); } } else { // Cool, the entity can go back to whence he came. UTIL_SetOrigin(pEntity, tr.endpos, true); } }
/* * @brief Adds the specified client entity to the view. */ static void Cg_AddEntity(cl_entity_t *e) { r_entity_t ent; memset(&ent, 0, sizeof(ent)); ent.scale = 1.0; // update the static lighting cache Cg_UpdateLighting(e, &ent); // resolve the origin so that we know where to add effects VectorLerp(e->prev.origin, e->current.origin, cgi.client->lerp, ent.origin); // add events Cg_EntityEvent(e); // add effects, augmenting the renderer entity Cg_EntityEffects(e, &ent); // if there's no model associated with the entity, we're done if (!e->current.model1) return; if (e->current.model1 == 0xff) { // add a player entity Cg_AddClientEntity(e, &ent); if (IS_SELF(e)) Cg_AddWeapon(e, &ent); return; } // assign the model ent.model = cgi.client->model_precache[e->current.model1]; // add to view list cgi.AddEntity(&ent); }
qboolean R_Shader_IsLightInScopeByLeaf( unsigned int lightIndex, mleaf_t *leaf ) { const R_ShaderLight *light = GetLightFromIndex( lightIndex ); if( !light->active ) { return false; } if( !R_Shader_IsLightVisibleFromLeaf( light, leaf ) ) { return false; } // bounding sphere check { vec3_t midPoint; float boundingSphereRadius; VectorLerp( &leaf->minmaxs[ 0 ], 0.5f, &leaf->minmaxs[ 3 ], midPoint ); boundingSphereRadius = VectorDistance( &leaf->minmaxs[ 0 ], midPoint ); if( VectorDistance( light->origin, midPoint ) > light->maxDistance + boundingSphereRadius ) { return false; } } return true; }
//----------------------------------------------------------------------------- // Purpose: Handles all flight movement. // Input : flInterval - Seconds to simulate. //----------------------------------------------------------------------------- void CNPC_Crow::MoveCrowFly( float flInterval ) { // // Bound interval so we don't get ludicrous motion when debugging // or when framerate drops catastrophically. // if (flInterval > 1.0) { flInterval = 1.0; } m_flDangerSoundTime = gpGlobals->curtime + 5.0f; // // Determine the goal of our movement. // Vector vecMoveGoal = GetAbsOrigin(); if ( GetNavigator()->IsGoalActive() ) { vecMoveGoal = GetNavigator()->GetCurWaypointPos(); if ( GetNavigator()->CurWaypointIsGoal() == false ) { AI_ProgressFlyPathParams_t params( MASK_NPCSOLID ); params.bTrySimplify = false; GetNavigator()->ProgressFlyPath( params ); // ignore result, crow handles completion directly // Fly towards the hint. if ( GetNavigator()->GetPath()->GetCurWaypoint() ) { vecMoveGoal = GetNavigator()->GetCurWaypointPos(); } } } else { // No movement goal. vecMoveGoal = GetAbsOrigin(); SetAbsVelocity( vec3_origin ); return; } Vector vecMoveDir = ( vecMoveGoal - GetAbsOrigin() ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); // // Fly towards the movement goal. // float flDistance = ( vecMoveGoal - GetAbsOrigin() ).Length(); if ( vecMoveGoal != m_vDesiredTarget ) { m_vDesiredTarget = vecMoveGoal; } else { m_vCurrentTarget = ( m_vDesiredTarget - GetAbsOrigin() ); VectorNormalize( m_vCurrentTarget ); } float flLerpMod = 0.25f; if ( flDistance <= 256.0f ) { flLerpMod = 1.0f - ( flDistance / 256.0f ); } VectorLerp( vForward, m_vCurrentTarget, flLerpMod, vForward ); if ( flDistance < CROW_AIRSPEED * flInterval ) { if ( GetNavigator()->IsGoalActive() ) { if ( GetNavigator()->CurWaypointIsGoal() ) { m_bReachedMoveGoal = true; } else { GetNavigator()->AdvancePath(); } } else m_bReachedMoveGoal = true; } if ( GetHintNode() ) { AIMoveTrace_t moveTrace; GetMoveProbe()->MoveLimit( NAV_FLY, GetAbsOrigin(), GetNavigator()->GetCurWaypointPos(), MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace ); //See if it succeeded if ( IsMoveBlocked( moveTrace.fStatus ) ) { Vector vNodePos = vecMoveGoal; GetHintNode()->GetPosition(this, &vNodePos); GetNavigator()->SetGoal( vNodePos ); } } // // Look to see if we are going to hit anything. // VectorNormalize( vForward ); Vector vecDeflect; if ( Probe( vForward, CROW_AIRSPEED * flInterval, vecDeflect ) ) { vForward = vecDeflect; VectorNormalize( vForward ); } SetAbsVelocity( vForward * CROW_AIRSPEED ); if ( GetAbsVelocity().Length() > 0 && GetNavigator()->CurWaypointIsGoal() && flDistance < CROW_AIRSPEED ) { SetIdealActivity( (Activity)ACT_CROW_LAND ); } //Bank and set angles. Vector vRight; QAngle vRollAngle; VectorAngles( vForward, vRollAngle ); vRollAngle.z = 0; AngleVectors( vRollAngle, NULL, &vRight, NULL ); float flRoll = DotProduct( vRight, vecMoveDir ) * 45; flRoll = clamp( flRoll, -45, 45 ); vRollAngle[ROLL] = flRoll; SetAbsAngles( vRollAngle ); }
void CPositionInterpolator_Linear::InterpolatePosition( float time, Vector &vOut ) { VectorLerp( g_KeyFramePtr[0].vPos, g_KeyFramePtr[1].vPos, time, vOut ); }
/* * 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; }
void CL_UpdateEntityFields( cl_entity_t *ent ) { // parametric rockets code if( ent->curstate.starttime != 0.0f && ent->curstate.impacttime != 0.0f ) { float lerp = ( cl.time - ent->curstate.starttime ) / ( ent->curstate.impacttime - ent->curstate.starttime ); vec3_t dir; lerp = bound( 0.0f, lerp, 1.0f ); // first we need to calc actual origin VectorLerp( ent->curstate.startpos, lerp, ent->curstate.endpos, ent->curstate.origin ); VectorSubtract( ent->curstate.endpos, ent->curstate.startpos, dir ); VectorAngles( dir, ent->curstate.angles ); // re-aim projectile } ent->model = Mod_Handle( ent->curstate.modelindex ); ent->curstate.msg_time = cl.time; CL_InterpolateModel( ent ); if( ent->player && RP_LOCALCLIENT( ent )) // stupid Half-Life bug ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f; // make me lerp if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f ) { float d, f = 0.0f; int i; // 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(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime )) f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime ); f = f - 1.0f; ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f; ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f; ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f; for( i = 0; i < 3; i++ ) { float ang1, ang2; ang1 = ent->angles[i]; ang2 = ent->latched.prevangles[i]; d = ang1 - ang2; if( d > 180.0f ) d -= 360.0f; else if( d < -180.0f ) d += 360.0f; ent->angles[i] += d * f; } } else if( ent->curstate.eflags & EFLAG_SLERP ) { float d, f = 0.0f; cl_entity_t *m_pGround = NULL; int i; // 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(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime )) f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime ); f = f - 1.0f; if( ent->curstate.movetype == MOVETYPE_FLY ) { ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f; ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f; ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f; for( i = 0; i < 3; i++ ) { float ang1, ang2; ang1 = ent->curstate.angles[i]; ang2 = ent->latched.prevangles[i]; d = ang1 - ang2; if( d > 180.0f ) d -= 360.0f; else if( d < -180.0f ) d += 360.0f; ent->angles[i] += d * f; } } else if( ent->curstate.movetype == MOVETYPE_STEP ) { vec3_t vecSrc, vecEnd; pmtrace_t trace; if( ent->model ) { CL_SetTraceHull( 0 ); // g-cont. player hull for better detect moving platforms VectorSet( vecSrc, ent->origin[0], ent->origin[1], ent->origin[2] + ent->model->maxs[2] ); VectorSet( vecEnd, vecSrc[0], vecSrc[1], vecSrc[2] - ent->model->mins[2] - 8.0f ); CL_PlayerTraceExt( vecSrc, vecEnd, PM_STUDIO_IGNORE, CL_PushMoveFilter, &trace ); m_pGround = CL_GetEntityByIndex( pfnIndexFromTrace( &trace )); } if( m_pGround && m_pGround->curstate.movetype == MOVETYPE_PUSH ) { qboolean applyVel, applyAvel; applyVel = !VectorCompare( m_pGround->curstate.origin, m_pGround->prevstate.origin ); applyAvel = !VectorCompare( m_pGround->curstate.angles, m_pGround->prevstate.angles ); if( applyVel || applyAvel ) { ent->origin[0] += ( m_pGround->curstate.origin[0] - m_pGround->prevstate.origin[0] ) * -1.0f; ent->origin[1] += ( m_pGround->curstate.origin[1] - m_pGround->prevstate.origin[1] ) * -1.0f; // ent->origin[2] += ( m_pGround->curstate.origin[2] - m_pGround->prevstate.origin[2] ) * -1.0f; ent->latched.prevorigin[2] = ent->origin[2]; } if( applyAvel ) { for( i = 0; i < 3; i++ ) { float ang1, ang2; ang1 = m_pGround->curstate.angles[i]; ang2 = m_pGround->prevstate.angles[i]; d = ang1 - ang2; if( d > 180.0f ) d -= 360.0f; else if( d < -180.0f ) d += 360.0f; ent->angles[i] += d * -1.0f; } } } // moved code from StudioSetupTransform here if( host.features & ENGINE_COMPUTE_STUDIO_LERP ) { ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f; ent->origin[1] += ( ent->curstate.origin[1] - ent->latched.prevorigin[1] ) * f; ent->origin[2] += ( ent->curstate.origin[2] - ent->latched.prevorigin[2] ) * f; for( i = 0; i < 3; i++ ) { float ang1, ang2; ang1 = ent->angles[i]; ang2 = ent->latched.prevangles[i]; d = ang1 - ang2; if( d > 180.0f ) d -= 360.0f; else if( d < -180.0f ) d += 360.0f; ent->angles[i] += d * f; } } } } }
/* ============== RE_BuildSkeleton ============== */ int RE_BuildSkeleton(refSkeleton_t * skel, qhandle_t hAnim, int startFrame, int endFrame, float frac, qboolean clearOrigin) { skelAnimation_t *skelAnim; skelAnim = R_GetAnimationByHandle(hAnim); if(skelAnim->type == AT_MD5 && skelAnim->md5) { int i; md5Animation_t *anim; md5Channel_t *channel; md5Frame_t *newFrame, *oldFrame; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; int componentsApplied; anim = skelAnim->md5; // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so // when the surfaces are rendered, they don't need to be // range checked again. /* if((startFrame >= anim->numFrames) || (startFrame < 0) || (endFrame >= anim->numFrames) || (endFrame < 0)) { ri.Printf(PRINT_DEVELOPER, "RE_BuildSkeleton: no such frame %d to %d for '%s'\n", startFrame, endFrame, anim->name); //startFrame = 0; //endFrame = 0; } */ Q_clamp(startFrame, 0, anim->numFrames - 1); Q_clamp(endFrame, 0, anim->numFrames - 1); // compute frame pointers oldFrame = &anim->frames[startFrame]; newFrame = &anim->frames[endFrame]; // calculate a bounding box in the current coordinate system for(i = 0; i < 3; i++) { skel->bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; skel->bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } for(i = 0, channel = anim->channels; i < anim->numChannels; i++, channel++) { // set baseframe values VectorCopy(channel->baseOrigin, newOrigin); VectorCopy(channel->baseOrigin, oldOrigin); QuatCopy(channel->baseQuat, newQuat); QuatCopy(channel->baseQuat, oldQuat); componentsApplied = 0; // update tranlation bits if(channel->componentsBits & COMPONENT_BIT_TX) { oldOrigin[0] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[0] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_TY) { oldOrigin[1] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[1] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_TZ) { oldOrigin[2] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[2] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } // update quaternion rotation bits if(channel->componentsBits & COMPONENT_BIT_QX) { ((vec_t *) oldQuat)[0] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[0] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_QY) { ((vec_t *) oldQuat)[1] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[1] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if(channel->componentsBits & COMPONENT_BIT_QZ) { ((vec_t *) oldQuat)[2] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[2] = newFrame->components[channel->componentsOffset + componentsApplied]; } QuatCalcW(oldQuat); QuatNormalize(oldQuat); QuatCalcW(newQuat); QuatNormalize(newQuat); #if 1 VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin); QuatSlerp(oldQuat, newQuat, frac, lerpedQuat); #else VectorCopy(newOrigin, lerpedOrigin); QuatCopy(newQuat, lerpedQuat); #endif // copy lerped information to the bone + extra data skel->bones[i].parentIndex = channel->parentIndex; if(channel->parentIndex < 0 && clearOrigin) { VectorClear(skel->bones[i].origin); QuatClear(skel->bones[i].rotation); // move bounding box back VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]); VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]); } else { VectorCopy(lerpedOrigin, skel->bones[i].origin); } QuatCopy(lerpedQuat, skel->bones[i].rotation); #if defined(REFBONE_NAMES) Q_strncpyz(skel->bones[i].name, channel->name, sizeof(skel->bones[i].name)); #endif } skel->numBones = anim->numChannels; skel->type = SK_RELATIVE; return qtrue; } else if(skelAnim->type == AT_PSA && skelAnim->psa) { int i; psaAnimation_t *anim; axAnimationKey_t *newKey, *oldKey; axReferenceBone_t *refBone; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; refSkeleton_t skeleton; anim = skelAnim->psa; Q_clamp(startFrame, 0, anim->info.numRawFrames - 1); Q_clamp(endFrame, 0, anim->info.numRawFrames - 1); ClearBounds(skel->bounds[0], skel->bounds[1]); skel->numBones = anim->info.numBones; for(i = 0, refBone = anim->bones; i < anim->info.numBones; i++, refBone++) { oldKey = &anim->keys[startFrame * anim->info.numBones + i]; newKey = &anim->keys[endFrame * anim->info.numBones + i]; VectorCopy(newKey->position, newOrigin); VectorCopy(oldKey->position, oldOrigin); QuatCopy(newKey->quat, newQuat); QuatCopy(oldKey->quat, oldQuat); //QuatCalcW(oldQuat); //QuatNormalize(oldQuat); //QuatCalcW(newQuat); //QuatNormalize(newQuat); VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin); QuatSlerp(oldQuat, newQuat, frac, lerpedQuat); // copy lerped information to the bone + extra data skel->bones[i].parentIndex = refBone->parentIndex; if(refBone->parentIndex < 0 && clearOrigin) { VectorClear(skel->bones[i].origin); QuatClear(skel->bones[i].rotation); // move bounding box back VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]); VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]); } else { VectorCopy(lerpedOrigin, skel->bones[i].origin); } QuatCopy(lerpedQuat, skel->bones[i].rotation); #if defined(REFBONE_NAMES) Q_strncpyz(skel->bones[i].name, refBone->name, sizeof(skel->bones[i].name)); #endif // calculate absolute values for the bounding box approximation VectorCopy(skel->bones[i].origin, skeleton.bones[i].origin); QuatCopy(skel->bones[i].rotation, skeleton.bones[i].rotation); if(refBone->parentIndex >= 0) { vec3_t rotated; quat_t quat; refBone_t *parent; refBone_t *bone; bone = &skeleton.bones[i]; parent = &skeleton.bones[refBone->parentIndex]; QuatTransformVector(parent->rotation, bone->origin, rotated); VectorAdd(parent->origin, rotated, bone->origin); QuatMultiply1(parent->rotation, bone->rotation, quat); QuatCopy(quat, bone->rotation); AddPointToBounds(bone->origin, skel->bounds[0], skel->bounds[1]); } } skel->numBones = anim->info.numBones; skel->type = SK_RELATIVE; return qtrue; } //ri.Printf(PRINT_WARNING, "RE_BuildSkeleton: bad animation '%s' with handle %i\n", anim->name, hAnim); // FIXME: clear existing bones and bounds? return qfalse; }
float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent) #endif { float maxfrac, maxrealfrac; int n; entity_render_t *ent; float tracemins[3], tracemaxs[3]; trace_t trace; float tempnormal[3], starttransformed[3], endtransformed[3]; #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND vec3_t end; vec_t len = 0; if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) { // TRICK: make the trace 1 qu longer! VectorSubtract(pEnd, start, end); len = VectorNormalizeLength(end); VectorMA(pEnd, collision_endposnudge.value, end, end); } else VectorCopy(pEnd, end); #endif memset (&trace, 0 , sizeof(trace_t)); trace.fraction = 1; trace.realfraction = 1; VectorCopy (end, trace.endpos); if (hitent) *hitent = 0; if (cl.worldmodel && cl.worldmodel->TraceLine) cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, start, end, SUPERCONTENTS_SOLID); if (normal) VectorCopy(trace.plane.normal, normal); maxfrac = trace.fraction; maxrealfrac = trace.realfraction; tracemins[0] = min(start[0], end[0]); tracemaxs[0] = max(start[0], end[0]); tracemins[1] = min(start[1], end[1]); tracemaxs[1] = max(start[1], end[1]); tracemins[2] = min(start[2], end[2]); tracemaxs[2] = max(start[2], end[2]); // look for embedded bmodels for (n = 0;n < cl.num_entities;n++) { if (!cl.entities_active[n]) continue; ent = &cl.entities[n].render; if (!BoxesOverlap(ent->mins, ent->maxs, tracemins, tracemaxs)) continue; if (!ent->model || !ent->model->TraceLine) continue; if ((ent->flags & RENDER_EXTERIORMODEL) && !chase_active.integer) continue; // if transparent and not selectable, skip entity if (!(cl.entities[n].state_current.effects & EF_SELECTABLE) && (ent->alpha < 1 || (ent->effects & (EF_ADDITIVE | EF_NODEPTHTEST)))) continue; if (ent == ignoreent) continue; Matrix4x4_Transform(&ent->inversematrix, start, starttransformed); Matrix4x4_Transform(&ent->inversematrix, end, endtransformed); Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID, 0, NULL); #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0) Collision_ShortenTrace(&trace, len / (len + collision_endposnudge.value), pEnd); #endif if (maxrealfrac < trace.realfraction) continue; ent->model->TraceLine(ent->model, ent->frameblend, ent->skeleton, &trace, starttransformed, endtransformed, SUPERCONTENTS_SOLID); if (maxrealfrac > trace.realfraction) { if (hitent) *hitent = n; maxfrac = trace.fraction; maxrealfrac = trace.realfraction; if (normal) { VectorCopy(trace.plane.normal, tempnormal); Matrix4x4_Transform3x3(&ent->matrix, tempnormal, normal); } } } maxfrac = bound(0, maxfrac, 1); maxrealfrac = bound(0, maxrealfrac, 1); //if (maxfrac < 0 || maxfrac > 1) Con_Printf("fraction out of bounds %f %s:%d\n", maxfrac, __FILE__, __LINE__); if (impact) VectorLerp(start, maxfrac, end, impact); return maxfrac; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void FX_GlassImpact( const Vector &pos, const Vector &normal ) { VPROF_BUDGET( "FX_GlassImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "FX_GlassImpact" ); pGlassEmitter->SetSortOrigin( pos ); Vector vecColor; engine->ComputeLighting( pos, NULL, true, vecColor ); // HACK: Blend a little toward white to match the materials... VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor ); float flShardSize = random->RandomFloat( 2.0f, 6.0f ); unsigned char color[3] = { 200, 200, 210 }; // --------------------- // Create glass shards // ---------------------- int numShards = random->RandomInt( 2, 4 ); for ( int i = 0; i < numShards; i++ ) { Particle3D *pParticle; pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Glass[random->RandomInt(0,1)], pos ); if ( pParticle ) { pParticle->m_flLifeRemaining = random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE); pParticle->m_vecVelocity[0] = ( normal[0] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED ); pParticle->m_vecVelocity[1] = ( normal[1] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED ); pParticle->m_vecVelocity[2] = ( normal[2] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED ); pParticle->m_uchSize = flShardSize + random->RandomFloat(-0.5*flShardSize,0.5*flShardSize); pParticle->m_vAngles = RandomAngle( 0, 360 ); pParticle->m_flAngSpeed = random->RandomFloat(-800,800); pParticle->m_uchFrontColor[0] = (byte)(color[0] * vecColor.x); pParticle->m_uchFrontColor[1] = (byte)(color[1] * vecColor.y); pParticle->m_uchFrontColor[2] = (byte)(color[2] * vecColor.z); pParticle->m_uchBackColor[0] = (byte)(color[0] * vecColor.x); pParticle->m_uchBackColor[1] = (byte)(color[1] * vecColor.y); pParticle->m_uchBackColor[2] = (byte)(color[2] * vecColor.z); } } pGlassEmitter->m_ParticleCollision.Setup( pos, &normal, GLASS_SHARD_NOISE, GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING ); color[0] = 64; color[1] = 64; color[2] = 92; // --------------------------- // Dust // --------------------------- Vector dir; Vector offset = pos + ( normal * 2.0f ); float colorRamp; SimpleParticle newParticle; for ( int i = 0; i < 4; i++ ) { newParticle.m_Pos = offset; newParticle.m_flLifetime= 0.0f; newParticle.m_flDieTime = random->RandomFloat( 0.1f, 0.25f ); dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f ); dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f ); dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f ); newParticle.m_uchStartSize = random->RandomInt( 1, 4 ); newParticle.m_uchEndSize = newParticle.m_uchStartSize * 8; newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 16.0f )*(i+1); newParticle.m_vecVelocity[2] -= random->RandomFloat( 16.0f, 32.0f )*(i+1); newParticle.m_uchStartAlpha = random->RandomInt( 128, 255 ); newParticle.m_uchEndAlpha = 0; newParticle.m_flRoll = random->RandomFloat( 0, 360 ); newParticle.m_flRollDelta = random->RandomFloat( -1, 1 ); colorRamp = random->RandomFloat( 0.5f, 1.25f ); newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f; newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f; AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] ); } // // Bullet hole capper // newParticle.m_Pos = offset; newParticle.m_flLifetime = 0.0f; newParticle.m_flDieTime = random->RandomFloat( 1.0f, 1.5f ); dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f ); dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f ); dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f ); newParticle.m_uchStartSize = random->RandomInt( 4, 8 ); newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4.0f; newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 8.0f ); newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f ); newParticle.m_uchStartAlpha = random->RandomInt( 32, 64 ); newParticle.m_uchEndAlpha = 0; newParticle.m_flRoll = random->RandomFloat( 0, 360 ); newParticle.m_flRollDelta = random->RandomFloat( -2, 2 ); colorRamp = random->RandomFloat( 0.5f, 1.25f ); newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f; newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f; newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f; AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] ); }
void BlendEdges( CCoreDispInfo **ppListBase, int listSize ) { for ( int iDisp=0; iDisp < listSize; iDisp++ ) { CCoreDispInfo *pDisp = ppListBase[iDisp]; for ( int iEdge=0; iEdge < 4; iEdge++ ) { CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge ); for ( int iSub=0; iSub < 2; iSub++ ) { CDispSubNeighbor *pSub = &pEdge->m_SubNeighbors[iSub]; if ( !pSub->IsValid() ) continue; CCoreDispInfo *pNeighbor = ppListBase[ pSub->GetNeighborIndex() ]; int iEdgeDim = g_EdgeDims[iEdge]; CDispSubEdgeIterator it; it.Start( pDisp, iEdge, iSub, true ); // Get setup on the first corner vert. it.Next(); CVertIndex viPrevPos = it.GetVertIndex(); while ( it.Next() ) { // Blend the two. if ( !it.IsLastVert() ) { Vector vAverage = pDisp->GetNormal( it.GetVertIndex() ) + pNeighbor->GetNormal( it.GetNBVertIndex() ); VectorNormalize( vAverage ); pDisp->SetNormal( it.GetVertIndex(), vAverage ); pNeighbor->SetNormal( it.GetNBVertIndex(), vAverage ); #if defined( USE_SCRATCHPAD ) ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( it.GetVertIndex() ), pDisp->GetNormal( it.GetVertIndex() ), Vector( 1, 0, 0 ), 25 ); #endif } // Now blend the in-between verts (if this edge is high-res). int iPrevPos = viPrevPos[ !iEdgeDim ]; int iCurPos = it.GetVertIndex()[ !iEdgeDim ]; for ( int iTween = iPrevPos+1; iTween < iCurPos; iTween++ ) { float flPercent = RemapVal( iTween, iPrevPos, iCurPos, 0, 1 ); Vector vNormal; VectorLerp( pDisp->GetNormal( viPrevPos ), pDisp->GetNormal( it.GetVertIndex() ), flPercent, vNormal ); VectorNormalize( vNormal ); CVertIndex viTween; viTween[iEdgeDim] = it.GetVertIndex()[ iEdgeDim ]; viTween[!iEdgeDim] = iTween; pDisp->SetNormal( viTween, vNormal ); #if defined( USE_SCRATCHPAD ) ScratchPad_DrawArrowSimple( g_pPad, pDisp->GetVert( viTween ), pDisp->GetNormal( viTween ), Vector( 1, 0.5, 0 ), 25 ); #endif } viPrevPos = it.GetVertIndex(); } } } } }
/* * R_TraceAgainstTriangle * * Ray-triangle intersection as per * http://geometryalgorithms.com/Archive/algorithm_0105/algorithm_0105.htm * (original paper by Dan Sunday) */ static void R_TraceAgainstTriangle( const vec_t *a, const vec_t *b, const vec_t *c ) { const vec_t *p1 = trace_start, *p2 = trace_end, *p0 = a; vec3_t u, v, w, n, p; float d1, d2, d, frac; float uu, uv, vv, wu, wv, s, t; // calculate two mostly perpendicular edge directions VectorSubtract( b, p0, u ); VectorSubtract( c, p0, v ); // we have two edge directions, we can calculate the normal CrossProduct( v, u, n ); if( VectorCompare( n, vec3_origin ) ) { return; // degenerate triangle } VectorSubtract( p2, p1, p ); d2 = DotProduct( n, p ); if( fabs( d2 ) < 0.0001 ) { return; } VectorSubtract( p1, p0, w ); d1 = -DotProduct( n, w ); // get intersect point of ray with triangle plane frac = ( d1 ) / d2; if( frac <= 0 ) { return; } if( frac >= trace_fraction ) { return; // we have hit something earlier } // calculate the impact point VectorLerp( p1, frac, p2, p ); // does p lie inside triangle? uu = DotProduct( u, u ); uv = DotProduct( u, v ); vv = DotProduct( v, v ); VectorSubtract( p, p0, w ); wu = DotProduct( w, u ); wv = DotProduct( w, v ); d = 1.0 / ( uv * uv - uu * vv ); // get and test parametric coords s = ( uv * wv - vv * wu ) * d; if( s < 0.0 || s > 1.0 ) { return; // p is outside } t = ( uv * wu - uu * wv ) * d; if( t < 0.0 || ( s + t ) > 1.0 ) { return; // p is outside } trace_fraction = frac; VectorCopy( p, trace_impact ); VectorCopy( n, trace_plane.normal ); }
// Traverse all the contacted leafs from the start to the end position. // If the trace is a point, they will be exactly in order, but for larger trace volumes it is possible to hit // something in a later leaf with a smaller intercept fraction. void CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vector3 *p1, vector3 *p2) { cNode_t *node; cplane_t *plane; float t1, t2, offset; float frac, frac2; float idist; vector3 mid; int side; float midf; if (tw->trace.fraction <= p1f) { return; // already hit something nearer } // if < 0, we are in a leaf node if (num < 0) { CM_TraceThroughLeaf( tw, &cm.leafs[-1-num] ); return; } // // find the point distances to the seperating plane // and the offset for the size of the box // node = cm.nodes + num; plane = node->plane; // adjust the plane distance appropriately for mins/maxs if ( plane->type < 3 ) { t1 = p1->data[plane->type] - plane->dist; t2 = p2->data[plane->type] - plane->dist; offset = tw->extents.data[plane->type]; } else { t1 = DotProduct (&plane->normal, p1) - plane->dist; t2 = DotProduct (&plane->normal, p2) - plane->dist; if ( tw->isPoint ) { offset = 0; } else { // this is silly offset = 2048; } } // see which sides we need to consider if ( t1 >= offset + 1 && t2 >= offset + 1 ) { CM_TraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 ); return; } if ( t1 < -offset - 1 && t2 < -offset - 1 ) { CM_TraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 ); return; } // put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side if ( t1 < t2 ) { idist = 1.0f/(t1-t2); side = 1; frac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist; frac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist; } else if (t1 > t2) { idist = 1.0f/(t1-t2); side = 0; frac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist; frac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist; } else { side = 0; frac = 1; frac2 = 0; } // move up to the node if ( frac < 0 ) { frac = 0; } if ( frac > 1 ) { frac = 1; } midf = p1f + (p2f - p1f)*frac; VectorLerp( p1, frac, p2, &mid ); CM_TraceThroughTree( tw, node->children[side], p1f, midf, p1, &mid ); // go past the node if ( frac2 < 0 ) { frac2 = 0; } if ( frac2 > 1 ) { frac2 = 1; } midf = p1f + (p2f - p1f)*frac2; VectorLerp( p1, frac, p2, &mid ); CM_TraceThroughTree( tw, node->children[side^1], midf, p2f, &mid, p2 ); }
// Handles offseting and rotation of the end points for moving and rotating entities void CM_TransformedBoxTrace( trace_t *results, const vector3 *start, const vector3 *end, const vector3 *mins, const vector3 *maxs, clipHandle_t model, int brushmask, const vector3 *origin, const vector3 *angles, int capsule ) { trace_t trace; vector3 start_l, end_l; qboolean rotated; vector3 offset; vector3 symetricSize[2]; matrix3 matrix, transpose; int i; float halfwidth; float halfheight; float t; sphere_t sphere; if ( !mins ) { mins = &vec3_origin; } if ( !maxs ) { maxs = &vec3_origin; } // adjust so that mins and maxs are always symetric, which // avoids some complications with plane expanding of rotated // bmodels for ( i = 0 ; i < 3 ; i++ ) { offset.data[i] = ( mins->data[i] + maxs->data[i] ) * 0.5f; symetricSize[0].data[i] = mins->data[i] - offset.data[i]; symetricSize[1].data[i] = maxs->data[i] - offset.data[i]; start_l.data[i] = start->data[i] + offset.data[i]; end_l.data[i] = end->data[i] + offset.data[i]; } // subtract origin offset VectorSubtract( &start_l, origin, &start_l ); VectorSubtract( &end_l, origin, &end_l ); // rotate start and end into the models frame of reference if ( model != BOX_MODEL_HANDLE && (angles->x || angles->y || angles->z) ) { rotated = qtrue; } else { rotated = qfalse; } halfwidth = symetricSize[1].x; halfheight = symetricSize[1].z; sphere.use = capsule; sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth; sphere.halfheight = halfheight; t = halfheight - sphere.radius; if (rotated) { // rotation on trace line (start-end) instead of rotating the bmodel // NOTE: This is still incorrect for bounding boxes because the actual bounding // box that is swept through the model is not rotated. We cannot rotate // the bounding box or the bmodel because that would make all the brush // bevels invalid. // However this is correct for capsules since a capsule itself is rotated too. CreateRotationMatrix(angles, matrix); RotatePoint(&start_l, matrix); RotatePoint(&end_l, matrix); // rotated sphere offset for capsule sphere.offset.x = matrix[0].z * t; sphere.offset.y = -matrix[1].z * t; sphere.offset.z = matrix[2].z * t; } else { VectorSet( &sphere.offset, 0, 0, t ); } // sweep the box through the model CM_Trace( &trace, &start_l, &end_l, &symetricSize[0], &symetricSize[1], model, origin, brushmask, capsule, &sphere ); // if the bmodel was rotated and there was a collision if ( rotated && trace.fraction != 1.0 ) { // rotation of bmodel collision plane MatrixTranspose(matrix, transpose); RotatePoint(&trace.plane.normal, transpose); } // re-calculate the end position of the trace because the trace.endpos // calculated by CM_Trace could be rotated and have an offset VectorLerp( start, trace.fraction, end, &trace.endpos ); *results = trace; }
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; }
//----------------------------------------------------------------------------- // Purpose: // Input : bool - //----------------------------------------------------------------------------- void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType ) { CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "C_TEShatterSurface 1" ); pGlassEmitter->SetSortOrigin( m_vecOrigin ); Vector vecColor; engine->ComputeLighting( m_vecOrigin, NULL, false, vecColor ); // HACK: Blend a little toward white to match the materials... VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor ); PMaterialHandle hMaterial1; PMaterialHandle hMaterial2; if (m_nSurfaceType == SHATTERSURFACE_GLASS) { hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_glass1" ); hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_glass2" ); } else { hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_tile1" ); hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_tile2" ); } // --------------------------------------------------- // Figure out number of particles required to fill space // --------------------------------------------------- int nNumWide = m_flWidth / m_flShardSize; int nNumHigh = m_flHeight / m_flShardSize; Vector vWidthStep,vHeightStep; AngleVectors(m_vecAngles,NULL,&vWidthStep,&vHeightStep); vWidthStep *= m_flShardSize; vHeightStep *= m_flShardSize; // --------------------- // Create glass shards // ---------------------- Vector vCurPos = m_vecOrigin; vCurPos.x += 0.5*m_flShardSize; vCurPos.z += 0.5*m_flShardSize; float flMinSpeed = 9999999999; float flMaxSpeed = 0; for (int width=0;width<nNumWide;width++) { for (int height=0;height<nNumHigh;height++) { Particle3D *pParticle; if (random->RandomInt(0,1)) { pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial1, vCurPos ); } else { pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial2, vCurPos ); } Vector vForceVel = Vector(0,0,0); if (random->RandomInt(0, 3) != 0) { float flForceDistSqr = (vCurPos - m_vecForcePos).LengthSqr(); vForceVel = m_vecForce; if (flForceDistSqr > 0 ) { vForceVel *= ( 40.0f / flForceDistSqr ); } } if (pParticle) { pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE); pParticle->m_vecVelocity = vForceVel; pParticle->m_vecVelocity += RandomVector(-25,25); pParticle->m_uchSize = m_flShardSize + random->RandomFloat(-0.5*m_flShardSize,0.5*m_flShardSize); pParticle->m_vAngles = m_vecAngles; pParticle->m_flAngSpeed = random->RandomFloat(-400,400); pParticle->m_uchFrontColor[0] = (int)(m_uchFrontColor[0] * vecColor.x + 0.5f); pParticle->m_uchFrontColor[1] = (int)(m_uchFrontColor[1] * vecColor.y + 0.5f); pParticle->m_uchFrontColor[2] = (int)(m_uchFrontColor[2] * vecColor.z + 0.5f); pParticle->m_uchBackColor[0] = (int)(m_uchBackColor[0] * vecColor.x + 0.5f); pParticle->m_uchBackColor[1] = (int)(m_uchBackColor[1] * vecColor.y + 0.5f); pParticle->m_uchBackColor[2] = (int)(m_uchBackColor[2] * vecColor.z + 0.5f); } // Keep track of min and max speed for collision detection float flForceSpeed = vForceVel.Length(); if (flForceSpeed > flMaxSpeed) { flMaxSpeed = flForceSpeed; } if (flForceSpeed < flMinSpeed) { flMinSpeed = flForceSpeed; } vCurPos += vHeightStep; } vCurPos -= nNumHigh*vHeightStep; vCurPos += vWidthStep; } // -------------------------------------------------- // Set collision parameters // -------------------------------------------------- Vector vMoveDir = m_vecForce; VectorNormalize(vMoveDir); pGlassEmitter->m_ParticleCollision.Setup( m_vecOrigin, &vMoveDir, GLASS_SHARD_NOISE, flMinSpeed, flMaxSpeed, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING ); }
static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp) { float *outXyz; int16_t *outNormal, *outTangent; mdvVertex_t *newVerts; int vertNum; newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts; outXyz = tess.xyz[tess.numVertexes]; outNormal = tess.normal[tess.numVertexes]; outTangent = tess.tangent[tess.numVertexes]; if (backlerp == 0) { // // just copy the vertexes // for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) { VectorCopy(newVerts->xyz, outXyz); VectorCopy4(newVerts->normal, outNormal); VectorCopy4(newVerts->tangent, outTangent); newVerts++; outXyz += 4; outNormal += 4; outTangent += 4; } } else { // // interpolate and copy the vertex and normal // mdvVertex_t *oldVerts; oldVerts = surf->verts + backEnd.currentEntity->e.oldframe * surf->numVerts; for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) { VectorLerp(newVerts->xyz, oldVerts->xyz, backlerp, outXyz); outNormal[0] = (int16_t)(newVerts->normal[0] * (1.0f - backlerp) + oldVerts->normal[0] * backlerp); outNormal[1] = (int16_t)(newVerts->normal[1] * (1.0f - backlerp) + oldVerts->normal[1] * backlerp); outNormal[2] = (int16_t)(newVerts->normal[2] * (1.0f - backlerp) + oldVerts->normal[2] * backlerp); outNormal[3] = 0; outTangent[0] = (int16_t)(newVerts->tangent[0] * (1.0f - backlerp) + oldVerts->tangent[0] * backlerp); outTangent[1] = (int16_t)(newVerts->tangent[1] * (1.0f - backlerp) + oldVerts->tangent[1] * backlerp); outTangent[2] = (int16_t)(newVerts->tangent[2] * (1.0f - backlerp) + oldVerts->tangent[2] * backlerp); outTangent[3] = newVerts->tangent[3]; newVerts++; oldVerts++; outXyz += 4; outNormal += 4; outTangent += 4; } } }
/* ============== RE_BuildSkeleton ============== */ int RE_BuildSkeleton( refSkeleton_t *skel, qhandle_t hAnim, int startFrame, int endFrame, float frac, bool clearOrigin ) { skelAnimation_t *skelAnim; skelAnim = R_GetAnimationByHandle( hAnim ); if ( skelAnim->type == animType_t::AT_IQM && skelAnim->iqm ) { return IQMBuildSkeleton( skel, skelAnim, startFrame, endFrame, frac ); } else if ( skelAnim->type == animType_t::AT_MD5 && skelAnim->md5 ) { int i; md5Animation_t *anim; md5Channel_t *channel; md5Frame_t *newFrame, *oldFrame; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; int componentsApplied; anim = skelAnim->md5; // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so // when the surfaces are rendered, they don't need to be // range checked again. /* if((startFrame >= anim->numFrames) || (startFrame < 0) || (endFrame >= anim->numFrames) || (endFrame < 0)) { Log::Debug("RE_BuildSkeleton: no such frame %d to %d for '%s'\n", startFrame, endFrame, anim->name); //startFrame = 0; //endFrame = 0; } */ startFrame = Math::Clamp( startFrame, 0, anim->numFrames - 1 ); endFrame = Math::Clamp( endFrame, 0, anim->numFrames - 1 ); // compute frame pointers oldFrame = &anim->frames[ startFrame ]; newFrame = &anim->frames[ endFrame ]; // calculate a bounding box in the current coordinate system for ( i = 0; i < 3; i++ ) { skel->bounds[ 0 ][ i ] = oldFrame->bounds[ 0 ][ i ] < newFrame->bounds[ 0 ][ i ] ? oldFrame->bounds[ 0 ][ i ] : newFrame->bounds[ 0 ][ i ]; skel->bounds[ 1 ][ i ] = oldFrame->bounds[ 1 ][ i ] > newFrame->bounds[ 1 ][ i ] ? oldFrame->bounds[ 1 ][ i ] : newFrame->bounds[ 1 ][ i ]; } for ( i = 0, channel = anim->channels; i < anim->numChannels; i++, channel++ ) { // set baseframe values VectorCopy( channel->baseOrigin, newOrigin ); VectorCopy( channel->baseOrigin, oldOrigin ); QuatCopy( channel->baseQuat, newQuat ); QuatCopy( channel->baseQuat, oldQuat ); componentsApplied = 0; // update tranlation bits if ( channel->componentsBits & COMPONENT_BIT_TX ) { oldOrigin[ 0 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; newOrigin[ 0 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_TY ) { oldOrigin[ 1 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; newOrigin[ 1 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_TZ ) { oldOrigin[ 2 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; newOrigin[ 2 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } // update quaternion rotation bits if ( channel->componentsBits & COMPONENT_BIT_QX ) { ( ( vec_t * ) oldQuat ) [ 0 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; ( ( vec_t * ) newQuat ) [ 0 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_QY ) { ( ( vec_t * ) oldQuat ) [ 1 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; ( ( vec_t * ) newQuat ) [ 1 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; componentsApplied++; } if ( channel->componentsBits & COMPONENT_BIT_QZ ) { ( ( vec_t * ) oldQuat ) [ 2 ] = oldFrame->components[ channel->componentsOffset + componentsApplied ]; ( ( vec_t * ) newQuat ) [ 2 ] = newFrame->components[ channel->componentsOffset + componentsApplied ]; } QuatCalcW( oldQuat ); QuatNormalize( oldQuat ); QuatCalcW( newQuat ); QuatNormalize( newQuat ); #if 1 VectorLerp( oldOrigin, newOrigin, frac, lerpedOrigin ); QuatSlerp( oldQuat, newQuat, frac, lerpedQuat ); #else VectorCopy( newOrigin, lerpedOrigin ); QuatCopy( newQuat, lerpedQuat ); #endif // copy lerped information to the bone + extra data skel->bones[ i ].parentIndex = channel->parentIndex; if ( channel->parentIndex < 0 && clearOrigin ) { VectorClear( skel->bones[ i ].t.trans ); QuatClear( skel->bones[ i ].t.rot ); // move bounding box back VectorSubtract( skel->bounds[ 0 ], lerpedOrigin, skel->bounds[ 0 ] ); VectorSubtract( skel->bounds[ 1 ], lerpedOrigin, skel->bounds[ 1 ] ); } else { VectorCopy( lerpedOrigin, skel->bones[ i ].t.trans ); } QuatCopy( lerpedQuat, skel->bones[ i ].t.rot ); skel->bones[ i ].t.scale = 1.0f; #if defined( REFBONE_NAMES ) Q_strncpyz( skel->bones[ i ].name, channel->name, sizeof( skel->bones[ i ].name ) ); #endif } skel->numBones = anim->numChannels; skel->type = refSkeletonType_t::SK_RELATIVE; return true; } // FIXME: clear existing bones and bounds? return false; }
/* ================== PM_RecursiveSurfCheck ================== */ msurface_t *PM_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t p1, vec3_t p2 ) { float t1, t2, frac; int side, ds, dt; mplane_t *plane; msurface_t *surf; vec3_t mid; int i; if( node->contents < 0 ) return NULL; plane = node->plane; if( plane->type < 3 ) { t1 = p1[plane->type] - plane->dist; t2 = p2[plane->type] - plane->dist; } else { t1 = DotProduct( plane->normal, p1 ) - plane->dist; t2 = DotProduct( plane->normal, p2 ) - plane->dist; } if( t1 >= 0.0f && t2 >= 0.0f ) return PM_RecursiveSurfCheck( model, node->children[0], p1, p2 ); if( t1 < 0.0f && t2 < 0.0f ) return PM_RecursiveSurfCheck( model, node->children[1], p1, p2 ); frac = t1 / ( t1 - t2 ); if( frac < 0.0f ) frac = 0.0f; if( frac > 1.0f ) frac = 1.0f; VectorLerp( p1, frac, p2, mid ); side = (t1 < 0.0f); // now this is weird. surf = PM_RecursiveSurfCheck( model, node->children[side], p1, mid ); if( surf != NULL || ( t1 >= 0.0f && t2 >= 0.0f ) || ( t1 < 0.0f && t2 < 0.0f )) { return surf; } surf = model->surfaces + node->firstsurface; for( i = 0; i < node->numsurfaces; i++, surf++ ) { ds = (int)((float)DotProduct( mid, surf->texinfo->vecs[0] ) + surf->texinfo->vecs[0][3] ); dt = (int)((float)DotProduct( mid, surf->texinfo->vecs[1] ) + surf->texinfo->vecs[1][3] ); if( ds >= surf->texturemins[0] && dt >= surf->texturemins[1] ) { int s = ds - surf->texturemins[0]; int t = dt - surf->texturemins[1]; if( s <= surf->extents[0] && t <= surf->extents[1] ) return surf; } } return PM_RecursiveSurfCheck( model, node->children[side^1], mid, p2 ); }
void FX_ThumperDust( const CEffectData &data ) { Vector vecDustColor; vecDustColor.x = 0.85f; vecDustColor.y = 0.75f; vecDustColor.z = 0.52f; CSmartPtr<ThumperDustEmitter> pSimple = ThumperDustEmitter::Create( "thumperdust" ); C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity ); if ( pEnt ) { Vector vWorldMins, vWorldMaxs; float scale = pEnt->CollisionProp()->BoundingRadius(); vWorldMins[0] = data.m_vOrigin[0] - scale; vWorldMins[1] = data.m_vOrigin[1] - scale; vWorldMins[2] = data.m_vOrigin[2] - scale; vWorldMaxs[0] = data.m_vOrigin[0] + scale; vWorldMaxs[1] = data.m_vOrigin[1] + scale; vWorldMaxs[2] = data.m_vOrigin[2] + scale; pSimple->GetBinding().SetBBox( vWorldMins, vWorldMaxs, true ); } pSimple->SetSortOrigin( data.m_vOrigin ); pSimple->SetNearClip( 32, 64 ); SimpleParticle *pParticle = NULL; Vector offset; //int numPuffs = IsXbox() ? THUMPER_MAX_PARTICLES/2 : THUMPER_MAX_PARTICLES; int numPuffs = THUMPER_MAX_PARTICLES; float flYaw = 0; float flIncr = (2*M_PI) / (float) numPuffs; // Radians Vector forward; Vector vecColor; int i = 0; float flScale = min( data.m_flScale, 255 ); // Setup the color for these particles engine->ComputeLighting( data.m_vOrigin, NULL, true, vecColor ); VectorLerp( vecColor, vecDustColor, 0.5, vecColor ); vecColor *= 255; for ( i = 0; i < numPuffs; i++ ) { flYaw += flIncr; SinCos( flYaw, &forward.y, &forward.x ); forward.z = 0.0f; offset = ( RandomVector( -4.0f, 4.0f ) + data.m_vOrigin ) + ( forward * 128.0f ); pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset ); if ( pParticle != NULL ) { pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 1.5f; Vector dir = (offset - data.m_vOrigin); float length = dir.Length(); VectorNormalize( dir ); pParticle->m_vecVelocity = dir * ( length * 2.0f ); pParticle->m_vecVelocity[2] = data.m_flScale / 3; pParticle->m_uchColor[0] = vecColor[0]; pParticle->m_uchColor[1] = vecColor[1]; pParticle->m_uchColor[2] = vecColor[2]; pParticle->m_uchStartAlpha = random->RandomInt( 64, 96 ); pParticle->m_uchEndAlpha = 0; pParticle->m_uchStartSize = flScale * 0.25f; pParticle->m_uchEndSize = flScale * 0.5f; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = random->RandomFloat( -6.0f, 6.0f ); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CNPC_VehicleDriver::OverridePathMove( float flInterval ) { // Setup our initial path data if we've just started running a path if ( !m_pCurrentWaypoint ) { m_vecPrevPoint = GetAbsOrigin(); m_vecPrevPrevPoint = GetAbsOrigin(); m_vecDesiredPosition = GetNavigator()->GetCurWaypointPos(); CalculatePostPoints(); // Init our two waypoints m_Waypoints[0] = new CVehicleWaypoint( m_vecPrevPrevPoint, m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint ); m_Waypoints[1] = new CVehicleWaypoint( m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint, m_vecPostPostPoint ); m_pCurrentWaypoint = m_Waypoints[0]; m_pNextWaypoint = m_Waypoints[1]; m_flDistanceAlongSpline = 0.2; } // Have we reached our target? See if we've passed the current waypoint's plane. Vector vecAbsMins, vecAbsMaxs; CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs ); if ( BoxOnPlaneSide( vecAbsMins, vecAbsMaxs, &m_pCurrentWaypoint->planeWaypoint ) == 3 ) { if ( WaypointReached() ) return true; } // Did we bypass it and reach the next one already? if ( m_pNextWaypoint && BoxOnPlaneSide( vecAbsMins, vecAbsMaxs, &m_pNextWaypoint->planeWaypoint ) == 3 ) { if ( WaypointReached() ) return true; } // We may have just teleported, so check to make sure we have a waypoint if ( !m_pCurrentWaypoint || !m_pNextWaypoint ) return false; // Figure out which spline we're trucking along CVehicleWaypoint *pCurrentSplineBeingTraversed = m_pCurrentWaypoint; if ( m_flDistanceAlongSpline > 1 ) { pCurrentSplineBeingTraversed = m_pNextWaypoint; } // Get our current speed, and check it against the length of the spline to know how far to advance our marker AngularImpulse angVel; Vector vecVelocity; IPhysicsObject *pVehiclePhysics = m_hVehicleEntity->VPhysicsGetObject(); if( !pVehiclePhysics ) { // I think my vehicle has been destroyed. return false; } pVehiclePhysics->GetVelocity( &vecVelocity, &angVel ); float flSpeed = vecVelocity.Length(); float flIncTime = gpGlobals->curtime - GetLastThink(); float flIncrement = flIncTime * (flSpeed / pCurrentSplineBeingTraversed->GetLength()); // Now advance our point along the spline m_flDistanceAlongSpline = clamp( m_flDistanceAlongSpline + flIncrement, 0, 2); if ( m_flDistanceAlongSpline > 1 ) { // We crossed the spline boundary pCurrentSplineBeingTraversed = m_pNextWaypoint; } Vector vSplinePoint = pCurrentSplineBeingTraversed->GetPointAt( m_flDistanceAlongSpline > 1 ? m_flDistanceAlongSpline-1 : m_flDistanceAlongSpline ); Vector vSplineTangent = pCurrentSplineBeingTraversed->GetTangentAt( m_flDistanceAlongSpline > 1 ? m_flDistanceAlongSpline-1 : m_flDistanceAlongSpline ); // Now that we've got the target spline point & tangent, use it to decide what our desired velocity is. // If we're close to the tangent, just use the tangent. Otherwise, Lerp towards it. Vector vecToDesired = (vSplinePoint - GetAbsOrigin()); float flDistToDesired = VectorNormalize( vecToDesired ); float flTangentLength = VectorNormalize( vSplineTangent ); if ( flDistToDesired > (flTangentLength * 0.75) ) { m_vecDesiredVelocity = vecToDesired * flTangentLength; } else { VectorLerp( vSplineTangent, vecToDesired * flTangentLength, (flDistToDesired / (flTangentLength * 0.5)), m_vecDesiredVelocity ); } // Decrease speed according to the turn we're trying to make Vector vecRight; m_hVehicleEntity->GetVectors( NULL, &vecRight, NULL ); Vector vecNormVel = m_vecDesiredVelocity; VectorNormalize( vecNormVel ); float flDotRight = DotProduct( vecRight, vecNormVel ); flSpeed = (1.0 - fabs(flDotRight)); // Don't go slower than we've been told to go if ( flSpeed < m_flDriversMinSpeed ) { flSpeed = m_flDriversMinSpeed; } m_vecDesiredVelocity = vecNormVel * (flSpeed * m_flMaxSpeed); // Bunch o'debug if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH ) { NDebugOverlay::Box( m_vecPrevPrevPoint, -Vector(15,15,15), Vector(15,15,15), 192,0,0, true, 0.1); NDebugOverlay::Box( m_vecPrevPoint, -Vector(20,20,20), Vector(20,20,20), 255,0,0, true, 0.1); NDebugOverlay::Box( m_vecPostPoint, -Vector(20,20,20), Vector(20,20,20), 0,192,0, true, 0.1); NDebugOverlay::Box( m_vecPostPostPoint, -Vector(20,20,20), Vector(20,20,20), 0,128,0, true, 0.1); NDebugOverlay::Box( vSplinePoint, -Vector(10,10,10), Vector(10,10,10), 0,0,255, true, 0.1); NDebugOverlay::Line( vSplinePoint, vSplinePoint + (vSplineTangent * 40), 0,0,255, true, 0.1); //NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[0], pCurrentSplineBeingTraversed->splinePoints[1], 30, 255,255,255,0, false, 0.1f ); //NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[1], pCurrentSplineBeingTraversed->splinePoints[2], 20, 255,255,255,0, false, 0.1f ); //NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[2], pCurrentSplineBeingTraversed->splinePoints[3], 10, 255,255,255,0, false, 0.1f ); // Draw the plane we're checking against for waypoint passing Vector vecPlaneRight; CrossProduct( m_pCurrentWaypoint->planeWaypoint.normal, Vector(0,0,1), vecPlaneRight ); Vector vecPlane = m_pCurrentWaypoint->splinePoints[2]; NDebugOverlay::Line( vecPlane + (vecPlaneRight * -100), vecPlane + (vecPlaneRight * 100), 255,0,0, true, 0.1); // Draw the next plane too CrossProduct( m_pNextWaypoint->planeWaypoint.normal, Vector(0,0,1), vecPlaneRight ); vecPlane = m_pNextWaypoint->splinePoints[2]; NDebugOverlay::Line( vecPlane + (vecPlaneRight * -100), vecPlane + (vecPlaneRight * 100), 192,0,0, true, 0.1); } if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH_SPLINE ) { for ( int i = 0; i < 10; i++ ) { Vector vecTarget = m_pCurrentWaypoint->GetPointAt( 0.1 * i ); Vector vecTangent = m_pCurrentWaypoint->GetTangentAt( 0.1 * i ); VectorNormalize(vecTangent); NDebugOverlay::Box( vecTarget, -Vector(10,10,10), Vector(10,10,10), 255,0,0, true, 0.1 ); NDebugOverlay::Line( vecTarget, vecTarget + (vecTangent * 10), 255,255,0, true, 0.1); } } return true; }
/* * CG_AddWeaponOnTag * * Add weapon model(s) positioned at the tag */ void CG_AddWeaponOnTag( entity_t *ent, orientation_t *tag, int weaponid, int effects, orientation_t *projectionSource, unsigned int flash_time, unsigned int barrel_time ) { entity_t weapon; weaponinfo_t *weaponInfo; float intensity; //don't try without base model if( !ent->model ) return; //don't try without a tag if( !tag ) return; weaponInfo = CG_GetWeaponInfo( weaponid ); if( !weaponInfo ) return; //if( ent->renderfx & RF_WEAPONMODEL ) // effects &= ~EF_RACEGHOST; //weapon memset( &weapon, 0, sizeof( weapon ) ); Vector4Set( weapon.shaderRGBA, 255, 255, 255, 255 ); weapon.scale = ent->scale; weapon.renderfx = ent->renderfx; weapon.frame = 0; weapon.oldframe = 0; weapon.model = weaponInfo->model[WEAPON]; CG_PlaceModelOnTag( &weapon, ent, tag ); CG_AddColoredOutLineEffect( &weapon, effects, 0, 0, 0, 255 ); if( !( effects & EF_RACEGHOST ) ) CG_AddEntityToScene( &weapon ); if( !weapon.model ) return; CG_AddShellEffects( &weapon, effects ); // update projection source if( projectionSource != NULL ) { VectorCopy( vec3_origin, projectionSource->origin ); Matrix3_Copy( axis_identity, projectionSource->axis ); CG_MoveToTag( projectionSource->origin, projectionSource->axis, weapon.origin, weapon.axis, weaponInfo->tag_projectionsource.origin, weaponInfo->tag_projectionsource.axis ); } //expansion if( ( effects & EF_STRONG_WEAPON ) && weaponInfo->model[EXPANSION] ) { if( CG_GrabTag( tag, &weapon, "tag_expansion" ) ) { entity_t expansion; memset( &expansion, 0, sizeof( expansion ) ); Vector4Set( expansion.shaderRGBA, 255, 255, 255, 255 ); expansion.model = weaponInfo->model[EXPANSION]; expansion.scale = ent->scale; expansion.renderfx = ent->renderfx; expansion.frame = 0; expansion.oldframe = 0; CG_PlaceModelOnTag( &expansion, &weapon, tag ); CG_AddColoredOutLineEffect( &expansion, effects, 0, 0, 0, 255 ); if( !( effects & EF_RACEGHOST ) ) CG_AddEntityToScene( &expansion ); // skelmod CG_AddShellEffects( &expansion, effects ); } } // barrel if( weaponInfo->model[BARREL] ) { if( CG_GrabTag( tag, &weapon, "tag_barrel" ) ) { orientation_t barrel_recoiled; vec3_t rotangles = { 0, 0, 0 }; entity_t barrel; memset( &barrel, 0, sizeof( barrel ) ); Vector4Set( barrel.shaderRGBA, 255, 255, 255, 255 ); barrel.model = weaponInfo->model[BARREL]; barrel.scale = ent->scale; barrel.renderfx = ent->renderfx; barrel.frame = 0; barrel.oldframe = 0; // rotation if( barrel_time > cg.time ) { intensity = (float)( barrel_time - cg.time ) / (float)weaponInfo->barrelTime; rotangles[2] = ( 360.0f * weaponInfo->barrelSpeed * intensity * intensity ); while( rotangles[2] > 360 ) rotangles[2] -= 360; // Check for tag_recoil if( CG_GrabTag( &barrel_recoiled, &weapon, "tag_recoil" ) ) VectorLerp( tag->origin, intensity, barrel_recoiled.origin, tag->origin ); } AnglesToAxis( rotangles, barrel.axis ); // barrel requires special tagging CG_PlaceRotatedModelOnTag( &barrel, &weapon, tag ); CG_AddColoredOutLineEffect( &barrel, effects, 0, 0, 0, 255 ); if( !( effects & EF_RACEGHOST ) ) CG_AddEntityToScene( &barrel ); // skelmod CG_AddShellEffects( &barrel, effects ); } } if( flash_time < cg.time ) return; // flash if( !CG_GrabTag( tag, &weapon, "tag_flash" ) ) return; if( weaponInfo->model[FLASH] ) { entity_t flash; qbyte c; if( weaponInfo->flashFade ) { intensity = (float)( flash_time - cg.time )/(float)weaponInfo->flashTime; c = ( qbyte )( 255 * intensity ); } else { intensity = 1.0f; c = 255; } memset( &flash, 0, sizeof( flash ) ); Vector4Set( flash.shaderRGBA, c, c, c, c ); flash.model = weaponInfo->model[FLASH]; flash.scale = ent->scale; flash.renderfx = ent->renderfx | RF_NOSHADOW; flash.frame = 0; flash.oldframe = 0; CG_PlaceModelOnTag( &flash, &weapon, tag ); if( !( effects & EF_RACEGHOST ) ) CG_AddEntityToScene( &flash ); CG_AddLightToScene( flash.origin, weaponInfo->flashRadius * intensity, weaponInfo->flashColor[0], weaponInfo->flashColor[1], weaponInfo->flashColor[2] ); } }
void V_CalcViewBlend(void) { float a2; int j; r_refdef.viewblend[0] = 0; r_refdef.viewblend[1] = 0; r_refdef.viewblend[2] = 0; r_refdef.viewblend[3] = 0; r_refdef.frustumscale_x = 1; r_refdef.frustumscale_y = 1; if (cls.state == ca_connected && cls.signon == SIGNONS) { // set contents color int supercontents; vec3_t vieworigin; Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, vieworigin); supercontents = CL_PointSuperContents(vieworigin); if (supercontents & SUPERCONTENTS_LIQUIDSMASK) { r_refdef.frustumscale_x *= 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); r_refdef.frustumscale_y *= 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); if (supercontents & SUPERCONTENTS_LAVA) { cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 255; cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80; cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0; } else if (supercontents & SUPERCONTENTS_SLIME) { cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0; cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 25; cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 5; } else { cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 130; cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 80; cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 50; } cl.cshifts[CSHIFT_CONTENTS].percent = 150 * 0.5; } else { cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0; cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 0; cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0; cl.cshifts[CSHIFT_CONTENTS].percent = 0; } if (gamemode != GAME_TRANSFUSION) { if (cl.stats[STAT_ITEMS] & IT_QUAD) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; cl.cshifts[CSHIFT_POWERUP].percent = 30; } else if (cl.stats[STAT_ITEMS] & IT_SUIT) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; cl.cshifts[CSHIFT_POWERUP].percent = 20; } else if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; cl.cshifts[CSHIFT_POWERUP].percent = 100; } else if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) { cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; cl.cshifts[CSHIFT_POWERUP].percent = 30; } else cl.cshifts[CSHIFT_POWERUP].percent = 0; } cl.cshifts[CSHIFT_VCSHIFT].destcolor[0] = v_cshift.destcolor[0]; cl.cshifts[CSHIFT_VCSHIFT].destcolor[1] = v_cshift.destcolor[1]; cl.cshifts[CSHIFT_VCSHIFT].destcolor[2] = v_cshift.destcolor[2]; cl.cshifts[CSHIFT_VCSHIFT].percent = v_cshift.percent; // LordHavoc: fixed V_CalcBlend for (j = 0;j < NUM_CSHIFTS;j++) { a2 = bound(0.0f, cl.cshifts[j].percent * (1.0f / 255.0f), 1.0f); if (a2 > 0) { VectorLerp(r_refdef.viewblend, a2, cl.cshifts[j].destcolor, r_refdef.viewblend); r_refdef.viewblend[3] = (1 - (1 - r_refdef.viewblend[3]) * (1 - a2)); // correct alpha multiply... took a while to find it on the web } } // saturate color (to avoid blending in black) if (r_refdef.viewblend[3]) { a2 = 1 / r_refdef.viewblend[3]; VectorScale(r_refdef.viewblend, a2, r_refdef.viewblend); } r_refdef.viewblend[0] = bound(0.0f, r_refdef.viewblend[0], 255.0f); r_refdef.viewblend[1] = bound(0.0f, r_refdef.viewblend[1], 255.0f); r_refdef.viewblend[2] = bound(0.0f, r_refdef.viewblend[2], 255.0f); r_refdef.viewblend[3] = bound(0.0f, r_refdef.viewblend[3] * gl_polyblend.value, 1.0f); if (vid.sRGB3D) { r_refdef.viewblend[0] = Image_LinearFloatFromsRGB(r_refdef.viewblend[0]); r_refdef.viewblend[1] = Image_LinearFloatFromsRGB(r_refdef.viewblend[1]); r_refdef.viewblend[2] = Image_LinearFloatFromsRGB(r_refdef.viewblend[2]); } else { r_refdef.viewblend[0] *= (1.0f/256.0f); r_refdef.viewblend[1] *= (1.0f/256.0f); r_refdef.viewblend[2] *= (1.0f/256.0f); } // Samual: Ugly hack, I know. But it's the best we can do since // there is no way to detect client states from the engine. if (cl.stats[STAT_HEALTH] <= 0 && cl.stats[STAT_HEALTH] != -666 && cl.stats[STAT_HEALTH] != -2342 && cl_deathfade.value > 0) { cl.deathfade += cl_deathfade.value * max(0.00001, cl.time - cl.oldtime); cl.deathfade = bound(0.0f, cl.deathfade, 0.9f); } else cl.deathfade = 0.0f; if(cl.deathfade > 0) { float a; float deathfadevec[3] = {0.3f, 0.0f, 0.0f}; a = r_refdef.viewblend[3] + cl.deathfade - r_refdef.viewblend[3]*cl.deathfade; if(a > 0) VectorMAM(r_refdef.viewblend[3] * (1 - cl.deathfade) / a, r_refdef.viewblend, cl.deathfade / a, deathfadevec, r_refdef.viewblend); r_refdef.viewblend[3] = a; } } }
void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, const Vector &vPre, const Vector &vStart, const Vector &vEnd, const Vector &vNext, float f, Vector &vOut ) { vOut.Init(); switch ( interpolationType ) { default: Warning( "Unknown interpolation type %d\n", (int)interpolationType ); // break; // Fall through and use catmull_rom as default case INTERPOLATE_CATMULL_ROM_NORMALIZEX: case INTERPOLATE_DEFAULT: case INTERPOLATE_CATMULL_ROM: case INTERPOLATE_CATMULL_ROM_NORMALIZE: case INTERPOLATE_CATMULL_ROM_TANGENT: Catmull_Rom_Spline( vPre, vStart, vEnd, vNext, f, vOut ); break; case INTERPOLATE_EASE_IN: { f = sin( M_PI * f * 0.5f ); // Fixme, since this ignores vPre and vNext we could omit computing them aove VectorLerp( vStart, vEnd, f, vOut ); } break; case INTERPOLATE_EASE_OUT: { f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); // Fixme, since this ignores vPre and vNext we could omit computing them aove VectorLerp( vStart, vEnd, f, vOut ); } break; case INTERPOLATE_EASE_INOUT: { f = SimpleSpline( f ); // Fixme, since this ignores vPre and vNext we could omit computing them aove VectorLerp( vStart, vEnd, f, vOut ); } break; case INTERPOLATE_LINEAR_INTERP: // Fixme, since this ignores vPre and vNext we could omit computing them aove VectorLerp( vStart, vEnd, f, vOut ); break; case INTERPOLATE_KOCHANEK_BARTELS: case INTERPOLATE_KOCHANEK_BARTELS_EARLY: case INTERPOLATE_KOCHANEK_BARTELS_LATE: { float t, b, c; Interpolator_GetKochanekBartelsParams( interpolationType, t, b, c ); Kochanek_Bartels_Spline ( t, b, c, vPre, vStart, vEnd, vNext, f, vOut ); } break; case INTERPOLATE_SIMPLE_CUBIC: Cubic_Spline( vPre, vStart, vEnd, vNext, f, vOut ); break; case INTERPOLATE_BSPLINE: BSpline( vPre, vStart, vEnd, vNext, f, vOut ); break; case INTERPOLATE_EXPONENTIAL_DECAY: { float dt = vEnd.x - vStart.x; if ( dt > 0.0f ) { float val = 1.0f - ExponentialDecay( 0.001, dt, f * dt ); vOut.y = vStart.y + val * ( vEnd.y - vStart.y ); } else { vOut.y = vStart.y; } } break; case INTERPOLATE_HOLD: { vOut.y = vStart.y; } break; } }
void ScratchPad_DrawLitCylinder( IScratchPad3D *pPad, const Vector &v1, const Vector &v2, const Vector &vBrightColor, const Vector &vDarkColor, const Vector &vLightDir, float width, int nSegments ) { // Make orthogonal vectors. Vector vDir = v2 - v1; VectorNormalize( vDir ); Vector vRight, vUp; VectorVectors( vDir, vRight, vUp ); vRight *= width; vUp *= width; // Setup the top and bottom caps. CSPVertList topCap, bottomCap, quad; topCap.m_Verts.SetSize( nSegments ); bottomCap.m_Verts.SetSize( nSegments ); quad.m_Verts.SetSize( 4 ); float flDot = -vLightDir.Dot( vDir ); Vector topColor, bottomColor; VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), topColor ); VectorLerp( vDarkColor, vBrightColor, RemapVal( -flDot, -1, 1, 0, 1 ), bottomColor ); // Draw each quad. Vector vPrevTop = v1 + vRight; Vector vPrevBottom = v2 + vRight; for ( int i=0; i < nSegments; i++ ) { float flAngle = (float)(i+1) * M_PI * 2.0 / nSegments; Vector vOffset = vRight * cos( flAngle ) + vUp * sin( flAngle ); Vector vCurTop = v1 + vOffset; Vector vCurBottom = v2 + vOffset; // Now light it. VectorNormalize( vOffset ); flDot = -vLightDir.Dot( vOffset ); Vector vColor; VectorLerp( vDarkColor, vBrightColor, RemapVal( flDot, -1, 1, 0, 1 ), vColor ); // Draw the quad. quad.m_Verts[0] = CSPVert( vPrevTop, vColor ); quad.m_Verts[1] = CSPVert( vPrevBottom, vColor ); quad.m_Verts[2] = CSPVert( vCurBottom, vColor ); quad.m_Verts[3] = CSPVert( vCurTop, vColor ); pPad->DrawPolygon( quad ); topCap.m_Verts[i] = CSPVert( vCurTop, topColor ); bottomCap.m_Verts[i] = CSPVert( vCurBottom, bottomColor ); } pPad->DrawPolygon( topCap ); pPad->DrawPolygon( bottomCap ); }
void CLagCompensationManager::BacktrackEntity( CAI_BaseNPC *pEntity, float flTargetTime ) { Vector org, mins, maxs; QAngle ang; VPROF_BUDGET( "BacktrackEntity", "CLagCompensationManager" ); // get track history of this entity int index = pEntity->GetAIIndex(); CUtlFixedLinkedList< LagRecord > *track = &m_EntityTrack[ index ]; // check if we have at leat one entry if ( track->Count() <= 0 ) return; int curr = track->Head(); LagRecord *prevRecord = NULL; LagRecord *record = NULL; Vector prevOrg = pEntity->GetLocalOrigin(); // Walk context looking for any invalidating event while( track->IsValidIndex(curr) ) { // remember last record prevRecord = record; // get next record record = &track->Element( curr ); if ( !(record->m_fFlags & LC_ALIVE) ) { // entity must be alive, lost track return; } Vector delta = record->m_vecOrigin - prevOrg; if ( delta.LengthSqr() > LAG_COMPENSATION_TELEPORTED_DISTANCE_SQR ) { // lost track, moved too far (may have teleported) return; } // did we find a context smaller than target time ? if ( record->m_flSimulationTime <= flTargetTime ) break; // hurra, stop prevOrg = record->m_vecOrigin; // go one step back in time curr = track->Next( curr ); } Assert( record ); if ( !record ) { if ( sv_unlag_debug.GetBool() ) { DevMsg( "No valid positions in history for BacktrackEntity ( %s )\n", pEntity->GetClassname() ); } return; // that should never happen } float frac = 0.0f; if ( prevRecord && (record->m_flSimulationTime < flTargetTime) && (record->m_flSimulationTime < prevRecord->m_flSimulationTime) ) { // we didn't find the exact time but have a valid previous record // so interpolate between these two records; Assert( prevRecord->m_flSimulationTime > record->m_flSimulationTime ); Assert( flTargetTime < prevRecord->m_flSimulationTime ); // calc fraction between both records frac = ( flTargetTime - record->m_flSimulationTime ) / ( prevRecord->m_flSimulationTime - record->m_flSimulationTime ); Assert( frac > 0 && frac < 1 ); // should never extrapolate ang = Lerp( frac, record->m_vecAngles, prevRecord->m_vecAngles ); org = Lerp( frac, record->m_vecOrigin, prevRecord->m_vecOrigin ); mins = Lerp( frac, record->m_vecMins, prevRecord->m_vecMins ); maxs = Lerp( frac, record->m_vecMaxs, prevRecord->m_vecMaxs ); } else { // we found the exact record or no other record to interpolate with // just copy these values since they are the best we have ang = record->m_vecAngles; org = record->m_vecOrigin; mins = record->m_vecMins; maxs = record->m_vecMaxs; } // See if this is still a valid position for us to teleport to if ( sv_unlag_fixstuck.GetBool() ) { // Try to move to the wanted position from our current position. trace_t tr; UTIL_TraceEntity( pEntity, org, org, MASK_NPCSOLID, &tr ); if ( tr.startsolid || tr.allsolid ) { if ( sv_unlag_debug.GetBool() ) DevMsg( "WARNING: BackupEntity trying to back entity into a bad position - %s\n", pEntity->GetClassname() ); CBasePlayer *pHitPlayer = dynamic_cast<CBasePlayer *>( tr.m_pEnt ); // don't lag compensate the current player if ( pHitPlayer && ( pHitPlayer != m_pCurrentPlayer ) ) { // If we haven't backtracked this player, do it now // this deliberately ignores WantsLagCompensationOnEntity. if ( !m_RestorePlayer.Get( pHitPlayer->entindex() - 1 ) ) { // prevent recursion - save a copy of m_RestorePlayer, // pretend that this player is off-limits int pl_index = pEntity->entindex() - 1; // Temp turn this flag on m_RestorePlayer.Set( pl_index ); BacktrackPlayer( pHitPlayer, flTargetTime ); // Remove the temp flag m_RestorePlayer.Clear( pl_index ); } } else { CAI_BaseNPC *pHitEntity = dynamic_cast<CAI_BaseNPC *>( tr.m_pEnt ); if ( pHitEntity ) { CAI_BaseNPC *pNPC = NULL; CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) // we'll have to find this entity's index though :( { pNPC = ppAIs[i]; if ( pNPC == pHitEntity ) break; } // If we haven't backtracked this player, do it now // this deliberately ignores WantsLagCompensationOnEntity. if ( pNPC && !m_RestoreEntity.Get( pNPC->GetAIIndex() ) ) { // prevent recursion - save a copy of m_RestoreEntity, // pretend that this player is off-limits // Temp turn this flag on m_RestoreEntity.Set( pNPC->GetAIIndex() ); BacktrackEntity( pHitEntity, flTargetTime ); // Remove the temp flag m_RestoreEntity.Clear( pNPC->GetAIIndex() ); } } } // now trace us back as far as we can go UTIL_TraceEntity( pEntity, pEntity->GetLocalOrigin(), org, MASK_NPCSOLID, &tr ); if ( tr.startsolid || tr.allsolid ) { // Our starting position is bogus if ( sv_unlag_debug.GetBool() ) DevMsg( "Backtrack failed completely, bad starting position\n" ); } else { // We can get to a valid place, but not all the way to the target Vector vPos; VectorLerp( pEntity->GetLocalOrigin(), org, tr.fraction * g_flFractionScale, vPos ); // This is as close as we're going to get org = vPos; if ( sv_unlag_debug.GetBool() ) DevMsg( "Backtrack got most of the way\n" ); } } } // See if this represents a change for the entity int flags = 0; LagRecord *restore = &m_EntityRestoreData[ index ]; LagRecord *change = &m_EntityChangeData[ index ]; QAngle angdiff = pEntity->GetLocalAngles() - ang; Vector orgdiff = pEntity->GetLocalOrigin() - org; // Always remember the pristine simulation time in case we need to restore it. restore->m_flSimulationTime = pEntity->GetSimulationTime(); if ( angdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR ) { flags |= LC_ANGLES_CHANGED; restore->m_vecAngles = pEntity->GetLocalAngles(); pEntity->SetLocalAngles( ang ); change->m_vecAngles = ang; } // Use absolute equality here if ( ( mins != pEntity->WorldAlignMins() ) || ( maxs != pEntity->WorldAlignMaxs() ) ) { flags |= LC_SIZE_CHANGED; restore->m_vecMins = pEntity->WorldAlignMins() ; restore->m_vecMaxs = pEntity->WorldAlignMaxs(); pEntity->SetSize( mins, maxs ); change->m_vecMins = mins; change->m_vecMaxs = maxs; } // Note, do origin at end since it causes a relink into the k/d tree if ( orgdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR ) { flags |= LC_ORIGIN_CHANGED; restore->m_vecOrigin = pEntity->GetLocalOrigin(); pEntity->SetLocalOrigin( org ); change->m_vecOrigin = org; } // Sorry for the loss of the optimization for the case of people // standing still, but you breathe even on the server. // This is quicker than actually comparing all bazillion floats. flags |= LC_ANIMATION_CHANGED; restore->m_masterSequence = pEntity->GetSequence(); restore->m_masterCycle = pEntity->GetCycle(); bool interpolationAllowed = false; if( prevRecord && (record->m_masterSequence == prevRecord->m_masterSequence) ) { // If the master state changes, all layers will be invalid too, so don't interp (ya know, interp barely ever happens anyway) interpolationAllowed = true; } //////////////////////// // First do the master settings bool interpolatedMasters = false; if( frac > 0.0f && interpolationAllowed ) { interpolatedMasters = true; pEntity->SetSequence( Lerp( frac, record->m_masterSequence, prevRecord->m_masterSequence ) ); pEntity->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) ); if( record->m_masterCycle > prevRecord->m_masterCycle ) { // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0 // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example. float newCycle = Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle + 1 ); pEntity->SetCycle(newCycle < 1 ? newCycle : newCycle - 1 );// and make sure .9 to 1.2 does not end up 1.05 } else { pEntity->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) ); } } if( !interpolatedMasters ) { pEntity->SetSequence(record->m_masterSequence); pEntity->SetCycle(record->m_masterCycle); } //////////////////////// // Now do all the layers int layerCount = pEntity->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pEntity->GetAnimOverlay(layerIndex); if( currentLayer ) { restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; bool interpolated = false; if( (frac > 0.0f) && interpolationAllowed ) { LayerRecord &recordsLayerRecord = record->m_layerRecords[layerIndex]; LayerRecord &prevRecordsLayerRecord = prevRecord->m_layerRecords[layerIndex]; if( (recordsLayerRecord.m_order == prevRecordsLayerRecord.m_order) && (recordsLayerRecord.m_sequence == prevRecordsLayerRecord.m_sequence) ) { // We can't interpolate across a sequence or order change interpolated = true; if( recordsLayerRecord.m_cycle > prevRecordsLayerRecord.m_cycle ) { // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0 // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example. float newCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle + 1 ); currentLayer->m_flCycle = newCycle < 1 ? newCycle : newCycle - 1;// and make sure .9 to 1.2 does not end up 1.05 } else { currentLayer->m_flCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle ); } currentLayer->m_nOrder = recordsLayerRecord.m_order; currentLayer->m_nSequence = recordsLayerRecord.m_sequence; currentLayer->m_flWeight = Lerp( frac, recordsLayerRecord.m_weight, prevRecordsLayerRecord.m_weight ); } } if( !interpolated ) { //Either no interp, or interp failed. Just use record. currentLayer->m_flCycle = record->m_layerRecords[layerIndex].m_cycle; currentLayer->m_nOrder = record->m_layerRecords[layerIndex].m_order; currentLayer->m_nSequence = record->m_layerRecords[layerIndex].m_sequence; currentLayer->m_flWeight = record->m_layerRecords[layerIndex].m_weight; } } } if ( !flags ) return; // we didn't change anything if ( sv_lagflushbonecache.GetBool() ) pEntity->InvalidateBoneCache(); /*char text[256]; Q_snprintf( text, sizeof(text), "time %.2f", flTargetTime ); pEntity->DrawServerHitboxes( 10 ); NDebugOverlay::Text( org, text, false, 10 ); NDebugOverlay::EntityBounds( pEntity, 255, 0, 0, 32, 10 ); */ m_RestoreEntity.Set( index ); //remember that we changed this entity m_bNeedToRestore = true; // we changed at least one player / entity restore->m_fFlags = flags; // we need to restore these flags change->m_fFlags = flags; // we have changed these flags if( sv_showlagcompensation.GetInt() == 1 ) { pEntity->DrawServerHitboxes(4, true); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPointCommentaryNode::UpdateViewThink( void ) { if ( !m_bActive ) return; CBasePlayer *pPlayer = GetCommentaryPlayer(); if ( !pPlayer ) return; // Swing the view towards the target if ( m_hViewTarget ) { QAngle angGoal; QAngle angCurrent; if ( m_hViewPositionMover ) { angCurrent = m_hViewPositionMover->GetAbsAngles(); VectorAngles( m_hViewTarget->WorldSpaceCenter() - m_hViewPositionMover->GetAbsOrigin(), angGoal ); } else { angCurrent = pPlayer->EyeAngles(); VectorAngles( m_hViewTarget->WorldSpaceCenter() - pPlayer->EyePosition(), angGoal ); } // Accelerate towards the target goal angles float dx = AngleDiff( angGoal.x, angCurrent.x ); float dy = AngleDiff( angGoal.y, angCurrent.y ); float mod = 1.0 - ExponentialDecay( 0.5, 0.3, gpGlobals->frametime ); float dxmod = dx * mod; float dymod = dy * mod; angCurrent.x = AngleNormalize( angCurrent.x + dxmod ); angCurrent.y = AngleNormalize( angCurrent.y + dymod ); if ( m_hViewPositionMover ) { m_hViewPositionMover->SetAbsAngles( angCurrent ); } else { pPlayer->SnapEyeAngles( angCurrent ); } SetNextThink( gpGlobals->curtime, s_pCommentaryUpdateViewThink ); } if ( m_hViewPosition.Get() ) { if ( pPlayer->GetActiveWeapon() ) { pPlayer->GetActiveWeapon()->Holster(); } if ( !m_hViewPositionMover ) { // Make an invisible info target entity for us to attach the view to, // and move it to the desired view position. m_hViewPositionMover = CreateEntityByName( "env_laserdot" ); m_hViewPositionMover->SetAbsAngles( pPlayer->EyeAngles() ); pPlayer->SetViewEntity( m_hViewPositionMover ); } // Blend to the target position over time. float flCurTime = (gpGlobals->curtime - m_flStartTime); float flBlendPerc = clamp( flCurTime / 2.0, 0, 1 ); // Figure out the current view position Vector vecCurEye; VectorLerp( pPlayer->EyePosition(), m_hViewPosition.Get()->GetAbsOrigin(), flBlendPerc, vecCurEye ); m_hViewPositionMover->SetAbsOrigin( vecCurEye ); SetNextThink( gpGlobals->curtime, s_pCommentaryUpdateViewThink ); } }
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; }
Vector4D VectorLerp(const Vector4D& src1, const Vector4D& src2, vec_t t) { Vector4D result; VectorLerp(src1, src2, t, result); return result; }