use super::{BackgroundInstance, CellRenderer, TextInstance};
use anyhow::Result;
pub(crate) const CURSOR_OVERLAY_SLOTS: usize = 10;
pub(crate) const GUTTER_WIDTH_CELLS: f32 = 2.0;
pub(crate) const UNDERLINE_HEIGHT_RATIO: f32 = 0.07;
pub(crate) const GLYPH_SNAP_THRESHOLD_PX: f32 = 3.0;
pub(crate) const GLYPH_SNAP_EXTENSION_PX: f32 = 0.5;
pub(crate) const COLOR_COMPONENT_EPSILON: f32 = 0.001;
pub(crate) const CURSOR_BRIGHTNESS_THRESHOLD: f32 = 0.5;
pub(crate) const CURSOR_BOOST_MAX_ALPHA: f32 = 0.3;
pub(crate) const HOLLOW_CURSOR_BORDER_PX: f32 = 1.0;
pub(crate) const STIPPLE_ON_PX: f32 = 2.0;
pub(crate) const STIPPLE_OFF_PX: f32 = 2.0;
pub(crate) const TEXT_INSTANCES_PER_CELL: usize = 2;
pub(crate) fn compute_cursor_text_color(
cursor_color: [f32; 3],
cursor_text_color: Option<[f32; 3]>,
text_alpha: f32,
) -> [f32; 4] {
if let Some(cursor_text) = cursor_text_color {
[cursor_text[0], cursor_text[1], cursor_text[2], text_alpha]
} else {
let cursor_brightness = (cursor_color[0] + cursor_color[1] + cursor_color[2]) / 3.0;
if cursor_brightness > CURSOR_BRIGHTNESS_THRESHOLD {
[0.0, 0.0, 0.0, text_alpha] } else {
[1.0, 1.0, 1.0, text_alpha] }
}
}
impl CellRenderer {
pub(crate) fn build_instance_buffers(&mut self) -> Result<()> {
for row in 0..self.grid.rows {
if self.dirty_rows[row] || self.row_cache[row].is_none() {
let start = row * self.grid.cols;
let end = (row + 1) * self.grid.cols;
let mut row_cells = std::mem::take(&mut self.scratch_row_cells);
row_cells.clear();
row_cells.extend_from_slice(&self.cells[start..end]);
self.scratch_row_bg.clear();
self.scratch_row_text.clear();
self.build_row_bg_instances(row, &row_cells);
self.build_row_text_instances(row, &row_cells, start);
let bg_start = row * self.grid.cols;
self.bg_instances[bg_start..bg_start + self.grid.cols]
.copy_from_slice(&self.scratch_row_bg);
let text_start = row * self.grid.cols * 2;
for i in 0..(self.grid.cols * 2) {
self.text_instances[text_start + i].size = [0.0, 0.0];
}
let text_count = self.scratch_row_text.len().min(self.grid.cols * 2);
self.text_instances[text_start..text_start + text_count]
.copy_from_slice(&self.scratch_row_text[..text_count]);
self.queue.write_buffer(
&self.buffers.bg_instance_buffer,
(bg_start * std::mem::size_of::<BackgroundInstance>()) as u64,
bytemuck::cast_slice(&self.scratch_row_bg),
);
self.queue.write_buffer(
&self.buffers.text_instance_buffer,
(text_start * std::mem::size_of::<TextInstance>()) as u64,
bytemuck::cast_slice(
&self.text_instances[text_start..text_start + self.grid.cols * 2],
),
);
self.row_cache[row] = Some(true);
self.dirty_rows[row] = false;
self.scratch_row_cells = row_cells;
}
}
let base_overlay_index = self.grid.cols * self.grid.rows;
let overlay_instances = self.build_cursor_overlay_instances();
for (i, instance) in overlay_instances.iter().enumerate() {
self.bg_instances[base_overlay_index + i] = *instance;
}
self.queue.write_buffer(
&self.buffers.bg_instance_buffer,
(base_overlay_index * std::mem::size_of::<BackgroundInstance>()) as u64,
bytemuck::cast_slice(&overlay_instances),
);
let separator_base = self.grid.cols * self.grid.rows + CURSOR_OVERLAY_SLOTS;
let separator_instances = self.build_separator_instances();
for (i, instance) in separator_instances.iter().enumerate() {
if separator_base + i < self.buffers.max_bg_instances {
self.bg_instances[separator_base + i] = *instance;
}
}
let separator_byte_offset = separator_base * std::mem::size_of::<BackgroundInstance>();
let separator_byte_count =
separator_instances.len() * std::mem::size_of::<BackgroundInstance>();
if separator_byte_offset + separator_byte_count
<= self.buffers.max_bg_instances * std::mem::size_of::<BackgroundInstance>()
{
self.queue.write_buffer(
&self.buffers.bg_instance_buffer,
separator_byte_offset as u64,
bytemuck::cast_slice(&separator_instances),
);
}
let gutter_base = separator_base + self.grid.rows;
let gutter_instances = self.build_gutter_instances();
for (i, instance) in gutter_instances.iter().enumerate() {
if gutter_base + i < self.buffers.max_bg_instances {
self.bg_instances[gutter_base + i] = *instance;
}
}
let gutter_byte_offset = gutter_base * std::mem::size_of::<BackgroundInstance>();
let gutter_byte_count = gutter_instances.len() * std::mem::size_of::<BackgroundInstance>();
if gutter_byte_offset + gutter_byte_count
<= self.buffers.max_bg_instances * std::mem::size_of::<BackgroundInstance>()
{
self.queue.write_buffer(
&self.buffers.bg_instance_buffer,
gutter_byte_offset as u64,
bytemuck::cast_slice(&gutter_instances),
);
}
self.buffers.actual_bg_instances = self.grid.cols * self.grid.rows
+ CURSOR_OVERLAY_SLOTS
+ self.grid.rows
+ self.grid.rows;
self.buffers.actual_text_instances =
self.grid.cols * self.grid.rows * TEXT_INSTANCES_PER_CELL;
Ok(())
}
}