| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- #ifndef FREE_GLYPH_H
- #define FREE_GLYPH_H
- #include <stdbool.h>
- #include <stdint.h>
- #include <ft2build.h>
- #include FT_FREETYPE_H
- #include "vec2.h"
- #include "vec4.h"
- #include "glyph_attr.h"
- struct glyph_info {
- struct vec2i64 a;
- struct {
- uint32_t w;
- uint32_t h;
- int32_t l;
- int32_t t;
- } b;
- float tx;
- };
- struct free_glyph {
- struct vec2f pos;
- struct vec2f size;
- struct vec2f uv_pos;
- struct vec2f uv_size;
- struct vec4f fg_color;
- struct vec4f bg_color;
- };
- DA_DEF_STRUCT(struct free_glyph, free_glyph_da);
- struct free_glyph_render {
- uint32_t font_tex;
- struct vec2ui atlas_dim;
- struct free_glyph_da glyphs;
- struct {
- uint32_t vert;
- uint32_t frag;
- } shaders;
- uint32_t prog;
- struct {
- int32_t resolution;
- int32_t time;
- int32_t camera;
- } uniforms;
- uint32_t vao;
- uint32_t vbo;
- struct glyph_info g_infos[128];
- };
- enum free_glyph_attr_enum {
- FREE_GLYPH_ATTR_POS = 0,
- FREE_GLYPH_ATTR_SIZE,
- FREE_GLYPH_ATTR_UV_POS,
- FREE_GLYPH_ATTR_UV_SIZE,
- FREE_GLYPH_ATTR_FG_COLOR,
- FREE_GLYPH_ATTR_BG_COLOR,
- FREE_GLYPH_ATTR_TOTAL
- };
- struct free_glyph_render free_glyph_render_create(FT_Face font_face,
- const char *vert_path,
- const char *frag_path);
- struct free_glyph_da free_glyph_da_create(void);
- const struct glyph_attr* free_glyph_get_attrs(void);
- void free_glyph_render_use(struct free_glyph_render fgr);
- float free_glyph_render_calc_col(struct free_glyph_render fgr, struct app app,
- const char *cstr, size_t cstr_size,
- struct vec2f pos, size_t index);
- float free_glyph_render_calc_col_buffer(struct free_glyph_render fgr,
- struct app app);
- struct free_glyph_render free_glyph_render_calc(
- struct free_glyph_render fgr, struct app app,
- const char *cstr, size_t cstr_size, struct vec2f pos,
- struct vec4f fg_color, struct vec4f bg_color);
- struct free_glyph_render free_glyph_render_calc_buffer(
- struct free_glyph_render fgr, struct app app,
- struct vec2f pos);
- void free_glyph_render_sync(struct free_glyph_render fgr);
- struct free_glyph_render free_glyph_render_gen_buffer(
- struct free_glyph_render fgr);
- struct free_glyph_render free_glyph_render_load_texture_atlas_or_exit(
- struct free_glyph_render fgr,
- FT_Face font_face);
- struct vec2ui free_glyph_render_calc_atlas_dimensions(FT_Face font_face);
- #if defined(FREE_GLYPH_IMP) || defined(IMP)
- #include "shader.h"
- #include "gl_util.h"
- struct free_glyph_render
- free_glyph_render_create(FT_Face font_face, const char *vert_path,
- const char *frag_path)
- {
- struct free_glyph_render fgr = {0};
- fgr = free_glyph_render_load_texture_atlas_or_exit(fgr, font_face);
- fgr.glyphs = free_glyph_da_create();
- fgr.shaders.vert = shader_compile_file_or_exit(
- vert_path, GL_VERTEX_SHADER);
- fgr.shaders.frag = shader_compile_file_or_exit(
- frag_path, GL_FRAGMENT_SHADER);
- fgr.prog = program_link_or_exit(fgr.shaders.vert, fgr.shaders.frag);
- glUseProgram(fgr.prog);
- fgr.uniforms.resolution = get_uniform_or_exit(fgr.prog, "resolution");
- fgr.uniforms.time = get_uniform_or_exit(fgr.prog, "time");
- fgr.uniforms.camera = get_uniform_or_exit(fgr.prog, "camera");
- fgr = free_glyph_render_gen_buffer(fgr);
- return fgr;
- }
- struct free_glyph_da
- free_glyph_da_create(void)
- {
- struct free_glyph_da glys;
- glys.cap = 1024 * 1024;
- glys.size = 0;
- glys.items = calloc(glys.cap, sizeof(struct free_glyph));
- return glys;
- }
- const struct glyph_attr *
- free_glyph_get_attrs(void)
- {
- static const struct glyph_attr
- free_glyph_attr[FREE_GLYPH_ATTR_TOTAL] = {
- [FREE_GLYPH_ATTR_POS] = {
- .size = 2,
- .type = GL_FLOAT,
- .norm = GL_FALSE,
- .stride = sizeof(struct free_glyph),
- .offset = offsetof(struct free_glyph, pos)
- },
- [FREE_GLYPH_ATTR_SIZE] = {
- .size = 2,
- .type = GL_FLOAT,
- .norm = GL_FALSE,
- .stride = sizeof(struct free_glyph),
- .offset = offsetof(struct free_glyph, size)
- },
- [FREE_GLYPH_ATTR_UV_POS] = {
- .size = 2,
- .type = GL_FLOAT,
- .norm = GL_FALSE,
- .stride = sizeof(struct free_glyph),
- .offset = offsetof(struct free_glyph, uv_pos)
- },
- [FREE_GLYPH_ATTR_UV_SIZE] = {
- .size = 2,
- .type = GL_FLOAT,
- .norm = GL_FALSE,
- .stride = sizeof(struct free_glyph),
- .offset = offsetof(struct free_glyph, uv_size)
- },
- [FREE_GLYPH_ATTR_FG_COLOR] = {
- .size = 4,
- .type = GL_FLOAT,
- .norm = GL_FALSE,
- .stride = sizeof(struct free_glyph),
- .offset = offsetof(struct free_glyph, fg_color)
- },
- [FREE_GLYPH_ATTR_BG_COLOR] = {
- .size = 4,
- .type = GL_FLOAT,
- .norm = GL_FALSE,
- .stride = sizeof(struct free_glyph),
- .offset = offsetof(struct free_glyph, bg_color)
- },
- };
- return free_glyph_attr;
- }
- void
- free_glyph_render_use(struct free_glyph_render fgr)
- {
- glBindVertexArray(fgr.vao);
- glBindBuffer(GL_ARRAY_BUFFER, fgr.vbo);
- glUseProgram(fgr.prog);
- }
- float
- free_glyph_render_calc_col(struct free_glyph_render fgr, struct app app,
- const char *cstr, size_t cstr_size, struct vec2f pos,
- size_t index)
- {
- struct vec2f pen = pos;
- struct vec2f dim = vec2f_from_ui(fgr.atlas_dim);
- if ( index > cstr_size ) {
- index = cstr_size - 1;
- }
- for ( size_t i = 0; i < index; ++i ) {
- char c = cstr[i];
- if ( c == '\n' ) {
- pen.x = 0;
- pen.y -= dim.y;
- continue;
- }
- struct glyph_info gi = fgr.g_infos[(int64_t)c];
- if ( c == '\t' ) {
- c = ' ';
- gi = fgr.g_infos[(int64_t)c];
- gi.a.x *= app.cfg.tab_size;
- }
- pen.x += (float) gi.a.x;
- pen.y += (float) gi.a.y;
- }
- return pen.x;
- }
- float
- free_glyph_render_calc_col_buffer(struct free_glyph_render fgr,
- struct app app)
- {
- return free_glyph_render_calc_col(fgr, app, app.buf.data.items,
- app.buf.data.size, vec2fs(0),
- app.buf.cur);
- }
- struct free_glyph_render
- free_glyph_render_calc(struct free_glyph_render fgr, struct app app,
- const char *cstr, size_t cstr_size, struct vec2f pos,
- struct vec4f fg_color, struct vec4f bg_color)
- {
- struct vec2f pen = pos;
- struct vec2f dim = vec2f_from_ui(fgr.atlas_dim);
- for ( size_t i = 0; i < cstr_size; ++i ) {
- char c = cstr[i];
- if ( c == '\n' ) {
- pen.x = 0;
- pen.y -= dim.y;
- continue;
- }
- struct glyph_info gi = fgr.g_infos[(int64_t)c];
- if ( c == '\t' ) {
- c = ' ';
- gi = fgr.g_infos[(int64_t)c];
- gi.a.x *= app.cfg.tab_size;
- }
- float w = (float)gi.b.w;
- float h = (float)gi.b.h;
- struct free_glyph gly = {
- .pos = {
- pen.x + (float) gi.b.l,
- pen.y + (float) gi.b.t
- },
- .size = {w, -h},
- .uv_pos = { gi.tx, 0.0f },
- .uv_size = { w / dim.x, h / dim.y },
- .fg_color = fg_color,
- .bg_color = bg_color,
- };
- pen.x += (float) gi.a.x;
- pen.y += (float) gi.a.y;
- DA_APPEND(fgr.glyphs, gly);
- }
- return fgr;
- }
- struct free_glyph_render
- free_glyph_render_calc_buffer(struct free_glyph_render fgr,
- struct app app,
- struct vec2f size)
- {
- return free_glyph_render_calc(fgr, app,
- app.buf.data.items, app.buf.data.size,
- size, vec4fs(1), vec4fs(0));
- }
- void
- free_glyph_render_sync(struct free_glyph_render fgr)
- {
- glBufferSubData(GL_ARRAY_BUFFER, 0,
- (ssize_t) (fgr.glyphs.size * sizeof(struct free_glyph)),
- fgr.glyphs.items);
- }
- struct free_glyph_render
- free_glyph_render_gen_buffer(struct free_glyph_render fgr)
- {
- glGenVertexArrays(1, &fgr.vao);
- glBindVertexArray(fgr.vao);
- glGenBuffers(1, &fgr.vbo);
- glBindBuffer(GL_ARRAY_BUFFER, fgr.vbo);
- glBufferData(GL_ARRAY_BUFFER,
- (ssize_t)(fgr.glyphs.cap * sizeof(struct free_glyph)),
- fgr.glyphs.items,
- GL_DYNAMIC_DRAW);
- glyph_attr_declare(free_glyph_get_attrs(), FREE_GLYPH_ATTR_TOTAL);
- return fgr;
- }
- struct free_glyph_render
- free_glyph_render_load_texture_atlas_or_exit(struct free_glyph_render fgr,
- FT_Face font_face)
- {
- struct vec2ui dim = free_glyph_render_calc_atlas_dimensions(font_face);
- fgr.atlas_dim = dim;
- glActiveTexture(GL_TEXTURE0);
- glGenTextures(1, &fgr.font_tex);
- glBindTexture(GL_TEXTURE_2D, fgr.font_tex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, (int32_t)dim.x, (int32_t)dim.y,
- 0, GL_RED, GL_UNSIGNED_BYTE, 0);
- FT_GlyphSlot g = font_face->glyph;
- uint64_t x = 0;
- for ( uint64_t i = 0; i < 128; ++i ) {
- if ( FT_Load_Char(font_face, i, FT_LOAD_RENDER) ) {
- fprintf(stderr, "[ERROR] Failed to load char: %c\n",
- (char)i);
- exit(EXIT_FAILURE);
- }
- if ( FT_Render_Glyph(g, FT_RENDER_MODE_NORMAL) ) {
- fprintf(stderr, "[ERROR] Failed to render char: %c\n",
- (char)i);
- exit(EXIT_FAILURE);
- }
- glTexSubImage2D(GL_TEXTURE_2D, 0, (int32_t) x, 0,
- (int32_t) g->bitmap.width,
- (int32_t) g->bitmap.rows,
- GL_RED, GL_UNSIGNED_BYTE,
- g->bitmap.buffer);
- fgr.g_infos[i] = (struct glyph_info) {
- .a = {
- .x = g->advance.x >> 6,
- .y = g->advance.y >> 6,
- },
- .b = {
- .w = g->bitmap.width,
- .h = g->bitmap.rows,
- .l = g->bitmap_left,
- .t = g->bitmap_top,
- },
- .tx = ((float) x) / ((float) dim.x),
- };
- x += g->bitmap.width;
- }
- return fgr;
- }
- struct vec2ui
- free_glyph_render_calc_atlas_dimensions(FT_Face font_face)
- {
- struct vec2ui dim = {0};
- for ( uint64_t i = 0; i < 128; ++i ) {
- if ( FT_Load_Char(font_face, i, FT_LOAD_RENDER) ) {
- fprintf(stderr, "[WARNING] Failed to load char: %c\n",
- (char)i);
- continue;
- }
- dim.x += font_face->glyph->bitmap.width;
- uint32_t row = font_face->glyph->bitmap.rows;
- dim.y = ( dim.y < row ) * row
- + ( ! (dim.y < row) ) * dim.y;
- }
- return dim;
- }
- #endif /* defined(FREE_GLYPH_IMP) || defined(IMP) */
- #endif
|