From 3a6558c2f148f118ec13c5f51781dbb8871d9ab9 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Wed, 13 Jan 2021 10:00:51 +0000 Subject: [PATCH] (RGUI) Add Russian language support --- gfx/drivers_font_renderer/bitmapfont_10x10.c | 11 ++ intl/msg_hash_ru.c | 50 ++++++- menu/drivers/rgui.c | 150 ++++++++++++++++++- 3 files changed, 207 insertions(+), 4 deletions(-) diff --git a/gfx/drivers_font_renderer/bitmapfont_10x10.c b/gfx/drivers_font_renderer/bitmapfont_10x10.c index 0d44faa44f..d8d9a140c8 100644 --- a/gfx/drivers_font_renderer/bitmapfont_10x10.c +++ b/gfx/drivers_font_renderer/bitmapfont_10x10.c @@ -54,6 +54,11 @@ #define FONT_10X10_GLYPH_MIN_KOR 0xAC00 #define FONT_10X10_GLYPH_MAX_KOR 0xD7A3 +#define FONT_10X10_FILE_RUS "bitmap10x10_rus.bin" +#define FONT_10X10_SIZE_RUS 1248 +#define FONT_10X10_GLYPH_MIN_RUS 0x400 +#define FONT_10X10_GLYPH_MAX_RUS 0x45F + #define FONT_10X10_OFFSET(x) ((x) * ((FONT_10X10_HEIGHT * FONT_10X10_WIDTH + 7) / 8)) /* Loads a font of the specified language @@ -107,6 +112,12 @@ bitmapfont_lut_t *bitmapfont_10x10_load(unsigned language) glyph_min = FONT_10X10_GLYPH_MIN_KOR; glyph_max = FONT_10X10_GLYPH_MAX_KOR; break; + case RETRO_LANGUAGE_RUSSIAN: + font_file = FONT_10X10_FILE_RUS; + font_size = FONT_10X10_SIZE_RUS; + glyph_min = FONT_10X10_GLYPH_MIN_RUS; + glyph_max = FONT_10X10_GLYPH_MAX_RUS; + break; default: break; } diff --git a/intl/msg_hash_ru.c b/intl/msg_hash_ru.c index 8ceb3cf9c1..9ba66acba5 100644 --- a/intl/msg_hash_ru.c +++ b/intl/msg_hash_ru.c @@ -12,10 +12,15 @@ * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ +#include #include -#include +#include + +#include +#include #include "../msg_hash.h" +#include "../verbosity.h" #if defined(_MSC_VER) && !defined(_XBOX) && (_MSC_VER >= 1500 && _MSC_VER < 1900) #if (_MSC_VER >= 1700) @@ -40,12 +45,51 @@ int msg_hash_get_help_ru_enum(enum msg_hash_enums msg, char *s, size_t len) return ret; } -const char *msg_hash_to_str_ru(enum msg_hash_enums msg) +#ifdef HAVE_MENU +static const char *menu_hash_to_str_ru_label_enum(enum msg_hash_enums msg) { + if (msg <= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_END && + msg >= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN) + { + static char hotkey_lbl[128] = {0}; + unsigned idx = msg - MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN; + snprintf(hotkey_lbl, sizeof(hotkey_lbl), "input_hotkey_binds_%d", idx); + return hotkey_lbl; + } + switch (msg) { -#include "msg_hash_ru.h" +#include "msg_hash_lbl.h" default: +#if 0 + RARCH_LOG("Unimplemented: [%d]\n", msg); +#endif + break; + } + + return "null"; +} +#endif + +const char *msg_hash_to_str_ru(enum msg_hash_enums msg) +{ +#ifdef HAVE_MENU + const char *ret = menu_hash_to_str_ru_label_enum(msg); + + if (ret && !string_is_equal(ret, "null")) + return ret; +#endif + + switch (msg) + { +#include "msg_hash_ru.h" + default: +#if 0 + RARCH_LOG("Unimplemented: [%d]\n", msg); + { + RARCH_LOG("[%d] : %s\n", msg - 1, msg_hash_to_str(((enum msg_hash_enums)(msg - 1)))); + } +#endif break; } diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index a4d688a4b3..4e292bc7de 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -602,6 +602,7 @@ typedef struct bitmapfont_lut_t *chn_10x10; bitmapfont_lut_t *jpn_10x10; bitmapfont_lut_t *kor_10x10; + bitmapfont_lut_t *rus_10x10; } fonts; frame_buf_t frame_buf; @@ -1148,6 +1149,12 @@ static void rgui_fonts_free(rgui_t *rgui) bitmapfont_free_lut(rgui->fonts.kor_10x10); rgui->fonts.kor_10x10 = NULL; } + + if (rgui->fonts.rus_10x10) + { + bitmapfont_free_lut(rgui->fonts.rus_10x10); + rgui->fonts.rus_10x10 = NULL; + } } static bool rgui_fonts_init(rgui_t *rgui) @@ -1212,6 +1219,26 @@ static bool rgui_fonts_init(rgui_t *rgui) rgui->language = language; break; case RETRO_LANGUAGE_RUSSIAN: + rgui->fonts.eng_10x10 = bitmapfont_10x10_load(RETRO_LANGUAGE_ENGLISH); + rgui->fonts.rus_10x10 = bitmapfont_10x10_load(RETRO_LANGUAGE_RUSSIAN); + + if (!rgui->fonts.eng_10x10 || + !rgui->fonts.rus_10x10) + { + rgui_fonts_free(rgui); + *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE) = RETRO_LANGUAGE_ENGLISH; + runloop_msg_queue_push( + msg_hash_to_str(MSG_RGUI_MISSING_FONTS), 1, 256, false, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + goto english; + } + + rgui->font_width = FONT_10X10_WIDTH; + rgui->font_height = FONT_10X10_HEIGHT; + rgui->font_width_stride = FONT_10X10_WIDTH_STRIDE; + rgui->font_height_stride = FONT_10X10_HEIGHT_STRIDE; + rgui->language = language; + break; case RETRO_LANGUAGE_ARABIC: case RETRO_LANGUAGE_GREEK: case RETRO_LANGUAGE_PERSIAN: @@ -2975,7 +3002,7 @@ static void blit_line_cjk_shadow( unsigned fb_width, int x, int y, const char *message, uint16_t color, uint16_t shadow_color) { - uint16_t *frame_buf_data = rgui->frame_buf.data; + uint16_t *frame_buf_data = rgui->frame_buf.data; bitmapfont_lut_t *font_eng = rgui->fonts.eng_10x10; bitmapfont_lut_t *font_chn = rgui->fonts.chn_10x10; bitmapfont_lut_t *font_jpn = rgui->fonts.jpn_10x10; @@ -3041,6 +3068,121 @@ static void blit_line_cjk_shadow( x += FONT_10X10_WIDTH_STRIDE; } } + +static void blit_line_rus( + rgui_t *rgui, + unsigned fb_width, int x, int y, + const char *message, uint16_t color, uint16_t shadow_color) +{ + uint16_t *frame_buf_data = rgui->frame_buf.data; + bitmapfont_lut_t *font_eng = rgui->fonts.eng_10x10; + bitmapfont_lut_t *font_rus = rgui->fonts.rus_10x10; + + while (!string_is_empty(message)) + { + /* Deal with spaces first, for efficiency */ + if (*message == ' ') + message++; + else + { + unsigned i, j; + bool *symbol_lut; + uint32_t symbol = utf8_walk(&message); + + if (symbol == 339) /* Latin small ligature oe */ + symbol = 156; + if (symbol == 338) /* Latin capital ligature oe */ + symbol = 140; + + /* Find glyph LUT data */ + if (symbol <= font_eng->glyph_max) + symbol_lut = font_eng->lut[symbol]; + else if ((symbol >= font_rus->glyph_min) && (symbol <= font_rus->glyph_max)) + symbol_lut = font_rus->lut[symbol - font_rus->glyph_min]; + else + continue; + + for (j = 0; j < FONT_10X10_HEIGHT; j++) + { + unsigned buff_offset = ((y + j) * fb_width) + x; + + for (i = 0; i < FONT_10X10_WIDTH; i++) + { + if (*(symbol_lut + i + (j * FONT_10X10_WIDTH))) + *(frame_buf_data + buff_offset + i) = color; + } + } + } + + x += FONT_10X10_WIDTH_STRIDE; + } +} + +static void blit_line_rus_shadow( + rgui_t *rgui, + unsigned fb_width, int x, int y, + const char *message, uint16_t color, uint16_t shadow_color) +{ + uint16_t *frame_buf_data = rgui->frame_buf.data; + bitmapfont_lut_t *font_eng = rgui->fonts.eng_10x10; + bitmapfont_lut_t *font_rus = rgui->fonts.rus_10x10; + uint16_t color_buf[2]; + uint16_t shadow_color_buf[2]; + + color_buf[0] = color; + color_buf[1] = shadow_color; + + shadow_color_buf[0] = shadow_color; + shadow_color_buf[1] = shadow_color; + + while (!string_is_empty(message)) + { + /* Deal with spaces first, for efficiency */ + if (*message == ' ') + message++; + else + { + unsigned i, j; + bool *symbol_lut; + uint32_t symbol = utf8_walk(&message); + + if (symbol == 339) /* Latin small ligature oe */ + symbol = 156; + if (symbol == 338) /* Latin capital ligature oe */ + symbol = 140; + + /* Find glyph LUT data */ + if (symbol <= font_eng->glyph_max) + symbol_lut = font_eng->lut[symbol]; + else if ((symbol >= font_rus->glyph_min) && (symbol <= font_rus->glyph_max)) + symbol_lut = font_rus->lut[symbol - font_rus->glyph_min]; + else + continue; + + for (j = 0; j < FONT_10X10_HEIGHT; j++) + { + unsigned buff_offset = ((y + j) * fb_width) + x; + + for (i = 0; i < FONT_10X10_WIDTH; i++) + { + if (*(symbol_lut + i + (j * FONT_10X10_WIDTH))) + { + uint16_t *frame_buf_ptr = frame_buf_data + buff_offset + i; + + /* Text pixel + right shadow */ + memcpy(frame_buf_ptr, color_buf, sizeof(color_buf)); + + /* Bottom shadow */ + frame_buf_ptr += fb_width; + memcpy(frame_buf_ptr, shadow_color_buf, sizeof(shadow_color_buf)); + } + } + } + } + + x += FONT_10X10_WIDTH_STRIDE; + } +} #endif static void (*blit_line)(rgui_t *rgui, unsigned fb_width, int x, int y, @@ -3175,6 +3317,9 @@ static void rgui_set_blit_functions(unsigned language, case RETRO_LANGUAGE_CHINESE_TRADITIONAL: blit_line = blit_line_cjk_shadow; break; + case RETRO_LANGUAGE_RUSSIAN: + blit_line = blit_line_rus_shadow; + break; default: if (extended_ascii) blit_line = blit_line_extended_shadow; @@ -3202,6 +3347,9 @@ static void rgui_set_blit_functions(unsigned language, case RETRO_LANGUAGE_CHINESE_TRADITIONAL: blit_line = blit_line_cjk; break; + case RETRO_LANGUAGE_RUSSIAN: + blit_line = blit_line_rus; + break; default: if (extended_ascii) blit_line = blit_line_extended;