[WIP] Add text rendering
This commit is contained in:
1 parent
3bd14b20c2
commit
b2508ce4ff
15 files changed
+248
-27
No files matched your search
@@ -0,0 +1,11 @@
|
||||
|
||||
set(FREE_TYPE_DIR "${PROJECT_SOURCE_DIR}/third_party/freetype/")
|
||||
|
||||
find_library(
|
||||
freetype
|
||||
NAMES freetype
|
||||
HINTS ${FREE_TYPE_DIR}/build/
|
||||
)
|
||||
|
||||
|
||||
set(FreeType_INCLUDE_DIR "${FREE_TYPE_DIR}/include/")
|
||||
@@ -19,3 +19,7 @@ custom_commands = cd Criterion && meson build && cd build && ninja
|
||||
[stb]
|
||||
git_url = https://github.com/nothings/stb.git
|
||||
tag = master
|
||||
|
||||
[FreeType]
|
||||
dl_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.10.0.tar.gz
|
||||
custom_commands = tar -xf freetype-2.10.0.tar.gz mv freetype-2.10.0 freetype && rm freetype-2.10.0.tar.gz && cmake -E make_directory build && cmake -E chdir build cmake -D BUILD_SHARED_LIBS:BOOL=true .. && cmake --build build
|
||||
@@ -2,6 +2,7 @@ find_package(Vulkan REQUIRED)
|
||||
find_package(vma REQUIRED)
|
||||
find_package(glfw3 REQUIRED)
|
||||
find_package(stb REQUIRED)
|
||||
find_package(FreeType REQUIRED)
|
||||
|
||||
find_package(Vulkan COMPONENTS glslc)
|
||||
find_program(glslc_executable NAMES glslc HINTS ${Vulkan_GLSLC_EXECUTABLE}/..)
|
||||
@@ -42,6 +43,7 @@ ${CMAKE_SOURCE_DIR}
|
||||
${vma_INCLUDE_DIR}
|
||||
${glfw3_INCLUDE_DIR}
|
||||
${stb_INCLUDE_DIR}
|
||||
${FreeType_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_sources(rse_graphics PRIVATE
|
||||
@@ -57,10 +59,12 @@ src/rse_math.c
|
||||
src/mesh_controller.c
|
||||
src/vulkan_commons.c
|
||||
src/rse_vulkan_image.c
|
||||
src/rse_text_renderer.c
|
||||
)
|
||||
|
||||
target_link_libraries(rse_graphics PRIVATE
|
||||
rse_utilities
|
||||
${Vulkan_LIBRARIES}
|
||||
${glfw}
|
||||
${freetype}
|
||||
)
|
||||
@@ -14,4 +14,4 @@ layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor * texture(texSampler[instanceTextureId], fragTexCoord).rgb, 1.0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,46 @@
|
||||
|
||||
/**
|
||||
* @file locale_fonts.h
|
||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||
* @brief Error messages for font handlers
|
||||
* @version 0.1
|
||||
* @date 2022-05-13
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RSE_LOCALE_FONTS_H
|
||||
#define RSE_LOCALE_FONTS_H
|
||||
|
||||
#include "utilities/localization.h"
|
||||
|
||||
#define font_messages font_messages_nolocale[SELECTED_LANGUAGE]
|
||||
|
||||
enum font_messages_t {
|
||||
FONT_INITIALIZATION_FAILED,
|
||||
FONT_LOAD_FONT_FAILED,
|
||||
FONT_CHANGE_SIZE_FAILED,
|
||||
FONT_LOAD_GLYPH_FAILED,
|
||||
FONT_RENDER_GLYPH_FAILED,
|
||||
FONT_LAST_MESSAGE
|
||||
};
|
||||
|
||||
|
||||
static const char font_messages_nolocale[LAST_LANGUAGE][FONT_LAST_MESSAGE][MAX_MESSAGE_LENGHT] = {
|
||||
{/* EN_US */
|
||||
/* FONT_INITIALIZATION_FAILED */
|
||||
"Font initialization failed\n",
|
||||
/* FONT_LOAD_FONT_FAILED */
|
||||
"Failed to load new font\n",
|
||||
/* FONT_CHANGE_SIZE_FAILED */
|
||||
"Failed to change font size\n",
|
||||
/* FONT_LOAD_GLYPH_FAILED */
|
||||
"Failed to load glyph into memeory\n",
|
||||
/* FONT_RENDER_GLYPH_FAILED */
|
||||
"Failed to render glypth into bitmap\n"
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RSE_LOCALE_FONTS_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file localeVulkan.h
|
||||
* @file locale_vulkan.h
|
||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||
* @brief Error messages for Vulkan initializers
|
||||
* @version 0.1
|
||||
@@ -136,4 +136,4 @@ static const char vulkan_messages_nolocale[LAST_LANGUAGE][VULKAN_LAST_MESSAGE][M
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* RSE_LOCALE_VULKAN_H */
|
||||
#endif /* RSE_LOCALE_VULKAN_H */
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file rse_font_errors.h
|
||||
* @author Piotr Krygier (everyonecancode@gmail.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-10-06
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RSE_FONT_ERRORS_H
|
||||
#define RSE_FONT_ERRORS_H
|
||||
|
||||
#define RSE_FONT_MODULE_ID 0x0400U
|
||||
|
||||
/* Error codes */
|
||||
enum rse_window_error_t {
|
||||
FONT_ERROR_INIT_FAILED = RSE_FONT_MODULE_ID,
|
||||
FONT_ERROR_LOAD_FAILED,
|
||||
FONT_ERROR_CHANGE_SIZE_FAILED,
|
||||
FONT_ERROR_LOAD_GLYPH_FAILED,
|
||||
FONT_ERROR_RENDER_GLYPH_FAILED
|
||||
};
|
||||
|
||||
#endif /* RSE_WINDOW_ERRORS_H */
|
||||
+16
-11
@@ -1,4 +1,5 @@
|
||||
#include "rse_graphics.h"
|
||||
#include "src/rse_text_renderer.h"
|
||||
#include "window.h"
|
||||
#include "vulkan_base.h"
|
||||
|
||||
@@ -8,11 +9,13 @@
|
||||
#include "utilities/logger.h"
|
||||
#include "utilities/rse_commons.h"
|
||||
#include "utilities/rse_errors_common.h"
|
||||
#include "rse_font_errors.h"
|
||||
|
||||
#include "rse_math.h"
|
||||
|
||||
extern struct rse_vulkan_state_t g_vulkan_state;
|
||||
|
||||
|
||||
rse_err_t rse_graphics_init(void)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
@@ -36,21 +39,23 @@ void rse_graphics_test_function(void)
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
uint16_t tex_id_2 = 0;
|
||||
|
||||
status = rse_load_texture("../../test_image.jpg", &tex_id_2);
|
||||
status = rse_load_texture_from_file("../../test_image.jpg", &tex_id_2);
|
||||
if (status != RSE_ERROR_NO_ERROR) {
|
||||
LOGE("Failed to do something. Check error messages");
|
||||
LOGE("Failed to do something. Check error messages. Error: %d", status);
|
||||
return;
|
||||
}
|
||||
(rse_fonts_initialize());
|
||||
(rse_fonts_load_from_file("/usr/share/fonts/JetBrainsMonoNerdFont/JetBrainsMonoNerdFont-Medium.ttf"));
|
||||
|
||||
// FIXME: Temporary array of vertices, for testing purposes
|
||||
struct rse_vertex_t vertices[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
struct rse_vertex_t vertices[] = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
|
||||
|
||||
struct rse_vertex_t vertices2[] = {{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
struct rse_vertex_t vertices2[] = {{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}};
|
||||
|
||||
// FIXME: Temporary array of vertices, for testing purposes
|
||||
@@ -61,14 +66,14 @@ void rse_graphics_test_function(void)
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
{0.0f, 0.0f, rse_math_deg_to_radians(45.0f)},
|
||||
1.0f,
|
||||
tex_id_2
|
||||
4
|
||||
});
|
||||
|
||||
create_mesh_instance(mesh_id, (struct rse_instance_data_t){
|
||||
{-1.0f, 0.0f, 0.3f},
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
1.0f,
|
||||
tex_id_2
|
||||
49
|
||||
});
|
||||
|
||||
mesh_id = create_mesh(vertices2, indices, 8, 6);
|
||||
@@ -76,7 +81,7 @@ void rse_graphics_test_function(void)
|
||||
{0.0f, 1.0f, 0.0f},
|
||||
{0.0f, 0.0f, rse_math_deg_to_radians(0.0f)},
|
||||
1.0f,
|
||||
tex_id_2
|
||||
33
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "rse_text_renderer.h"
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "freetype/fttypes.h"
|
||||
#include "locale_fonts.h"
|
||||
#include "rse_font_errors.h"
|
||||
#include "utilities/logger.h"
|
||||
#include "utilities/rse_commons.h"
|
||||
#include "utilities/rse_errors_common.h"
|
||||
#include "rse_vulkan_image.h"
|
||||
|
||||
#include "ft2build.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#define FONT_CHARACTERS_COUNT 126
|
||||
|
||||
uint16_t g_font_textures[FONT_CHARACTERS_COUNT];
|
||||
|
||||
FT_Library g_library;
|
||||
rse_err_t rse_fonts_initialize()
|
||||
{
|
||||
FT_Error error;
|
||||
|
||||
error = FT_Init_FreeType(&g_library);
|
||||
|
||||
if (error) {
|
||||
LOGF(font_messages[FONT_INITIALIZATION_FAILED]);
|
||||
return FONT_ERROR_INIT_FAILED;
|
||||
}
|
||||
return RSE_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
rse_err_t rse_fonts_load_from_file(const char* file_path)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
FT_Error error;
|
||||
FT_Face face;
|
||||
size_t iter = 0U;
|
||||
|
||||
error = FT_New_Face(g_library, file_path, 0, &face);
|
||||
|
||||
if (error) {
|
||||
LOGF(font_messages[FONT_LOAD_FONT_FAILED]);
|
||||
return FONT_ERROR_LOAD_FAILED;
|
||||
}
|
||||
|
||||
/* By default we set font size to 16px. TODO: change later? */
|
||||
error = FT_Set_Pixel_Sizes(face, 0, 48);
|
||||
|
||||
if (error) {
|
||||
LOGF(font_messages[FONT_CHANGE_SIZE_FAILED]);
|
||||
return FONT_ERROR_CHANGE_SIZE_FAILED;
|
||||
}
|
||||
|
||||
/* Convert font face to textured image */
|
||||
/* Loading only needed ascii characters, from 40 (space) to 126 (~) */
|
||||
for (iter = 33U; iter < face->num_glyphs && iter < 127U; ++iter) {
|
||||
error = FT_Load_Char(face, iter, FT_LOAD_RENDER);
|
||||
|
||||
if (error) {
|
||||
LOGF(font_messages[FONT_LOAD_GLYPH_FAILED]);
|
||||
return FONT_ERROR_LOAD_GLYPH_FAILED;
|
||||
}
|
||||
|
||||
STATUS_CHECK(rse_load_texture_from_bitmat(face->glyph->bitmap.buffer,
|
||||
face->glyph->bitmap.width,
|
||||
face->glyph->bitmap.rows,
|
||||
&g_font_textures[iter], VK_FORMAT_R8_UNORM));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
rse_err_t rse_print_text(const char* text)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
/**
|
||||
* @file rse_text_renderer.h
|
||||
* @author Piotr Krygier (piotr.krygier@meshsystems.com)
|
||||
* @brief Load and render text on screen or in space
|
||||
* @version 0.1
|
||||
* @date 2024-02-02
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RSE_TEXT_RENDERER_H
|
||||
#define RSE_TEXT_RENDERER_H
|
||||
|
||||
#include "utilities/rse_commons.h"
|
||||
|
||||
rse_err_t rse_fonts_initialize(void);
|
||||
rse_err_t rse_fonts_load_from_file(const char* file_path);
|
||||
|
||||
#endif // !RSE_TEXT_RENDERER_H_
|
||||
@@ -242,6 +242,10 @@ static rse_err_t format_to_pixel_size(VkFormat format,
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
*format_size = 1;
|
||||
break;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
*format_size = 4;
|
||||
break;
|
||||
@@ -258,7 +262,7 @@ static rse_err_t format_to_pixel_size(VkFormat format,
|
||||
static rse_err_t create_textured_image(uint32_t width,
|
||||
uint32_t height,
|
||||
VkFormat format,
|
||||
unsigned char* pixels,
|
||||
const unsigned char* pixels,
|
||||
uint16_t* texture_id)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
@@ -403,7 +407,20 @@ rse_err_t init_vulkan_images()
|
||||
return status;
|
||||
}
|
||||
|
||||
rse_err_t rse_load_texture(const char* file_path, uint16_t* texture_id)
|
||||
rse_err_t rse_load_texture_from_bitmat(const unsigned char* pixel_buffer, int width, int height, uint16_t* texture_id, VkFormat color_format)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
|
||||
/* Create actual Vulkan Image */
|
||||
STATUS_CHECK(create_textured_image(width,
|
||||
height,
|
||||
color_format,
|
||||
pixel_buffer, texture_id));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
rse_err_t rse_load_texture_from_file(const char* file_path, uint16_t* texture_id)
|
||||
{
|
||||
rse_err_t status = RSE_ERROR_NO_ERROR;
|
||||
int width = 0;
|
||||
@@ -418,16 +435,11 @@ rse_err_t rse_load_texture(const char* file_path, uint16_t* texture_id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create actual Vulkan Image */
|
||||
status = create_textured_image(width,
|
||||
height,
|
||||
VK_FORMAT_R8G8B8A8_SRGB,
|
||||
pixel_buffer, texture_id);
|
||||
STATUS_CHECK(rse_load_texture_from_bitmat(pixel_buffer, width, height, texture_id, VK_FORMAT_R8G8B8A8_SRGB));
|
||||
|
||||
stbi_image_free(pixel_buffer);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
void rse_destroy_textures()
|
||||
|
||||
@@ -34,13 +34,22 @@
|
||||
rse_err_t init_vulkan_images(void);
|
||||
|
||||
/**
|
||||
* @brief Loads image from file, for later to be uysed as a texture
|
||||
* @brief Loads image from file, for later to be used as a texture
|
||||
*
|
||||
* @param file_path Path to texture file
|
||||
* @param texture_id Texture ID will be set up here
|
||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||
*/
|
||||
rse_err_t rse_load_texture(const char* file_path, uint16_t* texture_id);
|
||||
rse_err_t rse_load_texture_from_bitmat(const unsigned char* pixel_buffer, int width, int height, uint16_t* texture_id, VkFormat color_format);
|
||||
|
||||
/**
|
||||
* @brief Loads image from file, for later to be used as a texture
|
||||
*
|
||||
* @param file_path Path to texture file
|
||||
* @param texture_id Texture ID will be set up here
|
||||
* @return rse_err_t RSE_ERROR_NO_ERROR on success
|
||||
*/
|
||||
rse_err_t rse_load_texture_from_file(const char* file_path, uint16_t* texture_id);
|
||||
|
||||
/**
|
||||
* @brief Destroy all loaded textures. Usefull for closing application or just clearing.
|
||||
|
||||
@@ -16,9 +16,9 @@ void rse_read_file(const char* file_name, long* bytes_count, char* buffer)
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fread(buffer, *bytes_count, 1, file)) {
|
||||
perror("Empty file read");
|
||||
fread(buffer, *bytes_count, 1, file);
|
||||
if (ferror(file) != 0) {
|
||||
perror("Error reading file");
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
Reference in new issue
Block a user