mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-15 04:28:20 +00:00
Merge pull request #9199 from Robyt3/Client-Font-Atlas-Cleanup
More efficient glyph uploading, fix crash with very large glyphs and font sizes, refactoring
This commit is contained in:
commit
241e8be4a5
|
@ -484,7 +484,7 @@ bool CGraphics_Threaded::UnloadTextTextures(CTextureHandle &TextTexture, CTextur
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData)
|
bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer)
|
||||||
{
|
{
|
||||||
CCommandBuffer::SCommand_TextTexture_Update Cmd;
|
CCommandBuffer::SCommand_TextTexture_Update Cmd;
|
||||||
Cmd.m_Slot = TextureId.Id();
|
Cmd.m_Slot = TextureId.Id();
|
||||||
|
@ -493,10 +493,17 @@ bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureId, int x, int
|
||||||
Cmd.m_Width = Width;
|
Cmd.m_Width = Width;
|
||||||
Cmd.m_Height = Height;
|
Cmd.m_Height = Height;
|
||||||
|
|
||||||
|
if(IsMovedPointer)
|
||||||
|
{
|
||||||
|
Cmd.m_pData = pData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
const size_t MemSize = Width * Height;
|
const size_t MemSize = Width * Height;
|
||||||
uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize));
|
uint8_t *pTmpData = static_cast<uint8_t *>(malloc(MemSize));
|
||||||
mem_copy(pTmpData, pData, MemSize);
|
mem_copy(pTmpData, pData, MemSize);
|
||||||
Cmd.m_pData = pTmpData;
|
Cmd.m_pData = pTmpData;
|
||||||
|
}
|
||||||
AddCmd(Cmd);
|
AddCmd(Cmd);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -950,7 +950,7 @@ public:
|
||||||
|
|
||||||
bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override;
|
bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) override;
|
||||||
bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override;
|
bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override;
|
||||||
bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) override;
|
bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer) override;
|
||||||
|
|
||||||
CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override;
|
CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) override;
|
||||||
|
|
||||||
|
|
|
@ -321,9 +321,6 @@ private:
|
||||||
CAtlas m_TextureAtlas;
|
CAtlas m_TextureAtlas;
|
||||||
std::unordered_map<std::tuple<FT_Face, int, int>, SGlyph, SGlyphKeyHash, SGlyphKeyEquals> m_Glyphs;
|
std::unordered_map<std::tuple<FT_Face, int, int>, SGlyph, SGlyphKeyHash, SGlyphKeyEquals> m_Glyphs;
|
||||||
|
|
||||||
// Data used for rendering glyphs
|
|
||||||
uint8_t m_aaGlyphData[NUM_FONT_TEXTURES][64 * 1024];
|
|
||||||
|
|
||||||
// Font faces
|
// Font faces
|
||||||
FT_Face m_DefaultFace = nullptr;
|
FT_Face m_DefaultFace = nullptr;
|
||||||
FT_Face m_IconFace = nullptr;
|
FT_Face m_IconFace = nullptr;
|
||||||
|
@ -485,13 +482,13 @@ private:
|
||||||
return OutlineThickness;
|
return OutlineThickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UploadGlyph(int TextureIndex, int PosX, int PosY, size_t Width, size_t Height, const unsigned char *pData)
|
void UploadGlyph(int TextureIndex, int PosX, int PosY, size_t Width, size_t Height, uint8_t *pData)
|
||||||
{
|
{
|
||||||
for(size_t y = 0; y < Height; ++y)
|
for(size_t y = 0; y < Height; ++y)
|
||||||
{
|
{
|
||||||
mem_copy(&m_apTextureData[TextureIndex][PosX + ((y + PosY) * m_TextureDimension)], &pData[y * Width], Width);
|
mem_copy(&m_apTextureData[TextureIndex][PosX + ((y + PosY) * m_TextureDimension)], &pData[y * Width], Width);
|
||||||
}
|
}
|
||||||
Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], PosX, PosY, Width, Height, pData);
|
Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], PosX, PosY, Width, Height, pData, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FitGlyph(size_t Width, size_t Height, int &PosX, int &PosY)
|
bool FitGlyph(size_t Width, size_t Height, int &PosX, int &PosY)
|
||||||
|
@ -510,6 +507,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
const FT_Bitmap *pBitmap = &Glyph.m_Face->glyph->bitmap;
|
const FT_Bitmap *pBitmap = &Glyph.m_Face->glyph->bitmap;
|
||||||
|
if(pBitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
|
||||||
|
{
|
||||||
|
log_debug("textrender", "Error loading glyph, unsupported pixel mode. Chr=%d GlyphIndex=%u PixelMode=%d", Glyph.m_Chr, Glyph.m_GlyphIndex, pBitmap->pixel_mode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned RealWidth = pBitmap->width;
|
const unsigned RealWidth = pBitmap->width;
|
||||||
const unsigned RealHeight = pBitmap->rows;
|
const unsigned RealHeight = pBitmap->rows;
|
||||||
|
@ -544,23 +546,23 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare glyph data
|
// prepare glyph data
|
||||||
mem_zero(m_aaGlyphData[FONT_TEXTURE_FILL], (size_t)Width * Height * sizeof(uint8_t));
|
const size_t GlyphDataSize = (size_t)Width * Height * sizeof(uint8_t);
|
||||||
|
uint8_t *pGlyphDataFill = static_cast<uint8_t *>(malloc(GlyphDataSize));
|
||||||
|
uint8_t *pGlyphDataOutline = static_cast<uint8_t *>(malloc(GlyphDataSize));
|
||||||
|
mem_zero(pGlyphDataFill, GlyphDataSize);
|
||||||
for(unsigned py = 0; py < pBitmap->rows; ++py)
|
for(unsigned py = 0; py < pBitmap->rows; ++py)
|
||||||
{
|
{
|
||||||
mem_copy(&m_aaGlyphData[FONT_TEXTURE_FILL][(py + y) * Width + x], &pBitmap->buffer[py * pBitmap->width], pBitmap->width);
|
mem_copy(&pGlyphDataFill[(py + y) * Width + x], &pBitmap->buffer[py * pBitmap->width], pBitmap->width);
|
||||||
}
|
}
|
||||||
|
Grow(pGlyphDataFill, pGlyphDataOutline, Width, Height, OutlineThickness);
|
||||||
|
|
||||||
// upload the glyph
|
// upload the glyph
|
||||||
UploadGlyph(FONT_TEXTURE_FILL, X, Y, Width, Height, m_aaGlyphData[FONT_TEXTURE_FILL]);
|
UploadGlyph(FONT_TEXTURE_FILL, X, Y, Width, Height, pGlyphDataFill);
|
||||||
Grow(m_aaGlyphData[FONT_TEXTURE_FILL], m_aaGlyphData[FONT_TEXTURE_OUTLINE], Width, Height, OutlineThickness);
|
UploadGlyph(FONT_TEXTURE_OUTLINE, X, Y, Width, Height, pGlyphDataOutline);
|
||||||
UploadGlyph(FONT_TEXTURE_OUTLINE, X, Y, Width, Height, m_aaGlyphData[FONT_TEXTURE_OUTLINE]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set glyph info
|
// set glyph info
|
||||||
{
|
{
|
||||||
const int BmpWidth = pBitmap->width + x * 2;
|
|
||||||
const int BmpHeight = pBitmap->rows + y * 2;
|
|
||||||
|
|
||||||
Glyph.m_Height = Height;
|
Glyph.m_Height = Height;
|
||||||
Glyph.m_Width = Width;
|
Glyph.m_Width = Width;
|
||||||
Glyph.m_CharHeight = RealHeight;
|
Glyph.m_CharHeight = RealHeight;
|
||||||
|
@ -571,8 +573,8 @@ private:
|
||||||
|
|
||||||
Glyph.m_aUVs[0] = X;
|
Glyph.m_aUVs[0] = X;
|
||||||
Glyph.m_aUVs[1] = Y;
|
Glyph.m_aUVs[1] = Y;
|
||||||
Glyph.m_aUVs[2] = Glyph.m_aUVs[0] + BmpWidth;
|
Glyph.m_aUVs[2] = Glyph.m_aUVs[0] + Width;
|
||||||
Glyph.m_aUVs[3] = Glyph.m_aUVs[1] + BmpHeight;
|
Glyph.m_aUVs[3] = Glyph.m_aUVs[1] + Height;
|
||||||
|
|
||||||
Glyph.m_State = SGlyph::EState::RENDERED;
|
Glyph.m_State = SGlyph::EState::RENDERED;
|
||||||
}
|
}
|
||||||
|
@ -694,7 +696,7 @@ public:
|
||||||
for(size_t TextureIndex = 0; TextureIndex < NUM_FONT_TEXTURES; ++TextureIndex)
|
for(size_t TextureIndex = 0; TextureIndex < NUM_FONT_TEXTURES; ++TextureIndex)
|
||||||
{
|
{
|
||||||
mem_zero(m_apTextureData[TextureIndex], m_TextureDimension * m_TextureDimension * sizeof(uint8_t));
|
mem_zero(m_apTextureData[TextureIndex], m_TextureDimension * m_TextureDimension * sizeof(uint8_t));
|
||||||
Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], 0, 0, m_TextureDimension, m_TextureDimension, m_apTextureData[TextureIndex]);
|
Graphics()->UpdateTextTexture(m_aTextures[TextureIndex], 0, 0, m_TextureDimension, m_TextureDimension, m_apTextureData[TextureIndex], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_TextureAtlas.Clear(m_TextureDimension);
|
m_TextureAtlas.Clear(m_TextureDimension);
|
||||||
|
@ -791,13 +793,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
const FT_Bitmap *pBitmap = &Face->glyph->bitmap;
|
const FT_Bitmap *pBitmap = &Face->glyph->bitmap;
|
||||||
|
if(pBitmap->pixel_mode != FT_PIXEL_MODE_GRAY)
|
||||||
// prepare glyph data
|
{
|
||||||
const size_t GlyphDataSize = (size_t)pBitmap->width * pBitmap->rows * sizeof(uint8_t);
|
log_debug("textrender", "Error loading glyph, unsupported pixel mode. Chr=%d GlyphIndex=%u PixelMode=%d", NextCharacter, GlyphIndex, pBitmap->pixel_mode);
|
||||||
if(pBitmap->pixel_mode == FT_PIXEL_MODE_GRAY)
|
pCurrent = pTmp;
|
||||||
mem_copy(m_aaGlyphData[FONT_TEXTURE_FILL], pBitmap->buffer, GlyphDataSize);
|
continue;
|
||||||
else
|
}
|
||||||
mem_zero(m_aaGlyphData[FONT_TEXTURE_FILL], GlyphDataSize);
|
|
||||||
|
|
||||||
for(unsigned OffY = 0; OffY < pBitmap->rows; ++OffY)
|
for(unsigned OffY = 0; OffY < pBitmap->rows; ++OffY)
|
||||||
{
|
{
|
||||||
|
@ -806,18 +807,11 @@ public:
|
||||||
const int ImgOffX = clamp(x + OffX + WidthLastChars, x, (x + TexSubWidth) - 1);
|
const int ImgOffX = clamp(x + OffX + WidthLastChars, x, (x + TexSubWidth) - 1);
|
||||||
const int ImgOffY = clamp(y + OffY, y, (y + TexSubHeight) - 1);
|
const int ImgOffY = clamp(y + OffY, y, (y + TexSubHeight) - 1);
|
||||||
const size_t ImageOffset = ImgOffY * (TextImage.m_Width * PixelSize) + ImgOffX * PixelSize;
|
const size_t ImageOffset = ImgOffY * (TextImage.m_Width * PixelSize) + ImgOffX * PixelSize;
|
||||||
const size_t GlyphOffset = OffY * pBitmap->width + OffX;
|
for(size_t i = 0; i < PixelSize - 1; ++i)
|
||||||
for(size_t i = 0; i < PixelSize; ++i)
|
|
||||||
{
|
{
|
||||||
if(i != PixelSize - 1)
|
TextImage.m_pData[ImageOffset + i] = 255;
|
||||||
{
|
|
||||||
*(TextImage.m_pData + ImageOffset + i) = 255;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*(TextImage.m_pData + ImageOffset + i) = *(m_aaGlyphData[FONT_TEXTURE_FILL] + GlyphOffset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
TextImage.m_pData[ImageOffset + PixelSize - 1] = pBitmap->buffer[OffY * pBitmap->width + OffX];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,7 @@ public:
|
||||||
// pTextData & pTextOutlineData are automatically free'd
|
// pTextData & pTextOutlineData are automatically free'd
|
||||||
virtual bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) = 0;
|
virtual bool LoadTextTextures(size_t Width, size_t Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, uint8_t *pTextData, uint8_t *pTextOutlineData) = 0;
|
||||||
virtual bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) = 0;
|
virtual bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) = 0;
|
||||||
virtual bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, const uint8_t *pData) = 0;
|
virtual bool UpdateTextTexture(CTextureHandle TextureId, int x, int y, size_t Width, size_t Height, uint8_t *pData, bool IsMovedPointer) = 0;
|
||||||
|
|
||||||
virtual CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) = 0;
|
virtual CTextureHandle LoadSpriteTexture(const CImageInfo &FromImageInfo, const struct CDataSprite *pSprite) = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue