Improved color management
This commit is contained in:
parent
f113ee79bf
commit
ef1d881c57
114
src/graphics.rs
114
src/graphics.rs
|
@ -131,7 +131,7 @@ impl Canvas {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct GlyphInfo {
|
||||
c: char,
|
||||
fg: u32,
|
||||
|
@ -141,24 +141,22 @@ pub struct GlyphInfo {
|
|||
|
||||
pub struct GlyphCache {
|
||||
renderer: BitmapGlyphRenderer,
|
||||
colors: Colors,
|
||||
glyphs: HashMap<GlyphInfo, Box<[u32]>>,
|
||||
}
|
||||
|
||||
impl GlyphCache {
|
||||
pub fn new(colors: Colors, font_config: &FontConfig) -> Self {
|
||||
pub fn new(font_config: &FontConfig) -> Self {
|
||||
Self {
|
||||
renderer: BitmapGlyphRenderer::new(font_config),
|
||||
colors,
|
||||
glyphs: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cell_info(&self, cell: &Cell) -> GlyphInfo {
|
||||
pub fn cell_info(&self, graphics: &Graphics, cell: &Cell) -> GlyphInfo {
|
||||
GlyphInfo {
|
||||
c: cell.c,
|
||||
fg: self.color_to_u32(&cell.fg),
|
||||
bg: self.color_to_u32(&cell.bg),
|
||||
fg: graphics.color_to_u32(&cell.fg),
|
||||
bg: graphics.color_to_u32(&cell.bg),
|
||||
flags: cell.flags,
|
||||
}
|
||||
}
|
||||
|
@ -168,21 +166,6 @@ impl GlyphCache {
|
|||
.entry(glyph.clone())
|
||||
.or_insert_with(|| self.renderer.draw(glyph).into_boxed_slice())
|
||||
}
|
||||
|
||||
// TODO deduplicate
|
||||
pub fn color_to_u32(&self, color: &Color) -> u32 {
|
||||
let rgb = match color {
|
||||
Color::Named(name) => self.colors[*name].unwrap(),
|
||||
Color::Spec(rgb) => *rgb,
|
||||
Color::Indexed(index) => self.colors[*index as usize].unwrap_or(Rgb {
|
||||
r: 255,
|
||||
g: 0,
|
||||
b: 255,
|
||||
}),
|
||||
};
|
||||
|
||||
((rgb.r as u32) << 16) | ((rgb.g as u32) << 8) | (rgb.b as u32)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BitmapGlyphRenderer {
|
||||
|
@ -213,6 +196,8 @@ impl BitmapGlyphRenderer {
|
|||
}
|
||||
|
||||
pub fn draw(&self, glyph: &GlyphInfo) -> Vec<u32> {
|
||||
// eprintln!("rendering glyph: {:?}", glyph);
|
||||
|
||||
let mut buf = Vec::with_capacity(self.cell_width * self.cell_height);
|
||||
|
||||
let font = if glyph.flags.contains(CellFlags::BOLD) {
|
||||
|
@ -246,6 +231,7 @@ impl BitmapGlyphRenderer {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("character bitmap miss: {:?}", glyph.c);
|
||||
buf.resize(buf.capacity(), 0x00ff00ff);
|
||||
}
|
||||
|
||||
|
@ -275,7 +261,7 @@ impl Graphics {
|
|||
let bg = ((bg.r as u32) << 16) | ((bg.g as u32) << 8) | (bg.b as u32);
|
||||
let canvas = Canvas::new(bg, 2000, 2000);
|
||||
|
||||
let glyph_cache = GlyphCache::new(colors.clone(), &config.fonts);
|
||||
let glyph_cache = GlyphCache::new(&config.fonts);
|
||||
let cell_cache = Default::default();
|
||||
|
||||
Self {
|
||||
|
@ -295,14 +281,16 @@ impl Graphics {
|
|||
pub fn load_colors(config: &ColorConfig, colors: &mut Colors) {
|
||||
use NamedColor::*;
|
||||
|
||||
let mut set = |color: NamedColor, value: hex_color::HexColor| {
|
||||
let rgb = Rgb {
|
||||
let rgb = |value: hex_color::HexColor| {
|
||||
Some(Rgb {
|
||||
r: value.r,
|
||||
g: value.g,
|
||||
b: value.b,
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
colors[color] = Some(rgb);
|
||||
let mut set = |color: NamedColor, value: hex_color::HexColor| {
|
||||
colors[color] = rgb(value);
|
||||
};
|
||||
|
||||
set(Background, config.background);
|
||||
|
@ -323,19 +311,69 @@ impl Graphics {
|
|||
set(BrightMagenta, config.bright_magenta);
|
||||
set(BrightCyan, config.bright_cyan);
|
||||
set(BrightWhite, config.bright_white);
|
||||
|
||||
colors[256] = rgb(config.foreground);
|
||||
colors[257] = rgb(config.background);
|
||||
}
|
||||
|
||||
pub fn get_color_idx(&self, index: usize) -> Rgb {
|
||||
if let Some(color) = self.colors[index] {
|
||||
color
|
||||
} else if index > 255 {
|
||||
eprintln!("color miss and out-of-bounds at {index}");
|
||||
|
||||
Rgb {
|
||||
r: 0xff,
|
||||
g: 0x00,
|
||||
b: 0xff,
|
||||
}
|
||||
} else if let Some(gray) = index.checked_sub(232) {
|
||||
let value = gray as u8 * 10 + 8;
|
||||
Rgb {
|
||||
r: value,
|
||||
g: value,
|
||||
b: value,
|
||||
}
|
||||
} else if let Some(cube_idx) = index.checked_sub(16) {
|
||||
let cube_idx = cube_idx as u8;
|
||||
let r = cube_idx / 36;
|
||||
let g = (cube_idx / 6) % 6;
|
||||
let b = cube_idx % 6;
|
||||
|
||||
let c = |c| {
|
||||
if c == 0 {
|
||||
0
|
||||
} else {
|
||||
c * 40 + 55
|
||||
}
|
||||
};
|
||||
|
||||
Rgb {
|
||||
r: c(r),
|
||||
g: c(g),
|
||||
b: c(b),
|
||||
}
|
||||
} else {
|
||||
eprintln!("color index miss at {index}");
|
||||
|
||||
Rgb {
|
||||
r: 0xff,
|
||||
g: 0x00,
|
||||
b: 0xff,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_color(&self, color: &Color) -> Rgb {
|
||||
match color {
|
||||
Color::Named(name) => self.colors[*name].unwrap(),
|
||||
Color::Spec(rgb) => *rgb,
|
||||
Color::Indexed(index) => self.get_color_idx(*index as usize),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color_to_u32(&self, color: &Color) -> u32 {
|
||||
let rgb = match color {
|
||||
Color::Named(name) => self.colors[*name].unwrap(),
|
||||
Color::Spec(rgb) => *rgb,
|
||||
Color::Indexed(index) => self.colors[*index as usize].unwrap_or(Rgb {
|
||||
r: 255,
|
||||
g: 0,
|
||||
b: 255,
|
||||
}),
|
||||
};
|
||||
|
||||
let rgb = self.get_color(color);
|
||||
((rgb.r as u32) << 16) | ((rgb.g as u32) << 8) | (rgb.b as u32)
|
||||
}
|
||||
|
||||
|
@ -380,7 +418,7 @@ impl Graphics {
|
|||
continue;
|
||||
}
|
||||
|
||||
let glyph_info = self.glyph_cache.cell_info(&cell);
|
||||
let glyph_info = self.glyph_cache.cell_info(self, &cell);
|
||||
|
||||
if self.cell_cache.get(&term_coords) == Some(&glyph_info) {
|
||||
continue;
|
||||
|
|
25
src/main.rs
25
src/main.rs
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2022 Marceline Cramer
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use alacritty_terminal::ansi::Color;
|
||||
use alacritty_terminal::config::PtyConfig;
|
||||
use alacritty_terminal::event::{Event as TermEvent, EventListener};
|
||||
use alacritty_terminal::event_loop::{
|
||||
|
@ -47,10 +48,11 @@ fn get_login_shell(config: Config) -> String {
|
|||
config.system.shell
|
||||
} else {
|
||||
match std::env::consts::OS {
|
||||
"linux" | "openbsd" | "netbsd" | "dragonfly" | "solaris" | "macos" =>
|
||||
std::env::var("SHELL").unwrap_or("/bin/sh".to_string()),
|
||||
"linux" | "openbsd" | "netbsd" | "dragonfly" | "solaris" | "macos" => {
|
||||
std::env::var("SHELL").unwrap_or("/bin/sh".to_string())
|
||||
}
|
||||
"windows" => r#"C:\Windows\System32\cmd.exe"#.to_string(),
|
||||
_ => unimplemented!("Unrecognized operating system; cannot get user's shell")
|
||||
_ => unimplemented!("Unrecognized operating system; cannot get user's shell"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +85,9 @@ impl App {
|
|||
|
||||
let term_config = alacritty_terminal::config::Config {
|
||||
pty_config: PtyConfig {
|
||||
shell: Some(alacritty_terminal::config::Program::Just(get_login_shell(config))),
|
||||
shell: Some(alacritty_terminal::config::Program::Just(get_login_shell(
|
||||
config,
|
||||
))),
|
||||
working_directory: None,
|
||||
hold: false,
|
||||
},
|
||||
|
@ -123,22 +127,17 @@ impl App {
|
|||
while let Ok(event) = self.term_events.try_recv() {
|
||||
match event {
|
||||
TermEvent::ColorRequest(index, format) => {
|
||||
let color = self.graphics.colors[index].unwrap_or(Rgb {
|
||||
r: 255,
|
||||
g: 0,
|
||||
b: 255,
|
||||
});
|
||||
|
||||
self.send_input(&format(color));
|
||||
let rgb = self.graphics.get_color_idx(index);
|
||||
self.send_input(&format(rgb));
|
||||
}
|
||||
TermEvent::PtyWrite(text) => self.send_input(&text),
|
||||
TermEvent::Wakeup => self.request_redraw(),
|
||||
TermEvent::Exit => self.should_quit = true,
|
||||
_ => {}
|
||||
event => eprintln!("unhandled event: {:#?}", event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn request_redraw(&self) {
|
||||
self.graphics_context.window().request_redraw();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue