|
|
@@ -1,13 +1,33 @@
|
|
|
#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 "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;
|
|
|
- int32_t c;
|
|
|
+ struct vec2f uv_pos;
|
|
|
+ struct vec2f uv_size;
|
|
|
struct vec4f fg_color;
|
|
|
struct vec4f bg_color;
|
|
|
};
|
|
|
@@ -15,6 +35,8 @@ struct free_glyph {
|
|
|
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;
|
|
|
@@ -28,19 +50,22 @@ struct free_glyph_render {
|
|
|
} 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_C,
|
|
|
+ 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(const char *font_path,
|
|
|
+struct free_glyph_render free_glyph_render_create(FT_Face font_face,
|
|
|
const char *vert_path,
|
|
|
const char *frag_path);
|
|
|
|
|
|
@@ -48,28 +73,33 @@ struct free_glyph_da free_glyph_da_create(void);
|
|
|
const struct glyph_attr* free_glyph_get_attrs(void);
|
|
|
|
|
|
struct free_glyph_render free_glyph_render_calc(
|
|
|
- struct free_glyph_render fgr, const char *cstr, size_t cstr_size,
|
|
|
- struct vec2f pos, struct vec2f size,
|
|
|
+ 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, struct vec2f size);
|
|
|
+ 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 "gl_util.h"
|
|
|
|
|
|
struct free_glyph_render
|
|
|
-free_glyph_render_create(const char *font_path, const char *vert_path,
|
|
|
+free_glyph_render_create(FT_Face font_face, const char *vert_path,
|
|
|
const char *frag_path)
|
|
|
{
|
|
|
- (void) font_path;
|
|
|
struct free_glyph_render fgr = {0};
|
|
|
- /* fgr = free_glyph_render_load_texture_atlas_or_exit(fgr, font_path); */
|
|
|
+ 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(
|
|
|
@@ -80,9 +110,9 @@ free_glyph_render_create(const char *font_path, const char *vert_path,
|
|
|
|
|
|
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.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);
|
|
|
|
|
|
@@ -118,12 +148,19 @@ free_glyph_get_attrs(void)
|
|
|
.stride = sizeof(struct free_glyph),
|
|
|
.offset = offsetof(struct free_glyph, size)
|
|
|
},
|
|
|
- [FREE_GLYPH_ATTR_C] = {
|
|
|
- .size = 1,
|
|
|
- .type = GL_INT,
|
|
|
+ [FREE_GLYPH_ATTR_UV_POS] = {
|
|
|
+ .size = 2,
|
|
|
+ .type = GL_FLOAT,
|
|
|
.norm = GL_FALSE,
|
|
|
.stride = sizeof(struct free_glyph),
|
|
|
- .offset = offsetof(struct free_glyph, c)
|
|
|
+ .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,
|
|
|
@@ -145,35 +182,57 @@ free_glyph_get_attrs(void)
|
|
|
}
|
|
|
|
|
|
struct free_glyph_render
|
|
|
-free_glyph_render_calc(struct free_glyph_render fgr,
|
|
|
- const char *cstr, size_t cstr_size,
|
|
|
- struct vec2f pos, struct vec2f size,
|
|
|
+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' ) {
|
|
|
- /* continue; */
|
|
|
+ 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 = pos,
|
|
|
- .size = size,
|
|
|
- .c = c,
|
|
|
+ .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
|
|
|
+ .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 pos, struct vec2f size)
|
|
|
+free_glyph_render_calc_buffer(struct free_glyph_render fgr,
|
|
|
+ struct app app,
|
|
|
+ struct vec2f size)
|
|
|
{
|
|
|
- return free_glyph_render_calc(fgr,
|
|
|
+ return free_glyph_render_calc(fgr, app,
|
|
|
app.buf.data.items, app.buf.data.size,
|
|
|
- pos, size, vec4fs(1), vec4fs(0));
|
|
|
+ size, vec4fs(1), vec4fs(0));
|
|
|
}
|
|
|
|
|
|
void
|
|
|
@@ -200,6 +259,89 @@ free_glyph_render_gen_buffer(struct free_glyph_render fgr)
|
|
|
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
|