Commit: 06f92343a2176078d1cc750fa8904cf8f6287a0e
Parent: 0b2029e8c1e0a921d674643938032ad7965740f7
Author: Randy Palamar
Date: Thu, 27 Jun 2024 23:11:37 -0600
draw to a secondary framebuffer
The use of this is analogous to using a retained cell matrix on
the CPU except this sucks way less.
Diffstat:
M | main.c | | | 21 | ++++++++++++++++++++- |
M | terminal.c | | | 1 | - |
M | util.h | | | 6 | ++++++ |
M | vtgl.c | | | 71 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- |
4 files changed, 86 insertions(+), 13 deletions(-)
diff --git a/main.c b/main.c
@@ -151,6 +151,25 @@ init_window(Term *t)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* NOTE: Scale up the size of the Render Framebuffer */
+ t->gl.window_size.h *= FB_HEIGHT_SCALE;
+
+ /* NOTE: Generate an oversized intermediate Framebuffer for rendering to */
+ glGenFramebuffers(1, &t->gl.fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb);
+
+ 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);
+
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, t->gl.fb_tex, 0);
}
static u32
@@ -277,9 +296,9 @@ main(void)
term.gl.dt = current_time - last_time;
last_time = current_time;
- glfwPollEvents();
do_terminal(&term, memory);
glfwSwapBuffers(term.gl.window);
+ glfwPollEvents();
}
return 0;
diff --git a/terminal.c b/terminal.c
@@ -98,7 +98,6 @@ cursor_step_column(Term *t, i32 step)
if (t->cursor.row < t->size.h)
return;
t->cursor.row = t->size.h - 1;
- /* TODO: scroll term up by a line */
}
static void
diff --git a/util.h b/util.h
@@ -27,6 +27,10 @@
#define ISPRINT(c) BETWEEN((c), ' ', '~')
+/* NOTE: Framebuffer Height is oversized by this to allow
+ * for text reflow without cpu side memory reallocations */
+#define FB_HEIGHT_SCALE 2
+
/* NOTE: GLFW does not sequentially number keys so switch statement will never be optimized */
#define ENCODE_KEY(action, mod, key) (((action) << 24) | ((mod) << 16) | ((key) & 0xFFFF))
@@ -148,6 +152,8 @@ typedef struct {
u32 vao, vbo;
+ u32 fb, fb_tex, fb_tex_unit;
+
u32 program;
#define X(name) i32 name;
union {
diff --git a/vtgl.c b/vtgl.c
@@ -25,6 +25,7 @@ static void
clear_colour(void)
{
v4 cc = normalized_colour((Colour){.r = 64, .g = 64, .b = 64, .a = 255});
+ //v4 cc = normalized_colour((Colour){.r = 20, .g = 20, .b = 20, .a = 255});
glClearColor(cc.r, cc.g, cc.b, cc.a);
glClear(GL_COLOR_BUFFER_BIT);
}
@@ -33,7 +34,6 @@ static void
resize(GLCtx *gl)
{
v2 ws = gl->window_size;
- glViewport(0, 0, ws.w, ws.h);
f32 pmat[4 * 4] = {
2.0 / ws.w, 0.0, 0.0, -1.0,
0.0, 2.0 / ws.h, 0.0, -1.0,
@@ -72,10 +72,10 @@ update_uniforms(Term *t)
t->gl.uniforms[i] = glGetUniformLocation(t->gl.program, uniform_names[i]);
t->gl.flags &= ~UPDATE_UNIFORMS;
- resize(&t->gl);
-
glUniform1i(t->gl.texslot, 0);
update_font_textures(t);
+
+ resize(&t->gl);
}
static i32
@@ -241,7 +241,7 @@ push_line(Term *t, Line *line, v2 start_pos)
static void
blit_lines(Term *t)
{
- size line_count = t->size.h - 1;
+ size line_count = t->size.h / FB_HEIGHT_SCALE - 1;
CLAMP(line_count, 0, t->log_lines.filled);
v2 cs = get_cell_size(t);
/* TODO: handle case where widx has wrapped around */
@@ -266,13 +266,21 @@ fb_callback(GLFWwindow *win, i32 w, i32 h)
{
Term *t = glfwGetWindowUserPointer(win);
t->gl.window_size.w = w;
- t->gl.window_size.h = h;
+ t->gl.window_size.h = FB_HEIGHT_SCALE * h;
t->gl.flags |= NEEDS_RESIZE;
v2 cs = get_cell_size(t);
t->size.w = (u32)(w / cs.w);
- t->size.h = (u32)(h / cs.h);
- os_set_term_size(t->child, t->size, w, h);
+ t->size.h = FB_HEIGHT_SCALE * (u32)(h / cs.h);
+
+ /* NOTE: The terminal size still needs to have the correct number
+ * of rows so that terminal programs know how to size themselves. */
+ os_set_term_size(t->child, (uv2){.w = t->size.w, .h = t->size.h/FB_HEIGHT_SCALE}, w, h);
+
+ glActiveTexture(GL_TEXTURE0 + t->gl.fb_tex_unit);
+ 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);
}
static void
@@ -326,8 +334,6 @@ do_terminal(Term *t, Arena a)
if (t->gl.flags & NEEDS_RESIZE)
resize(&t->gl);
- clear_colour();
-
if (os_child_data_available(t->child)) {
if (os_child_exited(t->child))
glfwSetWindowShouldClose(t->gl.window, GL_TRUE);
@@ -340,16 +346,59 @@ do_terminal(Term *t, Arena a)
/* TODO: think about only blitting update lines? */
(void)parsed_lines;
}
+
+ v2 ws = t->gl.window_size;
+
+ /* NOTE: reset the camera/viewport */
+ glBindFramebuffer(GL_FRAMEBUFFER, t->gl.fb);
+ clear_colour();
+ glViewport(0, 0, ws.w, ws.h);
blit_lines(t);
+ v2 cell_size = get_cell_size(t);
+ v2 cursor_pos = {
+ .x = t->cursor.col * cell_size.w,
+ .y = ws.h - cell_size.h * (t->cursor.row + 1),
+ };
+
+ v2 src_bl = {
+ .x = 0,
+ .y = ws.h / FB_HEIGHT_SCALE,
+ };
+ v2 src_tr = {
+ .x = ws.w,
+ .y = src_bl.y + ws.h / FB_HEIGHT_SCALE,
+ };
+
+ if (t->cursor.row > t->size.h / FB_HEIGHT_SCALE) {
+ src_tr.y = cursor_pos.y + ws.h / FB_HEIGHT_SCALE;
+ src_bl.y = cursor_pos.y;
+ }
+
{
s8 fps = s8alloc(&a, 64);
fps.len = snprintf((char *)fps.data, fps.len, "%0.01f ms/f", t->gl.dt * 1e3);
v2 ts = measure_text(&t->gl, fps, 1);
v2 pos = {
- .x = t->gl.window_size.w - ts.x - 10,
- .y = t->gl.window_size.h - ts.y - 10
+ .x = ws.w - ts.x - 10,
+ .y = src_tr.y - ts.y - 10
+ };
+
+ Rect r = {
+ .pos = {.x = pos.x - 0.05 * ts.x, .y = pos.y - 0.25 * ts.y},
+ .size = {.w = ts.w * 1.1, .h = ts.h * 1.2},
};
+
+ draw_rectangle(&t->gl, r, (Colour){.rgba = 0x303030ff});
draw_text(&t->gl, fps, pos, (Colour){.rgba = 0x1e9e33ff}, 1);
}
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, t->gl.fb);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glBlitFramebuffer(src_bl.x, src_bl.y, src_tr.x, src_tr.y,
+ 0, 0, ws.w, ws.h / FB_HEIGHT_SCALE,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ //glActiveTexture(GL_TEXTURE0 + t->gl.fb_tex_unit);
+ //glBindTexture(GL_TEXTURE_2D, t->gl.fb_tex);
}