aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-06-06 16:54:15 -0700
committerJoe Wilm <joe@jwilm.com>2016-06-06 16:54:15 -0700
commitcdea958e71fd59c8d2051feb4631badd6891e751 (patch)
treedc18120cb739e16a0c1a62eaaf42ff61091b3a7a
parent6636cf6b9fa03a711f8c3aa2d6ca43248fecfc0f (diff)
downloadalacritty-cdea958e71fd59c8d2051feb4631badd6891e751.tar.gz
alacritty-cdea958e71fd59c8d2051feb4631badd6891e751.zip
Add support for drawing background colors
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--res/text.f.glsl12
-rw-r--r--res/text.v.glsl31
-rw-r--r--src/grid.rs8
-rw-r--r--src/main.rs3
-rw-r--r--src/renderer/mod.rs95
-rw-r--r--src/term.rs18
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 {
+
+ // Glyphs are offset within their cell; account for y-flip
+ vec2 cellOffset = vec2(glyphOffset.x, glyphOffset.y - glyphSize.y);
+
+ // position coordinates are normalized on [0, 1]
+ vec2 finalPosition = glyphSize * position + cellPosition + cellOffset;
- // 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;
+ }
- 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
@@ -15,6 +15,9 @@ extern crate notify;
extern crate arrayvec;
#[macro_use]
+extern crate bitflags;
+
+#[macro_use]
mod macros;
mod list_fonts;
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<Atlas>,
+ 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::<f32>()) as *const _);
gl::EnableVertexAttribArray(4);
gl::VertexAttribDivisor(4, 1);
+ // color
+ gl::VertexAttribPointer(5, 3,
+ gl::FLOAT, gl::FALSE,
+ size_of::<InstanceData>() as i32,
+ (13 * size_of::<f32>()) 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<bool>
+ tabs: Vec<bool>,
+
+ /// 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);
}