1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-25 14:05:41 -05:00

Add support for drawing background colors

This commit is contained in:
Joe Wilm 2016-06-06 16:54:15 -07:00
parent 6636cf6b9f
commit cdea958e71
No known key found for this signature in database
GPG key ID: 39B57C6972F518DA
8 changed files with 142 additions and 27 deletions

1
Cargo.lock generated
View file

@ -3,6 +3,7 @@ name = "alacritty"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "freetype-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -14,6 +14,7 @@ cgmath = "0.7"
euclid = "0.6" euclid = "0.6"
notify = { git = "https://github.com/jwilm/rsnotify", branch = "add-ignore-op" } notify = { git = "https://github.com/jwilm/rsnotify", branch = "add-ignore-op" }
arrayvec = "0.3" arrayvec = "0.3"
bitflags = "*"
[build-dependencies] [build-dependencies]
gl_generator = "0.5" gl_generator = "0.5"

View file

@ -1,6 +1,8 @@
#version 330 core #version 330 core
in vec2 TexCoords; in vec2 TexCoords;
in vec3 fg; in vec3 fg;
in vec3 bg;
flat in int background;
layout(location = 0, index = 0) out vec4 color; layout(location = 0, index = 0) out vec4 color;
layout(location = 0, index = 1) out vec4 alphaMask; layout(location = 0, index = 1) out vec4 alphaMask;
@ -9,6 +11,12 @@ uniform sampler2D mask;
void main() void main()
{ {
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); alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0);
color = vec4(fg, 1.0); color = vec4(fg, 1.0);
}
} }

View file

@ -12,23 +12,28 @@ layout (location = 3) in vec4 uv;
// text fg color // text fg color
layout (location = 4) in vec3 textColor; layout (location = 4) in vec3 textColor;
// Background color
layout (location = 5) in vec3 backgroundColor;
out vec2 TexCoords; out vec2 TexCoords;
out vec3 fg; out vec3 fg;
out vec3 bg;
// Terminal properties // Terminal properties
uniform vec2 termDim; uniform vec2 termDim;
uniform vec2 cellDim; uniform vec2 cellDim;
uniform vec2 cellSep; uniform vec2 cellSep;
uniform int backgroundPass;
// Orthographic projection // Orthographic projection
uniform mat4 projection; uniform mat4 projection;
flat out int background;
void main() void main()
{ {
vec2 glyphOffset = glyph.xy; vec2 glyphOffset = glyph.xy;
vec2 glyphSize = glyph.zw; vec2 glyphSize = glyph.zw;
vec2 uvOffset = uv.xy; vec2 uvOffset = uv.xy;
vec2 uvSize = uv.zw; vec2 uvSize = uv.zw;
@ -38,14 +43,24 @@ void main()
// Invert Y since framebuffer origin is bottom-left // Invert Y since framebuffer origin is bottom-left
cellPosition.y = termDim.y - cellPosition.y - cellDim.y; cellPosition.y = termDim.y - cellPosition.y - cellDim.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 // Glyphs are offset within their cell; account for y-flip
vec2 cellOffset = vec2(glyphOffset.x, vec2 cellOffset = vec2(glyphOffset.x, glyphOffset.y - glyphSize.y);
glyphOffset.y - glyphSize.y);
// position coordinates are normalized on [0, 1] // position coordinates are normalized on [0, 1]
vec2 finalPosition = glyphSize * position + cellPosition + cellOffset; vec2 finalPosition = glyphSize * position + cellPosition + cellOffset;
gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0); gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0);
TexCoords = uvOffset + vec2(position.x, 1 - position.y) * uvSize; 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); fg = textColor / vec3(255.0, 255.0, 255.0);
} }

View file

@ -19,6 +19,13 @@ pub struct Cell {
pub c: char, pub c: char,
pub fg: Rgb, pub fg: Rgb,
pub bg: Rgb, pub bg: Rgb,
pub flags: CellFlags,
}
bitflags! {
pub flags CellFlags: u32 {
const INVERSE = 0b00000001,
}
} }
impl Cell { impl Cell {
@ -27,6 +34,7 @@ impl Cell {
c: c.into(), c: c.into(),
bg: Default::default(), bg: Default::default(),
fg: Default::default(), fg: Default::default(),
flags: CellFlags::empty(),
} }
} }
} }

View file

@ -14,6 +14,9 @@ extern crate euclid;
extern crate notify; extern crate notify;
extern crate arrayvec; extern crate arrayvec;
#[macro_use]
extern crate bitflags;
#[macro_use] #[macro_use]
mod macros; mod macros;

View file

@ -15,7 +15,7 @@ use gl;
use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op}; use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op};
use text::{Rasterizer, RasterizedGlyph, FontDesc}; use text::{Rasterizer, RasterizedGlyph, FontDesc};
use grid::Grid; use grid::{self, Grid, Cell, CellFlags};
use term; use term;
use super::{Rgb, TermProps}; use super::{Rgb, TermProps};
@ -48,6 +48,11 @@ pub struct ShaderProgram {
/// Cell separation (pixels) /// Cell separation (pixels)
u_cell_sep: GLint, 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, r: f32,
g: f32, g: f32,
b: f32, b: f32,
// background color
bg_r: f32,
bg_g: f32,
bg_b: f32,
} }
#[derive(Debug)] #[derive(Debug)]
@ -166,6 +175,7 @@ pub struct RenderApi<'a> {
active_tex: &'a mut GLuint, active_tex: &'a mut GLuint,
batch: &'a mut Batch, batch: &'a mut Batch,
atlas: &'a mut Vec<Atlas>, atlas: &'a mut Vec<Atlas>,
program: &'a mut ShaderProgram,
} }
#[derive(Debug)] #[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() { if self.is_empty() {
self.tex = glyph.tex_id; self.tex = glyph.tex_id;
} }
self.instances.push(InstanceData { let mut instance = InstanceData {
col: col, col: col,
row: row, row: row,
@ -214,10 +224,26 @@ impl Batch {
uv_width: glyph.uv_width, uv_width: glyph.uv_width,
uv_height: glyph.uv_height, uv_height: glyph.uv_height,
r: color.r as f32, r: cell.fg.r as f32,
g: color.g as f32, g: cell.fg.g as f32,
b: color.b 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] #[inline]
@ -345,6 +371,13 @@ impl QuadRenderer {
(10 * size_of::<f32>()) as *const _); (10 * size_of::<f32>()) as *const _);
gl::EnableVertexAttribArray(4); gl::EnableVertexAttribArray(4);
gl::VertexAttribDivisor(4, 1); 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::BindVertexArray(0);
gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0);
@ -421,6 +454,7 @@ impl QuadRenderer {
active_tex: &mut self.active_tex, active_tex: &mut self.active_tex,
batch: &mut self.batch, batch: &mut self.batch,
atlas: &mut self.atlas, atlas: &mut self.atlas,
program: &mut self.program,
}); });
unsafe { unsafe {
@ -472,6 +506,12 @@ impl<'a> RenderApi<'a> {
} }
unsafe { 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, gl::DrawElementsInstanced(gl::TRIANGLES,
6, gl::UNSIGNED_INT, ptr::null(), 6, gl::UNSIGNED_INT, ptr::null(),
self.batch.len() as GLsizei); self.batch.len() as GLsizei);
@ -491,7 +531,13 @@ impl<'a> RenderApi<'a> {
for c in s.chars() { for c in s.chars() {
if let Some(glyph) = glyph_cache.get(c, self) { 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; col += 1.0;
@ -499,7 +545,7 @@ impl<'a> RenderApi<'a> {
} }
#[inline] #[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 // Flush batch if tex changing
if !self.batch.is_empty() { if !self.batch.is_empty() {
if self.batch.tex != glyph.tex_id { 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 // Render batch and clear if it's full
if self.batch.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) { pub fn render_cursor(&mut self, cursor: term::Cursor, glyph_cache: &mut GlyphCache) {
if let Some(glyph) = glyph_cache.get(term::CURSOR_SHAPE, self) { 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 (i, row) in grid.rows().enumerate() {
for (j, cell) in row.cells().enumerate() { for (j, cell) in row.cells().enumerate() {
// Skip empty cells // Skip empty cells
if cell.c == ' ' { if cell.c == ' ' && cell.bg == term::DEFAULT_BG {
continue; continue;
} }
// Add cell to batch if the glyph is laoded // Add cell to batch if the glyph is laoded
if let Some(glyph) = glyph_cache.get(cell.c, self) { 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 // 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"projection\0")),
gl::GetUniformLocation(program, cptr!(b"termDim\0")), gl::GetUniformLocation(program, cptr!(b"termDim\0")),
gl::GetUniformLocation(program, cptr!(b"cellDim\0")), gl::GetUniformLocation(program, cptr!(b"cellDim\0")),
gl::GetUniformLocation(program, cptr!(b"cellSep\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_term_dim: term_dim,
u_cell_dim: cell_dim, u_cell_dim: cell_dim,
u_cell_sep: cell_sep, u_cell_sep: cell_sep,
u_background: background,
}; };
// set projection uniform // 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 { fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {
unsafe { unsafe {
let program = gl::CreateProgram(); let program = gl::CreateProgram();

View file

@ -2,7 +2,7 @@
use std::sync::Arc; use std::sync::Arc;
use ansi::{self, Attr, DebugHandler}; use ansi::{self, Attr, DebugHandler};
use grid::Grid; use grid::{self, Grid, CellFlags};
use tty; use tty;
use ::Rgb; use ::Rgb;
@ -89,7 +89,10 @@ pub struct Term {
bg: Rgb, bg: Rgb,
/// Tabstops /// Tabstops
tabs: Vec<bool> tabs: Vec<bool>,
/// Cell attributes
attr: grid::CellFlags,
} }
impl Term { impl Term {
@ -111,6 +114,7 @@ impl Term {
bg: DEFAULT_BG, bg: DEFAULT_BG,
tty: tty, tty: tty,
tabs: tabs, tabs: tabs,
attr: CellFlags::empty(),
} }
} }
@ -158,6 +162,7 @@ impl Term {
cell.c = c; cell.c = c;
cell.fg = self.fg; cell.fg = self.fg;
cell.bg = self.bg; cell.bg = self.bg;
cell.flags = self.attr;
} }
/// Advance to next line /// Advance to next line
@ -348,7 +353,14 @@ impl ansi::Handler for Term {
Attr::Reset => { Attr::Reset => {
self.fg = DEFAULT_FG; self.fg = DEFAULT_FG;
self.bg = DEFAULT_BG; 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); println!("Term got unhandled attr: {:?}", attr);
} }