Skip to content

Commit

Permalink
Added SHADER_LIBRARY_SHADER_PRESET_BITMAP_TEXT
Browse files Browse the repository at this point in the history
However, the bitmap text rendering is hard coded for now.
We would need to add more support the V3D shader language to make bitmap font rendering customizable.
Also, we're currently not using the screen projection matrix so the bitmap text might not scale correctly.
  • Loading branch information
ravi688 committed Jul 19, 2023
1 parent da67534 commit ad5d586
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 28 deletions.
15 changes: 15 additions & 0 deletions include/renderer/font.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ typedef struct font_glyph_info_t
* it can be calculated as: advance_width - left_side_bearing - width */
f32 right_side_bearing;

f32 bitmap_top;
f32 bitmap_left;

/* true if this glyph has a grpahical representation, otherwise false */
bool is_graph;
} font_glyph_info_t;
Expand Down Expand Up @@ -145,4 +148,16 @@ RENDERER_API void font_get_glyph_info(font_t* font, utf32_t unicode, font_glyph_
/* fills 'info' with information of the glyph only but calls font_load_glyph internally if required (be careful) */
RENDERER_API void font_get_glyph_info2(font_t* font, utf32_t unicode, font_glyph_info_t OUT info);

static INLINE_IF_RELEASE_MODE f32 get_inches_from_point_size(u32 point_size)
{
/* 72 points make 1 inch */
return point_size * 1.0 / 72;
}

static INLINE_IF_RELEASE_MODE u32 get_pixels_from_point_size(u32 point_size, u32 dpi)
{
/* convert inches to pixels by multiplying with 'dots per inch' */
return CAST_TO(u32, (get_inches_from_point_size(point_size) * dpi));
}

END_CPP_COMPATIBLE
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ typedef struct vulkan_bitmap_glyph_atlas_texture_create_info_t
font_t* font;
} vulkan_bitmap_glyph_atlas_texture_create_info_t;

typedef struct event_t event_t;

typedef struct vulkan_bitmap_glyph_atlas_texture_t
{
/* holds the actual host side pixel buffer and device side pixel buffer (VkImage) */
DERIVE_FROM(vulkan_host_buffered_texture_t);
vulkan_renderer_t* renderer;
/* facilitates pooling of rasterized glyphs, works on the host side pixel buffer */
bitmap_glyph_pool_t pool;
event_t* on_resize_event;
} vulkan_bitmap_glyph_atlas_texture_t;

#define VULKAN_BITMAP_GLYPH_ATLAS_TEXTURE(ptr) DYNAMIC_CAST(vulkan_bitmap_glyph_atlas_texture_t*, ptr)
Expand All @@ -35,6 +38,15 @@ RENDERER_API void vulkan_bitmap_glyph_atlas_texture_create_no_alloc(vulkan_rende
RENDERER_API void vulkan_bitmap_glyph_atlas_texture_destroy(vulkan_bitmap_glyph_atlas_texture_t* texture);
RENDERER_API void vulkan_bitmap_glyph_atlas_texture_release_resources(vulkan_bitmap_glyph_atlas_texture_t* texture);


static INLINE_IF_RELEASE_MODE event_t* vulkan_bitmap_glyph_atlas_texture_get_on_resize_event(vulkan_bitmap_glyph_atlas_texture_t* texture)
{
return texture->on_resize_event;
}
static INLINE_IF_RELEASE_MODE iextent2d_t vulkan_bitmap_glyph_atlas_texture_get_size(vulkan_bitmap_glyph_atlas_texture_t* texture)
{
return buffer2d_view_get_size(vulkan_host_buffered_texture_get_view(BASE(texture)));
}
/* returns pointer to the bitmap_glyph_pool_t object */
static INLINE_IF_RELEASE_MODE bitmap_glyph_pool_t* vulkan_bitmap_glyph_atlas_texture_get_pool(vulkan_bitmap_glyph_atlas_texture_t* texture)
{
Expand Down
5 changes: 5 additions & 0 deletions include/renderer/internal/vulkan/vulkan_bitmap_text.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <renderer/internal/vulkan/vulkan_instance_buffer.h>
#include <renderer/internal/vulkan/vulkan_mesh.h>
#include <renderer/dictionary.h>
#include <renderer/event.h> // event_subscription_handle_t
#include <renderer/rect.h> // rect2d_t
#include <hpml/mat4.h> // mat4_t
#include <hpml/vec3.h> // vec3_t
Expand Down Expand Up @@ -128,8 +129,12 @@ typedef struct vulkan_bitmap_text_t
/* instances of this quad will be drawn to lay out the glyph bitmaps */
vulkan_mesh_t quad_mesh;

event_subscription_handle_t bga_texture_update_handle;

} vulkan_bitmap_text_t;

#define VULKAN_BITMAP_TEXT(ptr) CAST_TO(vulkan_bitmap_text_t*, ptr)


BEGIN_CPP_COMPATIBLE

Expand Down
21 changes: 21 additions & 0 deletions include/renderer/internal/vulkan/vulkan_material.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,24 @@ RENDERER_API void vulkan_material_set_uintH(vulkan_material_t* material, vulkan_
RENDERER_API void vulkan_material_set_vec2H(vulkan_material_t* material, vulkan_material_field_handle_t handle, vec2_t v);
RENDERER_API void vulkan_material_set_vec3H(vulkan_material_t* material, vulkan_material_field_handle_t handle, vec3_t v);
RENDERER_API void vulkan_material_set_vec4H(vulkan_material_t* material, vulkan_material_field_handle_t handle, vec4_t v);
typedef union uvec2_t
{
struct { u32 x, y; };
struct { u32 width, height; };
} uvec2_t;
RENDERER_API void vulkan_material_set_uvec2H(vulkan_material_t* material, vulkan_material_field_handle_t handle, uvec2_t value);
typedef union uvec3_t
{
struct { u32 x, y, z; };
struct { u32 width, height, depth; };
} uvec3_t;
RENDERER_API void vulkan_material_set_uvec3H(vulkan_material_t* material, vulkan_material_field_handle_t handle, uvec3_t value);
typedef union uvec4_t
{
struct { u32 x, y, z, w; };
struct { u32 width, height, depth, time; };
} uvec4_t;
RENDERER_API void vulkan_material_set_uvec4H(vulkan_material_t* material, vulkan_material_field_handle_t handle, uvec4_t value);
RENDERER_API void vulkan_material_set_mat2H(vulkan_material_t* material, vulkan_material_field_handle_t handle, mat2_t m);
RENDERER_API void vulkan_material_set_mat4H(vulkan_material_t* material, vulkan_material_field_handle_t handle, mat4_t m);
RENDERER_API void vulkan_material_set_textureH(vulkan_material_t* material, vulkan_material_field_handle_t handle, vulkan_texture_t* texture);
Expand All @@ -161,6 +179,9 @@ RENDERER_API void vulkan_material_set_uint(vulkan_material_t* material, const ch
RENDERER_API void vulkan_material_set_vec2(vulkan_material_t* material, const char* name, vec2_t v);
RENDERER_API void vulkan_material_set_vec3(vulkan_material_t* material, const char* name, vec3_t v);
RENDERER_API void vulkan_material_set_vec4(vulkan_material_t* material, const char* name, vec4_t v);
RENDERER_API void vulkan_material_set_uvec2(vulkan_material_t* material, const char* name, uvec2_t v);
RENDERER_API void vulkan_material_set_uvec3(vulkan_material_t* material, const char* name, uvec3_t v);
RENDERER_API void vulkan_material_set_uvec4(vulkan_material_t* material, const char* name, uvec4_t v);
RENDERER_API void vulkan_material_set_mat2(vulkan_material_t* material, const char* name, mat2_t m);
RENDERER_API void vulkan_material_set_mat4(vulkan_material_t* material, const char* name, mat4_t m);
RENDERER_API void vulkan_material_set_texture(vulkan_material_t* material, const char* name, vulkan_texture_t* texture);
Expand Down
17 changes: 8 additions & 9 deletions shaders/presets/bitmap_text/bitmap_text.vert
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ struct Color

layout(std430, set = MATERIAL_SET, binding = MATERIAL_PROPERTIES_BINDING) uniform Parameters
{
int isScreenSpace;
uvec2 win_size;
uvec2 tex_size;
Color color;
} parameters;

Expand Down Expand Up @@ -69,15 +70,13 @@ void main()

GlyphTexCoord texcoord = gtc_buffer[indx];

float dpi = 141.0;
float dpi_inv = 1 / dpi;
vec2 tex_size = vec2(512, 512);
vec2 win_size = vec2(800, 800);
vec2 tex_size = parameters.tex_size;
vec2 win_size = parameters.win_size;
vec2 glyph_size = vec2(texcoord.trtc.x - texcoord.tltc.x, texcoord.bltc.y - texcoord.tltc.y) * tex_size;

float _scale_x = (texcoord.trtc.x - texcoord.tltc.x) * tex_size.x * dpi_inv * (1.0 / (win_size.x * dpi_inv));
float _scale_y = (texcoord.bltc.y - texcoord.tltc.y) * tex_size.y * dpi_inv * (1.0 / (win_size.y * dpi_inv));
float _space = ofst.x * 0.1f;
gl_Position = vec4(position.x * _scale_x + _space - 0.1 * 8, -position.y * _scale_y, 0, 1.0);
float _scale_x = glyph_size.x / win_size.x;
float _scale_y = glyph_size.y / win_size.y;
gl_Position = vec4(position.x * _scale_x + ofst.x / win_size.x, -(position.y * _scale_y + ofst.y / win_size.y), 0, 1.0);

if(gl_VertexIndex == 0)
out_texcoord = texcoord.tltc;
Expand Down
14 changes: 8 additions & 6 deletions source/renderer/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ RENDERER_API void font_release_resources(font_t* font)
RENDERER_API void font_set_char_size(font_t* font, u32 point_size)
{
if(font->ft_handle != NULL)
if(FT_Set_Char_Size(font->ft_handle, 0, point_size * 64, font->dpi.x, font->dpi.y) != 0)
if(FT_Set_Char_Size(font->ft_handle, 0, get_pixels_from_point_size(point_size, font->dpi.y) << 6, font->dpi.x, font->dpi.y) != 0)
debug_log_fetal_error("Failed to set char size");
font->point_size = point_size;
}
Expand All @@ -152,12 +152,14 @@ RENDERER_API bool font_load_glyph(font_t* font, utf32_t unicode, font_glyph_info

/* fill up the glyph information */
info.index = glyph_slot->glyph_index;
info.advance_width = CAST_TO(f32, glyph_slot->advance.x);
info.advance_width = CAST_TO(f32, glyph_slot->advance.x >> 6);
_debug_assert__(glyph_slot->advance.x == glyph_slot->metrics.horiAdvance);
info.width = CAST_TO(f32, glyph_slot->metrics.width);
info.height = CAST_TO(f32, glyph_slot->metrics.height);
info.bearing_x = CAST_TO(f32, glyph_slot->metrics.horiBearingX);
info.bearing_y = CAST_TO(f32, glyph_slot->metrics.horiBearingY);
info.width = CAST_TO(f32, glyph_slot->metrics.width >> 6);
info.height = CAST_TO(f32, glyph_slot->metrics.height >> 6);
info.bearing_x = CAST_TO(f32, glyph_slot->metrics.horiBearingX >> 6);
info.bearing_y = CAST_TO(f32, glyph_slot->metrics.horiBearingY >> 6);
info.bitmap_top = CAST_TO(f32, glyph_slot->bitmap_top >> 6);
info.bitmap_left = CAST_TO(f32, glyph_slot->bitmap_left >> 6);
info.right_side_bearing = info.advance_width - (info.left_side_bearing + info.width);
info.min_x = info.bearing_x;
info.min_y = info.bearing_y - info.height;
Expand Down
3 changes: 2 additions & 1 deletion source/renderer/shader_library.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ static vulkan_shader_resource_description_t* create_material_set_binding(vulkan_
struct_descriptor_add_field(Color, "b", GLSL_TYPE_FLOAT);
struct_descriptor_end(renderer->allocator, Color);
parameters = begin_uniform(renderer, &bindings, "parameters", VULKAN_DESCRIPTOR_SET_MATERIAL, VULKAN_DESCRIPTOR_BINDING_MATERIAL_PROPERTIES);
struct_descriptor_add_field(parameters, "isScreenSpace", GLSL_TYPE_UINT);
struct_descriptor_add_field(parameters, "win_size", GLSL_TYPE_UVEC2);
struct_descriptor_add_field(parameters, "tex_size", GLSL_TYPE_UVEC2);
struct_descriptor_add_field2(parameters, "color", Color);
end_uniform(renderer, &bindings);
}
Expand Down
14 changes: 13 additions & 1 deletion source/renderer/vulkan/vulkan_bitmap_glyph_atlas_texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,32 @@ RENDERER_API void vulkan_bitmap_glyph_atlas_texture_create_no_alloc(vulkan_rende
.view = vulkan_host_buffered_texture_get_view(BASE(texture))
};
bitmap_glyph_pool_create_no_alloc(RENDERER(renderer), &bgp_create_info, &texture->pool);

texture->on_resize_event = event_create(renderer->allocator, texture);
}

RENDERER_API void vulkan_bitmap_glyph_atlas_texture_destroy(vulkan_bitmap_glyph_atlas_texture_t* texture)
{
vulkan_host_buffered_texture_destroy(BASE(texture));
bitmap_glyph_pool_destroy(&texture->pool);
event_destroy(texture->on_resize_event);
}

RENDERER_API void vulkan_bitmap_glyph_atlas_texture_release_resources(vulkan_bitmap_glyph_atlas_texture_t* texture)
{
event_destroy(texture->on_resize_event);
memory_allocator_dealloc(texture->renderer->allocator, texture);
}

RENDERER_API bool vulkan_bitmap_glyph_atlas_texture_commit(vulkan_bitmap_glyph_atlas_texture_t* texture, bool OUT is_resized)
{
return vulkan_host_buffered_texture_commit(BASE(texture), is_resized);
bool _is_resized = false;
bool result = vulkan_host_buffered_texture_commit(BASE(texture), &_is_resized);
if(_is_resized)
{
event_publish(texture->on_resize_event);
if(is_resized != NULL)
OUT is_resized = _is_resized;
}
return result;
}
87 changes: 85 additions & 2 deletions source/renderer/vulkan/vulkan_bitmap_text.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <renderer/internal/vulkan/vulkan_renderer.h>
#include <renderer/internal/vulkan/vulkan_bitmap_glyph_atlas_texture.h>
#include <renderer/internal/vulkan/vulkan_material.h>
#include <renderer/render_window.h>
#include <renderer/memory_allocator.h>

RENDERER_API vulkan_bitmap_text_t* vulkan_bitmap_text_new(memory_allocator_t* allocator)
Expand All @@ -19,6 +20,55 @@ RENDERER_API vulkan_bitmap_text_t* vulkan_bitmap_text_create(vulkan_renderer_t*
return text;
}

static void update_bga_and_gtc_buffer(void* publisher, void* handler_data)
{
AUTO text = VULKAN_BITMAP_TEXT(handler_data);

/* update bga texture */
if(text->material != NULL)
{
vulkan_material_set_texture(text->material, "bga", VULKAN_TEXTURE(publisher));
AUTO tex_size = vulkan_bitmap_glyph_atlas_texture_get_size(text->texture);
vulkan_material_set_uvec2(text->material, "parameters.tex_size", (uvec2_t) { tex_size.width, tex_size.height });
}

/* update gtc buffer as the texture coordinate space has been transformed because of the new texture size */
buffer_t* gtc_buffer = vulkan_host_buffered_buffer_get_host_buffer(&text->glyph_texcoord_buffer);
u32 string_count = buf_get_element_count(&text->text_strings);
for(u32 i = 0; i < string_count; i++)
{
AUTO text_string = buf_get_ptr_at_typeof(&text->text_strings, vulkan_bitmap_text_string_t, i);
u32 char_count = buf_get_element_count(&text_string->chars);
for(u32 j = 0; j < char_count; j++)
{
/* get the ascii code of the character */
s8 ascii;
buf_get_at(&text_string->chars, j, &ascii);
_debug_assert__(vulkan_bitmap_glyph_atlas_texture_contains_texcoord(text->texture, ascii));

/* get the index of the GTC of this ascii in the GTC buffer */
utf32_t unicode = ascii;
u32 index;
dictionary_get_value(&text->glyph_texcoord_index_table, &unicode, &index);

/* update the GTC at the index */
glyph_texcoord_t texcoord;
vulkan_bitmap_glyph_atlas_texture_get_texcoord(text->texture, ascii, &texcoord);
glsl_glyph_texcoord_t glsl_texcoord =
{
.tltc = { texcoord.tltc.x, texcoord.tltc.y },
.trtc = { texcoord.trtc.x, texcoord.trtc.y },
.brtc = { texcoord.brtc.x, texcoord.brtc.y },
.bltc = { texcoord.bltc.x, texcoord.bltc.y }
};
buf_set_at(gtc_buffer, index, &glsl_texcoord);
}
}
bool is_resized = false;
_release_assert__(vulkan_host_buffered_buffer_commit(&text->glyph_texcoord_buffer, &is_resized));
_debug_assert__(is_resized == false);
}

RENDERER_API void vulkan_bitmap_text_create_no_alloc(vulkan_renderer_t* renderer, vulkan_bitmap_text_create_info_t* create_info, vulkan_bitmap_text_t OUT text)
{
memzero(text, vulkan_bitmap_text_t);
Expand All @@ -31,6 +81,16 @@ RENDERER_API void vulkan_bitmap_text_create_no_alloc(vulkan_renderer_t* renderer
/* setup BGA texture */
_debug_assert__(create_info->texture != NULL);
text->glyph_atlas_texture = create_info->texture;

/* subscribe to the on resize texture event */
event_subscription_create_info_t subscription =
{
.handler = EVENT_HANDLER(update_bga_and_gtc_buffer),
.wait_for = SIGNAL_NOTHING_BIT,
.signal = SIGNAL_NOTHING_BIT,
.handler_data = (void*)text
};
text->bga_texture_update_handle = event_subscribe(text->texture->on_resize_event, &subscription);

/* create GRD buffer */
vulkan_instance_buffer_create_info_t grd_buffer_create_info =
Expand Down Expand Up @@ -108,6 +168,7 @@ RENDERER_API void vulkan_bitmap_text_create_no_alloc(vulkan_renderer_t* renderer

RENDERER_API void vulkan_bitmap_text_destroy(vulkan_bitmap_text_t* text)
{
event_unsubscribe(text->texture->on_resize_event, text->bga_texture_update_handle);
buf_clear(&text->text_strings, NULL);

/* destroy the GRD buffer */
Expand Down Expand Up @@ -141,11 +202,19 @@ RENDERER_API void vulkan_bitmap_text_set_material(vulkan_bitmap_text_t* text, vu
{
text->material = material;

AUTO window = vulkan_renderer_get_window(text->renderer);
vulkan_material_set_uvec2(material, "parameters.win_size", (uvec2_t) { window->width, window->height });

vulkan_material_set_texture(material, "bga", VULKAN_TEXTURE(text->texture));
AUTO tex_size = vulkan_bitmap_glyph_atlas_texture_get_size(text->texture);
vulkan_material_set_uvec2(material, "parameters.tex_size", (uvec2_t) { tex_size.width, tex_size.height });

vulkan_material_set_array_size(material, "GTCBuffer.texcoords", buf_get_element_count(vulkan_host_buffered_buffer_get_host_buffer(&text->glyph_texcoord_buffer)));
vulkan_material_set_array_size(material, "TSTBuffer.transforms", buf_get_element_count(vulkan_host_buffered_buffer_get_host_buffer(&text->text_string_transform_buffer)));

vulkan_material_set_buffer(material, "GTCBuffer", vulkan_host_buffered_buffer_get_device_buffer(&text->glyph_texcoord_buffer));
vulkan_material_set_buffer(material, "TSTBuffer", vulkan_host_buffered_buffer_get_device_buffer(&text->text_string_transform_buffer));

}

static u32 get_index()
Expand Down Expand Up @@ -292,9 +361,19 @@ RENDERER_API void vulkan_bitmap_text_string_setH(vulkan_bitmap_text_t* text, vu

/* clear the glyphs for this text string */
multi_buffer_sub_buffer_clear(vulkan_instance_buffer_get_host_buffer(&text->glyph_render_data_buffer), text_string->render_data_handle);
buf_clear(&text_string->chars, NULL);

/* rewrite on the sub buffers */
u32 len = strlen(string);
u32 string_width = 0;
for(u32 i = 0; i < len; i++)
{
font_glyph_info_t info;
utf32_t ch = string[i];
font_get_glyph_info2(vulkan_bitmap_glyph_atlas_texture_get_font(text->texture), ch, &info);
string_width += info.advance_width;
}

/* rewrite on the sub buffers */
float horizontal_pen = 0.0f;
for(u32 i = 0; i < len; i++)
{
Expand All @@ -308,16 +387,20 @@ RENDERER_API void vulkan_bitmap_text_string_setH(vulkan_bitmap_text_t* text, vu
continue;
}

// _debug_assert__(info.bitmap_top == info.bearing_y);
glsl_glyph_render_data_t data =
{
.ofst = { i, 0, 0 },
.ofst = { horizontal_pen + info.width * 0.5f + info.bearing_x - string_width * 0.5f, info.height * 0.5f + (info.bearing_y - info.height), 0 },
.indx = get_or_create_glyph_texture_coordinate(text, ch),
.rotn = { ((i%3) == 0) ? 1 : 0, ((i%3) == 1) ? 1 : 0, ((i%3) == 2) ? 1 : 0 },
.stid = text_string->index,
.scal = { 1, 1, 1 }
};

multi_buffer_sub_buffer_push(vulkan_instance_buffer_get_host_buffer(&text->glyph_render_data_buffer), text_string->render_data_handle, (void*)&data);
buf_push(&text_string->chars, (void*)&string[i]);

horizontal_pen += info.advance_width;
}

vulkan_instance_buffer_commit(&text->glyph_render_data_buffer, NULL);
Expand Down
Loading

0 comments on commit ad5d586

Please sign in to comment.