2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/textrender.h>
|
2018-03-21 14:53:29 +00:00
|
|
|
#include <engine/graphics.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/shared/config.h>
|
|
|
|
#include <game/generated/protocol.h>
|
|
|
|
#include <game/generated/client_data.h>
|
2008-09-04 18:54:37 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
#include <game/client/animstate.h>
|
|
|
|
#include "nameplates.h"
|
|
|
|
#include "controls.h"
|
2018-03-21 14:53:29 +00:00
|
|
|
#include "camera.h"
|
2008-09-04 18:54:37 +00:00
|
|
|
|
2018-03-13 20:55:47 +00:00
|
|
|
#include "players.h"
|
|
|
|
|
2018-03-21 14:53:29 +00:00
|
|
|
void CNamePlates::MapscreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup)
|
|
|
|
{
|
|
|
|
float Points[4];
|
|
|
|
RenderTools()->MapscreenToWorld(CenterX, CenterY, pGroup->m_ParallaxX / 100.0f, pGroup->m_ParallaxY / 100.0f, pGroup->m_OffsetX, pGroup->m_OffsetY, Graphics()->ScreenAspect(), 1.0f, Points);
|
|
|
|
Graphics()->MapScreen(Points[0], Points[1], Points[2], Points[3]);
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CNamePlates::RenderNameplate(
|
|
|
|
const CNetObj_Character *pPrevChar,
|
|
|
|
const CNetObj_Character *pPlayerChar,
|
|
|
|
const CNetObj_PlayerInfo *pPlayerInfo
|
2008-09-04 18:54:37 +00:00
|
|
|
)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
float IntraTick = Client()->IntraGameTick();
|
2018-03-13 20:55:47 +00:00
|
|
|
int ClientID = pPlayerInfo->m_ClientID;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2018-03-13 20:55:47 +00:00
|
|
|
vec2 Position;
|
2018-08-30 20:53:28 +00:00
|
|
|
if((!m_pClient->AntiPingPlayers() && !pPlayerInfo->m_Local) || m_pClient->m_Snap.m_SpecInfo.m_Active)
|
2018-08-03 21:40:03 +00:00
|
|
|
{
|
2018-08-30 20:53:28 +00:00
|
|
|
Position = mix(vec2(pPrevChar->m_X, pPrevChar->m_Y), vec2(pPlayerChar->m_X, pPlayerChar->m_Y), IntraTick);
|
|
|
|
}
|
|
|
|
else if(!m_pClient->AntiPingPlayers() && pPlayerInfo->m_Local)
|
|
|
|
{
|
|
|
|
Position = vec2(m_pClient->m_LocalCharacterPos.x, m_pClient->m_LocalCharacterPos.y);
|
2018-08-03 21:40:03 +00:00
|
|
|
}
|
2018-03-13 20:55:47 +00:00
|
|
|
else
|
2018-08-03 21:40:03 +00:00
|
|
|
{
|
2018-03-13 20:55:47 +00:00
|
|
|
Position = m_pPlayers->m_CurPredictedPos[ClientID];
|
2018-08-03 21:40:03 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2014-01-24 22:11:33 +00:00
|
|
|
bool OtherTeam;
|
|
|
|
|
2018-03-13 20:55:47 +00:00
|
|
|
if(m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_Team == TEAM_SPECTATORS && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
|
2014-04-12 14:55:01 +00:00
|
|
|
OtherTeam = false;
|
2018-03-13 20:55:47 +00:00
|
|
|
else if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
|
2014-04-12 14:55:01 +00:00
|
|
|
OtherTeam = m_pClient->m_Teams.Team(pPlayerInfo->m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID);
|
2014-01-24 22:11:33 +00:00
|
|
|
else
|
|
|
|
OtherTeam = m_pClient->m_Teams.Team(pPlayerInfo->m_ClientID) != m_pClient->m_Teams.Team(m_pClient->m_Snap.m_LocalClientID);
|
|
|
|
|
2011-01-04 12:11:01 +00:00
|
|
|
float FontSize = 18.0f + 20.0f * g_Config.m_ClNameplatesSize / 100.0f;
|
2015-06-29 00:06:27 +00:00
|
|
|
float FontSizeClan = 18.0f + 20.0f * g_Config.m_ClNameplatesClanSize / 100.0f;
|
2008-09-04 18:54:37 +00:00
|
|
|
// render name plate
|
2018-06-26 20:30:23 +00:00
|
|
|
if(!pPlayerInfo->m_Local || g_Config.m_ClNameplatesOwn)
|
2008-09-04 18:54:37 +00:00
|
|
|
{
|
|
|
|
float a = 1;
|
2010-05-29 07:25:38 +00:00
|
|
|
if(g_Config.m_ClNameplatesAlways == 0)
|
2014-05-10 12:31:00 +00:00
|
|
|
a = clamp(1-powf(distance(m_pClient->m_pControls->m_TargetPos[g_Config.m_ClDummy], Position)/200.0f,16.0f), 0.0f, 1.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2018-08-03 21:40:03 +00:00
|
|
|
const char *pName = m_pClient->m_aClients[pPlayerInfo->m_ClientID].m_aName;
|
2018-03-13 20:55:47 +00:00
|
|
|
if(str_comp(pName, m_aNamePlates[ClientID].m_aName) != 0 || FontSize != m_aNamePlates[ClientID].m_NameTextFontSize)
|
|
|
|
{
|
|
|
|
mem_copy(m_aNamePlates[ClientID].m_aName, pName, sizeof(m_aNamePlates[ClientID].m_aName));
|
|
|
|
m_aNamePlates[ClientID].m_NameTextFontSize = FontSize;
|
|
|
|
|
|
|
|
m_aNamePlates[ClientID].m_NameTextWidth = TextRender()->TextWidth(0, FontSize, pName, -1);
|
|
|
|
|
|
|
|
if(m_aNamePlates[ClientID].m_NameTextContainerIndex != -1)
|
|
|
|
TextRender()->DeleteTextContainer(m_aNamePlates[ClientID].m_NameTextContainerIndex);
|
|
|
|
|
|
|
|
CTextCursor Cursor;
|
|
|
|
TextRender()->SetCursor(&Cursor, 0, 0, FontSize, TEXTFLAG_RENDER);
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
2018-03-21 14:53:29 +00:00
|
|
|
// create nameplates at standard zoom
|
|
|
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
|
|
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
|
|
|
MapscreenToGroup(m_pClient->m_pCamera->m_Center.x, m_pClient->m_pCamera->m_Center.y, Layers()->GameGroup());
|
2018-03-13 20:55:47 +00:00
|
|
|
m_aNamePlates[ClientID].m_NameTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pName);
|
2018-03-21 14:53:29 +00:00
|
|
|
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
2018-03-13 20:55:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(g_Config.m_ClNameplatesClan)
|
|
|
|
{
|
|
|
|
const char *pClan = m_pClient->m_aClients[ClientID].m_aClan;
|
|
|
|
if(str_comp(pClan, m_aNamePlates[ClientID].m_aClanName) != 0 || FontSizeClan != m_aNamePlates[ClientID].m_ClanNameTextFontSize)
|
|
|
|
{
|
|
|
|
mem_copy(m_aNamePlates[ClientID].m_aClanName, pClan, sizeof(m_aNamePlates[ClientID].m_aClanName));
|
|
|
|
m_aNamePlates[ClientID].m_ClanNameTextFontSize = FontSizeClan;
|
|
|
|
|
|
|
|
m_aNamePlates[ClientID].m_ClanNameTextWidth = TextRender()->TextWidth(0, FontSizeClan, pClan, -1);
|
|
|
|
|
|
|
|
if(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex != -1)
|
|
|
|
TextRender()->DeleteTextContainer(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2018-03-13 20:55:47 +00:00
|
|
|
CTextCursor Cursor;
|
|
|
|
TextRender()->SetCursor(&Cursor, 0, 0, FontSizeClan, TEXTFLAG_RENDER);
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
2018-03-21 14:53:29 +00:00
|
|
|
// create nameplates at standard zoom
|
|
|
|
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
|
|
|
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
|
|
|
|
MapscreenToGroup(m_pClient->m_pCamera->m_Center.x, m_pClient->m_pCamera->m_Center.y, Layers()->GameGroup());
|
2018-03-13 20:55:47 +00:00
|
|
|
m_aNamePlates[ClientID].m_ClanNameTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pClan);
|
2018-03-21 14:53:29 +00:00
|
|
|
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
|
2018-03-13 20:55:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float tw = m_aNamePlates[ClientID].m_NameTextWidth;
|
2014-04-12 14:55:01 +00:00
|
|
|
vec3 rgb = vec3(1.0f, 1.0f, 1.0f);
|
2018-03-13 20:55:47 +00:00
|
|
|
if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Teams.Team(ClientID))
|
|
|
|
rgb = HslToRgb(vec3(m_pClient->m_Teams.Team(ClientID) / 64.0f, 1.0f, 0.75f));
|
|
|
|
|
|
|
|
STextRenderColor TColor;
|
|
|
|
STextRenderColor TOutlineColor;
|
2014-04-12 14:55:01 +00:00
|
|
|
|
2018-03-13 20:55:47 +00:00
|
|
|
if(OtherTeam)
|
2014-01-24 22:11:33 +00:00
|
|
|
{
|
2018-03-13 20:55:47 +00:00
|
|
|
TOutlineColor.Set(0.0f, 0.0f, 0.0f, 0.2f);
|
|
|
|
TColor.Set(rgb.r, rgb.g, rgb.b, g_Config.m_ClShowOthersAlpha / 100.0f);
|
2014-01-24 22:11:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-03-13 20:55:47 +00:00
|
|
|
TOutlineColor.Set(0.0f, 0.0f, 0.0f, 0.5f*a);
|
|
|
|
TColor.Set(rgb.r, rgb.g, rgb.b, a);
|
2014-01-24 22:11:33 +00:00
|
|
|
}
|
2011-03-27 12:30:59 +00:00
|
|
|
if(g_Config.m_ClNameplatesTeamcolors && m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS)
|
2010-12-15 12:31:27 +00:00
|
|
|
{
|
2018-03-13 20:55:47 +00:00
|
|
|
if(m_pClient->m_aClients[ClientID].m_Team == TEAM_RED)
|
|
|
|
TColor.Set(1.0f, 0.5f, 0.5f, a);
|
|
|
|
else if(m_pClient->m_aClients[ClientID].m_Team == TEAM_BLUE)
|
|
|
|
TColor.Set(0.7f, 0.7f, 1.0f, a);
|
2010-12-15 12:31:27 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2018-03-13 20:55:47 +00:00
|
|
|
if(m_aNamePlates[ClientID].m_NameTextContainerIndex != -1)
|
|
|
|
TextRender()->RenderTextContainer(m_aNamePlates[ClientID].m_NameTextContainerIndex, &TColor, &TOutlineColor, Position.x - tw / 2.0f, Position.y - FontSize - 38.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2015-06-21 22:34:10 +00:00
|
|
|
if(g_Config.m_ClNameplatesClan)
|
2015-06-21 22:44:26 +00:00
|
|
|
{
|
2018-03-13 20:55:47 +00:00
|
|
|
if(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex != -1)
|
|
|
|
TextRender()->RenderTextContainer(m_aNamePlates[ClientID].m_ClanNameTextContainerIndex, &TColor, &TOutlineColor, Position.x - m_aNamePlates[ClientID].m_ClanNameTextWidth / 2.0f, Position.y - FontSize - FontSizeClan - 38.0f);
|
2015-06-21 22:44:26 +00:00
|
|
|
}
|
2015-06-21 22:34:10 +00:00
|
|
|
|
2018-02-04 15:00:47 +00:00
|
|
|
if(g_Config.m_Debug) // render client id when in debug as well
|
2008-09-04 18:54:37 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
char aBuf[128];
|
2011-02-12 10:40:36 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf),"%d", pPlayerInfo->m_ClientID);
|
2015-06-29 00:06:27 +00:00
|
|
|
float Offset = g_Config.m_ClNameplatesClan ? (FontSize * 2 + FontSizeClan) : (FontSize * 2);
|
2015-06-21 22:34:10 +00:00
|
|
|
float tw_id = TextRender()->TextWidth(0, FontSize, aBuf, -1);
|
|
|
|
TextRender()->Text(0, Position.x-tw_id/2.0f, Position.y-Offset-38.0f, 28.0f, aBuf, -1);
|
2008-09-04 18:54:37 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
TextRender()->TextColor(1,1,1,1);
|
2011-03-13 11:55:00 +00:00
|
|
|
TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
|
2008-09-04 18:54:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CNamePlates::OnRender()
|
2008-09-04 18:54:37 +00:00
|
|
|
{
|
2018-03-13 20:55:47 +00:00
|
|
|
if(!g_Config.m_ClNameplates)
|
2008-09-04 18:54:37 +00:00
|
|
|
return;
|
2008-09-23 08:42:38 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
2008-09-04 18:54:37 +00:00
|
|
|
{
|
2008-09-23 08:42:38 +00:00
|
|
|
// only render active characters
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!m_pClient->m_Snap.m_aCharacters[i].m_Active)
|
2008-09-23 08:42:38 +00:00
|
|
|
continue;
|
2008-09-04 18:54:37 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
const void *pInfo = Client()->SnapFindItem(IClient::SNAP_CURRENT, NETOBJTYPE_PLAYERINFO, i);
|
2008-09-04 18:54:37 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pInfo)
|
2008-09-23 08:42:38 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
RenderNameplate(
|
|
|
|
&m_pClient->m_Snap.m_aCharacters[i].m_Prev,
|
|
|
|
&m_pClient->m_Snap.m_aCharacters[i].m_Cur,
|
|
|
|
(const CNetObj_PlayerInfo *)pInfo);
|
2008-09-04 18:54:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-13 20:55:47 +00:00
|
|
|
|
|
|
|
void CNamePlates::SetPlayers(CPlayers* pPlayers)
|
|
|
|
{
|
|
|
|
m_pPlayers = pPlayers;
|
|
|
|
}
|
|
|
|
|
2018-03-21 14:53:29 +00:00
|
|
|
void CNamePlates::ResetNamePlates()
|
2018-03-13 20:55:47 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
{
|
|
|
|
if(m_aNamePlates[i].m_NameTextContainerIndex != -1)
|
|
|
|
TextRender()->DeleteTextContainer(m_aNamePlates[i].m_NameTextContainerIndex);
|
|
|
|
if(m_aNamePlates[i].m_ClanNameTextContainerIndex != -1)
|
|
|
|
TextRender()->DeleteTextContainer(m_aNamePlates[i].m_ClanNameTextContainerIndex);
|
|
|
|
|
|
|
|
m_aNamePlates[i].Reset();
|
|
|
|
}
|
2018-03-21 14:53:29 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void CNamePlates::OnWindowResize()
|
|
|
|
{
|
|
|
|
ResetNamePlates();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CNamePlates::OnInit()
|
|
|
|
{
|
|
|
|
ResetNamePlates();
|
2018-03-13 20:55:47 +00:00
|
|
|
}
|