#ifndef TILE_GLYPH_H #define TILE_GLYPH_H #include "glyph_attr.h" struct tile_glyph { struct vec2i tile; int32_t c; struct vec4f fg_color; struct vec4f bg_color; }; DA_DEF_STRUCT(struct tile_glyph, tile_glyph_da); enum tile_glyph_attr_enum { TILE_GLYPH_ATTR_TILE = 0, TILE_GLYPH_ATTR_C, TILE_GLYPH_ATTR_FG_COLOR, TILE_GLYPH_ATTR_BG_COLOR, TILE_GLYPH_ATTR_TOTAL }; struct ret_uint32_t_uint32_t { uint32_t f1; uint32_t f2; }; struct tile_glyph_da tile_glyph_da_create(void); const struct glyph_attr* tile_glyph_get_attrs(void); struct tile_glyph_da tile_glyph_da_calc(struct app app, struct tile_glyph_da glys, const char *cstr, size_t cstr_size, struct vec2i tile, struct vec4f fg_color, struct vec4f bg_color); struct tile_glyph_da tile_glyph_da_calc_buffer(struct app app, struct tile_glyph_da glys, struct vec2i tile); void tile_glyph_da_sync(struct app app, struct tile_glyph_da glys); uint32_t tile_glyph_gen_buffer(struct tile_glyph_da glys); uint32_t tile_glyph_load_texture_atlas(const char *filepath); struct ret_uint32_t_uint32_t tile_glyph_compile_shaders_or_exit(void); #if defined(TILE_GLYPH_IMP) || defined(IMP) #ifdef STB_IMAGE_IMPLEMENTATION #undef STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define STB_IMAGE_IMPLEMENTATION #else #include "stb_image.h" #endif #include "unwrap.h" struct tile_glyph_da tile_glyph_da_create(void) { struct tile_glyph_da glys; glys.cap = 1024 * 1024; glys.size = 0; glys.items = calloc(glys.cap, sizeof(struct tile_glyph)); return glys; } const struct glyph_attr * tile_glyph_get_attrs(void) { static const struct glyph_attr tile_glyph_attr[TILE_GLYPH_ATTR_TOTAL] = { [TILE_GLYPH_ATTR_TILE] = { .size = 2, .type = GL_INT, .norm = GL_FALSE, .stride = sizeof(struct tile_glyph), .offset = offsetof(struct tile_glyph, tile) }, [TILE_GLYPH_ATTR_C] = { .size = 1, .type = GL_INT, .norm = GL_FALSE, .stride = sizeof(struct tile_glyph), .offset = offsetof(struct tile_glyph, c) }, [TILE_GLYPH_ATTR_FG_COLOR] = { .size = 4, .type = GL_FLOAT, .norm = GL_FALSE, .stride = sizeof(struct tile_glyph), .offset = offsetof(struct tile_glyph, fg_color) }, [TILE_GLYPH_ATTR_BG_COLOR] = { .size = 4, .type = GL_FLOAT, .norm = GL_FALSE, .stride = sizeof(struct tile_glyph), .offset = offsetof(struct tile_glyph, bg_color) }, }; return tile_glyph_attr; } struct tile_glyph_da tile_glyph_da_calc(struct app app, struct tile_glyph_da glys, const char *cstr, size_t cstr_size, struct vec2i tile, struct vec4f fg_color, struct vec4f bg_color) { (void) app; struct vec2i pen = tile; int32_t row = 0; for ( size_t i = 0; i < cstr_size; ++i ) { char c = cstr[i]; if ( c == '\n' ) { pen.y -= 1; row = 0; continue; } struct tile_glyph gly = { .tile = vec2i_add(pen, vec2i(row, 0)), .c = c, .fg_color = fg_color, .bg_color = bg_color }; DA_APPEND(glys, gly); ++row; } return glys; } struct tile_glyph_da tile_glyph_da_calc_buffer(struct app app, struct tile_glyph_da glys, struct vec2i tile) { return tile_glyph_da_calc(app, glys, app.buf.data.items, app.buf.data.size, tile, vec4fs(1), vec4fs(0)); } void tile_glyph_da_sync(struct app app, struct tile_glyph_da glys) { (void) app; glBufferSubData(GL_ARRAY_BUFFER, 0, (ssize_t) (glys.size * sizeof(struct tile_glyph)), glys.items); } uint32_t tile_glyph_gen_buffer(struct tile_glyph_da glys) { uint32_t id = 0; glGenBuffers(1, &id); glBindBuffer(GL_ARRAY_BUFFER, id); glBufferData(GL_ARRAY_BUFFER, (ssize_t)(glys.cap * sizeof(struct tile_glyph)), glys.items, GL_DYNAMIC_DRAW); glyph_attr_declare(tile_glyph_get_attrs(), TILE_GLYPH_ATTR_TOTAL); return id; } uint32_t tile_glyph_load_texture_atlas(const char *filepath) { uint32_t id; int32_t w, h, n; uint8_t *data = stbi_load(filepath, &w, &h, &n, STBI_rgb_alpha); if ( data == NULL ) { fprintf(stderr, "ERROR loading file %s: %s", filepath, stbi_failure_reason()); exit(EXIT_FAILURE); } glActiveTexture(GL_TEXTURE0); glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); return id; } struct ret_uint32_t_uint32_t tile_glyph_compile_shaders_or_exit(void) { return (struct ret_uint32_t_uint32_t) { .f1 = shader_compile_file_or_exit("./shaders/tile_font.vert", GL_VERTEX_SHADER), .f2 = shader_compile_file_or_exit("./shaders/tile_font.frag", GL_FRAGMENT_SHADER), }; } #endif /* defined(TILE_GLYPH_IMP) || defined(IMP) */ #endif