Use two fonts, one as explicit fallback

Merging with fontforge had problems, for example for the Bei (U+5317) in
Beijing, see https://github.com/fontforge/fontforge/issues/4432
This commit is contained in:
def 2020-08-20 08:54:59 +02:00
parent b147950ef1
commit 446526486d
6 changed files with 72 additions and 25 deletions

View file

@ -1010,8 +1010,9 @@ set(EXPECTED_DATA
editor/winter_main.rules editor/winter_main.rules
emoticons.png emoticons.png
file_icons.png file_icons.png
fonts/DejavuWenQuanYiMicroHei.ttf fonts/DejaVuSansCJKName.ttf
fonts/Icons.ttf fonts/Icons.ttf
fonts/WenQuanYiMicroHei.ttf
game.png game.png
gui_buttons.png gui_buttons.png
gui_cursor.png gui_cursor.png

Binary file not shown.

View file

@ -3837,8 +3837,10 @@ void CClient::ToggleWindowVSync()
void CClient::LoadFont() void CClient::LoadFont()
{ {
static CFont *pDefaultFont = 0; static CFont *pDefaultFont = 0;
static CFont *pFallbackFont = 0;
char aFilename[512]; char aFilename[512];
const char *pFontFile = "fonts/DejavuWenQuanYiMicroHei.ttf"; const char *pFontFile = "fonts/DejaVuSansCJKName.ttf";
const char *pFallbackFontFile = "fonts/WenQuanYiMicroHei.ttf";
IOHANDLE File = Storage()->OpenFile(pFontFile, IOFLAG_READ, IStorage::TYPE_ALL, aFilename, sizeof(aFilename)); IOHANDLE File = Storage()->OpenFile(pFontFile, IOFLAG_READ, IStorage::TYPE_ALL, aFilename, sizeof(aFilename));
if(File) if(File)
{ {
@ -3847,10 +3849,24 @@ void CClient::LoadFont()
pDefaultFont = pTextRender->GetFont(aFilename); pDefaultFont = pTextRender->GetFont(aFilename);
if(pDefaultFont == NULL) if(pDefaultFont == NULL)
pDefaultFont = pTextRender->LoadFont(aFilename); pDefaultFont = pTextRender->LoadFont(aFilename);
Kernel()->RequestInterface<IEngineTextRender>()->SetDefaultFont(pDefaultFont);
File = Storage()->OpenFile(pFallbackFontFile, IOFLAG_READ, IStorage::TYPE_ALL, aFilename, sizeof(aFilename));
if(File)
{
io_close(File);
IEngineTextRender *pTextRender = Kernel()->RequestInterface<IEngineTextRender>();
pFallbackFont = pTextRender->GetFont(aFilename);
if(pFallbackFont == NULL)
pFallbackFont = pTextRender->LoadFont(aFilename);
}
Kernel()->RequestInterface<IEngineTextRender>()->SetDefaultFont(pDefaultFont, pFallbackFont);
} }
if(!pDefaultFont) if(!pDefaultFont)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load font. filename='%s'", pFontFile); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load font. filename='%s'", pFontFile);
if(!pFallbackFont)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load font. filename='%s'", pFallbackFontFile);
} }
void CClient::Notify(const char *pTitle, const char *pMessage) void CClient::Notify(const char *pTitle, const char *pMessage)

View file

@ -127,6 +127,7 @@ struct STextContainer
STextContainer() { Reset(); } STextContainer() { Reset(); }
CFont* m_pFont; CFont* m_pFont;
CFont* m_pFallbackFont;
int m_FontSize; int m_FontSize;
STextString m_StringInfo; STextString m_StringInfo;
@ -151,6 +152,7 @@ struct STextContainer
void Reset() void Reset()
{ {
m_pFont = NULL; m_pFont = NULL;
m_pFallbackFont = NULL;
m_FontSize = 0; m_FontSize = 0;
m_StringInfo.m_QuadBufferObjectIndex = m_StringInfo.m_QuadBufferContainerIndex = m_StringInfo.m_SelectionQuadContainerIndex = -1; m_StringInfo.m_QuadBufferObjectIndex = m_StringInfo.m_QuadBufferContainerIndex = m_StringInfo.m_SelectionQuadContainerIndex = -1;
@ -243,6 +245,7 @@ class CTextRender : public IEngineTextRender
ColorRGBA m_Color; ColorRGBA m_Color;
ColorRGBA m_OutlineColor; ColorRGBA m_OutlineColor;
CFont *m_pDefaultFont; CFont *m_pDefaultFont;
CFont *m_pFallbackFont;
FT_Library m_FTLibrary; FT_Library m_FTLibrary;
@ -425,7 +428,7 @@ class CTextRender : public IEngineTextRender
return false; return false;
} }
void RenderGlyph(CFont *pFont, CFontSizeData *pSizeData, int Chr) void RenderGlyph(CFont *pInitialFont, CFont *pFallbackFont, CFontSizeData *pSizeData, int Chr)
{ {
FT_Bitmap *pBitmap; FT_Bitmap *pBitmap;
@ -433,12 +436,25 @@ class CTextRender : public IEngineTextRender
int y = 1; int y = 1;
unsigned int px, py; unsigned int px, py;
CFont *pFont = pInitialFont;
FT_Set_Pixel_Sizes(pFont->m_FtFace, 0, pSizeData->m_FontSize); FT_Set_Pixel_Sizes(pFont->m_FtFace, 0, pSizeData->m_FontSize);
FT_UInt GlyphIndex = 0; FT_UInt GlyphIndex = 0;
if(pFont->m_FtFace->charmap) if(pFont->m_FtFace->charmap)
GlyphIndex = FT_Get_Char_Index(pFont->m_FtFace, (FT_ULong)Chr); GlyphIndex = FT_Get_Char_Index(pFont->m_FtFace, (FT_ULong)Chr);
if(GlyphIndex == 0)
{
if(pFallbackFont)
{
pFont = pFallbackFont;
FT_Set_Pixel_Sizes(pFont->m_FtFace, 0, pSizeData->m_FontSize);
if(pFont->m_FtFace->charmap)
GlyphIndex = FT_Get_Char_Index(pFont->m_FtFace, (FT_ULong)Chr);
}
if(GlyphIndex == 0) if(GlyphIndex == 0)
{ {
const int ReplacementChr = 0x25a1; // White square to indicate missing glyph const int ReplacementChr = 0x25a1; // White square to indicate missing glyph
@ -450,6 +466,7 @@ class CTextRender : public IEngineTextRender
return; return;
} }
} }
}
if(FT_Load_Glyph(pFont->m_FtFace, GlyphIndex, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP)) if(FT_Load_Glyph(pFont->m_FtFace, GlyphIndex, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP))
{ {
@ -477,20 +494,20 @@ class CTextRender : public IEngineTextRender
// upload the glyph // upload the glyph
int X = 0; int X = 0;
int Y = 0; int Y = 0;
while(!GetCharacterSpace(pFont, 0, (int)Width, (int)Height, X, Y)) while(!GetCharacterSpace(pInitialFont, 0, (int)Width, (int)Height, X, Y))
{ {
IncreaseFontTexture(pFont, 0); IncreaseFontTexture(pInitialFont, 0);
} }
UploadGlyph(pFont, 0, X, Y, (int)Width, (int)Height, ms_aGlyphData); UploadGlyph(pInitialFont, 0, X, Y, (int)Width, (int)Height, ms_aGlyphData);
if(OutlineThickness == 1) if(OutlineThickness == 1)
{ {
Grow(ms_aGlyphData, ms_aGlyphDataOutlined, Width, Height); Grow(ms_aGlyphData, ms_aGlyphDataOutlined, Width, Height);
while(!GetCharacterSpace(pFont, 1, (int)Width, (int)Height, X, Y)) while(!GetCharacterSpace(pInitialFont, 1, (int)Width, (int)Height, X, Y))
{ {
IncreaseFontTexture(pFont, 1); IncreaseFontTexture(pInitialFont, 1);
} }
UploadGlyph(pFont, 1, X, Y, (int)Width, (int)Height, ms_aGlyphDataOutlined); UploadGlyph(pInitialFont, 1, X, Y, (int)Width, (int)Height, ms_aGlyphDataOutlined);
} }
else else
{ {
@ -499,11 +516,11 @@ class CTextRender : public IEngineTextRender
Grow(ms_aGlyphData, ms_aGlyphDataOutlined, Width, Height); Grow(ms_aGlyphData, ms_aGlyphDataOutlined, Width, Height);
Grow(ms_aGlyphDataOutlined, ms_aGlyphData, Width, Height); Grow(ms_aGlyphDataOutlined, ms_aGlyphData, Width, Height);
} }
while(!GetCharacterSpace(pFont, 1, (int)Width, (int)Height, X, Y)) while(!GetCharacterSpace(pInitialFont, 1, (int)Width, (int)Height, X, Y))
{ {
IncreaseFontTexture(pFont, 1); IncreaseFontTexture(pInitialFont, 1);
} }
UploadGlyph(pFont, 1, X, Y, (int)Width, (int)Height, ms_aGlyphData); UploadGlyph(pInitialFont, 1, X, Y, (int)Width, (int)Height, ms_aGlyphData);
} }
// set char info // set char info
@ -527,7 +544,7 @@ class CTextRender : public IEngineTextRender
} }
} }
SFontSizeChar *GetChar(CFont *pFont, CFontSizeData *pSizeData, int Chr) SFontSizeChar *GetChar(CFont *pFont, CFont *pFallbackFont, CFontSizeData *pSizeData, int Chr)
{ {
std::map<int, SFontSizeChar>::iterator it = pSizeData->m_Chars.find(Chr); std::map<int, SFontSizeChar>::iterator it = pSizeData->m_Chars.find(Chr);
if(it == pSizeData->m_Chars.end()) if(it == pSizeData->m_Chars.end())
@ -535,7 +552,7 @@ class CTextRender : public IEngineTextRender
// render and add character // render and add character
SFontSizeChar& FontSizeChr = pSizeData->m_Chars[Chr]; SFontSizeChar& FontSizeChr = pSizeData->m_Chars[Chr];
RenderGlyph(pFont, pSizeData, Chr); RenderGlyph(pFont, pFallbackFont, pSizeData, Chr);
return &FontSizeChr; return &FontSizeChr;
} }
@ -569,6 +586,7 @@ public:
m_pCurFont = 0; m_pCurFont = 0;
m_pDefaultFont = 0; m_pDefaultFont = 0;
m_pFallbackFont = 0;
m_FTLibrary = 0; m_FTLibrary = 0;
// GL_LUMINANCE can be good for debugging // GL_LUMINANCE can be good for debugging
@ -708,10 +726,11 @@ public:
} }
} }
virtual void SetDefaultFont(CFont *pFont) virtual void SetDefaultFont(CFont *pFont, CFont *pFallbackFont)
{ {
dbg_msg("textrender", "default pFont set %p", pFont); dbg_msg("textrender", "default pFont set %p %p", pFont, pFallbackFont);
m_pDefaultFont = pFont; m_pDefaultFont = pFont;
m_pFallbackFont = pFallbackFont;
m_pCurFont = m_pDefaultFont; m_pCurFont = m_pDefaultFont;
} }
@ -791,6 +810,7 @@ public:
return; return;
CFont *pFont = pCursor->m_pFont; CFont *pFont = pCursor->m_pFont;
CFont *pFallbackFont = pCursor->m_pFallbackFont;
CFontSizeData *pSizeData = NULL; CFontSizeData *pSizeData = NULL;
float ScreenX0, ScreenY0, ScreenX1, ScreenY1; float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
@ -828,6 +848,9 @@ public:
if(!pFont) if(!pFont)
return; return;
if(!pFallbackFont)
pFallbackFont = m_pFallbackFont;
pSizeData = pFont->GetFontSize(ActualSize); pSizeData = pFont->GetFontSize(ActualSize);
// set length // set length
@ -943,7 +966,7 @@ public:
continue; continue;
} }
SFontSizeChar *pChr = GetChar(pFont, pSizeData, Character); SFontSizeChar *pChr = GetChar(pFont, pFallbackFont, pSizeData, Character);
if(pChr) if(pChr)
{ {
bool ApplyBearingX = !(((m_RenderFlags&TEXT_RENDER_FLAG_NO_X_BEARING) != 0) || (CharacterCounter == 0 && (m_RenderFlags&TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING) != 0)); bool ApplyBearingX = !(((m_RenderFlags&TEXT_RENDER_FLAG_NO_X_BEARING) != 0) || (CharacterCounter == 0 && (m_RenderFlags&TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING) != 0));
@ -1038,6 +1061,7 @@ public:
virtual int CreateTextContainer(CTextCursor *pCursor, const char *pText) virtual int CreateTextContainer(CTextCursor *pCursor, const char *pText)
{ {
CFont *pFont = pCursor->m_pFont; CFont *pFont = pCursor->m_pFont;
CFont *pFallbackFont = pCursor->m_pFallbackFont;
// fetch pFont data // fetch pFont data
if(!pFont) if(!pFont)
@ -1046,9 +1070,13 @@ public:
if(!pFont) if(!pFont)
return -1; return -1;
if(!pFallbackFont)
pFallbackFont = m_pFallbackFont;
int ContainerIndex = GetFreeTextContainerIndex(); int ContainerIndex = GetFreeTextContainerIndex();
STextContainer& TextContainer = GetTextContainer(ContainerIndex); STextContainer& TextContainer = GetTextContainer(ContainerIndex);
TextContainer.m_pFont = pFont; TextContainer.m_pFont = pFont;
TextContainer.m_pFallbackFont = pFallbackFont;
CFontSizeData *pSizeData = NULL; CFontSizeData *pSizeData = NULL;
@ -1248,7 +1276,7 @@ public:
continue; continue;
} }
SFontSizeChar *pChr = GetChar(TextContainer.m_pFont, pSizeData, Character); SFontSizeChar *pChr = GetChar(TextContainer.m_pFont, TextContainer.m_pFallbackFont, pSizeData, Character);
if(pChr) if(pChr)
{ {
bool ApplyBearingX = !(((RenderFlags&TEXT_RENDER_FLAG_NO_X_BEARING) != 0) || (CharacterCounter == 0 && (RenderFlags&TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING) != 0)); bool ApplyBearingX = !(((RenderFlags&TEXT_RENDER_FLAG_NO_X_BEARING) != 0) || (CharacterCounter == 0 && (RenderFlags&TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING) != 0));
@ -1468,6 +1496,7 @@ public:
FakeCursor.m_StartY = TextContainer.m_StartY; FakeCursor.m_StartY = TextContainer.m_StartY;
FakeCursor.m_LineWidth = TextContainer.m_LineWidth; FakeCursor.m_LineWidth = TextContainer.m_LineWidth;
FakeCursor.m_pFont = TextContainer.m_pFont; FakeCursor.m_pFont = TextContainer.m_pFont;
FakeCursor.m_pFallbackFont = TextContainer.m_pFallbackFont;
int Wlen = minimum(WordLength((char *)pCurrent), (int)(pEnd - pCurrent)); int Wlen = minimum(WordLength((char *)pCurrent), (int)(pEnd - pCurrent));
CTextCursor Compare = FakeCursor; CTextCursor Compare = FakeCursor;
@ -1530,7 +1559,7 @@ public:
continue; continue;
} }
SFontSizeChar *pChr = GetChar(TextContainer.m_pFont, pSizeData, Character); SFontSizeChar *pChr = GetChar(TextContainer.m_pFont, TextContainer.m_pFallbackFont, pSizeData, Character);
if(pChr) if(pChr)
{ {
bool ApplyBearingX = !(((RenderFlags&TEXT_RENDER_FLAG_NO_X_BEARING) != 0) || (CharacterCounter == 0 && (RenderFlags&TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING) != 0)); bool ApplyBearingX = !(((RenderFlags&TEXT_RENDER_FLAG_NO_X_BEARING) != 0) || (CharacterCounter == 0 && (RenderFlags&TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING) != 0));

View file

@ -47,6 +47,7 @@ public:
float m_X, m_Y; float m_X, m_Y;
CFont *m_pFont; CFont *m_pFont;
CFont *m_pFallbackFont;
float m_FontSize; float m_FontSize;
float m_AlignedFontSize; float m_AlignedFontSize;
}; };
@ -81,7 +82,7 @@ public:
virtual CFont *GetFont(const char *pFilename) = 0; virtual CFont *GetFont(const char *pFilename) = 0;
virtual void DestroyFont(CFont *pFont) = 0; virtual void DestroyFont(CFont *pFont) = 0;
virtual void SetDefaultFont(CFont *pFont) = 0; virtual void SetDefaultFont(CFont *pFont, CFont *pFallbackFont) = 0;
virtual void SetCurFont(CFont *pFont) = 0; virtual void SetCurFont(CFont *pFont) = 0;
virtual void SetRenderFlags(unsigned int Flags) = 0; virtual void SetRenderFlags(unsigned int Flags) = 0;