3113: Visual Chat Update r=def- a=Banana090

https://github.com/ddnet/ddnet/pull/3093

Co-authored-by: Дядя Женя <spy090@yandex.ru>
This commit is contained in:
bors[bot] 2020-10-20 16:03:57 +00:00 committed by GitHub
commit e5870ab06f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 376 additions and 109 deletions

View file

@ -3612,6 +3612,20 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSprite(const
UseProgram(m_pSpriteProgram);
SetState(pCommand->m_State, m_pSpriteProgram);
if(pCommand->m_State.m_Texture < 0)
{
if(m_UseMultipleTextureUnits && m_pSpriteProgram->m_LastTextureSampler >= 0)
{
m_TextureSlotBoundToUnit[m_pSpriteProgram->m_LastTextureSampler].m_TextureSlot = -1;
}
m_TextureSlotBoundToUnit[0].m_TextureSlot = -1;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
m_pSpriteProgram->SetUniform(m_pSpriteProgram->m_LocTextureSampler, 0);
m_pSpriteProgram->m_LastTextureSampler = -1;
glBindSampler(0, 0);
}
if(pCommand->m_Rotation != 0.0f && (m_pSpriteProgram->m_LastCenter[0] != pCommand->m_Center.x || m_pSpriteProgram->m_LastCenter[1] != pCommand->m_Center.y))
{
m_pSpriteProgram->SetUniformVec2(m_pSpriteProgram->m_LocCenter, 1, (float *)&pCommand->m_Center);

View file

@ -1444,13 +1444,16 @@ void CGraphics_Threaded::RenderQuadContainer(int ContainerIndex, int QuadOffset,
WrapNormal();
}
void CGraphics_Threaded::RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX, float ScaleY)
void CGraphics_Threaded::RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX, float ScaleY)
{
SQuadContainer &Container = m_QuadContainers[ContainerIndex];
if((int)Container.m_Quads.size() < QuadOffset + 1)
return;
if(QuadDrawNum == -1)
QuadDrawNum = (int)Container.m_Quads.size() - QuadOffset;
if(IsQuadContainerBufferingEnabled())
{
if(Container.m_QuadBufferContainerIndex == -1)
@ -1467,7 +1470,7 @@ void CGraphics_Threaded::RenderQuadContainerAsSprite(int ContainerIndex, int Qua
Cmd.m_State = m_State;
MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
Cmd.m_DrawNum = 1 * 6;
Cmd.m_DrawNum = QuadDrawNum * 6;
Cmd.m_pOffset = (void *)(QuadOffset * 6 * sizeof(unsigned int));
Cmd.m_BufferContainerIndex = Container.m_QuadBufferContainerIndex;
@ -1499,72 +1502,70 @@ void CGraphics_Threaded::RenderQuadContainerAsSprite(int ContainerIndex, int Qua
{
if(g_Config.m_GfxQuadAsTriangle)
{
SQuadContainer::SQuad &Quad = Container.m_Quads[QuadOffset];
m_aVertices[0] = Quad.m_aVertices[0];
m_aVertices[1] = Quad.m_aVertices[1];
m_aVertices[2] = Quad.m_aVertices[2];
m_aVertices[3] = Quad.m_aVertices[0];
m_aVertices[4] = Quad.m_aVertices[2];
m_aVertices[5] = Quad.m_aVertices[3];
for(int i = 0; i < 6; ++i)
for(int i = 0; i < QuadDrawNum; ++i)
{
m_aVertices[i].m_Pos.x *= ScaleX;
m_aVertices[i].m_Pos.y *= ScaleY;
SQuadContainer::SQuad &Quad = Container.m_Quads[QuadOffset + i];
m_aVertices[i * 6 + 0] = Quad.m_aVertices[0];
m_aVertices[i * 6 + 1] = Quad.m_aVertices[1];
m_aVertices[i * 6 + 2] = Quad.m_aVertices[2];
m_aVertices[i * 6 + 3] = Quad.m_aVertices[0];
m_aVertices[i * 6 + 4] = Quad.m_aVertices[2];
m_aVertices[i * 6 + 5] = Quad.m_aVertices[3];
for(int n = 0; n < 6; ++n)
{
m_aVertices[i * 6 + n].m_Pos.x *= ScaleX;
m_aVertices[i * 6 + n].m_Pos.y *= ScaleY;
SetColor(&m_aVertices[i * 6 + n], 0);
}
if(m_Rotation != 0)
{
CCommandBuffer::SPoint Center;
Center.x = m_aVertices[i * 6 + 0].m_Pos.x + (m_aVertices[i * 6 + 1].m_Pos.x - m_aVertices[i * 6 + 0].m_Pos.x) / 2.f;
Center.y = m_aVertices[i * 6 + 0].m_Pos.y + (m_aVertices[i * 6 + 2].m_Pos.y - m_aVertices[i * 6 + 0].m_Pos.y) / 2.f;
Rotate(Center, &m_aVertices[i * 6 + 0], 6);
}
for(int n = 0; n < 6; ++n)
{
m_aVertices[i * 6 + n].m_Pos.x += X;
m_aVertices[i * 6 + n].m_Pos.y += Y;
}
m_NumVertices += 6;
}
SetColor(&m_aVertices[0], 0);
SetColor(&m_aVertices[1], 0);
SetColor(&m_aVertices[2], 0);
SetColor(&m_aVertices[3], 0);
SetColor(&m_aVertices[4], 0);
SetColor(&m_aVertices[5], 0);
if(m_Rotation != 0)
{
CCommandBuffer::SPoint Center;
Center.x = m_aVertices[0].m_Pos.x + (m_aVertices[1].m_Pos.x - m_aVertices[0].m_Pos.x) / 2.f;
Center.y = m_aVertices[0].m_Pos.y + (m_aVertices[2].m_Pos.y - m_aVertices[0].m_Pos.y) / 2.f;
Rotate(Center, &m_aVertices[0], 6);
}
for(int i = 0; i < 6; ++i)
{
m_aVertices[i].m_Pos.x += X;
m_aVertices[i].m_Pos.y += Y;
}
m_NumVertices += 6;
}
else
{
mem_copy(m_aVertices, &Container.m_Quads[QuadOffset], sizeof(CCommandBuffer::SVertex) * 4 * 1);
SetColor(&m_aVertices[0], 0);
SetColor(&m_aVertices[1], 0);
SetColor(&m_aVertices[2], 0);
SetColor(&m_aVertices[3], 0);
for(int i = 0; i < 4; ++i)
for(int i = 0; i < QuadDrawNum; ++i)
{
m_aVertices[i].m_Pos.x *= ScaleX;
m_aVertices[i].m_Pos.y *= ScaleY;
}
mem_copy(m_aVertices, &Container.m_Quads[QuadOffset], sizeof(CCommandBuffer::SVertex) * 4 * 1);
if(m_Rotation != 0)
{
CCommandBuffer::SPoint Center;
Center.x = m_aVertices[0].m_Pos.x + (m_aVertices[1].m_Pos.x - m_aVertices[0].m_Pos.x) / 2.f;
Center.y = m_aVertices[0].m_Pos.y + (m_aVertices[2].m_Pos.y - m_aVertices[0].m_Pos.y) / 2.f;
for(int n = 0; n < 4; ++n)
{
m_aVertices[i * 4 + n].m_Pos.x *= ScaleX;
m_aVertices[i * 4 + n].m_Pos.y *= ScaleY;
SetColor(&m_aVertices[i * 4 + n], 0);
}
Rotate(Center, &m_aVertices[0], 4);
}
if(m_Rotation != 0)
{
CCommandBuffer::SPoint Center;
Center.x = m_aVertices[i * 4 + 0].m_Pos.x + (m_aVertices[i * 4 + 1].m_Pos.x - m_aVertices[i * 4 + 0].m_Pos.x) / 2.f;
Center.y = m_aVertices[i * 4 + 0].m_Pos.y + (m_aVertices[i * 4 + 2].m_Pos.y - m_aVertices[i * 4 + 0].m_Pos.y) / 2.f;
for(int i = 0; i < 4; ++i)
{
m_aVertices[i].m_Pos.x += X;
m_aVertices[i].m_Pos.y += Y;
Rotate(Center, &m_aVertices[i * 4 + 0], 4);
}
for(int n = 0; n < 4; ++n)
{
m_aVertices[i * 4 + n].m_Pos.x += X;
m_aVertices[i * 4 + n].m_Pos.y += Y;
}
m_NumVertices += 4;
}
m_NumVertices += 4;
}
m_Drawing = DRAWING_QUADS;
WrapClamp();
@ -1574,6 +1575,11 @@ void CGraphics_Threaded::RenderQuadContainerAsSprite(int ContainerIndex, int Qua
WrapNormal();
}
void CGraphics_Threaded::RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX, float ScaleY)
{
RenderQuadContainerEx(ContainerIndex, QuadOffset, 1, X, Y, ScaleX, ScaleY);
}
void CGraphics_Threaded::RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo)
{
SQuadContainer &Container = m_QuadContainers[ContainerIndex];

View file

@ -992,6 +992,7 @@ public:
void DeleteQuadContainer(int ContainerIndex) override;
void RenderQuadContainer(int ContainerIndex, int QuadDrawNum) override;
void RenderQuadContainer(int ContainerIndex, int QuadOffset, int QuadDrawNum) override;
void RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override;
void RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) override;
void RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo) override;

View file

@ -229,6 +229,12 @@ class CTextRender : public IEngineTextRender
m_FirstFreeTextContainerIndex = Index;
}
void FreeTextContainer(int Index)
{
m_TextContainers[Index].Reset();
FreeTextContainerIndex(Index);
}
STextContainer &GetTextContainer(int Index)
{
if(Index >= (int)m_TextContainers.size())
@ -241,12 +247,6 @@ class CTextRender : public IEngineTextRender
return m_TextContainers[Index];
}
void FreeTextContainer(int Index)
{
m_TextContainers[Index].Reset();
FreeTextContainerIndex(Index);
}
int WordLength(const char *pText)
{
int Length = 0;
@ -766,6 +766,13 @@ public:
pCursor->m_GlyphCount = 0;
pCursor->m_CharCount = 0;
pCursor->m_MaxCharacterHeight = 0;
pCursor->m_LongestLineWidth = 0;
}
virtual void MoveCursor(CTextCursor *pCursor, float x, float y)
{
pCursor->m_X += x;
pCursor->m_Y += y;
}
virtual void Text(void *pFontSetV, float x, float y, float Size, const char *pText, float LineWidth)
@ -1134,6 +1141,7 @@ public:
int OldRenderFlags = m_RenderFlags;
if(pCursor->m_LineWidth <= 0)
SetRenderFlags(OldRenderFlags | ETextRenderFlags::TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE);
TextContainer.m_RenderFlags = m_RenderFlags;
SetRenderFlags(OldRenderFlags);
@ -1287,6 +1295,7 @@ public:
const char *pTmp = pCurrent;
int NextCharacter = str_utf8_decode(&pTmp);
while(pCurrent < pBatchEnd)
{
TextContainer.m_CharCount += pTmp - pCurrent;
@ -1401,6 +1410,9 @@ public:
pCursor->m_GlyphCount++;
++CharacterCounter;
}
if(DrawX > pCursor->m_LongestLineWidth)
pCursor->m_LongestLineWidth = DrawX;
}
if(NewLine)

View file

@ -331,6 +331,7 @@ public:
virtual void DeleteQuadContainer(int ContainerIndex) = 0;
virtual void RenderQuadContainer(int ContainerIndex, int QuadDrawNum) = 0;
virtual void RenderQuadContainer(int ContainerIndex, int QuadOffset, int QuadDrawNum) = 0;
virtual void RenderQuadContainerEx(int ContainerIndex, int QuadOffset, int QuadDrawNum, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) = 0;
virtual void RenderQuadContainerAsSprite(int ContainerIndex, int QuadOffset, float X, float Y, float ScaleX = 1.f, float ScaleY = 1.f) = 0;
struct SRenderSpriteInfo

View file

@ -265,6 +265,9 @@ MACRO_CONFIG_INT(SvRejoinTeam0, sv_rejoin_team_0, 1, 0, 1, CFGFLAG_SERVER, "Make
MACRO_CONFIG_INT(ClReconnectTimeout, cl_reconnect_timeout, 120, 0, 600, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How many seconds to wait before reconnecting (after timeout, 0 for off)")
MACRO_CONFIG_INT(ClReconnectFull, cl_reconnect_full, 5, 0, 600, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How many seconds to wait before reconnecting (when server is full, 0 for off)")
MACRO_CONFIG_INT(ClChatTee, cl_chat_tee, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show a tee before the player name in chat");
MACRO_CONFIG_INT(ClChatBackground, cl_chat_background, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show a background for each chat message");
MACRO_CONFIG_COL(ClMessageSystemColor, cl_message_system_color, 2817983, CFGFLAG_CLIENT | CFGFLAG_SAVE, "System message color")
MACRO_CONFIG_COL(ClMessageClientColor, cl_message_client_color, 9633471, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Client message color")
MACRO_CONFIG_COL(ClMessageHighlightColor, cl_message_highlight_color, 65471, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Highlighted message color")

View file

@ -49,6 +49,8 @@ public:
float m_X, m_Y;
float m_MaxCharacterHeight;
float m_LongestLineWidth;
CFont *m_pFont;
float m_FontSize;
float m_AlignedFontSize;
@ -78,6 +80,7 @@ class ITextRender : public IInterface
MACRO_INTERFACE("textrender", 0)
public:
virtual void SetCursor(CTextCursor *pCursor, float x, float y, float FontSize, int Flags) = 0;
virtual void MoveCursor(CTextCursor *pCursor, float x, float y) = 0;
virtual CFont *LoadFont(const char *pFilename, const unsigned char *pBuf, size_t Size) = 0;
virtual bool LoadFallbackFont(CFont *pFont, const char *pFilename, const unsigned char *pBuf, size_t Size) = 0;

View file

@ -14,10 +14,12 @@
#include <game/generated/client_data.h>
#include <game/generated/protocol.h>
#include <game/client/animstate.h>
#include <game/client/gameclient.h>
#include <game/client/components/console.h>
#include <game/client/components/scoreboard.h>
#include <game/client/components/skins.h>
#include <game/client/components/sounds.h>
#include <game/localization.h>
@ -29,6 +31,7 @@ CChat::CChat()
{
// reset the container indices, so the text containers can be deleted on reset
m_aLines[i].m_TextContainerIndex = -1;
m_aLines[i].m_QuadContainerIndex = -1;
}
#define CHAT_COMMAND(name, params, flags, callback, userdata, help) RegisterCommand(name, params, flags, help);
@ -44,31 +47,43 @@ void CChat::RegisterCommand(const char *pName, const char *pParams, int flags, c
m_Commands.add_unsorted(CCommand{pName, pParams});
}
void CChat::OnWindowResize()
void CChat::RebuildChat()
{
for(int i = 0; i < MAX_LINES; i++)
{
if(m_aLines[i].m_TextContainerIndex != -1)
TextRender()->DeleteTextContainer(m_aLines[i].m_TextContainerIndex);
m_aLines[i].m_TextContainerIndex = -1;
if(m_aLines[i].m_QuadContainerIndex != -1)
Graphics()->DeleteQuadContainer(m_aLines[i].m_QuadContainerIndex);
m_aLines[i].m_QuadContainerIndex = -1;
// recalculate sizes
m_aLines[i].m_YOffset[0] = -1.f;
m_aLines[i].m_YOffset[1] = -1.f;
}
}
void CChat::OnWindowResize()
{
RebuildChat();
}
void CChat::Reset()
{
for(int i = 0; i < MAX_LINES; i++)
{
if(m_aLines[i].m_TextContainerIndex != -1)
TextRender()->DeleteTextContainer(m_aLines[i].m_TextContainerIndex);
if(m_aLines[i].m_QuadContainerIndex != -1)
Graphics()->DeleteQuadContainer(m_aLines[i].m_QuadContainerIndex);
m_aLines[i].m_Time = 0;
m_aLines[i].m_aText[0] = 0;
m_aLines[i].m_aName[0] = 0;
m_aLines[i].m_Friend = false;
m_aLines[i].m_TextContainerIndex = -1;
m_aLines[i].m_QuadContainerIndex = -1;
m_aLines[i].m_TimesRepeated = 0;
m_aLines[i].m_HasRenderTee = false;
}
m_PrevScoreBoardShowed = false;
m_PrevShowChat = false;
@ -136,6 +151,18 @@ void CChat::ConEcho(IConsole::IResult *pResult, void *pUserData)
((CChat *)pUserData)->Echo(pResult->GetString(0));
}
void CChat::ConchainChatTee(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
((CChat *)pUserData)->RebuildChat();
}
void CChat::ConchainChatBackground(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
((CChat *)pUserData)->RebuildChat();
}
void CChat::Echo(const char *pString)
{
AddLine(-2, 0, pString);
@ -148,6 +175,8 @@ void CChat::OnConsoleInit()
Console()->Register("chat", "s['team'|'all'] ?r[message]", CFGFLAG_CLIENT, ConChat, this, "Enable chat with all/team mode");
Console()->Register("+show_chat", "", CFGFLAG_CLIENT, ConShowChat, this, "Show chat");
Console()->Register("echo", "r[message]", CFGFLAG_CLIENT, ConEcho, this, "Echo the text in chat window");
Console()->Chain("cl_chat_tee", ConchainChatTee, this);
Console()->Chain("cl_chat_background", ConchainChatBackground, this);
}
bool CChat::OnInput(IInput::CEvent Event)
@ -662,13 +691,16 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
CLine *pCurrentLine = &m_aLines[m_CurrentLine];
// If it's a client message, m_aText will have ": " prepended so we have to work around it.
if(pCurrentLine->m_Team == Team && pCurrentLine->m_ClientID == ClientID &&
((ClientID < 0 && str_comp(pCurrentLine->m_aText, pLine) == 0) || (ClientID >= 0 && str_length(pCurrentLine->m_aText) > 2 && str_comp(pCurrentLine->m_aText + 2, pLine) == 0)))
if(pCurrentLine->m_Team == Team && pCurrentLine->m_ClientID == ClientID && str_comp(pCurrentLine->m_aText, pLine) == 0)
{
pCurrentLine->m_TimesRepeated++;
if(pCurrentLine->m_TextContainerIndex != -1)
TextRender()->DeleteTextContainer(pCurrentLine->m_TextContainerIndex);
pCurrentLine->m_TextContainerIndex = -1;
if(pCurrentLine->m_QuadContainerIndex != -1)
Graphics()->DeleteQuadContainer(pCurrentLine->m_QuadContainerIndex);
pCurrentLine->m_QuadContainerIndex = -1;
pCurrentLine->m_Time = time();
pCurrentLine->m_YOffset[0] = -1.f;
pCurrentLine->m_YOffset[1] = -1.f;
@ -690,6 +722,10 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
TextRender()->DeleteTextContainer(pCurrentLine->m_TextContainerIndex);
pCurrentLine->m_TextContainerIndex = -1;
if(pCurrentLine->m_QuadContainerIndex != -1)
Graphics()->DeleteQuadContainer(pCurrentLine->m_QuadContainerIndex);
pCurrentLine->m_QuadContainerIndex = -1;
// check for highlighted name
if(Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
@ -751,16 +787,35 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
Highlighted = true;
}
else
str_copy(pCurrentLine->m_aName, m_pClient->m_aClients[ClientID].m_aName, sizeof(pCurrentLine->m_aName));
str_format(pCurrentLine->m_aName, sizeof(pCurrentLine->m_aName), "%s", m_pClient->m_aClients[ClientID].m_aName);
str_format(pCurrentLine->m_aText, sizeof(pCurrentLine->m_aText), ": %s", pLine);
str_format(pCurrentLine->m_aText, sizeof(pCurrentLine->m_aText), "%s", pLine);
pCurrentLine->m_Friend = m_pClient->m_aClients[ClientID].m_Friend;
}
pCurrentLine->m_HasRenderTee = false;
pCurrentLine->m_Friend = ClientID >= 0 ? m_pClient->m_aClients[ClientID].m_Friend : false;
if(pCurrentLine->m_ClientID >= 0 && pCurrentLine->m_aName[0] != '\0')
{
if(g_Config.m_ClChatTee)
{
pCurrentLine->m_CustomColoredSkin = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_CustomColoredSkin;
if(pCurrentLine->m_CustomColoredSkin)
pCurrentLine->m_RenderSkin = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_ColorableRenderSkin;
else
pCurrentLine->m_RenderSkin = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_OriginalRenderSkin;
str_copy(pCurrentLine->m_aSkinName, m_pClient->m_aClients[pCurrentLine->m_ClientID].m_aSkinName, sizeof(pCurrentLine->m_aSkinName));
pCurrentLine->m_ColorBody = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_ColorBody;
pCurrentLine->m_ColorFeet = m_pClient->m_aClients[pCurrentLine->m_ClientID].m_RenderInfo.m_ColorFeet;
pCurrentLine->m_HasRenderTee = true;
}
}
char aBuf[1024];
str_format(aBuf, sizeof(aBuf), "%s%s", pCurrentLine->m_aName, pCurrentLine->m_aText);
str_format(aBuf, sizeof(aBuf), "%s: %s", pCurrentLine->m_aName, pCurrentLine->m_aText);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, Team >= 2 ? "whisper" : (pCurrentLine->m_Team ? "teamchat" : "chat"), aBuf, Highlighted);
}
@ -786,7 +841,7 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
if(Now - m_aLastSoundPlayed[CHAT_HIGHLIGHT] >= time_freq() * 3 / 10)
{
char aBuf[1024];
str_format(aBuf, sizeof(aBuf), "%s%s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText);
str_format(aBuf, sizeof(aBuf), "%s: %s", m_aLines[m_CurrentLine].m_aName, m_aLines[m_CurrentLine].m_aText);
Client()->Notify("DDNet Chat", aBuf);
if(g_Config.m_SndHighlight)
{
@ -813,27 +868,65 @@ void CChat::AddLine(int ClientID, int Team, const char *pLine)
}
}
void CChat::RefindSkins()
{
for(int i = 0; i < MAX_LINES; i++)
{
int r = ((m_CurrentLine - i) + MAX_LINES) % MAX_LINES;
if(m_aLines[r].m_TextContainerIndex == -1)
continue;
if(m_aLines[r].m_HasRenderTee)
{
const CSkin *pSkin = m_pClient->m_pSkins->Get(m_pClient->m_pSkins->Find(m_aLines[r].m_aSkinName));
if(m_aLines[r].m_CustomColoredSkin)
m_aLines[r].m_RenderSkin = pSkin->m_ColorableSkin;
else
m_aLines[r].m_RenderSkin = pSkin->m_OriginalSkin;
}
}
}
void CChat::OnPrepareLines()
{
float x = 5.0f;
float y = 300.0f - 28.0f;
float FontSize = 6.0f;
float FontSize = FONT_SIZE;
bool ForceRecreate = m_pClient->m_pScoreboard->Active() != m_PrevScoreBoardShowed;
bool ShowLargeArea = m_Show || g_Config.m_ClShowChat == 2;
ForceRecreate |= ShowLargeArea != m_PrevShowChat;
m_PrevScoreBoardShowed = m_pClient->m_pScoreboard->Active();
m_PrevShowChat = ShowLargeArea;
float RealMsgPaddingX = MESSAGE_PADDING_X;
float RealMsgPaddingY = MESSAGE_PADDING_Y;
float RealMsgPaddingTee = MESSAGE_TEE_SIZE + MESSAGE_TEE_PADDING_RIGHT;
if(!g_Config.m_ClChatBackground)
{
RealMsgPaddingX = 0;
RealMsgPaddingY = (g_Config.m_ClChatTee ? (MESSAGE_TEE_SIZE - FONT_SIZE) : 0);
}
if(!g_Config.m_ClChatTee)
RealMsgPaddingTee = 0;
int64 Now = time();
float LineWidth = m_pClient->m_pScoreboard->Active() ? 90.0f : 200.0f;
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 230.0f : m_PrevShowChat ? 50.0f : 200.0f;
float LineWidth = (m_pClient->m_pScoreboard->Active() ? 90.0f : 200.0f) - RealMsgPaddingX - RealMsgPaddingTee;
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 180.0f : m_PrevShowChat ? 50.0f : 200.0f;
float Begin = x;
float TextBegin = Begin + RealMsgPaddingX / 2.0f;
CTextCursor Cursor;
int OffsetType = m_pClient->m_pScoreboard->Active() ? 1 : 0;
for(int i = 0; i < MAX_LINES; i++)
{
int r = ((m_CurrentLine - i) + MAX_LINES) % MAX_LINES;
if(Now > m_aLines[r].m_Time + 16 * time_freq() && !m_PrevShowChat)
break;
@ -845,14 +938,19 @@ void CChat::OnPrepareLines()
m_aLines[r].m_TextContainerIndex = -1;
char aName[64] = "";
if(m_aLines[r].m_QuadContainerIndex != -1)
Graphics()->DeleteQuadContainer(m_aLines[r].m_QuadContainerIndex);
m_aLines[r].m_QuadContainerIndex = -1;
char aName[64 + 12] = "";
if(g_Config.m_ClShowIDs && m_aLines[r].m_ClientID >= 0 && m_aLines[r].m_aName[0] != '\0')
{
if(m_aLines[r].m_ClientID >= 10)
str_format(aName, sizeof(aName), "%d: ", m_aLines[r].m_ClientID);
if(m_aLines[r].m_ClientID < 10)
str_format(aName, sizeof(aName), " %d: ", m_aLines[r].m_ClientID);
else
str_format(aName, sizeof(aName), "%d: ", m_aLines[r].m_ClientID);
str_format(aName, sizeof(aName), "%d: ", m_aLines[r].m_ClientID);
}
str_append(aName, m_aLines[r].m_aName, sizeof(aName));
@ -863,20 +961,38 @@ void CChat::OnPrepareLines()
else
str_format(aCount, sizeof(aCount), " [%d]", m_aLines[r].m_TimesRepeated + 1);
if(!g_Config.m_ClChatTee)
{
m_aLines[r].m_HasRenderTee = false;
}
// get the y offset (calculate it if we haven't done that yet)
if(m_aLines[r].m_YOffset[OffsetType] < 0.0f)
{
TextRender()->SetCursor(&Cursor, Begin, 0.0f, FontSize, 0);
TextRender()->SetCursor(&Cursor, TextBegin, 0.0f, FontSize, 0);
Cursor.m_LineWidth = LineWidth;
if(g_Config.m_ClMessageFriend)
Cursor.m_X += RealMsgPaddingTee;
if(m_aLines[r].m_Friend && g_Config.m_ClMessageFriend)
{
TextRender()->TextEx(&Cursor, "", -1);
}
TextRender()->TextEx(&Cursor, aName, -1);
if(m_aLines[r].m_TimesRepeated > 0)
TextRender()->TextEx(&Cursor, aCount, -1);
TextRender()->TextEx(&Cursor, m_aLines[r].m_aText, -1);
m_aLines[r].m_YOffset[OffsetType] = Cursor.m_Y + Cursor.m_FontSize;
TextRender()->TextEx(&Cursor, ": ", -1);
CTextCursor AppendCursor = Cursor;
AppendCursor.m_StartX = Cursor.m_X;
TextRender()->TextEx(&AppendCursor, m_aLines[r].m_aText, -1);
m_aLines[r].m_YOffset[OffsetType] = AppendCursor.m_Y + AppendCursor.m_FontSize + RealMsgPaddingY;
}
y -= m_aLines[r].m_YOffset[OffsetType];
// cut off if msgs waste too much space
@ -884,51 +1000,57 @@ void CChat::OnPrepareLines()
break;
// the position the text was created
m_aLines[r].m_TextYOffset = y;
m_aLines[r].m_TextYOffset = y + RealMsgPaddingY / 2.f;
// reset the cursor
TextRender()->SetCursor(&Cursor, Begin, y, FontSize, TEXTFLAG_RENDER);
TextRender()->SetCursor(&Cursor, TextBegin, m_aLines[r].m_TextYOffset, FontSize, TEXTFLAG_RENDER);
Cursor.m_LineWidth = LineWidth;
if(g_Config.m_ClMessageFriend)
// Message is from valid player
if(m_aLines[r].m_ClientID >= 0 && m_aLines[r].m_aName[0] != '\0')
{
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClMessageFriendColor));
TextRender()->TextColor(rgb.WithAlpha(m_aLines[r].m_Friend ? 1.f : 0.f)); //Less ugly hack to align messages
if(m_aLines[r].m_TextContainerIndex == -1)
m_aLines[r].m_TextContainerIndex = TextRender()->CreateTextContainer(&Cursor, "");
else
TextRender()->AppendTextContainer(&Cursor, m_aLines[r].m_TextContainerIndex, "");
Cursor.m_X += RealMsgPaddingTee;
if(m_aLines[r].m_Friend && g_Config.m_ClMessageFriend)
{
const char *pHeartStr = "";
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClMessageFriendColor));
TextRender()->TextColor(rgb.WithAlpha(1.f));
if(m_aLines[r].m_TextContainerIndex == -1)
m_aLines[r].m_TextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pHeartStr);
else
TextRender()->AppendTextContainer(&Cursor, m_aLines[r].m_TextContainerIndex, pHeartStr);
}
}
// render name
ColorRGBA NameColor;
if(m_aLines[r].m_ClientID == -1) // system
{
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClMessageSystemColor));
TextRender()->TextColor(rgb);
NameColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClMessageSystemColor));
}
else if(m_aLines[r].m_ClientID == -2) // client
{
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClMessageClientColor));
TextRender()->TextColor(rgb);
NameColor = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClMessageClientColor));
}
else if(m_aLines[r].m_Team)
{
ColorRGBA rgb = CalculateNameColor(ColorHSLA(g_Config.m_ClMessageTeamColor));
TextRender()->TextColor(rgb); // team message
NameColor = CalculateNameColor(ColorHSLA(g_Config.m_ClMessageTeamColor));
}
else if(m_aLines[r].m_NameColor == TEAM_RED)
TextRender()->TextColor(1.0f, 0.5f, 0.5f, 1.f); // red
NameColor = ColorRGBA(1.0f, 0.5f, 0.5f, 1.f); // red
else if(m_aLines[r].m_NameColor == TEAM_BLUE)
TextRender()->TextColor(0.7f, 0.7f, 1.0f, 1.f); // blue
NameColor = ColorRGBA(0.7f, 0.7f, 1.0f, 1.f); // blue
else if(m_aLines[r].m_NameColor == TEAM_SPECTATORS)
TextRender()->TextColor(0.75f, 0.5f, 0.75f, 1.f); // spectator
NameColor = ColorRGBA(0.75f, 0.5f, 0.75f, 1.f); // spectator
else if(m_aLines[r].m_ClientID >= 0 && g_Config.m_ClChatTeamColors && m_pClient->m_Teams.Team(m_aLines[r].m_ClientID))
{
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA(m_pClient->m_Teams.Team(m_aLines[r].m_ClientID) / 64.0f, 1.0f, 0.75f));
TextRender()->TextColor(rgb);
NameColor = color_cast<ColorRGBA>(ColorHSLA(m_pClient->m_Teams.Team(m_aLines[r].m_ClientID) / 64.0f, 1.0f, 0.75f));
}
else
TextRender()->TextColor(0.8f, 0.8f, 0.8f, 1.f);
NameColor = ColorRGBA(0.8f, 0.8f, 0.8f, 1.f);
TextRender()->TextColor(NameColor);
if(m_aLines[r].m_TextContainerIndex == -1)
m_aLines[r].m_TextContainerIndex = TextRender()->CreateTextContainer(&Cursor, aName);
@ -944,6 +1066,15 @@ void CChat::OnPrepareLines()
TextRender()->AppendTextContainer(&Cursor, m_aLines[r].m_TextContainerIndex, aCount);
}
if(m_aLines[r].m_ClientID >= 0 && m_aLines[r].m_aName[0] != '\0')
{
TextRender()->TextColor(NameColor);
if(m_aLines[r].m_TextContainerIndex == -1)
m_aLines[r].m_TextContainerIndex = TextRender()->CreateTextContainer(&Cursor, ": ");
else
TextRender()->AppendTextContainer(&Cursor, m_aLines[r].m_TextContainerIndex, ": ");
}
// render line
ColorRGBA Color;
if(m_aLines[r].m_ClientID == -1) // system
@ -959,10 +1090,20 @@ void CChat::OnPrepareLines()
TextRender()->TextColor(Color);
CTextCursor AppendCursor = Cursor;
AppendCursor.m_StartX = Cursor.m_X;
if(m_aLines[r].m_TextContainerIndex == -1)
m_aLines[r].m_TextContainerIndex = TextRender()->CreateTextContainer(&Cursor, m_aLines[r].m_aText);
m_aLines[r].m_TextContainerIndex = TextRender()->CreateTextContainer(&AppendCursor, m_aLines[r].m_aText);
else
TextRender()->AppendTextContainer(&Cursor, m_aLines[r].m_TextContainerIndex, m_aLines[r].m_aText);
TextRender()->AppendTextContainer(&AppendCursor, m_aLines[r].m_TextContainerIndex, m_aLines[r].m_aText);
if(g_Config.m_ClChatBackground && (m_aLines[r].m_aText[0] != '\0' || m_aLines[r].m_aName[0] != '\0'))
{
float Height = m_aLines[r].m_YOffset[OffsetType];
Graphics()->SetColor(1, 1, 1, 1);
m_aLines[r].m_QuadContainerIndex = RenderTools()->CreateRoundRectQuadContainer(Begin, y, AppendCursor.m_LongestLineWidth - Begin + RealMsgPaddingX, Height, RealMsgPaddingY, CUI::CORNER_ALL);
}
}
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
@ -1066,8 +1207,18 @@ void CChat::OnRender()
OnPrepareLines();
int64 Now = time();
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 230.0f : m_PrevShowChat ? 50.0f : 200.0f;
float HeightLimit = m_pClient->m_pScoreboard->Active() ? 180.0f : m_PrevShowChat ? 50.0f : 200.0f;
int OffsetType = m_pClient->m_pScoreboard->Active() ? 1 : 0;
float RealMsgPaddingX = MESSAGE_PADDING_X;
float RealMsgPaddingY = MESSAGE_PADDING_Y;
if(!g_Config.m_ClChatBackground)
{
RealMsgPaddingX = 0;
RealMsgPaddingY = (g_Config.m_ClChatTee ? (MESSAGE_TEE_SIZE - FONT_SIZE) : 0);
}
for(int i = 0; i < MAX_LINES; i++)
{
int r = ((m_CurrentLine - i) + MAX_LINES) % MAX_LINES;
@ -1082,11 +1233,44 @@ void CChat::OnRender()
float Blend = Now > m_aLines[r].m_Time + 14 * time_freq() && !m_PrevShowChat ? 1.0f - (Now - m_aLines[r].m_Time - 14 * time_freq()) / (2.0f * time_freq()) : 1.0f;
// Draw backgrounds for messages in one batch
if(g_Config.m_ClChatBackground)
{
Graphics()->TextureClear();
if(m_aLines[r].m_QuadContainerIndex != -1)
{
Graphics()->SetColor(0, 0, 0, 0.12f * Blend);
Graphics()->RenderQuadContainerEx(m_aLines[r].m_QuadContainerIndex, 0, -1, 0, ((y + RealMsgPaddingY / 2.0f) - m_aLines[r].m_TextYOffset));
}
}
if(m_aLines[r].m_TextContainerIndex != -1)
{
if(g_Config.m_ClChatTee && m_aLines[r].m_HasRenderTee)
{
CTeeRenderInfo RenderInfo;
RenderInfo.m_CustomColoredSkin = m_aLines[r].m_CustomColoredSkin;
if(m_aLines[r].m_CustomColoredSkin)
RenderInfo.m_ColorableRenderSkin = m_aLines[r].m_RenderSkin;
else
RenderInfo.m_OriginalRenderSkin = m_aLines[r].m_RenderSkin;
RenderInfo.m_ColorBody = m_aLines[r].m_ColorBody;
RenderInfo.m_ColorFeet = m_aLines[r].m_ColorFeet;
RenderInfo.m_Size = MESSAGE_TEE_SIZE;
float RowHeight = FONT_SIZE + RealMsgPaddingY;
float OffsetTeeY = MESSAGE_TEE_SIZE / 2.0f;
float FullHeightMinusTee = RowHeight - MESSAGE_TEE_SIZE;
float TWSkinUnreliableOffset = 0.5f; // teeworlds skins were always a bit in the ground
CAnimState *pIdleState = CAnimState::GetIdle();
RenderTools()->RenderTee(pIdleState, &RenderInfo, EMOTE_NORMAL, vec2(1, 0.1f), vec2(x + (RealMsgPaddingX + MESSAGE_TEE_SIZE) / 2.0f, y + OffsetTeeY + FullHeightMinusTee / 2.0f + TWSkinUnreliableOffset), Blend);
}
STextRenderColor TextOutline(0.f, 0.f, 0.f, 0.3f * Blend);
STextRenderColor Text(1.f, 1.f, 1.f, Blend);
TextRender()->RenderTextContainer(m_aLines[r].m_TextContainerIndex, &Text, &TextOutline, 0, y - m_aLines[r].m_TextYOffset);
TextRender()->RenderTextContainer(m_aLines[r].m_TextContainerIndex, &Text, &TextOutline, 0, (y + RealMsgPaddingY / 2.0f) - m_aLines[r].m_TextYOffset);
}
}
}

View file

@ -2,6 +2,7 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef GAME_CLIENT_COMPONENTS_CHAT_H
#define GAME_CLIENT_COMPONENTS_CHAT_H
#include <engine/shared/config.h>
#include <engine/shared/ringbuffer.h>
#include <game/client/component.h>
#include <game/client/lineinput.h>
@ -10,9 +11,16 @@ class CChat : public CComponent
{
CLineInput m_Input;
static constexpr float MESSAGE_PADDING_X = 5.0f;
static constexpr float MESSAGE_TEE_SIZE = 8.0f;
static constexpr float MESSAGE_TEE_PADDING_RIGHT = 0.5f;
static constexpr float FONT_SIZE = 6.0f;
static constexpr float MESSAGE_PADDING_Y = 3.f;
static_assert(FONT_SIZE + MESSAGE_PADDING_Y >= 8.0f, "Corners for background chat are too huge for this combination of font size and message padding.");
enum
{
MAX_LINES = 25,
MAX_LINES = 25
};
struct CLine
@ -28,6 +36,15 @@ class CChat : public CComponent
bool m_Highlighted;
int m_TextContainerIndex;
int m_QuadContainerIndex;
char m_aSkinName[sizeof(g_Config.m_ClPlayerSkin) / sizeof(g_Config.m_ClPlayerSkin[0])];
CSkin::SSkinTextures m_RenderSkin;
bool m_CustomColoredSkin;
ColorRGBA m_ColorBody;
ColorRGBA m_ColorFeet;
bool m_HasRenderTee;
float m_TextYOffset;
int m_TimesRepeated;
@ -92,6 +109,9 @@ class CChat : public CComponent
static void ConShowChat(IConsole::IResult *pResult, void *pUserData);
static void ConEcho(IConsole::IResult *pResult, void *pUserData);
static void ConchainChatTee(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainChatBackground(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
bool LineShouldHighlight(const char *pLine, const char *pName);
void StoreSave(const char *pText);
void Reset();
@ -112,9 +132,12 @@ public:
virtual void OnConsoleInit();
virtual void OnStateChange(int NewState, int OldState);
virtual void OnRender();
virtual void RefindSkins();
virtual void OnPrepareLines();
virtual void OnRelease();
virtual void OnMessage(int MsgType, void *pRawMsg);
virtual bool OnInput(IInput::CEvent Event);
void RebuildChat();
};
#endif

View file

@ -18,6 +18,7 @@
#include <game/generated/protocol.h>
#include <game/client/animstate.h>
#include <game/client/components/chat.h>
#include <game/client/components/menu_background.h>
#include <game/client/components/sounds.h>
#include <game/client/gameclient.h>
@ -1631,13 +1632,31 @@ void CMenus::RenderSettingsHUD(CUIRect MainView)
g_Config.m_ClShowChat ^= 1;
}
bool IsOldChat = !(g_Config.m_ClChatTee || g_Config.m_ClChatBackground);
Left.HSplitTop(20.0f, &Button, &Left);
if(DoButton_CheckBox(&g_Config.m_ClChatTee, Localize("Use old chat style"), IsOldChat, &Button))
{
if(IsOldChat)
{
g_Config.m_ClChatTee = 1;
g_Config.m_ClChatBackground = 1;
}
else
{
g_Config.m_ClChatTee = 0;
g_Config.m_ClChatBackground = 0;
}
GameClient()->m_pChat->RebuildChat();
}
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClChatTeamColors, Localize("Show names in chat in team colors"), g_Config.m_ClChatTeamColors, &Button))
{
g_Config.m_ClChatTeamColors ^= 1;
}
Left.HSplitTop(20.0f, &Button, &Left);
Right.HSplitTop(20.0f, &Button, &Right);
if(DoButton_CheckBox(&g_Config.m_ClShowKillMessages, Localize("Show kill messages"), g_Config.m_ClShowKillMessages, &Button))
{
g_Config.m_ClShowKillMessages ^= 1;

View file

@ -2888,6 +2888,7 @@ void CGameClient::RefindSkins()
}
}
m_pGhost->RefindSkin();
m_pChat->RefindSkins();
}
void CGameClient::LoadMapSettings()