summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/text.f.glsl7
-rw-r--r--res/text.v.glsl43
-rw-r--r--src/main.rs14
-rw-r--r--src/renderer/mod.rs485
4 files changed, 277 insertions, 272 deletions
diff --git a/res/text.f.glsl b/res/text.f.glsl
index d3265712..d2defb39 100644
--- a/res/text.f.glsl
+++ b/res/text.f.glsl
@@ -1,17 +1,14 @@
#version 330 core
in vec2 TexCoords;
-flat in int InstanceId;
+in vec3 fg;
layout(location = 0, index = 0) out vec4 color;
layout(location = 0, index = 1) out vec4 alphaMask;
uniform sampler2D mask;
-uniform ivec3 textColor[32];
void main()
{
- int i = InstanceId;
alphaMask = vec4(texture(mask, TexCoords).rgb, 1.0);
- vec3 textColorF = vec3(textColor[i]) / vec3(255.0, 255.0, 255.0);
- color = vec4(textColorF, 1.0);
+ color = vec4(fg, 1.0);
}
diff --git a/res/text.v.glsl b/res/text.v.glsl
index 66bfad0c..276b1dc3 100644
--- a/res/text.v.glsl
+++ b/res/text.v.glsl
@@ -1,46 +1,51 @@
#version 330 core
layout (location = 0) in vec2 position;
+// Cell properties
+layout (location = 1) in vec2 gridCoords;
+
+// glyph properties
+layout (location = 2) in vec4 glyph;
+
+// uv mapping
+layout (location = 3) in vec4 uv;
+
+// text fg color
+layout (location = 4) in vec3 textColor;
+
out vec2 TexCoords;
-flat out int InstanceId;
+out vec3 fg;
// Terminal properties
uniform vec2 termDim;
uniform vec2 cellDim;
uniform vec2 cellSep;
-// Cell properties
-uniform vec2 gridCoords[32];
-
-// glyph properties
-uniform vec2 glyphScale[32];
-uniform vec2 glyphOffset[32];
-
-// uv mapping
-uniform vec2 uvScale[32];
-uniform vec2 uvOffset[32];
-
// Orthographic projection
uniform mat4 projection;
void main()
{
- int i = gl_InstanceID;
+ vec2 glyphOffset = glyph.xy;
+ vec2 glyphSize = glyph.zw;
+
+ vec2 uvOffset = uv.xy;
+ vec2 uvSize = uv.zw;
// Position of cell from top-left
- vec2 cellPosition = (cellDim + cellSep) * gridCoords[i];
+ vec2 cellPosition = (cellDim + cellSep) * gridCoords;
// Invert Y since framebuffer origin is bottom-left
cellPosition.y = termDim.y - cellPosition.y - cellDim.y;
// Glyphs are offset within their cell; account for y-flip
- vec2 cellOffset = vec2(glyphOffset[i].x,
- glyphOffset[i].y - glyphScale[i].y);
+ vec2 cellOffset = vec2(glyphOffset.x,
+ glyphOffset.y - glyphSize.y);
// position coordinates are normalized on [0, 1]
- vec2 finalPosition = glyphScale[i] * position + cellPosition + cellOffset;
+ vec2 finalPosition = glyphSize * position + cellPosition + cellOffset;
gl_Position = projection * vec4(finalPosition.xy, 0.0, 1.0);
- TexCoords = vec2(position.x, 1 - position.y) * uvScale[i] + uvOffset[i];
- InstanceId = i;
+ TexCoords = uvOffset + vec2(position.x, 1 - position.y) * uvSize;
+ fg = textColor / vec3(255.0, 255.0, 255.0);
}
diff --git a/src/main.rs b/src/main.rs
index 79c368df..e9817331 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -194,17 +194,21 @@ fn main() {
{
let _sampler = meter.sampler();
- // Draw the grid
- renderer.render_grid(terminal.grid(), &glyph_cache, &props);
+ renderer.with_api(&props, |mut api| {
+ // Draw the grid
+ api.render_grid(terminal.grid(), &glyph_cache);
- // Also draw the cursor
- renderer.render_cursor(terminal.cursor(), &glyph_cache, &props);
+ // Also draw the cursor
+ api.render_cursor(terminal.cursor(), &glyph_cache);
+ })
}
// Draw render timer
let timing = format!("{:.3} usec", meter.average());
let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
- renderer.render_string(&timing[..], &glyph_cache, &props, &color);
+ renderer.with_api(&props, |mut api| {
+ api.render_string(&timing[..], &glyph_cache, &color);
+ });
window.swap_buffers().unwrap();
}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index fe7919fd..ff2963f7 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -7,7 +7,6 @@ use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};
-use arrayvec::ArrayVec;
use cgmath::{self, Matrix};
use euclid::{Rect, Size2D, Point2D};
use gl::types::*;
@@ -23,7 +22,29 @@ use super::{Rgb, TermProps, GlyphCache};
static TEXT_SHADER_F_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.f.glsl");
static TEXT_SHADER_V_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/res/text.v.glsl");
+/// Text drawing program
+///
+/// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a".
#[derive(Debug)]
+pub struct ShaderProgram {
+ // Program id
+ id: GLuint,
+
+ /// projection matrix uniform
+ u_projection: GLint,
+
+ /// Terminal dimensions (pixels)
+ u_term_dim: GLint,
+
+ /// Cell dimensions (pixels)
+ u_cell_dim: GLint,
+
+ /// Cell separation (pixels)
+ u_cell_sep: GLint,
+}
+
+
+#[derive(Debug, Clone)]
pub struct Glyph {
tex_id: GLuint,
top: f32,
@@ -36,15 +57,46 @@ pub struct Glyph {
uv_height: f32,
}
+#[derive(Debug)]
+struct InstanceData {
+ // coords
+ col: f32,
+ row: f32,
+ // glyph offset
+ left: f32,
+ top: f32,
+ // glyph scale
+ width: f32,
+ height: f32,
+ // uv offset
+ uv_left: f32,
+ uv_bot: f32,
+ // uv scale
+ uv_width: f32,
+ uv_height: f32,
+ // color
+ r: f32,
+ g: f32,
+ b: f32,
+}
+
+#[derive(Debug)]
pub struct QuadRenderer {
program: ShaderProgram,
should_reload: Arc<AtomicBool>,
vao: GLuint,
vbo: GLuint,
ebo: GLuint,
- active_color: Rgb,
+ vbo_instance: GLuint,
atlas: Vec<Atlas>,
active_tex: GLuint,
+ batch: Batch,
+}
+
+#[derive(Debug)]
+pub struct RenderApi<'a> {
+ active_tex: &'a mut GLuint,
+ batch: &'a mut Batch,
}
#[derive(Debug)]
@@ -60,44 +112,17 @@ struct ElementIndex {
}
#[derive(Debug)]
-struct Batch {
+pub struct Batch {
tex: GLuint,
- coords: ArrayVec<[Point2D<f32>; BATCH_MAX]>,
- color: ArrayVec<[RgbUpload; BATCH_MAX]>,
- glyph_scale: ArrayVec<[Point2D<f32>; BATCH_MAX]>,
- glyph_offset: ArrayVec<[Point2D<f32>; BATCH_MAX]>,
- uv_scale: ArrayVec<[Point2D<f32>; BATCH_MAX]>,
- uv_offset: ArrayVec<[Point2D<f32>; BATCH_MAX]>,
-}
-
-#[derive(Debug)]
-struct RgbUpload {
- r: i32,
- g: i32,
- b: i32,
-}
-
-impl From<Rgb> for RgbUpload {
- #[inline]
- fn from(color: Rgb) -> RgbUpload {
- RgbUpload {
- r: color.r as i32,
- g: color.g as i32,
- b: color.b as i32,
- }
- }
+ instances: Vec<InstanceData>,
}
impl Batch {
+ #[inline]
pub fn new() -> Batch {
Batch {
tex: 0,
- coords: ArrayVec::new(),
- color: ArrayVec::new(),
- glyph_scale: ArrayVec::new(),
- glyph_offset: ArrayVec::new(),
- uv_scale: ArrayVec::new(),
- uv_offset: ArrayVec::new(),
+ instances: Vec::with_capacity(BATCH_MAX),
}
}
@@ -106,12 +131,24 @@ impl Batch {
self.tex = glyph.tex_id;
}
- self.coords.push(Point2D::new(col, row));
- self.color.push(RgbUpload::from(color));
- self.glyph_scale.push(Point2D::new(glyph.width, glyph.height));
- self.glyph_offset.push(Point2D::new(glyph.left, glyph.top));
- self.uv_scale.push(Point2D::new(glyph.uv_width, glyph.uv_height));
- self.uv_offset.push(Point2D::new(glyph.uv_left, glyph.uv_bot));
+ self.instances.push(InstanceData {
+ col: col,
+ row: row,
+
+ top: glyph.top,
+ left: glyph.left,
+ width: glyph.width,
+ height: glyph.height,
+
+ uv_bot: glyph.uv_bot,
+ uv_left: glyph.uv_left,
+ uv_width: glyph.uv_width,
+ uv_height: glyph.uv_height,
+
+ r: color.r as f32,
+ g: color.g as f32,
+ b: color.b as f32,
+ });
}
#[inline]
@@ -121,7 +158,7 @@ impl Batch {
#[inline]
pub fn len(&self) -> usize {
- self.color.len()
+ self.instances.len()
}
#[inline]
@@ -134,24 +171,20 @@ impl Batch {
self.len() == 0
}
- pub fn clear(&mut self) {
- self.tex = 0;
- self.coords.clear();
- self.color.clear();
- self.glyph_scale.clear();
- self.glyph_offset.clear();
- self.uv_scale.clear();
- self.uv_offset.clear();
+ #[inline]
+ pub fn size(&self) -> usize {
+ self.len() * size_of::<InstanceData>()
}
- pub fn render(&mut self, renderer: &mut QuadRenderer) {
- renderer.render_batch(self);
- self.clear();
+ pub fn clear(&mut self) {
+ self.tex = 0;
+ self.instances.clear();
}
}
/// Maximum items to be drawn in a batch.
-const BATCH_MAX: usize = 32usize;
+const BATCH_MAX: usize = 4096;
+const ATLAS_SIZE: i32 = 512;
impl QuadRenderer {
// TODO should probably hand this a transform instead of width/height
@@ -162,14 +195,19 @@ impl QuadRenderer {
let mut vbo: GLuint = 0;
let mut ebo: GLuint = 0;
+ let mut vbo_instance: GLuint = 0;
+
+
unsafe {
gl::GenVertexArrays(1, &mut vao);
gl::GenBuffers(1, &mut vbo);
gl::GenBuffers(1, &mut ebo);
+ gl::GenBuffers(1, &mut vbo_instance);
gl::BindVertexArray(vao);
- gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
-
+ // ----------------------------
+ // setup vertex position buffer
+ // ----------------------------
// Top right, Bottom right, Bottom left, Top left
let vertices = [
PackedVertex { x: 1.0, y: 1.0 },
@@ -178,33 +216,69 @@ impl QuadRenderer {
PackedVertex { x: 0.0, y: 1.0 },
];
- gl::BufferData(
- gl::ARRAY_BUFFER,
- (size_of::<PackedVertex>() * vertices.len()) as GLsizeiptr,
- vertices.as_ptr() as *const _,
- gl::STATIC_DRAW
- );
+ gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
+
+ gl::VertexAttribPointer(0, 2,
+ gl::FLOAT, gl::FALSE,
+ size_of::<PackedVertex>() as i32,
+ ptr::null());
+ gl::EnableVertexAttribArray(0);
+ gl::BufferData(gl::ARRAY_BUFFER,
+ (size_of::<PackedVertex>() * vertices.len()) as GLsizeiptr,
+ vertices.as_ptr() as *const _,
+ gl::STATIC_DRAW);
+
+ // ---------------------
+ // Set up element buffer
+ // ---------------------
let indices: [u32; 6] = [0, 1, 3,
1, 2, 3];
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
- 6 * size_of::<u32>() as isize,
+ (6 * size_of::<u32>()) as isize,
indices.as_ptr() as *const _,
gl::STATIC_DRAW);
- gl::EnableVertexAttribArray(0);
-
- // positions
- gl::VertexAttribPointer(0, 2,
+ // ----------------------------
+ // Setup vertex instance buffer
+ // ----------------------------
+ gl::BindBuffer(gl::ARRAY_BUFFER, vbo_instance);
+ gl::BufferData(gl::ARRAY_BUFFER,
+ (BATCH_MAX * size_of::<InstanceData>()) as isize,
+ ptr::null(), gl::STREAM_DRAW);
+ // coords
+ gl::VertexAttribPointer(1, 2,
gl::FLOAT, gl::FALSE,
- size_of::<PackedVertex>() as i32,
+ size_of::<InstanceData>() as i32,
ptr::null());
+ gl::EnableVertexAttribArray(1);
+ gl::VertexAttribDivisor(1, 1);
+ // glyphoffset
+ gl::VertexAttribPointer(2, 4,
+ gl::FLOAT, gl::FALSE,
+ size_of::<InstanceData>() as i32,
+ (2 * size_of::<f32>()) as *const _);
+ gl::EnableVertexAttribArray(2);
+ gl::VertexAttribDivisor(2, 1);
+ // uv
+ gl::VertexAttribPointer(3, 4,
+ gl::FLOAT, gl::FALSE,
+ size_of::<InstanceData>() as i32,
+ (6 * size_of::<f32>()) as *const _);
+ gl::EnableVertexAttribArray(3);
+ gl::VertexAttribDivisor(3, 1);
+ // color
+ gl::VertexAttribPointer(4, 3,
+ gl::FLOAT, gl::FALSE,
+ size_of::<InstanceData>() as i32,
+ (10 * size_of::<f32>()) as *const _);
+ gl::EnableVertexAttribArray(4);
+ gl::VertexAttribDivisor(4, 1);
gl::BindVertexArray(0);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
- gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
}
let should_reload = Arc::new(AtomicBool::new(false));
@@ -245,118 +319,40 @@ impl QuadRenderer {
vao: vao,
vbo: vbo,
ebo: ebo,
- active_color: Rgb { r: 0, g: 0, b: 0 },
+ vbo_instance: vbo_instance,
atlas: Vec::new(),
active_tex: 0,
+ batch: Batch::new(),
};
- let atlas = renderer.create_atlas(1024);
+ let atlas = renderer.create_atlas(ATLAS_SIZE);
renderer.atlas.push(atlas);
renderer
}
- /// Render a string in a predefined location. Used for printing render time for profiling and
- /// optimization.
- pub fn render_string(&mut self,
- s: &str,
- glyph_cache: &GlyphCache,
- props: &TermProps,
- color: &Rgb)
+ pub fn with_api<F>(&mut self, props: &TermProps, mut func: F)
+ where F: FnMut(RenderApi)
{
- self.prepare_render(props);
-
- let row = 40.0;
- let mut col = 100.0;
-
- let mut batch = Batch::new();
-
- for c in s.chars() {
- if let Some(glyph) = glyph_cache.get(&c) {
- batch.add_item(row, col, *color, glyph);
- }
-
- col += 1.0;
-
- // Render batch and clear if it's full
- if batch.full() {
- batch.render(self);
- }
- }
-
- if !batch.is_empty() {
- batch.render(self);
- }
-
- self.finish_render();
- }
-
- pub fn render_cursor(&mut self,
- cursor: term::Cursor,
- glyph_cache: &GlyphCache,
- props: &TermProps)
- {
- self.prepare_render(props);
-
- if let Some(glyph) = glyph_cache.get(&term::CURSOR_SHAPE) {
- let mut batch = Batch::new();
- batch.add_item(cursor.y as f32, cursor.x as f32, term::DEFAULT_FG, glyph);
- batch.render(self);
- }
-
- self.finish_render();
- }
-
- pub fn render_grid(&mut self, grid: &Grid, glyph_cache: &GlyphCache, props: &TermProps) {
- self.prepare_render(props);
-
- // All draws are batched
- let mut batch = Batch::new();
-
- for (i, row) in grid.rows().enumerate() {
- for (j, cell) in row.cells().enumerate() {
- // Skip empty cells
- if cell.c == ' ' {
- continue;
- }
-
- // Add cell to batch if the glyph is laoded
- if let Some(glyph) = glyph_cache.get(&cell.c) {
- batch.add_item(i as f32, j as f32, cell.fg, glyph);
- }
-
- // Render batch and clear if it's full
- if batch.full() {
- batch.render(self);
- }
- }
- }
-
- // Could have some data in a batch still; render it.
- if !batch.is_empty() {
- batch.render(self);
+ if self.should_reload.load(Ordering::Relaxed) {
+ self.reload_shaders(props.width as u32, props.height as u32);
}
- self.finish_render();
- }
-
- fn prepare_render(&mut self, props: &TermProps) {
unsafe {
self.program.activate();
self.program.set_term_uniforms(props);
gl::BindVertexArray(self.vao);
- gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
+ gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_instance);
gl::ActiveTexture(gl::TEXTURE0);
}
- if self.should_reload.load(Ordering::Relaxed) {
- self.reload_shaders(props.width as u32, props.height as u32);
- }
- }
+ func(RenderApi {
+ active_tex: &mut self.active_tex,
+ batch: &mut self.batch,
+ });
- fn finish_render(&mut self) {
unsafe {
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
@@ -386,27 +382,9 @@ impl QuadRenderer {
};
self.active_tex = 0;
- self.active_color = Rgb { r: 0, g: 0, b: 0 };
self.program = program;
}
- fn render_batch(&mut self, batch: &Batch) {
- self.program.set_uniforms(batch);
-
- // Bind texture if necessary
- if self.active_tex != batch.tex {
- unsafe {
- gl::BindTexture(gl::TEXTURE_2D, batch.tex);
- }
- self.active_tex = batch.tex;
- }
-
- unsafe {
- let count = batch.len() as GLsizei;
- gl::DrawElementsInstanced(gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null(), count);
- }
- }
-
/// Load a glyph into a texture atlas
///
/// If the current atlas is full, a new one will be created.
@@ -414,7 +392,7 @@ impl QuadRenderer {
match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) {
Ok(glyph) => glyph,
Err(_) => {
- let atlas = self.create_atlas(1024);
+ let atlas = self.create_atlas(ATLAS_SIZE);
self.atlas.push(atlas);
self.load_glyph(rasterized)
}
@@ -459,46 +437,94 @@ impl QuadRenderer {
}
}
-fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
- Rect::new(
- Point2D::new(x + glyph.left as f32, y - (glyph.height - glyph.top) as f32),
- Size2D::new(glyph.width as f32, glyph.height as f32)
- )
-}
+impl<'a> RenderApi<'a> {
+ fn render_batch(&mut self) {
+ unsafe {
+ gl::BufferSubData(gl::ARRAY_BUFFER, 0, self.batch.size() as isize,
+ self.batch.instances.as_ptr() as *const _);
+ }
-pub struct ShaderProgram {
- // Program id
- id: GLuint,
+ // Bind texture if necessary
+ if *self.active_tex != self.batch.tex {
+ unsafe {
+ gl::BindTexture(gl::TEXTURE_2D, self.batch.tex);
+ }
+ *self.active_tex = self.batch.tex;
+ }
- /// projection matrix uniform
- u_projection: GLint,
+ unsafe {
+ gl::DrawElementsInstanced(gl::TRIANGLES,
+ 6, gl::UNSIGNED_INT, ptr::null(),
+ self.batch.len() as GLsizei);
+ }
- /// color uniform
- u_color: GLint,
+ self.batch.clear();
+ }
+ /// Render a string in a predefined location. Used for printing render time for profiling and
+ /// optimization.
+ pub fn render_string(&mut self,
+ s: &str,
+ glyph_cache: &GlyphCache,
+ color: &Rgb)
+ {
+ let row = 40.0;
+ let mut col = 100.0;
- /// Terminal dimensions (pixels)
- u_term_dim: GLint,
+ for c in s.chars() {
+ if let Some(glyph) = glyph_cache.get(&c) {
+ self.add_render_item(row, col, *color, glyph);
+ }
- /// Cell dimensions (pixels)
- u_cell_dim: GLint,
+ col += 1.0;
+ }
+ }
- /// Cell separation (pixels)
- u_cell_sep: GLint,
+ #[inline]
+ fn add_render_item(&mut self, row: f32, col: f32, color: Rgb, glyph: &Glyph) {
+ self.batch.add_item(row, col, color, glyph);
- /// Cell coordinates in grid
- u_cell_coord: GLint,
+ // Render batch and clear if it's full
+ if self.batch.full() {
+ self.render_batch();
+ }
+ }
- /// Glyph scale
- u_glyph_scale: GLint,
+ pub fn render_cursor(&mut self, cursor: term::Cursor, glyph_cache: &GlyphCache) {
+ if let Some(glyph) = glyph_cache.get(&term::CURSOR_SHAPE) {
+ self.add_render_item(cursor.y as f32, cursor.x as f32, term::DEFAULT_FG, glyph);
+ }
+ }
- /// Glyph offset
- u_glyph_offset: GLint,
+ pub fn render_grid(&mut self, grid: &Grid, glyph_cache: &GlyphCache) {
+ for (i, row) in grid.rows().enumerate() {
+ for (j, cell) in row.cells().enumerate() {
+ // Skip empty cells
+ if cell.c == ' ' {
+ continue;
+ }
- /// Atlas scale
- u_uv_scale: GLint,
+ // Add cell to batch if the glyph is laoded
+ if let Some(glyph) = glyph_cache.get(&cell.c) {
+ self.add_render_item(i as f32, j as f32, cell.fg, glyph);
+ }
+ }
+ }
+ }
+}
- /// Atlas offset
- u_uv_offset: GLint,
+impl<'a> Drop for RenderApi<'a> {
+ fn drop(&mut self) {
+ if !self.batch.is_empty() {
+ self.render_batch();
+ }
+ }
+}
+
+fn get_rect(glyph: &Glyph, x: f32, y: f32) -> Rect<f32> {
+ Rect::new(
+ Point2D::new(x + glyph.left as f32, y - (glyph.height - glyph.top) as f32),
+ Size2D::new(glyph.width as f32, glyph.height as f32)
+ )
}
impl ShaderProgram {
@@ -541,47 +567,23 @@ impl ShaderProgram {
}
// get uniform locations
- let (projection, color, term_dim, cell_dim, cell_sep) = unsafe {
+ let (projection, term_dim, cell_dim, cell_sep) = unsafe {
(
gl::GetUniformLocation(program, cptr!(b"projection\0")),
- gl::GetUniformLocation(program, cptr!(b"textColor\0")),
gl::GetUniformLocation(program, cptr!(b"termDim\0")),
gl::GetUniformLocation(program, cptr!(b"cellDim\0")),
gl::GetUniformLocation(program, cptr!(b"cellSep\0")),
)
};
- assert_uniform_valid!(projection, color, term_dim, cell_dim, cell_sep);
-
- let (cell_coord, glyph_scale, glyph_offset, uv_scale, uv_offset) = unsafe {
- (
- gl::GetUniformLocation(program, cptr!(b"gridCoords\0")),
- gl::GetUniformLocation(program, cptr!(b"glyphScale\0")),
- gl::GetUniformLocation(program, cptr!(b"glyphOffset\0")),
- gl::GetUniformLocation(program, cptr!(b"uvScale\0")),
- gl::GetUniformLocation(program, cptr!(b"uvOffset\0")),
- )
- };
-
- assert_uniform_valid!(cell_coord, glyph_scale, glyph_offset, uv_scale, uv_offset);
-
- // Initialize to known color (black)
- unsafe {
- gl::Uniform3i(color, 0, 0, 0);
- }
+ assert_uniform_valid!(projection, term_dim, cell_dim, cell_sep);
let shader = ShaderProgram {
id: program,
u_projection: projection,
- u_color: color,
u_term_dim: term_dim,
u_cell_dim: cell_dim,
u_cell_sep: cell_sep,
- u_cell_coord: cell_coord,
- u_glyph_scale: glyph_scale,
- u_glyph_offset: glyph_offset,
- u_uv_scale: uv_scale,
- u_uv_offset: uv_offset,
};
// set projection uniform
@@ -608,18 +610,6 @@ impl ShaderProgram {
}
}
- fn set_uniforms(&self, batch: &Batch) {
- let len = batch.len();
- unsafe {
- gl::Uniform2fv(self.u_cell_coord, len as i32, batch.coords.as_ptr() as *const _);
- gl::Uniform2fv(self.u_glyph_scale, len as i32, batch.glyph_scale.as_ptr() as *const _);
- gl::Uniform2fv(self.u_glyph_offset, len as i32, batch.glyph_offset.as_ptr() as *const _);
- gl::Uniform2fv(self.u_uv_scale, len as i32, batch.uv_scale.as_ptr() as *const _);
- gl::Uniform2fv(self.u_uv_offset, len as i32, batch.uv_offset.as_ptr() as *const _);
- gl::Uniform3iv(self.u_color, len as i32, batch.color.as_ptr() as *const _);
- }
- }
-
fn create_program(vertex: GLuint, fragment: GLuint) -> GLuint {
unsafe {
let program = gl::CreateProgram();
@@ -667,6 +657,14 @@ impl ShaderProgram {
}
}
+impl Drop for ShaderProgram {
+ fn drop(&mut self) {
+ unsafe {
+ gl::DeleteProgram(self.id);
+ }
+ }
+}
+
fn get_program_info_log(program: GLuint) -> String {
// Get expected log length
let mut max_length: GLint = 0;
@@ -780,6 +778,7 @@ impl From<io::Error> for ShaderCreationError {
/// │ │ │ │ │ <- Row considered full when next glyph doesn't
/// └─────┴─────┴─────┴───────────┘ fit in the row.
/// (0, 0) x->
+#[derive(Debug)]
struct Atlas {
/// Texture id for this atlas
id: GLuint,