From 390d95a5af83403863b6e098c8bc32f7a9d69a9b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 19 Aug 2022 10:07:30 -0700 Subject: [PATCH] Enable depth buffer, add depth to shader --- shaders/cell.v.glsl | 28 ++++++++++++++++++++++------ src/Grid.zig | 14 ++++++++++++++ src/Window.zig | 10 +++++++++- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/shaders/cell.v.glsl b/shaders/cell.v.glsl index 5b2313c58..2ee0fd37c 100644 --- a/shaders/cell.v.glsl +++ b/shaders/cell.v.glsl @@ -35,6 +35,17 @@ layout (location = 5) in vec4 bg_color_in; // the entire terminal grid in a single GPU pass. layout (location = 6) in uint mode_in; +// The Z-depth. This is between 0.0 and 1.0. This is used to paint newer +// values on top of older ones to limit the amount of data that needs to +// be sent to the GPU. +// +// 0 is further back/away, 1 is front/near +// +// TODO: It would be better to just send the Z value as part of grid_coord +// and normalize it to NDC and then linearly transform it but this was easy +// to get going more quickly. +layout (location = 7) in float grid_z; + // The background or foreground color for the fragment, depending on // whether this is a background or foreground pass. flat out vec4 color; @@ -82,6 +93,11 @@ void main() { // Example: (1,0) with a 30 wide cell is converted to (30,0) vec2 cell_pos = cell_size * grid_coord; + // Our Z value. For now we just use grid_z directly but we pull it + // out here so the variable name is more uniform to our cell_pos and + // in case we want to do any other math later. + float cell_z = grid_z; + // Turn the cell position into a vertex point depending on the // gl_VertexID. Since we use instanced drawing, we have 4 vertices // for each corner of the cell. We can use gl_VertexID to determine @@ -103,7 +119,7 @@ void main() { // one cell up and to the left. (Do the math to verify yourself) cell_pos = cell_pos + cell_size * position; - gl_Position = projection * vec4(cell_pos, 0.0, 1.0); + gl_Position = projection * vec4(cell_pos, cell_z, 1.0); color = bg_color_in / 255.0; break; @@ -117,7 +133,7 @@ void main() { // Calculate the final position of the cell. cell_pos = cell_pos + glyph_size * position + glyph_offset_calc; - gl_Position = projection * vec4(cell_pos, 0.0, 1.0); + gl_Position = projection * vec4(cell_pos, cell_z, 1.0); // We need to convert our texture position and size to normalized // device coordinates (0 to 1.0) by dividing by the size of the texture. @@ -134,7 +150,7 @@ void main() { // Same as background since we're taking up the whole cell. cell_pos = cell_pos + cell_size * position; - gl_Position = projection * vec4(cell_pos, 0.0, 1.0); + gl_Position = projection * vec4(cell_pos, cell_z, 1.0); color = bg_color_in / 255.0; break; @@ -145,7 +161,7 @@ void main() { // Same as background since we're taking up the whole cell. cell_pos = cell_pos + cell_size * position; - gl_Position = projection * vec4(cell_pos, 0.0, 1.0); + gl_Position = projection * vec4(cell_pos, cell_z, 1.0); color = bg_color_in / 255.0; break; @@ -156,7 +172,7 @@ void main() { // Same as background since we're taking up the whole cell. cell_pos = cell_pos + bar_size * position; - gl_Position = projection * vec4(cell_pos, 0.0, 1.0); + gl_Position = projection * vec4(cell_pos, cell_z, 1.0); color = bg_color_in / 255.0; break; @@ -174,7 +190,7 @@ void main() { // above the bottom. cell_pos = cell_pos + underline_offset - underline_size * position; - gl_Position = projection * vec4(cell_pos, 0.0, 1.0); + gl_Position = projection * vec4(cell_pos, cell_z, 1.0); color = fg_color_in / 255.0; break; } diff --git a/src/Grid.zig b/src/Grid.zig index 432b453c6..3f57c8d15 100644 --- a/src/Grid.zig +++ b/src/Grid.zig @@ -100,6 +100,10 @@ const GPUCell = struct { /// uint mode mode: u8, + + /// float grid_z. This is normalized to a float by dividing by the + /// max int value. + grid_z: u16, }; pub fn init(alloc: Allocator, config: *const Config) !Grid { @@ -198,6 +202,8 @@ pub fn init(alloc: Allocator, config: *const Config) !Grid { try vbobind.attributeAdvanced(5, 4, gl.c.GL_UNSIGNED_BYTE, false, @sizeOf(GPUCell), offset); offset += 4 * @sizeOf(u8); try vbobind.attributeIAdvanced(6, 1, gl.c.GL_UNSIGNED_BYTE, @sizeOf(GPUCell), offset); + offset += 1 * @sizeOf(u8); + try vbobind.attributeAdvanced(7, 1, gl.c.GL_UNSIGNED_SHORT, true, @sizeOf(GPUCell), offset); try vbobind.enableAttribArray(0); try vbobind.enableAttribArray(1); try vbobind.enableAttribArray(2); @@ -205,6 +211,7 @@ pub fn init(alloc: Allocator, config: *const Config) !Grid { try vbobind.enableAttribArray(4); try vbobind.enableAttribArray(5); try vbobind.enableAttribArray(6); + try vbobind.enableAttribArray(7); try vbobind.attributeDivisor(0, 1); try vbobind.attributeDivisor(1, 1); try vbobind.attributeDivisor(2, 1); @@ -212,6 +219,7 @@ pub fn init(alloc: Allocator, config: *const Config) !Grid { try vbobind.attributeDivisor(4, 1); try vbobind.attributeDivisor(5, 1); try vbobind.attributeDivisor(6, 1); + try vbobind.attributeDivisor(7, 1); // Build our texture const tex = try gl.Texture.create(); @@ -342,6 +350,7 @@ pub fn updateCells(self: *Grid, term: Terminal) !void { .mode = 1, .grid_col = @intCast(u16, x), .grid_row = @intCast(u16, y), + .grid_z = 0, .glyph_x = 0, .glyph_y = 0, .glyph_width = 0, @@ -380,6 +389,7 @@ pub fn updateCells(self: *Grid, term: Terminal) !void { .mode = 2, .grid_col = @intCast(u16, x), .grid_row = @intCast(u16, y), + .grid_z = 1, .glyph_x = glyph.atlas_x, .glyph_y = glyph.atlas_y, .glyph_width = glyph.width, @@ -402,6 +412,7 @@ pub fn updateCells(self: *Grid, term: Terminal) !void { .mode = 6, // underline .grid_col = @intCast(u16, x), .grid_row = @intCast(u16, y), + .grid_z = 1, .glyph_x = 0, .glyph_y = 0, .glyph_width = 0, @@ -435,6 +446,9 @@ pub fn updateCells(self: *Grid, term: Terminal) !void { .bg_g = 0xFF, .bg_b = 0xFF, .bg_a = 255, + + // The cursor is always at the very front + .grid_z = 255, }); } } diff --git a/src/Window.zig b/src/Window.zig index bf0b79e19..5a0e4e29e 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -200,6 +200,14 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo gl.c.glEnable(gl.c.GL_BLEND); gl.c.glBlendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA); + // Depth test since we use the Z-buffer as an optimization to send + // only changed cells to the GPU. As cells are updated, we bump their + // Z value to be closer, so that over time new values are rendered "over" + // values (in reality old values are culled by the depth test, so they + // aren't ever "rendered"). + gl.c.glEnable(gl.c.GL_DEPTH_TEST); + gl.c.glDepthFunc(gl.c.GL_LESS); + // Create our terminal grid with the initial window size const window_size = try window.getSize(); var grid = try Grid.init(alloc, config); @@ -960,7 +968,7 @@ fn renderTimerCallback(t: *libuv.Timer) void { .a = win.bg_a, }; gl.clearColor(gl_bg.r, gl_bg.g, gl_bg.b, gl_bg.a); - gl.clear(gl.c.GL_COLOR_BUFFER_BIT); + gl.clear(gl.c.GL_COLOR_BUFFER_BIT | gl.c.GL_DEPTH_BUFFER_BIT); // Update the cells for drawing win.grid.updateCells(win.terminal) catch |err|