From 03182979e7c57b44c6d36f84ce8f0b32cc6cda93 Mon Sep 17 00:00:00 2001 From: Katie M Date: Sat, 23 Mar 2024 20:00:53 -0400 Subject: [PATCH] Fixing drawing of CJK characters in ImGui screens on CDDA. --- src/cata_imgui.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++--- src/cata_imgui.h | 18 ++++++++--- src/sdl_font.cpp | 30 ++++------------- src/sdl_font.h | 3 +- src/sdltiles.cpp | 9 ++---- 5 files changed, 101 insertions(+), 40 deletions(-) diff --git a/src/cata_imgui.cpp b/src/cata_imgui.cpp index 5064702cb1e08..d77610b6bab98 100644 --- a/src/cata_imgui.cpp +++ b/src/cata_imgui.cpp @@ -158,13 +158,59 @@ RGBTuple color_loader::from_rgb( const int r, const int g, const int b } #else #include "sdl_utils.h" +#include "sdl_font.h" +#include "font_loader.h" #include #include +struct GlyphToDraw { + std::string uni_str; + ImVec2 pos; + ImU32 col; +}; -SDL_Renderer *cataimgui::client::sdl_renderer = nullptr; -SDL_Window *cataimgui::client::sdl_window = nullptr; +static std::vector glyphsToDraw; +struct CataImFont : public ImFont { + std::unordered_map sdlColorsToCata; + const cataimgui::client &imclient; + const std::unique_ptr &cata_font; + CataImFont( const cataimgui::client &imclient, const std::unique_ptr &cata_font ) : + imclient( imclient ), cata_font( cata_font ) { + } -cataimgui::client::client() + void OutputChars() { + for( const GlyphToDraw &glyphToDraw : glyphsToDraw ) { + + std::string uni_string = std::string( glyphToDraw.uni_str ); + point p( int( glyphToDraw.pos.x - 3 ), int( glyphToDraw.pos.y - 5 ) ); + unsigned char col = 0; + auto it = sdlColorsToCata.find( glyphToDraw.col & 0xFFFFFF ); + if( it != sdlColorsToCata.end() ) { + col = it->second; + } + cata_font->OutputChar( imclient.sdl_renderer, imclient.sdl_geometry, uni_string, p, col ); + } + glyphsToDraw.clear(); + } + + // this function QUEUES a character to be drawn + bool RenderFallbackChar( const char *s_begin, const char *s_end, const ImVec2 &pos, + const ImU32 &col ) const override { + glyphsToDraw.push_back( { std::string( s_begin, s_end ), pos, col } ); + return true; + } + + int GetFallbackCharWidth( const char *s_begin, const char *s_end, + const float scale ) const override { + return cata_font->width * utf8_width( std::string( s_begin, s_end ) ) * int( scale ); + } +}; +static CataImFont *activeFont; + +cataimgui::client::client( const SDL_Renderer_Ptr &sdl_renderer, const SDL_Window_Ptr &sdl_window, + const GeometryRenderer_Ptr &sdl_geometry ) : + sdl_renderer( sdl_renderer ), + sdl_window( sdl_window ), + sdl_geometry( sdl_geometry ) { IMGUI_CHECKVERSION(); ImGui::CreateContext(); @@ -177,8 +223,29 @@ cataimgui::client::client() // Setup Dear ImGui style ImGui::StyleColorsDark(); - ImGui_ImplSDL2_InitForSDLRenderer( sdl_window, sdl_renderer ); - ImGui_ImplSDLRenderer2_Init( sdl_renderer ); + ImGui_ImplSDL2_InitForSDLRenderer( sdl_window.get(), sdl_renderer.get() ); + ImGui_ImplSDLRenderer2_Init( sdl_renderer.get() ); +} + +void cataimgui::client::load_fonts( const std::unique_ptr &cata_font, + const std::array::COLOR_NAMES_COUNT> &windowsPalette ) +{ + ImGuiIO &io = ImGui::GetIO(); + if( ImGui::GetIO().FontDefault == nullptr ) { + std::vector typefaces; + ensure_unifont_loaded( typefaces ); + + ImFontConfig cfg; + cfg.DstFont = activeFont = new CataImFont( *this, cata_font ); + for( size_t index = 0; index < color_loader::COLOR_NAMES_COUNT; index++ ) { + SDL_Color sdlCol = windowsPalette[index]; + ImU32 rgb = sdlCol.b << 16 | sdlCol.g << 8 | sdlCol.r; + activeFont->sdlColorsToCata[rgb] = index; + } + io.FontDefault = io.Fonts->AddFontFromFileTTF( typefaces[0].c_str(), cata_font->height, &cfg, + io.Fonts->GetGlyphRangesDefault() ); + io.Fonts->Fonts[0] = cfg.DstFont; + } } cataimgui::client::~client() @@ -198,6 +265,10 @@ void cataimgui::client::end_frame() { ImGui::Render(); ImGui_ImplSDLRenderer2_RenderDrawData( ImGui::GetDrawData() ); + if( activeFont ) { + activeFont->OutputChars(); + } + } void cataimgui::client::process_input( void *input ) diff --git a/src/cata_imgui.h b/src/cata_imgui.h index 8074be33f8f9f..a299e35b60c5c 100644 --- a/src/cata_imgui.h +++ b/src/cata_imgui.h @@ -10,12 +10,14 @@ struct input_event; struct item_info_data; #if defined(WIN32) || defined(TILES) -struct SDL_Renderer; -struct SDL_Window; +#include "sdl_geometry.h" +#include "sdl_wrappers.h" +#include "color_loader.h" #endif struct point; class ImVec2; +class Font; namespace cataimgui { @@ -44,7 +46,14 @@ enum class dialog_result { class client { public: +#if !(defined(TILES) || defined(WIN32)) client(); +#else + client( const SDL_Renderer_Ptr &sdl_renderer, const SDL_Window_Ptr &sdl_window, + const GeometryRenderer_Ptr &sdl_geometry ); + void load_fonts( const std::unique_ptr &cata_font, + const std::array::COLOR_NAMES_COUNT> &windowsPalette ); +#endif ~client(); void new_frame(); @@ -55,8 +64,9 @@ class client void upload_color_pair( int p, int f, int b ); void set_alloced_pair_count( short count ); #else - static struct SDL_Renderer *sdl_renderer; - static struct SDL_Window *sdl_window; + const SDL_Renderer_Ptr &sdl_renderer; + const SDL_Window_Ptr &sdl_window; + const GeometryRenderer_Ptr &sdl_geometry; #endif }; diff --git a/src/sdl_font.cpp b/src/sdl_font.cpp index c2b8d0b52d91f..8d6a98b1b1c55 100644 --- a/src/sdl_font.cpp +++ b/src/sdl_font.cpp @@ -3,8 +3,8 @@ #include "font_loader.h" #include "output.h" -#include "imgui/imgui.h" #include "sdl_utils.h" +#include "ui_manager.h" #if defined(_WIN32) # if 1 // HACK: Hack to prevent reordering of #include "platform_win.h" by IWYU @@ -299,26 +299,11 @@ CachedTTFFont::CachedTTFFont( throw std::runtime_error( TTF_GetError() ); } TTF_SetFontStyle( font.get(), TTF_STYLE_NORMAL ); - - ImGuiIO &io = ImGui::GetIO(); - if( io.FontDefault == nullptr && typeface.find( "unifont" ) != std::string::npos ) { - static const std::array ranges = { - 0x0020, 0x052F, - 0x1D00, 0x1DFF, - 0x2000, 0x20CF, - 0x2100, 0x214F, - 0x2190, 0x22FF, - 0x2500, 0x27BF, - 0xC900, 0xC9FF, - //0x0020, 0xCFFF, - 0 - }; - io.FontDefault = io.Fonts->AddFontFromFileTTF( typeface.c_str(), fontsize, nullptr, ranges.data() ); - } } SDL_Texture_Ptr CachedTTFFont::create_glyph( const SDL_Renderer_Ptr &renderer, const std::string &ch, + int &ch_width, const int color ) { const auto function = fontblending ? TTF_RenderUTF8_Blended : TTF_RenderUTF8_Solid; @@ -328,11 +313,12 @@ SDL_Texture_Ptr CachedTTFFont::create_glyph( const SDL_Renderer_Ptr &renderer, return nullptr; } const int wf = utf8_width( ch ); + ch_width = width * wf; // Note: bits per pixel must be 8 to be synchronized with the surface // that TTF_RenderGlyph above returns. This is important for SDL_BlitScaled - SDL_Surface_Ptr surface = create_surface_32( width * wf, height ); + SDL_Surface_Ptr surface = create_surface_32( ch_width, height ); SDL_Rect src_rect = { 0, 0, sglyph->w, sglyph->h }; - SDL_Rect dst_rect = { 0, 0, width * wf, height }; + SDL_Rect dst_rect = { 0, 0, ch_width, height }; if( src_rect.w < dst_rect.w ) { dst_rect.x = ( dst_rect.w - src_rect.w ) / 2; dst_rect.w = src_rect.w; @@ -380,10 +366,8 @@ void CachedTTFFont::OutputChar( const SDL_Renderer_Ptr &renderer, const Geometry auto it = glyph_cache_map.find( key ); if( it == std::end( glyph_cache_map ) ) { - cached_t new_entry { - create_glyph( renderer, key.codepoints, key.color ), - static_cast( width * utf8_width( key.codepoints ) ) - }; + cached_t new_entry; + new_entry.texture = create_glyph( renderer, key.codepoints, new_entry.width, key.color ); it = glyph_cache_map.insert( std::make_pair( std::move( key ), std::move( new_entry ) ) ).first; } const cached_t &value = it->second; diff --git a/src/sdl_font.h b/src/sdl_font.h index d87453ad40483..b85eee9711a57 100644 --- a/src/sdl_font.h +++ b/src/sdl_font.h @@ -85,7 +85,8 @@ class CachedTTFFont : public Font unsigned char color, float opacity = 1.0f ) override; protected: - SDL_Texture_Ptr create_glyph( const SDL_Renderer_Ptr &renderer, const std::string &ch, int color ); + SDL_Texture_Ptr create_glyph( const SDL_Renderer_Ptr &renderer, const std::string &ch, + int &ch_width, int color ); TTF_Font_Ptr font; // Maps (character code, color) to SDL_Texture* diff --git a/src/sdltiles.cpp b/src/sdltiles.cpp index c9fb3ac039ef1..d99ad5eb431fd 100644 --- a/src/sdltiles.cpp +++ b/src/sdltiles.cpp @@ -425,12 +425,7 @@ static void WinCreate() geometry = std::make_unique(); } - cataimgui::client::sdl_renderer = renderer.get(); - cataimgui::client::sdl_window = window.get(); - imclient = std::make_unique(); - - //io.Fonts->AddFontDefault(); - //io.Fonts->Build(); + imclient = std::make_unique( renderer, window, geometry ); } static void WinDestroy() @@ -3688,7 +3683,7 @@ void catacurses::init_interface() windowsPalette, fl.overmap_typeface, fl.overmap_fontsize, fl.fontblending ); stdscr = newwin( get_terminal_height(), get_terminal_width(), point_zero ); //newwin calls `new WINDOW`, and that will throw, but not return nullptr. - + imclient->load_fonts( font, windowsPalette ); #if defined(__ANDROID__) // Make sure we initialize preview_terminal_width/height to sensible values preview_terminal_width = TERMINAL_WIDTH * fontwidth;