load fonts at runtime
This commit is contained in:
parent
30510ab69a
commit
93f93a594e
@ -15,7 +15,9 @@ SDL_Window *win;
|
|||||||
void draw(void)
|
void draw(void)
|
||||||
{
|
{
|
||||||
ren_clear();
|
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);
|
ren_render_box(100, 300, 50, 50, 0xffff0000);
|
||||||
SDL_GL_SwapWindow(win);
|
SDL_GL_SwapWindow(win);
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,15 @@ STACK_DECL(vtstack, struct v_text)
|
|||||||
STACK_DECL(vcstack, struct v_col)
|
STACK_DECL(vcstack, struct v_col)
|
||||||
|
|
||||||
|
|
||||||
|
struct ren_font {
|
||||||
|
struct font_atlas *font;
|
||||||
|
GLuint texture;
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
SDL_GLContext *gl;
|
SDL_GLContext *gl;
|
||||||
struct font_atlas *font;
|
struct ren_font *fonts;
|
||||||
GLuint font_texture;
|
int fonts_no;
|
||||||
GLuint font_prog;
|
GLuint font_prog;
|
||||||
GLuint box_prog;
|
GLuint box_prog;
|
||||||
GLuint font_buffer;
|
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
|
// 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(glTexSubImage2D(
|
||||||
GL_TEXTURE_RECTANGLE,
|
GL_TEXTURE_RECTANGLE,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
ren.font->width,
|
ren.fonts[idx].font->width,
|
||||||
ren.font->height,
|
ren.fonts[idx].font->height,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
ren.font->atlas))
|
ren.fonts[idx].font->atlas))
|
||||||
font_dump(ren.font, "./atlas.png");
|
font_dump(ren.fonts[idx].font, "./atlas.png");
|
||||||
glUseProgram(0);
|
GL(glUseProgram(0));
|
||||||
return 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
|
// TODO: push window size uniforms
|
||||||
int ren_init(SDL_Window *w)
|
int ren_init(SDL_Window *w)
|
||||||
{
|
{
|
||||||
@ -343,19 +393,6 @@ int ren_init(SDL_Window *w)
|
|||||||
if (glew_err != GLEW_OK)
|
if (glew_err != GLEW_OK)
|
||||||
REN_RET(glew_err, REN_GLEW);
|
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
|
// Create stacks
|
||||||
ren.font_stack = vtstack_init();
|
ren.font_stack = vtstack_init();
|
||||||
ren.box_stack = vcstack_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(glUseProgram(ren.font_prog))
|
||||||
GL(glBindBuffer(GL_ARRAY_BUFFER, ren.font_buffer))
|
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
|
// 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(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.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_VERTEX_IDX))
|
||||||
GL(glEnableVertexAttribArray(REN_UV_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
|
// TODO: implement font size
|
||||||
int ren_render_text(const char *str, int x, int y, int w, int h, int 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
|
// FIXME: the bounding box (scissor) logic does not work
|
||||||
// TODO: create a method for calculating the total bounding box of a string
|
// TODO: create a method for calculating the total bounding box of a string
|
||||||
// given the box size
|
// 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;
|
size_t ret, off;
|
||||||
uint_least32_t cp;
|
uint_least32_t cp;
|
||||||
int updated, gx = x, gy = y;
|
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) {
|
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)
|
// skip special characters that render a box (not present in font)
|
||||||
// FIXME: handle tab
|
// FIXME: handle tab
|
||||||
if (iscntrl(cp)) goto skip_render;
|
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 (!g) REN_RET(-1, REN_FONT);
|
||||||
if (updated) {
|
if (updated) {
|
||||||
if (update_font_texture())
|
if (update_font_texture(idx))
|
||||||
REN_RET(-1, REN_TEXTURE);
|
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;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
// TODO: encode and/or store line height
|
// TODO: encode and/or store line height
|
||||||
gy += ren.font->glyph_max_h;
|
gy += ren.fonts[idx].font->glyph_max_h;
|
||||||
gx = x;
|
gx = x;
|
||||||
break;
|
break;
|
||||||
default: 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
|
// FIXME: here we are doing one draw call for string of text which is
|
||||||
// inefficient but is simpler and allows for individual scissors
|
// inefficient but is simpler and allows for individual scissors
|
||||||
ren_set_scissor(x, y, w, h);
|
ren_set_scissor(x, y, w, h);
|
||||||
ren_draw_font_stack();
|
ren_draw_font_stack(idx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -710,11 +748,13 @@ int ren_free(void)
|
|||||||
GL(glBindBuffer(GL_ARRAY_BUFFER, 0))
|
GL(glBindBuffer(GL_ARRAY_BUFFER, 0))
|
||||||
GL(glDeleteProgram(ren.box_prog));
|
GL(glDeleteProgram(ren.box_prog));
|
||||||
GL(glDeleteProgram(ren.font_prog));
|
GL(glDeleteProgram(ren.font_prog));
|
||||||
GL(glDeleteTextures(1, &ren.font_texture))
|
|
||||||
GL(glDeleteBuffers(1, &ren.font_buffer))
|
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);
|
SDL_GL_DeleteContext(ren.gl);
|
||||||
vtstack_free(&ren.font_stack);
|
vtstack_free(&ren.font_stack);
|
||||||
vcstack_free(&ren.box_stack);
|
vcstack_free(&ren.box_stack);
|
||||||
font_free(ren.font);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
|
||||||
#define FONT_PATH "./monospace.ttf"
|
#define DEFAULT_FONT "./monospace.ttf"
|
||||||
#define FONT_VERSHADER "./font_vertshader.glsl"
|
#define FONT_VERSHADER "./font_vertshader.glsl"
|
||||||
#define FONT_FRAGSHADER "./font_fragshader.glsl"
|
#define FONT_FRAGSHADER "./font_fragshader.glsl"
|
||||||
#define BOX_VERSHADER "./box_vertshader.glsl"
|
#define BOX_VERSHADER "./box_vertshader.glsl"
|
||||||
|
@ -38,6 +38,14 @@ void * ecalloc(unsigned long int nmemb, unsigned long int size)
|
|||||||
return r;
|
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)
|
void efree(void *ptr)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
void * emalloc(unsigned long int size);
|
void * emalloc(unsigned long int size);
|
||||||
void * ecalloc(unsigned long int nmemb, 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 efree(void *ptr);
|
||||||
|
|
||||||
void map_file(const unsigned char **str, int *size, const char *path);
|
void map_file(const unsigned char **str, int *size, const char *path);
|
||||||
|
Loading…
Reference in New Issue
Block a user