// This gets an AABB for the renderable, but it doesn't cause a parent's bones to be setup. // This is used for placement in the leaves, but the more expensive version is used for culling. void CalcRenderableWorldSpaceAABB_Fast( IClientRenderable *pRenderable, Vector &absMin, Vector &absMax ) { C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity(); if ( pEnt && pEnt->IsFollowingEntity() ) { C_BaseEntity *pParent = pEnt->GetMoveParent(); Assert( pParent ); // Get the parent's abs space world bounds. CalcRenderableWorldSpaceAABB_Fast( pParent, absMin, absMax ); // Add the maximum of our local render bounds. This is making the assumption that we can be at any // point and at any angle within the parent's world space bounds. Vector vAddMins, vAddMaxs; pEnt->GetRenderBounds( vAddMins, vAddMaxs ); // if our origin is actually farther away than that, expand again float radius = pEnt->GetLocalOrigin().Length(); float flBloatSize = max( vAddMins.Length(), vAddMaxs.Length() ); flBloatSize = max(flBloatSize, radius); absMin -= Vector( flBloatSize, flBloatSize, flBloatSize ); absMax += Vector( flBloatSize, flBloatSize, flBloatSize ); } else { // Start out with our own render bounds. Since we don't have a parent, this won't incur any nasty CalcRenderableWorldSpaceAABB( pRenderable, absMin, absMax ); } }
//----------------------------------------------------------------------------- // Helper functions. //----------------------------------------------------------------------------- void DefaultRenderBoundsWorldspace( IClientRenderable *pRenderable, Vector &absMins, Vector &absMaxs ) { // Tracker 37433: This fixes a bug where if the stunstick is being wielded by a combine soldier, the fact that the stick was // attached to the soldier's hand would move it such that it would get frustum culled near the edge of the screen. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity(); if ( pEnt && pEnt->IsFollowingEntity() ) { C_BaseEntity *pParent = pEnt->GetFollowedEntity(); if ( pParent ) { // Get the parent's abs space world bounds. CalcRenderableWorldSpaceAABB_Fast( pParent, absMins, absMaxs ); // Add the maximum of our local render bounds. This is making the assumption that we can be at any // point and at any angle within the parent's world space bounds. Vector vAddMins, vAddMaxs; pEnt->GetRenderBounds( vAddMins, vAddMaxs ); // if our origin is actually farther away than that, expand again float radius = pEnt->GetLocalOrigin().Length(); float flBloatSize = max( vAddMins.Length(), vAddMaxs.Length() ); flBloatSize = max(flBloatSize, radius); absMins -= Vector( flBloatSize, flBloatSize, flBloatSize ); absMaxs += Vector( flBloatSize, flBloatSize, flBloatSize ); return; } } Vector mins, maxs; pRenderable->GetRenderBounds( mins, maxs ); // FIXME: Should I just use a sphere here? // Another option is to pass the OBB down the tree; makes for a better fit // Generate a world-aligned AABB const QAngle& angles = pRenderable->GetRenderAngles(); const Vector& origin = pRenderable->GetRenderOrigin(); if (angles == vec3_angle) { VectorAdd( mins, origin, absMins ); VectorAdd( maxs, origin, absMaxs ); } else { matrix3x4_t boxToWorld; AngleMatrix( angles, origin, boxToWorld ); TransformAABB( boxToWorld, mins, maxs, absMins, absMaxs ); } Assert( absMins.IsValid() && absMaxs.IsValid() ); }
void C_Camera::CalcTVCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) { if (!GetMatchBall()) return; C_BaseEntity *pTarget; bool atMinGoalPos; Vector targetPos; int tvcamMode = GetTVCamMode(); if (GetReplayManager() && GetReplayManager()->IsReplaying()) { pTarget = GetReplayBall(); if (!pTarget) return; atMinGoalPos = GetReplayManager()->m_bAtMinGoalPos; targetPos = pTarget->GetLocalOrigin(); } else { if (GetMatchBall() && GetMatchBall()->m_eBallState == BALL_STATE_GOAL) { pTarget = GetMatchBall()->m_pLastActivePlayer; if (!pTarget) pTarget = GetMatchBall(); atMinGoalPos = pTarget->GetLocalOrigin().y < SDKGameRules()->m_vKickOff.GetY(); targetPos = pTarget->GetLocalOrigin(); } else { pTarget = CBasePlayer::GetLocalPlayer()->GetObserverTarget(); if (!pTarget) pTarget = GetMatchBall(); atMinGoalPos = pTarget->GetLocalOrigin().y < SDKGameRules()->m_vKickOff.GetY(); targetPos = pTarget->GetLocalOrigin(); // Move the camera towards the defending team's goal if (GetMatchBall()->m_nLastActiveTeam != TEAM_NONE) { if (m_nLastPossessingTeam == TEAM_NONE) { m_nLastPossessingTeam = GetMatchBall()->m_nLastActiveTeam; m_flLastPossessionChange = gpGlobals->curtime; m_flPossCoeff = 0; m_flOldPossCoeff = 0; } else { if (GetMatchBall()->m_nLastActiveTeam != m_nLastPossessingTeam) { m_nLastPossessingTeam = GetMatchBall()->m_nLastActiveTeam; m_flLastPossessionChange = gpGlobals->curtime; m_flOldPossCoeff = m_flPossCoeff; } float timeFrac = min(1.0f, (gpGlobals->curtime - m_flLastPossessionChange) / mp_tvcam_offset_forward_time.GetFloat()); float frac = pow(timeFrac, 2) * (3 - 2 * timeFrac); m_flPossCoeff = Lerp(frac, m_flOldPossCoeff, (float)GetGlobalTeam(GetMatchBall()->m_nLastActiveTeam)->m_nForward); } if (tvcamMode == TVCAM_MODE_SIDELINE) { targetPos.y += m_flPossCoeff * mp_tvcam_offset_forward.GetInt(); } } } } if (tvcamMode != TVCAM_MODE_CELEBRATION) { // Make sure the camera doesn't move too far away from the field borders targetPos.x = clamp(targetPos.x, SDKGameRules()->m_vFieldMin.GetX() + mp_tvcam_border_south.GetInt(), SDKGameRules()->m_vFieldMax.GetX() - mp_tvcam_border_north.GetInt()); targetPos.y = clamp(targetPos.y, SDKGameRules()->m_vFieldMin.GetY() + mp_tvcam_border_west.GetInt(), SDKGameRules()->m_vFieldMax.GetY() - mp_tvcam_border_east.GetInt()); targetPos.z = SDKGameRules()->m_vKickOff.GetZ(); } if (m_vOldTargetPos == vec3_invalid) m_vOldTargetPos = targetPos; else { float speedCoeff = tvcamMode == TVCAM_MODE_CELEBRATION ? mp_tvcam_speed_coeff_fast.GetFloat() : mp_tvcam_speed_coeff.GetFloat(); float speedExp = tvcamMode == TVCAM_MODE_CELEBRATION ? mp_tvcam_speed_exponent_fast.GetFloat() : mp_tvcam_speed_exponent.GetFloat(); Vector changeDir = targetPos - m_vOldTargetPos; float changeDist = changeDir.Length(); changeDir.NormalizeInPlace(); targetPos = m_vOldTargetPos + changeDir * min(changeDist, pow(changeDist * speedCoeff, speedExp) * gpGlobals->frametime); } switch (GetTVCamMode()) { case TVCAM_MODE_SIDELINE: { if (SDKGameRules() && SDKGameRules()->IsIntermissionState() && GetReplayManager() && !GetReplayManager()->IsReplaying()) { //float xLength = SDKGameRules()->m_vFieldMax.GetX() - SDKGameRules()->m_vFieldMin.GetX(); //float yLength = SDKGameRules()->m_vFieldMax.GetY() - SDKGameRules()->m_vFieldMin.GetY(); float zPos = 450; Vector points[4]; points[0] = Vector(SDKGameRules()->m_vFieldMin.GetX(), SDKGameRules()->m_vFieldMin.GetY(), SDKGameRules()->m_vKickOff.GetZ() + zPos); points[1] = Vector(SDKGameRules()->m_vFieldMin.GetX(), SDKGameRules()->m_vFieldMax.GetY(), SDKGameRules()->m_vKickOff.GetZ() + zPos); points[2] = Vector(SDKGameRules()->m_vFieldMax.GetX(), SDKGameRules()->m_vFieldMax.GetY(), SDKGameRules()->m_vKickOff.GetZ() + zPos); points[3] = Vector(SDKGameRules()->m_vFieldMax.GetX(), SDKGameRules()->m_vFieldMin.GetY(), SDKGameRules()->m_vKickOff.GetZ() + zPos); float totalLength = (points[1] - points[0]).Length() + (points[2] - points[1]).Length() + (points[3] - points[2]).Length() + (points[0] - points[3]).Length(); Vector newPoints[4]; const float maxDuration = 180.0f; float timePassed = fmodf(gpGlobals->curtime, maxDuration); float lengthSum = 0; int offset = 0; float length = 0; do { for (int i = 0; i < 4; i++) newPoints[i] = points[(i + offset) % 4]; length = (newPoints[2] - newPoints[1]).Length(); lengthSum += length; offset += 1; } while (timePassed > (lengthSum / totalLength * maxDuration)); float maxStepTime = length / totalLength * maxDuration; float frac = 1 - ((lengthSum / totalLength * maxDuration) - timePassed) / maxStepTime; Vector output; Catmull_Rom_Spline(newPoints[0], newPoints[1], newPoints[2], newPoints[3], frac, output); /* float targetDist = (newPoints[2] - newPoints[1]).Length() * frac; float epsilon = 10.0f; float oldDiff = 0; float diff = 0; float change = 0.001f; bool add = true; do { frac = clamp(frac += (add ? change : -change), 0.0f, 1.0f); Catmull_Rom_Spline(newPoints[0], newPoints[1], newPoints[2], newPoints[3], frac, output); oldDiff = diff; diff = abs((output - newPoints[1]).Length() - targetDist); if (diff >= oldDiff) add = !add; } while (diff > epsilon);*/ eyeOrigin = output; VectorAngles(SDKGameRules()->m_vKickOff - output, eyeAngles); } /*else if (SDKGameRules() && !SDKGameRules()->IsIntermissionState() && gpGlobals->curtime <= SDKGameRules()->m_flStateEnterTime + 4) { Vector points[4]; float zPosStart = 450; float zPosEnd = 50; points[0] = Vector(SDKGameRules()->m_vFieldMin.GetX(), SDKGameRules()->m_vKickOff.GetY() + 10000, SDKGameRules()->m_vKickOff.GetZ() + zPosStart); points[1] = Vector(SDKGameRules()->m_vFieldMin.GetX(), SDKGameRules()->m_vKickOff.GetY(), SDKGameRules()->m_vKickOff.GetZ() + zPosStart); points[2] = Vector(SDKGameRules()->m_vKickOff.GetX(), SDKGameRules()->m_vKickOff.GetY() - 300, SDKGameRules()->m_vKickOff.GetZ() + zPosEnd); points[3] = Vector(SDKGameRules()->m_vKickOff.GetX(), SDKGameRules()->m_vKickOff.GetY() + 10000, SDKGameRules()->m_vKickOff.GetZ() + zPosEnd); float frac = min(1.0f, (gpGlobals->curtime - SDKGameRules()->m_flStateEnterTime) / 3.0f); Vector output; Catmull_Rom_Spline(points[0], points[1], points[2], points[3], frac, output); eyeOrigin = output; VectorAngles(Vector(SDKGameRules()->m_vKickOff.GetX(), SDKGameRules()->m_vKickOff.GetY(), SDKGameRules()->m_vKickOff.GetZ() + 100) - output, eyeAngles); }*/ else { Vector newPos = Vector(targetPos.x - mp_tvcam_sideline_offset_north.GetInt(), targetPos.y, targetPos.z + mp_tvcam_sideline_offset_height.GetInt()); Vector offsetTargetPos = Vector(targetPos.x - mp_tvcam_offset_north.GetInt(), targetPos.y, targetPos.z); Vector newDir = offsetTargetPos - newPos; newDir.NormalizeInPlace(); eyeOrigin = newPos; VectorAngles(newDir, eyeAngles); } } break; case TVCAM_MODE_FIXED_SIDELINE: { Vector newPos = Vector(SDKGameRules()->m_vFieldMin.GetX() - 500, SDKGameRules()->m_vKickOff.GetY(), SDKGameRules()->m_vKickOff.GetZ() + 1000); Vector offsetTargetPos = Vector(targetPos.x - 500, targetPos.y, targetPos.z); Vector newDir = offsetTargetPos - newPos; float dist = newDir.Length(); newDir.NormalizeInPlace(); newPos = offsetTargetPos - min(750, dist) * newDir; eyeOrigin = newPos; VectorAngles(newDir, eyeAngles); } break; case TVCAM_MODE_BEHIND_GOAL: { float yPos = atMinGoalPos ? SDKGameRules()->m_vFieldMin.GetY() : SDKGameRules()->m_vFieldMax.GetY(); Vector goalCenter = Vector((SDKGameRules()->m_vFieldMin.GetX() + SDKGameRules()->m_vFieldMax.GetX()) / 2.0f, yPos, SDKGameRules()->m_vKickOff.GetZ()); Vector newPos = goalCenter + Vector(0, 300 * (atMinGoalPos ? -1 : 1), 300); Vector newDir = targetPos - newPos; newDir.NormalizeInPlace(); eyeOrigin = newPos; VectorAngles(newDir, eyeAngles); } break; case TVCAM_MODE_TOPDOWN: { eyeOrigin = Vector(targetPos.x, targetPos.y, SDKGameRules()->m_vKickOff.GetZ() + 1000); eyeAngles = QAngle(89, 0, 0); } break; case TVCAM_MODE_FLY_FOLLOW: { Vector newPos = Vector(targetPos.x, targetPos.y + (atMinGoalPos ? 1 : -1) * 500, SDKGameRules()->m_vKickOff.GetZ() + 225); Vector newDir = targetPos - newPos; newDir.NormalizeInPlace(); eyeOrigin = newPos; VectorAngles(newDir, eyeAngles); } break; case TVCAM_MODE_GOAL_LINE: { Vector center = Vector(SDKGameRules()->m_vKickOff.GetX(), (atMinGoalPos ? SDKGameRules()->m_vFieldMin.GetY() + 5 : SDKGameRules()->m_vFieldMax.GetY() - 5), SDKGameRules()->m_vKickOff.GetZ()); Vector newPos = center; newPos.x -= 350; newPos.z += 200; QAngle newAng; VectorAngles(center - newPos, newAng); eyeOrigin = newPos; eyeAngles = newAng; } break; case TVCAM_MODE_CELEBRATION: { Vector newPos = Vector( targetPos.x < SDKGameRules()->m_vKickOff.GetX() ? SDKGameRules()->m_vFieldMin.GetX() - 500 : SDKGameRules()->m_vFieldMax.GetX() + 500, targetPos.y < SDKGameRules()->m_vKickOff.GetY() ? SDKGameRules()->m_vFieldMin.GetY() - 500 : SDKGameRules()->m_vFieldMax.GetY() + 500, SDKGameRules()->m_vKickOff.GetZ() + 1000); Vector newDir = targetPos - newPos; float dist = newDir.Length(); newDir.NormalizeInPlace(); newPos = targetPos - min(300, dist) * newDir; eyeOrigin = newPos; VectorAngles(newDir, eyeAngles); } break; } m_vOldTargetPos = targetPos; fov = C_SDKPlayer::GetLocalSDKPlayer()->GetFOV(); }
void CheckAutoTransparentProps(const Vector &pos, const QAngle &ang) { float opacity = clamp(cl_goal_opacity.GetFloat(), 0.0f, 1.0f); for (int i = gpGlobals->maxClients; i <= ClientEntityList().GetHighestEntityIndex(); i++) { C_BaseEntity *pEnt = ClientEntityList().GetBaseEntity(i); if(!dynamic_cast<C_AutoTransparentProp *>(pEnt)) continue; // Check if the camera is behind the goal line and close to the goal. Use an additional offset so the goal post doesn't get in the way. if (opacity != 1.0f && (pos.y <= SDKGameRules()->m_vFieldMin.GetY() + cl_goal_opacity_fieldoffset.GetFloat() && pEnt->GetLocalOrigin().y < SDKGameRules()->m_vKickOff.GetY() || pos.y >= SDKGameRules()->m_vFieldMax.GetY() - cl_goal_opacity_fieldoffset.GetFloat() && pEnt->GetLocalOrigin().y > SDKGameRules()->m_vKickOff.GetY()) && pos.x >= SDKGameRules()->m_vKickOff.GetX() - 500 && pos.x <= SDKGameRules()->m_vKickOff.GetX() + 500) { pEnt->SetRenderMode(kRenderTransColor); pEnt->SetRenderColorA(opacity * 255); } else { pEnt->SetRenderMode(kRenderNormal); } } }