From 59601b7d71a127b1f8bc3fdf2ee86aaec64222bb Mon Sep 17 00:00:00 2001 From: keith Date: Fri, 27 Dec 2019 11:23:52 -0800 Subject: [PATCH] progress toward smeared cursor --- src/renderer/cursor_renderer.rs | 148 ++++++++++++++++++++------------ src/renderer/mod.rs | 59 ++++--------- 2 files changed, 107 insertions(+), 100 deletions(-) diff --git a/src/renderer/cursor_renderer.rs b/src/renderer/cursor_renderer.rs index dec579b..4f2340b 100644 --- a/src/renderer/cursor_renderer.rs +++ b/src/renderer/cursor_renderer.rs @@ -1,63 +1,46 @@ -use std::cmp::Ordering; +use std::sync::{Arc, Mutex}; -use skulpin::skia_safe::{Canvas, Point}; +use skulpin::skia_safe::{Canvas, Paint, Point}; +use skulpin::skia_safe::canvas::PointMode; -use crate::editor::Cursor; +use crate::renderer::{CachingShaper, FontLookup}; +use crate::editor::{Colors, Cursor, CursorShape, Editor}; -const motion_percentages: [f32; 4] = [0.4, 0.5, 0.6, 0.7]; +const average_motion_percentage: f32 = 0.5; +const motion_percentage_spread: f32 = 0.3; -#[derive(new, Eq, PartialEq, Clone)] -struct Corner { - pub x: f32, - pub y: f32, +const bar_width: f32 = 1.0 / 8.0; - pub center_x: f32, - pub center_y: f32, +const standard_corners: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)]; - pub position_x: f32, - pub position_y: f32 +#[derive(Debug, Clone)] +pub struct Corner { + pub current_position: Point, + pub relative_position: Point, } impl Corner { - pub fn new(position_x: f32, position_y: f32) -> Corner { + pub fn new(relative_position: Point) -> Corner { Corner { - x: 0, y: 0, - center_x: 0, center_y: 0, - position_x, position_y + current_position: Point::new(0.0, 0.0), + relative_position } } - pub fn remaining_distance(&self) -> f32 { - let dx = self.center_x - x; - let dy = self.center_y - y; + pub fn update(&mut self, font_dimensions: Point, destination: Point) -> bool { + let relative_scaled_position: Point = + (self.relative_position.x * font_dimensions.x, self.relative_position.y * font_dimensions.y).into(); + let corner_destination = destination + relative_scaled_position; - (dx * dx + dy * dy).sqrt() - } - - pub fn update(&mut self, motion_percentage: f32) { - let delta_x = self.dest_x - self.x; - let delta_y = self.dest_y - self.y; + let delta = corner_destination - self.current_position; - self.x += delta_x * motion_percentage; - self.y += delta_y * motion_percentage; - } -} - -impl Ord for Corner { - fn cmp(&self, other: &Self) -> Ordering { - self.remaining_distance().cmp(&other.remaining_distance()) - } -} + let motion_scale = delta.dot(relative_scaled_position) / delta.length() / font_dimensions.length(); + let motion_percentage = motion_scale * motion_percentage_spread + average_motion_percentage; -impl PartialOrd for Corner { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} + let delta = corner_destination - self.current_position; + self.current_position += delta * motion_percentage; -impl Into for Corner { - fn into(self) -> Point { - (self.x, self.y).into() + delta.length() > 0.001 } } @@ -67,24 +50,75 @@ pub struct CursorRenderer { impl CursorRenderer { pub fn new() -> CursorRenderer { - CursorRenderer { - corners: vec![Corner::new(-0.5, -0.5), Corner::new(0.5, -0.5), Corner::new(0.5, 0.5), Corner::new(-0.5, 0.5)] - } + let mut renderer = CursorRenderer { + corners: vec![Corner::new((0.0, 0.0).into()); 4] + }; + renderer.set_cursor_shape(CursorShape::Block); + renderer } - pub fn update(&mut self, destination: (u64, u64), font_width: f32, font_height: f32) { - let (grid_x, grid_y) = destination; - let mut center_x = grid_x as f32 * font_width + font_width / 2.0; - let mut center_y = grid_y as f32 * font_height + font_height / 2.0; + fn set_cursor_shape(&mut self, cursor_shape: CursorShape) { + self.corners = self.corners + .clone() + .into_iter().enumerate() + .map(|(i, corner)| { + let (x, y) = standard_corners[i]; + Corner { + relative_position: match cursor_shape { + CursorShape::Block => (x, y).into(), + CursorShape::Vertical => ((x + 0.5) * bar_width - 0.5, y).into(), + CursorShape::Horizontal => (x, (y + 0.5) * bar_width - 0.5).into() + }, + .. corner + } + }) + .collect::>(); + } - let mut corners: Vec<&mut Corner> = self.corners.iter_mut().collect(); - corners.sort(); - for (&mut corner, motion_percentage) in corners.iter().zip(motion_percentages.iter()) { - corner.update(motion_percentage); + pub fn draw(&mut self, + cursor: Cursor, default_colors: &Colors, + font_width: f32, font_height: f32, + paint: &mut Paint, editor: Arc>, + shaper: &mut CachingShaper, fonts_lookup: &mut FontLookup, + canvas: &mut Canvas) -> bool { + let (grid_x, grid_y) = cursor.position; + let font_dimensions: Point = (font_width, font_height).into(); + let center_destination: Point = ( + grid_x as f32 * (font_width * 1.5), + grid_y as f32 * (font_height * 1.5) + ).into(); + + let mut animating = false; + for corner in self.corners.iter_mut() { + let corner_animating = corner.update(font_dimensions, center_destination); + animating = animating || corner_animating; + } + + if cursor.enabled { + // Draw Background + paint.set_color(cursor.background(&default_colors).to_color()); + canvas.draw_points(PointMode::Polygon, &self.corners.iter().map(|corner| corner.current_position).collect::>(), &paint); + + let mut position_sum: Point = (0.0, 0.0).into(); + for i in 0..4 { + position_sum += self.corners[i].current_position; + } + let Point { x: cursor_x, y: cursor_y } = position_sum * (1.0 / 4.0); + + // Draw foreground + if let CursorShape::Block = cursor.shape { + let (cursor_grid_y, cursor_grid_x) = cursor.position; + paint.set_color(cursor.foreground(&default_colors).to_color()); + let editor = editor.lock().unwrap(); + let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone() + .map(|(character, _)| character) + .unwrap_or(' '); + canvas.draw_text_blob( + shaper.shape_cached(character.to_string(), &fonts_lookup.size(1).normal), + (cursor_x, cursor_y), &paint); + } } - } - pub fn draw(&self, &mut canvas: Canvas, paint: &Paint) { - canvas.draw_points(PointMode::Polygon, canvas.as_slice().map(|corner| corner.into::()).as_slice(), paint); + animating } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 56f1716..c118c9d 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -5,15 +5,17 @@ use skulpin::skia_safe::{Canvas, Paint, Surface, Budgeted, Rect, Typeface, Font, use skulpin::skia_safe::gpu::SurfaceOrigin; mod caching_shaper; +mod cursor_renderer; -use caching_shaper::CachingShaper; +pub use caching_shaper::CachingShaper; -use crate::editor::{Editor, CursorShape, Style, Colors}; +use cursor_renderer::CursorRenderer; +use crate::editor::{Editor, Style, Colors}; const FONT_NAME: &str = "Delugia Nerd Font"; const FONT_SIZE: f32 = 14.0; -struct Fonts { +pub struct Fonts { pub name: String, pub size: f32, pub normal: Font, @@ -52,7 +54,7 @@ impl Fonts { } } -struct FontLookup { +pub struct FontLookup { pub name: String, pub base_size: f32, pub loaded_fonts: HashMap @@ -92,7 +94,7 @@ pub struct Renderer { pub font_width: f32, pub font_height: f32, - cursor_pos: (f32, f32), + cursor_renderer: CursorRenderer, } impl Renderer { @@ -108,9 +110,9 @@ impl Renderer { let font_width = bounds.width(); let (_, metrics) = base_fonts.normal.metrics(); let font_height = metrics.descent - metrics.ascent; - let cursor_pos = (0.0, 0.0); + let cursor_renderer = CursorRenderer::new(); - Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_pos } + Renderer { editor, surface, paint, fonts_lookup, shaper, font_width, font_height, cursor_renderer } } fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), size: u16, style: &Option