diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index f1e3e9baa8..92ee2d057d 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -14,11 +14,10 @@ #include "Common/Log.h" #include "Common/StringUtils.h" -DrawBuffer::DrawBuffer() : count_(0), atlas(0) { +DrawBuffer::DrawBuffer() { verts_ = new Vertex[MAX_VERTS]; fontscalex = 1.0f; fontscaley = 1.0f; - inited_ = false; } DrawBuffer::~DrawBuffer() { @@ -482,7 +481,9 @@ float AtlasWordWrapper::MeasureWidth(const char *str, size_t bytes) { } void DrawBuffer::MeasureTextCount(FontID font, const char *text, int count, float *w, float *h) { - const AtlasFont *atlasfont = atlas->getFont(font); + const AtlasFont *atlasfont = fontAtlas_->getFont(font); + if (!atlasfont) + atlasfont = atlas->getFont(font); if (!atlasfont) { *w = 0.0f; *h = 0.0f; @@ -533,7 +534,9 @@ void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, co std::string toMeasure = std::string(text, count); int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); if (wrap) { - const AtlasFont *font = atlas->getFont(font_id); + const AtlasFont *font = fontAtlas_->getFont(font_id); + if (!font) + font = atlas->getFont(font_id); if (!font) { *w = 0.0f; *h = 0.0f; @@ -582,7 +585,9 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f std::string toDraw = text; int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); - const AtlasFont *atlasfont = atlas->getFont(font); + const AtlasFont *atlasfont = fontAtlas_->getFont(font); + if (!atlasfont) + atlasfont = atlas->getFont(font); if (wrap && atlasfont) { AtlasWordWrapper wrapper(*atlasfont, fontscalex, toDraw.c_str(), w, wrap); toDraw = wrapper.Wrapped(); @@ -624,7 +629,9 @@ void DrawBuffer::DrawText(FontID font, const char *text, float x, float y, Color } } - const AtlasFont *atlasfont = atlas->getFont(font); + const AtlasFont *atlasfont = fontAtlas_->getFont(font); + if (!atlasfont) + atlasfont = atlas->getFont(font); if (!atlasfont) return; unsigned int cval; diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index 6190f3ecba..8565b78a12 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -110,6 +110,10 @@ public: atlas = _atlas; } const Atlas *GetAtlas() const { return atlas; } + void SetFontAtlas(const Atlas *_atlas) { + fontAtlas_ = _atlas; + } + const Atlas *GetFontAtlas() const { return fontAtlas_; } bool MeasureImage(ImageID atlas_image, float *w, float *h); void DrawImage(ImageID atlas_image, float x, float y, float scale, Color color = COLOR(0xFFFFFF), int align = ALIGN_TOPLEFT); @@ -189,18 +193,18 @@ private: float alpha_ = 1.0f; std::vector alphaStack_; - Draw::DrawContext *draw_; - Draw::Buffer *vbuf_; - Draw::Pipeline *pipeline_; + Draw::DrawContext *draw_ = nullptr; + Draw::Buffer *vbuf_ = nullptr; + Draw::Pipeline *pipeline_ = nullptr; Vertex *verts_; - int count_; - const Atlas *atlas; + int count_ = 0; + const Atlas *atlas = nullptr; + const Atlas *fontAtlas_ = nullptr; - bool inited_; - float fontscalex; - float fontscaley; + bool inited_ = false; + float fontscalex = 1.0f; + float fontscaley = 1.0f; float curZ_ = 0.0f; }; - diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index ff698bbc97..78ce59fec5 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -39,6 +39,11 @@ void UIContext::BeginFrame() { if (!uitexture_) { uitexture_ = CreateTextureFromFile(draw_, "ui_atlas.zim", ImageFileType::ZIM, false); _dbg_assert_msg_(uitexture_, "Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); + if (!fontTexture_) { + fontTexture_ = CreateTextureFromFile(draw_, "font_atlas.zim", ImageFileType::ZIM, false); + if (!fontTexture_) + WARN_LOG(SYSTEM, "Failed to load font_atlas.zim"); + } } uidrawbufferTop_->SetCurZ(0.0f); uidrawbuffer_->SetCurZ(0.0f); @@ -70,6 +75,14 @@ void UIContext::RebindTexture() const { draw_->BindTexture(0, uitexture_->GetTexture()); } +void UIContext::BindFontTexture() const { + // Fall back to the UI texture, in case they have an old atlas. + if (fontTexture_) + draw_->BindTexture(0, fontTexture_->GetTexture()); + else if (uitexture_) + draw_->BindTexture(0, uitexture_->GetTexture()); +} + void UIContext::Flush() { if (uidrawbuffer_) { uidrawbuffer_->Flush(); @@ -190,14 +203,22 @@ void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float void UIContext::DrawText(const char *str, float x, float y, uint32_t color, int align) { if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { + // Use the font texture if this font is in that texture instead. + bool useFontTexture = Draw()->GetFontAtlas()->getFont(fontStyle_->atlasFont) != nullptr; + if (useFontTexture) { + Flush(); + BindFontTexture(); + } float sizeFactor = (float)fontStyle_->sizePts / 24.0f; Draw()->SetFontScale(fontScaleX_ * sizeFactor, fontScaleY_ * sizeFactor); Draw()->DrawText(fontStyle_->atlasFont, str, x, y, color, align); + if (useFontTexture) + Flush(); } else { textDrawer_->SetFontScale(fontScaleX_, fontScaleY_); textDrawer_->DrawString(*Draw(), str, x, y, color, align); - RebindTexture(); } + RebindTexture(); } void UIContext::DrawTextShadow(const char *str, float x, float y, uint32_t color, int align) { @@ -208,17 +229,25 @@ void UIContext::DrawTextShadow(const char *str, float x, float y, uint32_t color void UIContext::DrawTextRect(const char *str, const Bounds &bounds, uint32_t color, int align) { if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) { + // Use the font texture if this font is in that texture instead. + bool useFontTexture = Draw()->GetFontAtlas()->getFont(fontStyle_->atlasFont) != nullptr; + if (useFontTexture) { + Flush(); + BindFontTexture(); + } float sizeFactor = (float)fontStyle_->sizePts / 24.0f; Draw()->SetFontScale(fontScaleX_ * sizeFactor, fontScaleY_ * sizeFactor); Draw()->DrawTextRect(fontStyle_->atlasFont, str, bounds.x, bounds.y, bounds.w, bounds.h, color, align); + if (useFontTexture) + Flush(); } else { textDrawer_->SetFontScale(fontScaleX_, fontScaleY_); Bounds rounded = bounds; rounded.x = floorf(rounded.x); rounded.y = floorf(rounded.y); textDrawer_->DrawStringRect(*Draw(), str, rounded, color, align); - RebindTexture(); } + RebindTexture(); } void UIContext::DrawTextShadowRect(const char *str, const Bounds &bounds, uint32_t color, int align) { diff --git a/Common/UI/Context.h b/Common/UI/Context.h index 6514e87de4..699935628d 100644 --- a/Common/UI/Context.h +++ b/Common/UI/Context.h @@ -59,6 +59,7 @@ public: void Flush(); void RebindTexture() const; + void BindFontTexture() const; // TODO: Support transformed bounds using stencil void PushScissor(const Bounds &bounds); @@ -112,6 +113,7 @@ private: Draw::Pipeline *ui_pipeline_ = nullptr; Draw::Pipeline *ui_pipeline_notex_ = nullptr; std::unique_ptr uitexture_; + std::unique_ptr fontTexture_; DrawBuffer *uidrawbuffer_ = nullptr; DrawBuffer *uidrawbufferTop_ = nullptr; diff --git a/Common/UI/View.h b/Common/UI/View.h index 6a554b5b78..c591573d9a 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -77,15 +77,14 @@ struct Style { }; struct FontStyle { - FontStyle() : atlasFont(0), sizePts(0), flags(0) {} - FontStyle(const char *name, int size) : atlasFont(0), fontName(name), sizePts(size), flags(0) {} - FontStyle(FontID atlasFnt, const char *name, int size) : atlasFont(atlasFnt), fontName(name), sizePts(size), flags(0) {} + FontStyle() {} + FontStyle(FontID atlasFnt, const char *name, int size) : atlasFont(atlasFnt), fontName(name), sizePts(size) {} - FontID atlasFont; + FontID atlasFont{ nullptr }; // For native fonts: std::string fontName; - int sizePts; - int flags; + int sizePts = 0; + int flags = 0; }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b8dac68c5b..8191b7bb09 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1154,6 +1154,8 @@ static void DrawCrashDump(UIContext *ctx) { sysName.c_str(), sysVersion, GetCompilerABI() ); + if (ctx->Draw()->GetFontAtlas()->getFont(ubuntu24)) + ctx->BindFontTexture(); ctx->Draw()->SetFontScale(.7f, .7f); ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF); y += 140; @@ -1205,6 +1207,8 @@ BREAK CheatsInEffect() ? "Y" : "N", HLEPlugins::HasEnabled() ? "Y" : "N"); ctx->Draw()->DrawTextShadow(ubuntu24, statbuf, x, y, 0xFFFFFFFF); + ctx->Flush(); + ctx->RebindTexture(); } static void DrawAudioDebugStats(DrawBuffer *draw2d, const Bounds &bounds) { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 4bb1c4236a..ba56d5d1f2 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -132,8 +132,8 @@ // The new UI framework, for initialization static UI::Theme ui_theme; - -Atlas g_ui_atlas; +static Atlas g_ui_atlas; +static Atlas g_font_atlas; #if PPSSPP_ARCH(ARM) && defined(__ANDROID__) #include "../../android/jni/ArmEmitterTest.h" @@ -900,6 +900,22 @@ static void UIThemeInit() { void RenderOverlays(UIContext *dc, void *userdata); bool CreateGlobalPipelines(); +static void LoadAtlasMetadata(Atlas &metadata, const char *filename, bool required) { + size_t atlas_data_size = 0; + if (!metadata.IsMetadataLoaded()) { + const uint8_t *atlas_data = VFSReadFile(filename, &atlas_data_size); + bool load_success = atlas_data != nullptr && metadata.Load(atlas_data, atlas_data_size); + if (!load_success) { + if (required) + ERROR_LOG(G3D, "Failed to load %s - graphics will be broken", filename); + else + WARN_LOG(G3D, "Failed to load %s", filename); + // Stumble along with broken visuals instead of dying... + } + delete[] atlas_data; + } +} + bool NativeInitGraphics(GraphicsContext *graphicsContext) { INFO_LOG(SYSTEM, "NativeInitGraphics"); @@ -914,20 +930,14 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { return false; } - // Load the atlas. - size_t atlas_data_size = 0; - if (!g_ui_atlas.IsMetadataLoaded()) { - const uint8_t *atlas_data = VFSReadFile("ui_atlas.meta", &atlas_data_size); - bool load_success = atlas_data != nullptr && g_ui_atlas.Load(atlas_data, atlas_data_size); - if (!load_success) { - ERROR_LOG(G3D, "Failed to load ui_atlas.meta - graphics will be broken."); - // Stumble along with broken visuals instead of dying. - } - delete[] atlas_data; - } + // Load any missing atlas. + LoadAtlasMetadata(g_ui_atlas, "ui_atlas.meta", true); + LoadAtlasMetadata(g_font_atlas, "font_atlas.meta", g_ui_atlas.num_fonts == 0); ui_draw2d.SetAtlas(&g_ui_atlas); + ui_draw2d.SetFontAtlas(&g_font_atlas); ui_draw2d_front.SetAtlas(&g_ui_atlas); + ui_draw2d_front.SetFontAtlas(&g_font_atlas); UIThemeInit();