From 47eaf0c418e95318d999ac1ef8ea1b4b1dddd6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Vald=C3=A9s?= Date: Tue, 25 Feb 2020 23:15:04 +0100 Subject: [PATCH] Implemented settings-based control for cursor animations --- src/main.rs | 1 + src/renderer/cursor_renderer/cursor_vfx.rs | 69 +++++++++++++++++++--- src/renderer/cursor_renderer/mod.rs | 61 +++++++++++++++---- src/renderer/mod.rs | 2 +- src/settings.rs | 2 +- 5 files changed, 114 insertions(+), 21 deletions(-) diff --git a/src/main.rs b/src/main.rs index bcfa176..d65246a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50); fn main() { window::initialize_settings(); redraw_scheduler::initialize_settings(); + renderer::cursor_renderer::initialize_settings(); initialize(&BRIDGE); ui_loop(); diff --git a/src/renderer/cursor_renderer/cursor_vfx.rs b/src/renderer/cursor_renderer/cursor_vfx.rs index 9b52685..e4ae3c3 100644 --- a/src/renderer/cursor_renderer/cursor_vfx.rs +++ b/src/renderer/cursor_renderer/cursor_vfx.rs @@ -1,21 +1,76 @@ use skulpin::skia_safe::{paint::Style, BlendMode, Canvas, Color, Paint, Point, Rect}; +use log::error; use super::animation_utils::*; use crate::editor::{Colors, Cursor}; +use crate::settings::*; -pub trait CursorVFX { +pub trait CursorVfx { fn update(&mut self, current_cursor_destination: Point, dt: f32) -> bool; fn restart(&mut self, position: Point); fn render(&self, canvas: &mut Canvas, cursor: &Cursor, colors: &Colors, font_size: (f32, f32)); } -#[allow(dead_code)] +#[derive(Clone, PartialEq)] pub enum HighlightMode { SonicBoom, Ripple, Wireframe, } +#[derive(Clone, PartialEq)] +pub enum TrailMode { + Railgun, +} + +#[derive(Clone, PartialEq)] +pub enum VfxMode { + Highlight(HighlightMode), + Trail(TrailMode), + Disabled, +} + +impl FromValue for VfxMode { + fn from_value(&mut self, value: Value) { + if value.is_str() { + *self = match value.as_str().unwrap() { + "sonicboom" => VfxMode::Highlight(HighlightMode::SonicBoom), + "ripple" => VfxMode::Highlight(HighlightMode::Ripple), + "wireframe" => VfxMode::Highlight(HighlightMode::Wireframe), + "railgun" => VfxMode::Trail(TrailMode::Railgun), + "" => VfxMode::Disabled, + value => { + error!("Expected a VfxMode name, but received {:?}", value); + return; + } + }; + + }else{ + error!("Expected a VfxMode string, but received {:?}", value); + } + } +} + +impl From for Value { + fn from(mode: VfxMode) -> Self { + match mode { + VfxMode::Highlight(HighlightMode::SonicBoom) => Value::from("sonicboom"), + VfxMode::Highlight(HighlightMode::Ripple) => Value::from("ripple"), + VfxMode::Highlight(HighlightMode::Wireframe) => Value::from("wireframe"), + VfxMode::Trail(TrailMode::Railgun) => Value::from("railgun"), + VfxMode::Disabled => Value::from(""), + } + } +} + +pub fn new_cursor_vfx(mode: &VfxMode) -> Option> { + match mode { + VfxMode::Highlight(mode) => Some(Box::new(PointHighlight::new(mode))), + VfxMode::Trail(_) => Some(Box::new(ParticleTrail::new())), + VfxMode::Disabled => None, + } +} + pub struct PointHighlight { t: f32, center_position: Point, @@ -23,16 +78,16 @@ pub struct PointHighlight { } impl PointHighlight { - pub fn new(center: Point, mode: HighlightMode) -> PointHighlight { + pub fn new(mode: &HighlightMode) -> PointHighlight { PointHighlight { t: 0.0, - center_position: center, - mode, + center_position: Point::new(0.0, 0.0), + mode: mode.clone(), } } } -impl CursorVFX for PointHighlight { +impl CursorVfx for PointHighlight { fn update(&mut self, _current_cursor_destination: Point, dt: f32) -> bool { self.t = (self.t + dt * 5.0).min(1.0); // TODO - speed config self.t < 1.0 @@ -121,7 +176,7 @@ impl ParticleTrail { const PARTICLE_DENSITY: f32 = 0.008; const PARTICLE_LIFETIME: f32 = 1.2; -impl CursorVFX for ParticleTrail { +impl CursorVfx for ParticleTrail { fn update(&mut self, current_cursor_dest: Point, dt: f32) -> bool { // Update lifetimes and remove dead particles let mut i = 0; diff --git a/src/renderer/cursor_renderer/mod.rs b/src/renderer/cursor_renderer/mod.rs index db52bef..e6ebcbe 100644 --- a/src/renderer/cursor_renderer/mod.rs +++ b/src/renderer/cursor_renderer/mod.rs @@ -2,7 +2,7 @@ use std::time::{Duration, Instant}; use skulpin::skia_safe::{Canvas, Paint, Path, Point}; -use crate::settings::SETTINGS; +use crate::settings::*; use crate::renderer::CachingShaper; use crate::editor::{EDITOR, Colors, Cursor, CursorShape}; use crate::redraw_scheduler::REDRAW_SCHEDULER; @@ -11,15 +11,32 @@ mod animation_utils; use animation_utils::*; mod cursor_vfx; -use cursor_vfx::*; -const BASE_ANIMATION_LENGTH_SECONDS: f32 = 0.06; const CURSOR_TRAIL_SIZE: f32 = 0.7; const COMMAND_LINE_DELAY_FRAMES: u64 = 5; const DEFAULT_CELL_PERCENTAGE: f32 = 1.0 / 8.0; const STANDARD_CORNERS: &[(f32, f32); 4] = &[(-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5)]; + +#[derive(Clone)] +pub struct CursorSettings { + animation_length: f32, + vfx_mode: cursor_vfx::VfxMode, +} + +pub fn initialize_settings() { + + SETTINGS.set(&CursorSettings { + animation_length: 0.06, + vfx_mode: cursor_vfx::VfxMode::Disabled, + }); + + register_nvim_setting!("cursor_animation_length", CursorSettings::animation_length); + register_nvim_setting!("cursor_vfx_mode", CursorSettings::vfx_mode); +} + + enum BlinkState { Waiting, On, @@ -110,7 +127,7 @@ impl Corner { } } - pub fn update(&mut self, font_dimensions: Point, destination: Point, dt: f32) -> bool { + pub fn update(&mut self, settings: &CursorSettings, font_dimensions: Point, destination: Point, dt: f32) -> bool { // Update destination if needed let mut immediate_movement = false; if destination != self.previous_destination { @@ -170,7 +187,7 @@ impl Corner { self.t = 2.0; } else { let corner_dt = dt * lerp(1.0, 1.0 - CURSOR_TRAIL_SIZE, -direction_alignment); - self.t = (self.t + corner_dt / BASE_ANIMATION_LENGTH_SECONDS).min(1.0) + self.t = (self.t + corner_dt / settings.animation_length).min(1.0) } true @@ -183,7 +200,8 @@ pub struct CursorRenderer { pub command_line_delay: u64, blink_status: BlinkStatus, previous_cursor_shape: Option, - cursor_vfx: Box, + cursor_vfx: Option>, + previous_vfx_mode: cursor_vfx::VfxMode, } impl CursorRenderer { @@ -195,7 +213,8 @@ impl CursorRenderer { blink_status: BlinkStatus::new(), previous_cursor_shape: None, //cursor_vfx: Box::new(PointHighlight::new(Point{x:0.0, y:0.0}, HighlightMode::Ripple)), - cursor_vfx: Box::new(ParticleTrail::new()), + cursor_vfx: None, + previous_vfx_mode: cursor_vfx::VfxMode::Disabled, }; renderer.set_cursor_shape(&CursorShape::Block, DEFAULT_CELL_PERCENTAGE); renderer @@ -234,6 +253,13 @@ impl CursorRenderer { dt: f32) { let render = self.blink_status.update_status(&cursor); + let settings = SETTINGS.get::(); + + if settings.vfx_mode != self.previous_vfx_mode { + self.cursor_vfx = cursor_vfx::new_cursor_vfx(&settings.vfx_mode); + self.previous_vfx_mode = settings.vfx_mode.clone(); + } + let mut paint = Paint::new(skulpin::skia_safe::colors::WHITE, None); paint.set_anti_alias(true); @@ -284,17 +310,25 @@ impl CursorRenderer { if self.previous_cursor_shape != new_cursor { self.previous_cursor_shape = new_cursor; self.set_cursor_shape(&cursor.shape, cursor.cell_percentage.unwrap_or(DEFAULT_CELL_PERCENTAGE)); - - self.cursor_vfx.restart(center_destination); + + if let Some(vfx) = self.cursor_vfx.as_mut() { + vfx.restart(center_destination); + } } let mut animating = false; if !center_destination.is_zero() { for corner in self.corners.iter_mut() { - let corner_animating = corner.update(font_dimensions, center_destination, dt); + let corner_animating = corner.update(&settings, font_dimensions, center_destination, dt); animating |= corner_animating; } - let vfx_animating = self.cursor_vfx.update(center_destination, dt); + + let vfx_animating = if let Some(vfx) = self.cursor_vfx.as_mut() { + vfx.update(center_destination, dt) + }else{ + false + }; + animating |= vfx_animating; } @@ -326,7 +360,10 @@ impl CursorRenderer { canvas.draw_text_blob(&blob, destination, &paint); } canvas.restore(); - self.cursor_vfx.render(canvas, &cursor, &default_colors, (font_width, font_height)); + if let Some(vfx) = self.cursor_vfx.as_ref() { + vfx.render(canvas, &cursor, &default_colors, (font_width, font_height)); + } + } } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 8c82191..d11a254 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -6,7 +6,7 @@ use skulpin::skia_safe::gpu::SurfaceOrigin; use log::trace; mod caching_shaper; -mod cursor_renderer; +pub mod cursor_renderer; pub use caching_shaper::CachingShaper; diff --git a/src/settings.rs b/src/settings.rs index 7162f02..467ad57 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -26,7 +26,7 @@ pub trait FromValue { // FromValue implementations for most typical types impl FromValue for f32 { fn from_value(&mut self, value: Value) { - if value.is_f32() { + if value.is_f64() { *self = value.as_f64().unwrap() as f32; }else{ error!("Setting expected an f32, but received {:?}", value);