1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

opengl: make it easier to track quads

The offset math around the scroll thumb made me uncomfortable
so this commit introduces a struct to keep track of the vertex
indices and make it easier to recall them later.
This commit is contained in:
Wez Furlong 2019-12-23 19:13:15 -08:00
parent 68a2d9f159
commit fc6d80af0e
3 changed files with 113 additions and 92 deletions

View File

@ -3,7 +3,9 @@
#![allow(clippy::unneeded_field_pattern)]
use ::window::bitmaps::TextureRect;
use ::window::glium::VertexBuffer;
use ::window::*;
use std::cell::RefMut;
/// Each cell is composed of two triangles built from 4 vertices.
/// The buffer is organized row by row.
@ -44,20 +46,65 @@ pub struct Vertex {
has_color
);
/// A helper for knowing how to locate the right quad for an element
/// in the UI
#[derive(Default, Debug, Clone)]
pub struct Quads {
/// How many cells per row
pub cols: usize,
/// row number to vertex index for the first vertex on that row
pub row_starts: Vec<usize>,
/// The vertex index for the first vertex of the scroll bar thumb
pub scroll_thumb: usize,
}
pub struct MappedQuads<'a> {
mapping: glium::buffer::Mapping<'a, [Vertex]>,
quads: Quads,
}
impl<'a> MappedQuads<'a> {
pub fn cell<'b>(&'b mut self, x: usize, y: usize) -> anyhow::Result<Quad<'b>> {
if x >= self.quads.cols {
anyhow::bail!("column {} is outside of the vertex buffer range", x);
}
let start = self
.quads
.row_starts
.get(y)
.ok_or_else(|| anyhow::anyhow!("line {} is outside the vertex buffer range", y))?
+ x * VERTICES_PER_CELL;
Ok(Quad {
vert: &mut self.mapping[start..start + VERTICES_PER_CELL],
})
}
pub fn scroll_thumb<'b>(&'b mut self) -> Quad<'b> {
let start = self.quads.scroll_thumb;
Quad {
vert: &mut self.mapping[start..start + VERTICES_PER_CELL],
}
}
}
impl Quads {
pub fn map<'a>(&self, vb: &'a mut RefMut<VertexBuffer<Vertex>>) -> MappedQuads<'a> {
let mapping = vb.slice_mut(..).expect("to map vertex buffer").map();
MappedQuads {
mapping,
quads: self.clone(),
}
}
}
/// A helper for updating the 4 vertices that compose a glyph cell
pub struct Quad<'a> {
vert: &'a mut [Vertex],
}
impl<'a> Quad<'a> {
/// Returns a reference to the Quad for the given cell column index
/// into the set of vertices for a line.
pub fn for_cell(cell_idx: usize, vertices: &'a mut [Vertex]) -> Self {
let vert_idx = cell_idx * VERTICES_PER_CELL;
let vert = &mut vertices[vert_idx..vert_idx + VERTICES_PER_CELL];
Self { vert }
}
/// Assign the texture coordinates
pub fn set_texture(&mut self, coords: TextureRect) {
self.vert[V_TOP_LEFT].tex = (coords.min_x(), coords.min_y());

View File

@ -1,4 +1,5 @@
use super::glyphcache::{CachedGlyph, GlyphCache};
use super::quad::*;
use super::utilsprites::{RenderMetrics, UtilSprites};
use crate::config::{configuration, TextStyle};
use crate::font::{FontConfiguration, GlyphInfo};
@ -11,8 +12,6 @@ use anyhow::{anyhow, bail};
use std::cell::RefCell;
use std::rc::Rc;
use super::quad::*;
pub struct SoftwareRenderState {
pub glyph_cache: RefCell<GlyphCache<ImageTexture>>,
pub util_sprites: UtilSprites<ImageTexture>,
@ -40,6 +39,7 @@ pub struct OpenGLRenderState {
pub program: glium::Program,
pub glyph_vertex_buffer: RefCell<VertexBuffer<Vertex>>,
pub glyph_index_buffer: IndexBuffer<u32>,
pub quads: Quads,
}
impl OpenGLRenderState {
@ -80,7 +80,7 @@ impl OpenGLRenderState {
let program =
program.ok_or_else(|| anyhow!("Failed to compile shaders: {}", errors.join("\n")))?;
let (glyph_vertex_buffer, glyph_index_buffer) =
let (glyph_vertex_buffer, glyph_index_buffer, quads) =
Self::compute_vertices(&context, metrics, pixel_width as f32, pixel_height as f32)?;
Ok(Self {
@ -90,6 +90,7 @@ impl OpenGLRenderState {
program,
glyph_vertex_buffer: RefCell::new(glyph_vertex_buffer),
glyph_index_buffer,
quads,
})
}
@ -99,7 +100,7 @@ impl OpenGLRenderState {
pixel_width: usize,
pixel_height: usize,
) -> anyhow::Result<()> {
let (glyph_vertex_buffer, glyph_index_buffer) = Self::compute_vertices(
let (glyph_vertex_buffer, glyph_index_buffer, quads) = Self::compute_vertices(
&self.context,
metrics,
pixel_width as f32,
@ -108,6 +109,7 @@ impl OpenGLRenderState {
*self.glyph_vertex_buffer.borrow_mut() = glyph_vertex_buffer;
self.glyph_index_buffer = glyph_index_buffer;
self.quads = quads;
Ok(())
}
@ -130,7 +132,7 @@ impl OpenGLRenderState {
metrics: &RenderMetrics,
width: f32,
height: f32,
) -> anyhow::Result<(VertexBuffer<Vertex>, IndexBuffer<u32>)> {
) -> anyhow::Result<(VertexBuffer<Vertex>, IndexBuffer<u32>, Quads)> {
let cell_width = metrics.cell_size.width as f32;
let cell_height = metrics.cell_size.height as f32;
let mut verts = Vec::new();
@ -159,31 +161,31 @@ impl OpenGLRenderState {
padding_top
);
for y in 0..num_rows {
let y_pos = (height / -2.0) + (y as f32 * cell_height) + padding_top;
for x in 0..num_cols {
let x_pos = (width / -2.0) + (x as f32 * cell_width) + padding_left;
let mut quads = Quads::default();
quads.cols = num_cols;
let mut define_quad = |left, top, right, bottom| -> u32 {
// Remember starting index for this position
let idx = verts.len() as u32;
verts.push(Vertex {
// Top left
position: (x_pos, y_pos),
position: (left, top),
..Default::default()
});
verts.push(Vertex {
// Top Right
position: (x_pos + cell_width, y_pos),
position: (right, top),
..Default::default()
});
verts.push(Vertex {
// Bottom Left
position: (x_pos, y_pos + cell_height),
position: (left, bottom),
..Default::default()
});
verts.push(Vertex {
// Bottom Right
position: (x_pos + cell_width, y_pos + cell_height),
position: (right, bottom),
..Default::default()
});
@ -195,6 +197,21 @@ impl OpenGLRenderState {
indices.push(idx + V_TOP_RIGHT as u32);
indices.push(idx + V_BOT_LEFT as u32);
indices.push(idx + V_BOT_RIGHT as u32);
idx
};
for y in 0..num_rows {
let y_pos = (height / -2.0) + (y as f32 * cell_height) + padding_top;
for x in 0..num_cols {
let x_pos = (width / -2.0) + (x as f32 * cell_width) + padding_left;
let idx = define_quad(x_pos, y_pos, x_pos + cell_width, y_pos + cell_height);
if x == 0 {
// build row -> vertex mapping
quads.row_starts.push(idx as usize);
}
}
}
@ -205,37 +222,8 @@ impl OpenGLRenderState {
let thumb_width = cell_width;
let thumb_height = height;
// Remember starting index for this position
let idx = verts.len() as u32;
verts.push(Vertex {
// Top left
position: (x_pos, thumb_width),
..Default::default()
});
verts.push(Vertex {
// Top Right
position: (x_pos + thumb_width, y_pos),
..Default::default()
});
verts.push(Vertex {
// Bottom Left
position: (x_pos, y_pos + thumb_height),
..Default::default()
});
verts.push(Vertex {
// Bottom Right
position: (x_pos + thumb_width, y_pos + thumb_height),
..Default::default()
});
// Emit two triangles to form the glyph quad
indices.push(idx + V_TOP_LEFT as u32);
indices.push(idx + V_TOP_RIGHT as u32);
indices.push(idx + V_BOT_LEFT as u32);
indices.push(idx + V_TOP_RIGHT as u32);
indices.push(idx + V_BOT_LEFT as u32);
indices.push(idx + V_BOT_RIGHT as u32);
quads.scroll_thumb =
define_quad(x_pos, y_pos, x_pos + thumb_width, y_pos + thumb_height) as usize;
}
Ok((
@ -245,6 +233,7 @@ impl OpenGLRenderState {
glium::index::PrimitiveType::TrianglesList,
&indices,
)?,
quads,
))
}
}

View File

@ -1403,6 +1403,10 @@ impl TermWindow {
}
};
let gl_state = self.render_state.opengl();
let mut vb = gl_state.glyph_vertex_buffer.borrow_mut();
let mut quads = gl_state.quads.map(&mut vb);
if self.show_tab_bar {
self.render_screen_line_opengl(
0,
@ -1411,6 +1415,7 @@ impl TermWindow {
&cursor,
&*term,
&palette,
&mut quads,
)?;
}
@ -1419,13 +1424,7 @@ impl TermWindow {
let thumb_top = info.top as f32;
let thumb_size = info.height as f32;
let gl_state = self.render_state.opengl();
// We reserved the final quad in the vertex buffer as the scrollbar
let mut vb = gl_state.glyph_vertex_buffer.borrow_mut();
let num_vert = vb.len() - VERTICES_PER_CELL;
let mut vertices = &mut vb.slice_mut(num_vert..).unwrap().map();
let mut quad = Quad::for_cell(0, &mut vertices);
let mut quad = quads.scroll_thumb();
// Adjust the scrollbar thumb position
let top = (self.dimensions.pixel_height as f32 / -2.0) + thumb_top;
@ -1454,11 +1453,11 @@ impl TermWindow {
&cursor,
&*term,
&palette,
&mut quads,
)?;
}
}
let gl_state = self.render_state.opengl();
let tex = gl_state.glyph_cache.borrow().atlas.texture();
let projection = euclid::Transform3D::<f32, f32, f32>::ortho(
-(self.dimensions.pixel_width as f32) / 2.0,
@ -1475,9 +1474,11 @@ impl TermWindow {
..Default::default()
};
drop(quads);
// Pass 1: Draw backgrounds, strikethrough and underline
frame.draw(
&*gl_state.glyph_vertex_buffer.borrow(),
&*vb,
&gl_state.glyph_index_buffer,
&gl_state.program,
&uniform! {
@ -1490,7 +1491,7 @@ impl TermWindow {
// Pass 2: Draw glyphs
frame.draw(
&*gl_state.glyph_vertex_buffer.borrow(),
&*vb,
&gl_state.glyph_index_buffer,
&gl_state.program,
&uniform! {
@ -1518,27 +1519,11 @@ impl TermWindow {
cursor: &CursorPosition,
terminal: &dyn Renderable,
palette: &ColorPalette,
quads: &mut MappedQuads,
) -> anyhow::Result<()> {
let gl_state = self.render_state.opengl();
let (_num_rows, num_cols) = terminal.physical_dimensions();
let mut vb = gl_state.glyph_vertex_buffer.borrow_mut();
let mut vertices = {
let per_line = num_cols * VERTICES_PER_CELL;
let start_pos = line_idx * per_line;
vb.slice_mut(start_pos..start_pos + per_line)
.ok_or_else(|| {
anyhow!(
"we're confused about the screen size; \
line_idx={} start_pos={} per_line={} num_cols={}",
line_idx,
start_pos,
per_line,
num_cols
)
})?
.map()
};
let current_highlight = terminal.current_highlight();
let cursor_border_color = rgbcolor_to_window_color(palette.cursor_border);
@ -1673,7 +1658,7 @@ impl TermWindow {
let texture_rect = sprite.texture.to_texture_coords(coords);
let mut quad = Quad::for_cell(cell_idx, &mut vertices);
let mut quad = quads.cell(cell_idx, line_idx)?;
quad.set_fg_color(glyph_color);
quad.set_bg_color(bg_color);
@ -1715,7 +1700,7 @@ impl TermWindow {
let right = pixel_rect.size.width as f32 + left
- self.render_metrics.cell_size.width as f32;
let mut quad = Quad::for_cell(cell_idx, &mut vertices);
let mut quad = quads.cell(cell_idx, line_idx)?;
quad.set_fg_color(glyph_color);
quad.set_bg_color(bg_color);
@ -1757,7 +1742,7 @@ impl TermWindow {
palette,
);
let mut quad = Quad::for_cell(cell_idx, &mut vertices);
let mut quad = quads.cell(cell_idx, line_idx)?;
quad.set_bg_color(bg_color);
quad.set_fg_color(glyph_color);