From dfe05f86ae497314a624ae945f020b889172778d Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Tue, 18 Apr 2023 09:33:45 -0400 Subject: [PATCH 1/2] 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") -- 2.44.1 From f419fb06eead2acab2a3ba3568b9afeb2110175d Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Tue, 18 Apr 2023 09:56:35 -0400 Subject: [PATCH 2/2] Add the CodingTogether hashtag --- cyberpunk-splash/src/main.rs | 130 +++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 61 deletions(-) diff --git a/cyberpunk-splash/src/main.rs b/cyberpunk-splash/src/main.rs index 6bc440d..0e188cb 100644 --- a/cyberpunk-splash/src/main.rs +++ b/cyberpunk-splash/src/main.rs @@ -161,48 +161,86 @@ impl SplashPrivate { let _ = context.paint(); context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold); - context.set_font_size(128.); - - let center_x = *self.width.borrow() as f64 / 2.; - let center_y = *self.height.borrow() as f64 / 2.; - - let title_extents = context.text_extents(&self.text.borrow()).unwrap(); - let title_width = title_extents.width(); - let title_height = title_extents.height(); { - let start_length = center_x - title_width / 2. - title_height - 20.; + context.set_source_rgb(0.7, 0., 1.); - let title_cutout = AsymLineCutout { + let hashtag = "#CodingTogether"; + context.set_font_size(64.); + let extents = context.text_extents(hashtag).unwrap(); + + context.move_to(20., extents.height() + 40.); + let _ = context.show_text(hashtag); + + AsymLine { + orientation: gtk::Orientation::Horizontal, + start_x: 10., + start_y: extents.height() + 10., + start_length: 0., + height: extents.height() / 2., + total_length: extents.width() + extents.height() / 2., + invert: false, + } + .draw(&pen); + pen.stroke(); + + AsymLine { orientation: gtk::Orientation::Horizontal, start_x: 20., - start_y: center_y - 20. - title_height / 2., - start_length, - total_length: *self.width.borrow() as f64 - 120., - cutout_length: title_width, - height: title_height, + start_y: extents.height() + 60., + start_length: extents.width(), + height: extents.height() / 2., + total_length: extents.width() + extents.height() / 2., invert: false, - }; - - title_cutout.draw(&pen); + } + .draw(&pen); pen.stroke(); } { - let title_baseline_x = center_x - title_width / 2.; - let title_baseline_y = center_y - 20.; + context.set_font_size(128.); - let gradient = LinearGradient::new( - title_baseline_x, - title_baseline_y - title_height, - title_baseline_x, - title_baseline_y, - ); - gradient.add_color_stop_rgb(0.2, 0.7, 0.0, 1.0); - gradient.add_color_stop_rgb(0.8, 0.2, 0.0, 1.0); - context.move_to(title_baseline_x, title_baseline_y); - let _ = context.set_source(gradient); - let _ = context.show_text(&self.text.borrow()); + let center_x = *self.width.borrow() as f64 / 2.; + let center_y = *self.height.borrow() as f64 / 2.; + + let title_extents = context.text_extents(&self.text.borrow()).unwrap(); + let title_width = title_extents.width(); + let title_height = title_extents.height(); + + { + let start_length = center_x - title_width / 2. - title_height - 20.; + + let title_cutout = AsymLineCutout { + orientation: gtk::Orientation::Horizontal, + start_x: 20., + start_y: center_y - 20. - title_height / 2., + start_length, + total_length: *self.width.borrow() as f64 - 120., + cutout_length: title_width, + height: title_height, + invert: false, + }; + + title_cutout.draw(&pen); + pen.stroke(); + } + + { + let title_baseline_x = center_x - title_width / 2.; + let title_baseline_y = center_y - 20.; + + let gradient = LinearGradient::new( + title_baseline_x, + title_baseline_y - title_height, + title_baseline_x, + title_baseline_y, + ); + gradient.add_color_stop_rgb(0.2, 0.7, 0.0, 1.0); + gradient.add_color_stop_rgb(0.8, 0.2, 0.0, 1.0); + context.move_to(title_baseline_x, title_baseline_y); + let _ = context.set_source(gradient); + let _ = context.show_text(&self.text.borrow()); + } } { @@ -490,36 +528,6 @@ impl AsymLine { } } -struct RoundedRectangle { - x: f64, - y: f64, - width: f64, - height: f64, -} - -impl RoundedRectangle { - fn draw(&self, context: &Context) { - context.arc( - self.x, - self.y - self.height / 2., - self.height / 2., - 0.5 * std::f64::consts::PI, - 1.5 * std::f64::consts::PI, - ); - let _ = context.fill(); - context.arc( - self.x + self.width, - self.y - self.height / 2., - self.height / 2., - 1.5 * std::f64::consts::PI, - 0.5 * std::f64::consts::PI, - ); - let _ = context.fill(); - context.rectangle(self.x, self.y, self.width, -self.height); - let _ = context.fill(); - } -} - struct SlashMeter { orientation: gtk::Orientation, start_x: f64, -- 2.44.1