load fonts at runtime
This commit is contained in:
parent
30510ab69a
commit
93f93a594e
@ -15,7 +15,9 @@ SDL_Window *win;
|
||||
void draw(void)
|
||||
{
|
||||
ren_clear();
|
||||
ren_render_text(str, 0, 0, 100, 50, 12);
|
||||
if (ren_render_text(str, 0, 0, 100, 50, 20))
|
||||
printf("text: %s\n", ren_strerror());
|
||||
ren_render_text("altro font", 200, 40, 300, 300, 40);
|
||||
ren_render_box(100, 300, 50, 50, 0xffff0000);
|
||||
SDL_GL_SwapWindow(win);
|
||||
}
|
||||
|
@ -74,10 +74,15 @@ STACK_DECL(vtstack, struct v_text)
|
||||
STACK_DECL(vcstack, struct v_col)
|
||||
|
||||
|
||||
struct ren_font {
|
||||
struct font_atlas *font;
|
||||
GLuint texture;
|
||||
};
|
||||
|
||||
struct {
|
||||
SDL_GLContext *gl;
|
||||
struct font_atlas *font;
|
||||
GLuint font_texture;
|
||||
struct ren_font *fonts;
|
||||
int fonts_no;
|
||||
GLuint font_prog;
|
||||
GLuint box_prog;
|
||||
GLuint font_buffer;
|
||||
@ -304,23 +309,68 @@ static GLuint ren_texturer_rect(const char *buf, int w, int h, int upscale, int
|
||||
|
||||
|
||||
// FIXME: update only the newly generated character instead of the whole texture
|
||||
static int update_font_texture(void)
|
||||
static int update_font_texture(int idx)
|
||||
{
|
||||
glUseProgram(ren.font_prog);
|
||||
GL(glUseProgram(ren.font_prog))
|
||||
GL(glTexSubImage2D(
|
||||
GL_TEXTURE_RECTANGLE,
|
||||
0, 0, 0,
|
||||
ren.font->width,
|
||||
ren.font->height,
|
||||
ren.fonts[idx].font->width,
|
||||
ren.fonts[idx].font->height,
|
||||
GL_RED,
|
||||
GL_UNSIGNED_BYTE,
|
||||
ren.font->atlas))
|
||||
font_dump(ren.font, "./atlas.png");
|
||||
glUseProgram(0);
|
||||
ren.fonts[idx].font->atlas))
|
||||
font_dump(ren.fonts[idx].font, "./atlas.png");
|
||||
GL(glUseProgram(0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// loads a font and returns it's index in the fonts array
|
||||
static int ren_load_font(int size, const char *path)
|
||||
{
|
||||
int idx = ren.fonts_no;
|
||||
struct font_atlas *f;
|
||||
ren.fonts = erealloc(ren.fonts, sizeof(struct ren_font)*(idx+1));
|
||||
ren.fonts[idx].font = font_init();
|
||||
f = ren.fonts[idx].font;
|
||||
if (!f)
|
||||
REN_RET(-1, REN_FONT)
|
||||
|
||||
if (!path)
|
||||
path = DEFAULT_FONT;
|
||||
|
||||
if (font_load(f, path, size))
|
||||
REN_RET(-1, REN_FONT)
|
||||
font_dump(f, "./atlas.png");
|
||||
|
||||
// load font texture (atlas)
|
||||
ren.fonts[idx].texture = ren_texturer_rect(
|
||||
(const char *)f->atlas,
|
||||
f->width,
|
||||
f->height,
|
||||
GL_LINEAR, GL_LINEAR);
|
||||
if (!ren.fonts[idx].texture)
|
||||
return -1;
|
||||
|
||||
ren.fonts_no = idx+1;
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
// returns the index to the ren.fonts array to the font with the correct size
|
||||
// return -1 on errror
|
||||
static int ren_get_font(int size)
|
||||
{
|
||||
for (int i = 0; i < ren.fonts_no; i++) {
|
||||
if (ren.fonts[i].font->size == size)
|
||||
return i;
|
||||
}
|
||||
// TODO: add a way to change font family
|
||||
return ren_load_font(size, NULL);
|
||||
}
|
||||
|
||||
|
||||
// TODO: push window size uniforms
|
||||
int ren_init(SDL_Window *w)
|
||||
{
|
||||
@ -343,19 +393,6 @@ int ren_init(SDL_Window *w)
|
||||
if (glew_err != GLEW_OK)
|
||||
REN_RET(glew_err, REN_GLEW);
|
||||
|
||||
// Load font
|
||||
ren.font = font_init();
|
||||
if (!ren.font) REN_RET(-1, REN_FONT)
|
||||
if (font_load(ren.font, FONT_PATH, 20)) REN_RET(-1, REN_FONT)
|
||||
font_dump(ren.font, "./atlas.png");
|
||||
// load font texture (atlas)
|
||||
ren.font_texture = ren_texturer_rect(
|
||||
(const char *)ren.font->atlas,
|
||||
ren.font->width,
|
||||
ren.font->height,
|
||||
GL_LINEAR, GL_LINEAR);
|
||||
if (!ren.font_texture) return -1;
|
||||
|
||||
// Create stacks
|
||||
ren.font_stack = vtstack_init();
|
||||
ren.box_stack = vcstack_init();
|
||||
@ -403,7 +440,9 @@ int ren_clear(void)
|
||||
}
|
||||
|
||||
|
||||
static int ren_draw_font_stack(void)
|
||||
// idx refers to the fonts array index, this means that when drawing the font stack
|
||||
// only one font size at the time can be used
|
||||
static int ren_draw_font_stack(int idx)
|
||||
{
|
||||
GL(glUseProgram(ren.font_prog))
|
||||
GL(glBindBuffer(GL_ARRAY_BUFFER, ren.font_buffer))
|
||||
@ -412,7 +451,7 @@ static int ren_draw_font_stack(void)
|
||||
// this has caused me some trouble, convert from image coordiates to viewport
|
||||
GL(glScissor(ren.s_x, ren.height-ren.s_y-ren.s_h, ren.s_w, ren.s_h))
|
||||
GL(glUniform2i(ren.viewsize_loc, ren.width, ren.height))
|
||||
GL(glUniform2i(ren.texturesize_loc, ren.font->width, ren.font->height))
|
||||
GL(glUniform2i(ren.texturesize_loc, ren.fonts[idx].font->width, ren.fonts[idx].font->height))
|
||||
|
||||
GL(glEnableVertexAttribArray(REN_VERTEX_IDX))
|
||||
GL(glEnableVertexAttribArray(REN_UV_IDX))
|
||||
@ -595,10 +634,6 @@ static int ren_push_glyph(const struct font_glyph *g, int gx, int gy)
|
||||
// TODO: implement font size
|
||||
int ren_render_text(const char *str, int x, int y, int w, int h, int size)
|
||||
{
|
||||
// TODO: check size, if the current font is not of the same size then load
|
||||
// load a new font and use that texture instead, this implies making
|
||||
// a system to store and use different fonts, like:
|
||||
// struct font_atlas * font_by_size(int size);
|
||||
// FIXME: the bounding box (scissor) logic does not work
|
||||
// TODO: create a method for calculating the total bounding box of a string
|
||||
// given the box size
|
||||
@ -606,14 +641,17 @@ int ren_render_text(const char *str, int x, int y, int w, int h, int size)
|
||||
size_t ret, off;
|
||||
uint_least32_t cp;
|
||||
int updated, gx = x, gy = y;
|
||||
int idx = ren_get_font(size);
|
||||
if (idx < 0)
|
||||
return -1;
|
||||
for (off = 0; (ret = grapheme_decode_utf8(str+off, SIZE_MAX, &cp)) > 0 && cp != 0; off += ret) {
|
||||
// skip special characters that render a box (not present in font)
|
||||
// FIXME: handle tab
|
||||
if (iscntrl(cp)) goto skip_render;
|
||||
g = font_get_glyph_texture(ren.font, cp, &updated);
|
||||
g = font_get_glyph_texture(ren.fonts[idx].font, cp, &updated);
|
||||
if (!g) REN_RET(-1, REN_FONT);
|
||||
if (updated) {
|
||||
if (update_font_texture())
|
||||
if (update_font_texture(idx))
|
||||
REN_RET(-1, REN_TEXTURE);
|
||||
}
|
||||
|
||||
@ -631,7 +669,7 @@ int ren_render_text(const char *str, int x, int y, int w, int h, int size)
|
||||
break;
|
||||
case '\n':
|
||||
// TODO: encode and/or store line height
|
||||
gy += ren.font->glyph_max_h;
|
||||
gy += ren.fonts[idx].font->glyph_max_h;
|
||||
gx = x;
|
||||
break;
|
||||
default: break;
|
||||
@ -641,7 +679,7 @@ int ren_render_text(const char *str, int x, int y, int w, int h, int size)
|
||||
// FIXME: here we are doing one draw call for string of text which is
|
||||
// inefficient but is simpler and allows for individual scissors
|
||||
ren_set_scissor(x, y, w, h);
|
||||
ren_draw_font_stack();
|
||||
ren_draw_font_stack(idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -710,11 +748,13 @@ int ren_free(void)
|
||||
GL(glBindBuffer(GL_ARRAY_BUFFER, 0))
|
||||
GL(glDeleteProgram(ren.box_prog));
|
||||
GL(glDeleteProgram(ren.font_prog));
|
||||
GL(glDeleteTextures(1, &ren.font_texture))
|
||||
GL(glDeleteBuffers(1, &ren.font_buffer))
|
||||
for (int i = 0; i < ren.fonts_no; i++) {
|
||||
GL(glDeleteTextures(1, &ren.fonts[i].texture))
|
||||
font_free(ren.fonts[i].font);
|
||||
}
|
||||
SDL_GL_DeleteContext(ren.gl);
|
||||
vtstack_free(&ren.font_stack);
|
||||
vcstack_free(&ren.box_stack);
|
||||
font_free(ren.font);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
|
||||
#define FONT_PATH "./monospace.ttf"
|
||||
#define DEFAULT_FONT "./monospace.ttf"
|
||||
#define FONT_VERSHADER "./font_vertshader.glsl"
|
||||
#define FONT_FRAGSHADER "./font_fragshader.glsl"
|
||||
#define BOX_VERSHADER "./box_vertshader.glsl"
|
||||
|
@ -38,6 +38,14 @@ void * ecalloc(unsigned long int nmemb, unsigned long int size)
|
||||
return r;
|
||||
}
|
||||
|
||||
void * erealloc(void *ptr, unsigned long int size)
|
||||
{
|
||||
void *r = realloc(ptr, size);
|
||||
if (!r)
|
||||
err(EXIT_FAILURE, "ralloc() of 0x%lx, to size %ld", (unsigned long)ptr, size);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void efree(void *ptr)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
void * emalloc(unsigned long int size);
|
||||
void * ecalloc(unsigned long int nmemb, unsigned long int size);
|
||||
void * erealloc(void *ptr, unsigned long int size);
|
||||
void efree(void *ptr);
|
||||
|
||||
void map_file(const unsigned char **str, int *size, const char *path);
|
||||
|
Loading…
Reference in New Issue
Block a user