Cl_text_entities_size (#1632)

* new command added

* fix code duplication after merge

* merge #1632 suggestions

* align the texture to the center vertically

* refactor

* fix RenderSwitchOverlay

* Update src/engine/client/text.cpp

Co-Authored-By: BannZay <bannzay3@gmail.com>

* Apply suggestions from code review

Co-Authored-By: BannZay <bannzay3@gmail.com>

* Apply suggestions from code review

* Apply suggestions from code review

Co-Authored-By: BannZay <bannzay3@gmail.com>

* Apply suggestions from code review
This commit is contained in:
Andrew 2019-05-06 15:19:10 +03:00 committed by Dennis Felsing
parent 76f2a5965f
commit 0fffd7705f
8 changed files with 186 additions and 132 deletions

View file

@ -1698,64 +1698,14 @@ public:
Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);
}
virtual void UploadEntityLayerText(int TextureID, const char *pText, int Length, float x, float y, int Size, int MaxWidth, int MaxSize = -1, int MinSize = -1)
virtual void UploadEntityLayerText(int TextureID, const char *pText, int Length, float x, float y, int FontSize)
{
const char *pCurrent = (char *)pText;
const char *pEnd = pCurrent + Length;
CFont *pFont = m_pDefaultFont;
FT_Bitmap *pBitmap;
if(!pFont)
return;
// set length
if(Length < 0)
Length = str_length(pText);
const char *pCurrent = (char *)pText;
const char *pEnd = pCurrent+Length;
int WidthLastChars = 0;
int FontSize = Size;
//adjust font size by the full space
if(Size == -1)
{
int WidthOfText = 0;
FT_Set_Pixel_Sizes(pFont->m_FtFace, 0, 100);
while(pCurrent < pEnd)
{
const char *pTmp = pCurrent;
int NextCharacter = str_utf8_decode(&pTmp);
if(NextCharacter)
{
FT_Int32 FTFlags = 0;
#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 7 && (FREETYPE_MINOR > 7 || FREETYPE_PATCH >= 1)
FTFlags = FT_LOAD_BITMAP_METRICS_ONLY | FT_LOAD_NO_BITMAP;
#else
FTFlags = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP;
#endif
if(FT_Load_Char(pFont->m_FtFace, NextCharacter, FTFlags))
{
dbg_msg("pFont", "error loading glyph %d", NextCharacter);
pCurrent = pTmp;
continue;
}
WidthOfText += (pFont->m_FtFace->glyph->metrics.width >> 6) + 1;
}
pCurrent = pTmp;
}
FontSize = 100.f / ((float)WidthOfText / (float)MaxWidth);
if(FontSize > MaxSize)
FontSize = MaxSize;
pCurrent = (char *)pText;
pEnd = pCurrent + Length;
}
while(pCurrent < pEnd)
{
const char *pTmp = pCurrent;
@ -1775,18 +1725,15 @@ public:
}
pBitmap = &pFont->m_FtFace->glyph->bitmap; // ignore_convention
int SlotW = pBitmap->width;
int SlotH = pBitmap->rows;
int SlotSize = SlotW*SlotH;
// prepare glyph data
mem_zero(ms_aGlyphData, SlotSize);
int MaxSizeWidth = (MaxWidth - WidthLastChars);
if(MaxSizeWidth > 0)
{
int SlotW = ((((unsigned int)MaxSizeWidth) < pBitmap->width) ? MaxSizeWidth : pBitmap->width);
int SlotH = pBitmap->rows;
int SlotSize = SlotW*SlotH;
// prepare glyph data
mem_zero(ms_aGlyphData, SlotSize);
if(pBitmap->pixel_mode == FT_PIXEL_MODE_GRAY) // ignore_convention
if(pBitmap->pixel_mode == FT_PIXEL_MODE_GRAY) // ignore_convention
{
for(py = 0; py < (unsigned)SlotH; py++) // ignore_convention
for(px = 0; px < (unsigned)SlotW; px++)
@ -1794,15 +1741,63 @@ public:
ms_aGlyphData[(py)*SlotW + px] = pBitmap->buffer[py*pBitmap->width + px]; // ignore_convention
}
}
Graphics()->LoadTextureRawSub(TextureID, x + WidthLastChars, y, SlotW, SlotH, CImageInfo::FORMAT_ALPHA, ms_aGlyphData);
WidthLastChars += (SlotW + 1);
}
Graphics()->LoadTextureRawSub(TextureID, x + WidthLastChars, y, SlotW, SlotH, CImageInfo::FORMAT_ALPHA, ms_aGlyphData);
WidthLastChars += (SlotW + 1);
}
pCurrent = pTmp;
}
}
virtual int AdjustFontSize(const char *pText, int TextLength, int MaxSize = -1)
{
int WidthOfText = CalculateTextWidth(pText, TextLength, 0, 100);
int FontSize = 100.f / ((float)WidthOfText / (float)MaxSize);
if (MaxSize > 0 && FontSize > MaxSize)
FontSize = MaxSize;
return FontSize;
}
virtual int CalculateTextWidth(const char *pText, int TextLength, int FontWidth, int FontHeight)
{
CFont *pFont = m_pDefaultFont;
const char *pCurrent = (char *)pText;
const char *pEnd = pCurrent + TextLength;
int WidthOfText = 0;
FT_Set_Pixel_Sizes(pFont->m_FtFace, FontWidth, FontHeight);
while (pCurrent < pEnd)
{
const char *pTmp = pCurrent;
int NextCharacter = str_utf8_decode(&pTmp);
if(NextCharacter)
{
FT_Int32 FTFlags = 0;
#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 7 && (FREETYPE_MINOR > 7 || FREETYPE_PATCH >= 1)
FTFlags = FT_LOAD_BITMAP_METRICS_ONLY | FT_LOAD_NO_BITMAP;
#else
FTFlags = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP;
#endif
if(FT_Load_Char(pFont->m_FtFace, NextCharacter, FTFlags))
{
dbg_msg("pFont", "error loading glyph %d", NextCharacter);
pCurrent = pTmp;
continue;
}
WidthOfText += (pFont->m_FtFace->glyph->metrics.width >> 6) + 1;
}
pCurrent = pTmp;
}
return WidthOfText;
}
virtual void OnWindowResize()
{
bool FoundTextContainer = false;

View file

@ -98,7 +98,8 @@ public:
virtual void RenderTextContainer(int TextContainerIndex, STextRenderColor *pTextColor, STextRenderColor *pTextOutlineColor) = 0;
virtual void RenderTextContainer(int TextContainerIndex, STextRenderColor *pTextColor, STextRenderColor *pTextOutlineColor, float X, float Y) = 0;
virtual void UploadEntityLayerText(int TextureID, const char *pText, int Length, float x, float y, int Size, int MaxWidth, int MaxSize = -1, int MinSize = -1) = 0;
virtual void UploadEntityLayerText(int TextureID, const char *pText, int Length, float x, float y, int FontHeight) = 0;
virtual int AdjustFontSize(const char *pText, int TextLength, int MaxSize = -1) = 0;
// old foolish interface
virtual void TextColor(float r, float g, float b, float a) = 0;

View file

@ -10,72 +10,23 @@
#include "mapimages.h"
CMapImages::CMapImages()
CMapImages::CMapImages() : CMapImages(100)
{
}
CMapImages::CMapImages(int TextureSize)
{
m_Count = 0;
m_EntitiesTextures = -1;
m_OverlayBottomTexture = -1;
m_OverlayTopTexture = -1;
m_OverlayCenterTexture = -1;
m_TextureScale = TextureSize;
}
void CMapImages::OnInit()
{
//TODO: improve this a bit -- with better from sizes etc.
if(m_OverlayBottomTexture == -1)
{
void *pMem = calloc(1024 * 1024, 1);
m_OverlayBottomTexture = Graphics()->LoadTextureRaw(1024, 1024, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, IGraphics::TEXLOAD_NOMIPMAPS);
free(pMem);
for(int i = 0; i < 256; ++i)
{
char buff[4];
str_format(buff, 4, "%d", i);
float x = (i%16) * 64;
float y = (i/16) * 64;
TextRender()->UploadEntityLayerText(m_OverlayBottomTexture, buff, -1, x+1, y + 12 + 32, 20, 64-1);
}
}
if(m_OverlayTopTexture == -1)
{
void *pMem = calloc(1024 * 1024, 1);
m_OverlayTopTexture = Graphics()->LoadTextureRaw(1024, 1024, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, IGraphics::TEXLOAD_NOMIPMAPS);
free(pMem);
for(int i = 0; i < 256; ++i)
{
char buff[4];
str_format(buff, 4, "%d", i);
float x = (i%16) * 64;
float y = (i/16) * 64;
TextRender()->UploadEntityLayerText(m_OverlayTopTexture, buff, -1, x+1, y+1, 20, 64-1);
}
}
if(m_OverlayCenterTexture == -1)
{
void *pMem = calloc(1024 * 1024, 1);
m_OverlayCenterTexture = Graphics()->LoadTextureRaw(1024, 1024, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, IGraphics::TEXLOAD_NOMIPMAPS);
free(pMem);
for(int i = 0; i < 256; ++i)
{
char buff[4];
str_format(buff, 4, "%d", i);
int len = str_length(buff);
float x = (i%16) * 64;
float y = (i/16) * 64;
int MinSize = (len == 3 ? 20 : 50);
int OffY = (len == 3 ? 10 : 5);
int OffX = (len == 3 ? 5 : 1);
TextRender()->UploadEntityLayerText(m_OverlayCenterTexture, buff, -1, x + OffX, y + OffY, -1, 64-(OffX*2), 64, MinSize);
}
}
InitOverlayTextures();
}
void CMapImages::OnMapLoad()
@ -196,3 +147,74 @@ int CMapImages::GetOverlayCenter()
{
return m_OverlayCenterTexture;
}
void CMapImages::SetTextureScale(int Scale)
{
if(m_TextureScale == Scale)
return;
m_TextureScale = Scale;
if(Graphics() && m_OverlayCenterTexture != -1) // check if component was initialized
{
// reinitialize component
Graphics()->UnloadTexture(m_OverlayBottomTexture);
Graphics()->UnloadTexture(m_OverlayTopTexture);
Graphics()->UnloadTexture(m_OverlayCenterTexture);
m_OverlayBottomTexture = m_OverlayTopTexture = m_OverlayCenterTexture = -1;
InitOverlayTextures();
}
}
int CMapImages::GetTextureScale()
{
return m_TextureScale;
}
int CMapImages::UploadEntityLayerText(int TextureSize, int YOffset)
{
void *pMem = calloc(1024 * 1024, 1);
int TextureID = Graphics()->LoadTextureRaw(1024, 1024, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, IGraphics::TEXLOAD_NOMIPMAPS);
free(pMem);
char aBuf[4];
int Len = str_format(aBuf, 4, "%d", 255);
int FontSize = TextRender()->AdjustFontSize(aBuf, Len, TextureSize);
YOffset += ((TextureSize - FontSize)/2);
for(int i = 0; i < 256; ++i)
{
int Len = str_format(aBuf, 4, "%d", i);
float x = (i%16)*64;
float y = (i/16)*64;
TextRender()->UploadEntityLayerText(TextureID, aBuf, Len, x, y + YOffset, FontSize);
}
return TextureID;
}
void CMapImages::InitOverlayTextures()
{
int TextureSize = 64*m_TextureScale/100;
int TextureToVerticalCenterOffset = (64-TextureSize)/2; // should be used to move texture to the center of 64 pixels area
if(m_OverlayBottomTexture == -1)
{
m_OverlayBottomTexture = UploadEntityLayerText(TextureSize/2, 32+TextureToVerticalCenterOffset/2);
}
if(m_OverlayTopTexture == -1)
{
m_OverlayTopTexture = UploadEntityLayerText(TextureSize/2, TextureToVerticalCenterOffset/2);
}
if(m_OverlayCenterTexture == -1)
{
m_OverlayCenterTexture = UploadEntityLayerText(TextureSize, TextureToVerticalCenterOffset);
}
}

View file

@ -14,6 +14,7 @@ class CMapImages : public CComponent
char m_aEntitiesGameType[16];
public:
CMapImages();
CMapImages(int ImageSize);
int Get(int Index) const { return m_aTextures[Index]; }
int Num() const { return m_Count; }
@ -23,19 +24,25 @@ public:
void LoadBackground(class IMap *pMap);
// DDRace
int GetEntities();
int GetOverlayBottom();
int GetOverlayTop();
int GetOverlayCenter();
void SetTextureScale(int Size);
int GetTextureScale();
private:
int m_EntitiesTextures;
int m_OverlayBottomTexture;
int m_OverlayTopTexture;
int m_OverlayCenterTexture;
int m_TextureScale;
void InitOverlayTextures();
int UploadEntityLayerText(int TextureSize, int YOffset);
};
#endif

View file

@ -266,6 +266,7 @@ void CGameClient::OnConsoleInit()
Console()->Chain("dummy_skin", ConchainSpecialDummyInfoupdate, this);
Console()->Chain("cl_dummy", ConchainSpecialDummy, this);
Console()->Chain("cl_text_entities_size", ConchainClTextEntitiesSize, this);
//
m_SuppressEvents = false;
@ -350,6 +351,8 @@ void CGameClient::OnInit()
m_GameWorld.m_GameTickSpeed = SERVER_TICK_SPEED;
m_GameWorld.m_pCollision = Collision();
m_GameWorld.m_pTeams = &m_TeamsPredicted;
m_pMapimages->SetTextureScale(g_Config.m_ClTextEntitiesSize);
}
void CGameClient::OnUpdate()
@ -1793,6 +1796,17 @@ void CGameClient::ConchainSpecialDummy(IConsole::IResult *pResult, void *pUserDa
g_Config.m_ClDummy = 0;
}
void CGameClient::ConchainClTextEntitiesSize(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
if(pResult->NumArguments())
{
CGameClient *pGameClient = (CGameClient*)pUserData;
pGameClient->m_pMapimages->SetTextureScale(g_Config.m_ClTextEntitiesSize);
}
}
IGameClient *CreateGameClient()
{
return &g_GameClient;

View file

@ -118,6 +118,7 @@ class CGameClient : public IGameClient
static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainSpecialDummyInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainSpecialDummy(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainClTextEntitiesSize(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
public:
IKernel *Kernel() { return IInterface::Kernel(); }

View file

@ -415,6 +415,9 @@ void CRenderTools::RenderTeleOverlay(CTeleTile *pTele, int w, int h, float Scale
if(EndX - StartX > Graphics()->ScreenWidth() / g_Config.m_GfxTextOverlay || EndY - StartY > Graphics()->ScreenHeight() / g_Config.m_GfxTextOverlay)
return; // its useless to render text at this distance
float Size = g_Config.m_ClTextEntitiesSize/100.f;
float ToCenterOffset = (1-Size)/2.f;
for(int y = StartY; y < EndY; y++)
for(int x = StartX; x < EndX; x++)
{
@ -439,7 +442,7 @@ void CRenderTools::RenderTeleOverlay(CTeleTile *pTele, int w, int h, float Scale
char aBuf[16];
str_format(aBuf, sizeof(aBuf), "%d", Index);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, Alpha);
UI()->TextRender()->Text(0, mx*Scale - 3.f, my*Scale, Scale - 5.f, aBuf, -1);
UI()->TextRender()->Text(0, mx*Scale - 3.f, (my+ToCenterOffset)*Scale, Size*Scale, aBuf, -1);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
}
@ -460,6 +463,9 @@ void CRenderTools::RenderSpeedupOverlay(CSpeedupTile *pSpeedup, int w, int h, fl
if(EndX - StartX > Graphics()->ScreenWidth() / g_Config.m_GfxTextOverlay || EndY - StartY > Graphics()->ScreenHeight() / g_Config.m_GfxTextOverlay)
return; // its useless to render text at this distance
float Size = g_Config.m_ClTextEntitiesSize / 100.f;
float ToCenterOffset = (1-Size)/2.f;
for(int y = StartY; y < EndY; y++)
for(int x = StartX; x < EndX; x++)
{
@ -498,13 +504,13 @@ void CRenderTools::RenderSpeedupOverlay(CSpeedupTile *pSpeedup, int w, int h, fl
char aBuf[16];
str_format(aBuf, sizeof(aBuf), "%d", Force);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, Alpha);
UI()->TextRender()->Text(0, mx*Scale, (my*Scale) + 16.f + ((16.f - (Scale - 20.f)) / 2.f), Scale - 20.f, aBuf, -1);
UI()->TextRender()->Text(0, mx*Scale, (my+0.5+ToCenterOffset/2)*Scale, Size*Scale/2.f, aBuf, -1);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
if(MaxSpeed)
{
str_format(aBuf, sizeof(aBuf), "%d", MaxSpeed);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, Alpha);
UI()->TextRender()->Text(0, mx*Scale, (my*Scale) + ((16.f - (Scale - 20.f)) / 2.f), Scale - 20.f, aBuf, -1);
UI()->TextRender()->Text(0, mx*Scale, (my+ToCenterOffset/2)*Scale, Size*Scale/2.f, aBuf, -1);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
}
@ -529,6 +535,9 @@ void CRenderTools::RenderSwitchOverlay(CSwitchTile *pSwitch, int w, int h, float
if(EndX - StartX > Graphics()->ScreenWidth() / g_Config.m_GfxTextOverlay || EndY - StartY > Graphics()->ScreenHeight() / g_Config.m_GfxTextOverlay)
return; // its useless to render text at this distance
float Size = g_Config.m_ClTextEntitiesSize/100.f;
float ToCenterOffset = (1-Size)/2.f;
for(int y = StartY; y < EndY; y++)
for(int x = StartX; x < EndX; x++)
{
@ -553,7 +562,7 @@ void CRenderTools::RenderSwitchOverlay(CSwitchTile *pSwitch, int w, int h, float
char aBuf[16];
str_format(aBuf, sizeof(aBuf), "%d", Index);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, Alpha);
UI()->TextRender()->Text(0, mx*Scale, my*Scale + 16.f + ((16.f - (Scale - 20.f)) / 2.f), Scale - 20.f, aBuf, -1);
UI()->TextRender()->Text(0, mx*Scale, (my+ToCenterOffset/2)*Scale, Size*Scale/2.f, aBuf, -1);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
@ -563,7 +572,7 @@ void CRenderTools::RenderSwitchOverlay(CSwitchTile *pSwitch, int w, int h, float
char aBuf[16];
str_format(aBuf, sizeof(aBuf), "%d", Delay);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, Alpha);
UI()->TextRender()->Text(0, mx*Scale, my*Scale + ((16.f - (Scale - 20.f)) / 2.f), Scale - 20.f, aBuf, -1);
UI()->TextRender()->Text(0, mx*Scale, (my+0.5f+ToCenterOffset/2)* Scale, Size*Scale/2.f, aBuf, -1);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
}
@ -587,6 +596,8 @@ void CRenderTools::RenderTuneOverlay(CTuneTile *pTune, int w, int h, float Scale
if(EndX - StartX > Graphics()->ScreenWidth() / g_Config.m_GfxTextOverlay || EndY - StartY > Graphics()->ScreenHeight() / g_Config.m_GfxTextOverlay)
return; // its useless to render text at this distance
float Size = g_Config.m_ClTextEntitiesSize/100.f;
for(int y = StartY; y < EndY; y++)
for(int x = StartX; x < EndX; x++)
{
@ -611,7 +622,7 @@ void CRenderTools::RenderTuneOverlay(CTuneTile *pTune, int w, int h, float Scale
char aBuf[16];
str_format(aBuf, sizeof(aBuf), "%d", Index);
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, Alpha);
UI()->TextRender()->Text(0, mx*Scale+11.f, my*Scale+6.f, Scale/1.5f-5.f, aBuf, -1); // numbers shouldn't be too big and in the center of the tile
UI()->TextRender()->Text(0, mx*Scale+11.f, my*Scale+6.f, Size*Scale/1.5f-5.f, aBuf, -1); // numbers shouldn't be too big and in the center of the tile
UI()->TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
}

View file

@ -21,8 +21,11 @@ MACRO_CONFIG_INT(ClNameplatesClan, cl_nameplates_clan, 0, 0, 1, CFGFLAG_CLIENT|C
MACRO_CONFIG_INT(ClNameplatesClanSize, cl_nameplates_clan_size, 30, 0, 100, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Size of the clan plates from 0 to 100%")
MACRO_CONFIG_INT(ClNameplatesOwn, cl_nameplates_own, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show own name plate (useful for demo recording)")
MACRO_CONFIG_INT(ClTextEntities, cl_text_entities, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Render textual entity data")
MACRO_CONFIG_INT(ClTextEntitiesSize, cl_text_entities_size, 70, 0, 100, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Size of textual entity data from 0 to 100%")
MACRO_CONFIG_COL(ClAuthedPlayerColor, cl_authed_player_color, 5898211, 0, 0xFFFFFF, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Color of name of authenticated player in scoreboard")
MACRO_CONFIG_COL(ClSameClanColor, cl_same_clan_color, 5898211, 0, 0xFFFFFF, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Clan color of players with the same clan as you in scoreboard.")
MACRO_CONFIG_INT(ClEnablePingColor, cl_enable_ping_color, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Whether ping is colored in scoreboard.")
MACRO_CONFIG_INT(ClAutoswitchWeapons, cl_autoswitch_weapons, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Auto switch weapon on pickup")
MACRO_CONFIG_INT(ClAutoswitchWeaponsOutOfAmmo, cl_autoswitch_weapons_out_of_ammo, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Auto switch weapon when out of ammo")