mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-18 13:55:23 -05:00
Add support for drawing background colors
This commit is contained in:
parent
6636cf6b9f
commit
cdea958e71
8 changed files with 142 additions and 27 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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)",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ extern crate euclid;
|
|||
extern crate notify;
|
||||
extern crate arrayvec;
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
18
src/term.rs
18
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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue