1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-03 00:38:44 +00:00

(RGUI) Add support for CJK fonts

This commit is contained in:
jdgleaver 2020-12-09 16:48:09 +00:00
parent 625f0d4fc6
commit 0f0ccbadc0
14 changed files with 1356 additions and 600 deletions

View File

@ -278,6 +278,7 @@ endif
OBJ += \
gfx/drivers_font_renderer/bitmapfont.o \
gfx/drivers_font_renderer/bitmapfont_10x10.o \
tasks/task_autodetect.o \
input/input_autodetect_builtin.o \
input/input_keymaps.o \
@ -2394,4 +2395,5 @@ ifeq ($(HAVE_ODROIDGO2), 1)
$(DEPS_DIR)/libgo2/src/queue.o \
gfx/drivers/oga_gfx.o
endif
##################################

View File

@ -320,6 +320,23 @@ void fill_pathname_application_special(char *s,
#endif
break;
case APPLICATION_SPECIAL_DIRECTORY_ASSETS_RGUI_FONT:
#ifdef HAVE_RGUI
{
char rgui_dir[PATH_MAX_LENGTH];
settings_t *settings = config_get_ptr();
const char *dir_assets = settings->paths.directory_assets;
rgui_dir[0] = '\0';
fill_pathname_join(rgui_dir, dir_assets, "rgui",
sizeof(rgui_dir));
fill_pathname_join(s,
rgui_dir, "font", len);
}
#endif
break;
case APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB:
#ifdef HAVE_XMB
{

View File

@ -128,6 +128,7 @@ enum application_special_type
APPLICATION_SPECIAL_DIRECTORY_ASSETS_XMB_FONT,
APPLICATION_SPECIAL_DIRECTORY_ASSETS_OZONE,
APPLICATION_SPECIAL_DIRECTORY_ASSETS_OZONE_ICONS,
APPLICATION_SPECIAL_DIRECTORY_ASSETS_RGUI_FONT,
APPLICATION_SPECIAL_DIRECTORY_ASSETS_SOUNDS,
APPLICATION_SPECIAL_DIRECTORY_ASSETS_SYSICONS,
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES,

View File

@ -17,6 +17,8 @@
#ifndef __RARCH_FONT_BITMAP_H
#define __RARCH_FONT_BITMAP_H
#include <stdint.h>
#define FONT_WIDTH 5
#define FONT_HEIGHT 10
/* FONT_HEIGHT_BASELINE_OFFSET:
@ -143,4 +145,22 @@ static const unsigned char bitmap_bin[1792] = {
0xD0, 0x01, 0x20, 0x84, 0x17, 0x63, 0x7C, 0x21, 0x00, 0x40, 0x81, 0x18, 0x63, 0xF4, 0xD0, 0x01
};
typedef struct
{
bool **lut;
uint16_t glyph_min;
uint16_t glyph_max;
} bitmapfont_lut_t;
/* Generates a boolean LUT:
* lut[num_glyphs][glyph_width * glyph_height]
* LUT value is 'true' if glyph pixel has a
* non-zero value.
* Returned object must be freed using
* bitmapfont_free_lut().
* Returns NULL in the event of an error. */
bitmapfont_lut_t *bitmapfont_get_lut(void);
void bitmapfont_free_lut(bitmapfont_lut_t *font);
#endif

View File

@ -161,3 +161,86 @@ font_renderer_driver_t bitmap_font_renderer = {
"bitmap",
font_renderer_bmp_get_line_metrics
};
/* Generates a boolean LUT:
* lut[num_glyphs][glyph_width * glyph_height]
* LUT value is 'true' if glyph pixel has a
* non-zero value.
* Returned object must be freed using
* bitmapfont_free_lut().
* Returns NULL in the event of an error. */
bitmapfont_lut_t *bitmapfont_get_lut(void)
{
bitmapfont_lut_t *font = NULL;
size_t symbol_index;
size_t i, j;
/* Initialise font struct */
font = (bitmapfont_lut_t*)calloc(1, sizeof(bitmapfont_lut_t));
if (!font)
goto error;
font->glyph_min = 0;
font->glyph_max = BMP_ATLAS_SIZE - 1;
/* Note: Need to use a calloc() here, otherwise
* we'll get undefined behaviour when calling
* bitmapfont_free_lut() if the following loop fails */
font->lut = (bool**)calloc(1, BMP_ATLAS_SIZE * sizeof(bool*));
if (!font->lut)
goto error;
/* Loop over all possible characters */
for (symbol_index = 0; symbol_index < BMP_ATLAS_SIZE; symbol_index++)
{
/* Allocate memory for current symbol */
font->lut[symbol_index] = (bool*)malloc(FONT_WIDTH *
FONT_HEIGHT * sizeof(bool));
if (!font->lut[symbol_index])
goto error;
for (j = 0; j < FONT_HEIGHT; j++)
{
for (i = 0; i < FONT_WIDTH; i++)
{
uint8_t rem = 1 << ((i + j * FONT_WIDTH) & 7);
unsigned offset = (i + j * FONT_WIDTH) >> 3;
/* LUT value is 'true' if specified glyph
* position contains a pixel */
font->lut[symbol_index][i + (j * FONT_WIDTH)] =
(bitmap_bin[FONT_OFFSET(symbol_index) + offset] & rem) > 0;
}
}
}
return font;
error:
if (font)
bitmapfont_free_lut(font);
return NULL;
}
void bitmapfont_free_lut(bitmapfont_lut_t *font)
{
if (!font)
return;
if (font->lut)
{
size_t num_glyphs = (font->glyph_max - font->glyph_min) + 1;
size_t i;
for (i = 0; i < num_glyphs; i++)
{
if (font->lut[i])
free(font->lut[i]);
}
free(font->lut);
}
free(font);
}

View File

@ -0,0 +1,196 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2020 - Daniel De Matteis
* Copyright (C) 2019-2020 - James Leaver
* Copyright (C) 2020 - trngaje
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <libretro.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <boolean.h>
#include <string/stdstring.h>
#include <file/file_path.h>
#include <streams/rzip_stream.h>
#include <retro_miscellaneous.h>
#include "../../file_path_special.h"
#include "../../verbosity.h"
#include "bitmapfont_10x10.h"
#define FONT_10X10_FILE_ENG "bitmap10x10_eng.bin"
#define FONT_10X10_SIZE_ENG 3328
#define FONT_10X10_GLYPH_MIN_ENG 0x0
#define FONT_10X10_GLYPH_MAX_ENG 0xFF
#define FONT_10X10_FILE_CHN "bitmap10x10_chn.bin"
#define FONT_10X10_SIZE_CHN 272896
#define FONT_10X10_GLYPH_MIN_CHN 0x4E00
#define FONT_10X10_GLYPH_MAX_CHN 0x9FFF
#define FONT_10X10_FILE_JPN "bitmap10x10_jpn.bin"
#define FONT_10X10_SIZE_JPN 2496
#define FONT_10X10_GLYPH_MIN_JPN 0x3040
#define FONT_10X10_GLYPH_MAX_JPN 0x30FF
#define FONT_10X10_FILE_KOR "bitmap10x10_kor.bin"
#define FONT_10X10_SIZE_KOR 145236
#define FONT_10X10_GLYPH_MIN_KOR 0xAC00
#define FONT_10X10_GLYPH_MAX_KOR 0xD7A3
#define FONT_10X10_OFFSET(x) ((x) * ((FONT_10X10_HEIGHT * FONT_10X10_WIDTH + 7) / 8))
/* Loads a font of the specified language
* Returns NULL if language is invalid or
* font file is missing */
bitmapfont_lut_t *bitmapfont_10x10_load(unsigned language)
{
char font_dir[PATH_MAX_LENGTH];
char font_path[PATH_MAX_LENGTH];
const char *font_file = NULL;
void *bitmap_raw = NULL;
unsigned char *bitmap_char = NULL;
bitmapfont_lut_t *font = NULL;
int64_t font_size = 0;
int64_t len = 0;
size_t glyph_min = 0;
size_t glyph_max = 0;
size_t num_glyphs = 0;
size_t symbol_index;
size_t i, j;
font_dir[0] = '\0';
font_path[0] = '\0';
/* Get font file associated with
* specified language */
switch (language)
{
case RETRO_LANGUAGE_ENGLISH:
font_file = FONT_10X10_FILE_ENG;
font_size = FONT_10X10_SIZE_ENG;
glyph_min = FONT_10X10_GLYPH_MIN_ENG;
glyph_max = FONT_10X10_GLYPH_MAX_ENG;
break;
case RETRO_LANGUAGE_CHINESE_SIMPLIFIED:
case RETRO_LANGUAGE_CHINESE_TRADITIONAL:
font_file = FONT_10X10_FILE_CHN;
font_size = FONT_10X10_SIZE_CHN;
glyph_min = FONT_10X10_GLYPH_MIN_CHN;
glyph_max = FONT_10X10_GLYPH_MAX_CHN;
break;
case RETRO_LANGUAGE_JAPANESE:
font_file = FONT_10X10_FILE_JPN;
font_size = FONT_10X10_SIZE_JPN;
glyph_min = FONT_10X10_GLYPH_MIN_JPN;
glyph_max = FONT_10X10_GLYPH_MAX_JPN;
break;
case RETRO_LANGUAGE_KOREAN:
font_file = FONT_10X10_FILE_KOR;
font_size = FONT_10X10_SIZE_KOR;
glyph_min = FONT_10X10_GLYPH_MIN_KOR;
glyph_max = FONT_10X10_GLYPH_MAX_KOR;
break;
default:
break;
}
if (string_is_empty(font_file))
{
RARCH_WARN("[bitmap 10x10] No font file found for specified language: %u\n", language);
goto error;
}
/* Get font path */
fill_pathname_application_special(font_dir, sizeof(font_dir),
APPLICATION_SPECIAL_DIRECTORY_ASSETS_RGUI_FONT);
fill_pathname_join(font_path, font_dir, font_file,
sizeof(font_path));
/* Attempt to read bitmap file */
if (!rzipstream_read_file(font_path, &bitmap_raw, &len))
{
RARCH_WARN("[bitmap 10x10] Failed to read font file: %s\n", font_path);
goto error;
}
/* Ensure that we have the correct number
* of bytes */
if (len < font_size)
{
RARCH_WARN("[bitmap 10x10] Font file has invalid size: %s\n", font_path);
goto error;
}
bitmap_char = (unsigned char *)bitmap_raw;
num_glyphs = (glyph_max - glyph_min) + 1;
/* Initialise font struct */
font = (bitmapfont_lut_t*)calloc(1, sizeof(bitmapfont_lut_t));
if (!font)
goto error;
font->glyph_min = glyph_min;
font->glyph_max = glyph_max;
/* Note: Need to use a calloc() here, otherwise
* we'll get undefined behaviour when calling
* bitmapfont_free_lut() if the following loop fails */
font->lut = (bool**)calloc(1, num_glyphs * sizeof(bool*));
if (!font->lut)
goto error;
/* Loop over all possible characters */
for (symbol_index = 0; symbol_index < num_glyphs; symbol_index++)
{
/* Allocate memory for current symbol */
font->lut[symbol_index] = (bool*)malloc(FONT_10X10_WIDTH *
FONT_10X10_HEIGHT * sizeof(bool));
if (!font->lut[symbol_index])
goto error;
for (j = 0; j < FONT_10X10_HEIGHT; j++)
{
for (i = 0; i < FONT_10X10_WIDTH; i++)
{
uint8_t rem = 1 << ((i + j * FONT_10X10_WIDTH) & 7);
unsigned offset = (i + j * FONT_10X10_WIDTH) >> 3;
/* LUT value is 'true' if specified glyph
* position contains a pixel */
font->lut[symbol_index][i + (j * FONT_10X10_WIDTH)] =
(bitmap_char[FONT_10X10_OFFSET(symbol_index) + offset] & rem) > 0;
}
}
}
/* Clean up */
free(bitmap_raw);
return font;
error:
if (bitmap_raw)
free(bitmap_raw);
if (font)
bitmapfont_free_lut(font);
return NULL;
}

View File

@ -0,0 +1,40 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2020 - Daniel De Matteis
* Copyright (C) 2019-2020 - James Leaver
* Copyright (C) 2020 - trngaje
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_FONT_BITMAP_10X10_H
#define __RARCH_FONT_BITMAP_10X10_H
#include "bitmap.h"
#define FONT_10X10_WIDTH 10
#define FONT_10X10_HEIGHT 10
/* FONT_HEIGHT_BASELINE_OFFSET:
* Distance in pixels from top of character
* to baseline */
#define FONT_10X10_HEIGHT_BASELINE_OFFSET 8
#define FONT_10X10_WIDTH_STRIDE (FONT_10X10_WIDTH + 1)
#define FONT_10X10_HEIGHT_STRIDE (FONT_10X10_HEIGHT + 1)
/* Loads a font of the specified language.
* Returned object must be freed using
* bitmapfont_free_lut().
* Returns NULL if language is invalid or
* font file is missing */
bitmapfont_lut_t *bitmapfont_10x10_load(unsigned language);
#endif

View File

@ -571,6 +571,7 @@ FONTS
============================================================ */
#include "../gfx/drivers_font_renderer/bitmapfont.c"
#include "../gfx/drivers_font_renderer/bitmapfont_10x10.c"
#include "../gfx/font_driver.c"
#if defined(HAVE_D3D9) && defined(HAVE_D3DX)

View File

@ -11458,6 +11458,14 @@ MSG_HASH(
MSG_MISSING_ASSETS,
"Warning: Missing assets, use the Online Updater if available"
)
MSG_HASH(
MSG_RGUI_MISSING_FONTS,
"Warning: Missing fonts for selected language, use the Online Updater if available"
)
MSG_HASH(
MSG_RGUI_INVALID_LANGUAGE,
"Warning: Unsupported language - using English"
)
MSG_HASH(
MSG_DUMPING_DISC,
"Dumping disc..."

File diff suppressed because it is too large Load Diff

View File

@ -230,7 +230,7 @@ enum menu_settings_type
typedef struct menu_ctx_driver
{
/* Set a framebuffer texture. This is used for instance by RGUI. */
void (*set_texture)(void);
void (*set_texture)(void *data);
/* Render a messagebox to the screen. */
void (*render_messagebox)(void *data, const char *msg);
int (*iterate)(void *data, void *userdata, enum menu_action action);

View File

@ -18012,6 +18012,8 @@ static bool setting_append_list(
true,
true);
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
(*list)[list_info->index - 1].action_left = &setting_uint_action_left_with_refresh;
(*list)[list_info->index - 1].action_right = &setting_uint_action_right_with_refresh;
(*list)[list_info->index - 1].get_string_representation =
&setting_get_string_representation_uint_user_language;
(*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX;

View File

@ -467,6 +467,8 @@ enum msg_hash_enums
MSG_RUNAHEAD_FAILED_TO_LOAD_STATE,
MSG_RUNAHEAD_FAILED_TO_CREATE_SECONDARY_INSTANCE,
MSG_MISSING_ASSETS,
MSG_RGUI_MISSING_FONTS,
MSG_RGUI_INVALID_LANGUAGE,
#ifdef HAVE_LAKKA
MSG_LOCALAP_SWITCHING_OFF,
MSG_WIFI_DISCONNECT_FROM,

View File

@ -22992,9 +22992,33 @@ static void menu_input_get_touchscreen_hw_state(
last_cancel_pressed = hw_state->cancel_pressed;
}
static INLINE bool input_event_osk_show_symbol_pages(
struct rarch_state *p_rarch)
{
#if defined(HAVE_LANGEXTRA)
#if defined(HAVE_RGUI)
menu_handle_t *menu = p_rarch->menu_driver_data;
bool menu_has_fb = (menu &&
menu->driver_ctx &&
menu->driver_ctx->set_texture);
unsigned language = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE);
return !menu_has_fb ||
((language == RETRO_LANGUAGE_JAPANESE) ||
(language == RETRO_LANGUAGE_KOREAN) ||
(language == RETRO_LANGUAGE_CHINESE_SIMPLIFIED) ||
(language == RETRO_LANGUAGE_CHINESE_TRADITIONAL));
#else /* HAVE_RGUI */
return true;
#endif /* HAVE_RGUI */
#else /* HAVE_LANGEXTRA */
return false;
#endif /* HAVE_LANGEXTRA */
}
static void input_event_osk_append(
struct rarch_state *p_rarch,
enum osk_type *osk_idx, int ptr, bool is_rgui,
enum osk_type *osk_idx, int ptr,
bool show_symbol_pages,
const char *word)
{
#ifdef HAVE_LANGEXTRA
@ -23020,7 +23044,7 @@ static void input_event_osk_append(
*osk_idx = OSK_LOWERCASE_LATIN;
else if (string_is_equal(word, "Next"))
#endif
if (*osk_idx < (is_rgui ? OSK_SYMBOLS_PAGE1 : OSK_TYPE_LAST - 1))
if (*osk_idx < (show_symbol_pages ? OSK_TYPE_LAST - 1 : OSK_SYMBOLS_PAGE1))
*osk_idx = (enum osk_type)(*osk_idx + 1);
else
*osk_idx = ((enum osk_type)(OSK_TYPE_UNKNOWN + 1));
@ -23123,15 +23147,6 @@ static unsigned menu_event(
RETRO_DEVICE_ID_JOYPAD_A : RETRO_DEVICE_ID_JOYPAD_B;
unsigned ok_current = BIT256_GET_PTR(p_input, menu_ok_btn);
unsigned ok_trigger = ok_current & ~ok_old;
#ifdef HAVE_RGUI
menu_handle_t *menu = p_rarch->menu_driver_data;
bool menu_has_fb =
(menu &&
menu->driver_ctx &&
menu->driver_ctx->set_texture);
#else
bool menu_has_fb = false;
#endif
ok_old = ok_current;
@ -23189,6 +23204,8 @@ static unsigned menu_event(
if (display_kb)
{
bool show_osk_symbols = input_event_osk_show_symbol_pages(p_rarch);
input_event_osk_iterate(p_rarch, p_rarch->osk_idx);
if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_DOWN))
@ -23221,16 +23238,16 @@ static unsigned menu_event(
p_rarch->osk_idx = ((enum osk_type)
(p_rarch->osk_idx - 1));
else
p_rarch->osk_idx = ((enum osk_type)(menu_has_fb
? OSK_SYMBOLS_PAGE1
: OSK_TYPE_LAST - 1));
p_rarch->osk_idx = ((enum osk_type)(show_osk_symbols
? OSK_TYPE_LAST - 1
: OSK_SYMBOLS_PAGE1));
}
if (BIT256_GET_PTR(p_trigger_input, RETRO_DEVICE_ID_JOYPAD_R))
{
if (p_rarch->osk_idx < (menu_has_fb
? OSK_SYMBOLS_PAGE1
: OSK_TYPE_LAST - 1))
if (p_rarch->osk_idx < (show_osk_symbols
? OSK_TYPE_LAST - 1
: OSK_SYMBOLS_PAGE1))
p_rarch->osk_idx = ((enum osk_type)(
p_rarch->osk_idx + 1));
else
@ -23244,7 +23261,7 @@ static unsigned menu_event(
p_rarch,
&p_rarch->osk_idx,
p_rarch->osk_ptr,
menu_has_fb,
show_osk_symbols,
p_rarch->osk_grid[p_rarch->osk_ptr]);
}
@ -23900,17 +23917,14 @@ static int menu_input_pointer_post_iterate(
menu_driver_ctl(RARCH_MENU_CTL_OSK_PTR_AT_POS, &point);
if (point.retcode > -1)
{
bool menu_has_fb =
(menu &&
menu->driver_ctx &&
menu->driver_ctx->set_texture);
bool show_osk_symbols = input_event_osk_show_symbol_pages(p_rarch);
p_rarch->osk_ptr = point.retcode;
input_event_osk_append(
p_rarch,
&p_rarch->osk_idx,
point.retcode,
menu_has_fb,
show_osk_symbols,
p_rarch->osk_grid[p_rarch->osk_ptr]);
}
}
@ -36831,7 +36845,7 @@ static enum runloop_state runloop_check_state(
video_driver_cached_frame();
if (menu->driver_ctx->set_texture)
menu->driver_ctx->set_texture();
menu->driver_ctx->set_texture(menu->userdata);
menu->state = 0;
}