mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 13:21:38 +03:00
Use the palette crate for blending
I wasn't pleased with how text was rendering on a colored background, and after some research I discovered that I was neglecting to convert from sRGB to a linear RGB colorspace, and that this was causing the blending to have inaccurate results. This diff pulls in the palette crate to handle the heavy lifting. It doesn't appear to have any especially fast optimizations for this though, which is a shame because the blending code I was using previously was largely integer math with few branches. The colorspace conversion has several floating point operations and branches that are unavoidable :-/ We run a bit hotter on the CPU but the results are much more pleasing to the eye.
This commit is contained in:
parent
6c75ff4146
commit
4ce67c7f9a
@ -10,6 +10,7 @@ freetype = "0.3.0"
|
|||||||
harfbuzz-sys = "0.1.15"
|
harfbuzz-sys = "0.1.15"
|
||||||
libc = "0.2.36"
|
libc = "0.2.36"
|
||||||
mio = "0.6.12"
|
mio = "0.6.12"
|
||||||
|
palette = "0.2.1"
|
||||||
resize = "0.3.0"
|
resize = "0.3.0"
|
||||||
serde = "1.0.27"
|
serde = "1.0.27"
|
||||||
serde_derive = "1.0.27"
|
serde_derive = "1.0.27"
|
||||||
|
@ -421,9 +421,8 @@ impl Font {
|
|||||||
) -> Result<&ftwrap::FT_GlyphSlotRec_, Error> {
|
) -> Result<&ftwrap::FT_GlyphSlotRec_, Error> {
|
||||||
let info = &mut self.fonts[font_idx];
|
let info = &mut self.fonts[font_idx];
|
||||||
|
|
||||||
let render_mode =
|
let render_mode = ftwrap::FT_Render_Mode::FT_RENDER_MODE_NORMAL;
|
||||||
//ftwrap::FT_Render_Mode::FT_RENDER_MODE_NORMAL;
|
//ftwrap::FT_Render_Mode::FT_RENDER_MODE_LCD;
|
||||||
ftwrap::FT_Render_Mode::FT_RENDER_MODE_LCD;
|
|
||||||
|
|
||||||
// when changing the load flags, we also need
|
// when changing the load flags, we also need
|
||||||
// to change them for harfbuzz otherwise it won't
|
// to change them for harfbuzz otherwise it won't
|
||||||
|
@ -12,6 +12,7 @@ extern crate mio;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
extern crate palette;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
61
src/xgfx.rs
61
src/xgfx.rs
@ -15,6 +15,8 @@ pub type Result<T> = result::Result<T, Error>;
|
|||||||
pub use xkeysyms::*;
|
pub use xkeysyms::*;
|
||||||
|
|
||||||
use super::term::color::RgbColor;
|
use super::term::color::RgbColor;
|
||||||
|
use palette::Blend;
|
||||||
|
use palette::pixel::Srgb;
|
||||||
|
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
conn: xcb::Connection,
|
conn: xcb::Connection,
|
||||||
@ -278,6 +280,21 @@ impl<'a> Drop for Context<'a> {
|
|||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Color(u32);
|
pub struct Color(u32);
|
||||||
|
|
||||||
|
impl From<Srgb> for Color {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: Srgb) -> Color {
|
||||||
|
let b: [u8; 4] = s.to_pixel();
|
||||||
|
Color::rgba(b[0], b[1], b[2], b[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for Srgb {
|
||||||
|
#[inline]
|
||||||
|
fn from(c: Color) -> Srgb {
|
||||||
|
Srgb::from_pixel(&c.as_rgba())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rgb(red: u8, green: u8, blue: u8) -> Color {
|
pub fn rgb(red: u8, green: u8, blue: u8) -> Color {
|
||||||
@ -307,43 +324,41 @@ impl Color {
|
|||||||
pub fn composite(&self, dest: Color, operator: &Operator) -> Color {
|
pub fn composite(&self, dest: Color, operator: &Operator) -> Color {
|
||||||
match operator {
|
match operator {
|
||||||
&Operator::Over => {
|
&Operator::Over => {
|
||||||
let (src_r, src_g, src_b, src_a) = self.as_rgba();
|
let src: Srgb = (*self).into();
|
||||||
let (dst_r, dst_g, dst_b, _dst_a) = dest.as_rgba();
|
let dest: Srgb = dest.into();
|
||||||
|
Srgb::from_linear(src.to_linear().over(dest.to_linear())).into()
|
||||||
// Alpha blending per https://stackoverflow.com/a/12016968/149111
|
|
||||||
let inv_alpha = 256u16 - src_a as u16;
|
|
||||||
let alpha = src_a as u16 + 1;
|
|
||||||
|
|
||||||
Color::rgb(
|
|
||||||
((alpha * src_r as u16 + inv_alpha * dst_r as u16) >> 8) as u8,
|
|
||||||
((alpha * src_g as u16 + inv_alpha * dst_g as u16) >> 8) as u8,
|
|
||||||
((alpha * src_b as u16 + inv_alpha * dst_b as u16) >> 8) as u8,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&Operator::Source => *self,
|
&Operator::Source => *self,
|
||||||
|
|
||||||
&Operator::Multiply => {
|
&Operator::Multiply => {
|
||||||
let (src_r, src_g, src_b, src_a) = self.as_rgba();
|
let src: Srgb = (*self).into();
|
||||||
let (dst_r, dst_g, dst_b, _dst_a) = dest.as_rgba();
|
let dest: Srgb = dest.into();
|
||||||
let r = ((src_r as u16 * dst_r as u16) >> 8) as u8;
|
let result: Color = Srgb::from_linear(src.to_linear().multiply(dest.to_linear()))
|
||||||
let g = ((src_g as u16 * dst_g as u16) >> 8) as u8;
|
.into();
|
||||||
let b = ((src_b as u16 * dst_b as u16) >> 8) as u8;
|
result.into()
|
||||||
|
|
||||||
Color::rgba(r, g, b, src_a)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&Operator::MultiplyThenOver(ref tint) => {
|
&Operator::MultiplyThenOver(ref tint) => {
|
||||||
self.composite(*tint, &Operator::Multiply).composite(
|
// First multiply by the tint color. This colorizes the glyph.
|
||||||
dest,
|
let src: Srgb = (*self).into();
|
||||||
&Operator::Over,
|
let tint: Srgb = (*tint).into();
|
||||||
)
|
let mut tinted = src.to_linear().multiply(tint.to_linear());
|
||||||
|
// We take the alpha from the source. This is important because
|
||||||
|
// we're using Multiply to tint the glyph and if we don't reset the
|
||||||
|
// alpha we tend to end up with a background square of the tint color.
|
||||||
|
tinted.alpha = src.alpha;
|
||||||
|
|
||||||
|
// Then blend the tinted glyph over the destination background
|
||||||
|
let dest: Srgb = dest.into();
|
||||||
|
Srgb::from_linear(tinted.over(dest.to_linear())).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RgbColor> for Color {
|
impl From<RgbColor> for Color {
|
||||||
|
#[inline]
|
||||||
fn from(color: RgbColor) -> Self {
|
fn from(color: RgbColor) -> Self {
|
||||||
Color::rgb(color.red, color.green, color.blue)
|
Color::rgb(color.red, color.green, color.blue)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user