summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gl.c38
-rw-r--r--main.c78
-rw-r--r--text.c116
-rw-r--r--text.h2
4 files changed, 134 insertions, 100 deletions
diff --git a/gl.c b/gl.c
index 41e29e5..1f5d7bc 100644
--- a/gl.c
+++ b/gl.c
@@ -138,7 +138,6 @@ static GLSimpleTriangle *gl_geometry_triangles;
static GLuint gl_geometry_program;
static GLuint gl_geometry_v_pos;
static GLuint gl_geometry_v_color;
-static GLint gl_geometry_u_window_size;
static GLuint gl_geometry_vbo, gl_geometry_vao;
static void gl_geometry_init(void) {
@@ -146,11 +145,8 @@ static void gl_geometry_init(void) {
attribute vec2 v_pos;\n\
attribute vec4 v_color;\n\
varying vec4 color;\n\
- uniform vec2 window_size;\n\
void main() {\n\
- float x = v_pos.x / window_size.x * 2.0 - 1.0;\n\
- float y = 1.0 - v_pos.y / window_size.y * 2.0;\n\
- gl_Position = vec4(x, y, 0.0, 1.0);\n\
+ gl_Position = vec4(v_pos, 0.0, 1.0);\n\
color = v_color;\n\
}\n\
";
@@ -164,39 +160,54 @@ static void gl_geometry_init(void) {
gl_geometry_program = gl_compile_and_link_shaders(vshader_code, fshader_code);
gl_geometry_v_pos = gl_attrib_loc(gl_geometry_program, "v_pos");
gl_geometry_v_color = gl_attrib_loc(gl_geometry_program, "v_color");
- gl_geometry_u_window_size = gl_uniform_loc(gl_geometry_program, "window_size");
glGenBuffers(1, &gl_geometry_vbo);
if (gl_version_major >= 3)
glGenVertexArrays(1, &gl_geometry_vao);
}
+static float gl_window_width, gl_window_height;
+
+static void gl_convert_to_ndc(v2 *pos) {
+ pos->x = pos->x / gl_window_width * 2.0f - 1.0f;
+ pos->y = 1.0f - pos->y / gl_window_height * 2.0f;
+}
+
static void gl_geometry_rect(Rect r, u32 color_rgba) {
v4 color = rgba_u32_to_v4(color_rgba);
v2 p1 = r.pos;
v2 p2 = v2_add(r.pos, V2(0, r.size.y));
v2 p3 = v2_add(r.pos, V2(r.size.x, r.size.y));
- v2 p4 = p3;
- v2 p5 = v2_add(r.pos, V2(r.size.x, 0));
- v2 p6 = p1;
+ v2 p4 = v2_add(r.pos, V2(r.size.x, 0));
+
GLSimpleTriangle triangle = {
{p1, color},
{p2, color},
{p3, color}
};
arr_add(gl_geometry_triangles, triangle);
- triangle.v1.pos = p4;
- triangle.v2.pos = p5;
- triangle.v3.pos = p6;
+ triangle.v1.pos = p3;
+ triangle.v2.pos = p4;
+ triangle.v3.pos = p1;
arr_add(gl_geometry_triangles, triangle);
}
-static void gl_geometry_draw(Ted *ted) {
+static void gl_geometry_draw(void) {
size_t ntriangles = arr_len(gl_geometry_triangles);
+
+ // convert coordinates to NDC
+ for (size_t i = 0; i < ntriangles; ++i) {
+ GLSimpleTriangle *triangle = &gl_geometry_triangles[i];
+ gl_convert_to_ndc(&triangle->v1.pos);
+ gl_convert_to_ndc(&triangle->v2.pos);
+ gl_convert_to_ndc(&triangle->v3.pos);
+ }
+
if (gl_version_major >= 3)
glBindVertexArray(gl_geometry_vao);
+
glBindBuffer(GL_ARRAY_BUFFER, gl_geometry_vbo);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(ntriangles * sizeof(GLSimpleTriangle)), gl_geometry_triangles, GL_STREAM_DRAW);
glVertexAttribPointer(gl_geometry_v_pos, 2, GL_FLOAT, 0, sizeof(GLSimpleVertex), (void *)offsetof(GLSimpleVertex, pos));
@@ -205,7 +216,6 @@ static void gl_geometry_draw(Ted *ted) {
glEnableVertexAttribArray(gl_geometry_v_color);
glUseProgram(gl_geometry_program);
- glUniform2f(gl_geometry_u_window_size, ted->window_width, ted->window_height);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)(3 * ntriangles));
arr_clear(gl_geometry_triangles);
diff --git a/main.c b/main.c
index 49f4730..92d6b23 100644
--- a/main.c
+++ b/main.c
@@ -283,96 +283,42 @@ int main(int argc, char **argv) {
#endif
gl_geometry_init();
+ text_init();
SDL_GL_SetSwapInterval(1); // vsync
- #if 0
- float vertices[][6] = {
- {0, 0, 1, 0, 0, 1},
- {50, 0, 0, 1, 0, 1},
- {0, 50, 0, 0, 1, 1},
- };
- char const *vshader_code = "#version 110\n\
- attribute vec2 v_pos;\n\
- attribute vec4 v_color;\n\
- varying vec4 color;\n\
- uniform vec2 window_size;\n\
- void main() {\n\
- float x = v_pos.x / window_size.x * 2.0 - 1.0;\n\
- float y = 1.0 - v_pos.y / window_size.y * 2.0;\n\
- gl_Position = vec4(x, y, 0.0, 1.0);\n\
- color = v_color;\n\
- }\n\
- ";
- char const *fshader_code = "#version 110\n\
- varying vec4 color;\n\
- void main() {\n\
- gl_FragColor = color;\n\
- }\n\
- ";
- GLuint program = gl_compile_and_link_shaders(vshader_code, fshader_code);
- GLuint v_pos = gl_attrib_loc(program, "v_pos");
- GLuint v_color = gl_attrib_loc(program, "v_color");
- GLint u_window_size = gl_uniform_loc(program, "window_size");
-
- GLuint vbo = 0, vao = 0;
- glGenBuffers(1, &vbo);
- glGenVertexArrays(1, &vao);
-
- glBindVertexArray(vao);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW);
- glVertexAttribPointer(v_pos, 2, GL_FLOAT, 0, 6 * sizeof(float), (void *)0);
- glEnableVertexAttribArray(v_pos);
- glVertexAttribPointer(v_color, 4, GL_FLOAT, 0, 6 * sizeof(float), (void *)(2 * sizeof(float)));
- glEnableVertexAttribArray(v_color);
- glBindVertexArray(0);
-
- while (1) {
- int w, h;
- SDL_GetWindowSize(window, &w, &h);
-
- SDL_Event event;
- while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) return 0;
-
- glViewport(0, 0, w, h);
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
-
-
- glUseProgram(program);
- glUniform2f(u_window_size, (float)w, (float)h);
- glBindVertexArray(vao);
-
- glDrawArrays(GL_TRIANGLES, 0, 3);
- SDL_GL_SwapWindow(window);
+ Font *font = text_font_load("assets/font.ttf", 16);
+ if (!font) {
+ die("%s", text_get_err());
}
- #endif
while (1) {
int w, h;
SDL_GetWindowSize(window, &w, &h);
ted->window_width = (float)w;
ted->window_height = (float)h;
+ gl_window_width = (float)w, gl_window_height = (float)h;
SDL_Event event;
while (SDL_PollEvent(&event)) if (event.type == SDL_QUIT) return 0;
+ (void)settings;
glViewport(0, 0, w, h);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
- for (int i = 0; i < 20; ++i) {
- gl_geometry_rect(rect(V2(0, 10*(float)i), V2(100, 100)), 0xffffffff >> i);
+ for (int i = 0; i < 200; ++i) {
+ gl_geometry_rect(rect(V2(0, 4*(float)i), V2(100, 100)), 0xffffffff >> i);
- gl_geometry_draw(ted);
+ gl_geometry_draw();
}
+ text_render(font, "hello", 5, 5);
SDL_GL_SwapWindow(window);
}
return 0;
-
+#if 0
ted_load_fonts(ted);
if (ted_haserr(ted))
die("Error loading font: %s", ted_geterr(ted));
@@ -456,6 +402,7 @@ int main(int argc, char **argv) {
ted->window_height = (float)window_height_int;
}
window_width = ted->window_width, window_height = ted->window_height;
+ gl_window_width = window_width, gl_window_height = window_height;
while (SDL_PollEvent(&event)) {
TextBuffer *buffer = ted->active_buffer;
@@ -786,4 +733,5 @@ int main(int argc, char **argv) {
#endif
return 0;
+#endif
}
diff --git a/text.c b/text.c
index c2554e8..3368414 100644
--- a/text.c
+++ b/text.c
@@ -13,6 +13,16 @@ no_warn_end
#define CHAR_PAGE_SIZE 2048
#define CHAR_PAGE_COUNT UNICODE_CODE_POINTS / CHAR_PAGE_SIZE
+typedef struct {
+ v2 pos;
+ v2 tex_coord;
+ v4 color;
+} TextVertex;
+
+typedef struct {
+ TextVertex v1, v2, v3;
+} TextTriangle;
+
struct Font {
float char_width; // width of the character 'a'. calculated when font is loaded.
float char_height;
@@ -21,6 +31,7 @@ struct Font {
stbtt_bakedchar *char_pages[CHAR_PAGE_COUNT]; // character pages. NULL if the page hasn't been loaded yet.
// TTF data (i.e. the contents of the TTF file)
u8 *ttf_data;
+ TextTriangle *triangles[CHAR_PAGE_COUNT]; // triangles to render for each page
int curr_page;
};
@@ -29,7 +40,8 @@ TextRenderState const text_render_state_default = {
.wrap = false,
.x = 0, .y = 0,
.min_x = -FLT_MAX, .max_x = +FLT_MAX,
- .min_y = -FLT_MAX, .max_y = +FLT_MAX
+ .min_y = -FLT_MAX, .max_y = +FLT_MAX,
+ .r = 1, .g = 0, .b = 1, .a = 1,
};
static char text_err[200];
@@ -54,6 +66,45 @@ static void text_set_err(char const *fmt, ...) {
}
}
+static GLuint text_program;
+static GLuint text_vbo, text_vao;
+static GLuint text_v_pos, text_v_color, text_v_tex_coord;
+static GLint text_u_sampler;
+
+static bool text_init(void) {
+ char const *vshader_code = "#version 110\n\
+attribute vec4 v_color;\n\
+attribute vec2 v_pos;\n\
+attribute vec2 v_tex_coord;\n\
+varying vec4 color;\n\
+varying vec2 tex_coord;\n\
+void main() {\n\
+ color = v_color;\n\
+ tex_coord = v_tex_coord;\n\
+ gl_Position = vec4(v_pos, 0.0, 1.0);\n\
+}\n\
+";
+ char const *fshader_code = "#version 110\n\
+varying vec4 color;\n\
+varying vec2 tex_coord;\n\
+uniform sampler2D sampler;\n\
+void main() {\n\
+ vec4 tex_color = texture2D(sampler, tex_coord);\n\
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);//vec4(1.0, 1.0, 1.0, tex_color.x * color);\n\
+}\n\
+";
+
+ text_program = gl_compile_and_link_shaders(vshader_code, fshader_code);
+ text_v_pos = gl_attrib_loc(text_program, "v_pos");
+ text_v_color = gl_attrib_loc(text_program, "v_color");
+ text_v_tex_coord = gl_attrib_loc(text_program, "v_tex_coord");
+ text_u_sampler = gl_uniform_loc(text_program, "sampler");
+ glGenBuffers(1, &text_vbo);
+ glGenVertexArrays(1, &text_vao);
+
+ return true;
+}
+
static Status text_load_char_page(Font *font, int page) {
if (font->char_pages[page]) {
// already loaded
@@ -70,7 +121,7 @@ static Status text_load_char_page(Font *font, int page) {
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, bitmap_width, bitmap_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, bitmap_width, bitmap_height, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if DEBUG
@@ -162,18 +213,7 @@ float text_font_char_width(Font *font) {
}
static void text_render_with_page(Font *font, int page) {
- if (font->curr_page != page) {
- if (font->curr_page != -1) {
- // we were rendering chars from another page.
- glEnd(); // stop doing that
- }
- if (text_load_char_page(font, page)) { // load the page if necessary
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, font->textures[page]);
- font->curr_page = page;
- }
- glBegin(GL_QUADS);
- }
+ font->curr_page = page;
}
void text_chars_begin(Font *font) {
@@ -181,9 +221,37 @@ void text_chars_begin(Font *font) {
}
void text_chars_end(Font *font) {
- glEnd();
- glDisable(GL_TEXTURE_2D);
- font->curr_page = -1;
+ for (uint i = 0; i < CHAR_PAGE_COUNT; ++i) {
+ if (font->triangles[i]) {
+ // render these triangles
+ size_t ntriangles = arr_len(font->triangles[i]);
+
+ // convert coordinates to NDC
+ for (size_t t = 0; t < ntriangles; ++t) {
+ TextTriangle *triangle = &font->triangles[i][t];
+ gl_convert_to_ndc(&triangle->v1.pos);
+ gl_convert_to_ndc(&triangle->v2.pos);
+ gl_convert_to_ndc(&triangle->v3.pos);
+ }
+
+ if (gl_version_major >= 3)
+ glBindVertexArray(text_vao);
+ glBindBuffer(GL_ARRAY_BUFFER, text_vbo);
+ glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(ntriangles * sizeof(TextTriangle)), font->triangles, GL_STREAM_DRAW);
+ glVertexAttribPointer(text_v_pos, 2, GL_FLOAT, 0, sizeof(TextVertex), (void *)offsetof(TextVertex, pos));
+ glEnableVertexAttribArray(text_v_pos);
+ glVertexAttribPointer(text_v_tex_coord, 2, GL_FLOAT, 0, sizeof(TextVertex), (void *)offsetof(TextVertex, tex_coord));
+ glEnableVertexAttribArray(text_v_tex_coord);
+ glVertexAttribPointer(text_v_color, 4, GL_FLOAT, 0, sizeof(TextVertex), (void *)offsetof(TextVertex, color));
+ glEnableVertexAttribArray(text_v_color);
+ glUseProgram(text_program);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, font->textures[i]);
+ glUniform1i(text_u_sampler, 0);
+ glDrawArrays(GL_TRIANGLES, 0, (GLsizei)(3 * ntriangles));
+ arr_clear(font->triangles[i]);
+ }
+ }
}
void text_render_char(Font *font, TextRenderState *state, char32_t c) {
@@ -242,10 +310,15 @@ top:
y1 = max_y-1;
}
if (state->render) {
- glTexCoord2f(s0,t0); glVertex2f(x0,y0);
- glTexCoord2f(s0,t1); glVertex2f(x0,y1);
- glTexCoord2f(s1,t1); glVertex2f(x1,y1);
- glTexCoord2f(s1,t0); glVertex2f(x1,y0);
+ float r = state->r, g = state->g, b = state->b, a = state->a;
+ TextVertex v1 = {{x0, y0}, {s0, t0}, {r, g, b, a}};
+ TextVertex v2 = {{x0, y1}, {s0, t1}, {r, g, b, a}};
+ TextVertex v3 = {{x1, y1}, {s1, t1}, {r, g, b, a}};
+ TextVertex v4 = {{x1, y0}, {s1, t0}, {r, g, b, a}};
+ TextTriangle triangle1 = {v1, v2, v3};
+ TextTriangle triangle2 = {v3, v4, v1};
+ arr_add(font->triangles[font->curr_page], triangle1);
+ arr_add(font->triangles[font->curr_page], triangle2);
}
}
}
@@ -330,6 +403,7 @@ void text_font_free(Font *font) {
if (char_pages[i]) {
free(char_pages[i]);
}
+ arr_clear(font->triangles[i]);
}
free(font);
}
diff --git a/text.h b/text.h
index b0629b9..f57fef9 100644
--- a/text.h
+++ b/text.h
@@ -18,6 +18,8 @@ typedef struct {
float x, y;
// points at which the text should be cut off
float min_x, max_x, min_y, max_y;
+ // color
+ float r, g, b, a;
} TextRenderState;
typedef enum {