mirror of
https://github.com/alacritty/alacritty.git
synced 2025-11-06 22:44:18 -05:00
parent
7263d223bf
commit
73c3dd8628
11 changed files with 195 additions and 49 deletions
|
|
@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
- Option `font.builtin_box_drawing` to disable the built-in font for drawing box characters
|
||||
- Track and report surface damage information to Wayland compositors
|
||||
- Escape sequence for undercurl (`CSI 4 : 3 m`)
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,53 @@
|
|||
#version 330 core
|
||||
|
||||
// We're using `origin_upper_left`, since we only known about padding from left
|
||||
// and top. If we use default `origin_bottom_left` we won't be able to offset
|
||||
// `gl_FragCoord` properly to align with the terminal grid.
|
||||
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||
|
||||
flat in vec4 color;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform int isUndercurl;
|
||||
|
||||
uniform float cellWidth;
|
||||
uniform float cellHeight;
|
||||
uniform float paddingY;
|
||||
uniform float paddingX;
|
||||
|
||||
uniform float undercurlThickness;
|
||||
uniform float undercurlPosition;
|
||||
|
||||
#define PI 3.1415926538
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = color;
|
||||
if (isUndercurl == 0) {
|
||||
FragColor = color;
|
||||
return;
|
||||
}
|
||||
|
||||
int x = int(gl_FragCoord.x - paddingX) % int(cellWidth);
|
||||
int y = int(gl_FragCoord.y - paddingY) % int(cellHeight);
|
||||
|
||||
// We use `undercurlPosition` as amplitude, since it's half of the descent
|
||||
// value.
|
||||
float undercurl = -1. * undercurlPosition / 2.
|
||||
* cos(float(x) * 2 * PI / float(cellWidth))
|
||||
+ cellHeight - undercurlPosition;
|
||||
|
||||
float undercurl_top = undercurl + undercurlThickness / 2.;
|
||||
float undercurl_bottom = undercurl - undercurlThickness / 2.;
|
||||
|
||||
|
||||
// Compute resulted alpha based on distance from `gl_FragCoord.y` to the
|
||||
// cosine curve.
|
||||
float alpha = 1.;
|
||||
if (y > undercurl_top || y < undercurl_bottom) {
|
||||
alpha = 1. - min(abs(undercurl_top - y), abs(undercurl_bottom - y));
|
||||
}
|
||||
|
||||
// The result is an alpha mask on a rect, which leaves only curve opaque.
|
||||
FragColor = vec4(color.xyz, alpha);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ impl RenderableCell {
|
|||
self.bg_alpha == 0.
|
||||
&& self.character == ' '
|
||||
&& self.zerowidth.is_none()
|
||||
&& !self.flags.intersects(Flags::UNDERLINE | Flags::STRIKEOUT | Flags::DOUBLE_UNDERLINE)
|
||||
&& !self.flags.intersects(Flags::ALL_UNDERLINES | Flags::STRIKEOUT)
|
||||
}
|
||||
|
||||
/// Apply [`CellRgb`] colors to the cell's colors.
|
||||
|
|
|
|||
|
|
@ -668,7 +668,7 @@ impl Display {
|
|||
rects.push(message_bar_rect);
|
||||
|
||||
// Draw rectangles.
|
||||
self.renderer.draw_rects(&size_info, rects);
|
||||
self.renderer.draw_rects(&size_info, &metrics, rects);
|
||||
|
||||
// Relay messages to the user.
|
||||
let glyph_cache = &mut self.glyph_cache;
|
||||
|
|
@ -681,7 +681,7 @@ impl Display {
|
|||
}
|
||||
} else {
|
||||
// Draw rectangles.
|
||||
self.renderer.draw_rects(&size_info, rects);
|
||||
self.renderer.draw_rects(&size_info, &metrics, rects);
|
||||
}
|
||||
|
||||
self.draw_render_timer(config, &size_info);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::{fmt, ptr};
|
|||
|
||||
use bitflags::bitflags;
|
||||
use crossfont::{
|
||||
BitmapBuffer, Error as RasterizerError, FontDesc, FontKey, GlyphKey, Rasterize,
|
||||
BitmapBuffer, Error as RasterizerError, FontDesc, FontKey, GlyphKey, Metrics, Rasterize,
|
||||
RasterizedGlyph, Rasterizer, Size, Slant, Style, Weight,
|
||||
};
|
||||
use fnv::FnvHasher;
|
||||
|
|
@ -35,6 +35,7 @@ macro_rules! cstr {
|
|||
unsafe { std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr().cast()) }
|
||||
};
|
||||
}
|
||||
pub(crate) use cstr;
|
||||
|
||||
// Shader source.
|
||||
static TEXT_SHADER_F: &str = include_str!("../../res/text.f.glsl");
|
||||
|
|
@ -148,7 +149,7 @@ pub struct GlyphCache {
|
|||
glyph_offset: Delta<i8>,
|
||||
|
||||
/// Font metrics.
|
||||
metrics: crossfont::Metrics,
|
||||
metrics: Metrics,
|
||||
|
||||
/// Whether to use the built-in font for box drawing characters.
|
||||
builtin_box_drawing: bool,
|
||||
|
|
@ -687,7 +688,7 @@ impl QuadRenderer {
|
|||
}
|
||||
|
||||
/// Draw all rectangles simultaneously to prevent excessive program swaps.
|
||||
pub fn draw_rects(&mut self, size_info: &SizeInfo, rects: Vec<RenderRect>) {
|
||||
pub fn draw_rects(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) {
|
||||
if rects.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -699,7 +700,7 @@ impl QuadRenderer {
|
|||
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::SRC_ALPHA, gl::ONE);
|
||||
}
|
||||
|
||||
self.rect_renderer.draw(size_info, rects);
|
||||
self.rect_renderer.draw(size_info, metrics, rects);
|
||||
|
||||
// Activate regular state again.
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@ use alacritty_terminal::term::color::Rgb;
|
|||
use alacritty_terminal::term::SizeInfo;
|
||||
|
||||
use crate::display::content::RenderableCell;
|
||||
use crate::gl;
|
||||
use crate::gl::types::*;
|
||||
use crate::renderer::shader::ShaderProgram;
|
||||
use crate::{gl, renderer};
|
||||
use crate::renderer::shader::{ShaderError, ShaderProgram};
|
||||
use crate::renderer::{self, cstr};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RenderRect {
|
||||
|
|
@ -22,11 +23,12 @@ pub struct RenderRect {
|
|||
pub height: f32,
|
||||
pub color: Rgb,
|
||||
pub alpha: f32,
|
||||
pub is_undercurl: bool,
|
||||
}
|
||||
|
||||
impl RenderRect {
|
||||
pub fn new(x: f32, y: f32, width: f32, height: f32, color: Rgb, alpha: f32) -> Self {
|
||||
RenderRect { x, y, width, height, color, alpha }
|
||||
RenderRect { x, y, width, height, color, alpha, is_undercurl: false }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,20 +82,17 @@ impl RenderLine {
|
|||
|
||||
(bottom_pos, metrics.underline_thickness)
|
||||
},
|
||||
// Make undercurl occupy the entire descent area.
|
||||
Flags::UNDERCURL => (metrics.descent, metrics.descent.abs()),
|
||||
Flags::UNDERLINE => (metrics.underline_position, metrics.underline_thickness),
|
||||
Flags::STRIKEOUT => (metrics.strikeout_position, metrics.strikeout_thickness),
|
||||
_ => unimplemented!("Invalid flag for cell line drawing specified"),
|
||||
};
|
||||
|
||||
rects.push(Self::create_rect(
|
||||
size,
|
||||
metrics.descent,
|
||||
start,
|
||||
end,
|
||||
position,
|
||||
thickness,
|
||||
color,
|
||||
));
|
||||
let mut rect =
|
||||
Self::create_rect(size, metrics.descent, start, end, position, thickness, color);
|
||||
rect.is_undercurl = flag == Flags::UNDERCURL;
|
||||
rects.push(rect);
|
||||
}
|
||||
|
||||
/// Create a line's rect at a position relative to the baseline.
|
||||
|
|
@ -161,6 +160,7 @@ impl RenderLines {
|
|||
self.update_flag(cell, Flags::UNDERLINE);
|
||||
self.update_flag(cell, Flags::DOUBLE_UNDERLINE);
|
||||
self.update_flag(cell, Flags::STRIKEOUT);
|
||||
self.update_flag(cell, Flags::UNDERCURL);
|
||||
}
|
||||
|
||||
/// Update the lines for a specific flag.
|
||||
|
|
@ -222,16 +222,17 @@ pub struct RectRenderer {
|
|||
vao: GLuint,
|
||||
vbo: GLuint,
|
||||
|
||||
program: ShaderProgram,
|
||||
program: RectShaderProgram,
|
||||
|
||||
vertices: Vec<Vertex>,
|
||||
rect_vertices: Vec<Vertex>,
|
||||
curl_vertices: Vec<Vertex>,
|
||||
}
|
||||
|
||||
impl RectRenderer {
|
||||
pub fn new() -> Result<Self, renderer::Error> {
|
||||
let mut vao: GLuint = 0;
|
||||
let mut vbo: GLuint = 0;
|
||||
let program = ShaderProgram::new(RECT_SHADER_V, RECT_SHADER_F)?;
|
||||
let program = RectShaderProgram::new()?;
|
||||
|
||||
unsafe {
|
||||
// Allocate buffers.
|
||||
|
|
@ -273,10 +274,10 @@ impl RectRenderer {
|
|||
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
Ok(Self { vao, vbo, program, vertices: Vec::new() })
|
||||
Ok(Self { vao, vbo, program, rect_vertices: Vec::new(), curl_vertices: Vec::new() })
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, size_info: &SizeInfo, rects: Vec<RenderRect>) {
|
||||
pub fn draw(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) {
|
||||
unsafe {
|
||||
// Bind VAO to enable vertex attribute slots.
|
||||
gl::BindVertexArray(self.vao);
|
||||
|
|
@ -285,28 +286,51 @@ impl RectRenderer {
|
|||
gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
|
||||
|
||||
gl::UseProgram(self.program.id());
|
||||
self.program.update_uniforms(size_info, metrics);
|
||||
}
|
||||
|
||||
let half_width = size_info.width() / 2.;
|
||||
let half_height = size_info.height() / 2.;
|
||||
|
||||
// Build rect vertices vector.
|
||||
self.vertices.clear();
|
||||
self.rect_vertices.clear();
|
||||
self.curl_vertices.clear();
|
||||
for rect in &rects {
|
||||
self.add_rect(half_width, half_height, rect);
|
||||
if rect.is_undercurl {
|
||||
Self::add_rect(&mut self.curl_vertices, half_width, half_height, rect);
|
||||
} else {
|
||||
Self::add_rect(&mut self.rect_vertices, half_width, half_height, rect);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Upload accumulated vertices.
|
||||
gl::BufferData(
|
||||
gl::ARRAY_BUFFER,
|
||||
(self.vertices.len() * mem::size_of::<Vertex>()) as isize,
|
||||
self.vertices.as_ptr() as *const _,
|
||||
gl::STREAM_DRAW,
|
||||
);
|
||||
if !self.curl_vertices.is_empty() {
|
||||
self.program.set_undercurl(true);
|
||||
// Upload accumulated undercurl vertices.
|
||||
gl::BufferData(
|
||||
gl::ARRAY_BUFFER,
|
||||
(self.curl_vertices.len() * mem::size_of::<Vertex>()) as isize,
|
||||
self.curl_vertices.as_ptr() as *const _,
|
||||
gl::STREAM_DRAW,
|
||||
);
|
||||
|
||||
// Draw all vertices as list of triangles.
|
||||
gl::DrawArrays(gl::TRIANGLES, 0, self.vertices.len() as i32);
|
||||
// Draw all vertices as list of triangles.
|
||||
gl::DrawArrays(gl::TRIANGLES, 0, self.curl_vertices.len() as i32);
|
||||
}
|
||||
|
||||
if !self.rect_vertices.is_empty() {
|
||||
self.program.set_undercurl(false);
|
||||
// Upload accumulated rect vertices.
|
||||
gl::BufferData(
|
||||
gl::ARRAY_BUFFER,
|
||||
(self.rect_vertices.len() * mem::size_of::<Vertex>()) as isize,
|
||||
self.rect_vertices.as_ptr() as *const _,
|
||||
gl::STREAM_DRAW,
|
||||
);
|
||||
|
||||
// Draw all vertices as list of triangles.
|
||||
gl::DrawArrays(gl::TRIANGLES, 0, self.rect_vertices.len() as i32);
|
||||
}
|
||||
|
||||
// Disable program.
|
||||
gl::UseProgram(0);
|
||||
|
|
@ -317,7 +341,7 @@ impl RectRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_rect(&mut self, half_width: f32, half_height: f32, rect: &RenderRect) {
|
||||
fn add_rect(vertices: &mut Vec<Vertex>, half_width: f32, half_height: f32, rect: &RenderRect) {
|
||||
// Calculate rectangle vertices positions in normalized device coordinates.
|
||||
// NDC range from -1 to +1, with Y pointing up.
|
||||
let x = rect.x / half_width - 1.0;
|
||||
|
|
@ -336,12 +360,12 @@ impl RectRenderer {
|
|||
];
|
||||
|
||||
// Append the vertices to form two triangles.
|
||||
self.vertices.push(quad[0]);
|
||||
self.vertices.push(quad[1]);
|
||||
self.vertices.push(quad[2]);
|
||||
self.vertices.push(quad[2]);
|
||||
self.vertices.push(quad[3]);
|
||||
self.vertices.push(quad[1]);
|
||||
vertices.push(quad[0]);
|
||||
vertices.push(quad[1]);
|
||||
vertices.push(quad[2]);
|
||||
vertices.push(quad[2]);
|
||||
vertices.push(quad[3]);
|
||||
vertices.push(quad[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -353,3 +377,72 @@ impl Drop for RectRenderer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rectangle drawing program.
|
||||
#[derive(Debug)]
|
||||
pub struct RectShaderProgram {
|
||||
/// Shader program.
|
||||
program: ShaderProgram,
|
||||
|
||||
/// Undercurl flag.
|
||||
///
|
||||
/// Rect rendering has two modes; one for normal filled rects, and other for undercurls.
|
||||
u_is_undercurl: GLint,
|
||||
|
||||
/// Cell width.
|
||||
u_cell_width: GLint,
|
||||
|
||||
/// Cell height.
|
||||
u_cell_height: GLint,
|
||||
|
||||
/// Terminal padding.
|
||||
u_padding_x: GLint,
|
||||
u_padding_y: GLint,
|
||||
|
||||
/// Undercurl thickness.
|
||||
u_undercurl_thickness: GLint,
|
||||
|
||||
/// Undercurl position.
|
||||
u_undercurl_position: GLint,
|
||||
}
|
||||
|
||||
impl RectShaderProgram {
|
||||
pub fn new() -> Result<Self, ShaderError> {
|
||||
let program = ShaderProgram::new(RECT_SHADER_V, RECT_SHADER_F)?;
|
||||
|
||||
Ok(Self {
|
||||
u_is_undercurl: program.get_uniform_location(cstr!("isUndercurl"))?,
|
||||
u_cell_width: program.get_uniform_location(cstr!("cellWidth"))?,
|
||||
u_cell_height: program.get_uniform_location(cstr!("cellHeight"))?,
|
||||
u_padding_x: program.get_uniform_location(cstr!("paddingX"))?,
|
||||
u_padding_y: program.get_uniform_location(cstr!("paddingY"))?,
|
||||
u_undercurl_position: program.get_uniform_location(cstr!("undercurlPosition"))?,
|
||||
u_undercurl_thickness: program.get_uniform_location(cstr!("undercurlThickness"))?,
|
||||
program,
|
||||
})
|
||||
}
|
||||
|
||||
fn id(&self) -> GLuint {
|
||||
self.program.id()
|
||||
}
|
||||
|
||||
fn set_undercurl(&self, is_undercurl: bool) {
|
||||
let value = if is_undercurl { 1 } else { 0 };
|
||||
|
||||
unsafe {
|
||||
gl::Uniform1i(self.u_is_undercurl, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_uniforms(&self, size_info: &SizeInfo, metrics: &Metrics) {
|
||||
let position = (0.5 * metrics.descent).abs();
|
||||
unsafe {
|
||||
gl::Uniform1f(self.u_cell_width, size_info.cell_width());
|
||||
gl::Uniform1f(self.u_cell_height, size_info.cell_height());
|
||||
gl::Uniform1f(self.u_padding_y, size_info.padding_y());
|
||||
gl::Uniform1f(self.u_padding_x, size_info.padding_x());
|
||||
gl::Uniform1f(self.u_undercurl_thickness, metrics.underline_thickness);
|
||||
gl::Uniform1f(self.u_undercurl_position, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -770,6 +770,8 @@ pub enum Attr {
|
|||
Underline,
|
||||
/// Underlined twice.
|
||||
DoubleUnderline,
|
||||
/// Undercurled text.
|
||||
Undercurl,
|
||||
/// Blink cursor slowly.
|
||||
BlinkSlow,
|
||||
/// Blink cursor fast.
|
||||
|
|
@ -1329,6 +1331,7 @@ fn attrs_from_sgr_parameters(params: &mut ParamsIter<'_>) -> Vec<Option<Attr>> {
|
|||
[3] => Some(Attr::Italic),
|
||||
[4, 0] => Some(Attr::CancelUnderline),
|
||||
[4, 2] => Some(Attr::DoubleUnderline),
|
||||
[4, 3] => Some(Attr::Undercurl),
|
||||
[4, ..] => Some(Attr::Underline),
|
||||
[5] => Some(Attr::BlinkSlow),
|
||||
[6] => Some(Attr::BlinkFast),
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ bitflags! {
|
|||
const STRIKEOUT = 0b0000_0010_0000_0000;
|
||||
const LEADING_WIDE_CHAR_SPACER = 0b0000_0100_0000_0000;
|
||||
const DOUBLE_UNDERLINE = 0b0000_1000_0000_0000;
|
||||
const UNDERCURL = 0b0001_0000_0000_0000;
|
||||
const ALL_UNDERLINES = Self::UNDERLINE.bits | Self::DOUBLE_UNDERLINE.bits | Self::UNDERCURL.bits;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,6 +121,7 @@ impl GridCell for Cell {
|
|||
Flags::INVERSE
|
||||
| Flags::UNDERLINE
|
||||
| Flags::DOUBLE_UNDERLINE
|
||||
| Flags::UNDERCURL
|
||||
| Flags::STRIKEOUT
|
||||
| Flags::WRAPLINE
|
||||
| Flags::WIDE_CHAR_SPACER
|
||||
|
|
|
|||
|
|
@ -1839,16 +1839,18 @@ impl<T: EventListener> Handler for Term<T> {
|
|||
Attr::Italic => cursor.template.flags.insert(Flags::ITALIC),
|
||||
Attr::CancelItalic => cursor.template.flags.remove(Flags::ITALIC),
|
||||
Attr::Underline => {
|
||||
cursor.template.flags.remove(Flags::DOUBLE_UNDERLINE);
|
||||
cursor.template.flags.remove(Flags::ALL_UNDERLINES);
|
||||
cursor.template.flags.insert(Flags::UNDERLINE);
|
||||
},
|
||||
Attr::DoubleUnderline => {
|
||||
cursor.template.flags.remove(Flags::UNDERLINE);
|
||||
cursor.template.flags.remove(Flags::ALL_UNDERLINES);
|
||||
cursor.template.flags.insert(Flags::DOUBLE_UNDERLINE);
|
||||
},
|
||||
Attr::CancelUnderline => {
|
||||
cursor.template.flags.remove(Flags::UNDERLINE | Flags::DOUBLE_UNDERLINE);
|
||||
Attr::Undercurl => {
|
||||
cursor.template.flags.remove(Flags::ALL_UNDERLINES);
|
||||
cursor.template.flags.insert(Flags::UNDERCURL);
|
||||
},
|
||||
Attr::CancelUnderline => cursor.template.flags.remove(Flags::ALL_UNDERLINES),
|
||||
Attr::Hidden => cursor.template.flags.insert(Flags::HIDDEN),
|
||||
Attr::CancelHidden => cursor.template.flags.remove(Flags::HIDDEN),
|
||||
Attr::Strike => cursor.template.flags.insert(Flags::STRIKEOUT),
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
{"width":939.0,"height":503.0,"cell_width":8.0,"cell_height":16.0,"padding_x":5.0,"padding_y":3.0,"columns":116,"screen_lines":31}
|
||||
{"width":948.0,"height":1041.0,"cell_width":7.0,"cell_height":16.0,"padding_x":5.0,"padding_y":8.0,"screen_lines":64,"columns":134}
|
||||
Loading…
Add table
Add a link
Reference in a new issue