From dfe05f86ae497314a624ae945f020b889172778d Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Tue, 18 Apr 2023 09:33:45 -0400 Subject: [PATCH] Add a pen which paints glow effects --- cyberpunk-splash/src/main.rs | 139 ++++++++++++++++++++++++++++------- 1 file changed, 111 insertions(+), 28 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 3d84c9d..6bc440d 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -143,6 +143,15 @@ impl SplashPrivate { } fn redraw_background(&self) { + let pen = GlowPen::new( + *self.width.borrow(), + *self.height.borrow(), + 2., + 8., + 8., + (0.7, 0., 1.), + ); + let background = ImageSurface::create(Format::Rgb24, *self.width.borrow(), *self.height.borrow()) .unwrap(); @@ -175,11 +184,8 @@ impl SplashPrivate { invert: false, }; - context.set_line_cap(LineCap::Round); - context.set_source_rgb(0.7, 0., 1.); - context.set_line_width(2.); - title_cutout.draw(&context); - let _ = context.stroke(); + title_cutout.draw(&pen); + pen.stroke(); } { @@ -200,7 +206,6 @@ impl SplashPrivate { } { - context.set_source_rgb(0.7, 0., 1.); AsymLine { orientation: gtk::Orientation::Horizontal, start_x: 100., @@ -210,8 +215,8 @@ impl SplashPrivate { total_length: 650., invert: true, } - .draw(&context); - let _ = context.stroke(); + .draw(&pen); + pen.stroke(); } { @@ -225,10 +230,14 @@ impl SplashPrivate { total_length: 650., invert: false, } - .draw(&context); - let _ = context.stroke(); + .draw(&pen); + pen.stroke(); } + let tracery = pen.finish(); + let _ = context.set_source(tracery); + let _ = context.paint(); + let background = context.pop_group().unwrap(); *self.background.borrow_mut() = background; @@ -394,7 +403,7 @@ struct AsymLineCutout { } impl AsymLineCutout { - fn draw(&self, context: &Context) { + fn draw(&self, pen: &impl Pen) { let dodge = if self.invert { self.height } else { @@ -402,17 +411,17 @@ impl AsymLineCutout { }; match self.orientation { gtk::Orientation::Horizontal => { - context.move_to(self.start_x, self.start_y); - context.line_to(self.start_x + self.start_length, self.start_y); - context.line_to( + pen.move_to(self.start_x, self.start_y); + pen.line_to(self.start_x + self.start_length, self.start_y); + pen.line_to( self.start_x + self.start_length + self.height, self.start_y + dodge, ); - context.line_to( + pen.line_to( self.start_x + self.start_length + self.height + self.cutout_length, self.start_y + dodge, ); - context.line_to( + pen.line_to( self.start_x + self.start_length + self.height @@ -420,20 +429,20 @@ impl AsymLineCutout { + (self.height / 2.), self.start_y + dodge / 2., ); - context.line_to(self.total_length, self.start_y + dodge / 2.); + pen.line_to(self.total_length, self.start_y + dodge / 2.); } gtk::Orientation::Vertical => { - context.move_to(self.start_x, self.start_y); - context.line_to(self.start_x, self.start_y + self.start_length); - context.line_to( + pen.move_to(self.start_x, self.start_y); + pen.line_to(self.start_x, self.start_y + self.start_length); + pen.line_to( self.start_x + dodge, self.start_y + self.start_length + self.height, ); - context.line_to( + pen.line_to( self.start_x + dodge, self.start_y + self.start_length + self.height + self.cutout_length, ); - context.line_to( + pen.line_to( self.start_x + dodge / 2., self.start_y + self.start_length @@ -441,7 +450,7 @@ impl AsymLineCutout { + self.cutout_length + (self.height / 2.), ); - context.line_to(self.start_x + dodge / 2., self.total_length); + pen.line_to(self.start_x + dodge / 2., self.total_length); } _ => panic!("unknown orientation"), } @@ -459,7 +468,7 @@ struct AsymLine { } impl AsymLine { - fn draw(&self, context: &Context) { + fn draw(&self, pen: &impl Pen) { let dodge = if self.invert { self.height } else { @@ -467,13 +476,13 @@ impl AsymLine { }; match self.orientation { gtk::Orientation::Horizontal => { - context.move_to(self.start_x, self.start_y); - context.line_to(self.start_x + self.start_length, self.start_y); - context.line_to( + pen.move_to(self.start_x, self.start_y); + pen.line_to(self.start_x + self.start_length, self.start_y); + pen.line_to( self.start_x + self.start_length + self.height, self.start_y + dodge, ); - context.line_to(self.start_x + self.total_length, self.start_y + dodge); + pen.line_to(self.start_x + self.total_length, self.start_y + dodge); } gtk::Orientation::Vertical => {} _ => panic!("unknown orientation"), @@ -551,6 +560,80 @@ impl SlashMeter { } } +trait Pen { + fn move_to(&self, x: f64, y: f64); + fn line_to(&self, x: f64, y: f64); + fn stroke(&self); + + fn finish(self) -> Pattern; +} + +struct GlowPen { + blur_context: Context, + draw_context: Context, + + line_width: f64, + blur_line_width: f64, + blur_size: f64, +} + +impl GlowPen { + fn new( + width: i32, + height: i32, + line_width: f64, + blur_line_width: f64, + blur_size: f64, + color: (f64, f64, f64), + ) -> Self { + let blur_context = + Context::new(ImageSurface::create(Format::Rgb24, width, height).unwrap()).unwrap(); + blur_context.set_line_width(blur_line_width); + blur_context.set_source_rgba(color.0, color.1, color.2, 0.5); + blur_context.push_group(); + blur_context.set_line_cap(LineCap::Round); + + let draw_context = + Context::new(ImageSurface::create(Format::Rgb24, width, height).unwrap()).unwrap(); + draw_context.set_line_width(line_width); + draw_context.set_source_rgb(color.0, color.1, color.2); + draw_context.push_group(); + draw_context.set_line_cap(LineCap::Round); + + Self { + blur_context, + draw_context, + line_width, + blur_line_width, + blur_size, + } + } +} + +impl Pen for GlowPen { + fn move_to(&self, x: f64, y: f64) { + self.blur_context.move_to(x, y); + self.draw_context.move_to(x, y); + } + + fn line_to(&self, x: f64, y: f64) { + self.blur_context.line_to(x, y); + self.draw_context.line_to(x, y); + } + + fn stroke(&self) { + self.blur_context.stroke(); + self.draw_context.stroke(); + } + + fn finish(self) -> Pattern { + let foreground = self.draw_context.pop_group().unwrap(); + self.blur_context.set_source(foreground).unwrap(); + self.blur_context.paint().unwrap(); + self.blur_context.pop_group().unwrap() + } +} + fn main() { let app = gtk::Application::builder() .application_id("com.luminescent-dreams.cyberpunk-splash")