mirror of
https://github.com/alacritty/alacritty.git
synced 2025-04-14 17:53:03 -04:00
Use subpixel font rendering
OpenGL only supports shared alpha blending. Subpixel font rendering requires using the font RGB values as alpha masks for the corresponding RGB channels. To support this, blending is implemented in the fragment shader.
This commit is contained in:
parent
b84eb9e921
commit
e794bc11b9
5 changed files with 93 additions and 22 deletions
|
@ -3,9 +3,28 @@ in vec2 TexCoords;
|
|||
|
||||
uniform sampler2D mask;
|
||||
uniform vec3 textColor;
|
||||
uniform vec3 bgColor;
|
||||
|
||||
// SRC = SRC_ALPHA; DST = 1 - SRC_ALPHA
|
||||
void MyBlend(in vec3 srcValue,
|
||||
in vec3 dstValue,
|
||||
in vec3 srcAlpha,
|
||||
out vec3 blended)
|
||||
{
|
||||
vec3 dstAlpha = vec3(1.0, 1.0, 1.0) - srcAlpha;
|
||||
vec3 preBlended = (srcValue * srcAlpha + dstValue * dstAlpha);
|
||||
|
||||
blended = vec3(min(1.0, preBlended.x),
|
||||
min(1.0, preBlended.y),
|
||||
min(1.0, preBlended.z));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(mask, TexCoords).r);
|
||||
gl_FragColor = vec4(textColor, 1.0) * sampled;
|
||||
// vec4 red = vec4(sampled.rgb, sampled.r * sampled.g * sampled.b);
|
||||
// vec4 sampled = vec4(1.0, 1.0, 1.0, texture(mask, TexCoords));
|
||||
vec3 blended = vec3(1.0, 1.0, 1.0);
|
||||
MyBlend(textColor, bgColor, texture(mask, TexCoords).rgb, blended);
|
||||
|
||||
gl_FragColor = vec4(blended, 1.0);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ pub struct Grid {
|
|||
raw: Vec<Row>,
|
||||
|
||||
/// Number of columns
|
||||
_cols: usize,
|
||||
cols: usize,
|
||||
|
||||
/// Number of rows.
|
||||
///
|
||||
|
@ -43,7 +43,7 @@ impl Grid {
|
|||
|
||||
Grid {
|
||||
raw: raw,
|
||||
_cols: cols,
|
||||
cols: cols,
|
||||
rows: rows,
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,10 @@ impl Grid {
|
|||
pub fn rows(&self) -> usize {
|
||||
self.rows
|
||||
}
|
||||
|
||||
pub fn cols(&self) -> usize {
|
||||
self.cols
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for Grid {
|
||||
|
|
45
src/main.rs
45
src/main.rs
|
@ -20,7 +20,7 @@ use grid::Grid;
|
|||
static INIT_LIST: &'static str = "abcdefghijklmnopqrstuvwxyz\
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
||||
01234567890\
|
||||
~`!@#$%^&*()[]{}-_=+\\|\"/?.,<>";
|
||||
~`!@#$%^&*()[]{}-_=+\\|\"/?.,<>;:";
|
||||
|
||||
fn main() {
|
||||
let window = glutin::Window::new().unwrap();
|
||||
|
@ -37,12 +37,12 @@ fn main() {
|
|||
let (dpi_x, dpi_y) = window.get_dpi().unwrap();
|
||||
let dpr = window.hidpi_factor();
|
||||
|
||||
let font_size = 12.0;
|
||||
let font_size = 11.0;
|
||||
|
||||
let sep_x = 2;
|
||||
let sep_y = 2;
|
||||
let sep_y = 5;
|
||||
|
||||
let desc = FontDesc::new("Ubuntu Mono", "Regular");
|
||||
let desc = FontDesc::new("DejaVu Sans Mono", "Book");
|
||||
let mut rasterizer = text::Rasterizer::new(dpi_x, dpi_y, dpr);
|
||||
|
||||
let (cell_width, cell_height) = rasterizer.box_size_for_font(&desc, font_size);
|
||||
|
@ -54,10 +54,35 @@ fn main() {
|
|||
|
||||
let mut grid = Grid::new(num_rows as usize, num_cols as usize);
|
||||
|
||||
grid[0][0] = grid::Cell::new(Some(String::from("R")));
|
||||
grid[0][1] = grid::Cell::new(Some(String::from("u")));
|
||||
grid[0][2] = grid::Cell::new(Some(String::from("s")));
|
||||
grid[0][3] = grid::Cell::new(Some(String::from("t")));
|
||||
// let contents = [
|
||||
// "for (row, line) in contents.iter().enumerate() {",
|
||||
// " for (i, c) in line.chars().enumerate() {",
|
||||
// " grid[row][i] = grid::Cell::new(Some(c.escape_default().collect()));",
|
||||
// " }",
|
||||
// "}"];
|
||||
|
||||
let contents = include_str!("grid.rs");
|
||||
let mut row = 0usize;
|
||||
let mut col = 0;
|
||||
|
||||
for (i, c) in contents.chars().enumerate() {
|
||||
if c == '\n' {
|
||||
row += 1;
|
||||
col = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if row >= (num_rows as usize) {
|
||||
break;
|
||||
}
|
||||
|
||||
if col >= grid.cols() {
|
||||
continue;
|
||||
}
|
||||
|
||||
grid[row][col] = grid::Cell::new(Some(c.escape_default().collect()));
|
||||
col += 1;
|
||||
}
|
||||
|
||||
let mut glyph_cache = HashMap::new();
|
||||
for c in INIT_LIST.chars() {
|
||||
|
@ -67,8 +92,8 @@ fn main() {
|
|||
}
|
||||
|
||||
unsafe {
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||
// gl::Enable(gl::BLEND);
|
||||
// gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
|
||||
gl::Enable(gl::MULTISAMPLE);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ impl QuadRenderer {
|
|||
unsafe {
|
||||
// set color
|
||||
gl::Uniform3f(self.program.u_color, 1., 1., 0.5);
|
||||
gl::Uniform3f(self.program.u_bg_color, 0.08, 0.08, 0.08);
|
||||
}
|
||||
|
||||
let rect = get_rect(glyph, x, y);
|
||||
|
@ -134,7 +135,7 @@ impl QuadRenderer {
|
|||
|
||||
fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
|
||||
Rect::new(
|
||||
Point2D::new(x, y),
|
||||
Point2D::new(x + glyph.left as f32, y - (glyph.height - glyph.top) as f32),
|
||||
Size2D::new(glyph.width as f32, glyph.height as f32)
|
||||
)
|
||||
}
|
||||
|
@ -152,6 +153,8 @@ pub struct ShaderProgram {
|
|||
u_projection: GLint,
|
||||
/// color uniform
|
||||
u_color: GLint,
|
||||
/// background color uniform
|
||||
u_bg_color: GLint,
|
||||
}
|
||||
|
||||
impl ShaderProgram {
|
||||
|
@ -180,11 +183,13 @@ impl ShaderProgram {
|
|||
// get uniform locations
|
||||
let projection_str = CString::new("projection").unwrap();
|
||||
let color_str = CString::new("textColor").unwrap();
|
||||
let bg_color_str = CString::new("bgColor").unwrap();
|
||||
|
||||
let (projection, color) = unsafe {
|
||||
let (projection, color, bg_color) = unsafe {
|
||||
(
|
||||
gl::GetUniformLocation(program, projection_str.as_ptr()),
|
||||
gl::GetUniformLocation(program, color_str.as_ptr())
|
||||
gl::GetUniformLocation(program, color_str.as_ptr()),
|
||||
gl::GetUniformLocation(program, bg_color_str.as_ptr()),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -192,11 +197,14 @@ impl ShaderProgram {
|
|||
assert!(projection != gl::INVALID_OPERATION as i32);
|
||||
assert!(color != gl::INVALID_VALUE as i32);
|
||||
assert!(color != gl::INVALID_OPERATION as i32);
|
||||
assert!(bg_color != gl::INVALID_VALUE as i32);
|
||||
assert!(bg_color != gl::INVALID_OPERATION as i32);
|
||||
|
||||
let shader = ShaderProgram {
|
||||
id: program,
|
||||
u_projection: projection,
|
||||
u_color: color,
|
||||
u_bg_color: bg_color,
|
||||
};
|
||||
|
||||
// set projection uniform
|
||||
|
@ -287,11 +295,11 @@ impl Glyph {
|
|||
gl::TexImage2D(
|
||||
gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::RED as i32,
|
||||
gl::RGB as i32,
|
||||
rasterized.width as i32,
|
||||
rasterized.height as i32,
|
||||
0,
|
||||
gl::RED,
|
||||
gl::RGB,
|
||||
gl::UNSIGNED_BYTE,
|
||||
rasterized.buf.as_ptr() as *const _
|
||||
);
|
||||
|
|
21
src/text.rs
21
src/text.rs
|
@ -87,15 +87,30 @@ impl Rasterizer {
|
|||
pub fn get_glyph(&mut self, desc: &FontDesc, size: f32, c: char) -> RasterizedGlyph {
|
||||
let face = self.get_face(desc).expect("TODO handle get_face error");
|
||||
face.set_char_size(to_freetype_26_6(size * self.dpr), 0, self.dpi_x, self.dpi_y).unwrap();
|
||||
face.load_char(c as usize, freetype::face::RENDER).unwrap();
|
||||
face.load_char(c as usize, freetype::face::TARGET_LIGHT).unwrap();
|
||||
let glyph = face.glyph();
|
||||
glyph.render_glyph(freetype::render_mode::RenderMode::Lcd).unwrap();
|
||||
|
||||
// FIXME need LCD filtering to reduce color fringes with subpixel rendering. The freetype
|
||||
// bindings don't currently expose this!
|
||||
|
||||
let bitmap = glyph.bitmap();
|
||||
let buf = bitmap.buffer();
|
||||
let pitch = bitmap.pitch() as usize;
|
||||
|
||||
let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
|
||||
for i in 0..bitmap.rows() {
|
||||
let start = (i as usize) * pitch;
|
||||
let stop = start + bitmap.width() as usize;
|
||||
packed.extend_from_slice(&buf[start..stop]);
|
||||
}
|
||||
|
||||
RasterizedGlyph {
|
||||
top: glyph.bitmap_top() as usize,
|
||||
left: glyph.bitmap_left() as usize,
|
||||
width: glyph.bitmap().width() as usize,
|
||||
width: glyph.bitmap().width() as usize / 3,
|
||||
height: glyph.bitmap().rows() as usize,
|
||||
buf: glyph.bitmap().buffer().to_vec(),
|
||||
buf: packed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue