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"
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)",

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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(),
}
}
}

View File

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

View File

@ -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();

View File

@ -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);
}