因为是使用Deepseek V4 Flash生成的,放官方仓库上大概率不给过(禁AI),我也不懂没法review,就直接放这里了,有需要的自己打补丁后编译就可以了。具体方法直接把补丁内容复制过去问AI就可以了。
diff --git a/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformSplash.cpp b/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformSplash.cpp
index 2b6c97eed..c7e33083d 100644
--- a/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformSplash.cpp
+++ b/Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxPlatformSplash.cpp
@@ -63,20 +63,21 @@ private:
#if WITH_EDITOR
void DrawCharacter(int32 penx, int32 peny, FT_GlyphSlot Glyph, int32 CurTypeIndex, float Red, float Green, float Blue);
void RenderStrings();
bool OpenFonts();
FT_Library FontLibrary = nullptr;
FT_Face FontSmall = nullptr;
FT_Face FontNormal = nullptr;
FT_Face FontLarge = nullptr;
+ FT_Face FontFallback = nullptr;
SDL_Renderer *SplashRenderer = nullptr;
SDL_Texture *SplashTexture = nullptr;
FText SplashText[ SplashTextType::NumTextTypes ];
Rect SplashTextRects[ SplashTextType::NumTextTypes ];
unsigned char *ScratchSpace = nullptr;
bool bStringsChanged = false;
#endif // WITH_EDITOR
@@ -128,20 +129,25 @@ FLinuxSplashState::~FLinuxSplashState()
if (FontNormal)
{
FT_Done_Face(FontNormal);
}
if (FontLarge)
{
FT_Done_Face(FontLarge);
}
+ if (FontFallback)
+ {
+ FT_Done_Face(FontFallback);
+ }
+
if (FontLibrary)
{
FT_Done_FreeType(FontLibrary);
}
#endif // WITH_EDITOR
// do not deinit SDL here
}
#if WITH_EDITOR
@@ -184,20 +190,33 @@ bool FLinuxSplashState::OpenFonts()
if (FT_New_Face(FontLibrary, TCHAR_TO_UTF8(*FontPath), 0, &FontLarge))
{
UE_LOGF(LogHAL, Error, "*** Unable to open large font face for splash screen.");
}
else
{
FT_Set_Pixel_Sizes(FontLarge, 0, 32);
}
+ // fallback font face, used for characters not covered by the fonts above (e.g. CJK),
+ // matching the fallback font used by Slate's composite font chain.
+ FontPath = FPaths::ConvertRelativePathToFull(FPaths::EngineContentDir() / TEXT("Slate/Fonts/DroidSansFallback.ttf"));
+
+ if (FT_New_Face(FontLibrary, TCHAR_TO_UTF8(*FontPath), 0, &FontFallback))
+ {
+ UE_LOGF(LogHAL, Error, "*** Unable to open fallback font face for splash screen.");
+ }
+ else
+ {
+ FT_Set_Pixel_Sizes(FontFallback, 0, 10);
+ }
+
return true;
}
//---------------------------------------------------------
void FLinuxSplashState::DrawCharacter(int32 PenX, int32 PenY, FT_GlyphSlot Glyph, int32 CurTypeIndex, float Red, float Green, float Blue)
{
// drawing boundaries
const int32 MinX = SplashTextRects[CurTypeIndex].Left;
const int32 MaxX = SplashTextRects[CurTypeIndex].Right;
@@ -242,20 +261,21 @@ void FLinuxSplashState::DrawCharacter(int32 PenX, int32 PenY, FT_GlyphSlot Glyph
ScratchSpace[DestIndex] = (uint8)(ScratchSpace[DestIndex]*(1.0 - Alpha) + Alpha*Blue);
}
}
}
//---------------------------------------------------------
void FLinuxSplashState::RenderStrings()
{
FT_UInt LastGlyph = 0;
+ FT_Face LastGlyphFont = nullptr;
FT_Vector Kerning;
bool bRightJustify = false;
float Red, Blue, Green; // font color
if (!bStringsChanged)
{
return;
}
bStringsChanged = false;
@@ -344,53 +364,82 @@ void FLinuxSplashState::RenderStrings()
if (bRightJustify)
{
CharacterCode = (Uint32)(Text[Text.Len() - i - 1]);
}
else
{
CharacterCode = (Uint32)(Text[i]);
}
FT_UInt GlyphIndex = FT_Get_Char_Index(Font, CharacterCode);
- FT_Load_Glyph(Font, GlyphIndex, FT_LOAD_DEFAULT);
- if (Font->glyph->format != FT_GLYPH_FORMAT_BITMAP)
+ // If the primary font doesn't cover this character (e.g. CJK), fall back to the
+ // engine's bundled fallback font, mirroring Slate's composite font chain.
+ FT_Face GlyphFont = Font;
+ if (GlyphIndex == 0 && FontFallback != nullptr)
{
- FT_Render_Glyph(Font->glyph, FT_RENDER_MODE_NORMAL);
+ FT_UInt FallbackGlyphIndex = FT_Get_Char_Index(FontFallback, CharacterCode);
+ if (FallbackGlyphIndex != 0)
+ {
+ GlyphIndex = FallbackGlyphIndex;
+ GlyphFont = FontFallback;
+
+ // match the primary font's pixel size so the fallback glyph renders at the same size
+ if (Font->size != nullptr)
+ {
+ FT_Set_Pixel_Sizes(FontFallback, 0, Font->size->metrics.y_ppem);
+ }
+ }
+ }
+
+ FT_Load_Glyph(GlyphFont, GlyphIndex, FT_LOAD_DEFAULT);
+
+ if (GlyphFont->glyph->format != FT_GLYPH_FORMAT_BITMAP)
+ {
+ FT_Render_Glyph(GlyphFont->glyph, FT_RENDER_MODE_NORMAL);
}
- // pen advance and kerning
+ // pen advance and kerning (kerning only applies between glyphs from the same face)
if (bRightJustify)
{
- if (LastGlyph != 0)
+ if (LastGlyph != 0 && LastGlyphFont == GlyphFont)
+ {
+ FT_Get_Kerning(GlyphFont, GlyphIndex, LastGlyph, FT_KERNING_DEFAULT, &Kerning);
+ }
+ else
{
- FT_Get_Kerning(Font, GlyphIndex, LastGlyph, FT_KERNING_DEFAULT, &Kerning);
+ Kerning.x = 0;
}
- PenX -= (Font->glyph->metrics.horiAdvance - Kerning.x) >> 6;
+ PenX -= (GlyphFont->glyph->metrics.horiAdvance - Kerning.x) >> 6;
}
else
{
- if (LastGlyph != 0)
+ if (LastGlyph != 0 && LastGlyphFont == GlyphFont)
+ {
+ FT_Get_Kerning(GlyphFont, LastGlyph, GlyphIndex, FT_KERNING_DEFAULT, &Kerning);
+ }
+ else
{
- FT_Get_Kerning(Font, LastGlyph, GlyphIndex, FT_KERNING_DEFAULT, &Kerning);
+ Kerning.x = 0;
}
}
LastGlyph = GlyphIndex;
+ LastGlyphFont = GlyphFont;
// draw character
- DrawCharacter(PenX, PenY, Font->glyph, CurTypeIndex, Red, Green, Blue);
+ DrawCharacter(PenX, PenY, GlyphFont->glyph, CurTypeIndex, Red, Green, Blue);
if (!bRightJustify)
{
- PenX += (Font->glyph->metrics.horiAdvance - Kerning.x) >> 6;
+ PenX += (GlyphFont->glyph->metrics.horiAdvance - Kerning.x) >> 6;
}
}
}
// store rendered text as texture
SDL_UpdateTexture(SplashTexture, NULL, ScratchSpace, SplashWidth * SplashBPP);
}
}
#endif // WITH_EDITOR