vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

Commit: 17cdb1108111ff4ebdd0f01e9c76890aca6a4945
Parent: 8bf48859b5e39e7bce1c9bd8260621863c0c71f6
Author: Randy Palamar
Date:   Tue, 22 Oct 2024 06:58:16 -0600

add basic rectangle drawing shader

this will be used for UI (and fixing the debug overlay)

Diffstat:
Afrag_for_rects.glsl | 14++++++++++++++
Mfrag_post.glsl | 2+-
Mmain.c | 52++++++++++++++++++++++++++++++++++------------------
Mutil.h | 13+++++--------
Mvtgl.c | 30+++++++++++++++++++-----------
5 files changed, 73 insertions(+), 38 deletions(-)

diff --git a/frag_for_rects.glsl b/frag_for_rects.glsl @@ -0,0 +1,14 @@ +#version 430 core + +layout(location = 0) in vec2 fragment_pixel_coordinate; +layout(location = 1) in vec2 fragment_texture_coordinate; +layout(location = 2) in vec4 fragment_colour; + +layout(location = 0) out vec4 colour; + +layout(location = 3) uniform sampler2D u_texslot; + +void main() +{ + colour = fragment_colour * texture(u_texslot, fragment_texture_coordinate); +} diff --git a/frag_post.glsl b/frag_post.glsl @@ -12,7 +12,7 @@ layout(location = 4) uniform float u_param; void main() { vec2 texture_coord = fragment_texture_coordinate; - //if (mod(tex_coord.y + u_param, 0.005) < 0.0005) { + //if (mod(texture_coord.y + u_param, 0.005) < 0.0005) { if (false) { vec4 tint = vec4(0.1, 0.1, 0.1, 1); colour = mix(texture(u_texslot, texture_coord), tint, 0.5); diff --git a/main.c b/main.c @@ -91,6 +91,19 @@ error_callback(int code, const char *desc) fprintf(stderr, "GLFW Error (0x%04X): %s\n", code, desc); } +static u32 +gen_2D_texture(iv2 size, u32 format, u32 filter, u32 *rgba) +{ + /* TODO: logging */ + u32 result; + glGenTextures(1, &result); + glBindTexture(GL_TEXTURE_2D, result); + glTexImage2D(GL_TEXTURE_2D, 0, format, size.w, size.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + return result; +} + static void init_window(Term *t, Arena arena, iv2 window_size) { @@ -164,13 +177,10 @@ init_window(Term *t, Arena arena, iv2 window_size) glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * ARRAY_COUNT(rpb->positions) * sizeof(i32), element_indices, GL_STATIC_DRAW); - glGenTextures(1, &t->gl.glyph_bitmap_tex); - glBindTexture(GL_TEXTURE_2D, t->gl.glyph_bitmap_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - t->gl.glyph_bitmap_dim.w, t->gl.glyph_bitmap_dim.h, - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + u32 white = 0xFFFFFFFF; + + t->gl.default_tex = gen_2D_texture((iv2){.x = 1, .y = 1}, GL_RGBA, GL_NEAREST, &white); + t->gl.glyph_bitmap_tex = gen_2D_texture(t->gl.glyph_bitmap_dim, GL_RGBA, GL_NEAREST, 0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -182,14 +192,8 @@ init_window(Term *t, Arena arena, iv2 window_size) t->gl.fb_tex_unit = 1; glActiveTexture(GL_TEXTURE0 + t->gl.fb_tex_unit); - glGenTextures(1, &t->gl.fb_tex); - glBindTexture(GL_TEXTURE_2D, t->gl.fb_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - t->gl.window_size.w, t->gl.window_size.h, - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - + iv2 ws = {.x = t->gl.window_size.w, .y = t->gl.window_size.h}; + t->gl.fb_tex = gen_2D_texture(ws, GL_RGBA, GL_NEAREST, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, t->gl.fb_tex, 0); glGenBuffers(1, &t->gl.render_shader_ubo); @@ -197,6 +201,8 @@ init_window(Term *t, Arena arena, iv2 window_size) glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderParameters), 0, GL_DYNAMIC_DRAW); glBindBufferBase(GL_UNIFORM_BUFFER, 0, t->gl.render_shader_ubo); + glActiveTexture(GL_TEXTURE0); + t->gl.flags |= INIT_DEBUG; } @@ -256,14 +262,24 @@ program_from_shader_text(s8 vertex, s8 fragment, Arena a) static void check_shaders(GLCtx *gl, Arena a) { - static char *fs_name[SHADER_LAST] = {"frag_render.glsl", "frag_post.glsl"}; - static char *vs_name[SHADER_LAST] = {"vert_for_rects.glsl", "vert_for_rects.glsl"}; + static char *fs_name[SHADER_LAST] = { + "frag_render.glsl", + "frag_for_rects.glsl", + "frag_post.glsl", + }; + static char *vs_name[SHADER_LAST] = { + "vert_for_rects.glsl", + "vert_for_rects.glsl", + "vert_for_rects.glsl", + }; + static os_file_stats fs_stats[SHADER_LAST], vs_stats[SHADER_LAST]; static struct { char *name; u32 flag; } map[SHADER_LAST] = { - [SHADER_RENDER] = {.name = "Render", .flag = UPDATE_RENDER_UNIFORMS}, + [SHADER_RENDER] = {.name = "Render", .flag = 0}, + [SHADER_RECTS] = {.name = "Rects", .flag = 0}, [SHADER_POST] = {.name = "Post", .flag = UPDATE_POST_UNIFORMS}, }; diff --git a/util.h b/util.h @@ -183,8 +183,7 @@ typedef struct { size last_line_idx; } TermView; -#define GL_RENDER_UNIFORMS \ - X(Pmat) +#define SHADER_PMAT_LOC 0 #define GL_POST_UNIFORMS \ X(Pmat) \ @@ -197,7 +196,6 @@ enum gl_flags { NEEDS_FULL_REFILL = 1 << 2, UPDATE_RENDER_BUFFER = 1 << 3, - UPDATE_RENDER_UNIFORMS = 1 << 27, UPDATE_POST_UNIFORMS = 1 << 28, INIT_DEBUG = 1 << 29, DRAW_DEBUG_OVERLAY = 1 << 30, @@ -213,6 +211,7 @@ enum win_mode { enum shader_stages { SHADER_RENDER, + SHADER_RECTS, SHADER_POST, SHADER_LAST }; @@ -244,15 +243,13 @@ typedef struct { u32 fb, fb_tex, fb_tex_unit; + u32 default_tex; + u32 programs[SHADER_LAST]; #define X(name) i32 name; union { - struct { GL_RENDER_UNIFORMS }; - i32 uniforms[7]; - } render; - union { struct { GL_POST_UNIFORMS }; - i32 uniforms[4]; + i32 uniforms[3]; } post; #undef X diff --git a/vtgl.c b/vtgl.c @@ -48,10 +48,9 @@ set_projection_matrix(GLCtx *gl) 0.0, 0.0, 0.0, 1.0, }; - glUseProgram(gl->programs[SHADER_RENDER]); - glUniformMatrix4fv(gl->render.Pmat, 1, GL_TRUE, pmat); - glUseProgram(gl->programs[SHADER_POST]); - glUniformMatrix4fv(gl->post.Pmat, 1, GL_TRUE, pmat); + glProgramUniformMatrix4fv(gl->programs[SHADER_RENDER], SHADER_PMAT_LOC, 1, GL_TRUE, pmat); + glProgramUniformMatrix4fv(gl->programs[SHADER_RECTS], SHADER_PMAT_LOC, 1, GL_TRUE, pmat); + glProgramUniformMatrix4fv(gl->programs[SHADER_POST], SHADER_PMAT_LOC, 1, GL_TRUE, pmat); } static v2 @@ -127,11 +126,7 @@ update_uniforms(Term *t, enum shader_stages stage) { switch (stage) { case SHADER_RENDER: - #define X(name) \ - t->gl.render.name = glGetUniformLocation(t->gl.programs[stage], "u_" #name); - GL_RENDER_UNIFORMS - #undef X - t->gl.flags &= ~UPDATE_RENDER_UNIFORMS; + case SHADER_RECTS: break; case SHADER_POST: #define X(name) \ @@ -771,8 +766,6 @@ do_terminal(Term *t, f32 dt) { dt_for_frame = dt; - if (t->gl.flags & UPDATE_RENDER_UNIFORMS) - update_uniforms(t, SHADER_RENDER); if (t->gl.flags & UPDATE_POST_UNIFORMS) update_uniforms(t, SHADER_POST); @@ -784,6 +777,11 @@ do_terminal(Term *t, f32 dt) t->gl.flags &= ~INIT_DEBUG; } + /* NOTE: this needs to be bound for blitting lines because that function can + * access the font cache. + * TODO: cleanup */ + glBindTexture(GL_TEXTURE_2D, t->gl.glyph_bitmap_tex); + size parsed_lines = 0; if (os_child_data_available(t->child)) { RingBuf *rb = &t->views[t->view_idx].log; @@ -856,6 +854,16 @@ do_terminal(Term *t, f32 dt) push_rect(rpb, &t->gl, (Rect){.size = t->gl.window_size}, (v4){0}, 1); flush_render_push_buffer(rpb, &t->gl); + + #if 0 + /* NOTE: this happens at the end so that ui stuff doesn't go through the post + * processing/effects shader */ + glUseProgram(t->gl.programs[SHADER_RECTS]); + glBindTexture(GL_TEXTURE_2D, t->gl.default_tex); + push_rect(rpb, &t->gl, (Rect){.size = {.w = 300, .h = 200}}, (v4){.r = 0.5, .a = 1}, 0); + push_rect(rpb, &t->gl, (Rect){.pos = {.x = 300, .y = 200}, .size = {.w = 300, .h = 200}}, (v4){.g = 0.5, .a = 1}, 0); + flush_render_push_buffer(rpb, &t->gl); + #endif } #ifdef _DEBUG