Pārlūkot izejas kodu

Extracting font to own file

Signed-off-by: Pikuinha <git@japa.boo>
Vinicius Teshima 1 gadu atpakaļ
vecāks
revīzija
aa73d9d92c
8 mainītis faili ar 426 papildinājumiem un 282 dzēšanām
  1. BIN
      charmap-oldschool_white.png
  2. 22 0
      src/app.h
  3. 158 0
      src/free_glyph.h
  4. 42 0
      src/glyph_attr.h
  5. 1 1
      src/keybind.h
  6. 19 281
      src/main.c
  7. 184 0
      src/tile_glyph.h
  8. BIN
      unifont-15.1.05.bmp

BIN
charmap-oldschool_white.png


+ 22 - 0
src/app.h

@@ -33,6 +33,11 @@ struct app {
 	} uniforms;
 };
 
+struct ret_app_vec2 {
+	struct app f1;
+	struct vec2 f2;
+};
+
 struct app app_create(const char *win_title);
 void app_destroy(struct app app);
 
@@ -57,6 +62,8 @@ void MessageCallback(GLenum source, GLenum type, GLuint id,
 
 struct vec2i app_calc_cursor(struct app app);
 
+struct ret_app_vec2 app_calc_buffer_cam(struct app app, double dt);
+
 #if defined(APP_IMP) || defined(IMP)
 
 #define UNHEX_COLOR(hex)			\
@@ -356,6 +363,21 @@ app_calc_cursor(struct app app)
 	return vec2i((int32_t)col, (int32_t)row);
 }
 
+struct ret_app_vec2
+app_calc_buffer_cam(struct app app, double dt)
+{
+	struct vec2 cur_pos = app_calc_cur_pos(app);
+	struct vec2 cpos = app.buf.cam.pos;
+	struct vec2 cvel = app.buf.cam.vel;
+	cvel = vec2_sub(cur_pos, cpos);
+	cpos = vec2_add(cpos, vec2_mul(cvel, vec2s(dt)));
+	app.buf.cam.pos = cpos;
+	app.buf.cam.vel = cvel;
+	return (struct ret_app_vec2) {
+		.f1 = app,
+		.f2 = cpos
+	};
+}
 
 #endif /* defined(APP_IMP) || defined(IMP) */
 

+ 158 - 0
src/free_glyph.h

@@ -0,0 +1,158 @@
+#ifndef TILE_GLYPH_H
+#define TILE_GLYPH_H
+
+#include "glyph_attr.h"
+
+struct free_glyph {
+	struct vec2f pos;
+	struct vec2f size;
+	int32_t ch;
+	struct vec4f fg_color;
+	struct vec4f bg_color;
+};
+
+DA_DEF_STRUCT(struct free_glyph, free_glyph_da);
+
+enum free_glyph_attr_enum {
+	FREE_GLYPH_ATTR_POS = 0,
+	FREE_GLYPH_ATTR_SIZE = 0,
+	FREE_GLYPH_ATTR_C,
+	FREE_GLYPH_ATTR_FG_COLOR,
+	FREE_GLYPH_ATTR_BG_COLOR,
+	FREE_GLYPH_ATTR_TOTAL
+};
+
+struct free_glyph_da free_glyph_da_create(void);
+const struct glyph_attr* free_glyph_get_attrs(void);
+
+struct free_glyph_da free_glyph_da_calc(struct app app,
+					struct free_glyph_da glys,
+					const char *cstr, size_t cstr_size,
+					struct vec2f pos,
+					struct vec2f size,
+					struct vec4f fg_color,
+					struct vec4f bg_color);
+struct free_glyph_da free_glyph_da_calc_buffer(struct app app,
+					       struct free_glyph_da glys,
+					       struct vec2f pos,
+					       struct vec2f size);
+void free_glyph_da_sync(struct app app, struct free_glyph_da glys);
+uint32_t tile_glyph_gen_buffer(struct free_glyph_da glys);
+
+#if defined(FREE_GLYPH_IMP) || defined(IMP)
+
+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 gly;
+}
+
+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_C] = {
+			.size = 1,
+			.type = GL_INT,
+			.norm = GL_FALSE,
+			.stride = sizeof(struct free_glyph),
+			.offset = offsetof(struct free_glyph, c)
+		},
+		[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;
+}
+
+struct free_glyph_da
+free_glyph_da_calc(struct app app, struct free_glyph_da glys,
+		   const char *cstr, size_t cstr_size,
+		   struct vec2f pos, struct vec2f size,
+		   struct vec4f fg_color, struct vec4f bg_color)
+{
+	(void) app;
+	for ( size_t i = 0; i < cstr_size; ++i ) {
+		char c = cstr[i];
+		if ( c == '\n' ) {
+			/* continue; */
+		}
+		struct free_glyph gly = {
+			.pos = pos,
+			.size = size,
+			.c = c,
+			.fg_color = fg_color,
+			.bg_color = bg_color
+		};
+		DA_APPEND(glys, gly);
+	}
+	return glys;
+}
+
+struct free_glyph_da
+free_glyph_da_calc_buffer(struct app app, struct free_glyph_da glys,
+			  struct vec2f pos, struct vec2f size)
+{
+	return free_glyph_da_calc(app, glys,
+				  app.buf.data.items, app.buf.data.size,
+				  pos, size, vec4fs(1), vec4fs(0));
+}
+
+void
+free_glyph_da_sync(struct app app, struct free_glyph_da glys)
+{
+	(void) app;
+	glBufferSubData(GL_ARRAY_BUFFER, 0,
+			(ssize_t) (glys.size * sizeof(struct free_glyph)),
+			glys.items);
+}
+
+uint32_t
+free_glyph_gen_buffer(struct free_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(free_glyph_get_attrs(), FREE_GLYPH_ATTR_TOTAL);
+	return id;
+}
+
+
+#endif /* defined(FREE_GLYPH_IMP) || defined(IMP) */
+
+#endif

+ 42 - 0
src/glyph_attr.h

@@ -0,0 +1,42 @@
+#ifndef GLYPH_ATTR_H
+#define GLYPH_ATTR_H
+
+struct glyph_attr {
+	GLint size;
+	GLenum type;
+	GLboolean norm;
+	GLsizei stride;
+	size_t offset;
+};
+
+void glyph_attr_declare(const struct glyph_attr *attrs, size_t size);
+
+#if defined(GLYPH_ATTR_IMP) || defined(IMP)
+
+void
+glyph_attr_declare(const struct glyph_attr *attrs, size_t size)
+{
+	for ( size_t i = 0; i < size; ++i ) {
+		struct glyph_attr ga = attrs[i];
+		glEnableVertexAttribArray((uint32_t) i);
+		switch ( ga.type ) {
+		case GL_FLOAT: {
+			glVertexAttribPointer((uint32_t) i,
+					      ga.size, ga.type,
+					      ga.norm, ga.stride,
+					      (void*)ga.offset);
+		} break;
+		case GL_INT: {
+			glVertexAttribIPointer((uint32_t) i,
+					       ga.size, ga.type,
+					       ga.stride,
+					       (void*)ga.offset);
+		} break;
+		}
+		glVertexAttribDivisor((uint32_t) i, 1);
+	}
+}
+
+#endif /* defined(GLYPH_ATTR_IMP) || defined(IMP) */
+
+#endif

+ 1 - 1
src/keybind.h

@@ -177,7 +177,7 @@ keybind_mv_cur_line(struct app app, union keybind_args args)
 		RET_UNWRAP2(index, err, struct ret_size_t_err,
 			    buffer_index_fw_char(app.buf,
 						 app.buf.cur, '\n'));
-		index = ( err == BUFFER_ERR_NOT_FOUND ) * app.buf.data.size
+		index = ( err != BUFFER_ERR_OK ) * (app.buf.data.size - 1)
 			+ ( err == BUFFER_ERR_OK ) * (index + 1);
 	} break;
 	case DIR_BACKWARD: {

+ 19 - 281
src/main.c

@@ -31,73 +31,10 @@
 #include "keybind.h"
 #include "config.h"
 #include "shader.h"
+#include "tile_glyph.h"
 
 struct app handle_events(struct app app);
 
-struct glyph {
-	struct vec2i tile;
-	int32_t c;
-	struct vec4f fg_color;
-	struct vec4f bg_color;
-};
-
-DA_DEF_STRUCT(struct glyph, glyphs);
-
-struct glyph_attr {
-	GLint size;
-	GLenum type;
-	GLboolean norm;
-	GLsizei stride;
-	size_t offset;
-};
-
-enum glyph_attr_enum {
-	GLYPH_ATTR_TILE = 0,
-	GLYPH_ATTR_C,
-	GLYPH_ATTR_FG_COLOR,
-	GLYPH_ATTR_BG_COLOR,
-	GLYPH_ATTR_TOTAL
-};
-
-static const struct glyph_attr glyph_attr[GLYPH_ATTR_TOTAL] = {
-	[GLYPH_ATTR_TILE] = {
-		.size = 2,
-		.type = GL_INT,
-		.norm = GL_FALSE,
-		.stride = sizeof(struct glyph),
-		.offset = offsetof(struct glyph, tile)
-	},
-	[GLYPH_ATTR_C] = {
-		.size = 1,
-		.type = GL_INT,
-		.norm = GL_FALSE,
-		.stride = sizeof(struct glyph),
-		.offset = offsetof(struct glyph, c)
-	},
-	[GLYPH_ATTR_FG_COLOR] = {
-		.size = 4,
-		.type = GL_FLOAT,
-		.norm = GL_FALSE,
-		.stride = sizeof(struct glyph),
-		.offset = offsetof(struct glyph, fg_color)
-	},
-	[GLYPH_ATTR_BG_COLOR] = {
-		.size = 4,
-		.type = GL_FLOAT,
-		.norm = GL_FALSE,
-		.stride = sizeof(struct glyph),
-		.offset = offsetof(struct glyph, bg_color)
-	},
-};
-
-struct glyphs _gl_render_text(struct app app, struct glyphs glys,
-			      const char *cstr, size_t cstr_size,
-			      struct vec2i tile,
-			      struct vec4f fg_color, struct vec4f bg_color);
-struct glyphs gl_render_text(struct app app, struct glyphs glys,
-			     struct vec2i tile);
-void glyphs_sync(struct app app, struct glyphs glys);
-
 int32_t get_uniform(uint32_t prog, const char *name);
 
 int32_t
@@ -112,7 +49,7 @@ main(int32_t argc, char **argv)
 	}
 
 	struct app app = app_create("ged");
-	const char *font_path = "./charmap-oldschool_white.png";
+	const char *font_path = "./fonts/charmap-oldschool_white.png";
 	app.font = font_create(app.rdr, font_path, 7, 18);
 	app.font.scale = 4.0;
 
@@ -124,10 +61,7 @@ main(int32_t argc, char **argv)
 		exit(EXIT_FAILURE);
 	}
 
-	struct glyphs glys;
-	glys.cap = 1024 * 1024;
-	glys.size = 0;
-	glys.items = calloc(glys.cap, sizeof(struct glyph));
+	struct tile_glyph_da glys = tile_glyph_da_create();
 
 	uint32_t prog;
 	uint32_t vert_shader;
@@ -161,36 +95,8 @@ main(int32_t argc, char **argv)
 
 	glUseProgram(prog);
 
-	uint32_t font_tex = 0;
-	/* Init Font Texture */
-	{
-		int32_t w, h, n;
-		uint8_t *data = stbi_load(font_path,
-					  &w, &h, &n,
-					  STBI_rgb_alpha);
-
-		if ( data == NULL ) {
-			fprintf(stderr, "ERROR loading file %s: %s",
-				font_path, stbi_failure_reason());
-			exit(EXIT_FAILURE);
-		}
-
-		glActiveTexture(GL_TEXTURE0);
-		glGenTextures(1, &font_tex);
-		glBindTexture(GL_TEXTURE_2D, font_tex);
-		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);
-	}
+	uint32_t font_tex = tile_glyph_load_texture_atlas(font_path);
+	(void) font_tex;
 
 	/* Getting the uniforms */
 	app.uniforms.time = get_uniform(prog, "time");
@@ -206,34 +112,8 @@ main(int32_t argc, char **argv)
 	{
 		glGenVertexArrays(1, &vao);
 		glBindVertexArray(vao);
-
-		glGenBuffers(1, &vbo);
-		glBindBuffer(GL_ARRAY_BUFFER, vbo);
-		glBufferData(GL_ARRAY_BUFFER,
-			     (ssize_t)(glys.cap * sizeof(struct glyph)),
-			     glys.items,
-			     GL_DYNAMIC_DRAW);
-
-		for ( size_t i = 0; i < GLYPH_ATTR_TOTAL; ++i ) {
-			struct glyph_attr ga = glyph_attr[i];
-			glEnableVertexAttribArray((uint32_t) i);
-			switch ( ga.type ) {
-			case GL_FLOAT: {
-				glVertexAttribPointer((uint32_t) i,
-						      ga.size, ga.type,
-						      ga.norm, ga.stride,
-						      (void*)ga.offset);
-			} break;
-			case GL_INT: {
-				glVertexAttribIPointer((uint32_t) i,
-						       ga.size, ga.type,
-						       ga.stride,
-						       (void*)ga.offset);
-			} break;
-			}
-			glVertexAttribDivisor((uint32_t) i, 1);
-		}
-
+		vbo = tile_glyph_gen_buffer(glys);
+		(void) vbo;
 	}
 
 	glUniform1f(app.uniforms.scale, (float)app.font.scale);
@@ -268,21 +148,18 @@ main(int32_t argc, char **argv)
 
 		/* Calc Camera */
 		{
-			struct vec2 cur_pos = app_calc_cur_pos(app);
-			struct vec2 cpos = buf->cam.pos;
-			struct vec2 cvel = buf->cam.vel;
-			cvel = vec2_sub(cur_pos, cpos);
-			cpos = vec2_add(cpos, vec2_mul(cvel, vec2s(dt)));
-			buf->cam.pos = cpos;
-			buf->cam.vel = cvel;
+			struct vec2 cpos;
+			RET_UNWRAP2(app, cpos,
+				    struct ret_app_vec2,
+				    app_calc_buffer_cam(app, dt));
 			glUniform2f(app.uniforms.camera,
 				    (float)cpos.x,
 				    (float)cpos.y);
 		}
 
 		glys.size = 0;
-		glys = gl_render_text(app, glys, vec2is(0));
-		glyphs_sync(app, glys);
+		glys = tile_glyph_da_calc_buffer(app, glys, vec2is(0));
+		tile_glyph_da_sync(app, glys);
 		glDrawArraysInstanced(GL_TRIANGLE_STRIP,
 				      0, 4,
 				      (int32_t) glys.size);
@@ -296,12 +173,12 @@ main(int32_t argc, char **argv)
 
 			const char *c = buf->data.items + buf->cur;
 			glys.size = 0;
-			glys = _gl_render_text(app, glys,
-					       ( *c == '\n' ) ? " " : c, 1,
-					       vec2i((int32_t)col,
-						     -(int32_t)row),
-					       vec4fs(0), vec4fs(1));
-			glyphs_sync(app, glys);
+			glys = tile_glyph_da_calc(app, glys,
+						  ( *c == '\n' ) ? " " : c, 1,
+						  vec2i((int32_t)col,
+							-(int32_t)row),
+						  vec4fs(0), vec4fs(1));
+			tile_glyph_da_sync(app, glys);
 			glDrawArraysInstanced(GL_TRIANGLE_STRIP,
 					      0, 4,
 					      (int32_t) glys.size);
@@ -323,52 +200,6 @@ main(int32_t argc, char **argv)
 	exit(EXIT_SUCCESS);
 }
 
-struct glyphs
-_gl_render_text(struct app app, struct glyphs 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 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 glyphs
-gl_render_text(struct app app, struct glyphs glys, struct vec2i tile)
-{
-	return _gl_render_text(app, glys,
-			       app.buf.data.items, app.buf.data.size,
-			       tile, vec4fs(1), vec4fs(0));
-}
-
-void
-glyphs_sync(struct app app, struct glyphs glys)
-{
-	(void) app;
-	glBufferSubData(GL_ARRAY_BUFFER,
-			0,
-			(ssize_t) (glys.size * sizeof(struct glyph)),
-			glys.items);
-}
-
 int32_t
 get_uniform(uint32_t prog, const char *name)
 {
@@ -381,99 +212,6 @@ get_uniform(uint32_t prog, const char *name)
 	return uni;
 }
 
-int32_t main2(int32_t argc, char **argv);
-int32_t
-main2(int32_t argc, char **argv)
-{
-	srand((uint32_t) time(NULL));
-	if ( argc != 2 ) {
-		fprintf(stderr, "MUST pass file to open\n");
-		exit(EXIT_FAILURE);
-	}
-	/* (void) argc; (void) argv; */
-
-	SCE(SDL_Init(SDL_INIT_VIDEO));
-
-	const char *font_path = "./charmap-oldschool_white.png";
-
-	struct app app = app_create("ged");
-
-	app.font = font_create(app.rdr, font_path, 7, 18);
-	app.font.scale = 2.0;
-
-	/* const char *filepath = "./src/main.c"; */
-	enum buffer_err err;
-	RET_UNWRAP2(app.buf, err,
-		    struct ret_buffer_err,
-		    buffer_load_from_file(app.buf, argv[1]));
-	if ( err != BUFFER_ERR_OK ) {
-		printf("%d\n", err);
-		fprintf(stderr, "Failed to open buffer\n");
-		exit(EXIT_FAILURE);
-	}
-	(void) err;
-
-	uint64_t i = 0;
-	double dt = (1.0 / (double)app.target_fps) * 3;
-	uint32_t frame_target_dur = (uint32_t)(1000 / app.target_fps);
-
-	char *fps_text = calloc(1, 128);
-	size_t fps_text_size = 0;
-
-	uint32_t fr_end = 0;
-	uint32_t fr_start = 0;
-	uint32_t fr_dur = 1;
-	while ( app.running == true ) {
-		fr_start = SDL_GetTicks();
-		struct buffer *buf = &app.buf;
-		app = handle_events(app);
-
-		SCE(SDL_SetRenderDrawColor(app.rdr, 0x0, 0, 0, 1));
-		SCE(SDL_RenderClear(app.rdr));
-
-		if ( app.show_fps == true ) {
-			fps_text_size = (size_t) snprintf(fps_text, 128,
-							  "FPS: %.2f",
-							  1000.0 / fr_dur);
-			app_render_text(app, fps_text, fps_text_size,
-					vec2s(0), 0xFF00FFFF, 5);
-		}
-
-		{
-			struct vec2 cur_pos = app_calc_cur_pos(app);
-			cur_pos = vec2_sub(vec2(app.win.hw, app.win.hh),
-					   cur_pos);
-			struct vec2 cpos = buf->cam.pos;
-			struct vec2 cvel = buf->cam.vel;
-			cvel = vec2_sub(cur_pos, cpos);
-			cpos = vec2_add(cpos, vec2_mul(cvel, vec2s(dt)));
-			buf->cam.pos = cpos;
-			buf->cam.vel = cvel;
-		}
-
-		app_render_buffer(app, buf->cam.pos, (uint32_t)
-				  (0xFF << 24)
-				  | (0xFF << 16)
-				  | (0xFF << 8 )
-				  | 0xFF
-				  /* 0xFFFFFFFF */, app.font.scale);
-
-		SDL_RenderPresent(app.rdr);
-		fr_end = SDL_GetTicks();
-		fr_dur = (fr_end - fr_start);
-		if ( fr_dur < frame_target_dur ) {
-			SDL_Delay(frame_target_dur - fr_dur);
-		}
-		++i;
-	}
-
-	SDL_DestroyWindow(app.win.ptr);
-	DA_DESTROY(app.buf.data);
-	SDL_Quit();
-	exit(EXIT_SUCCESS);
-}
-
-
 struct app
 handle_events(struct app app)
 {

+ 184 - 0
src/tile_glyph.h

@@ -0,0 +1,184 @@
+#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 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);
+
+#if defined(TILE_GLYPH_IMP) || defined(IMP)
+
+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;
+}
+
+#endif /* defined(TILE_GLYPH_IMP) || defined(IMP) */
+
+#endif

BIN
unifont-15.1.05.bmp