Skip to content

Commit

Permalink
Camera smoothing improvements.
Browse files Browse the repository at this point in the history
  • Loading branch information
PazerOP committed Nov 19, 2016
1 parent d26418a commit eefb111
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 93 deletions.
Binary file modified .vs/CastingEssentials/v14/.suo
Binary file not shown.
13 changes: 9 additions & 4 deletions CastingEssentials/Hooking/TemplateFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,19 @@ namespace Hooking{ namespace Internal

char** parameters[] = { (char**)(&(va_arg(vaArgList, ArgType<Args>::type)))... };

// 8192 is the length used internally by CCvar
char buffer[8192];
vsnprintf_s(buffer, _TRUNCATE, *fmt, vaArgList);
std::string formatted = vstrprintf(*fmt, vaArgList);
va_end(vaArgList);

// Escape any '%' with a second %
for (size_t i = 0; i < formatted.size(); i++)
{
if (formatted[i] == '%')
formatted.insert(i++, 1, '%');
}

// Can't have variable arguments in std::function, overwrite the "format" parameter with
// the fully parsed buffer
*parameters[fmtParameter] = &buffer[0];
*parameters[fmtParameter] = (char*)formatted.c_str();

// Now run all the hooks
return HookFunctionsInvoker<GroupHookType::BaseGroupHookType, RetVal, Args...>::Invoke(s_Hook, args...);
Expand Down
7 changes: 7 additions & 0 deletions CastingEssentials/Misc/DebugOverlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,11 @@ void NDebugOverlay::Cross3DOriented(const Vector& position, const QAngle& angles
Line(position + right, position - right, r, g, b, noDepthTest, flDuration);
Line(position + forward, position - forward, r, g, b, noDepthTest, flDuration);
Line(position + up, position - up, r, g, b, noDepthTest, flDuration);
}

void NDebugOverlay::EntityText(int entityID, int text_offset, const char *text, float duration, int r, int g, int b, int a)
{
debugoverlay->AddEntityTextOverlay(entityID, text_offset, duration,
(int)clamp(r * 255.f, 0.f, 255.f), (int)clamp(g * 255.f, 0.f, 255.f), (int)clamp(b * 255.f, 0.f, 255.f),
(int)clamp(a * 255.f, 0.f, 255.f), text);
}
261 changes: 189 additions & 72 deletions CastingEssentials/Modules/CameraSmooths.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
#include "CameraSmooths.h"
#include "PluginBase/HookManager.h"
#include "PluginBase/Interfaces.h"
#include "PluginBase/Player.h"
#include "PluginBase/TFDefinitions.h"
#include "Misc/DebugOverlay.h"

#include <convar.h>
#include <client/hltvcamera.h>
#include <shareddefs.h>
#include <toolframework/ienginetool.h>
#include <cdll_int.h>
#include <view_shared.h>
#include <icliententity.h>
#include <engine/IEngineTrace.h>
#include <util_shared.h>

#undef max
#include <algorithm>
Expand Down Expand Up @@ -36,35 +42,44 @@ class CameraSmooths::HLTVCameraOverride : public C_HLTVCamera
using C_HLTVCamera::m_vecVelocity;
};

static const std::vector<std::shared_ptr<const Vector>>& GetTestPoints()
static const Vector TEST_POINTS[27] =
{
constexpr int resolution = 6;
constexpr float mins = -1;
constexpr float maxs = 1;

static thread_local std::vector<std::shared_ptr<const Vector>> s_Vectors;
static thread_local bool s_VectorInitialized = false;

if (!s_VectorInitialized)
{
for (int x = 0; x < resolution; x++)
{
const float xpos = RemapVal(x, 0, resolution - 1, mins, maxs);
for (int y = 0; y < resolution; y++)
{
const float ypos = RemapVal(y, 0, resolution - 1, mins, maxs);
for (int z = 0; z < resolution; z++)
{
const float zpos = RemapVal(y, 0, resolution - 1, mins, maxs);

s_Vectors.push_back(std::make_shared<Vector>(xpos, ypos, zpos));
}
}
}
}

return s_Vectors;
}
Vector(0, 0, 0),
Vector(0, 0, 0.5),
Vector(0, 0, 1),

Vector(0, 0.5, 0),
Vector(0, 0.5, 0.5),
Vector(0, 0.5, 1),

Vector(0, 1, 0),
Vector(0, 1, 0.5),
Vector(0, 1, 1),

Vector(0.5, 0, 0),
Vector(0.5, 0, 0.5),
Vector(0.5, 0, 1),

Vector(0.5, 0.5, 0),
Vector(0.5, 0.5, 0.5),
Vector(0.5, 0.5, 1),

Vector(0.5, 1, 0),
Vector(0.5, 1, 0.5),
Vector(0.5, 1, 1),

Vector(1, 0, 0),
Vector(1, 0, 0.5),
Vector(1, 0, 1),

Vector(1, 0.5, 0),
Vector(1, 0.5, 0.5),
Vector(1, 0.5, 1),

Vector(1, 1, 0),
Vector(1, 1, 0.5),
Vector(1, 1, 1),
};

CameraSmooths::CameraSmooths()
{
Expand All @@ -78,13 +93,23 @@ CameraSmooths::CameraSmooths()
smoothLastTime = 0;

enabled = new ConVar("ce_camerasmooths_enabled", "0", FCVAR_NONE, "smooth transition between camera positions", [](IConVar *var, const char *pOldValue, float flOldValue) { GetModule()->ToggleEnabled(var, pOldValue, flOldValue); });
max_angle_difference = new ConVar("ce_camerasmooths_max_angle_difference", "90", FCVAR_NONE, "max angle difference at which smoothing will be performed", true, 0, true, 180);
max_angle = new ConVar("ce_camerasmooths_max_angle", "45", FCVAR_NONE, "max angle difference at which smoothing will be performed", true, 0, true, 180);
max_distance = new ConVar("ce_camerasmooths_max_distance", "-1", FCVAR_NONE, "max distance at which smoothing will be performed");
ce_camerasmooths_min_distance = new ConVar("ce_camerasmooths_min_distance", "128", FCVAR_NONE, "Always smooth if we're closer than this distance.");
max_speed = new ConVar("ce_camerasmooths_max_speed", "2000", FCVAR_NONE, "max units per second to move view");
ce_camerasmooths_duration = new ConVar("ce_camerasmooths_duration", "0.5", FCVAR_NONE, "Duration over which to smooth the camera.");

ce_camerasmooths_ang_bias = new ConVar("ce_camerasmooths_ang_bias", "0.65", FCVAR_NONE, "biasAmt for angle smoothing. 1 = linear, 0 = sharp snap at halfway", true, 0, true, 1);
ce_camerasmooths_pos_bias = new ConVar("ce_camerasmooths_pos_bias", "0.75", FCVAR_NONE, "biasAmt for position smoothing. 1 = linear, 0 = sharp snap at halfway", true, 0, true, 1);

ce_camerasmooths_check_los = new ConVar("ce_camerasmooths_check_los", "1", FCVAR_NONE, "Make sure we have LOS to the player we're smoothing to.");

ce_camerasmooths_los_buffer = new ConVar("ce_camerasmooths_los_buffer", "32", FCVAR_NONE, "Additional space to give ourselves so we can sorta see around corners.");

ce_camerasmooths_debug_los = new ConVar("ce_camerasmooths_debug_los", "0", FCVAR_NONE, "Draw points associated with LOS checking for camera smooths.");
ce_camerasmooths_debug = new ConVar("ce_camerasmooths_debug", "0", FCVAR_NONE, "Prints debugging info about camera smooths to the console.");

ce_camerasmooths_avoid_scoped_snipers = new ConVar("ce_camerasmooths_avoid_scoped_snipers", "0", FCVAR_NONE, "DHW HACK: Don't smooth to scoped snipers.");
}

bool CameraSmooths::CheckDependencies()
Expand Down Expand Up @@ -141,9 +166,93 @@ bool CameraSmooths::CheckDependencies()
return ready;
}

bool CameraSmooths::TestCollision(const Vector& currentPos, const Vector& targetPos)
void CameraSmooths::UpdateCollisionTests()
{
return false;
const auto currentFrame = Interfaces::GetEngineTool()->HostFrameCount();
if (m_CollisionTestFrame != currentFrame)
{
m_CollisionTests.clear();

const Vector viewPos = m_LastFramePos;

for (Player* player : Player::Iterable())
{
const auto team = player->GetTeam();
if (team != TFTeam::Red && team != TFTeam::Blue)
continue;

if (!player->IsAlive())
continue;

IClientEntity* const entity = player->GetEntity();
if (!entity)
continue;

CollisionTest newTest;
newTest.m_Entity = entity->GetRefEHandle();

const TFClassType playerClass = player->GetClass();
const Vector eyePos = entity->GetAbsOrigin() + VIEW_OFFSETS[(int)playerClass];
const Vector buffer(ce_camerasmooths_los_buffer->GetFloat());
newTest.m_Mins = eyePos - buffer;
newTest.m_Maxs = eyePos + buffer;

const Vector delta = newTest.m_Maxs - newTest.m_Mins;

size_t pointsPassed = 0;
for (const auto& testPoint : TEST_POINTS)
{
const Vector worldTestPoint = newTest.m_Mins + delta * testPoint;

trace_t tr;
UTIL_TraceLine(viewPos, worldTestPoint, MASK_VISIBLE, entity, COLLISION_GROUP_NONE, &tr);

if (tr.fraction >= 1)
pointsPassed++;
}

newTest.m_Visibility = (float)pointsPassed / arraysize(TEST_POINTS);

m_CollisionTests.push_back(newTest);
}

m_CollisionTestFrame = currentFrame;
}
}

void CameraSmooths::DrawCollisionTests()
{
UpdateCollisionTests();

for (const CollisionTest& test : m_CollisionTests)
{
C_BaseEntity* entity = test.m_Entity.Get();
if (!entity)
continue;

NDebugOverlay::Box(Vector(0, 0, 0), test.m_Mins, test.m_Maxs,
Lerp(test.m_Visibility, 255, 0),
Lerp(test.m_Visibility, 0, 255),
0,
64, 0);

const std::string success = strprintf("Success rate: %1.1f", test.m_Visibility * 100);
NDebugOverlay::Text(entity->GetAbsOrigin(), success.c_str(), false, 0);
}
}

float CameraSmooths::GetVisibility(int entIndex)
{
UpdateCollisionTests();
for (const auto& test : m_CollisionTests)
{
if (test.m_Entity.GetEntryIndex() != entIndex)
continue;

return test.m_Visibility;
}

return 0;
}

bool CameraSmooths::InToolModeOverride()
Expand Down Expand Up @@ -188,9 +297,50 @@ bool CameraSmooths::SetupEngineViewOverride(Vector &origin, QAngle &angles, floa
smoothEndMode = hltvcamera->m_nCameraMode;
smoothEndTarget = hltvcamera->m_iTraget1;

Vector targetForward, currentForward;
AngleVectors(angles, &targetForward);
AngleVectors(smoothLastAngles, &currentForward);
Vector currentForward;
AngleVectors(m_LastFrameAng, &currentForward);

const Vector deltaPos = origin - m_LastFramePos;
const float angle = Rad2Deg(std::acosf(currentForward.Dot(deltaPos) / (currentForward.Length() + deltaPos.Length())));
const float distance = deltaPos.Length();

const bool forceSmooth = distance <= ce_camerasmooths_min_distance->GetFloat();
if (!forceSmooth)
{
if (angle > max_angle->GetFloat())
{
ConColorMsg(DBGMSG_COLOR, "[%s] Skipping smooth, angle difference was %1.0f degrees.\n\n", GetModuleName(), angle);
smoothInProgress = false;
return false;
}

ConColorMsg(DBGMSG_COLOR, "[%s] Smooth passed angle test with difference of %1.0f degrees.\n", GetModuleName(), angle);

const float visibility = GetVisibility(smoothEndTarget);
if (visibility <= 0)
{
ConColorMsg(DBGMSG_COLOR, "[%s] Skipping smooth, no visibility to new target\n\n", GetModuleName());
smoothInProgress = false;
return false;
}

ConColorMsg(DBGMSG_COLOR, "[%s] Smooth passed LOS test (%1.0f%% visible)\n", GetModuleName(), visibility * 100);

if (distance > max_distance->GetFloat())
{
ConColorMsg(DBGMSG_COLOR, "[%s] Skipping smooth, distance of %1.0f units > %s (1.0f units)\n\n", GetModuleName(), distance, max_distance->GetName(), max_distance->GetFloat());
smoothInProgress = false;
return false;
}

ConColorMsg(DBGMSG_COLOR, "[%s] Smooth passed distance test, %1.0f units < %s (%1.0f units)\n", GetModuleName(), distance, max_distance->GetName(), max_distance->GetFloat());
}
else
{
ConColorMsg(DBGMSG_COLOR, "[%s] Forcing smooth, distance of %1.0f units < %s (%1.0f units)\n", GetModuleName(), distance, ce_camerasmooths_min_distance->GetName(), ce_camerasmooths_min_distance->GetFloat());
}

ConColorMsg(DBGMSG_COLOR, "[%s] Launching smooth!\n\n", GetModuleName());

m_SmoothStartAng = m_LastFrameAng;
m_SmoothBeginPos = m_SmoothStartPos = m_LastFramePos;
Expand Down Expand Up @@ -280,42 +430,6 @@ bool CameraSmooths::SetupEngineViewOverride(Vector &origin, QAngle &angles, floa
smoothEnding = true;
return true;
}

#if 0
if (moveDistance < moveVector.Length() && moveVector.Length() < max_distance->GetFloat() && angle < max_angle_difference->GetFloat())
{
float movePercentage = moveDistance / moveVector.Length();

moveVector *= movePercentage;

origin = smoothLastOrigin + moveVector;

angles.x = smoothLastAngles.x + ((angles.x - smoothLastAngles.x) * movePercentage);
angles.y = smoothLastAngles.y + ((angles.y - smoothLastAngles.y) * movePercentage);
angles.z = smoothLastAngles.z + ((angles.z - smoothLastAngles.z) * movePercentage);

GetHooks()->GetFunc<C_HLTVCamera_SetCameraAngle>()(angles);
hltvcamera->m_vCamOrigin = origin;

smoothEnding = false;
smoothInProgress = true;
}
else
{
if (hltvcamera)
GetHooks()->GetFunc<C_HLTVCamera_SetMode>()(OBS_MODE_ROAMING);

smoothEnding = true;
smoothInProgress = false;
}

smoothLastAngles = angles;
smoothLastOrigin = origin;
smoothLastTime = Interfaces::GetEngineTool()->HostTime();

GetHooks()->SetState<IClientEngineTools_SetupEngineView>(Hooking::HookAction::SUPERCEDE);
return true;
#endif
}
else if (smoothEnding)
{
Expand All @@ -327,8 +441,8 @@ bool CameraSmooths::SetupEngineViewOverride(Vector &origin, QAngle &angles, floa
smoothEndMode = hltvcamera->m_nCameraMode;
smoothEndTarget = hltvcamera->m_iTraget1;
smoothInProgress = false;
smoothLastAngles = angles;
smoothLastOrigin = origin;
m_LastFrameAng = smoothLastAngles = angles;
m_LastFramePos = smoothLastOrigin = origin;
smoothLastTime = Interfaces::GetEngineTool()->HostTime();

return false;
Expand Down Expand Up @@ -378,5 +492,8 @@ void CameraSmooths::OnTick(bool inGame)
m_LastFrameAng = view.angles;
}
}

if (ce_camerasmooths_debug_los->GetBool())
DrawCollisionTests();
}
}
Loading

0 comments on commit eefb111

Please sign in to comment.