From cdea958e71fd59c8d2051feb4631badd6891e751 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 6 Jun 2016 16:54:15 -0700 Subject: [PATCH] Add support for drawing background colors --- Cargo.lock | 1 + Cargo.toml | 1 + res/text.f.glsl | 12 +++++- res/text.v.glsl | 31 +++++++++++---- src/grid.rs | 8 ++++ src/main.rs | 3 ++ src/renderer/mod.rs | 95 ++++++++++++++++++++++++++++++++++++++------- src/term.rs | 18 +++++++-- 8 files changed, 142 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7633fc26..01b0290c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,7 @@ name = "alacritty" version = "0.1.0" dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 2de24e9d..c39e134e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ cgmath = "0.7" euclid = "0.6" notify = { git = "https://github.com/jwilm/rsnotify", branch = "add-ignore-op" } arrayvec = "0.3" +bitflags = "*" [build-dependencies] gl_generator = "0.5" diff --git a/res/text.f.glsl b/res/text.f.glsl index d2defb39..5ba7255d 100644 --- a/res/text.f.glsl +++ b/res/text.f.glsl @@ -1,6 +1,8 @@ #version 330 core in vec2 TexCoords; in vec3 fg; +in vec3 bg; +flat in int background; layout(location = 0, index = 0) out vec4 color; layout(location = 0, index = 1) out vec4 alphaMask; @@ -9,6 +11,12 @@ uniform sampler2D mask; void main() { - alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0); - color = vec4(fg, 1.0); + if (background != 0) { + alphaMask = vec4(1.0, 1.0, 1.0, 1.0); + color = vec4(bg, 1.0); + } else { + alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0); + color = vec4(fg, 1.0); + } + } diff --git a/res/text.v.glsl b/res/text.v.glsl index 276b1dc3..0432babd 100644 --- a/res/text.v.glsl +++ b/res/text.v.glsl @@ -12,23 +12,28 @@ layout (location = 3) in vec4 uv; // text fg color layout (location = 4) in vec3 textColor; +// Background color +layout (location = 5) in vec3 backgroundColor; out vec2 TexCoords; out vec3 fg; +out vec3 bg; // Terminal properties uniform vec2 termDim; uniform vec2 cellDim; uniform vec2 cellSep; +uniform int backgroundPass; + // Orthographic projection uniform mat4 projection; +flat out int background; void main() { vec2 glyphOffset = glyph.xy; vec2 glyphSize = glyph.zw; - vec2 uvOffset = uv.xy; vec2 uvSize = uv.zw; @@ -38,14 +43,24 @@ void main() // Invert Y since framebuffer origin is bottom-left cellPosition.y = termDim.y - cellPosition.y - cellDim.y; - // Glyphs are offset within their cell; account for y-flip - vec2 cellOffset = vec2(glyphOffset.x, - glyphOffset.y - glyphSize.y); + if (backgroundPass != 0) { + cellPosition.y = cellPosition.y - 3; + vec2 finalPosition = (cellDim + cellSep) * position + cellPosition; + gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0); + TexCoords = vec2(0, 0); + } else { - // position coordinates are normalized on [0, 1] - vec2 finalPosition = glyphSize * position + cellPosition + cellOffset; + // Glyphs are offset within their cell; account for y-flip + vec2 cellOffset = vec2(glyphOffset.x, glyphOffset.y - glyphSize.y); - gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0); - TexCoords = uvOffset + vec2(position.x, 1 - position.y) * uvSize; + // position coordinates are normalized on [0, 1] + vec2 finalPosition = glyphSize * position + cellPosition + cellOffset; + + gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0); + TexCoords = uvOffset + vec2(position.x, 1 - position.y) * uvSize; + } + + background = backgroundPass; + bg = backgroundColor / vec3(255.0, 255.0, 255.0); fg = textColor / vec3(255.0, 255.0, 255.0); } diff --git a/src/grid.rs b/src/grid.rs index a3009f8b..f5c98afb 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -19,6 +19,13 @@ pub struct Cell { pub c: char, pub fg: Rgb, pub bg: Rgb, + pub flags: CellFlags, +} + +bitflags! { + pub flags CellFlags: u32 { + const INVERSE = 0b00000001, + } } impl Cell { @@ -27,6 +34,7 @@ impl Cell { c: c.into(), bg: Default::default(), fg: Default::default(), + flags: CellFlags::empty(), } } } diff --git a/src/main.rs b/src/main.rs index 498cdee6..b5f5f9d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,9 @@ extern crate euclid; extern crate notify; extern crate arrayvec; +#[macro_use] +extern crate bitflags; + #[macro_use] mod macros; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 2aa2fc81..87dfe84e 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -15,7 +15,7 @@ use gl; use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op}; use text::{Rasterizer, RasterizedGlyph, FontDesc}; -use grid::Grid; +use grid::{self, Grid, Cell, CellFlags}; use term; use super::{Rgb, TermProps}; @@ -48,6 +48,11 @@ pub struct ShaderProgram { /// Cell separation (pixels) u_cell_sep: GLint, + + /// Background pass flag + /// + /// Rendering is split into two passes; 1 for backgrounds, and one for text + u_background: GLint } @@ -146,6 +151,10 @@ struct InstanceData { r: f32, g: f32, b: f32, + // background color + bg_r: f32, + bg_g: f32, + bg_b: f32, } #[derive(Debug)] @@ -166,6 +175,7 @@ pub struct RenderApi<'a> { active_tex: &'a mut GLuint, batch: &'a mut Batch, atlas: &'a mut Vec, + program: &'a mut ShaderProgram, } #[derive(Debug)] @@ -195,12 +205,12 @@ impl Batch { } } - pub fn add_item(&mut self, row: f32, col: f32, color: Rgb, glyph: &Glyph) { + pub fn add_item(&mut self, row: f32, col: f32, cell: &Cell, glyph: &Glyph) { if self.is_empty() { self.tex = glyph.tex_id; } - self.instances.push(InstanceData { + let mut instance = InstanceData { col: col, row: row, @@ -214,10 +224,26 @@ impl Batch { uv_width: glyph.uv_width, uv_height: glyph.uv_height, - r: color.r as f32, - g: color.g as f32, - b: color.b as f32, - }); + r: cell.fg.r as f32, + g: cell.fg.g as f32, + b: cell.fg.b as f32, + + bg_r: cell.bg.r as f32, + bg_g: cell.bg.g as f32, + bg_b: cell.bg.b as f32, + }; + + if cell.flags.contains(grid::INVERSE) { + instance.r = cell.bg.r as f32; + instance.g = cell.bg.g as f32; + instance.b = cell.bg.b as f32; + + instance.bg_r = cell.fg.r as f32; + instance.bg_g = cell.fg.g as f32; + instance.bg_b = cell.fg.b as f32; + } + + self.instances.push(instance); } #[inline] @@ -345,6 +371,13 @@ impl QuadRenderer { (10 * size_of::()) as *const _); gl::EnableVertexAttribArray(4); gl::VertexAttribDivisor(4, 1); + // color + gl::VertexAttribPointer(5, 3, + gl::FLOAT, gl::FALSE, + size_of::() as i32, + (13 * size_of::()) as *const _); + gl::EnableVertexAttribArray(5); + gl::VertexAttribDivisor(5, 1); gl::BindVertexArray(0); gl::BindBuffer(gl::ARRAY_BUFFER, 0); @@ -421,6 +454,7 @@ impl QuadRenderer { active_tex: &mut self.active_tex, batch: &mut self.batch, atlas: &mut self.atlas, + program: &mut self.program, }); unsafe { @@ -472,6 +506,12 @@ impl<'a> RenderApi<'a> { } unsafe { + + self.program.set_background_pass(true); + gl::DrawElementsInstanced(gl::TRIANGLES, + 6, gl::UNSIGNED_INT, ptr::null(), + self.batch.len() as GLsizei); + self.program.set_background_pass(false); gl::DrawElementsInstanced(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null(), self.batch.len() as GLsizei); @@ -491,7 +531,13 @@ impl<'a> RenderApi<'a> { for c in s.chars() { if let Some(glyph) = glyph_cache.get(c, self) { - self.add_render_item(row, col, *color, glyph); + let cell = Cell { + c: c, + fg: *color, + bg: term::DEFAULT_BG, + flags: grid::INVERSE, + }; + self.add_render_item(row, col, &cell, glyph); } col += 1.0; @@ -499,7 +545,7 @@ impl<'a> RenderApi<'a> { } #[inline] - fn add_render_item(&mut self, row: f32, col: f32, color: Rgb, glyph: &Glyph) { + fn add_render_item(&mut self, row: f32, col: f32, cell: &Cell, glyph: &Glyph) { // Flush batch if tex changing if !self.batch.is_empty() { if self.batch.tex != glyph.tex_id { @@ -507,7 +553,7 @@ impl<'a> RenderApi<'a> { } } - self.batch.add_item(row, col, color, glyph); + self.batch.add_item(row, col, cell, glyph); // Render batch and clear if it's full if self.batch.full() { @@ -517,7 +563,14 @@ impl<'a> RenderApi<'a> { pub fn render_cursor(&mut self, cursor: term::Cursor, glyph_cache: &mut GlyphCache) { if let Some(glyph) = glyph_cache.get(term::CURSOR_SHAPE, self) { - self.add_render_item(cursor.y as f32, cursor.x as f32, term::DEFAULT_FG, glyph); + let cell = Cell { + c: term::CURSOR_SHAPE, + fg: term::DEFAULT_FG, + bg: term::DEFAULT_BG, + flags: CellFlags::empty(), + }; + + self.add_render_item(cursor.y as f32, cursor.x as f32, &cell, glyph); } } @@ -525,13 +578,13 @@ impl<'a> RenderApi<'a> { for (i, row) in grid.rows().enumerate() { for (j, cell) in row.cells().enumerate() { // Skip empty cells - if cell.c == ' ' { + if cell.c == ' ' && cell.bg == term::DEFAULT_BG { continue; } // Add cell to batch if the glyph is laoded if let Some(glyph) = glyph_cache.get(cell.c, self) { - self.add_render_item(i as f32, j as f32, cell.fg, glyph); + self.add_render_item(i as f32, j as f32, cell, glyph); } } } @@ -610,12 +663,13 @@ impl ShaderProgram { } // get uniform locations - let (projection, term_dim, cell_dim, cell_sep) = unsafe { + let (projection, term_dim, cell_dim, cell_sep, background) = unsafe { ( gl::GetUniformLocation(program, cptr!(b"projection\0")), gl::GetUniformLocation(program, cptr!(b"termDim\0")), gl::GetUniformLocation(program, cptr!(b"cellDim\0")), gl::GetUniformLocation(program, cptr!(b"cellSep\0")), + gl::GetUniformLocation(program, cptr!(b"backgroundPass\0")), ) }; @@ -627,6 +681,7 @@ impl ShaderProgram { u_term_dim: term_dim, u_cell_dim: cell_dim, u_cell_sep: cell_sep, + u_background: background, }; // set projection uniform @@ -653,6 +708,18 @@ impl ShaderProgram { } } + fn set_background_pass(&self, background_pass: bool) { + let value = if background_pass { + 1 + } else { + 0 + }; + + unsafe { + gl::Uniform1i(self.u_background, value); + } + } + fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint { unsafe { let program = gl::CreateProgram(); diff --git a/src/term.rs b/src/term.rs index 5b00acfd..a552ee5d 100644 --- a/src/term.rs +++ b/src/term.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use ansi::{self, Attr, DebugHandler}; -use grid::Grid; +use grid::{self, Grid, CellFlags}; use tty; use ::Rgb; @@ -89,7 +89,10 @@ pub struct Term { bg: Rgb, /// Tabstops - tabs: Vec + tabs: Vec, + + /// Cell attributes + attr: grid::CellFlags, } impl Term { @@ -111,6 +114,7 @@ impl Term { bg: DEFAULT_BG, tty: tty, tabs: tabs, + attr: CellFlags::empty(), } } @@ -158,6 +162,7 @@ impl Term { cell.c = c; cell.fg = self.fg; cell.bg = self.bg; + cell.flags = self.attr; } /// Advance to next line @@ -348,7 +353,14 @@ impl ansi::Handler for Term { Attr::Reset => { self.fg = DEFAULT_FG; self.bg = DEFAULT_BG; - } + self.attr = CellFlags::empty(); + }, + Attr::Reverse => { + self.attr.insert(grid::INVERSE); + }, + Attr::CancelReverse => { + self.attr.remove(grid::INVERSE); + }, _ => { println!("Term got unhandled attr: {:?}", attr); }