mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Merge #4870
4870: Don't render tees or nameplates offscreen r=def- a=sjrc6 It seems difficult to measure the fps from the ingame graph or fps counter so these numbers are from NVidia fps overlay FPS on full multeasymap server, fullscreen, vulkan renderer /showall 0 - 4500 /showall 1 - 2100 /showall 1 (after preventing offscreen render) - 4200 ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [x] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Tater <Mr.Potatooh@gmail.com>
This commit is contained in:
commit
309283d551
|
@ -344,6 +344,7 @@ void CGhost::OnRender()
|
|||
Player.m_AttackTick += Client()->GameTick(g_Config.m_ClDummy) - GhostTick;
|
||||
|
||||
m_pClient->m_Players.RenderHook(&Prev, &Player, &Ghost.m_RenderInfo, -2, IntraTick);
|
||||
m_pClient->m_Players.RenderHookCollLine(&Prev, &Player, -2, IntraTick);
|
||||
m_pClient->m_Players.RenderPlayer(&Prev, &Player, &Ghost.m_RenderInfo, -2, IntraTick);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,6 +305,18 @@ void CNamePlates::OnRender()
|
|||
if(!g_Config.m_ClNameplates && ShowDirection == 0)
|
||||
return;
|
||||
|
||||
// get screen edges to avoid rendering offscreen
|
||||
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
||||
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
||||
// expand the edges to prevent popping in/out onscreen
|
||||
//
|
||||
// it is assumed that the nameplate and all its components fit into a 800x800 box placed directly above the tee
|
||||
// this may need to be changed or calculated differently in the future
|
||||
ScreenX0 -= 400;
|
||||
ScreenX1 += 400;
|
||||
//ScreenY0 -= 0;
|
||||
ScreenY1 += 800;
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paPlayerInfos[i];
|
||||
|
@ -313,6 +325,13 @@ void CNamePlates::OnRender()
|
|||
continue;
|
||||
}
|
||||
|
||||
// don't render offscreen
|
||||
vec2 *pRenderPos = &m_pClient->m_aClients[i].m_RenderPos;
|
||||
if(pRenderPos->x < ScreenX0 || pRenderPos->x > ScreenX1 || pRenderPos->y < ScreenY0 || pRenderPos->y > ScreenY1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m_pClient->m_aClients[i].m_SpecCharPresent)
|
||||
{
|
||||
RenderNameplatePos(m_pClient->m_aClients[i].m_SpecChar, pInfo, 0.4f, true);
|
||||
|
|
|
@ -76,7 +76,156 @@ inline float AngularApproach(float Src, float Dst, float Amount)
|
|||
return Dst;
|
||||
return n;
|
||||
}
|
||||
void CPlayers::RenderHookCollLine(
|
||||
const CNetObj_Character *pPrevChar,
|
||||
const CNetObj_Character *pPlayerChar,
|
||||
int ClientID,
|
||||
float Intra)
|
||||
{
|
||||
CNetObj_Character Prev;
|
||||
CNetObj_Character Player;
|
||||
Prev = *pPrevChar;
|
||||
Player = *pPlayerChar;
|
||||
|
||||
bool Local = m_pClient->m_Snap.m_LocalClientID == ClientID;
|
||||
bool OtherTeam = m_pClient->IsOtherTeam(ClientID);
|
||||
float Alpha = (OtherTeam || ClientID < 0) ? g_Config.m_ClShowOthersAlpha / 100.0f : 1.0f;
|
||||
|
||||
float IntraTick = Intra;
|
||||
if(ClientID >= 0)
|
||||
IntraTick = m_pClient->m_aClients[ClientID].m_IsPredicted ? Client()->PredIntraGameTick(g_Config.m_ClDummy) : Client()->IntraGameTick(g_Config.m_ClDummy);
|
||||
|
||||
float Angle;
|
||||
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
||||
{
|
||||
// just use the direct input if it's the local player we are rendering
|
||||
Angle = angle(m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float AngleIntraTick = IntraTick;
|
||||
// using unpredicted angle when rendering other players in-game
|
||||
if(ClientID >= 0)
|
||||
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
|
||||
// If the player moves their weapon through top, then change
|
||||
// the end angle by 2*Pi, so that the mix function will use the
|
||||
// short path and not the long one.
|
||||
if(Player.m_Angle > (256.0f * pi) && Prev.m_Angle < 0)
|
||||
Player.m_Angle -= 256.0f * 2 * pi;
|
||||
else if(Player.m_Angle < 0 && Prev.m_Angle > (256.0f * pi))
|
||||
Player.m_Angle += 256.0f * 2 * pi;
|
||||
|
||||
Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, AngleIntraTick) / 256.0f;
|
||||
}
|
||||
|
||||
vec2 Direction = direction(Angle);
|
||||
vec2 Position;
|
||||
if(in_range(ClientID, MAX_CLIENTS - 1))
|
||||
Position = m_pClient->m_aClients[ClientID].m_RenderPos;
|
||||
else
|
||||
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
|
||||
// draw hook collision line
|
||||
{
|
||||
bool AlwaysRenderHookColl = GameClient()->m_GameInfo.m_AllowHookColl && (Local ? g_Config.m_ClShowHookCollOwn : g_Config.m_ClShowHookCollOther) == 2;
|
||||
bool RenderHookCollPlayer = ClientID >= 0 && Player.m_PlayerFlags & PLAYERFLAG_AIM && (Local ? g_Config.m_ClShowHookCollOwn : g_Config.m_ClShowHookCollOther) > 0;
|
||||
bool RenderHookCollVideo = true;
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
RenderHookCollVideo = !IVideo::Current() || g_Config.m_ClVideoShowHookCollOther || Local;
|
||||
#endif
|
||||
if((AlwaysRenderHookColl || RenderHookCollPlayer) && RenderHookCollVideo)
|
||||
{
|
||||
vec2 ExDirection = Direction;
|
||||
|
||||
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
||||
ExDirection = normalize(vec2((int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].x, (int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].y));
|
||||
|
||||
Graphics()->TextureClear();
|
||||
vec2 InitPos = Position;
|
||||
vec2 FinishPos = InitPos + ExDirection * (m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength - 42.0f);
|
||||
|
||||
if(g_Config.m_ClHookCollSize > 0)
|
||||
Graphics()->QuadsBegin();
|
||||
else
|
||||
Graphics()->LinesBegin();
|
||||
|
||||
ColorRGBA HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorNoColl));
|
||||
|
||||
float PhysSize = 28.0f;
|
||||
|
||||
vec2 OldPos = InitPos + ExDirection * PhysSize * 1.5f;
|
||||
vec2 NewPos = OldPos;
|
||||
|
||||
bool DoBreak = false;
|
||||
int Hit = 0;
|
||||
|
||||
do
|
||||
{
|
||||
OldPos = NewPos;
|
||||
NewPos = OldPos + ExDirection * m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookFireSpeed;
|
||||
|
||||
if(distance(InitPos, NewPos) > m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength)
|
||||
{
|
||||
NewPos = InitPos + normalize(NewPos - InitPos) * m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength;
|
||||
DoBreak = true;
|
||||
}
|
||||
|
||||
int TeleNr = 0;
|
||||
Hit = Collision()->IntersectLineTeleHook(OldPos, NewPos, &FinishPos, 0x0, &TeleNr);
|
||||
|
||||
if(!DoBreak && Hit)
|
||||
{
|
||||
if(Hit != TILE_NOHOOK)
|
||||
{
|
||||
HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorHookableColl));
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pClient->IntersectCharacter(OldPos, FinishPos, FinishPos, ClientID) != -1)
|
||||
{
|
||||
HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorTeeColl));
|
||||
break;
|
||||
}
|
||||
|
||||
if(Hit)
|
||||
break;
|
||||
|
||||
NewPos.x = round_to_int(NewPos.x);
|
||||
NewPos.y = round_to_int(NewPos.y);
|
||||
|
||||
if(OldPos == NewPos)
|
||||
break;
|
||||
|
||||
ExDirection.x = round_to_int(ExDirection.x * 256.0f) / 256.0f;
|
||||
ExDirection.y = round_to_int(ExDirection.y * 256.0f) / 256.0f;
|
||||
} while(!DoBreak);
|
||||
|
||||
if(AlwaysRenderHookColl && RenderHookCollPlayer)
|
||||
{
|
||||
// invert the hook coll colors when using cl_show_hook_coll_always and +showhookcoll is pressed
|
||||
HookCollColor = color_invert(HookCollColor);
|
||||
}
|
||||
Graphics()->SetColor(HookCollColor.WithAlpha(Alpha));
|
||||
if(g_Config.m_ClHookCollSize > 0)
|
||||
{
|
||||
float LineWidth = 0.5f + (float)(g_Config.m_ClHookCollSize - 1) * 0.25f;
|
||||
vec2 PerpToAngle = normalize(vec2(ExDirection.y, -ExDirection.x)) * GameClient()->m_Camera.m_Zoom;
|
||||
vec2 Pos0 = FinishPos + PerpToAngle * -LineWidth;
|
||||
vec2 Pos1 = FinishPos + PerpToAngle * LineWidth;
|
||||
vec2 Pos2 = InitPos + PerpToAngle * -LineWidth;
|
||||
vec2 Pos3 = InitPos + PerpToAngle * LineWidth;
|
||||
IGraphics::CFreeformItem FreeformItem(Pos0.x, Pos0.y, Pos1.x, Pos1.y, Pos2.x, Pos2.y, Pos3.x, Pos3.y);
|
||||
Graphics()->QuadsDrawFreeform(&FreeformItem, 1);
|
||||
Graphics()->QuadsEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
IGraphics::CLineItem LineItem(InitPos.x, InitPos.y, FinishPos.x, FinishPos.y);
|
||||
Graphics()->LinesDraw(&LineItem, 1);
|
||||
Graphics()->LinesEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void CPlayers::RenderHook(
|
||||
const CNetObj_Character *pPrevChar,
|
||||
const CNetObj_Character *pPlayerChar,
|
||||
|
@ -231,7 +380,6 @@ void CPlayers::RenderPlayer(
|
|||
Position = m_pClient->m_aClients[ClientID].m_RenderPos;
|
||||
else
|
||||
Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), IntraTick);
|
||||
|
||||
vec2 Vel = mix(vec2(Prev.m_VelX / 256.0f, Prev.m_VelY / 256.0f), vec2(Player.m_VelX / 256.0f, Player.m_VelY / 256.0f), IntraTick);
|
||||
|
||||
m_pClient->m_Flow.Add(Position, Vel * 100.0f, 10.0f);
|
||||
|
@ -277,105 +425,6 @@ void CPlayers::RenderPlayer(
|
|||
|
||||
// draw gun
|
||||
{
|
||||
bool AlwaysRenderHookColl = GameClient()->m_GameInfo.m_AllowHookColl && (Local ? g_Config.m_ClShowHookCollOwn : g_Config.m_ClShowHookCollOther) == 2;
|
||||
bool RenderHookCollPlayer = ClientID >= 0 && Player.m_PlayerFlags & PLAYERFLAG_AIM && (Local ? g_Config.m_ClShowHookCollOwn : g_Config.m_ClShowHookCollOther) > 0;
|
||||
bool RenderHookCollVideo = true;
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
RenderHookCollVideo = !IVideo::Current() || g_Config.m_ClVideoShowHookCollOther || Local;
|
||||
#endif
|
||||
if((AlwaysRenderHookColl || RenderHookCollPlayer) && RenderHookCollVideo)
|
||||
{
|
||||
vec2 ExDirection = Direction;
|
||||
|
||||
if(Local && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
||||
ExDirection = normalize(vec2((int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].x, (int)m_pClient->m_Controls.m_MousePos[g_Config.m_ClDummy].y));
|
||||
|
||||
Graphics()->TextureClear();
|
||||
vec2 InitPos = Position;
|
||||
vec2 FinishPos = InitPos + ExDirection * (m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength - 42.0f);
|
||||
|
||||
if(g_Config.m_ClHookCollSize > 0)
|
||||
Graphics()->QuadsBegin();
|
||||
else
|
||||
Graphics()->LinesBegin();
|
||||
|
||||
ColorRGBA HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorNoColl));
|
||||
|
||||
float PhysSize = 28.0f;
|
||||
|
||||
vec2 OldPos = InitPos + ExDirection * PhysSize * 1.5f;
|
||||
vec2 NewPos = OldPos;
|
||||
|
||||
bool DoBreak = false;
|
||||
int Hit = 0;
|
||||
|
||||
do
|
||||
{
|
||||
OldPos = NewPos;
|
||||
NewPos = OldPos + ExDirection * m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookFireSpeed;
|
||||
|
||||
if(distance(InitPos, NewPos) > m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength)
|
||||
{
|
||||
NewPos = InitPos + normalize(NewPos - InitPos) * m_pClient->m_Tuning[g_Config.m_ClDummy].m_HookLength;
|
||||
DoBreak = true;
|
||||
}
|
||||
|
||||
int TeleNr = 0;
|
||||
Hit = Collision()->IntersectLineTeleHook(OldPos, NewPos, &FinishPos, 0x0, &TeleNr);
|
||||
|
||||
if(!DoBreak && Hit)
|
||||
{
|
||||
if(Hit != TILE_NOHOOK)
|
||||
{
|
||||
HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorHookableColl));
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pClient->IntersectCharacter(OldPos, FinishPos, FinishPos, ClientID) != -1)
|
||||
{
|
||||
HookCollColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClHookCollColorTeeColl));
|
||||
break;
|
||||
}
|
||||
|
||||
if(Hit)
|
||||
break;
|
||||
|
||||
NewPos.x = round_to_int(NewPos.x);
|
||||
NewPos.y = round_to_int(NewPos.y);
|
||||
|
||||
if(OldPos == NewPos)
|
||||
break;
|
||||
|
||||
ExDirection.x = round_to_int(ExDirection.x * 256.0f) / 256.0f;
|
||||
ExDirection.y = round_to_int(ExDirection.y * 256.0f) / 256.0f;
|
||||
} while(!DoBreak);
|
||||
|
||||
if(AlwaysRenderHookColl && RenderHookCollPlayer)
|
||||
{
|
||||
// invert the hook coll colors when using cl_show_hook_coll_always and +showhookcoll is pressed
|
||||
HookCollColor = color_invert(HookCollColor);
|
||||
}
|
||||
Graphics()->SetColor(HookCollColor.WithAlpha(Alpha));
|
||||
if(g_Config.m_ClHookCollSize > 0)
|
||||
{
|
||||
float LineWidth = 0.5f + (float)(g_Config.m_ClHookCollSize - 1) * 0.25f;
|
||||
vec2 PerpToAngle = normalize(vec2(ExDirection.y, -ExDirection.x)) * GameClient()->m_Camera.m_Zoom;
|
||||
vec2 Pos0 = FinishPos + PerpToAngle * -LineWidth;
|
||||
vec2 Pos1 = FinishPos + PerpToAngle * LineWidth;
|
||||
vec2 Pos2 = InitPos + PerpToAngle * -LineWidth;
|
||||
vec2 Pos3 = InitPos + PerpToAngle * LineWidth;
|
||||
IGraphics::CFreeformItem FreeformItem(Pos0.x, Pos0.y, Pos1.x, Pos1.y, Pos2.x, Pos2.y, Pos3.x, Pos3.y);
|
||||
Graphics()->QuadsDrawFreeform(&FreeformItem, 1);
|
||||
Graphics()->QuadsEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
IGraphics::CLineItem LineItem(InitPos.x, InitPos.y, FinishPos.x, FinishPos.y);
|
||||
Graphics()->LinesDraw(&LineItem, 1);
|
||||
Graphics()->LinesEnd();
|
||||
}
|
||||
}
|
||||
|
||||
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
Graphics()->QuadsSetRotation(State.GetAttach()->m_Angle * pi * 2 + Angle);
|
||||
|
||||
|
@ -681,6 +730,19 @@ void CPlayers::OnRender()
|
|||
m_RenderInfoSpec.m_Size = 64.0f;
|
||||
int LocalClientID = m_pClient->m_Snap.m_LocalClientID;
|
||||
|
||||
// get screen edges to avoid rendering offscreen
|
||||
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
||||
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
||||
// expand the edges to prevent popping in/out onscreen
|
||||
//
|
||||
// it is assumed that the tee, all its weapons, and emotes fit into a 200x200 box centered on the tee
|
||||
// this may need to be changed or calculated differently in the future
|
||||
float BorderBuffer = 100;
|
||||
ScreenX0 -= BorderBuffer;
|
||||
ScreenX1 += BorderBuffer;
|
||||
ScreenY0 -= BorderBuffer;
|
||||
ScreenY1 += BorderBuffer;
|
||||
|
||||
// render everyone else's hook, then our own
|
||||
for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++)
|
||||
{
|
||||
|
@ -713,11 +775,21 @@ void CPlayers::OnRender()
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RenderHookCollLine(&m_pClient->m_aClients[ClientID].m_RenderPrev, &m_pClient->m_aClients[ClientID].m_RenderCur, ClientID);
|
||||
|
||||
//don't render offscreen
|
||||
vec2 *pRenderPos = &m_pClient->m_aClients[ClientID].m_RenderPos;
|
||||
if(pRenderPos->x < ScreenX0 || pRenderPos->x > ScreenX1 || pRenderPos->y < ScreenY0 || pRenderPos->y > ScreenY1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
RenderPlayer(&m_pClient->m_aClients[ClientID].m_RenderPrev, &m_pClient->m_aClients[ClientID].m_RenderCur, &m_aRenderInfo[ClientID], ClientID);
|
||||
}
|
||||
if(LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[LocalClientID].m_Active && IsPlayerInfoAvailable(LocalClientID))
|
||||
{
|
||||
const CGameClient::CClientData *pLocalClientData = &m_pClient->m_aClients[LocalClientID];
|
||||
RenderHookCollLine(&pLocalClientData->m_RenderPrev, &pLocalClientData->m_RenderCur, LocalClientID);
|
||||
RenderPlayer(&pLocalClientData->m_RenderPrev, &pLocalClientData->m_RenderCur, &m_aRenderInfo[LocalClientID], LocalClientID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,11 @@ class CPlayers : public CComponent
|
|||
const CTeeRenderInfo *pRenderInfo,
|
||||
int ClientID,
|
||||
float Intra = 0.f);
|
||||
void RenderHookCollLine(
|
||||
const CNetObj_Character *pPrevChar,
|
||||
const CNetObj_Character *pPlayerChar,
|
||||
int ClientID,
|
||||
float Intra = 0.f);
|
||||
bool IsPlayerInfoAvailable(int ClientID) const;
|
||||
|
||||
int m_WeaponEmoteQuadContainerIndex;
|
||||
|
|
Loading…
Reference in a new issue