summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-06-06 13:20:35 -0700
committerJoe Wilm <joe@jwilm.com>2016-06-06 13:20:35 -0700
commited7aa96907e8c5e51facb45f9b590ce25b4f3dd5 (patch)
treedfd2185e57f9ff792d25ae7ca81d56b69e96096d
parent1f3f9add49d9b6fae8f57bb907b278eb06b513c9 (diff)
Refactor Instanced Drawing to use Vertex Arrays
Per-instanced data was previously stored in uniforms. This required several OpenGL calls to upload all of the data, and it was more complex to prepare (several vecs vs one). Additionally, drawing APIs are now accessible through a `RenderApi` (obtained through `QuadRenderer::with_api`) which enables some RAII patterns. Specifically, checks for batch flushing are handled in Drop.
-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,