1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-25 06:12:16 +03:00

fixup rendering of wide and color glyphs

This commit is contained in:
Wez Furlong 2018-02-17 08:19:01 -08:00
parent cbad708398
commit 6991f5c6e0

View File

@ -80,9 +80,14 @@ uniform vec3 fg_color;
out vec4 color;
in vec2 tex_coords;
uniform sampler2D glyph_tex;
uniform bool has_color;
void main() {
color = texture(glyph_tex, tex_coords) * vec4(fg_color, 1.0);
color = texture(glyph_tex, tex_coords);
if (!has_color) {
// if it's not a color emoji, tint with the fg_color
color = color * vec4(fg_color, 1.0);
}
}
"#;
@ -171,13 +176,13 @@ struct GlyphKey {
/// Caches a rendered glyph.
/// The image data may be None for whitespace glyphs.
struct CachedGlyph {
image: Option<xgfx::Image>,
has_color: bool,
x_offset: isize,
y_offset: isize,
bearing_x: isize,
bearing_y: isize,
texture: Option<glium::texture::SrgbTexture2d>,
scale: f32,
}
impl<'a> term::TerminalHost for Host<'a> {
@ -496,13 +501,13 @@ impl<'a> TerminalWindow<'a> {
let glyph = if ft_glyph.bitmap.width == 0 || ft_glyph.bitmap.rows == 0 {
// a whitespace glyph
CachedGlyph {
image: None,
texture: None,
has_color,
x_offset: x_offset as isize,
y_offset: y_offset as isize,
bearing_x: 0,
bearing_y: 0,
scale: scale as f32,
}
} else {
@ -519,139 +524,90 @@ impl<'a> TerminalWindow<'a> {
};
let (image, raw_im) =
match mode {
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
let width = ft_glyph.bitmap.width as usize / 3;
let height = ft_glyph.bitmap.rows as usize;
let size = (width * height * 4) as usize;
let mut rgba = Vec::with_capacity(size);
rgba.resize(size, 0u8);
for y in 0..height {
let src_offset = y * pitch as usize;
let dest_offset = y * width * 4;
for x in 0..width {
let blue = data[src_offset + (x * 3) + 0];
let green = data[src_offset + (x * 3) + 1];
let red = data[src_offset + (x * 3) + 2];
let alpha = red | green | blue;
rgba[dest_offset + (x * 4) + 0] = blue;
rgba[dest_offset + (x * 4) + 1] = green;
rgba[dest_offset + (x * 4) + 2] = red;
rgba[dest_offset + (x * 4) + 3] = alpha;
}
let raw_im = match mode {
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_LCD => {
let width = ft_glyph.bitmap.width as usize / 3;
let height = ft_glyph.bitmap.rows as usize;
let size = (width * height * 4) as usize;
let mut rgba = Vec::with_capacity(size);
rgba.resize(size, 0u8);
for y in 0..height {
let src_offset = y * pitch as usize;
let dest_offset = y * width * 4;
for x in 0..width {
let blue = data[src_offset + (x * 3) + 0];
let green = data[src_offset + (x * 3) + 1];
let red = data[src_offset + (x * 3) + 2];
let alpha = red | green | blue;
rgba[dest_offset + (x * 4) + 0] = red;
rgba[dest_offset + (x * 4) + 1] = green;
rgba[dest_offset + (x * 4) + 2] = blue;
rgba[dest_offset + (x * 4) + 3] = alpha;
}
(
xgfx::Image::with_bgr24(width, height, pitch as usize, data),
glium::texture::RawImage2d::from_raw_rgba(
rgba,
(width as u32, height as u32),
),
)
}
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
let width = ft_glyph.bitmap.width as usize;
let height = ft_glyph.bitmap.rows as usize;
let size = (width * height * 4) as usize;
let mut rgba = Vec::with_capacity(size);
rgba.resize(size, 0u8);
for y in 0..height {
let src_offset = y * pitch as usize;
let dest_offset = y * width * 4;
for x in 0..width {
let blue = data[src_offset + (x * 4) + 0];
let green = data[src_offset + (x * 4) + 1];
let red = data[src_offset + (x * 4) + 2];
let alpha = data[src_offset + (x * 4) + 3];
rgba[dest_offset + (x * 4) + 0] = blue;
rgba[dest_offset + (x * 4) + 1] = green;
rgba[dest_offset + (x * 4) + 2] = red;
rgba[dest_offset + (x * 4) + 3] = alpha;
}
glium::texture::RawImage2d::from_raw_rgba(rgba, (width as u32, height as u32))
}
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_BGRA => {
let width = ft_glyph.bitmap.width as usize;
let height = ft_glyph.bitmap.rows as usize;
let size = (width * height * 4) as usize;
let mut rgba = Vec::with_capacity(size);
rgba.resize(size, 0u8);
for y in 0..height {
let src_offset = y * pitch as usize;
let dest_offset = y * width * 4;
for x in 0..width {
let blue = data[src_offset + (x * 4) + 0];
let green = data[src_offset + (x * 4) + 1];
let red = data[src_offset + (x * 4) + 2];
let alpha = data[src_offset + (x * 4) + 3];
rgba[dest_offset + (x * 4) + 0] = red;
rgba[dest_offset + (x * 4) + 1] = green;
rgba[dest_offset + (x * 4) + 2] = blue;
rgba[dest_offset + (x * 4) + 3] = alpha;
}
(
xgfx::Image::with_bgra32(
ft_glyph.bitmap.width as usize,
ft_glyph.bitmap.rows as usize,
pitch as usize,
data,
),
glium::texture::RawImage2d::from_raw_rgba(
rgba,
(width as u32, height as u32),
),
)
}
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
let width = ft_glyph.bitmap.width as usize;
let height = ft_glyph.bitmap.rows as usize;
let size = (width * height * 4) as usize;
let mut rgba = Vec::with_capacity(size);
rgba.resize(size, 0u8);
for y in 0..height {
let src_offset = y * pitch;
let dest_offset = y * width * 4;
for x in 0..width {
let gray = data[src_offset + x];
rgba[dest_offset + (x * 4) + 0] = gray;
rgba[dest_offset + (x * 4) + 1] = gray;
rgba[dest_offset + (x * 4) + 2] = gray;
rgba[dest_offset + (x * 4) + 3] = gray;
}
glium::texture::RawImage2d::from_raw_rgba(rgba, (width as u32, height as u32))
}
ftwrap::FT_Pixel_Mode::FT_PIXEL_MODE_GRAY => {
let width = ft_glyph.bitmap.width as usize;
let height = ft_glyph.bitmap.rows as usize;
let size = (width * height * 4) as usize;
let mut rgba = Vec::with_capacity(size);
rgba.resize(size, 0u8);
for y in 0..height {
let src_offset = y * pitch;
let dest_offset = y * width * 4;
for x in 0..width {
let gray = data[src_offset + x];
rgba[dest_offset + (x * 4) + 0] = gray;
rgba[dest_offset + (x * 4) + 1] = gray;
rgba[dest_offset + (x * 4) + 2] = gray;
rgba[dest_offset + (x * 4) + 3] = gray;
}
(
xgfx::Image::with_8bpp(
ft_glyph.bitmap.width as usize,
ft_glyph.bitmap.rows as usize,
pitch as usize,
data,
),
glium::texture::RawImage2d::from_raw_rgba(
rgba,
(width as u32, height as u32),
),
)
}
mode @ _ => bail!("unhandled pixel mode: {:?}", mode),
};
glium::texture::RawImage2d::from_raw_rgba(rgba, (width as u32, height as u32))
}
mode @ _ => bail!("unhandled pixel mode: {:?}", mode),
};
let tex = glium::texture::SrgbTexture2d::new(&self.host.window, raw_im)?;
let bearing_x = (ft_glyph.bitmap_left as f64 * scale) as isize;
let bearing_y = (ft_glyph.bitmap_top as f64 * scale) as isize;
let image = if scale != 1.0 {
image.scale_by(scale)
} else {
image
};
#[cfg(debug_assertions)]
{
if info.text == "X" {
println!(
"X: x_offset={} bearing_x={} image={:?} info={:?} glyph={:?}",
x_offset,
bearing_x,
image.image_dimensions(),
info,
ft_glyph
);
}
}
CachedGlyph {
image: Some(image),
texture: Some(tex),
has_color,
x_offset: x_offset as isize,
y_offset: y_offset as isize,
bearing_x,
bearing_y,
scale: scale as f32,
}
};
@ -767,6 +723,42 @@ impl<'a> TerminalWindow<'a> {
let (w, h) = image.dimensions();
(w as usize, h as usize)
};
let width = self.width as f32;
let height = self.height as f32;
let scale_y = glyph_height.min(self.cell_height) as f32 / self.cell_height as f32;
let draw_y = base_y - (glyph.y_offset as isize + glyph.bearing_y);
let (r, g, b): (f32, f32, f32) = glyph_color.to_linear().to_pixel();
let draw_x = x + glyph.x_offset as isize + glyph.bearing_x;
// Translate cell coordinate from top-left origin in cell coords
// to center origin pixel coords
let xlate_model = Transform2D::create_translation(
(draw_x as f32) - width / 2.0,
(draw_y as f32) - height / 2.0,
).to_3d();
let scale_x = info.num_cells as f32;
let scale_model = Transform2D::create_scale(scale_x, scale_y).to_3d();
target.draw(
&self.vertex_buffer,
glium::index::NoIndices(
glium::index::PrimitiveType::TriangleStrip,
),
&self.program,
&uniform! {
fg_color: (r, g, b),
projection: self.projection.to_column_arrays(),
translation: scale_model.post_mul(&xlate_model).to_column_arrays(),
glyph_tex: image,
has_color: glyph.has_color,
},
&Default::default(),
)?;
return Ok(());
for slice_x in 0..info.num_cells as usize {
let is_cursor = cursor.x == slice_x + cell_idx && line_idx as i64 == cursor.y;
@ -797,10 +789,7 @@ impl<'a> TerminalWindow<'a> {
};
let draw_x = slice_offset as isize + x + glyph.x_offset as isize + glyph.bearing_x;
let draw_y = base_y - (glyph.y_offset as isize + glyph.bearing_y);
let width = self.width as f32;
let height = self.height as f32;
// Translate cell coordinate from top-left origin in cell coords
// to center origin pixel coords
let xlate_model = Transform2D::create_translation(
@ -808,13 +797,10 @@ impl<'a> TerminalWindow<'a> {
(draw_y as f32) - height / 2.0,
).to_3d();
let scale_y = glyph_height.min(self.cell_height) as f32 / self.cell_height as f32;
let scale_x = slice_width as f32 / slice_width.saturating_sub(slice_offset) as f32;
let scale_model = Transform2D::create_scale(scale_x, scale_y).to_3d();
let (r, g, b): (f32, f32, f32) = glyph_color.to_linear().to_pixel();
target.draw(
&self.vertex_buffer,
glium::index::NoIndices(