aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-04-11 08:05:19 -0700
committerJoe Wilm <joe@jwilm.com>2016-04-11 08:05:19 -0700
commite794bc11b962adef4d6fbbaeb85344cb138376da (patch)
tree71d0442ca31a24fcb3c8e64f7887d35688f2109b
parentb84eb9e921c040c4eadaabd8f3087690efa267b6 (diff)
downloadalacritty-e794bc11b962adef4d6fbbaeb85344cb138376da.tar.gz
alacritty-e794bc11b962adef4d6fbbaeb85344cb138376da.zip
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.
-rw-r--r--res/text.f.glsl23
-rw-r--r--src/grid.rs8
-rw-r--r--src/main.rs45
-rw-r--r--src/renderer/mod.rs18
-rw-r--r--src/text.rs21
5 files changed, 93 insertions, 22 deletions
diff --git a/res/text.f.glsl b/res/text.f.glsl
index ce9dd41e..7e80a11c 100644
--- a/res/text.f.glsl
+++ b/res/text.f.glsl
@@ -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);
}
diff --git a/src/grid.rs b/src/grid.rs
index 93d9cd28..0418ed53 100644
--- a/src/grid.rs
+++ b/src/grid.rs
@@ -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 {
diff --git a/src/main.rs b/src/main.rs
index 1845bb94..48aaf11b 100644
--- a/src/main.rs
+++ b/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);
}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index b84ed1ee..001cb40f 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -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 _
);
diff --git a/src/text.rs b/src/text.rs
index ea0df76a..ca414342 100644
--- a/src/text.rs
+++ b/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,
}
}
}