#include "text_renderer.h" #include #include #include "freetype/fttypes.h" #include "font_errors.h" #include "src/mesh_controller.h" #include "src/math.h" #include "src/vulkan_commons.h" #include "utilities/logger.h" #include "utilities/commons.h" #include "utilities/errors_common.h" #include "utilities/localization.h" #include "vulkan_image.h" #include "vulkan/vulkan_core.h" #include FT_FREETYPE_H /* Load only ASCII characters that are needed. TODO: Add unicode characters */ #define FONT_CHARACTERS_COUNT 94 #define FONT_START_CHARACTER 32U #define FONT_SIZE 200 /* Use this to scale font to 0.0 <-> 1.0 range */ #define FONT_SCALING 1.0f/FONT_SIZE struct font_data_t { uint16_t mesh_id; uint16_t texture_id; float width; float height; float bearing_x; float bearing_y; float advance; }; struct font_data_t g_fonts_data[FONT_CHARACTERS_COUNT]; FT_Library g_library; rse_err_t fonts_initialize() { FT_Error error; memset(g_fonts_data, 0, sizeof(g_fonts_data)); error = FT_Init_FreeType(&g_library); if (error) { LOGF(_("Font initialization failed\n")); return FONT_ERROR_INIT_FAILED; } return RSE_ERROR_NO_ERROR; } rse_err_t fonts_load_from_file(struct graphics_context_t* context, const char* file_path) { rse_err_t status = RSE_ERROR_NO_ERROR; FT_Error error; FT_Face face; size_t iter = 0U; struct vertex_t font_vertices[4]; uint16_t font_indices[] = {0, 1, 2, 2, 3, 0}; error = FT_New_Face(g_library, file_path, 0, &face); if (error) { LOGF(_("Failed to load new font\n")); return FONT_ERROR_LOAD_FAILED; } /* By default we set font size to FONT_SIZE.*/ error = FT_Set_Pixel_Sizes(face, 0, FONT_SIZE); if (error) { LOGF(_("Failed to change font size\n")); return FONT_ERROR_CHANGE_SIZE_FAILED; } /* Convert font face to textured image */ /* Loading only needed ascii characters, from 40 (space) to 126 (~) */ for (iter = 0U; iter < face->num_glyphs && iter < FONT_CHARACTERS_COUNT; ++iter) { error = FT_Load_Char(face, iter + FONT_START_CHARACTER, FT_LOAD_RENDER); if (error) { LOGF(_("Failed to load glyph into memeory\n")); return FONT_ERROR_LOAD_GLYPH_FAILED; } g_fonts_data[iter].width = face->glyph->bitmap.width; g_fonts_data[iter].height = face->glyph->bitmap.rows; g_fonts_data[iter].bearing_x = face->glyph->bitmap_left; g_fonts_data[iter].bearing_y = face->glyph->bitmap_top; g_fonts_data[iter].advance = (face->glyph->advance.x >> 6); /* Skip generating mesh if character is space */ if ((char)(iter + FONT_START_CHARACTER) == ' ') { continue; } font_vertices[0] = (struct vertex_t) { {g_fonts_data[iter].bearing_x, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f} }; font_vertices[1] = (struct vertex_t) { {g_fonts_data[iter].bearing_x + g_fonts_data[iter].width, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f} }; font_vertices[2] = (struct vertex_t) { {g_fonts_data[iter].bearing_x + g_fonts_data[iter].width, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f} }; font_vertices[3] = (struct vertex_t) { {g_fonts_data[iter].bearing_x, g_fonts_data[iter].height, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f} }; g_fonts_data[iter].mesh_id = create_mesh(context, font_vertices, font_indices, 8, 6); STATUS_CHECK(load_texture_from_bitmat(context, face->glyph->bitmap.buffer, face->glyph->bitmap.width, face->glyph->bitmap.rows, &g_fonts_data[iter].texture_id, VK_FORMAT_R8_SRGB)); } return status; } rse_err_t print_text(struct graphics_context_t* context, const char* text, struct vec3_t position, float font_size) { rse_err_t status = RSE_ERROR_NO_ERROR; size_t iter = 0U; size_t charactet_code = 0U; float advance = 0.0f; float x_pos = 0.0f; float y_pos = 0.0f; float scale = FONT_SCALING * font_size; for (iter = 0U; iter < strlen(text); ++iter) { if (text[iter] == ' ') { advance += g_fonts_data[charactet_code].advance * scale; continue; } charactet_code = (size_t)text[iter] - FONT_START_CHARACTER; x_pos = position.x + advance - (g_fonts_data[charactet_code].bearing_x * scale); y_pos = position.y - (g_fonts_data[charactet_code].bearing_y * scale); create_mesh_instance(context, g_fonts_data[charactet_code].mesh_id, (struct instance_data_t){ {x_pos, y_pos, 0.0f}, {0.0f, 0.0f, math_deg_to_radians(0.0f)}, FONT_SCALING * font_size, g_fonts_data[charactet_code].texture_id }); advance += g_fonts_data[charactet_code].advance * scale; } return status; }