diff options
-rw-r--r-- | gl.c | 38 | ||||
-rw-r--r-- | main.c | 78 | ||||
-rw-r--r-- | text.c | 116 | ||||
-rw-r--r-- | text.h | 2 |
4 files changed, 134 insertions, 100 deletions
@@ -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); @@ -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 } @@ -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); } @@ -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 { |