From f21371f166a49344a7f9f1d90f4c2d78e2389175 Mon Sep 17 00:00:00 2001 From: Toad King Date: Tue, 19 Jun 2012 12:41:06 -0400 Subject: [PATCH] reuse font code for Raspberry Pi graphics core also move bcm_host_init() to graphics core --- gfx/fonts/fonts.c | 10 +- gfx/fonts/fonts.h | 1 + gfx/rpi.c | 437 ++++++++++++---------------------------------- retroarch.c | 7 - 4 files changed, 121 insertions(+), 334 deletions(-) diff --git a/gfx/fonts/fonts.c b/gfx/fonts/fonts.c index c027a7133f..b6ac68e695 100644 --- a/gfx/fonts/fonts.c +++ b/gfx/fonts/fonts.c @@ -93,8 +93,12 @@ void font_renderer_msg(font_renderer_t *handle, const char *msg, struct font_out tmp->width = slot->bitmap.width; tmp->height = slot->bitmap.rows; tmp->pitch = slot->bitmap.pitch; - tmp->off_x = off_x + slot->bitmap_left; - tmp->off_y = off_y + slot->bitmap_top - slot->bitmap.rows; + tmp->advance_x = slot->advance.x >> 6; + tmp->advance_y = slot->advance.y >> 6; + tmp->char_off_x = slot->bitmap_left; + tmp->char_off_y = slot->bitmap_top - slot->bitmap.rows; + tmp->off_x = off_x + tmp->char_off_x; + tmp->off_y = off_y + tmp->char_off_y; tmp->next = NULL; if (i == 0) @@ -147,6 +151,8 @@ static const char *font_paths[] = { static const char *font_paths[] = { "/usr/share/fonts/TTF/DejaVuSansMono.ttf", "/usr/share/fonts/TTF/DejaVuSans.ttf", + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", + "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", #endif "osd-font.ttf", // Magic font to search for, useful for distribution. }; diff --git a/gfx/fonts/fonts.h b/gfx/fonts/fonts.h index 6f2abd6934..f99f94df2c 100644 --- a/gfx/fonts/fonts.h +++ b/gfx/fonts/fonts.h @@ -26,6 +26,7 @@ struct font_output uint8_t *output; // 8-bit intensity. unsigned width, height, pitch; int off_x, off_y; + int advance_x, advance_y, char_off_x, char_off_y; // for advanced font rendering struct font_output *next; // linked list. }; diff --git a/gfx/rpi.c b/gfx/rpi.c index 62c94b335a..bed72cdb99 100644 --- a/gfx/rpi.c +++ b/gfx/rpi.c @@ -1,3 +1,19 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2012 - Michael Lelli + * + * 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 . + */ + #include #include #include @@ -14,10 +30,7 @@ typedef struct linuxraw_input linuxraw_input_t; #include "../driver.h" #ifdef HAVE_FREETYPE -#include -#include -#include FT_FREETYPE_H -#include FT_OUTLINE_H +#include "fonts/fonts.h" #include "../file.h" #endif @@ -43,9 +56,8 @@ typedef struct { #ifdef HAVE_FREETYPE char *mLastMsg; uint32_t mFontHeight; - FT_Library ftLib; - FT_Face ftFace; VGFont mFont; + font_renderer_t *mFontRenderer; bool mFontsOn; VGuint mMsgLength; VGuint mGlyphIndices[1024]; @@ -89,6 +101,8 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v EGLConfig config; + bcm_host_init(); + // get an EGL display connection rpi->mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert(rpi->mDisplay != EGL_NO_DISPLAY); @@ -160,87 +174,41 @@ static void *rpi_init(const video_info_t *video, const input_driver_t **input, v rpi->mImage = vgCreateImage(video->rgb32 ? VG_sABGR_8888 : VG_sXBGR_8888, rpi->mTextureWidth, rpi->mTextureHeight, video->smooth ? VG_IMAGE_QUALITY_BETTER : VG_IMAGE_QUALITY_NONANTIALIASED); rpi_set_nonblock_state(rpi, !video->vsync); - if (isatty(0)) + linuxraw_input_t *linuxraw_input = (linuxraw_input_t *)input_linuxraw.init(); + if (linuxraw_input) { - const linuxraw_input_t *linuxraw_input = (const linuxraw_input_t *) input_linuxraw.init(); - if (linuxraw_input) - { - *input = (const input_driver_t *) &input_linuxraw; - *input_data = linuxraw_input; - } + *input = (const input_driver_t *)&input_linuxraw; + *input_data = linuxraw_input; } #ifdef HAVE_FREETYPE - - static const char *font_paths[] = { - "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", - "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", - "osd-font.ttf", // Magic font to search for, useful for distribution. - }; - - const char *font = g_settings.video.font_path; - - if (!g_settings.video.font_enable) - goto fail; - - if (!path_file_exists(font)) + if (g_settings.video.font_enable) { - font = NULL; + rpi->mFont = vgCreateFont(0); + rpi->mFontHeight = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); - for (int i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++) + const char *path = g_settings.video.font_path; + if (!*path || !path_file_exists(path)) + path = font_renderer_get_default_font(); + + rpi->mFontRenderer = font_renderer_new(path, rpi->mFontHeight); + + if (rpi->mFont != VG_INVALID_HANDLE && rpi->mFontRenderer) { - if (path_file_exists(font_paths[i])) - { - font = font_paths[i]; - break; - } + rpi->mFontsOn = true; + + rpi->mPaintFg = vgCreatePaint(); + rpi->mPaintBg = vgCreatePaint(); + VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; + VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; + + vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); + + vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); } } - - if (!font) - { - RARCH_WARN("No font found, messages disabled...\n"); - goto fail; - } - - if (FT_Init_FreeType(&rpi->ftLib)) { - RARCH_WARN("failed to initialize freetype\n"); - goto fail; - } - - if (FT_New_Face(rpi->ftLib, font, 0, &rpi->ftFace)) { - RARCH_WARN("failed to load %s\n", font); - goto fail; - } - - if (FT_Select_Charmap(rpi->ftFace, FT_ENCODING_UNICODE)) { - RARCH_WARN("failed to select an unicode charmap\n"); - goto fail; - } - - uint32_t size = g_settings.video.font_size * (g_settings.video.font_scale ? (float) rpi->mScreenWidth / 1280.0f : 1.0f); - rpi->mFontHeight = size; - - if (FT_Set_Pixel_Sizes(rpi->ftFace, size, size)) - RARCH_WARN("failed to set pixel sizes\n"); - - rpi->mFont = vgCreateFont(0); - - if (rpi->mFont) - rpi->mFontsOn = true; - - rpi->mPaintFg = vgCreatePaint(); - rpi->mPaintBg = vgCreatePaint(); - VGfloat paintFg[] = { g_settings.video.msg_color_r, g_settings.video.msg_color_g, g_settings.video.msg_color_b, 1.0f }; - VGfloat paintBg[] = { g_settings.video.msg_color_r / 2.0f, g_settings.video.msg_color_g / 2.0f, g_settings.video.msg_color_b / 2.0f, 0.5f }; - - vgSetParameteri(rpi->mPaintFg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintFg, VG_PAINT_COLOR, 4, paintFg); - - vgSetParameteri(rpi->mPaintBg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); - vgSetParameterfv(rpi->mPaintBg, VG_PAINT_COLOR, 4, paintBg); - - fail: #endif return rpi; @@ -252,6 +220,16 @@ static void rpi_free(void *data) vgDestroyImage(rpi->mImage); +#ifdef HAVE_FREETYPE + if (rpi->mFontsOn) + { + vgDestroyFont(rpi->mFont); + font_renderer_free(rpi->mFontRenderer); + vgDestroyPaint(rpi->mPaintFg); + vgDestroyPaint(rpi->mPaintBg); + } +#endif + // Release EGL resources eglMakeCurrent(rpi->mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(rpi->mDisplay, rpi->mSurface); @@ -263,254 +241,62 @@ static void rpi_free(void *data) #ifdef HAVE_FREETYPE -// mostly adapted from example code in Mesa-3d - -static int path_append(VGPath path, VGubyte segment, const FT_Vector **vectors) +static void rpi_render_message(rpi_t *rpi, const char *msg) { - VGfloat coords[6]; - int i, num_vectors; + free(rpi->mLastMsg); + rpi->mLastMsg = strdup(msg); - switch (segment) + if(rpi->mMsgLength) { - case VG_MOVE_TO: - case VG_LINE_TO: - num_vectors = 1; - break; - case VG_QUAD_TO: - num_vectors = 2; - break; - case VG_CUBIC_TO: - num_vectors = 3; - break; - default: - return -1; + while (--rpi->mMsgLength) + vgClearGlyph(rpi->mFont, rpi->mMsgLength); + + vgClearGlyph(rpi->mFont, 0); + } + + struct font_output_list out; + font_renderer_msg(rpi->mFontRenderer, msg, &out); + struct font_output *head = out.head; + + while (head) + { + if (rpi->mMsgLength >= 1024) break; + + VGfloat origin[2], escapement[2]; + VGImage img; + + escapement[0] = (VGfloat) (head->advance_x); + escapement[1] = (VGfloat) (head->advance_y); + origin[0] = (VGfloat) (-head->char_off_x); + origin[1] = (VGfloat) (head->char_off_y); + + img = vgCreateImage(VG_A_8, head->width, head->height, VG_IMAGE_QUALITY_NONANTIALIASED); + + // flip it + for (unsigned i = 0; i < head->height; i++) + vgImageSubData(img, head->output + head->pitch * i, head->pitch, VG_A_8, 0, head->height - i - 1, head->width, 1); + + vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, img, origin, escapement); + vgDestroyImage(img); + + rpi->mMsgLength++; + head = head->next; } - for (i = 0; i < num_vectors; i++) - { - coords[2 * i + 0] = (float) vectors[i]->x / 64.0f; - coords[2 * i + 1] = (float) vectors[i]->y / 64.0f; - } + font_renderer_free_output(&out); - vgAppendPathData(path, 1, &segment, (const void *) coords); - - return 0; -} - -static int decompose_move_to(const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - - return path_append(path, VG_MOVE_TO, &to); -} - -static int decompose_line_to(const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - - return path_append(path, VG_LINE_TO, &to); -} - -static int decompose_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - const FT_Vector *vectors[2] = { control, to }; - - return path_append(path, VG_QUAD_TO, vectors); -} - -static int decompose_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) -{ - VGPath path = (VGPath) (VGuint) user; - const FT_Vector *vectors[3] = { control1, control2, to }; - - return path_append(path, VG_CUBIC_TO, vectors); -} - -static VGHandle convert_outline_glyph(rpi_t *rpi) -{ - FT_GlyphSlot glyph = rpi->ftFace->glyph; - FT_Outline_Funcs funcs = { - decompose_move_to, - decompose_line_to, - decompose_conic_to, - decompose_cubic_to, - 0, 0 - }; - - VGHandle path; - - path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, glyph->outline.n_points, VG_PATH_CAPABILITY_ALL); - - if (FT_Outline_Decompose(&glyph->outline, &funcs, (void *) (VGuint) path)) - { - vgDestroyPath(path); - path = VG_INVALID_HANDLE; - } - - return path; -} - -static VGint glyph_string_add_path(rpi_t *rpi, VGPath path, const VGfloat origin[2], VGfloat escapement[2]) -{ - if (rpi->mMsgLength >= 1024) - return -1; - - if (rpi->mFont != VG_INVALID_HANDLE) - { - vgSetGlyphToPath(rpi->mFont, rpi->mMsgLength, path, VG_TRUE, origin, escapement); - return rpi->mMsgLength++; - } - - return -1; -} - -static VGHandle convert_bitmap_glyph(rpi_t *rpi) -{ - FT_GlyphSlot glyph = rpi->ftFace->glyph; - VGImage image; - VGint width, height, stride; - unsigned char *data; - int i, j; - - switch (glyph->bitmap.pixel_mode) - { - case FT_PIXEL_MODE_MONO: - case FT_PIXEL_MODE_GRAY: - break; - default: - return VG_INVALID_HANDLE; - break; - } - - data = glyph->bitmap.buffer; - width = glyph->bitmap.width; - height = glyph->bitmap.rows; - stride = glyph->bitmap.pitch; - - /* mono to gray, and flip if needed */ - if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) - { - data = malloc(width * height); - if (!data) - return VG_INVALID_HANDLE; - - for (i = 0; i < height; i++) - { - unsigned char *dst = &data[width * i]; - const unsigned char *src; - - if (stride > 0) - src = glyph->bitmap.buffer + stride * (height - i - 1); - else - src = glyph->bitmap.buffer - stride * i; - - for (j = 0; j < width; j++) - { - if (src[j / 8] & (1 << (7 - (j % 8)))) - dst[j] = 0xff; - else - dst[j] = 0x0; - } - } - stride = -width; - } - - image = vgCreateImage(VG_A_8, width, height, VG_IMAGE_QUALITY_NONANTIALIASED); - - if (stride < 0) - { - stride = -stride; - vgImageSubData(image, data, stride, VG_A_8, 0, 0, width, height); - } - else - { - /* flip vertically */ - for (i = 0; i < height; i++) - { - const unsigned char *row = data + stride * i; - - vgImageSubData(image, row, stride, VG_A_8, 0, height - i - 1, width, 1); - } - } - - if (data != glyph->bitmap.buffer) - free(data); - - return (VGHandle) image; -} - -static VGint glyph_string_add_image(rpi_t *rpi, VGImage image, const VGfloat origin[2], VGfloat escapement[2]) -{ - if (rpi->mMsgLength >= 1024) - return -1; - - if (rpi->mFont != VG_INVALID_HANDLE) - { - vgSetGlyphToImage(rpi->mFont, rpi->mMsgLength, image, origin, escapement); - return rpi->mMsgLength++; - } - - return -1; + for (unsigned i = 0; i < rpi->mMsgLength; i++) + rpi->mGlyphIndices[i] = i; } static void rpi_draw_message(rpi_t *rpi, const char *msg) { if (!rpi->mLastMsg || strcmp(rpi->mLastMsg, msg)) - { - if (rpi->mLastMsg) - free(rpi->mLastMsg); - - rpi->mLastMsg = strdup(msg); - - if(rpi->mMsgLength) - while (--rpi->mMsgLength) - vgClearGlyph(rpi->mFont, rpi->mMsgLength); - - for (int i = 0; msg[i]; i++) - { - VGfloat origin[2], escapement[2]; - VGHandle handle; - - /* - * if a character appears more than once, it will be loaded and converted - * again... - */ - if (FT_Load_Char(rpi->ftFace, msg[i], FT_LOAD_DEFAULT)) - { - RARCH_WARN("failed to load glyph '%c'\n", msg[i]); - goto fail; - } - - escapement[0] = (VGfloat) rpi->ftFace->glyph->advance.x / 64.0f; - escapement[1] = (VGfloat) rpi->ftFace->glyph->advance.y / 64.0f; - - switch (rpi->ftFace->glyph->format) - { - case FT_GLYPH_FORMAT_OUTLINE: - handle = convert_outline_glyph(rpi); - origin[0] = 0.0f; - origin[1] = 0.0f; - glyph_string_add_path(rpi, (VGPath) handle, origin, escapement); - break; - case FT_GLYPH_FORMAT_BITMAP: - handle = convert_bitmap_glyph(rpi); - origin[0] = (VGfloat) (-rpi->ftFace->glyph->bitmap_left); - origin[1] = (VGfloat) (rpi->ftFace->glyph->bitmap.rows - rpi->ftFace->glyph->bitmap_top); - glyph_string_add_image(rpi, (VGImage) handle, origin, escapement); - break; - default: - break; - } - } - for (int i = 0; i < rpi->mMsgLength; i++) - rpi->mGlyphIndices[i] = i; - } - - fail: + rpi_render_message(rpi, msg); vgSeti(VG_SCISSORING, VG_FALSE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL); VGfloat origins[] = { rpi->mScreenWidth * g_settings.video.msg_pos_x - 2.0f, rpi->mScreenHeight * g_settings.video.msg_pos_y - 2.0f }; vgSetfv(VG_GLYPH_ORIGIN, 2, origins); @@ -523,6 +309,7 @@ static void rpi_draw_message(rpi_t *rpi, const char *msg) vgDrawGlyphs(rpi->mFont, rpi->mMsgLength, rpi->mGlyphIndices, NULL, NULL, VG_FILL_PATH, VG_TRUE); vgSeti(VG_SCISSORING, VG_TRUE); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); } #endif @@ -614,14 +401,14 @@ static bool rpi_frame(void *data, const void *frame, unsigned width, unsigned he static bool rpi_alive(void *data) { - (void)data; - return true; + (void)data; + return true; } static bool rpi_focus(void *data) { - (void)data; - return true; + (void)data; + return true; } static void rpi_set_rotation(void *data, unsigned rotation) @@ -631,13 +418,13 @@ static void rpi_set_rotation(void *data, unsigned rotation) } const video_driver_t video_rpi = { - rpi_init, - rpi_frame, - rpi_set_nonblock_state, - rpi_alive, - rpi_focus, - NULL, - rpi_free, - "rpi", - rpi_set_rotation, + rpi_init, + rpi_frame, + rpi_set_nonblock_state, + rpi_alive, + rpi_focus, + NULL, + rpi_free, + "rpi", + rpi_set_rotation, }; diff --git a/retroarch.c b/retroarch.c index b3cb31915c..2062d2803c 100644 --- a/retroarch.c +++ b/retroarch.c @@ -55,10 +55,6 @@ // We want to use -mconsole in Win32, so we need main(). #endif -#ifdef HAVE_RPI -#include -#endif - // To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. static void set_fast_forward_button(bool new_button_state, bool new_hold_button_state) { @@ -2628,9 +2624,6 @@ void rarch_main_deinit(void) // Consoles use the higher level API. int main(int argc, char *argv[]) { -#ifdef HAVE_RPI - bcm_host_init(); -#endif int init_ret; if ((init_ret = rarch_main_init(argc, argv))) return init_ret; rarch_init_msg_queue();