浏览代码

FreeType rendering Working

Vinicius Teshima 1 年之前
父节点
当前提交
0c03788acf
共有 6 个文件被更改,包括 243 次插入46 次删除
  1. 12 3
      shaders/free_font.frag
  2. 11 9
      shaders/free_font.vert
  3. 170 28
      src/free_glyph.h
  4. 1 1
      src/keybind.h
  5. 37 5
      src/main.c
  6. 12 0
      src/vec2.h

+ 12 - 3
shaders/free_font.frag

@@ -10,13 +10,16 @@
 #define FONT_CH_H_UV (float(FONT_CH_H) / float(FONT_HEIGHT))
 
 uniform sampler2D font;
+
 uniform float time;
 uniform vec2 resolution;
 
-flat in int glyph_c;
+in vec2 uv;
+
+in vec2 glyph_uv_pos;
+in vec2 glyph_uv_size;
 in vec4 glyph_fg_color;
 in vec4 glyph_bg_color;
-in vec2 uv;
 
 float map01(float x)
 {
@@ -32,5 +35,11 @@ vec3 hsl2rgb( in vec3 c )
 }
 
 void main() {
-	gl_FragColor = vec4(1,0,0,1);
+	// vec2 t = glyph_uv_pos + glyph_uv_size * uv;
+	// gl_FragColor = vec4(texture(font, t).x, 0, 0, 1);
+	vec2 t = glyph_uv_pos + glyph_uv_size * uv;
+	vec4 tc = texture(font, t);
+	vec2 frag_uv = gl_FragCoord.xy / resolution;
+	vec4 rainbow = vec4(hsl2rgb(vec3((time + frag_uv.x + frag_uv.y), 0.5, 0.5)), 1.0);
+	gl_FragColor = glyph_bg_color * (1.0 - tc.x) + tc.x * glyph_fg_color * rainbow;
 }

+ 11 - 9
shaders/free_font.vert

@@ -7,19 +7,20 @@
 #define FONT_CH_W (FONT_WIDTH / FONT_COLS)
 #define FONT_CH_H (FONT_HEIGHT / FONT_ROWS)
 
-uniform float scale;
 uniform vec2 resolution;
 uniform float time;
 uniform vec2 camera;
 
-layout(location = 0) in ivec2 pos;
-layout(location = 1) in ivec2 size;
-layout(location = 2) in int c;
-layout(location = 3) in vec4 fg_color;
-layout(location = 4) in vec4 bg_color;
+layout(location = 0) in vec2 pos;
+layout(location = 1) in vec2 size;
+layout(location = 2) in vec2 uv_pos;
+layout(location = 3) in vec2 uv_size;
+layout(location = 4) in vec4 fg_color;
+layout(location = 5) in vec4 bg_color;
 
 out vec2 uv;
-flat out int glyph_c;
+out vec2 glyph_uv_pos;
+out vec2 glyph_uv_size;
 out vec4 glyph_fg_color;
 out vec4 glyph_bg_color;
 
@@ -33,9 +34,10 @@ void main()
 	uv = vec2(float(gl_VertexID & 1),
 		  float((gl_VertexID >> 1) & 1));
 
-	gl_Position = vec4(uv- 0.5, 0.0, 1.0);
+	gl_Position = vec4(project_point(uv * size + pos), 0.0, 1.0);
 
-	glyph_c = c;
+	glyph_uv_pos = uv_pos;
+	glyph_uv_size = uv_size;
 	glyph_fg_color = fg_color;
 	glyph_bg_color = bg_color;
 }

+ 170 - 28
src/free_glyph.h

@@ -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

+ 1 - 1
src/keybind.h

@@ -54,7 +54,7 @@ struct app
 keybind_save_buffer(struct app app, union keybind_args args)
 {
 	(void) args;
-	buffer_save(app.buf);
+	/* buffer_save(app.buf); */
 	return app;
 }
 

+ 37 - 5
src/main.c

@@ -61,6 +61,7 @@ main(int32_t argc, char **argv)
 
 	const char *ffont_path = "./fonts/VictorMono-Regular.ttf";
 
+	FT_Face face;
 	{
 		FT_Error error = FT_Init_FreeType( &library );
 		if ( error ) {
@@ -69,7 +70,6 @@ main(int32_t argc, char **argv)
 			exit(EXIT_FAILURE);
 		}
 
-		FT_Face face;
 		error = FT_New_Face(library, ffont_path, 0, &face);
 		if ( error == FT_Err_Unknown_File_Format ) {
 			fprintf(stderr, "[ERROR] Font %s has unknown format\n",
@@ -81,7 +81,7 @@ main(int32_t argc, char **argv)
 			exit(EXIT_FAILURE);
 		}
 
-		FT_UInt pixel_size = 64;
+		FT_UInt pixel_size = 32;
 		error = FT_Set_Pixel_Sizes(face, 0, pixel_size);
 		if ( error ) {
 			fprintf(stderr, "[ERROR] Failed to set font size: %u\n",
@@ -108,7 +108,7 @@ main(int32_t argc, char **argv)
 	/* 	"./shaders/tile_font.vert", */
 	/* 	"./shaders/tile_font.frag"); */
 	struct free_glyph_render fgr = free_glyph_render_create(
-		ffont_path,
+		face,
 		"./shaders/free_font.vert",
 		"./shaders/free_font.frag");
 
@@ -128,7 +128,7 @@ main(int32_t argc, char **argv)
 		fr_start = SDL_GetTicks();
 
 		/* app = handle_events(app, tgr.uniforms.resolution); */
-		app = handle_events(app, -1);
+		app = handle_events(app, fgr.uniforms.resolution);
 
 		if ( app.show_fps == true ) {
 			fps_text_size = (size_t) snprintf(fps_text, 128,
@@ -260,6 +260,38 @@ struct free_glyph_render
 render_buffer_into_fgr(struct free_glyph_render fgr, struct app app,
 		       struct vec2 cpos)
 {
-	(void) fgr; (void) app; (void) cpos;
+	glUniform2f(fgr.uniforms.camera,
+		    (float)cpos.x,
+		    (float)cpos.y);
+
+	fgr.glyphs.size = 0;
+	fgr = free_glyph_render_calc_buffer(fgr, app, vec2fs(0));
+	free_glyph_render_sync(fgr);
+	glDrawArraysInstanced(GL_TRIANGLE_STRIP,
+			      0, 4,
+			      (int32_t) fgr.glyphs.size);
+
+	/* { */
+	/* 	size_t col = 0; */
+	/* 	size_t row = 0; */
+	/* 	RET_UNWRAP2(col, row, */
+	/* 		    struct ret_size_t_size_t, */
+	/* 		    buffer_calc_cur_pos(app.buf)); */
+
+	/* 	const char *c = app.buf.data.items + app.buf.cur; */
+	/* 	fgr.glyphs.size = 0; */
+	/* 	fgr = free_glyph_render_calc(fgr, app, */
+	/* 				     ( *c == '\n' ) ? " " : c, 1, */
+	/* 				     vec2f((float)col, */
+	/* 					   -(float)(row*fgr.atlas_dim.y)), */
+	/* 				     vec4fs(0), vec4fs(1)); */
+	/* 	free_glyph_render_sync(fgr); */
+	/* 	glDrawArraysInstanced(GL_TRIANGLE_STRIP, */
+	/* 			      0, 4, */
+	/* 			      (int32_t) fgr.glyphs.size); */
+	/* } */
+	uint32_t ticks = SDL_GetTicks();
+	glUniform1f(fgr.uniforms.time,
+		    ((float) ticks) / 1000.0f);
 	return fgr;
 }

+ 12 - 0
src/vec2.h

@@ -20,11 +20,15 @@ struct _NAME _NAME##_div(struct _NAME a, struct _NAME b);
 
 _CREATE_DECLARATION(vec2, double)
 _CREATE_DECLARATION(vec2f, float)
+
 struct vec2f vec2_to_f(struct vec2 a);
 
 _CREATE_DECLARATION(vec2i, int32_t)
+_CREATE_DECLARATION(vec2i64, int64_t)
 _CREATE_DECLARATION(vec2ui, uint32_t)
 
+struct vec2f vec2f_from_ui(struct vec2ui a);
+
 #undef _CREATE_DECLARATION
 
 #if defined(VEC2_IMP) || defined(IMP)
@@ -78,6 +82,13 @@ _NAME##_div(struct _NAME a, struct _NAME b)				\
 
 _CREATE_DEFINITION(vec2, double)
 _CREATE_DEFINITION(vec2f, float)
+
+struct vec2f
+vec2f_from_ui(struct vec2ui a)
+{
+	return (struct vec2f) { .x = (float) a.x, .y = (float) a.y };
+}
+
 struct vec2f
 vec2_to_f(struct vec2 a)
 {
@@ -86,6 +97,7 @@ vec2_to_f(struct vec2 a)
 
 
 _CREATE_DEFINITION(vec2i, int32_t)
+_CREATE_DEFINITION(vec2i64, int64_t)
 _CREATE_DEFINITION(vec2ui, uint32_t)
 
 #undef _CREATE_DEFINITION