Skip to content

Commit

Permalink
Text rendering (#17)
Browse files Browse the repository at this point in the history
* Implementing character string (Text) rendering (WIP)

* added text_shader.glsl

* Added space (' ') whitespace support.

* Added new font

* Deleted MeshLib

* Added MeshLib

* Deleted MeshLib

* Updated MeshLib, SafeMemory and BufferLib submodules

* Updated safe memory submodule
  • Loading branch information
ravi688 authored Dec 25, 2021
1 parent 1289f08 commit 02ee1d0
Show file tree
Hide file tree
Showing 16 changed files with 322 additions and 116 deletions.
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
[submodule "dependencies/SafeMemory"]
path = dependencies/SafeMemory
url = https://github.com/ravi688/SafeMemory.git
[submodule "dependencies/MeshLib"]
path = dependencies/MeshLib
url = https://github.com/ravi688/MeshLib.git
[submodule "dependencies/ttf2mesh"]
path = dependencies/ttf2mesh
url = https://github.com/ravi688/ttf2mesh.git
[submodule "dependencies/MeshLib"]
path = dependencies/MeshLib
url = https://github.com/ravi688/MeshLib.git
26 changes: 26 additions & 0 deletions include/renderer/font.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,30 @@

#include <ttf2mesh.h>

enum
{
FONT_GLYPH_MESH_QUALITY_LOW,
FONT_GLYPH_MESH_QUALITY_NORMAL,
FONT_GLYPH_MESH_QUALITY_HIGH
};

typedef struct font_t font_t;
typedef struct mesh3d_t mesh3d_t;

typedef struct font_glyph_info_t
{
u32 index;

float min_x;
float max_x;
float min_y;
float max_y;

float advance_width;

float left_side_bearing;
float right_side_bearing;
} font_glyph_info_t;

typedef struct font_t
{
Expand All @@ -19,3 +41,7 @@ font_t* font_create(void* bytes, u64 length);
font_t* font_load_and_create(const char* file_name);
void font_destroy(font_t* font);
void font_release_resources(font_t* font);

void font_get_glyph_mesh(font_t* font, u16 wide_char, u8 mesh_quality, mesh3d_t* out_mesh);
void font_get_glyph_info(font_t* font, u16 wide_char, font_glyph_info_t* out_info);
// void font_get_glyph_bitmap(font_t* font, void* out_bytes);
2 changes: 1 addition & 1 deletion include/renderer/internal/vulkan/vulkan_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ typedef struct vulkan_buffer_t
uint32_t count;
} vulkan_buffer_t;


void vulkan_buffer_init(vulkan_buffer_t* buffer);
vulkan_buffer_t* vulkan_buffer_new();
vulkan_buffer_t* vulkan_buffer_create(renderer_t* renderer, vulkan_buffer_create_info_t* create_info);
void vulkan_buffer_create_no_alloc(renderer_t* renderer, vulkan_buffer_create_info_t* create_info, vulkan_buffer_t* buffer);
Expand Down
8 changes: 5 additions & 3 deletions include/renderer/text_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

#include <renderer/font.h>
#include <renderer/mesh.h>
#include <buffer.h>

typedef struct renderer_t renderer_t;
typedef struct font_t font_t;
typedef struct mesh3d_t mesh3d_t;

typedef struct text_mesh_t
{
mesh3d_t* handle;
mesh_t* render_handle;
font_t* font;
BUFFER/*typeof(mesh3d_t*)*/ meshes;
BUFFER/*typeof(mesh_t*)*/ render_meshes;
BUFFER/*typeof(u32)*/ instance_counts;
} text_mesh_t;


Expand All @@ -21,6 +23,6 @@ void text_mesh_release_resources(text_mesh_t* text);

void text_mesh_draw(text_mesh_t* text, renderer_t* renderer);

void text_mesh_set_string(text_mesh_t* text, const char* string);
void text_mesh_set_string(text_mesh_t* text, renderer_t* renderer, const char* string);
void text_mesh_set_size(text_mesh_t* text, u32 size);

64 changes: 62 additions & 2 deletions source/renderer/font.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

#include <renderer/font.h>
#include <renderer/assert.h>
#include <renderer/mesh3d.h>
#include <memory_allocator/memory_allocator.h>
#include <disk_manager/file_reader.h>

#include <ttf2mesh.h>
#include <renderer/assert.h>


font_t* font_load_and_create(const char* file_name)
Expand Down Expand Up @@ -42,3 +42,63 @@ void font_release_resources(font_t* font)
heap_free(font);
}

void font_get_glyph_mesh(font_t* font, u16 wide_char, u8 mesh_quality, mesh3d_t* out_mesh)
{
assert(out_mesh != NULL);
mesh3d_positions_new(out_mesh, 0);
// mesh3d_colors_new(out_mesh, 0);
mesh3d_triangles_new(out_mesh, 0);
font_glyph_info_t info;
font_get_glyph_info(font, wide_char, &info);
ttf_mesh_t* mesh;
u8 quality;
switch(mesh_quality)
{
case FONT_GLYPH_MESH_QUALITY_LOW: quality = TTF_QUALITY_LOW; break;
case FONT_GLYPH_MESH_QUALITY_NORMAL: quality = TTF_QUALITY_NORMAL; break;
case FONT_GLYPH_MESH_QUALITY_HIGH: quality = TTF_QUALITY_HIGH; break;
default: LOG_FETAL_ERR("Invalid font mesh quality: %u\n", mesh_quality);
}
int result = ttf_glyph2mesh(&font->handle->glyphs[info.index], &mesh, quality, TTF_FEATURES_DFLT);
assert(result == TTF_DONE);

float max_y = 0, min_y = 0, max_x = 0, min_x = 0;
for(int i = 0; i < mesh->nvert; i++)
{
if(mesh->vert[i].y > max_y)
max_y = mesh->vert[i].y;
if(mesh->vert[i].y < min_y)
min_y = mesh->vert[i].y;

if(mesh->vert[i].x > max_x)
max_x = mesh->vert[i].x;
if(mesh->vert[i].x < min_x)
min_x = mesh->vert[i].x;

mesh3d_position_add(out_mesh, 0, mesh->vert[i].y, mesh->vert[i].x);
// mesh3d_color_add(out_mesh, 1, 1, 1);
}
for(int i = 0; i < mesh->nfaces; i++)
mesh3d_triangle_add(out_mesh, mesh->faces[i].v3, mesh->faces[i].v2, mesh->faces[i].v1);
mesh3d_optimize_buffer(out_mesh);
ttf_free_mesh(mesh);
}


void font_get_glyph_info(font_t* font, u16 wide_char, font_glyph_info_t* out_info)
{
int index = ttf_find_glyph(font->handle, wide_char);
if(index < 0)
{
LOG_FETAL_ERR("Font error: couldn't find glyph \"%c\"\n", wide_char);
}
ttf_glyph_t info = font->handle->glyphs[index];
out_info->left_side_bearing = info.lbearing;
out_info->right_side_bearing = info.rbearing;
out_info->advance_width = info.advance;
out_info->min_x = info.xbounds[0];
out_info->max_x = info.xbounds[1];
out_info->min_y = info.ybounds[0];
out_info->max_y = info.ybounds[1];
out_info->index = index;
}
103 changes: 92 additions & 11 deletions source/renderer/text_mesh.c
Original file line number Diff line number Diff line change
@@ -1,52 +1,133 @@


#include <renderer/text_mesh.h>
#include <renderer/assert.h>
#include <renderer/mesh.h>
#include <renderer/internal/vulkan/vulkan_mesh.h>
#include <renderer/mesh3d.h>
#include <renderer/font.h>
#include <memory_allocator/memory_allocator.h>
#include <renderer/assert.h>
#include <ctype.h>

static void build_meshes(BUFFER* meshes, font_t* font);

text_mesh_t* text_mesh_create(font_t* font)
{
assert(font != NULL);
text_mesh_t* text_mesh = heap_new(text_mesh_t);
memset(text_mesh, 0, sizeof(text_mesh_t));
text_mesh->handle = mesh3d_new();
text_mesh->font = font;
return text_mesh;
text_mesh_t* text = heap_new(text_mesh_t);
memset(text, 0, sizeof(text_mesh_t));
text->meshes = buf_create(sizeof(mesh3d_t*), 0, 0);
text->render_meshes = buf_create(sizeof(mesh_t*), 0, 0);
text->instance_counts = buf_create(sizeof(u32), 0, 0);
text->font = font;
build_meshes(&text->meshes, font);
return text;
}

void text_mesh_destroy(text_mesh_t* text, renderer_t* renderer)
{
assert(text != NULL);
mesh_destroy(text->render_handle, renderer);
mesh3d_destroy(text->handle);
for(u32 i = 0; i < text->meshes.element_count; i++)
mesh3d_destroy(*(mesh3d_t**)buf_get_ptr_at(&text->meshes, i));
for(u32 i = 0; i < text->render_meshes.element_count; i++)
mesh_destroy(*(mesh_t**)buf_get_ptr_at(&text->render_meshes, i), renderer);
}

void text_mesh_release_resources(text_mesh_t* text)
{
assert(text != NULL);
mesh_release_resources(text->render_handle);
for(u32 i = 0; i < text->render_meshes.element_count; i++)
mesh_release_resources(*(mesh_t**)buf_get_ptr_at(&text->render_meshes, i));
buf_free(&text->render_meshes);
buf_free(&text->meshes);
heap_free(text);
}


void text_mesh_draw(text_mesh_t* text, renderer_t* renderer)
{
assert(text != NULL);
mesh_draw_indexed(text->render_handle, renderer);
for(u32 i = 0; i < text->render_meshes.element_count; i++)
mesh_draw_indexed_instanced(*(mesh_t**)buf_get_ptr_at(&text->render_meshes, i), renderer, *(u32*)buf_get_ptr_at(&text->instance_counts, i));
}


void text_mesh_set_string(text_mesh_t* text, const char* string)
void text_mesh_set_string(text_mesh_t* text, renderer_t* renderer, const char* string)
{
assert(text != NULL);

//maximum number of characters in the character set
u8 unique_char_count = 126 - 33 + 1;

//create a count_mask,
u32 count_mask[unique_char_count];
memset(count_mask, 0UL, sizeof(u32) * unique_char_count);

//create instance buffers for each possible character in the character set
BUFFER instance_buffers[unique_char_count];
for(u8 i = 0; i < unique_char_count; i++)
instance_buffers[i] = buf_create(sizeof(vec3_t(float)), 0, 0);

float horizontal_pen = 0;
while(*string != 0)
{
char ch = *string;
assert((ch >= 32) && (ch <= 126));
font_glyph_info_t info;
font_get_glyph_info(text->font, ch, &info);

vec3_t(float) v = { 0, 0, horizontal_pen };
horizontal_pen += info.advance_width;

if(ch != 32)
{
BUFFER* buffer = &instance_buffers[ch - 33];
count_mask[ch - 33]++;
buf_push(buffer, &v);
}
string++;
}

for(u8 i = 0; i < unique_char_count; i++)
{
if(count_mask[i] == 0UL) continue;
mesh_t* mesh = mesh_create(renderer, *(mesh3d_t**)buf_get_ptr_at(&text->meshes, i));
vulkan_vertex_buffer_create_info_t create_info =
{
.data = instance_buffers[i].bytes,
.stride = sizeof(vec3_t(float)),
.count = instance_buffers[i].element_count
};
vulkan_mesh_create_and_add_vertex_buffer(mesh, renderer, &create_info);
buf_free(&instance_buffers[i]);
buf_push(&text->render_meshes, &mesh);
}

for(u8 i = 0; i < unique_char_count; i++)
if(count_mask[i] != 0UL)
buf_push(&text->instance_counts, &count_mask[i]);
}

void text_mesh_set_size(text_mesh_t* text, const u32 size)
{
assert(text != NULL);

}


static void build_meshes(BUFFER* meshes, font_t* font)
{
/*NOTE: 32 is space, not printable character*/
u16 A = 33;
buf_clear(meshes, NULL);
while(A <= 126)
{
font_glyph_info_t info;
font_get_glyph_info(font, A, &info);
mesh3d_t* mesh = mesh3d_new();
font_get_glyph_mesh(font, A, FONT_GLYPH_MESH_QUALITY_LOW, mesh);
buf_push(meshes, &mesh);
A++;
}
}

8 changes: 6 additions & 2 deletions source/renderer/vulkan/vulkan_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@
#include <memory_allocator/memory_allocator.h>
#include <renderer/assert.h>

void vulkan_buffer_init(vulkan_buffer_t* buffer)
{
memset(buffer, 0, sizeof(vulkan_buffer_t));
}

vulkan_buffer_t* vulkan_buffer_new()
{
vulkan_buffer_t* buffer = heap_new(vulkan_buffer_t);
memset(buffer, 0, sizeof(vulkan_buffer_t));
vulkan_buffer_init(buffer);
return buffer;
}


vulkan_buffer_t* vulkan_buffer_create(renderer_t* renderer, vulkan_buffer_create_info_t* create_info)
{

vulkan_buffer_t* buffer = vulkan_buffer_new();
vulkan_buffer_create_no_alloc(renderer, create_info, buffer);
return buffer;
Expand Down
Loading

0 comments on commit 02ee1d0

Please sign in to comment.