From 5876b4bf7a88a59482aefcc85e04a9ef6ecfed74 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Sun, 23 Oct 2016 15:37:06 -0700 Subject: Proof of concept live reloading for colors The architecture here is really poor. Need to move file watching into a dedicated location and probably have an spmc broadcast queue. other modules besides rendering will care about config reloading in the future. --- src/ansi.rs | 12 ++--- src/config.rs | 6 ++- src/main.rs | 17 ++----- src/renderer/mod.rs | 139 +++++++++++++++++++++++++++++++++++++++++----------- src/term.rs | 84 ++++++++++++------------------- 5 files changed, 157 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/src/ansi.rs b/src/ansi.rs index 45cc66f9..c419d7e5 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -337,6 +337,10 @@ pub enum Color { BrightCyan, /// Bright white BrightWhite, + /// The foreground color + Foreground, + /// The background color + Background, } /// Terminal character attributes @@ -384,10 +388,6 @@ pub enum Attr { Background(Color), /// Set specific background color BackgroundSpec(Rgb), - /// Set default foreground - DefaultForeground, - /// Set default background - DefaultBackground, } impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> { @@ -584,7 +584,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> { break; } }, - 39 => Attr::DefaultForeground, + 39 => Attr::Foreground(Color::Foreground), 40 => Attr::Background(Color::Black), 41 => Attr::Background(Color::Red), 42 => Attr::Background(Color::Green), @@ -600,7 +600,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> { break; } }, - 49 => Attr::DefaultBackground, + 49 => Attr::Background(Color::Background), 90 => Attr::Foreground(Color::BrightBlack), 91 => Attr::Foreground(Color::BrightRed), 92 => Attr::Foreground(Color::BrightGreen), diff --git a/src/config.rs b/src/config.rs index 56f96e80..27fcf3ca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -259,7 +259,7 @@ impl Config { /// /// The ordering returned here is expected by the terminal. Colors are simply indexed in this /// array for performance. - pub fn color_list(&self) -> [Rgb; 16] { + pub fn color_list(&self) -> [Rgb; 18] { let colors = &self.colors; [ @@ -282,6 +282,10 @@ impl Config { colors.bright.magenta, colors.bright.cyan, colors.bright.white, + + // Foreground and background + colors.primary.foreground, + colors.primary.background, ] } diff --git a/src/main.rs b/src/main.rs index 9639fd29..9042494d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -112,6 +112,7 @@ pub struct Rgb { } mod gl { + #![allow(non_upper_case_globals)] include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); } @@ -155,7 +156,7 @@ fn main() { let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr); // Create renderer - let mut renderer = QuadRenderer::new(width, height); + let mut renderer = QuadRenderer::new(&config, width, height); // Initialize glyph cache let glyph_cache = { @@ -180,7 +181,6 @@ fn main() { println!("Cell Size: ({} x {})", cell_width, cell_height); let terminal = Term::new( - &config, width as f32, height as f32, cell_width as f32, @@ -295,11 +295,6 @@ impl Display { // events into one. let mut new_size = None; - // TODO should be built into renderer - unsafe { - gl::ClearColor(self.clear_red, self.clear_blue, self.clear_green, 1.0); - gl::Clear(gl::COLOR_BUFFER_BIT); - } // Check for any out-of-band resize events (mac only) while let Ok(sz) = self.rx.try_recv() { @@ -322,18 +317,16 @@ impl Display { let size_info = terminal.size_info().clone(); self.renderer.with_api(&size_info, |mut api| { // Draw the grid - let bg = terminal.bg; - api.render_grid(&bg, &terminal.render_grid(), glyph_cache); + api.render_grid(&terminal.render_grid(), glyph_cache); }); } // Draw render timer if self.render_timer { let timing = format!("{:.3} usec", self.meter.average()); - let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 }; + let color = ::term::cell::Color::Rgb(Rgb { r: 0xd5, g: 0x4e, b: 0x53 }); self.renderer.with_api(terminal.size_info(), |mut api| { - let bg = terminal.bg; - api.render_string(&bg, &timing[..], glyph_cache, &color); + api.render_string(&timing[..], glyph_cache, &color); }); } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 7ddf1d01..959b3d4f 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -20,6 +20,7 @@ use std::path::{PathBuf}; use std::ptr; use std::sync::Arc; use std::sync::atomic::{Ordering, AtomicBool}; +use std::sync::mpsc; use cgmath; use font::{self, Rasterizer, RasterizedGlyph, FontDesc, GlyphKey, FontKey}; @@ -42,6 +43,38 @@ pub trait LoadGlyph { fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph; } +enum Msg { + ConfigReload(Config), + ShaderReload, +} + +/// Colors! +/// +/// FIXME this is obviously bad; need static for reload logic for now. Hacking something in with +/// minimal effort and will improve later. +/// +/// Only renderer is allowed to access this to prevent race conditions +static mut COLORS: [Rgb; 18] = [ + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, + Rgb { r: 0, g: 0, b: 0 }, +]; + /// Text drawing program /// /// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a". @@ -222,7 +255,6 @@ struct InstanceData { #[derive(Debug)] pub struct QuadRenderer { program: ShaderProgram, - should_reload: Arc, vao: GLuint, vbo: GLuint, ebo: GLuint, @@ -230,6 +262,7 @@ pub struct QuadRenderer { atlas: Vec, active_tex: GLuint, batch: Batch, + rx: mpsc::Receiver, } #[derive(Debug)] @@ -272,6 +305,18 @@ impl Batch { self.tex = glyph.tex_id; } + // TODO move colors list to uniform buffer and do this indexing in vertex shader + let fg = match cell.fg { + ::term::cell::Color::Rgb(rgb) => rgb, + ::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] }, + }; + + // TODO move colors list to uniform buffer and do this indexing in vertex shader + let bg = match cell.bg { + ::term::cell::Color::Rgb(rgb) => rgb, + ::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] }, + }; + let mut instance = InstanceData { col: col, row: row, @@ -286,23 +331,23 @@ impl Batch { uv_width: glyph.uv_width, uv_height: glyph.uv_height, - r: cell.fg.r as f32, - g: cell.fg.g as f32, - b: cell.fg.b as f32, + r: fg.r as f32, + g: fg.g as f32, + b: fg.b as f32, - bg_r: cell.bg.r as f32, - bg_g: cell.bg.g as f32, - bg_b: cell.bg.b as f32, + bg_r: bg.r as f32, + bg_g: bg.g as f32, + bg_b: bg.b as f32, }; if cell.flags.contains(cell::INVERSE) { - instance.r = cell.bg.r as f32; - instance.g = cell.bg.g as f32; - instance.b = cell.bg.b as f32; + instance.r = bg.r as f32; + instance.g = bg.g as f32; + instance.b = bg.b as f32; - instance.bg_r = cell.fg.r as f32; - instance.bg_g = cell.fg.g as f32; - instance.bg_b = cell.fg.b as f32; + instance.bg_r = fg.r as f32; + instance.bg_g = fg.g as f32; + instance.bg_b = fg.b as f32; } self.instances.push(instance); @@ -345,7 +390,7 @@ const ATLAS_SIZE: i32 = 1024; impl QuadRenderer { // TODO should probably hand this a transform instead of width/height - pub fn new(width: u32, height: u32) -> QuadRenderer { + pub fn new(config: &Config, width: u32, height: u32) -> QuadRenderer { let program = ShaderProgram::new(width, height).unwrap(); let mut vao: GLuint = 0; @@ -448,11 +493,14 @@ impl QuadRenderer { let should_reload = Arc::new(AtomicBool::new(false)); let should_reload2 = should_reload.clone(); + let (msg_tx, msg_rx) = mpsc::channel(); + ::std::thread::spawn(move || { - let (tx, rx) = ::std::sync::mpsc::channel(); + let (tx, rx) = mpsc::channel(); let mut watcher = Watcher::new(tx).unwrap(); watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader"); watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader"); + watcher.watch("/home/jwilm/.alacritty.yml").expect("watch alacritty yml"); loop { let event = rx.recv().expect("watcher event"); @@ -468,10 +516,17 @@ impl QuadRenderer { if let Err(err) = watcher.watch(path) { println!("failed to establish watch on {:?}: {:?}", path, err); } - } - // This is last event we see after saving in vim - should_reload2.store(true, Ordering::Relaxed); + if path == ::std::path::Path::new("/home/jwilm/.alacritty.yml") { + if let Ok(config) = Config::load() { + msg_tx.send(Msg::ConfigReload(config)) + .expect("msg send ok"); + }; + } else { + msg_tx.send(Msg::ShaderReload) + .expect("msg send ok"); + } + } } } } @@ -479,7 +534,6 @@ impl QuadRenderer { let mut renderer = QuadRenderer { program: program, - should_reload: should_reload, vao: vao, vbo: vbo, ebo: ebo, @@ -487,8 +541,13 @@ impl QuadRenderer { atlas: Vec::new(), active_tex: 0, batch: Batch::new(), + rx: msg_rx, }; + unsafe { + COLORS = config.color_list(); + } + let atlas = Atlas::new(ATLAS_SIZE); renderer.atlas.push(atlas); @@ -498,8 +557,17 @@ impl QuadRenderer { pub fn with_api(&mut self, props: &term::SizeInfo, func: F) -> T where F: FnOnce(RenderApi) -> T { - if self.should_reload.load(Ordering::Relaxed) { - self.reload_shaders(props.width as u32, props.height as u32); + while let Ok(msg) = self.rx.try_recv() { + match msg { + Msg::ConfigReload(config) => { + unsafe { + COLORS = config.color_list(); + } + }, + Msg::ShaderReload => { + self.reload_shaders(props.width as u32, props.height as u32); + } + } } unsafe { @@ -544,7 +612,6 @@ impl QuadRenderer { } pub fn reload_shaders(&mut self, width: u32, height: u32) { - self.should_reload.store(false, Ordering::Relaxed); let program = match ShaderProgram::new(width, height) { Ok(program) => program, Err(err) => { @@ -612,10 +679,9 @@ impl<'a> RenderApi<'a> { /// optimization. pub fn render_string( &mut self, - bg: &Rgb, s: &str, glyph_cache: &mut GlyphCache, - color: &Rgb, + color: &::term::cell::Color, ) { let row = 40.0; let mut col = 100.0; @@ -630,8 +696,8 @@ impl<'a> RenderApi<'a> { if let Some(glyph) = glyph_cache.get(&glyph_key, self) { let cell = Cell { c: c, - fg: *color, - bg: *bg, + fg: color.clone(), + bg: cell::Color::Rgb(Rgb { r: 0, g: 0, b: 0}), flags: cell::INVERSE, }; self.add_render_item(row, col, &cell, glyph); @@ -658,12 +724,27 @@ impl<'a> RenderApi<'a> { } } - pub fn render_grid(&mut self, bg: &Rgb, grid: &Grid, glyph_cache: &mut GlyphCache) { + pub fn render_grid( + &mut self, + grid: &Grid, + glyph_cache: &mut GlyphCache + ) { + // TODO should be built into renderer + let color = unsafe { COLORS[::ansi::Color::Background as usize] }; + unsafe { + gl::ClearColor( + color.r as f32 / 255.0, + color.g as f32 / 255.0, + color.b as f32 / 255.0, + 1.0 + ); + gl::Clear(gl::COLOR_BUFFER_BIT); + } + for (i, line) in grid.lines().enumerate() { for (j, cell) in line.cells().enumerate() { // Skip empty cells - if cell.c == ' ' && - cell.bg == *bg && + if cell.c == ' ' && cell.bg == cell::Color::Ansi(::ansi::Color::Background) && !cell.flags.contains(cell::INVERSE) { continue; diff --git a/src/term.rs b/src/term.rs index 898251d7..a2b6aa3c 100644 --- a/src/term.rs +++ b/src/term.rs @@ -21,9 +21,7 @@ use ansi::{self, Attr, Handler}; use grid::{Grid, ClearRegion}; use index::{Cursor, Column, Line}; use tty; -use config::Config; - -use ::Rgb; +use ansi::Color; /// RAII type which manages grid state for render /// @@ -90,20 +88,26 @@ pub mod cell { } } - #[derive(Clone, Debug, Copy)] + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum Color { + Rgb(Rgb), + Ansi(::ansi::Color), + } + + #[derive(Clone, Debug)] pub struct Cell { pub c: char, - pub fg: Rgb, - pub bg: Rgb, + pub fg: Color, + pub bg: Color, pub flags: Flags, } impl Cell { - pub fn new(c: char) -> Cell { + pub fn new(c: char, fg: Color, bg: Color) -> Cell { Cell { c: c.into(), - bg: Default::default(), - fg: Default::default(), + bg: bg, + fg: fg, flags: Flags::empty(), } } @@ -111,13 +115,7 @@ pub mod cell { #[inline] pub fn reset(&mut self, template: &Cell) { // memcpy template to self - unsafe { - ::std::ptr::copy_nonoverlapping( - template as *const Cell, - self as *mut Cell, - 1 - ); - } + *self = template.clone(); } } } @@ -165,12 +163,6 @@ pub struct Term { /// Alt cursor alt_cursor: Cursor, - /// Active foreground color - pub fg: Rgb, - - /// Active background color - pub bg: Rgb, - /// Tabstops tabs: Vec, @@ -189,9 +181,6 @@ pub struct Term { /// Empty cell empty_cell: Cell, - /// Text colors - colors: [Rgb; 16], - pub dirty: bool, } @@ -225,7 +214,6 @@ impl SizeInfo { impl Term { pub fn new( - config: &Config, width: f32, height: f32, cell_width: f32, @@ -238,20 +226,18 @@ impl Term { cell_height: cell_height as f32, }; - let mut template = Cell::new(' '); - template.flags = cell::Flags::empty(); - template.bg = config.bg_color(); - template.fg = config.fg_color(); + let template = Cell::new( + ' ', + cell::Color::Ansi(Color::Foreground), + cell::Color::Ansi(Color::Background) + ); let num_cols = size.cols(); let num_lines = size.lines(); println!("num_cols, num_lines = {}, {}", num_cols, num_lines); - println!("bg: {:?}, fg: {:?}", template.bg, template.fg); - println!("colors: {:?}", config.color_list()); - - let grid = Grid::new(num_lines, num_cols, &Cell::new(' ')); + let grid = Grid::new(num_lines, num_cols, &template); let tty = tty::new(*num_lines as u8, *num_cols as u8); tty.resize(*num_lines as usize, *num_cols as usize, size.width as usize, size.height as usize); @@ -272,16 +258,13 @@ impl Term { alt: false, cursor: Cursor::default(), alt_cursor: Cursor::default(), - fg: config.fg_color(), - bg: config.bg_color(), tty: tty, tabs: tabs, mode: Default::default(), scroll_region: scroll_region, size_info: size, - template_cell: template, + template_cell: template.clone(), empty_cell: template, - colors: config.color_list(), } } @@ -323,8 +306,9 @@ impl Term { println!("num_cols, num_lines = {}, {}", num_cols, num_lines); // Resize grids to new size - self.grid.resize(num_lines, num_cols, &Cell::new(' ')); - self.alt_grid.resize(num_lines, num_cols, &Cell::new(' ')); + let template = self.template_cell.clone(); + self.grid.resize(num_lines, num_cols, &template); + self.alt_grid.resize(num_lines, num_cols, &template); // Ensure cursor is in-bounds self.cursor.line = limit(self.cursor.line, Line(0), num_lines); @@ -462,7 +446,7 @@ impl ansi::Handler for Term { } let cell = &mut self.grid[&self.cursor]; - *cell = self.template_cell; + *cell = self.template_cell.clone(); cell.c = c; self.cursor.col += 1; } @@ -779,27 +763,21 @@ impl ansi::Handler for Term { fn terminal_attribute(&mut self, attr: Attr) { debug_println!("Set Attribute: {:?}", attr); match attr { - Attr::DefaultForeground => { - self.template_cell.fg = self.fg; - }, - Attr::DefaultBackground => { - self.template_cell.bg = self.bg; - }, Attr::Foreground(named_color) => { - self.template_cell.fg = self.colors[named_color as usize]; + self.template_cell.fg = cell::Color::Ansi(named_color); }, Attr::Background(named_color) => { - self.template_cell.bg = self.colors[named_color as usize]; + self.template_cell.bg = cell::Color::Ansi(named_color); }, Attr::ForegroundSpec(rgb) => { - self.template_cell.fg = rgb; + self.template_cell.fg = cell::Color::Rgb(rgb); }, Attr::BackgroundSpec(rgb) => { - self.template_cell.bg = rgb; + self.template_cell.bg = cell::Color::Rgb(rgb); }, Attr::Reset => { - self.template_cell.fg = self.fg; - self.template_cell.bg = self.bg; + self.template_cell.fg = cell::Color::Ansi(Color::Foreground); + self.template_cell.bg = cell::Color::Ansi(Color::Background); self.template_cell.flags = cell::Flags::empty(); }, Attr::Reverse => self.template_cell.flags.insert(cell::INVERSE), -- cgit From b29eed27cf6d6fbe36b68564b90fa90f767e7167 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 24 Oct 2016 08:24:33 -0700 Subject: Add discriminant_value test for cell::Color The renderer should be able to use the discriminant_value to determine vertex colors. --- src/term.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src') diff --git a/src/term.rs b/src/term.rs index a2b6aa3c..cac260a2 100644 --- a/src/term.rs +++ b/src/term.rs @@ -118,6 +118,23 @@ pub mod cell { *self = template.clone(); } } + + #[cfg(test)] + mod tests { + use super::Color; + use std::intrinsics::discriminant_value; + + #[test] + fn color_discriminant_values() { + let rgb_color = Color::Rgb(::Rgb { r: 0, g: 0, b: 0 }); + let ansi_color = Color::Ansi(::ansi::Color::Foreground); + + unsafe { + assert_eq!(discriminant_value(&rgb_color), 0); + assert_eq!(discriminant_value(&ansi_color), 1); + } + } + } } pub use self::cell::Cell; -- cgit From 741a8b3f47117d2d72af29c39627603595402168 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 24 Oct 2016 08:36:14 -0700 Subject: Fix some compiler warnings --- src/main.rs | 14 +++----------- src/renderer/mod.rs | 5 ----- 2 files changed, 3 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 9042494d..01c5f511 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,7 +75,7 @@ use term::Term; use tty::process_should_exit; /// Channel used by resize handling on mac -static mut resize_sender: Option> = None; +static mut RESIZE_SENDER: Option> = None; #[derive(Clone)] pub struct Flag(Arc); @@ -98,7 +98,7 @@ impl Flag { /// Resize handling for Mac fn window_resize_handler(width: u32, height: u32) { unsafe { - if let Some(ref tx) = resize_sender { + if let Some(ref tx) = RESIZE_SENDER { let _ = tx.send((width, height)); } } @@ -190,7 +190,7 @@ fn main() { let (tx, rx) = mpsc::channel(); unsafe { - resize_sender = Some(tx.clone()); + RESIZE_SENDER = Some(tx.clone()); } let signal_flag = Flag::new(false); @@ -214,7 +214,6 @@ fn main() { window.clone(), renderer, glyph_cache, - config.bg_color(), render_timer, rx ); @@ -253,9 +252,6 @@ struct Display { renderer: QuadRenderer, glyph_cache: GlyphCache, render_timer: bool, - clear_red: f32, - clear_blue: f32, - clear_green: f32, rx: mpsc::Receiver<(u32, u32)>, meter: Meter, } @@ -264,7 +260,6 @@ impl Display { pub fn new(window: Arc, renderer: QuadRenderer, glyph_cache: GlyphCache, - clear_color: Rgb, render_timer: bool, rx: mpsc::Receiver<(u32, u32)>) -> Display @@ -274,9 +269,6 @@ impl Display { renderer: renderer, glyph_cache: glyph_cache, render_timer: render_timer, - clear_red: clear_color.r as f32 / 255.0, - clear_blue: clear_color.g as f32 / 255.0, - clear_green: clear_color.b as f32 / 255.0, rx: rx, meter: Meter::new(), } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 959b3d4f..8ca82ba7 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -18,8 +18,6 @@ use std::io::{self, Read}; use std::mem::size_of; use std::path::{PathBuf}; use std::ptr; -use std::sync::Arc; -use std::sync::atomic::{Ordering, AtomicBool}; use std::sync::mpsc; use cgmath; @@ -490,9 +488,6 @@ impl QuadRenderer { gl::BindBuffer(gl::ARRAY_BUFFER, 0); } - let should_reload = Arc::new(AtomicBool::new(false)); - let should_reload2 = should_reload.clone(); - let (msg_tx, msg_rx) = mpsc::channel(); ::std::thread::spawn(move || { -- cgit From e9304afd36e549b5c330f8a35545ae61808a1553 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 24 Oct 2016 08:44:07 -0700 Subject: Expand cell::Color layout tests The whole enumeration should be well defined for the renderer. --- src/term.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/term.rs b/src/term.rs index cac260a2..bcd78814 100644 --- a/src/term.rs +++ b/src/term.rs @@ -122,16 +122,34 @@ pub mod cell { #[cfg(test)] mod tests { use super::Color; - use std::intrinsics::discriminant_value; + use std::mem; + // Ensure memory layout is well defined so components like renderer + // can exploit it. + // + // Thankfully, everything is just a u8 for now so no endianness + // considerations are needed. #[test] - fn color_discriminant_values() { - let rgb_color = Color::Rgb(::Rgb { r: 0, g: 0, b: 0 }); + fn color_memory_layout() { + let rgb_color = Color::Rgb(::Rgb { r: 1, g: 2, b: 3 }); let ansi_color = Color::Ansi(::ansi::Color::Foreground); unsafe { - assert_eq!(discriminant_value(&rgb_color), 0); - assert_eq!(discriminant_value(&ansi_color), 1); + // Color::Rgb + // [discriminant(0), red, green ,blue] + let bytes: [u8; 4] = mem::transmute_copy(&rgb_color); + assert_eq!(bytes[0], 0); + assert_eq!(bytes[1], 1); + assert_eq!(bytes[2], 2); + assert_eq!(bytes[3], 3); + + // Color::Ansi + // [discriminant(1), ansi::Color, 0, 0] + let bytes: [u8; 4] = mem::transmute_copy(&ansi_color); + assert_eq!(bytes[0], 1); + assert_eq!(bytes[1], ::ansi::Color::Foreground as u8); + assert_eq!(bytes[2], 0); + assert_eq!(bytes[3], 0); } } } -- cgit From 0958c0f0f28664fe2f48ad1b552b69b0ced731c1 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Mon, 24 Oct 2016 10:59:25 -0700 Subject: Move color indexing to vertex shader Move more work to GPU from CPU. Some very non-scientific profiling suggests this is implementation is more performant, but more work should be done there. --- src/renderer/mod.rs | 121 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 8ca82ba7..eccbb8af 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -93,7 +93,12 @@ pub struct ShaderProgram { /// Background pass flag /// /// Rendering is split into two passes; 1 for backgrounds, and one for text - u_background: GLint + u_background: GLint, + + /// Color uniforms + /// + /// Ansi colors are uploaded to the GPU and indexed in the vertex shader + u_colors: [GLint; 18], } @@ -224,6 +229,7 @@ impl GlyphCache { } #[derive(Debug)] +#[repr(C)] struct InstanceData { // coords col: f32, @@ -241,13 +247,15 @@ struct InstanceData { uv_width: f32, uv_height: f32, // color - r: f32, - g: f32, - b: f32, + disc: u32, + r: u32, + g: u32, + b: u32, // background color - bg_r: f32, - bg_g: f32, - bg_b: f32, + bg_disc: u32, + bg_r: u32, + bg_g: u32, + bg_b: u32, } #[derive(Debug)] @@ -260,6 +268,7 @@ pub struct QuadRenderer { atlas: Vec, active_tex: GLuint, batch: Batch, + colors: [Rgb; 18], rx: mpsc::Receiver, } @@ -303,17 +312,8 @@ impl Batch { self.tex = glyph.tex_id; } - // TODO move colors list to uniform buffer and do this indexing in vertex shader - let fg = match cell.fg { - ::term::cell::Color::Rgb(rgb) => rgb, - ::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] }, - }; - - // TODO move colors list to uniform buffer and do this indexing in vertex shader - let bg = match cell.bg { - ::term::cell::Color::Rgb(rgb) => rgb, - ::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] }, - }; + let fg: &[u8; 4] = unsafe { ::std::mem::transmute(&cell.fg) }; + let bg: &[u8; 4] = unsafe { ::std::mem::transmute(&cell.bg) }; let mut instance = InstanceData { col: col, @@ -329,23 +329,27 @@ impl Batch { uv_width: glyph.uv_width, uv_height: glyph.uv_height, - r: fg.r as f32, - g: fg.g as f32, - b: fg.b as f32, + disc: fg[0] as u32, + r: fg[1] as u32, + g: fg[2] as u32, + b: fg[3] as u32, - bg_r: bg.r as f32, - bg_g: bg.g as f32, - bg_b: bg.b as f32, + bg_disc: bg[0] as u32, + bg_r: bg[1] as u32, + bg_g: bg[2] as u32, + bg_b: bg[3] as u32, }; if cell.flags.contains(cell::INVERSE) { - instance.r = bg.r as f32; - instance.g = bg.g as f32; - instance.b = bg.b as f32; - - instance.bg_r = fg.r as f32; - instance.bg_g = fg.g as f32; - instance.bg_b = fg.b as f32; + instance.disc = bg[0] as u32; + instance.r = bg[1] as u32; + instance.g = bg[2] as u32; + instance.b = bg[3] as u32; + + instance.bg_disc = fg[0] as u32; + instance.bg_r = fg[1] as u32; + instance.bg_g = fg[2] as u32; + instance.bg_b = fg[3] as u32; } self.instances.push(instance); @@ -389,7 +393,8 @@ const ATLAS_SIZE: i32 = 1024; impl QuadRenderer { // TODO should probably hand this a transform instead of width/height pub fn new(config: &Config, width: u32, height: u32) -> QuadRenderer { - let program = ShaderProgram::new(width, height).unwrap(); + let colors = config.color_list(); + let program = ShaderProgram::new(&colors, width, height).unwrap(); let mut vao: GLuint = 0; let mut vbo: GLuint = 0; @@ -470,17 +475,17 @@ impl QuadRenderer { gl::EnableVertexAttribArray(3); gl::VertexAttribDivisor(3, 1); // color - gl::VertexAttribPointer(4, 3, - gl::FLOAT, gl::FALSE, + gl::VertexAttribIPointer(4, 4, + gl::UNSIGNED_INT, size_of::() as i32, (10 * size_of::()) as *const _); gl::EnableVertexAttribArray(4); gl::VertexAttribDivisor(4, 1); // color - gl::VertexAttribPointer(5, 3, - gl::FLOAT, gl::FALSE, + gl::VertexAttribIPointer(5, 4, + gl::UNSIGNED_INT, size_of::() as i32, - (13 * size_of::()) as *const _); + (14 * size_of::()) as *const _); gl::EnableVertexAttribArray(5); gl::VertexAttribDivisor(5, 1); @@ -536,6 +541,7 @@ impl QuadRenderer { atlas: Vec::new(), active_tex: 0, batch: Batch::new(), + colors: config.color_list(), rx: msg_rx, }; @@ -555,9 +561,10 @@ impl QuadRenderer { while let Ok(msg) = self.rx.try_recv() { match msg { Msg::ConfigReload(config) => { - unsafe { - COLORS = config.color_list(); - } + self.colors = config.color_list(); + self.program.activate(); + self.program.set_color_uniforms(&self.colors); + self.program.deactivate(); }, Msg::ShaderReload => { self.reload_shaders(props.width as u32, props.height as u32); @@ -607,7 +614,7 @@ impl QuadRenderer { } pub fn reload_shaders(&mut self, width: u32, height: u32) { - let program = match ShaderProgram::new(width, height) { + let program = match ShaderProgram::new(&self.colors, width, height) { Ok(program) => program, Err(err) => { match err { @@ -826,7 +833,11 @@ impl ShaderProgram { } } - pub fn new(width: u32, height: u32) -> Result { + pub fn new( + colors: &[Rgb; 18], + width: u32, + height: u32 + ) -> Result { let vertex_shader = ShaderProgram::create_shader(TEXT_SHADER_V_PATH, gl::VERTEX_SHADER)?; let fragment_shader = ShaderProgram::create_shader(TEXT_SHADER_F_PATH, gl::FRAGMENT_SHADER)?; @@ -864,8 +875,19 @@ impl ShaderProgram { assert_uniform_valid!(projection, term_dim, cell_dim); + let mut color_uniforms: [GLint; 18] = unsafe { ::std::mem::uninitialized() }; + for i in 0..18 { + color_uniforms[i] = unsafe { + let s = format!("colors[{}]\0", i).into_bytes(); + gl::GetUniformLocation(program, cptr!(&s[..])) + }; + + assert_uniform_valid!(color_uniforms[i]); + } + let shader = ShaderProgram { id: program, + u_colors: color_uniforms, u_projection: projection, u_term_dim: term_dim, u_cell_dim: cell_dim, @@ -873,6 +895,7 @@ impl ShaderProgram { }; shader.update_projection(width as f32, height as f32); + shader.set_color_uniforms(colors); shader.deactivate(); @@ -893,6 +916,20 @@ impl ShaderProgram { } + fn set_color_uniforms(&self, colors: &[Rgb; 18]) { + println!("setting colors: {:#?}", colors); + for (i, rgb) in colors.iter().enumerate() { + unsafe { + gl::Uniform3f( + self.u_colors[i], + rgb.r as f32 / 255.0, + rgb.g as f32 / 255.0, + rgb.b as f32 / 255.0, + ); + } + } + } + fn set_term_uniforms(&self, props: &term::SizeInfo) { unsafe { gl::Uniform2f(self.u_term_dim, props.width, props.height); -- cgit From 06ea6c8e565af0fdddc4de80f59435cfe05670c2 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 27 Oct 2016 10:05:04 -0700 Subject: Move config reloading to separate thread This feature was previously shoved into the renderer due to initial proof of concept. Now, providing config updates to other systems is possible. This will be especially important for key bindings! --- src/config.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++-------- src/main.rs | 44 +++++++++++++++++++++++++++++++--- src/renderer/mod.rs | 61 ++++++++++------------------------------------- 3 files changed, 111 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/config.rs b/src/config.rs index 27fcf3ca..f3e68dca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,11 +7,13 @@ use std::env; use std::fs; use std::io::{self, Read}; use std::path::{Path, PathBuf}; +use std::sync::mpsc; use ::Rgb; use font::Size; use serde_yaml; use serde::{self, Error as SerdeError}; +use notify::{Watcher as WatcherApi, RecommendedWatcher as FileWatcher, op}; /// Top-level config type #[derive(Debug, Deserialize, Default)] @@ -232,7 +234,7 @@ impl Config { /// /// 1. `$HOME/.config/alacritty.yml` /// 2. `$HOME/.alacritty.yml` - pub fn load() -> Result { + pub fn load() -> Result<(Config, PathBuf)> { let home = env::var("HOME")?; // First path @@ -240,15 +242,17 @@ impl Config { path.push(".config"); path.push("alacritty.yml"); - // Fallback path - let mut alt_path = PathBuf::from(&home); - alt_path.push(".alacritty.yml"); - - match Config::load_from(&path) { + match Config::load_from(path) { Ok(c) => Ok(c), Err(e) => { match e { - Error::NotFound => Config::load_from(&alt_path), + Error::NotFound => { + // Fallback path + let mut alt_path = PathBuf::from(&home); + alt_path.push(".alacritty.yml"); + + Config::load_from(alt_path) + }, _ => Err(e), } } @@ -315,9 +319,10 @@ impl Config { self.render_timer } - fn load_from>(path: P) -> Result { - let raw = Config::read_file(path)?; - Ok(serde_yaml::from_str(&raw[..])?) + fn load_from>(path: P) -> Result<(Config, PathBuf)> { + let path = path.into(); + let raw = Config::read_file(path.as_path())?; + Ok((serde_yaml::from_str(&raw[..])?, path)) } fn read_file>(path: P) -> Result { @@ -525,3 +530,46 @@ impl Default for Font { } } } + +pub struct Watcher(::std::thread::JoinHandle<()>); + +pub trait OnConfigReload { + fn on_config_reload(&mut self, Config); +} + +impl Watcher { + pub fn new(path: PathBuf, mut handler: H) -> Watcher { + Watcher(::util::thread::spawn_named("config watcher", move || { + let (tx, rx) = mpsc::channel(); + let mut watcher = FileWatcher::new(tx).unwrap(); + watcher.watch(&path).expect("watch alacritty yml"); + + let config_path = path.as_path(); + + loop { + let event = rx.recv().expect("watcher event"); + let ::notify::Event { path, op } = event; + + if let Ok(op) = op { + if op.contains(op::RENAME) { + continue; + } + + if op.contains(op::IGNORED) { + if let Some(path) = path.as_ref() { + if let Err(err) = watcher.watch(&path) { + err_println!("failed to establish watch on {:?}: {:?}", path, err); + } + + if path == config_path { + if let Ok((config, _)) = Config::load() { + handler.on_config_reload(config); + }; + } + } + } + } + } + })) + } +} diff --git a/src/main.rs b/src/main.rs index 01c5f511..8a2159e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -118,14 +118,14 @@ mod gl { fn main() { // Load configuration - let config = match Config::load() { + let (config, config_path) = match Config::load() { Err(err) => match err { // Use default config when not found - config::Error::NotFound => Config::default(), + config::Error::NotFound => (Config::default(), None), // Exit when there's a problem with it _ => die!("{}", err), }, - Ok(config) => config, + Ok((config, path)) => (config, Some(path)), }; let font = config.font(); @@ -225,11 +225,25 @@ fn main() { tx ); + let (config_tx, config_rx) = mpsc::channel(); + + // create a config watcher when config is loaded from disk + let _config_reloader = config_path.map(|config_path| { + config::Watcher::new(config_path, ConfigHandler { + tx: config_tx, + window: window.create_window_proxy(), + }) + }); + // Main loop loop { // Wait for something to happen processor.process_events(&window); + if let Ok(config) = config_rx.try_recv() { + display.update_config(&config); + } + // Maybe draw the terminal let terminal = terminal.lock(); signal_flag.set(false); @@ -242,11 +256,31 @@ fn main() { } } + // FIXME need file watcher to work with custom delegates before + // joining config reloader is possible + // config_reloader.join().ok(); + // shutdown event_loop_handle.join().ok(); println!("Goodbye"); } +struct ConfigHandler { + tx: mpsc::Sender, + window: ::glutin::WindowProxy, +} + +impl config::OnConfigReload for ConfigHandler { + fn on_config_reload(&mut self, config: Config) { + if let Err(..) = self.tx.send(config) { + err_println!("Failed to notify of new config"); + return; + } + + self.window.wakeup_event_loop(); + } +} + struct Display { window: Arc, renderer: QuadRenderer, @@ -257,6 +291,10 @@ struct Display { } impl Display { + pub fn update_config(&mut self, config: &Config) { + self.renderer.update_config(config); + } + pub fn new(window: Arc, renderer: QuadRenderer, glyph_cache: GlyphCache, diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index eccbb8af..bbd07fe5 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -42,37 +42,9 @@ pub trait LoadGlyph { } enum Msg { - ConfigReload(Config), ShaderReload, } -/// Colors! -/// -/// FIXME this is obviously bad; need static for reload logic for now. Hacking something in with -/// minimal effort and will improve later. -/// -/// Only renderer is allowed to access this to prevent race conditions -static mut COLORS: [Rgb; 18] = [ - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, - Rgb { r: 0, g: 0, b: 0 }, -]; - /// Text drawing program /// /// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a". @@ -278,6 +250,7 @@ pub struct RenderApi<'a> { batch: &'a mut Batch, atlas: &'a mut Vec, program: &'a mut ShaderProgram, + colors: &'a [Rgb; 18], } #[derive(Debug)] @@ -500,7 +473,6 @@ impl QuadRenderer { let mut watcher = Watcher::new(tx).unwrap(); watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader"); watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader"); - watcher.watch("/home/jwilm/.alacritty.yml").expect("watch alacritty yml"); loop { let event = rx.recv().expect("watcher event"); @@ -517,15 +489,8 @@ impl QuadRenderer { println!("failed to establish watch on {:?}: {:?}", path, err); } - if path == ::std::path::Path::new("/home/jwilm/.alacritty.yml") { - if let Ok(config) = Config::load() { - msg_tx.send(Msg::ConfigReload(config)) - .expect("msg send ok"); - }; - } else { - msg_tx.send(Msg::ShaderReload) - .expect("msg send ok"); - } + msg_tx.send(Msg::ShaderReload) + .expect("msg send ok"); } } } @@ -545,27 +510,24 @@ impl QuadRenderer { rx: msg_rx, }; - unsafe { - COLORS = config.color_list(); - } - let atlas = Atlas::new(ATLAS_SIZE); renderer.atlas.push(atlas); renderer } + pub fn update_config(&mut self, config: &Config) { + self.colors = config.color_list(); + self.program.activate(); + self.program.set_color_uniforms(&self.colors); + self.program.deactivate(); + } + pub fn with_api(&mut self, props: &term::SizeInfo, func: F) -> T where F: FnOnce(RenderApi) -> T { while let Ok(msg) = self.rx.try_recv() { match msg { - Msg::ConfigReload(config) => { - self.colors = config.color_list(); - self.program.activate(); - self.program.set_color_uniforms(&self.colors); - self.program.deactivate(); - }, Msg::ShaderReload => { self.reload_shaders(props.width as u32, props.height as u32); } @@ -587,6 +549,7 @@ impl QuadRenderer { batch: &mut self.batch, atlas: &mut self.atlas, program: &mut self.program, + colors: &self.colors, }); unsafe { @@ -732,7 +695,7 @@ impl<'a> RenderApi<'a> { glyph_cache: &mut GlyphCache ) { // TODO should be built into renderer - let color = unsafe { COLORS[::ansi::Color::Background as usize] }; + let color = self.colors[::ansi::Color::Background as usize]; unsafe { gl::ClearColor( color.r as f32 / 255.0, -- cgit From cb2fa27f1501b560ffa671d8351fe18424ed320c Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 28 Oct 2016 08:11:45 -0700 Subject: Dynamically update render_timer config Everything else was already in place, just needed to set the flag. --- src/main.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 8a2159e8..b8bc5d07 100644 --- a/src/main.rs +++ b/src/main.rs @@ -293,6 +293,7 @@ struct Display { impl Display { pub fn update_config(&mut self, config: &Config) { self.renderer.update_config(config); + self.render_timer = config.render_timer(); } pub fn new(window: Arc, -- cgit From f8cb6d42cc0947e93d8913b894d7105afdfe1a2e Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Fri, 28 Oct 2016 08:36:26 -0700 Subject: Set colors on CPU Indexing colors on the vertex shader added complexity and after profiling suggests perf is basically the same. This commit will still be here in case it makes sense to try this again at some point. --- src/renderer/mod.rs | 102 +++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index bbd07fe5..29c9dff7 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -66,11 +66,6 @@ pub struct ShaderProgram { /// /// Rendering is split into two passes; 1 for backgrounds, and one for text u_background: GLint, - - /// Color uniforms - /// - /// Ansi colors are uploaded to the GPU and indexed in the vertex shader - u_colors: [GLint; 18], } @@ -219,15 +214,13 @@ struct InstanceData { uv_width: f32, uv_height: f32, // color - disc: u32, - r: u32, - g: u32, - b: u32, + r: f32, + g: f32, + b: f32, // background color - bg_disc: u32, - bg_r: u32, - bg_g: u32, - bg_b: u32, + bg_r: f32, + bg_g: f32, + bg_b: f32, } #[derive(Debug)] @@ -269,14 +262,16 @@ pub struct PackedVertex { pub struct Batch { tex: GLuint, instances: Vec, + colors: [Rgb; 18], } impl Batch { #[inline] - pub fn new() -> Batch { + pub fn new(colors: [Rgb; 18]) -> Batch { Batch { tex: 0, instances: Vec::with_capacity(BATCH_MAX), + colors: colors, } } @@ -285,8 +280,15 @@ impl Batch { self.tex = glyph.tex_id; } - let fg: &[u8; 4] = unsafe { ::std::mem::transmute(&cell.fg) }; - let bg: &[u8; 4] = unsafe { ::std::mem::transmute(&cell.bg) }; + let fg = match cell.fg { + ::term::cell::Color::Rgb(rgb) => rgb, + ::term::cell::Color::Ansi(ansi) => self.colors[ansi as usize], + }; + + let bg = match cell.bg { + ::term::cell::Color::Rgb(rgb) => rgb, + ::term::cell::Color::Ansi(ansi) => self.colors[ansi as usize], + }; let mut instance = InstanceData { col: col, @@ -302,27 +304,23 @@ impl Batch { uv_width: glyph.uv_width, uv_height: glyph.uv_height, - disc: fg[0] as u32, - r: fg[1] as u32, - g: fg[2] as u32, - b: fg[3] as u32, + r: fg.r as f32, + g: fg.g as f32, + b: fg.b as f32, - bg_disc: bg[0] as u32, - bg_r: bg[1] as u32, - bg_g: bg[2] as u32, - bg_b: bg[3] as u32, + bg_r: bg.r as f32, + bg_g: bg.g as f32, + bg_b: bg.b as f32, }; if cell.flags.contains(cell::INVERSE) { - instance.disc = bg[0] as u32; - instance.r = bg[1] as u32; - instance.g = bg[2] as u32; - instance.b = bg[3] as u32; - - instance.bg_disc = fg[0] as u32; - instance.bg_r = fg[1] as u32; - instance.bg_g = fg[2] as u32; - instance.bg_b = fg[3] as u32; + instance.r = bg.r as f32; + instance.g = bg.g as f32; + instance.b = bg.b as f32; + + instance.bg_r = fg.r as f32; + instance.bg_g = fg.g as f32; + instance.bg_b = fg.b as f32; } self.instances.push(instance); @@ -366,8 +364,7 @@ const ATLAS_SIZE: i32 = 1024; impl QuadRenderer { // TODO should probably hand this a transform instead of width/height pub fn new(config: &Config, width: u32, height: u32) -> QuadRenderer { - let colors = config.color_list(); - let program = ShaderProgram::new(&colors, width, height).unwrap(); + let program = ShaderProgram::new(width, height).unwrap(); let mut vao: GLuint = 0; let mut vbo: GLuint = 0; @@ -448,17 +445,17 @@ impl QuadRenderer { gl::EnableVertexAttribArray(3); gl::VertexAttribDivisor(3, 1); // color - gl::VertexAttribIPointer(4, 4, - gl::UNSIGNED_INT, + gl::VertexAttribPointer(4, 3, + gl::FLOAT, gl::FALSE, size_of::() as i32, (10 * size_of::()) as *const _); gl::EnableVertexAttribArray(4); gl::VertexAttribDivisor(4, 1); // color - gl::VertexAttribIPointer(5, 4, - gl::UNSIGNED_INT, + gl::VertexAttribPointer(5, 3, + gl::FLOAT, gl::FALSE, size_of::() as i32, - (14 * size_of::()) as *const _); + (13 * size_of::()) as *const _); gl::EnableVertexAttribArray(5); gl::VertexAttribDivisor(5, 1); @@ -505,7 +502,7 @@ impl QuadRenderer { vbo_instance: vbo_instance, atlas: Vec::new(), active_tex: 0, - batch: Batch::new(), + batch: Batch::new(config.color_list()), colors: config.color_list(), rx: msg_rx, }; @@ -518,9 +515,7 @@ impl QuadRenderer { pub fn update_config(&mut self, config: &Config) { self.colors = config.color_list(); - self.program.activate(); - self.program.set_color_uniforms(&self.colors); - self.program.deactivate(); + self.batch.colors = config.color_list(); } pub fn with_api(&mut self, props: &term::SizeInfo, func: F) -> T @@ -577,7 +572,7 @@ impl QuadRenderer { } pub fn reload_shaders(&mut self, width: u32, height: u32) { - let program = match ShaderProgram::new(&self.colors, width, height) { + let program = match ShaderProgram::new(width, height) { Ok(program) => program, Err(err) => { match err { @@ -797,7 +792,6 @@ impl ShaderProgram { } pub fn new( - colors: &[Rgb; 18], width: u32, height: u32 ) -> Result { @@ -850,7 +844,6 @@ impl ShaderProgram { let shader = ShaderProgram { id: program, - u_colors: color_uniforms, u_projection: projection, u_term_dim: term_dim, u_cell_dim: cell_dim, @@ -858,7 +851,6 @@ impl ShaderProgram { }; shader.update_projection(width as f32, height as f32); - shader.set_color_uniforms(colors); shader.deactivate(); @@ -879,20 +871,6 @@ impl ShaderProgram { } - fn set_color_uniforms(&self, colors: &[Rgb; 18]) { - println!("setting colors: {:#?}", colors); - for (i, rgb) in colors.iter().enumerate() { - unsafe { - gl::Uniform3f( - self.u_colors[i], - rgb.r as f32 / 255.0, - rgb.g as f32 / 255.0, - rgb.b as f32 / 255.0, - ); - } - } - } - fn set_term_uniforms(&self, props: &term::SizeInfo) { unsafe { gl::Uniform2f(self.u_term_dim, props.width, props.height); -- cgit