reloading font dynamically
This commit is contained in:
@@ -97,31 +97,33 @@ r2f32_t rn_pack_bitmap(rn_atlas_t *atlas, u8 *bitmap, i32 width, i32 height) {
|
||||
return result;
|
||||
}
|
||||
|
||||
rn_font_t rn_create_font(ma_arena_t *glyph_arena, s8_t font_data, rn_atlas_t *atlas, i32 size) {
|
||||
rn_font_t result = {};
|
||||
rn_font_t *rn_create_font(ma_arena_t *arena) {
|
||||
rn_font_t *font = ma_push_type(arena, rn_font_t);
|
||||
font->first_char = ' ';
|
||||
font->last_char = '~';
|
||||
i32 glyph_count = font->last_char - font->first_char + 1; // + 1 because it's '<=' not '<'
|
||||
font->glyphs = ma_push_array(arena, rn_glyph_t, glyph_count);
|
||||
return font;
|
||||
}
|
||||
|
||||
b32 rn_reload_font_atlas(rn_font_t *font, s8_t font_data, rn_atlas_t *atlas, i32 size) {
|
||||
font->glyph_count = 0;
|
||||
stbtt_fontinfo stb_font;
|
||||
i32 success = stbtt_InitFont(&stb_font, (const unsigned char *)font_data.str, 0);
|
||||
if (!success) {
|
||||
return result;
|
||||
}
|
||||
if (!success) return false;
|
||||
|
||||
f32 scale = stbtt_ScaleForPixelHeight(&stb_font, (f32)size);
|
||||
// f32 em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, (f32)size);
|
||||
|
||||
i32 ascent, descent, line_gap;
|
||||
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &line_gap);
|
||||
result.ascent = (f32)ascent * scale;
|
||||
result.descent = (f32)descent * scale;
|
||||
result.line_gap = (f32)line_gap * scale;
|
||||
result.size = (f32)size;
|
||||
result.first_char = ' ';
|
||||
result.last_char = '~';
|
||||
result.white_texture_bounding_box = atlas->white_texture_bounding_box;
|
||||
font->ascent = (f32)ascent * scale;
|
||||
font->descent = (f32)descent * scale;
|
||||
font->line_gap = (f32)line_gap * scale;
|
||||
font->size = (f32)size;
|
||||
font->white_texture_bounding_box = atlas->white_texture_bounding_box;
|
||||
|
||||
i32 glyph_count = result.last_char - result.first_char + 1; // + 1 because it's '<=' not '<'
|
||||
result.glyphs = ma_push_array(glyph_arena, rn_glyph_t, glyph_count);
|
||||
|
||||
for (u32 ascii_symbol = result.first_char; ascii_symbol <= result.last_char; ascii_symbol++) {
|
||||
for (u32 ascii_symbol = font->first_char; ascii_symbol <= font->last_char; ascii_symbol++) {
|
||||
i32 width, height, xoff, yoff;
|
||||
u8 *bitmap = (u8 *)stbtt_GetCodepointBitmap(&stb_font, 0, scale, ascii_symbol, &width, &height, &xoff, &yoff);
|
||||
|
||||
@@ -135,13 +137,12 @@ rn_font_t rn_create_font(ma_arena_t *glyph_arena, s8_t font_data, rn_atlas_t *at
|
||||
glyph.xadvance = (f32)xadvance * scale;
|
||||
glyph.left_side_bearing = (f32)left_side_bearing * scale;
|
||||
|
||||
assert(result.glyph_count + 1 <= glyph_count);
|
||||
result.glyphs[result.glyph_count++] = glyph;
|
||||
font->glyphs[font->glyph_count++] = glyph;
|
||||
|
||||
stbtt_FreeBitmap(bitmap, 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
rn_glyph_t *rn_get_glyph(rn_font_t *font, u32 codepoint) {
|
||||
|
||||
@@ -31,7 +31,7 @@ struct rn_cmd_t {
|
||||
|
||||
typedef struct rn_state_t rn_state_t;
|
||||
struct rn_state_t {
|
||||
rn_font_t main_font;
|
||||
rn_font_t *main_font;
|
||||
rn_shader_t shader2d;
|
||||
|
||||
rn_cmd_t *first_cmd;
|
||||
@@ -43,9 +43,9 @@ struct rn_state_t {
|
||||
u32 vao;
|
||||
u32 vbo;
|
||||
};
|
||||
rn_state_t rn_state;
|
||||
gb rn_state_t rn_state;
|
||||
|
||||
rn_shader_t rn_create_shader(char *glsl_vshader, char *glsl_fshader) {
|
||||
fn rn_shader_t rn_create_shader(char *glsl_vshader, char *glsl_fshader) {
|
||||
rn_shader_t result = {};
|
||||
result.vshader = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
|
||||
result.fshader = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
|
||||
@@ -71,7 +71,7 @@ rn_shader_t rn_create_shader(char *glsl_vshader, char *glsl_fshader) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void gl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) {
|
||||
fn void gl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *user) {
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
|
||||
fatalf("opengl message: %s", message);
|
||||
} else {
|
||||
@@ -79,7 +79,7 @@ void gl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, G
|
||||
}
|
||||
}
|
||||
|
||||
rn_cmd_t *rn_get_cmd(rn_cmd_kind_t kind) {
|
||||
fn rn_cmd_t *rn_get_cmd(rn_cmd_kind_t kind) {
|
||||
b32 alloc_new = false;
|
||||
if (rn_state.last_cmd == NULL) {
|
||||
alloc_new = true;
|
||||
@@ -101,14 +101,14 @@ rn_cmd_t *rn_get_cmd(rn_cmd_kind_t kind) {
|
||||
return result;
|
||||
}
|
||||
|
||||
rn_vertex_t *rn_push_vertex(rn_cmd_t *cmd, u32 count) {
|
||||
fn rn_vertex_t *rn_push_vertex(rn_cmd_t *cmd, u32 count) {
|
||||
rn_vertex_t *result = cmd->vertex + cmd->len;
|
||||
rn_state.len += count;
|
||||
cmd->len += count;
|
||||
return result;
|
||||
}
|
||||
|
||||
void rn_push_quad(r2f32_t rect, r2f32_t tex, v4f32_t color) {
|
||||
fn void rn_push_quad(r2f32_t rect, r2f32_t tex, v4f32_t color) {
|
||||
rn_cmd_t *cmd = rn_get_cmd(rn_cmd_kind_quad);
|
||||
rn_vertex_t *v = rn_push_vertex(cmd, 6);
|
||||
v[0] = (rn_vertex_t){
|
||||
@@ -143,33 +143,33 @@ void rn_push_quad(r2f32_t rect, r2f32_t tex, v4f32_t color) {
|
||||
};
|
||||
}
|
||||
|
||||
void rn_draw_rect(r2f32_t rect, v4f32_t color) {
|
||||
rn_push_quad(rect, rn_state.main_font.white_texture_bounding_box, color);
|
||||
fn void rn_draw_rect(r2f32_t rect, v4f32_t color) {
|
||||
rn_push_quad(rect, rn_state.main_font->white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
void rn_draw_rect_border(r2f32_t rect, v4f32_t color) {
|
||||
fn void rn_draw_rect_border(r2f32_t rect, v4f32_t color) {
|
||||
r2f32_t left = r2f32_cut_left(&rect, 1);
|
||||
r2f32_t right = r2f32_cut_right(&rect, 1);
|
||||
r2f32_t top = r2f32_cut_top(&rect, 1);
|
||||
r2f32_t bottom = r2f32_cut_bottom(&rect, 1);
|
||||
rn_push_quad(left, rn_state.main_font.white_texture_bounding_box, color);
|
||||
rn_push_quad(right, rn_state.main_font.white_texture_bounding_box, color);
|
||||
rn_push_quad(top, rn_state.main_font.white_texture_bounding_box, color);
|
||||
rn_push_quad(bottom, rn_state.main_font.white_texture_bounding_box, color);
|
||||
rn_push_quad(left, rn_state.main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(right, rn_state.main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(top, rn_state.main_font->white_texture_bounding_box, color);
|
||||
rn_push_quad(bottom, rn_state.main_font->white_texture_bounding_box, color);
|
||||
}
|
||||
|
||||
i64 rn_get_char_spacing(rn_font_t *font, u32 codepoint) {
|
||||
fn i64 rn_get_char_spacing(rn_font_t *font, u32 codepoint) {
|
||||
rn_glyph_t *g = rn_get_glyph(font, codepoint);
|
||||
if (g->xadvance) return (i64)g->xadvance;
|
||||
return (i64)g->size.x;
|
||||
}
|
||||
|
||||
i64 rn_get_line_spacing(rn_font_t *font) {
|
||||
fn i64 rn_get_line_spacing(rn_font_t *font) {
|
||||
i64 result = (i64)(font->ascent - font->descent + font->line_gap);
|
||||
return result;
|
||||
}
|
||||
|
||||
v2f32_t rn_base_draw_string(rn_font_t *font, s8_t string, v2f32_t pos, v4f32_t color, b32 draw) {
|
||||
fn v2f32_t rn_base_draw_string(rn_font_t *font, s8_t string, v2f32_t pos, v4f32_t color, b32 draw) {
|
||||
pos.y += rn_get_line_spacing(font) + font->descent;
|
||||
v2f32_t original_pos = pos;
|
||||
|
||||
@@ -188,48 +188,51 @@ v2f32_t rn_base_draw_string(rn_font_t *font, s8_t string, v2f32_t pos, v4f32_t c
|
||||
return result;
|
||||
}
|
||||
|
||||
v2f32_t rn_draw_string(rn_font_t *font, v2f32_t pos, v4f32_t color, s8_t string) {
|
||||
fn v2f32_t rn_draw_string(rn_font_t *font, v2f32_t pos, v4f32_t color, s8_t string) {
|
||||
return rn_base_draw_string(font, string, pos, color, true);
|
||||
}
|
||||
|
||||
v2f32_t rn_draw_stringf(rn_font_t *font, v2f32_t pos, v4f32_t color, char *str, ...) {
|
||||
fn v2f32_t rn_draw_stringf(rn_font_t *font, v2f32_t pos, v4f32_t color, char *str, ...) {
|
||||
S8_FMT(tcx.temp, str, result);
|
||||
return rn_draw_string(font, pos, color, result);
|
||||
}
|
||||
|
||||
v2f32_t rn_measure_string(rn_font_t *font, s8_t string) {
|
||||
fn v2f32_t rn_measure_string(rn_font_t *font, s8_t string) {
|
||||
return rn_base_draw_string(font, string, v2f32(0,0), v4f32(0,0,0,0), false);
|
||||
}
|
||||
|
||||
void rn_set_clip(r2f32_t rect) {
|
||||
fn void rn_set_clip(r2f32_t rect) {
|
||||
rn_cmd_t *cmd = rn_get_cmd(rn_cmd_kind_set_clip);
|
||||
cmd->rect = rect;
|
||||
}
|
||||
|
||||
void rn_init(ma_arena_t *perm, s8_t font_data, f32 _font_size) {
|
||||
fn void rn_reload_font(s8_t font_data, f32 font_size) {
|
||||
if (rn_state.main_font->texture_id) {
|
||||
glDeleteTextures(1, &rn_state.main_font->texture_id);
|
||||
}
|
||||
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
rn_atlas_t *atlas = rn_create_atlas(scratch.arena, (v2i32_t){2048, 2048});
|
||||
rn_reload_font_atlas(rn_state.main_font, font_data, atlas, (i32)font_size);
|
||||
|
||||
GLint filter = GL_NEAREST;
|
||||
glCreateTextures(GL_TEXTURE_2D, 1, &atlas->texture_id);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTextureStorage2D(atlas->texture_id, 1, GL_R8, (GLsizei)atlas->size.x, (GLsizei)atlas->size.y);
|
||||
glTextureSubImage2D(atlas->texture_id, 0, 0, 0, (GLsizei)atlas->size.x, (GLsizei)atlas->size.y, GL_RED, GL_UNSIGNED_BYTE, atlas->bitmap);
|
||||
rn_state.main_font->texture_id = atlas->texture_id;
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn void rn_init(ma_arena_t *perm, s8_t font_data, f32 font_size) {
|
||||
rn_state.cap = 1024*256;
|
||||
rn_state.vertices = ma_push_array(perm, rn_vertex_t, rn_state.cap);
|
||||
|
||||
{
|
||||
ma_temp_t scratch = ma_begin_scratch1(perm);
|
||||
// s8_t font_data = ;//rn_get_default_font(tcx.temp);
|
||||
rn_atlas_t *atlas = rn_create_atlas(scratch.arena, (v2i32_t){2048, 2048});
|
||||
|
||||
u32 font_size = (u32)_font_size;
|
||||
rn_state.main_font = rn_create_font(perm, font_data, atlas, font_size);
|
||||
|
||||
GLint filter = GL_NEAREST;
|
||||
// filter = GL_LINEAR;
|
||||
glCreateTextures(GL_TEXTURE_2D, 1, &atlas->texture_id);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTextureParameteri(atlas->texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTextureStorage2D(atlas->texture_id, 1, GL_R8, (GLsizei)atlas->size.x, (GLsizei)atlas->size.y);
|
||||
glTextureSubImage2D(atlas->texture_id, 0, 0, 0, (GLsizei)atlas->size.x, (GLsizei)atlas->size.y, GL_RED, GL_UNSIGNED_BYTE, atlas->bitmap);
|
||||
rn_state.main_font.texture_id = atlas->texture_id;
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
rn_state.main_font = rn_create_font(perm);
|
||||
rn_reload_font(font_data, font_size);
|
||||
|
||||
|
||||
glDebugMessageCallback(&gl_debug_callback, NULL);
|
||||
@@ -326,7 +329,7 @@ void rn_end(v2f32_t window_size, v4f32_t color) {
|
||||
glNamedBufferSubData(rn_state.vbo, 0, it->len * sizeof(rn_vertex_t), it->vertex);
|
||||
glBindVertexArray(rn_state.vao);
|
||||
GLint s_texture = 0; // texture unit that sampler2D will use in GLSL code
|
||||
glBindTextureUnit(s_texture, rn_state.main_font.texture_id);
|
||||
glBindTextureUnit(s_texture, rn_state.main_font->texture_id);
|
||||
glDrawArrays(GL_TRIANGLES, 0, it->len);
|
||||
} else if (it->kind == rn_cmd_kind_set_clip) {
|
||||
GLint x = (GLint)it->rect.min.x;
|
||||
|
||||
Reference in New Issue
Block a user