part way to multi grid rendering

macos-click-through
keith 4 years ago
parent 655339bbf8
commit 4ef6adcfef

721
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -33,6 +33,7 @@ cfg-if = "0.1.10"
which = "4"
dirs = "2"
rand = "0.7"
skia-safe = "0.32.1"
[dev-dependencies]
mockall = "0.7.0"

@ -160,6 +160,7 @@ async fn start_process(mut receiver: UnboundedReceiver<UiCommand>) {
.unwrap_or_explained_panic("Could not communicate with neovim process");
let mut options = UiAttachOptions::new();
options.set_linegrid_external(true);
options.set_multigrid_external(true);
options.set_rgb(true);
if let Err(command_error) = nvim.command("runtime! ginit.vim").await {
nvim.command(&format!(

@ -43,6 +43,8 @@ pub struct Cursor {
pub blinkoff: Option<u64>,
pub style: Option<Arc<Style>>,
pub enabled: bool,
pub double_width: bool,
pub character: String
}
impl Cursor {
@ -56,6 +58,8 @@ impl Cursor {
blinkon: None,
blinkoff: None,
enabled: true,
double_width: false,
character: " ".to_string()
}
}

@ -1,18 +1,18 @@
mod cursor;
mod grid;
mod style;
mod window;
use std::collections::HashMap;
use std::collections::{HashSet, HashMap};
use std::sync::Arc;
use log::trace;
use log::{trace, error};
use parking_lot::Mutex;
use skulpin::skia_safe::colors;
use unicode_segmentation::UnicodeSegmentation;
use crate::bridge::{EditorMode, GridLineCell, GuiOption, RedrawEvent};
use crate::bridge::{EditorMode, GuiOption, RedrawEvent, WindowAnchor};
use crate::redraw_scheduler::REDRAW_SCHEDULER;
use crate::window::window_geometry_or_default;
pub use window::*;
pub use cursor::{Cursor, CursorMode, CursorShape};
pub use grid::CharacterGrid;
pub use style::{Colors, Style};
@ -21,17 +21,25 @@ lazy_static! {
pub static ref EDITOR: Arc<Mutex<Editor>> = Arc::new(Mutex::new(Editor::new()));
}
#[derive(new, Debug, Clone)]
pub struct DrawCommand {
pub text: String,
pub cell_width: u64,
pub struct RenderInfo {
windows: Vec<WindowRenderInfo>,
closed_window_ids: Vec<u64>,
}
pub struct WindowRenderInfo {
pub grid_id: u64,
pub grid_position: (u64, u64),
pub style: Option<Arc<Style>>,
pub width: u64,
pub height: u64,
pub should_clear: bool,
pub draw_commands: Vec<DrawCommand>,
pub child_windows: Vec<WindowRenderInfo>
}
pub struct Editor {
pub grid: CharacterGrid,
pub title: String,
pub windows: HashMap<u64, Window>,
pub closed_window_ids: HashSet<u64>,
pub mouse_enabled: bool,
pub guifont: Option<String>,
pub cursor: Cursor,
@ -45,8 +53,9 @@ pub struct Editor {
impl Editor {
pub fn new() -> Editor {
Editor {
grid: CharacterGrid::new(window_geometry_or_default()),
title: "Neovide".to_string(),
windows: HashMap::new(),
closed_window_ids: HashSet::new(),
mouse_enabled: true,
guifont: None,
cursor: Cursor::new(),
@ -91,218 +100,180 @@ impl Editor {
trace!("Image flushed");
REDRAW_SCHEDULER.queue_next_frame();
}
RedrawEvent::Resize { width, height, .. } => self.grid.resize(width, height),
RedrawEvent::DefaultColorsSet { colors } => {
self.default_style = Arc::new(Style::new(colors))
}
RedrawEvent::HighlightAttributesDefine { id, style } => {
self.defined_styles.insert(id, Arc::new(style));
}
RedrawEvent::CursorGoto { grid, row, column } => self.set_cursor_position(grid, row, column),
RedrawEvent::Resize { grid, width, height } => {
self.windows.get_mut(&grid).map(|window| window.resize(width, height));
},
RedrawEvent::GridLine {
grid,
row,
column_start,
cells,
..
} => self.draw_grid_line(row, column_start, cells),
RedrawEvent::Clear { .. } => self.grid.clear(),
RedrawEvent::CursorGoto { row, column, .. } => self.cursor.position = (row, column),
cells
} => {
self.windows.get_mut(&grid).map(|window| window.draw_grid_line(row, column_start, cells, &self.defined_styles, &mut self.previous_style));
},
RedrawEvent::Clear { grid } => {
self.windows.get_mut(&grid).map(|window| window.grid.clear());
},
RedrawEvent::Scroll {
grid,
top,
bottom,
left,
right,
rows,
columns,
..
} => self.scroll_region(top, bottom, left, right, rows, columns),
columns
} => {
self.windows.get_mut(&grid).map(|window| window.scroll_region(top, bottom, left, right, rows, columns));
},
RedrawEvent::WindowPosition { grid, window, start_row, start_column, width, height } => self.set_window_position(grid, window, start_row, start_column, width, height),
RedrawEvent::WindowFloatPosition { grid, window, anchor, anchor_grid, anchor_row, anchor_column, .. } => self.set_window_float_position(grid, window, anchor_grid, anchor, anchor_row, anchor_column),
RedrawEvent::WindowHide { grid } => {
self.windows.get_mut(&grid).map(|window| window.hidden = true);
},
RedrawEvent::WindowClose { grid } => self.close_window(grid),
_ => {}
};
}
pub fn build_draw_commands(&mut self) -> (Vec<DrawCommand>, bool) {
let mut draw_commands = Vec::new();
for (row_index, row) in self.grid.rows().enumerate() {
let mut command = None;
fn add_command(commands_list: &mut Vec<DrawCommand>, command: Option<DrawCommand>) {
if let Some(command) = command {
commands_list.push(command);
}
}
fn close_window(&mut self, grid: u64) {
self.windows.remove(&grid);
self.closed_window_ids.insert(grid);
}
fn command_matches(command: &Option<DrawCommand>, style: &Option<Arc<Style>>) -> bool {
match command {
Some(command) => &command.style == style,
None => true,
}
fn set_window_position(&mut self, grid: u64, window_id: u64, start_row: u64, start_column: u64, width: u64, height: u64) {
match self.windows.get_mut(&grid) {
Some(window) => {
window.hidden = false;
window.anchor_grid_id = None;
window.anchor_type = WindowAnchor::NorthWest;
window.anchor_row = start_row;
window.anchor_column = start_column;
window.resize(width, height);
},
None => {
let new_window = Window::new(window_id, grid, width, height, None, WindowAnchor::NorthWest, start_row, start_column);
self.windows.insert(grid, new_window);
}
}
}
fn add_character(
command: &mut Option<DrawCommand>,
character: &str,
row_index: u64,
col_index: u64,
style: Option<Arc<Style>>,
) {
match command {
Some(command) => {
command.text.push_str(character);
command.cell_width += 1;
}
None => {
command.replace(DrawCommand::new(
character.to_string(),
1,
(col_index, row_index),
style,
));
}
}
}
fn set_window_float_position(&mut self, grid: u64, window_id: u64, anchor_grid: u64, anchor_type: WindowAnchor, anchor_row: u64, anchor_column: u64) {
if let Some(window) = self.windows.get_mut(&grid) {
window.hidden = false;
window.anchor_grid_id = Some(anchor_grid);
window.anchor_type = anchor_type;
window.anchor_row = anchor_row;
window.anchor_column = anchor_column;
} else {
error!("Attempted to float window that does not exist.");
}
for (col_index, cell) in row.iter().enumerate() {
if let Some((character, style)) = cell {
if character.is_empty() {
add_character(
&mut command,
&" ",
row_index as u64,
col_index as u64,
style.clone(),
);
add_command(&mut draw_commands, command);
command = None;
} else {
if !command_matches(&command, &style) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(
&mut command,
&character,
row_index as u64,
col_index as u64,
style.clone(),
);
}
} else {
if !command_matches(&command, &None) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(&mut command, " ", row_index as u64, col_index as u64, None);
}
}
add_command(&mut draw_commands, command);
if let Some(anchor_window) = self.windows.get_mut(&anchor_grid) {
anchor_window.children.insert(grid);
}
}
let should_clear = self.grid.should_clear;
let draw_commands = draw_commands
.into_iter()
.filter(|command| {
let (x, y) = command.grid_position;
let min = (x as i64 - 1).max(0) as u64;
let max = (x + command.cell_width + 1).min(self.grid.width);
fn get_window_top_left(&self, grid: u64) -> Option<(u64, u64)> {
let window = self.windows.get(&grid)?;
for char_index in min..max {
if self.grid.is_dirty_cell(char_index, y) {
return true;
}
match window.anchor_grid_id {
Some(anchor_grid) => {
let (parent_anchor_row, parent_anchor_column) = self.get_window_top_left(anchor_grid)?;
match window.anchor_type {
WindowAnchor::NorthWest => {
Some((parent_anchor_row + window.anchor_row, parent_anchor_column + window.anchor_column))
},
WindowAnchor::NorthEast => {
Some((parent_anchor_row + window.anchor_row, parent_anchor_column + window.anchor_column - window.grid.width))
},
WindowAnchor::SouthWest => {
Some((parent_anchor_row + window.anchor_row - window.grid.height, parent_anchor_column + window.anchor_column))
},
WindowAnchor::SouthEast => {
Some((parent_anchor_row + window.anchor_row - window.grid.height, parent_anchor_column + window.anchor_column - window.grid.width))
},
}
false
})
.collect::<Vec<DrawCommand>>();
self.grid.set_dirty_all(false);
self.grid.should_clear = false;
trace!("Draw commands sent");
(draw_commands, should_clear)
},
None => Some((window.anchor_row, window.anchor_column))
}
}
fn draw_grid_line_cell(&mut self, row_index: u64, column_pos: &mut u64, cell: GridLineCell) {
let style = match cell.highlight_id {
Some(0) => None,
Some(style_id) => self.defined_styles.get(&style_id).cloned(),
None => self.previous_style.clone(),
};
let mut text = cell.text;
if let Some(times) = cell.repeat {
text = text.repeat(times as usize);
}
fn set_cursor_position(&self, grid: u64, row: u64, column: u64) {
match self.get_window_top_left(grid) {
Some((window_row, window_column)) => {
self.cursor.position = (window_row + row, window_column + column);
if text.is_empty() {
if let Some(cell) = self.grid.get_cell_mut(*column_pos, row_index) {
*cell = Some(("".to_string(), style.clone()));
}
if let Some(window) = self.windows.get(&grid) {
self.cursor.character = match window.grid.get_cell(column, row) {
Some(Some((character, _))) => character.clone(),
_ => ' '.to_string(),
};
self.grid.set_dirty_cell(*column_pos, row_index);
*column_pos += 1;
} else {
for (i, character) in text.graphemes(true).enumerate() {
if let Some(cell) = self.grid.get_cell_mut(i as u64 + *column_pos, row_index) {
*cell = Some((character.to_string(), style.clone()));
self.grid.set_dirty_cell(*column_pos, row_index);
self.cursor.double_width = match window.grid.get_cell(column + 1, row) {
Some(Some((character, _))) => character.is_empty(),
_ => false,
};
}
},
None => {
self.cursor.position = (row, column);
self.cursor.double_width = false;
self.cursor.character = " ".to_string();
}
*column_pos += text.graphemes(true).count() as u64;
}
self.previous_style = style;
}
fn draw_grid_line(&mut self, row: u64, column_start: u64, cells: Vec<GridLineCell>) {
if row < self.grid.height {
let mut column_pos = column_start;
for cell in cells {
self.draw_grid_line_cell(row, &mut column_pos, cell);
}
} else {
println!("Draw command out of bounds");
fn set_option(&mut self, gui_option: GuiOption) {
trace!("Option set {:?}", &gui_option);
if let GuiOption::GuiFont(guifont) = gui_option {
self.guifont = Some(guifont);
}
}
fn scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64, rows: i64, cols: i64) {
let y_iter: Box<dyn Iterator<Item = i64>> = if rows > 0 {
Box::new((top as i64 + rows)..bot as i64)
} else {
Box::new((top as i64..(bot as i64 + rows)).rev())
fn build_window_render_info(&mut self, grid: u64) -> Option<WindowRenderInfo> {
let grid_position = self.get_window_top_left(grid)?;
let (draw_commands, should_clear) = {
let mut window = self.windows.get_mut(&grid)?;
window.build_draw_commands()
};
for y in y_iter {
let dest_y = y - rows;
if dest_y >= 0 && dest_y < self.grid.height as i64 {
let x_iter: Box<dyn Iterator<Item = i64>> = if cols > 0 {
Box::new((left as i64 + cols)..right as i64)
} else {
Box::new((left as i64..(right as i64 + cols)).rev())
};
let window = self.windows.get(&grid)?;
let child_windows = window.children.iter().filter_map(|child_id| self.build_window_render_info(*child_id)).collect();
for x in x_iter {
let dest_x = x - cols;
let cell_data = self.grid.get_cell(x as u64, y as u64).cloned();
Some(WindowRenderInfo {
grid_id: grid,
grid_position,
width: window.grid.width,
height: window.grid.height,
should_clear,
draw_commands,
child_windows
})
}
if let Some(cell_data) = cell_data {
if let Some(dest_cell) =
self.grid.get_cell_mut(dest_x as u64, dest_y as u64)
{
*dest_cell = cell_data;
self.grid.set_dirty_cell(dest_x as u64, dest_y as u64);
}
}
pub fn build_render_info(&mut self) -> RenderInfo {
let mut windows = Vec::new();
for window in self.windows.values() {
if !window.hidden && window.anchor_grid_id.is_none() {
if let Some(window_render_info) = self.build_window_render_info(window.grid_id) {
windows.push(window_render_info);
}
}
}
trace!("Region scrolled");
}
fn set_option(&mut self, gui_option: GuiOption) {
trace!("Option set {:?}", &gui_option);
if let GuiOption::GuiFont(guifont) = gui_option {
self.guifont = Some(guifont);
let closed_window_ids = self.closed_window_ids.iter().copied().collect();
self.closed_window_ids.clear();
RenderInfo {
windows, closed_window_ids
}
}
}

@ -0,0 +1,224 @@
use std::collections::{HashSet, HashMap};
use std::sync::Arc;
use log::trace;
use unicode_segmentation::UnicodeSegmentation;
use crate::bridge::{GridLineCell, WindowAnchor};
use super::grid::CharacterGrid;
use super::style::Style;
#[derive(new, Debug, Clone)]
pub struct DrawCommand {
pub text: String,
pub cell_width: u64,
pub grid_position: (u64, u64),
pub style: Option<Arc<Style>>,
}
pub struct Window {
pub id: u64,
pub grid_id: u64,
pub grid: CharacterGrid,
pub hidden: bool,
pub anchor_grid_id: Option<u64>,
pub anchor_type: WindowAnchor,
pub anchor_row: u64,
pub anchor_column: u64,
pub children: HashSet<u64>,
}
impl Window {
pub fn new(id: u64, grid_id: u64, width: u64, height: u64, anchor_grid_id: Option<u64>, anchor_type: WindowAnchor, anchor_row: u64, anchor_column: u64) -> Window {
Window {
id, grid_id, anchor_grid_id, anchor_type, anchor_row, anchor_column,
grid: CharacterGrid::new((width, height)),
hidden: false,
children: HashSet::new()
}
}
pub fn resize(&mut self, width: u64, height: u64) {
self.grid.resize(width, height);
}
fn draw_grid_line_cell(&mut self, row_index: u64, column_pos: &mut u64, cell: GridLineCell, defined_styles: &HashMap<u64, Arc<Style>>, previous_style: &mut Option<Arc<Style>>) {
let style = match cell.highlight_id {
Some(0) => None,
Some(style_id) => defined_styles.get(&style_id).cloned(),
None => previous_style.clone(),
};
let mut text = cell.text;
if let Some(times) = cell.repeat {
text = text.repeat(times as usize);
}
if text.is_empty() {
if let Some(cell) = self.grid.get_cell_mut(*column_pos, row_index) {
*cell = Some(("".to_string(), style.clone()));
}
self.grid.set_dirty_cell(*column_pos, row_index);
*column_pos += 1;
} else {
for (i, character) in text.graphemes(true).enumerate() {
if let Some(cell) = self.grid.get_cell_mut(i as u64 + *column_pos, row_index) {
*cell = Some((character.to_string(), style.clone()));
self.grid.set_dirty_cell(*column_pos, row_index);
}
}
*column_pos += text.graphemes(true).count() as u64;
}
*previous_style = style;
}
pub fn draw_grid_line(&mut self, row: u64, column_start: u64, cells: Vec<GridLineCell>, defined_styles: &HashMap<u64, Arc<Style>>, previous_style: &mut Option<Arc<Style>>) {
if row < self.grid.height {
let mut column_pos = column_start;
for cell in cells {
self.draw_grid_line_cell(row, &mut column_pos, cell, defined_styles, previous_style);
}
} else {
println!("Draw command out of bounds");
}
}
pub fn scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64, rows: i64, cols: i64) {
let y_iter: Box<dyn Iterator<Item = i64>> = if rows > 0 {
Box::new((top as i64 + rows)..bot as i64)
} else {
Box::new((top as i64..(bot as i64 + rows)).rev())
};
for y in y_iter {
let dest_y = y - rows;
if dest_y >= 0 && dest_y < self.grid.height as i64 {
let x_iter: Box<dyn Iterator<Item = i64>> = if cols > 0 {
Box::new((left as i64 + cols)..right as i64)
} else {
Box::new((left as i64..(right as i64 + cols)).rev())
};
for x in x_iter {
let dest_x = x - cols;
let cell_data = self.grid.get_cell(x as u64, y as u64).cloned();
if let Some(cell_data) = cell_data {
if let Some(dest_cell) =
self.grid.get_cell_mut(dest_x as u64, dest_y as u64)
{
*dest_cell = cell_data;
self.grid.set_dirty_cell(dest_x as u64, dest_y as u64);
}
}
}
}
}
trace!("Region scrolled");
}
pub fn build_draw_commands(&mut self) -> (Vec<DrawCommand>, bool) {
let mut draw_commands = Vec::new();
for (row_index, row) in self.grid.rows().enumerate() {
let mut command = None;
fn add_command(commands_list: &mut Vec<DrawCommand>, command: Option<DrawCommand>) {
if let Some(command) = command {
commands_list.push(command);
}
}
fn command_matches(command: &Option<DrawCommand>, style: &Option<Arc<Style>>) -> bool {
match command {
Some(command) => &command.style == style,
None => true,
}
}
fn add_character(
command: &mut Option<DrawCommand>,
character: &str,
row_index: u64,
col_index: u64,
style: Option<Arc<Style>>,
) {
match command {
Some(command) => {
command.text.push_str(character);
command.cell_width += 1;
}
None => {
command.replace(DrawCommand::new(
character.to_string(),
1,
(col_index, row_index),
style,
));
}
}
}
for (col_index, cell) in row.iter().enumerate() {
if let Some((character, style)) = cell {
if character.is_empty() {
add_character(
&mut command,
&" ",
row_index as u64,
col_index as u64,
style.clone(),
);
add_command(&mut draw_commands, command);
command = None;
} else {
if !command_matches(&command, &style) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(
&mut command,
&character,
row_index as u64,
col_index as u64,
style.clone(),
);
}
} else {
if !command_matches(&command, &None) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(&mut command, " ", row_index as u64, col_index as u64, None);
}
}
add_command(&mut draw_commands, command);
}
let should_clear = self.grid.should_clear;
let draw_commands = draw_commands
.into_iter()
.filter(|command| {
let (x, y) = command.grid_position;
let min = (x as i64 - 1).max(0) as u64;
let max = (x + command.cell_width + 1).min(self.grid.width);
for char_index in min..max {
if self.grid.is_dirty_cell(char_index, y) {
return true;
}
}
false
})
.collect::<Vec<DrawCommand>>();
self.grid.set_dirty_all(false);
self.grid.should_clear = false;
trace!("Draw commands sent");
(draw_commands, should_clear)
}
}

@ -276,26 +276,18 @@ impl CursorRenderer {
};
let (grid_x, grid_y) = self.previous_position;
let (character, font_dimensions, in_insert_mode): (String, Point, bool) = {
let editor = EDITOR.lock();
let character = match editor.grid.get_cell(grid_x, grid_y) {
Some(Some((character, _))) => character.clone(),
_ => ' '.to_string(),
};
let is_double = match editor.grid.get_cell(grid_x + 1, grid_y) {
Some(Some((character, _))) => character.is_empty(),
_ => false,
};
let character = cursor.text;
let font_width = match (is_double, &cursor.shape) {
(true, CursorShape::Block) => font_width * 2.0,
_ => font_width,
};
let font_width = match (cursor.double_width, &cursor.shape) {
(true, CursorShape::Block) => font_width * 2.0,
_ => font_width
};
let in_insert_mode = matches!(editor.current_mode, EditorMode::Insert);
let font_dimensions: Point = (font_width, font_height).into();
(character, (font_width, font_height).into(), in_insert_mode)
let in_insert_mode = {
let editor = EDITOR.lock();
matches!(editor.current_mode, EditorMode::Insert);
};
let destination: Point = (grid_x as f32 * font_width, grid_y as f32 * font_height).into();

@ -1,8 +1,9 @@
use std::collections::HashMap;
use std::sync::Arc;
use log::trace;
use skulpin::skia_safe::gpu::SurfaceOrigin;
use skulpin::skia_safe::{colors, dash_path_effect, Budgeted, Canvas, Paint, Rect, Surface};
use skulpin::skia_safe::{colors, dash_path_effect, Budgeted, Canvas, Paint, Rect, Surface, ImageInfo};
use skulpin::CoordinateSystemHelper;
mod caching_shaper;
@ -16,7 +17,7 @@ use crate::editor::{Style, EDITOR};
use cursor_renderer::CursorRenderer;
pub struct Renderer {
surface: Option<Surface>,
window_surfaces: HashMap<u64, Surface>,
paint: Paint,
shaper: CachingShaper,
@ -27,7 +28,6 @@ pub struct Renderer {
impl Renderer {
pub fn new() -> Renderer {
let surface = None;
let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false);
@ -37,7 +37,7 @@ impl Renderer {
let cursor_renderer = CursorRenderer::new();
Renderer {
surface,
window_surfaces: HashMap::new(),
paint,
shaper,
font_width,
@ -149,56 +149,47 @@ impl Renderer {
canvas.restore();
}
pub fn draw(
&mut self,
gpu_canvas: &mut Canvas,
coordinate_system_helper: &CoordinateSystemHelper,
dt: f32,
) -> bool {
trace!("Rendering");
pub fn build_window_surface(&self, gpu_canvas: &mut Canvas, default_style: &Arc<Style>, dimensions: (u64, u64)) -> Surface {
let mut context = gpu_canvas.gpu_context().unwrap();
let budgeted = Budgeted::YES;
let parent_image_info = gpu_canvas.image_info();
let image_info = ImageInfo::new(dimensions, parent_image_info.color_type(), parent_image_info.alpha_type(), parent_image_info.color_space());
let surface_origin = SurfaceOrigin::TopLeft;
let mut surface = Surface::new_render_target(
&mut context,
budgeted,
&image_info,
None,
surface_origin,
None,
None,
)
.expect("Could not create surface");
let canvas = surface.canvas();
canvas.clear(default_style.colors.background.clone().unwrap().to_color());
surface
}
let ((draw_commands, should_clear), default_style, cursor, guifont_setting) = {
let mut editor = EDITOR.lock();
(
editor.build_draw_commands(),
editor.default_style.clone(),
editor.cursor.clone(),
editor.guifont.clone(),
)
};
pub fn draw_window(&mut self, root_canvas: &mut Canvas, window_render_info: &WindowRenderInfo, coordinate_system_helper: &CoordinateSystemHelper, default_style: Arc<Style>) {
let image_width = (window_render_info.width * self.font_width) as i32;
let image_height = (window_render_info.height * self.font_height) as i32;
let font_changed = guifont_setting
.map(|guifont| self.update_font(&guifont))
.unwrap_or(false);
let mut surface_entry = self.window_surfaces.entry(&window_render_info.grid_id);
let build_surface = || build_window_surface(gpu_canvas, default_style, (image_width, image_height));
if should_clear {
self.surface = None;
if window_render_info.should_clear {
surface_entry = surface_entry.insert(build_surface());
}
let mut surface = self.surface.take().unwrap_or_else(|| {
let mut context = gpu_canvas.gpu_context().unwrap();
let budgeted = Budgeted::YES;
let image_info = gpu_canvas.image_info();
let surface_origin = SurfaceOrigin::TopLeft;
let mut surface = Surface::new_render_target(
&mut context,
budgeted,
&image_info,
None,
surface_origin,
None,
None,
)
.expect("Could not create surface");
let canvas = surface.canvas();
canvas.clear(default_style.colors.background.clone().unwrap().to_color());
surface
});
let surface = self.window_surfaces
.entry(&window_render_info.grid_id)
.or_insert_with(build_surface());
let mut canvas = surface.canvas();
coordinate_system_helper.use_logical_coordinates(&mut canvas);
for command in draw_commands.iter() {
for command in window_render_info.draw_commands.iter() {
self.draw_background(
&mut canvas,
command.grid_position,
@ -208,7 +199,7 @@ impl Renderer {
);
}
for command in draw_commands.iter() {
for command in window_render_info.draw_commands.iter() {
self.draw_foreground(
&mut canvas,
&command.text,
@ -220,15 +211,43 @@ impl Renderer {
}
let image = surface.image_snapshot();
let window_size = coordinate_system_helper.window_logical_size();
let (grid_left, grid_right) = window_render_info.grid_position;
let image_destination = Rect::new(
0.0,
0.0,
window_size.width as f32,
window_size.height as f32,
grid_left * self.font_width,
grid_height * self.font_height,
image_width as f32,
image_height as f32,
);
gpu_canvas.draw_image_rect(image, None, &image_destination, &self.paint);
root_canvas.draw_image_rect(image, None, &image_destination, &self.paint);
for child_window_render_info in window_render_info.child_windows.iter() {
self.draw_window(root_canvas, child_window_render_info, coordinate_system_helper, default_style);
}
}
pub fn draw(
&mut self,
gpu_canvas: &mut Canvas,
coordinate_system_helper: &CoordinateSystemHelper,
dt: f32,
) -> bool {
trace!("Rendering");
let (render_info, default_style, cursor, guifont_setting) = {
let mut editor = EDITOR.lock();
(
editor.build_render_info(),
editor.default_style.clone(),
editor.cursor.clone(),
editor.guifont.clone(),
)
};
let font_changed = guifont_setting
.map(|guifont| self.update_font(&guifont))
.unwrap_or(false);
self.surface = Some(surface);
self.cursor_renderer.draw(

Loading…
Cancel
Save