Skip to content

Commit

Permalink
Fixing drawing of CJK characters in ImGui screens on CDDA.
Browse files Browse the repository at this point in the history
  • Loading branch information
katemonster33 committed Mar 26, 2024
1 parent 38d741e commit 84b2a8d
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 40 deletions.
69 changes: 64 additions & 5 deletions src/cata_imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,41 @@ RGBTuple color_loader<RGBTuple>::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 "wcwidth.h"
#include <imgui/imgui_impl_sdl2.h>
#include <imgui/imgui_impl_sdlrenderer2.h>

SDL_Renderer *cataimgui::client::sdl_renderer = nullptr;
SDL_Window *cataimgui::client::sdl_window = nullptr;
struct CataImFont : public ImFont {
std::unordered_map<ImU32, unsigned char> sdlColorsToCata;
const cataimgui::client &imclient;
const std::unique_ptr<Font> &cata_font;
CataImFont( const cataimgui::client &imclient, const std::unique_ptr<Font> &cata_font ) :
imclient( imclient ), cata_font( cata_font ) {
}

cataimgui::client::client()
// this function QUEUES a character to be drawn
bool CanRenderFallbackChar( const char *s_begin, const char *s_end ) const override {
return s_begin != nullptr && s_end != nullptr;
}

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 );
}

int GetFallbackCharWidth( ImWchar c, const float scale ) const override {
return cata_font->width * mk_wcwidth( c ) * 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();
Expand All @@ -177,8 +205,39 @@ 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<Font> &cata_font,
const std::array<SDL_Color, color_loader<SDL_Color>::COLOR_NAMES_COUNT> &windowsPalette )
{
ImGuiIO &io = ImGui::GetIO();
if( ImGui::GetIO().FontDefault == nullptr ) {
std::vector<std::string> typefaces;
ensure_unifont_loaded( typefaces );

ImFontConfig cfg;
cfg.DstFont = activeFont = new CataImFont( *this, cata_font );
for( size_t index = 0; index < color_loader<SDL_Color>::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;
ImGui_ImplSDLRenderer2_SetFallbackGlyphDrawCallback( [&]( const ImFontGlyphToDraw & glyph ) {
std::string uni_string = std::string( glyph.uni_str );
point p( int( glyph.pos.x ), int( glyph.pos.y - 5 ) );
unsigned char col = 0;
auto it = activeFont->sdlColorsToCata.find( glyph.col & 0xFFFFFF );
if( it != activeFont->sdlColorsToCata.end() ) {
col = it->second;
}
cata_font->OutputChar( sdl_renderer, sdl_geometry, glyph.uni_str, p, col );
} );
}
}

cataimgui::client::~client()
Expand Down
18 changes: 14 additions & 4 deletions src/cata_imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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<Font> &cata_font,
const std::array<SDL_Color, color_loader<SDL_Color>::COLOR_NAMES_COUNT> &windowsPalette );
#endif
~client();

void new_frame();
Expand All @@ -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
};

Expand Down
30 changes: 7 additions & 23 deletions src/sdl_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<ImWchar, 17> 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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<int>( 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;
Expand Down
3 changes: 2 additions & 1 deletion src/sdl_font.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*
Expand Down
9 changes: 2 additions & 7 deletions src/sdltiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,12 +425,7 @@ static void WinCreate()
geometry = std::make_unique<DefaultGeometryRenderer>();
}

cataimgui::client::sdl_renderer = renderer.get();
cataimgui::client::sdl_window = window.get();
imclient = std::make_unique<cataimgui::client>();

//io.Fonts->AddFontDefault();
//io.Fonts->Build();
imclient = std::make_unique<cataimgui::client>( renderer, window, geometry );
}

static void WinDestroy()
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 84b2a8d

Please sign in to comment.