% jwilm@kurast.local ➜  ~/code/alacritty  [?1h=[?2004hvvivim ssrrcc//rreennderer//mmood.rs  [?1l>[?2004l [?1049h[?1h=▽ [?12;25h[?12l[?25h[?25l"src/renderer/mod.rs" 1354L, 40527C[>c 78 impl ::std::fmt::Display for Error {   79  fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {   80 match *self {   81 Error::ShaderCreation(ref err) => {   82 write!(f, "There was an error initializing the shaders: {}", err)   83 }   84 }   85  }   86 }   87    88 impl From<ShaderCreationError> for Error {   89  fn from(val: ShaderCreationError) -> Error {   90 Error::ShaderCreation(val)   91  }   92 }   93    94    95 /// Text drawing program   96 ///   97 /// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".   98 #[derive(Debug)]   99 pub struct ShaderProgram {   100  // Program id   101  id: GLuint,   102    103  /// projection matrix uniform   104  u_projection: GLint,   105    106  /// Terminal dimensions (pixels)   107  u_term_dim: GLint,   108    109  /// Cell dimensions (pixels)   110  u_cell_dim: GLint,   111    112  /// Visual bell   113  u_visual_bell: GLint,   114    115  /// Background pass flag   116  ///   117  /// Rendering is split into two passes; 1 for backgrounds, and one for text   118  u_background: GLint,   119    120  padding_x: f32,   121  padding_y: f32,   122 }   123    124    125 #[derive(Debug, Clone)]   126 pub struct Glyph {   127  tex_id: GLuint,   128  top: f32,   129  left: f32,   130  width: f32,   131  height: f32,   132  uv_bot: f32,   133  uv_left: f32, 105,0-15%[?12l[?25h[?25l 1 // Copyright 2016 Joe Wilm, The Alacritty Project Contributors   2 //   3 // Licensed under the Apache License, Version 2.0 (the "License");   4 // you may not use this file except in compliance with the License.   5 // You may obtain a copy of the License at   6 //   7 // http://www.apache.org/licenses/LICENSE-2.0   8 //   9 // Unless required by applicable law or agreed to in writing, software   10 // distributed under the License is distributed on an "AS IS" BASIS,   11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   12 // See the License for the specific language governing permissions and   13 // limitations under the License.   14 use std::collections::HashMap;   15 use std::hash::BuildHasherDefault;   16 use std::fs::File;   17 use std::io::{self, Read};   18 use std::mem::size_of;   19 use std::path::{PathBuf};   20 use std::ptr;   21 use std::sync::mpsc;   22    23 use cgmath;   24 use fnv::FnvHasher;   25 use font::{self, Rasterizer, Rasterize, RasterizedGlyph, FontDesc, GlyphKey, FontKey};   26 use gl::types::*;   27 use gl;   28 use index::{Line, Column, RangeInclusive};   29 use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op};   30    31 use config::{self, Config, Delta};   32 use term::{self, cell, RenderableCell};   33 use window::{Size, Pixels};   34    35 use Rgb;   36    37 // Shader paths for live reload   38 static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl");    39 static TEXT_SHADER_V_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl");    40    41 // Shader source which is used when live-shader-reload feature is disable   42 static TEXT_SHADER_F: &'static str = include_str!(   43  concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl")   44 );   45 static TEXT_SHADER_V: &'static str = include_str!(   46  concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl")   47 );   48    49 /// `LoadGlyph` allows for copying a rasterized glyph into graphics memory   50 pub trait LoadGlyph {   51  /// Load the rasterized glyph into GPU memory   52  fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph;   53 }   54    55 enum Msg {   56  ShaderReload, 1,1Top[?12l[?25h[?25l2[?12l[?25h[?25l3[?12l[?25h[?25l4[?12l[?25h[?25l5[?12l[?25h[?25l6[?12l[?25h[?25l7[?12l[?25h[?25l8[?12l[?25h[?25l9[?12l[?25h[?25l10,1[?12l[?25h[?25l1[?12l[?25h[?25l2[?12l[?25h[?25l3[?12l[?25h[?25l4[?12l[?25h[?25l5[?12l[?25h[?25l6[?12l[?25h[?25l7[?12l[?25h[?25l8[?12l[?25h[?25l9[?12l[?25h[?25l20[?12l[?25h[?25l1[?12l[?25h[?25l2,0-1[?12l[?25h[?25l3,1 [?12l[?25h[?25l4[?12l[?25h[?25l5[?12l[?25h[?25l6[?12l[?25h[?25l7[?12l[?25h[?25l8[?12l[?25h[?25l9[?12l[?25h[?25l30,0-1[?12l[?25h[?25l1,1 [?12l[?25h[?25l2[?12l[?25h[?25l3[?12l[?25h[?25l4,0-1[?12l[?25h[?25l5,1 [?12l[?25h[?25l6,0-1[?12l[?25h[?25l7,1 [?12l[?25h[?25l8[?12l[?25h[?25l9[?12l[?25h[?25l40,0-1[?12l[?25h[?25l1,1 [?12l[?25h[?25l2[?12l[?25h[?25l3[?12l[?25h[?25l()4[?12l[?25h[?25l()5[?12l[?25h[?25l6[?12l[?25h[?25l()7[?12l[?25h[?25l()8,0-1[?12l[?25h[?25l9,1 [?12l[?25h[?25l50[?12l[?25h[?25l1[?12l[?25h[?25l2[?12l[?25h[?25l{}3[?12l[?25h[?25l{}4,0-1[?12l[?25h[?25l5,1 [?12l[?25h[?25l6[?12l[?25h[?25l {  57 } 57,10%[?12l[?25h[?25l {}  58  58,0-10%[?12l[?25h[?25l  59 #[derive(Debug)] 59,10%[?12l[?25h[?25l  60 pub enum Error { 60,10%[?12l[?25h[?25l  61  ShaderCreation(ShaderCreationError), 61,10%[?12l[?25h[?25l {  62 } 62,10%[?12l[?25h[?25l {}  63  63,0-10%[?12l[?25h[?25l  64 impl ::std::error::Error for Error { 64,10%[?12l[?25h[?25l  65  fn cause(&self) -> Option<&::std::error::Error> { 65,10%[?12l[?25h[?25l  66 match *self { 66,10%[?12l[?25h[?25l  67 Error::ShaderCreation(ref err) => Some(err), 67,10%[?12l[?25h[?25l  68 } 68,10%[?12l[?25h[?25l  69  } 69,11%[?12l[?25h[?25l  70  70,0-11%[?12l[?25h[?25l  71  fn description(&self) -> &str { 71,11%[?12l[?25h[?25l  72 match *self { 72,11%[?12l[?25h[?25l  73 Error::ShaderCreation(ref err) => err.description(), 73,11%[?12l[?25h[?25l  74 } 74,11%[?12l[?25h[?25l  75  } 75,11%[?12l[?25h[?25l { 76 } 76,11%[?12l[?25h[?25l {}  77  77,0-11%[?12l[?25h[?25l  78 impl ::std::fmt::Display for Error { 78,11%[?12l[?25h[?25l  79  fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 79,11%[?12l[?25h[?25l  80 match *self { 80,11%[?12l[?25h[?25l  81 Error::ShaderCreation(ref err) => { 81,11%[?12l[?25h[?25l  82 write!(f, "There was an error initializing the shaders: {}", err) 82,12%[?12l[?25h[?25l  83 } 83,12%[?12l[?25h[?25l  84 } 84,12%[?12l[?25h[?25l  85  } 85,12%[?12l[?25h[?25l { 86 } 86,12%[?12l[?25h[?25l {}  87  87,0-12%[?12l[?25h[?25l  88 impl From<ShaderCreationError> for Error { 88,12%[?12l[?25h[?25l  89  fn from(val: ShaderCreationError) -> Error { 89,12%[?12l[?25h[?25l  90 Error::ShaderCreation(val) 90,12%[?12l[?25h[?25l  91  } 91,12%[?12l[?25h[?25l { 92 } 92,12%[?12l[?25h[?25l {}  93  93,0-12%[?12l[?25h[?25l  94  94,0-12%[?12l[?25h[?25l  95 /// Text drawing program 95,13%[?12l[?25h[?25l  96 /// 96,13%[?12l[?25h[?25l  97 /// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a". 97,13%[?12l[?25h[?25l  98 #[derive(Debug)] 98,13%[?12l[?25h[?25l  99 pub struct ShaderProgram { 99,13%[?12l[?25h[?25l  100  // Program id 100,13%[?12l[?25h[?25l  101  id: GLuint, 101,13%[?12l[?25h[?25l  102  102,0-13%[?12l[?25h[?25l  103  /// projection matrix uniform 103,13%[?12l[?25h[?25l  104  u_projection: GLint, 104,13%[?12l[?25h[?25l  105  105,0-13%[?12l[?25h[?25l  106  /// Terminal dimensions (pixels) 106,13%[?12l[?25h[?25l  107  u_term_dim: GLint, 107,13%[?12l[?25h[?25l  108  108,0-14%[?12l[?25h[?25l  109  /// Cell dimensions (pixels) 109,14%[?12l[?25h[?25l  110  u_cell_dim: GLint, 110,14%[?12l[?25h[?25l  111  111,0-14%[?12l[?25h[?25l  112  /// Visual bell 112,14%[?12l[?25h[?25l  113  u_visual_bell: GLint, 113,14%[?12l[?25h[?25l  114  114,0-14%[?12l[?25h[?25l  115  /// Background pass flag 115,14%[?12l[?25h[?25l  116  /// 116,14%[?12l[?25h[?25l  117  /// Rendering is split into two passes; 1 for backgrounds, and one for text 117,14%[?12l[?25h[?25l  118  u_background: GLint, 118,14%[?12l[?25h[?25l  119  119,0-14%[?12l[?25h[?25l  120  padding_x: f32, 120,14%[?12l[?25h[?25l  121  padding_y: f32, 121,15%[?12l[?25h[?25l { 122 } 122,15%[?12l[?25h[?25l {}  123  123,0-15%[?12l[?25h[?25l  124  124,0-15%[?12l[?25h[?25l  125 #[derive(Debug, Clone)] 125,15%[?12l[?25h[?25l  126 pub struct Glyph { 126,15%[?12l[?25h[?25l  127  tex_id: GLuint, 127,15%[?12l[?25h[?25l  128  top: f32, 128,15%[?12l[?25h[?25l  129  left: f32, 129,15%[?12l[?25h[?25l  130  width: f32, 130,15%[?12l[?25h[?25l  131  height: f32, 131,15%[?12l[?25h[?25l  132  uv_bot: f32, 132,15%[?12l[?25h[?25l  133  uv_left: f32, 133,15%[?12l[?25h[?25l  134  uv_width: f32, 134,16%[?12l[?25h[?25l  135  uv_height: f32, 135,16%[?12l[?25h[?25l { 136 } 136,16%[?12l[?25h[?25l {}  137  137,0-16%[?12l[?25h[?25l  138 /// Naïve glyph cache 138,16%[?12l[?25h[?25l  139 /// 139,16%[?12l[?25h[?25l  140 /// Currently only keyed by `char`, and thus not possible to hold different 140,16%[?12l[?25h[?25l  141 /// representations of the same code point. 141,16%[?12l[?25h[?25l  142 pub struct GlyphCache { 142,16%[?12l[?25h[?25l  143  /// Cache of buffered glyphs 143,16%[?12l[?25h[?25l  144  cache: HashMap<GlyphKey, Glyph, BuildHasherDefault<FnvHasher>>, 144,16%[?12l[?25h[?25l  145  145,0-16%[?12l[?25h[?25l  146  /// Rasterizer for loading new glyphs 146,16%[?12l[?25h[?25l  147  rasterizer: Rasterizer, 147,17%[?12l[?25h[?25l  148  148,0-17%[?12l[?25h[?25l  149  /// regular font 149,17%[?12l[?25h[?25l  150  font_key: FontKey, 150,17%[?12l[?25h[?25l  151  151,0-17%[?12l[?25h[?25l  152  /// italic font 152,17%[?12l[?25h[?25l  153  italic_key: FontKey, 153,17%[?12l[?25h[?25l  154  154,0-17%[?12l[?25h[?25l  155  /// bold font 155,17%[?12l[?25h[?25l  156  bold_key: FontKey, 156,17%[?12l[?25h[?25l  157  157,0-17%[?12l[?25h[?25l  158  /// font size 158,17%[?12l[?25h[?25l  159  font_size: font::Size, 159,17%[?12l[?25h[?25l  160  160,0-18%[?12l[?25h[?25l  161  /// glyph offset 161,18%[?12l[?25h[?25l  162  glyph_offset: Delta, 162,18%[?12l[?25h[?25l  163  163,0-18%[?12l[?25h[?25l  164  metrics: ::font::Metrics, 164,18%[?12l[?25h[?25l { 165 } 165,18%[?12l[?25h[?25l {}  166  166,0-18%[?12l[?25h[?25l  167 impl GlyphCache { 167,18%[?12l[?25h[?25l  168  pub fn new<L>( 168,18%[?12l[?25h[?25l  169 mut rasterizer: Rasterizer, 169,18%[?12l[?25h[?25l  170 config: &Config, 170,18%[?12l[?25h[?25l  171 loader: &mut L 171,18%[?12l[?25h[?25l  172  ) -> Result<GlyphCache, font::Error> 172,18%[?12l[?25h[?25l  173 where L: LoadGlyph 173,19%[?12l[?25h[?25l  174  { 174,19%[?12l[?25h[?25l  175 let font = config.font(); 175,19%[?12l[?25h[?25l  176 let size = font.size(); 176,19%[?12l[?25h[?25l  177 let glyph_offset = *font.glyph_offset(); 177,19%[?12l[?25h[?25l  178  178,0-19%[?12l[?25h[?25l  179 fn make_desc( 179,19%[?12l[?25h[?25l  180 desc: &config::FontDescription, 180,19%[?12l[?25h[?25l  181 slant: font::Slant, 181,19%[?12l[?25h[?25l  182 weight: font::Weight, 182,19%[?12l[?25h[?25l  183 ) -> FontDesc 183,19%[?12l[?25h[?25l  184 { 184,19%[?12l[?25h[?25l  185 let style = if let Some(ref spec) = desc.style { 185,19%[?12l[?25h[?25l  186 font::Style::Specific(spec.to_owned()) 186,110%[?12l[?25h[?25l  187 } else { 187,110%[?12l[?25h[?25l  188 font::Style::Description {slant:slant, weight:weight} 188,110%[?12l[?25h[?25l  189 }; 189,110%[?12l[?25h[?25l  190 FontDesc::new(&desc.family[..], style) 190,110%[?12l[?25h[?25l  191 } 191,110%[?12l[?25h[?25l  192  192,0-110%[?12l[?25h[?25l  193 // Load regular font 193,110%[?12l[?25h[?25l  194 let regular_desc = make_desc(&font.normal, font::Slant::Normal, font::Weight::Normal);  194,110%[?12l[?25h[?25l  195  195,0-110%[?12l[?25h[?25l  196 let regular = rasterizer 196,110%[?12l[?25h[?25l  197 .load_font(&regular_desc, size)?; 197,110%[?12l[?25h[?25l  198  198,0-110%[?12l[?25h[?25l  199 // helper to load a description if it is not the regular_desc 199,111%[?12l[?25h[?25l  200 let load_or_regular = |desc:FontDesc, rasterizer: &mut Rasterizer| { 200,111%[?12l[?25h[?25l  201 if desc == regular_desc { 201,111%[?12l[?25h[?25l  202 regular 202,111%[?12l[?25h[?25l  203 } else { 203,111%[?12l[?25h[?25l  204 rasterizer.load_font(&desc, size).unwrap_or_else(|_| regular) 204,111%[?12l[?25h[?25l  205 } 205,111%[?12l[?25h[?25l  206 }; 206,111%[?12l[?25h[?25l  207  207,0-111%[?12l[?25h[?25l  208 // Load bold font 208,111%[?12l[?25h[?25l  209 let bold_desc = make_desc(&font.bold, font::Slant::Normal, font::Weight::Bold); 209,111%[?12l[?25h[?25l  210  210,0-111%[?12l[?25h[?25l  211 let bold = load_or_regular(bold_desc, &mut rasterizer); 211,111%[?12l[?25h[?25l  212  212,0-112%[?12l[?25h[?25l  213 // Load italic font 213,112%[?12l[?25h[?25l  214 let italic_desc = make_desc(&font.italic, font::Slant::Italic, font::Weight::Normal); 214,112%[?12l[?25h[?25l  215  215,0-112%[?12l[?25h[?25l  216 let italic = load_or_regular(italic_desc, &mut rasterizer); 216,112%[?12l[?25h[?25l  217  217,0-112%[?12l[?25h[?25l  218 // Need to load at least one glyph for the face before calling metrics. 218,112%[?12l[?25h[?25l  219 // The glyph requested here ('m' at the time of writing) has no special 219,112%[?12l[?25h[?25l  220 // meaning. 220,112%[?12l[?25h[?25l  221 rasterizer.get_glyph(&GlyphKey { font_key: regular, c: 'm', size: font.size() })?; 221,112%[?12l[?25h[?25l  222 let metrics = rasterizer.metrics(regular)?; 222,112%[?12l[?25h[?25l  223  223,0-112%[?12l[?25h[?25l  224 let mut cache = GlyphCache { 224,112%[?12l[?25h[?25l  225 cache: HashMap::default(), 225,113%[?12l[?25h[?25l  226 rasterizer: rasterizer, 226,113%[?12l[?25h[?25l  227 font_size: font.size(), 227,113%[?12l[?25h[?25l  228 font_key: regular, 228,113%[?12l[?25h[?25l  229 bold_key: bold, 229,113%[?12l[?25h[?25l  230 italic_key: italic, 230,113%[?12l[?25h[?25l  231 glyph_offset: glyph_offset, 231,113%[?12l[?25h[?25l  232 metrics: metrics 232,113%[?12l[?25h[?25l  233 }; 233,113%[?12l[?25h[?25l  234  234,0-113%[?12l[?25h[?25l  235 macro_rules! load_glyphs_for_font { 235,113%[?12l[?25h[?25l  236 ($font:expr) => { 236,113%[?12l[?25h[?25l  237 for i in RangeInclusive::new(32u8, 128u8) { 237,113%[?12l[?25h[?25l  238 cache.get(&GlyphKey { 238,114%[?12l[?25h[?25l  239 font_key: $font, 239,114%[?12l[?25h[?25l  240 c: i as char, 240,114%[?12l[?25h[?25l  241 size: font.size() 241,114%[?12l[?25h[?25l  242 }, loader); 242,114%[?12l[?25h[?25l  243 } 243,114%[?12l[?25h[?25l  244 } 244,114%[?12l[?25h[?25l  245 } 245,114%[?12l[?25h[?25l  246  246,0-114%[?12l[?25h[?25l  247 load_glyphs_for_font!(regular); 247,114%[?12l[?25h[?25l  248 load_glyphs_for_font!(bold); 248,114%[?12l[?25h[?25l  249 load_glyphs_for_font!(italic); 249,114%[?12l[?25h[?25l  250  250,0-114%[?12l[?25h[?25l  251 Ok(cache) 251,115%[?12l[?25h[?25l  252  } 252,115%[?12l[?25h[?25l  253  253,0-115%[?12l[?25h[?25l  254  pub fn font_metrics(&self) -> font::Metrics { 254,115%[?12l[?25h[?25l  255 self.rasterizer 255,115%[?12l[?25h[?25l  256 .metrics(self.font_key) 256,115%[?12l[?25h[?25l  257 .expect("metrics load since font is loaded at glyph cache creation") 257,115%[?12l[?25h[?25l  258  } 258,115%[?12l[?25h[?25l  259  259,0-115%[?12l[?25h[?25l  260  pub fn get<'a, L>(&'a mut self, glyph_key: &GlyphKey, loader: &mut L) -> &'a Glyph 260,115%[?12l[?25h[?25l  261 where L: LoadGlyph 261,115%[?12l[?25h[?25l  262  { 262,115%[?12l[?25h[?25l  263 let glyph_offset = self.glyph_offset; 263,115%[?12l[?25h[?25l  264 let rasterizer = &mut self.rasterizer; 264,116%[?12l[?25h[?25l  265 let metrics = &self.metrics; 265,116%[?12l[?25h[?25l  266 self.cache 266,116%[?12l[?25h[?25l  267 .entry(*glyph_key) 267,116%[?12l[?25h[?25l  268 .or_insert_with(|| { 268,116%[?12l[?25h[?25l  269 let mut rasterized = rasterizer.get_glyph(&glyph_key) 269,116%[?12l[?25h[?25l  270 .unwrap_or_else(|_| Default::default()); 270,116%[?12l[?25h[?25l  271  271,0-116%[?12l[?25h[?25l  272 rasterized.left += glyph_offset.x as i32; 272,116%[?12l[?25h[?25l  273 rasterized.top += glyph_offset.y as i32; 273,116%[?12l[?25h[?25l  274 rasterized.top -= metrics.descent as i32; 274,116%[?12l[?25h[?25l  275  275,0-116%[?12l[?25h[?25l  276 loader.load_glyph(&rasterized) 276,116%[?12l[?25h[?25l  277 }) 277,117%[?12l[?25h[?25l  278  } 278,117%[?12l[?25h[?25l  279 } 279,117%[?12l[?25h[?25l  280  280,0-117%[?12l[?25h[?25l  281 #[derive(Debug)] 281,117%[?12l[?25h[?25l  282 #[repr(C)] 282,117%[?12l[?25h[?25l  283 struct InstanceData { 283,117%[?12l[?25h[?25l  284  // coords 284,117%[?12l[?25h[?25l  285  col: f32, 285,117%[?12l[?25h[?25l  286  row: f32, 286,117%[?12l[?25h[?25l  287  // glyph offset 287,117%[?12l[?25h[?25l  288  left: f32, 288,117%[?12l[?25h[?25l  289  top: f32, 289,117%[?12l[?25h[?25l  290  // glyph scale 290,118%[?12l[?25h[?25l  291  width: f32, 291,118%[?12l[?25h[?25l  292  height: f32, 292,118%[?12l[?25h[?25l  293  // uv offset 293,118%[?12l[?25h[?25l  294  uv_left: f32, 294,118%[?12l[?25h[?25l  295  uv_bot: f32, 295,118%[?12l[?25h[?25l  296  // uv scale 296,118%[?12l[?25h[?25l  297  uv_width: f32, 297,118%[?12l[?25h[?25l  298  uv_height: f32, 298,118%[?12l[?25h[?25l  299  // color 299,118%[?12l[?25h[?25l  300  r: f32, 300,118%[?12l[?25h[?25l  301  g: f32, 301,118%[?12l[?25h[?25l  302  b: f32, 302,118%[?12l[?25h[?25l  303  // background color 303,119%[?12l[?25h[?25l  304  bg_r: f32, 304,119%[?12l[?25h[?25l  305  bg_g: f32, 305,119%[?12l[?25h[?25l  306  bg_b: f32, 306,119%[?12l[?25h[?25l { 307 } 307,119%[?12l[?25h[?25l {}  308  308,0-119%[?12l[?25h[?25l  309 #[derive(Debug)] 309,119%[?12l[?25h[?25l  310 pub struct QuadRenderer { 310,119%[?12l[?25h[?25l  311  program: ShaderProgram, 311,119%[?12l[?25h[?25l  312  vao: GLuint, 312,119%[?12l[?25h[?25l  313  vbo: GLuint, 313,119%[?12l[?25h[?25l  314  ebo: GLuint, 314,119%[?12l[?25h[?25l  315  vbo_instance: GLuint, 315,119%[?12l[?25h[?25l  316  atlas: Vec<Atlas>, 316,120%[?12l[?25h[?25l  317  active_tex: GLuint, 317,120%[?12l[?25h[?25l  318  batch: Batch, 318,120%[?12l[?25h[?25l  319  rx: mpsc::Receiver<Msg>, 319,120%[?12l[?25h[?25l { 320 } 320,120%[?12l[?25h[?25l {}  321  321,0-120%[?12l[?25h[?25l  322 #[derive(Debug)] 322,120%[?12l[?25h[?25l  323 pub struct RenderApi<'a> { 323,120%[?12l[?25h[?25l  324  active_tex: &'a mut GLuint, 324,120%[?12l[?25h[?25l  325  batch: &'a mut Batch, 325,120%[?12l[?25h[?25l  326  atlas: &'a mut Vec<Atlas>, 326,120%[?12l[?25h[?25l  327  program: &'a mut ShaderProgram, 327,120%[?12l[?25h[?25l  328  config: &'a Config, 328,120%[?12l[?25h[?25l  329  visual_bell_intensity: f32 329,121%[?12l[?25h[?25l { 330 } 330,121%[?12l[?25h[?25l {}  331  331,0-121%[?12l[?25h[?25l  332 #[derive(Debug)] 332,121%[?12l[?25h[?25l  333 pub struct LoaderApi<'a> { 333,121%[?12l[?25h[?25l  334  active_tex: &'a mut GLuint, 334,121%[?12l[?25h[?25l  335  atlas: &'a mut Vec<Atlas>, 335,121%[?12l[?25h[?25l {  336 } 336,121%[?12l[?25h[?25l {}  337  337,0-121%[?12l[?25h[?25l  338 #[derive(Debug)] 338,121%[?12l[?25h[?25l  339 pub struct PackedVertex { 339,121%[?12l[?25h[?25l  340  x: f32, 340,121%[?12l[?25h[?25l  341  y: f32, 341,121%[?12l[?25h[?25l {  342 } 342,122%[?12l[?25h[?25l {}  343  343,0-122%[?12l[?25h[?25l  344 #[derive(Debug)] 344,122%[?12l[?25h[?25l  345 pub struct Batch { 345,122%[?12l[?25h[?25l  346  tex: GLuint, 346,122%[?12l[?25h[?25l  347  instances: Vec<InstanceData>, 347,122%[?12l[?25h[?25l {  348 } 348,122%[?12l[?25h[?25l {}  349  349,0-122%[?12l[?25h[?25l  350 impl Batch { 350,122%[?12l[?25h[?25l  351  #[inline] 351,122%[?12l[?25h[?25l  352  pub fn new() -> Batch { 352,122%[?12l[?25h[?25l  353 Batch { 353,122%[?12l[?25h[?25l  354 tex: 0, 354,122%[?12l[?25h[?25l  355 instances: Vec::with_capacity(BATCH_MAX), 355,123%[?12l[?25h[?25l  356 } 356,123%[?12l[?25h[?25l  357  } 357,123%[?12l[?25h[?25l  358  358,0-123%[?12l[?25h[?25l  359  pub fn add_item( 359,123%[?12l[?25h[?25l  360 &mut self, 360,123%[?12l[?25h[?25l  361 cell: &RenderableCell, 361,123%[?12l[?25h[?25l  362 glyph: &Glyph, 362,123%[?12l[?25h[?25l  363  ) { 363,123%[?12l[?25h[?25l  364 if self.is_empty() { 364,123%[?12l[?25h[?25l  365 self.tex = glyph.tex_id; 365,123%[?12l[?25h[?25l  366 } 366,123%[?12l[?25h[?25l  367  367,0-123%[?12l[?25h[?25l  368 self.instances.push(InstanceData { 368,124%[?12l[?25h[?25l  369 col: cell.column.0 as f32, 369,124%[?12l[?25h[?25l  370 row: cell.line.0 as f32, 370,124%[?12l[?25h[?25l  371  371,0-124%[?12l[?25h[?25l  372 top: glyph.top, 372,124%[?12l[?25h[?25l  373 left: glyph.left, 373,124%[?12l[?25h[?25l  374 width: glyph.width, 374,124%[?12l[?25h[?25l  375 height: glyph.height, 375,124%[?12l[?25h[?25l  376  376,0-124%[?12l[?25h[?25l  377 uv_bot: glyph.uv_bot, 377,124%[?12l[?25h[?25l  378 uv_left: glyph.uv_left, 378,124%[?12l[?25h[?25l  379 uv_width: glyph.uv_width, 379,124%[?12l[?25h[?25l  380 uv_height: glyph.uv_height, 380,124%[?12l[?25h[?25l  381  381,0-125%[?12l[?25h[?25l  382 r: cell.fg.r as f32, 382,125%[?12l[?25h[?25l  383 g: cell.fg.g as f32, 383,125%[?12l[?25h[?25l  384 b: cell.fg.b as f32, 384,125%[?12l[?25h[?25l  385  385,0-125%[?12l[?25h[?25l  386 bg_r: cell.bg.r as f32, 386,125%[?12l[?25h[?25l  387 bg_g: cell.bg.g as f32, 387,125%[?12l[?25h[?25l  388 bg_b: cell.bg.b as f32, 388,125%[?12l[?25h[?25l  389 }); 389,125%[?12l[?25h[?25l  390  } 390,125%[?12l[?25h[?25l  391  391,0-125%[?12l[?25h[?25l  392  #[inline] 392,125%[?12l[?25h[?25l  393  pub fn full(&self) -> bool { 393,125%[?12l[?25h[?25l  394 self.capacity() == self.len() 394,126%[?12l[?25h[?25l  395  } 395,126%[?12l[?25h[?25l  396  396,0-126%[?12l[?25h[?25l  397  #[inline] 397,126%[?12l[?25h[?25l  398  pub fn len(&self) -> usize { 398,126%[?12l[?25h[?25l  399 self.instances.len() 399,126%[?12l[?25h[?25l  400  } 400,126%[?12l[?25h[?25l  401  401,0-126%[?12l[?25h[?25l  402  #[inline] 402,126%[?12l[?25h[?25l  403  pub fn capacity(&self) -> usize { 403,126%[?12l[?25h[?25l  404 BATCH_MAX 404,126%[?12l[?25h[?25l  405  } 405,126%[?12l[?25h[?25l  406  406,0-126%[?12l[?25h[?25l  407  #[inline] 407,127%[?12l[?25h[?25l  408  pub fn is_empty(&self) -> bool { 408,127%[?12l[?25h[?25l  409 self.len() == 0 409,127%[?12l[?25h[?25l  410  } 410,127%[?12l[?25h[?25l  411  411,0-127%[?12l[?25h[?25l  412  #[inline] 412,127%[?12l[?25h[?25l  413  pub fn size(&self) -> usize { 413,127%[?12l[?25h[?25l  414 self.len() * size_of::<InstanceData>() 414,127%[?12l[?25h[?25l  415  } 415,127%[?12l[?25h[?25l  416  416,0-127%[?12l[?25h[?25l  417  pub fn clear(&mut self) { 417,127%[?12l[?25h[?25l  418 self.tex = 0; 418,127%[?12l[?25h[?25l  419 self.instances.clear(); 419,127%[?12l[?25h[?25l  420  } 420,128%[?12l[?25h[?25l  421 } 421,128%[?12l[?25h[?25l  422  422,0-128%[?12l[?25h[?25l  423 /// Maximum items to be drawn in a batch. 423,128%[?12l[?25h[?25l  424 const BATCH_MAX: usize = 65_536; 424,128%[?12l[?25h[?25l  425 const ATLAS_SIZE: i32 = 1024; 425,128%[?12l[?25h[?25l  426  426,0-128%[?12l[?25h[?25l  427 impl QuadRenderer { 427,128%[?12l[?25h[?25l  428  // TODO should probably hand this a transform instead of width/height 428,128%[?12l[?25h[?25l  429  pub fn new(config: &Config, size: Size<Pixels<u32>>) -> Result<QuadRenderer, Error> { 429,128%[?12l[?25h[?25l  430 let program = ShaderProgram::new(config, size)?; 430,128%[?12l[?25h[?25l  431  431,0-128%[?12l[?25h[?25l  432 let mut vao: GLuint = 0; 432,128%[?12l[?25h[?25l  433 let mut vbo: GLuint = 0; 433,129%[?12l[?25h[?25l  434 let mut ebo: GLuint = 0; 434,129%[?12l[?25h[?25l  435  435,0-129%[?12l[?25h[?25l  436 let mut vbo_instance: GLuint = 0; 436,129%[?12l[?25h[?25l  437  437,0-129%[?12l[?25h[?25l  438 unsafe { 438,129%[?12l[?25h[?25l  439 gl::Enable(gl::BLEND); 439,129%[?12l[?25h[?25l  440 gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR); 440,129%[?12l[?25h[?25l  441 gl::Enable(gl::MULTISAMPLE); 441,129%[?12l[?25h[?25l  442  442,0-129%[?12l[?25h[?25l  443 gl::GenVertexArrays(1, &mut vao); 443,129%[?12l[?25h[?25l  444 gl::GenBuffers(1, &mut vbo); 444,129%[?12l[?25h[?25l  445 gl::GenBuffers(1, &mut ebo); 445,129%[?12l[?25h[?25l  446 gl::GenBuffers(1, &mut vbo_instance); 446,130%[?12l[?25h[?25l  447 gl::BindVertexArray(vao); 447,130%[?12l[?25h[?25l  448  448,0-130%[?12l[?25h[?25l  449 // ---------------------------- 449,130%[?12l[?25h[?25l  450 // setup vertex position buffer 450,130%[?12l[?25h[?25l  451 // ---------------------------- 451,130%[?12l[?25h[?25l  452 // Top right, Bottom right, Bottom left, Top left 452,130%[?12l[?25h[?25l  453 let vertices = [ 453,130%[?12l[?25h[?25l  454 PackedVertex { x: 1.0, y: 1.0 }, 454,130%[?12l[?25h[?25l  455 PackedVertex { x: 1.0, y: 0.0 }, 455,130%[?12l[?25h[?25l  456 PackedVertex { x: 0.0, y: 0.0 }, 456,130%[?12l[?25h[?25l  457 PackedVertex { x: 0.0, y: 1.0 }, 457,130%[?12l[?25h[?25l  458 ]; 458,130%[?12l[?25h[?25l  459  459,0-131%[?12l[?25h[?25l  460 gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 460,131%[?12l[?25h[?25l  461  461,0-131%[?12l[?25h[?25l  462 gl::VertexAttribPointer(0, 2, 462,131%[?12l[?25h[?25l  463 gl::FLOAT, gl::FALSE, 463,131%[?12l[?25h[?25l  464 size_of::<PackedVertex>() as i32, 464,131%[?12l[?25h[?25l  465 ptr::null()); 465,131%[?12l[?25h[?25l  466 gl::EnableVertexAttribArray(0); 466,131%[?12l[?25h[?25l  467  467,0-131%[?12l[?25h[?25l  468 gl::BufferData(gl::ARRAY_BUFFER, 468,131%[?12l[?25h[?25l  469 (size_of::<PackedVertex>() * vertices.len()) as GLsizeiptr, 469,131%[?12l[?25h[?25l  470 vertices.as_ptr() as *const _, 470,131%[?12l[?25h[?25l  471 gl::STATIC_DRAW); 471,131%[?12l[?25h[?25l  472  472,0-132%[?12l[?25h[?25l  473 // --------------------- 473,132%[?12l[?25h[?25l  474 // Set up element buffer 474,132%[?12l[?25h[?25l  475 // --------------------- 475,132%[?12l[?25h[?25l  476 let indices: [u32; 6] = [0, 1, 3, 476,132%[?12l[?25h[?25l  477 1, 2, 3]; 477,132%[?12l[?25h[?25l  478  478,0-132%[?12l[?25h[?25l  479 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo); 479,132%[?12l[?25h[?25l  480 gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, 480,132%[?12l[?25h[?25l  481 (6 * size_of::<u32>()) as isize, 481,132%[?12l[?25h[?25l  482 indices.as_ptr() as *const _, 482,132%[?12l[?25h[?25l  483 gl::STATIC_DRAW); 483,132%[?12l[?25h[?25l  484  484,0-132%[?12l[?25h[?25l  485 // ---------------------------- 485,133%[?12l[?25h[?25l  486 // Setup vertex instance buffer 486,133%[?12l[?25h[?25l  487 // ---------------------------- 487,133%[?12l[?25h[?25l  488 gl::BindBuffer(gl::ARRAY_BUFFER, vbo_instance); 488,133%[?12l[?25h[?25l  489 gl::BufferData(gl::ARRAY_BUFFER, 489,133%[?12l[?25h[?25l  490 (BATCH_MAX * size_of::<InstanceData>()) as isize, 490,133%[?12l[?25h[?25l  491 ptr::null(), gl::STREAM_DRAW); 491,133%[?12l[?25h[?25l  492 // coords 492,133%[?12l[?25h[?25l  493 gl::VertexAttribPointer(1, 2, 493,133%[?12l[?25h[?25l  494 gl::FLOAT, gl::FALSE, 494,133%[?12l[?25h[?25l  495 size_of::<InstanceData>() as i32, 495,133%[?12l[?25h[?25l  496 ptr::null()); 496,133%[?12l[?25h[?25l  497 gl::EnableVertexAttribArray(1); 497,133%[?12l[?25h[?25l  498 gl::VertexAttribDivisor(1, 1); 498,134%[?12l[?25h[?25l  499 // glyphoffset 499,134%[?12l[?25h[?25l  500 gl::VertexAttribPointer(2, 4, 500,134%[?12l[?25h[?25l  501 gl::FLOAT, gl::FALSE, 501,134%[?12l[?25h[?25l  502 size_of::<InstanceData>() as i32, 502,134%[?12l[?25h[?25l  503 (2 * size_of::<f32>()) as *const _); 503,134%[?12l[?25h[?25l  504 gl::EnableVertexAttribArray(2); 504,134%[?12l[?25h[?25l  505 gl::VertexAttribDivisor(2, 1); 505,134%[?12l[?25h[?25l  506 // uv 506,134%[?12l[?25h[?25l  507 gl::VertexAttribPointer(3, 4, 507,134%[?12l[?25h[?25l  508 gl::FLOAT, gl::FALSE, 508,134%[?12l[?25h[?25l  509 size_of::<InstanceData>() as i32, 509,134%[?12l[?25h[?25l  510 (6 * size_of::<f32>()) as *const _); 510,134%[?12l[?25h[?25l  511 gl::EnableVertexAttribArray(3); 511,135%[?12l[?25h[?25l  512 gl::VertexAttribDivisor(3, 1); 512,135%[?12l[?25h[?25l  513 // color 513,135%[?12l[?25h[?25l  514 gl::VertexAttribPointer(4, 3, 514,135%[?12l[?25h[?25l  515 gl::FLOAT, gl::FALSE, 515,135%[?12l[?25h[?25l  516 size_of::<InstanceData>() as i32, 516,135%[?12l[?25h[?25l  517 (10 * size_of::<f32>()) as *const _); 517,135%[?12l[?25h[?25l  518 gl::EnableVertexAttribArray(4); 518,135%[?12l[?25h[?25l  519 gl::VertexAttribDivisor(4, 1); 519,135%[?12l[?25h[?25l  520 // color 520,135%[?12l[?25h[?25l  521 gl::VertexAttribPointer(5, 3, 521,135%[?12l[?25h[?25l  522 gl::FLOAT, gl::FALSE, 522,135%[?12l[?25h[?25l  523 size_of::<InstanceData>() as i32, 523,135%[?12l[?25h[?25l  524 (13 * size_of::<f32>()) as *const _); 524,136%[?12l[?25h[?25l  525 gl::EnableVertexAttribArray(5); 525,136%[?12l[?25h[?25l  526 gl::VertexAttribDivisor(5, 1); 526,136%[?12l[?25h[?25l  527  527,0-136%[?12l[?25h[?25l  528 gl::BindVertexArray(0); 528,136%[?12l[?25h[?25l  529 gl::BindBuffer(gl::ARRAY_BUFFER, 0); 529,136%[?12l[?25h[?25l  530 } 530,136%[?12l[?25h[?25l  531  531,0-136%[?12l[?25h[?25l  532 let (msg_tx, msg_rx) = mpsc::channel(); 532,136%[?12l[?25h[?25l  533  533,0-136%[?12l[?25h[?25l  534 if cfg!(feature = "live-shader-reload") { 534,136%[?12l[?25h[?25l  535 ::std::thread::spawn(move || { 535,136%[?12l[?25h[?25l  536 let (tx, rx) = ::std::sync::mpsc::channel(); 536,136%[?12l[?25h[?25l  537 let mut watcher = Watcher::new(tx).expect("create file watcher"); 537,137%[?12l[?25h[?25l  538 watcher.watch(TEXT_SHADER_F_PATH).expect("watch fragment shader"); 538,137%[?12l[?25h[?25l  539 watcher.watch(TEXT_SHADER_V_PATH).expect("watch vertex shader"); 539,137%[?12l[?25h[?25l  540  540,0-137%[?12l[?25h[?25l  541 loop { 541,137%[?12l[?25h[?25l  542 let event = rx.recv().expect("watcher event"); 542,137%[?12l[?25h[?25l  543 let ::notify::Event { path, op } = event; 543,137%[?12l[?25h[?25l  544  544,0-137%[?12l[?25h[?25l  545 if let Ok(op) = op { 545,137%[?12l[?25h[?25l  546 if op.contains(op::RENAME) { 546,137%[?12l[?25h[?25l  547 continue; 547,137%[?12l[?25h[?25l  548 } 548,137%[?12l[?25h[?25l  549  549,0-137%[?12l[?25h[?25l  550 if op.contains(op::IGNORED) { 550,138%[?12l[?25h[?25l  551 if let Some(path) = path.as_ref() { 551,138%[?12l[?25h[?25l  552 if let Err(err) = watcher.watch(path) { 552,138%[?12l[?25h[?25l  553 warn!("failed to establish watch on {:?}: {:?}", path, err);  553,138%[?12l[?25h[?25l  554 } 554,138%[?12l[?25h[?25l  555 } 555,138%[?12l[?25h[?25l  556  556,0-138%[?12l[?25h[?25l  557 msg_tx.send(Msg::ShaderReload) 557,138%[?12l[?25h[?25l  558 .expect("msg send ok"); 558,138%[?12l[?25h[?25l  559 } 559,138%[?12l[?25h[?25l  560 } 560,138%[?12l[?25h[?25l  561 } 561,138%[?12l[?25h[?25l  562 }); 562,138%[?12l[?25h[?25l  563 } 563,139%[?12l[?25h[?25l  564  564,0-139%[?12l[?25h[?25l  565 let mut renderer = QuadRenderer { 565,139%[?12l[?25h[?25l  566 program: program, 566,139%[?12l[?25h[?25l  567 vao: vao, 567,139%[?12l[?25h[?25l  568 vbo: vbo, 568,139%[?12l[?25h[?25l  569 ebo: ebo, 569,139%[?12l[?25h[?25l  570 vbo_instance: vbo_instance, 570,139%[?12l[?25h[?25l  571 atlas: Vec::new(), 571,139%[?12l[?25h[?25l  572 active_tex: 0, 572,139%[?12l[?25h[?25l  573 batch: Batch::new(), 573,139%[?12l[?25h[?25l  574 rx: msg_rx, 574,139%[?12l[?25h[?25l  575 }; 575,139%[?12l[?25h[?25l  576  576,0-140%[?12l[?25h[?25l  577 let atlas = Atlas::new(ATLAS_SIZE); 577,140%[?12l[?25h[?25l  578 renderer.atlas.push(atlas); 578,140%[?12l[?25h[?25l  579  579,0-140%[?12l[?25h[?25l  580 Ok(renderer) 580,140%[?12l[?25h[?25l  581  } 581,140%[?12l[?25h[?25l  582  582,0-140%[?12l[?25h[?25l  583  pub fn with_api<F, T>( 583,140%[?12l[?25h[?25l  584 &mut self, 584,140%[?12l[?25h[?25l  585 config: &Config, 585,140%[?12l[?25h[?25l  586 props: &term::SizeInfo, 586,140%[?12l[?25h[?25l  587 visual_bell_intensity: f64, 587,140%[?12l[?25h[?25l  588 func: F 588,140%[?12l[?25h[?25l  589  ) -> T 589,141%[?12l[?25h[?25l  590 where F: FnOnce(RenderApi) -> T 590,141%[?12l[?25h[?25l  591  { 591,141%[?12l[?25h[?25l  592 while let Ok(msg) = self.rx.try_recv() { 592,141%[?12l[?25h[?25l  593 match msg { 593,141%[?12l[?25h[?25l  594 Msg::ShaderReload => { 594,141%[?12l[?25h[?25l  595 self.reload_shaders(&config, Size { 595,141%[?12l[?25h[?25l  596 width: Pixels(props.width as u32), 596,141%[?12l[?25h[?25l  597 height: Pixels(props.height as u32) 597,141%[?12l[?25h[?25l  598 }); 598,141%[?12l[?25h[?25l  599 } 599,141%[?12l[?25h[?25l  600 } 600,141%[?12l[?25h[?25l  601 } 601,141%[?12l[?25h[?25l  602  602,0-142%[?12l[?25h[?25l  603 unsafe { 603,142%[?12l[?25h[?25l  604 self.program.activate(); 604,142%[?12l[?25h[?25l  605 self.program.set_term_uniforms(props); 605,142%[?12l[?25h[?25l  606 self.program.set_visual_bell(visual_bell_intensity as _); 606,142%[?12l[?25h[?25l  607  607,0-142%[?12l[?25h[?25l  608 gl::BindVertexArray(self.vao); 608,142%[?12l[?25h[?25l  609 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo); 609,142%[?12l[?25h[?25l  610 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_instance); 610,142%[?12l[?25h[?25l  611 gl::ActiveTexture(gl::TEXTURE0); 611,142%[?12l[?25h[?25l  612 } 612,142%[?12l[?25h[?25l  613  613,0-142%[?12l[?25h[?25l  614 let res = func(RenderApi { 614,142%[?12l[?25h[?25l  615 active_tex: &mut self.active_tex, 615,143%[?12l[?25h[?25l  616 batch: &mut self.batch, 616,143%[?12l[?25h[?25l  617 atlas: &mut self.atlas, 617,143%[?12l[?25h[?25l  618 program: &mut self.program, 618,143%[?12l[?25h[?25l  619 visual_bell_intensity: visual_bell_intensity as _, 619,143%[?12l[?25h[?25l  620 config: config, 620,143%[?12l[?25h[?25l  621 }); 621,143%[?12l[?25h[?25l  622  622,0-143%[?12l[?25h[?25l  623 unsafe { 623,143%[?12l[?25h[?25l  624 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); 624,143%[?12l[?25h[?25l  625 gl::BindBuffer(gl::ARRAY_BUFFER, 0); 625,143%[?12l[?25h[?25l  626 gl::BindVertexArray(0); 626,143%[?12l[?25h[?25l  627  627,0-143%[?12l[?25h[?25l  628 self.program.deactivate(); 628,144%[?12l[?25h[?25l  629 } 629,144%[?12l[?25h[?25l  630  630,0-144%[?12l[?25h[?25l  631 res 631,144%[?12l[?25h[?25l  632  } 632,144%[?12l[?25h[?25l  633  633,0-144%[?12l[?25h[?25l  634  pub fn with_loader<F, T>(&mut self, func: F) -> T 634,144%[?12l[?25h[?25l  635 where F: FnOnce(LoaderApi) -> T 635,144%[?12l[?25h[?25l  636  { 636,144%[?12l[?25h[?25l  637 unsafe { 637,144%[?12l[?25h[?25l  638 gl::ActiveTexture(gl::TEXTURE0); 638,144%[?12l[?25h[?25l  639 } 639,144%[?12l[?25h[?25l  640  640,0-144%[?12l[?25h[?25l  641 func(LoaderApi { 641,145%[?12l[?25h[?25l  642 active_tex: &mut self.active_tex, 642,145%[?12l[?25h[?25l  643 atlas: &mut self.atlas, 643,145%[?12l[?25h[?25l  644 }) 644,145%[?12l[?25h[?25l  645  } 645,145%[?12l[?25h[?25l  646  646,0-145%[?12l[?25h[?25l  647  pub fn reload_shaders(&mut self, config: &Config, size: Size<Pixels<u32>>) { 647,145%[?12l[?25h[?25l  648 info!("Reloading shaders"); 648,145%[?12l[?25h[?25l  649 let program = match ShaderProgram::new(config, size) { 649,145%[?12l[?25h[?25l  650 Ok(program) => program, 650,145%[?12l[?25h[?25l  651 Err(err) => { 651,145%[?12l[?25h[?25l  652 match err { 652,145%[?12l[?25h[?25l  653 ShaderCreationError::Io(err) => { 653,145%[?12l[?25h[?25l  654 error!("Error reading shader file: {}", err); 654,146%[?12l[?25h[?25l  655 }, 655,146%[?12l[?25h[?25l  656 ShaderCreationError::Compile(path, log) => { 656,146%[?12l[?25h[?25l  657 error!("Error compiling shader at {:?}", path); 657,146%[?12l[?25h[?25l  658 let _ = io::copy(&mut log.as_bytes(), &mut io::stdout()); 658,146%[?12l[?25h[?25l  659 } 659,146%[?12l[?25h[?25l  660 } 660,146%[?12l[?25h[?25l  661  661,0-146%[?12l[?25h[?25l  662 return; 662,146%[?12l[?25h[?25l  663 } 663,146%[?12l[?25h[?25l  664 }; 664,146%[?12l[?25h[?25l  665  665,0-146%[?12l[?25h[?25l  666 self.active_tex = 0; 666,146%[?12l[?25h[?25l  667 self.program = program; 667,147%[?12l[?25h[?25l  668  } 668,147%[?12l[?25h[?25l  669  669,0-147%[?12l[?25h[?25l  670  pub fn resize(&mut self, width: i32, height: i32) { 670,147%[?12l[?25h[?25l  671 let padding_x = self.program.padding_x as i32; 671,147%[?12l[?25h[?25l  672 let padding_y = self.program.padding_y as i32; 672,147%[?12l[?25h[?25l  673  673,0-147%[?12l[?25h[?25l  674 // viewport 674,147%[?12l[?25h[?25l  675 unsafe { 675,147%[?12l[?25h[?25l  676 gl::Viewport(padding_x, padding_y, width - 2 * padding_x, height - 2 * padding_y);  676,147%[?12l[?25h[?25l  677 } 677,147%[?12l[?25h[?25l  678  678,0-147%[?12l[?25h[?25l  679 // update projection 679,147%[?12l[?25h[?25l  680 self.program.activate(); 680,148%[?12l[?25h[?25l  681 self.program.update_projection(width as f32, height as f32); 681,148%[?12l[?25h[?25l  682 self.program.deactivate(); 682,148%[?12l[?25h[?25l  683  } 683,148%[?12l[?25h[?25l  684 } 684,148%[?12l[?25h[?25l  685  685,0-148%[?12l[?25h[?25l  686 impl<'a> RenderApi<'a> { 686,148%[?12l[?25h[?25l  687  pub fn clear(&self, color: Rgb) { 687,148%[?12l[?25h[?25l  688 unsafe { 688,148%[?12l[?25h[?25l  689 gl::ClearColor( 689,148%[?12l[?25h[?25l  690 (self.visual_bell_intensity + color.r as f32 / 255.0).min(1.0), 690,148%[?12l[?25h[?25l  691 (self.visual_bell_intensity + color.g as f32 / 255.0).min(1.0), 691,148%[?12l[?25h[?25l  692 (self.visual_bell_intensity + color.b as f32 / 255.0).min(1.0), 692,148%[?12l[?25h[?25l  693 1.0 693,149%[?12l[?25h[?25l  694 ); 694,149%[?12l[?25h[?25l  695 gl::Clear(gl::COLOR_BUFFER_BIT); 695,149%[?12l[?25h[?25l  696 } 696,149%[?12l[?25h[?25l  697  } 697,149%[?12l[?25h[?25l  698  698,0-149%[?12l[?25h[?25l  699  fn render_batch(&mut self) { 699,149%[?12l[?25h[?25l  700 unsafe { 700,149%[?12l[?25h[?25l  701 gl::BufferSubData(gl::ARRAY_BUFFER, 0, self.batch.size() as isize, 701,149%[?12l[?25h[?25l  702 self.batch.instances.as_ptr() as *const _); 702,149%[?12l[?25h[?25l  703 } 703,149%[?12l[?25h[?25l  704  704,0-149%[?12l[?25h[?25l  705 // Bind texture if necessary 705,150%[?12l[?25h[?25l  706 if *self.active_tex != self.batch.tex { 706,150%[?12l[?25h[?25l  707 unsafe { 707,150%[?12l[?25h[?25l  708 gl::BindTexture(gl::TEXTURE_2D, self.batch.tex); 708,150%[?12l[?25h[?25l  709 } 709,150%[?12l[?25h[?25l  710 *self.active_tex = self.batch.tex; 710,150%[?12l[?25h[?25l  711 } 711,150%[?12l[?25h[?25l  712  712,0-150%[?12l[?25h[?25l  713 unsafe { 713,150%[?12l[?25h[?25l  714 self.program.set_background_pass(true); 714,150%[?12l[?25h[?25l  715 gl::DrawElementsInstanced(gl::TRIANGLES, 715,150%[?12l[?25h[?25l  716 6, gl::UNSIGNED_INT, ptr::null(), 716,150%[?12l[?25h[?25l  717 self.batch.len() as GLsizei); 717,150%[?12l[?25h[?25l  718 self.program.set_background_pass(false); 718,151%[?12l[?25h[?25l  719 gl::DrawElementsInstanced(gl::TRIANGLES, 719,151%[?12l[?25h[?25l  720 6, gl::UNSIGNED_INT, ptr::null(), 720,151%[?12l[?25h[?25l  721 self.batch.len() as GLsizei); 721,151%[?12l[?25h[?25l  722 } 722,151%[?12l[?25h[?25l  723  723,0-151%[?12l[?25h[?25l  724 self.batch.clear(); 724,151%[?12l[?25h[?25l  725  } 725,151%[?12l[?25h[?25l  726  /// Render a string in a predefined location. Used for printing render time for profiling and  726,151%[?12l[?25h[?25l  727  /// optimization. 727,151%[?12l[?25h[?25l  728  pub fn render_string( 728,151%[?12l[?25h[?25l  729 &mut self, 729,151%[?12l[?25h[?25l  730 string: &str, 730,151%[?12l[?25h[?25l  731 glyph_cache: &mut GlyphCache, 731,152%[?12l[?25h[?25l  732 color: Rgb, 732,152%[?12l[?25h[?25l  733  ) { 733,152%[?12l[?25h[?25l  734 let line = Line(23); 734,152%[?12l[?25h[?25l  735 let col = Column(0); 735,152%[?12l[?25h[?25l  736  736,0-152%[?12l[?25h[?25l  737 let cells = string.chars() 737,152%[?12l[?25h[?25l  738 .enumerate() 738,152%[?12l[?25h[?25l  739 .map(|(i, c)| RenderableCell { 739,152%[?12l[?25h[?25l  740 line: line, 740,152%[?12l[?25h[?25l  741 column: col + i, 741,152%[?12l[?25h[?25l  742 c: c, 742,152%[?12l[?25h[?25l  743 bg: color, 743,152%[?12l[?25h[?25l  744 fg: Rgb { r: 0, g: 0, b: 0 }, 744,153%[?12l[?25h[?25l  745 flags: cell::Flags::empty(), 745,153%[?12l[?25h[?25l  746 }) 746,153%[?12l[?25h[?25l  747 .collect::<Vec<_>>(); 747,153%[?12l[?25h[?25l  748  748,0-153%[?12l[?25h[?25l  749 self.render_cells(cells.into_iter(), glyph_cache); 749,153%[?12l[?25h[?25l  750  } 750,153%[?12l[?25h[?25l  751  751,0-153%[?12l[?25h[?25l  752  #[inline] 752,153%[?12l[?25h[?25l  753  fn add_render_item(&mut self, cell: &RenderableCell, glyph: &Glyph) { 753,153%[?12l[?25h[?25l  754 // Flush batch if tex changing 754,153%[?12l[?25h[?25l  755 if !self.batch.is_empty() && self.batch.tex != glyph.tex_id { 755,153%[?12l[?25h[?25l  756 self.render_batch(); 756,153%[?12l[?25h[?25l  757 } 757,154%[?12l[?25h[?25l  758  758,0-154%[?12l[?25h[?25l  759 self.batch.add_item(cell, glyph); 759,154%[?12l[?25h[?25l  760  760,0-154%[?12l[?25h[?25l  761 // Render batch and clear if it's full 761,154%[?12l[?25h[?25l  762 if self.batch.full() { 762,154%[?12l[?25h[?25l  763 self.render_batch(); 763,154%[?12l[?25h[?25l  764 } 764,154%[?12l[?25h[?25l  765  } 765,154%[?12l[?25h[?25l  766  766,0-154%[?12l[?25h[?25l  767  pub fn render_cells<I>( 767,154%[?12l[?25h[?25l  768 &mut self, 768,154%[?12l[?25h[?25l  769 cells: I, 769,154%[?12l[?25h[?25l  770 glyph_cache: &mut GlyphCache 770,155%[?12l[?25h[?25l  771  ) 771,155%[?12l[?25h[?25l  772 where I: Iterator<Item=RenderableCell> 772,155%[?12l[?25h[?25l  773  { 773,155%[?12l[?25h[?25l  774 for cell in cells { 774,155%[?12l[?25h[?25l  775 // Get font key for cell 775,155%[?12l[?25h[?25l  776 // FIXME this is super inefficient. 776,155%[?12l[?25h[?25l  777 let mut font_key = glyph_cache.font_key; 777,155%[?12l[?25h[?25l  778 if cell.flags.contains(cell::BOLD) { 778,155%[?12l[?25h[?25l  779 font_key = glyph_cache.bold_key; 779,155%[?12l[?25h[?25l  780 } else if cell.flags.contains(cell::ITALIC) { 780,155%[?12l[?25h[?25l  781 font_key = glyph_cache.italic_key; 781,155%[?12l[?25h[?25l  782 } 782,155%[?12l[?25h[?25l  783  783,0-156%[?12l[?25h[?25l  784 let glyph_key = GlyphKey { 784,156%[?12l[?25h[?25l  785 font_key: font_key, 785,156%[?12l[?25h[?25l  786 size: glyph_cache.font_size, 786,156%[?12l[?25h[?25l  787 c: cell.c 787,156%[?12l[?25h[?25l  788 }; 788,156%[?12l[?25h[?25l  789  789,0-156%[?12l[?25h[?25l  790 // Add cell to batch 790,156%[?12l[?25h[?25l  791 { 791,156%[?12l[?25h[?25l  792 let glyph = glyph_cache.get(&glyph_key, self); 792,156%[?12l[?25h[?25l  793 self.add_render_item(&cell, glyph); 793,156%[?12l[?25h[?25l  794 } 794,156%[?12l[?25h[?25l  795  795,0-156%[?12l[?25h[?25l  796 // FIXME This is a super hacky way to do underlined text. During 796,157%[?12l[?25h[?25l  797 // a time crunch to release 0.1, this seemed like a really 797,157%[?12l[?25h[?25l  798 // easy, clean hack. 798,157%[?12l[?25h[?25l  799 if cell.flags.contains(cell::UNDERLINE) { 799,157%[?12l[?25h[?25l  800 let glyph_key = GlyphKey { 800,157%[?12l[?25h[?25l  801 font_key: font_key, 801,157%[?12l[?25h[?25l  802 size: glyph_cache.font_size, 802,157%[?12l[?25h[?25l  803 c: '_' 803,157%[?12l[?25h[?25l  804 }; 804,157%[?12l[?25h[?25l  805  805,0-157%[?12l[?25h[?25l  806 let underscore = glyph_cache.get(&glyph_key, self); 806,157%[?12l[?25h[?25l  807 self.add_render_item(&cell, underscore); 807,157%[?12l[?25h[?25l  808 } 808,157%[?12l[?25h[?25l  809 } 809,158%[?12l[?25h[?25l  810  } 810,158%[?12l[?25h[?25l  811 } 811,158%[?12l[?25h[?25l  812  812,0-158%[?12l[?25h[?25l  813 impl<'a> LoadGlyph for LoaderApi<'a> { 813,158%[?12l[?25h[?25l  814  /// Load a glyph into a texture atlas 814,158%[?12l[?25h[?25l  815  /// 815,158%[?12l[?25h[?25l  816  /// If the current atlas is full, a new one will be created. 816,158%[?12l[?25h[?25l  817  fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { 817,158%[?12l[?25h[?25l  818 // At least one atlas is guaranteed to be in the `self.atlas` list; thus 818,158%[?12l[?25h[?25l  819 // the unwrap should always be ok. 819,158%[?12l[?25h[?25l  820 match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) { 820,158%[?12l[?25h[?25l  821 Ok(glyph) => glyph, 821,158%[?12l[?25h[?25l  822 Err(_) => { 822,159%[?12l[?25h[?25l  823 let atlas = Atlas::new(ATLAS_SIZE); 823,159%[?12l[?25h[?25l  824 *self.active_tex = 0; // Atlas::new binds a texture. Ugh this is sloppy. 824,159%[?12l[?25h[?25l  825 self.atlas.push(atlas); 825,159%[?12l[?25h[?25l  826 self.load_glyph(rasterized) 826,159%[?12l[?25h[?25l  827 } 827,159%[?12l[?25h[?25l  828 } 828,159%[?12l[?25h[?25l  829  } 829,159%[?12l[?25h[?25l { 830 } 830,159%[?12l[?25h[?25l {}  831  831,0-159%[?12l[?25h[?25l  832 impl<'a> LoadGlyph for RenderApi<'a> { 832,159%[?12l[?25h[?25l  833  /// Load a glyph into a texture atlas 833,159%[?12l[?25h[?25l  834  /// 834,159%[?12l[?25h[?25l  835  /// If the current atlas is full, a new one will be created. 835,160%[?12l[?25h[?25l  836  fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { 836,160%[?12l[?25h[?25l  837 // At least one atlas is guaranteed to be in the `self.atlas` list; thus 837,160%[?12l[?25h[?25l  838 // the unwrap. 838,160%[?12l[?25h[?25l  839 match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) { 839,160%[?12l[?25h[?25l  840 Ok(glyph) => glyph, 840,160%[?12l[?25h[?25l  841 Err(_) => { 841,160%[?12l[?25h[?25l  842 let atlas = Atlas::new(ATLAS_SIZE); 842,160%[?12l[?25h[?25l  843 *self.active_tex = 0; // Atlas::new binds a texture. Ugh this is sloppy. 843,160%[?12l[?25h[?25l  844 self.atlas.push(atlas); 844,160%[?12l[?25h[?25l  845 self.load_glyph(rasterized) 845,160%[?12l[?25h[?25l  846 } 846,160%[?12l[?25h[?25l  847 } 847,160%[?12l[?25h[?25l  848  } 848,161%[?12l[?25h[?25l { 849 } 849,161%[?12l[?25h[?25l {}  850  850,0-161%[?12l[?25h[?25l  851 impl<'a> Drop for RenderApi<'a> { 851,161%[?12l[?25h[?25l  852  fn drop(&mut self) { 852,161%[?12l[?25h[?25l  853 if !self.batch.is_empty() { 853,161%[?12l[?25h[?25l  854 self.render_batch(); 854,161%[?12l[?25h[?25l  855 } 855,161%[?12l[?25h[?25l  856  } 856,161%[?12l[?25h[?25l { 857 } 857,161%[?12l[?25h[?25l {}  858  858,0-161%[?12l[?25h[?25l  859 impl ShaderProgram { 859,161%[?12l[?25h[?25l  860  pub fn activate(&self) { 860,161%[?12l[?25h[?25l  861 unsafe { 861,162%[?12l[?25h[?25l  862 gl::UseProgram(self.id); 862,162%[?12l[?25h[?25l  863 } 863,162%[?12l[?25h[?25l  864  } 864,162%[?12l[?25h[?25l  865  865,0-162%[?12l[?25h[?25l  866  pub fn deactivate(&self) { 866,162%[?12l[?25h[?25l  867 unsafe { 867,162%[?12l[?25h[?25l  868 gl::UseProgram(0); 868,162%[?12l[?25h[?25l  869 } 869,162%[?12l[?25h[?25l  870  } 870,162%[?12l[?25h[?25l  871  871,0-162%[?12l[?25h[?25l  872  pub fn new( 872,162%[?12l[?25h[?25l  873 config: &Config, 873,162%[?12l[?25h[?25l  874 size: Size<Pixels<u32>> 874,163%[?12l[?25h[?25l  875  ) -> Result<ShaderProgram, ShaderCreationError> { 875,163%[?12l[?25h[?25l  876 let vertex_source = if cfg!(feature = "live-shader-reload") { 876,163%[?12l[?25h[?25l  877 None 877,163%[?12l[?25h[?25l  878 } else { 878,163%[?12l[?25h[?25l  879 Some(TEXT_SHADER_V) 879,163%[?12l[?25h[?25l  880 }; 880,163%[?12l[?25h[?25l  881 let vertex_shader = ShaderProgram::create_shader( 881,163%[?12l[?25h[?25l  882 TEXT_SHADER_V_PATH, 882,163%[?12l[?25h[?25l  883 gl::VERTEX_SHADER, 883,163%[?12l[?25h[?25l  884 vertex_source 884,163%[?12l[?25h[?25l  885 )?; 885,163%[?12l[?25h[?25l  886 let frag_source = if cfg!(feature = "live-shader-reload") { 886,163%[?12l[?25h[?25l  887 None 887,164%[?12l[?25h[?25l  888 } else { 888,164%[?12l[?25h[?25l  889 Some(TEXT_SHADER_F) 889,164%[?12l[?25h[?25l  890 }; 890,164%[?12l[?25h[?25l  891 let fragment_shader = ShaderProgram::create_shader( 891,164%[?12l[?25h