Add a glow effect to the cyberpunk-splash line drawing #48
|
@ -143,6 +143,15 @@ impl SplashPrivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redraw_background(&self) {
|
fn redraw_background(&self) {
|
||||||
|
let pen = GlowPen::new(
|
||||||
|
*self.width.borrow(),
|
||||||
|
*self.height.borrow(),
|
||||||
|
2.,
|
||||||
|
8.,
|
||||||
|
8.,
|
||||||
|
(0.7, 0., 1.),
|
||||||
|
);
|
||||||
|
|
||||||
let background =
|
let background =
|
||||||
ImageSurface::create(Format::Rgb24, *self.width.borrow(), *self.height.borrow())
|
ImageSurface::create(Format::Rgb24, *self.width.borrow(), *self.height.borrow())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -152,55 +161,89 @@ impl SplashPrivate {
|
||||||
let _ = context.paint();
|
let _ = context.paint();
|
||||||
|
|
||||||
context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold);
|
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,
|
orientation: gtk::Orientation::Horizontal,
|
||||||
start_x: 20.,
|
start_x: 20.,
|
||||||
start_y: center_y - 20. - title_height / 2.,
|
start_y: extents.height() + 60.,
|
||||||
start_length,
|
start_length: extents.width(),
|
||||||
total_length: *self.width.borrow() as f64 - 120.,
|
height: extents.height() / 2.,
|
||||||
cutout_length: title_width,
|
total_length: extents.width() + extents.height() / 2.,
|
||||||
height: title_height,
|
|
||||||
invert: false,
|
invert: false,
|
||||||
};
|
}
|
||||||
|
.draw(&pen);
|
||||||
context.set_line_cap(LineCap::Round);
|
pen.stroke();
|
||||||
context.set_source_rgb(0.7, 0., 1.);
|
|
||||||
context.set_line_width(2.);
|
|
||||||
title_cutout.draw(&context);
|
|
||||||
let _ = context.stroke();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let title_baseline_x = center_x - title_width / 2.;
|
context.set_font_size(128.);
|
||||||
let title_baseline_y = center_y - 20.;
|
|
||||||
|
|
||||||
let gradient = LinearGradient::new(
|
let center_x = *self.width.borrow() as f64 / 2.;
|
||||||
title_baseline_x,
|
let center_y = *self.height.borrow() as f64 / 2.;
|
||||||
title_baseline_y - title_height,
|
|
||||||
title_baseline_x,
|
let title_extents = context.text_extents(&self.text.borrow()).unwrap();
|
||||||
title_baseline_y,
|
let title_width = title_extents.width();
|
||||||
);
|
let title_height = title_extents.height();
|
||||||
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 start_length = center_x - title_width / 2. - title_height - 20.;
|
||||||
let _ = context.set_source(gradient);
|
|
||||||
let _ = context.show_text(&self.text.borrow());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
context.set_source_rgb(0.7, 0., 1.);
|
|
||||||
AsymLine {
|
AsymLine {
|
||||||
orientation: gtk::Orientation::Horizontal,
|
orientation: gtk::Orientation::Horizontal,
|
||||||
start_x: 100.,
|
start_x: 100.,
|
||||||
|
@ -210,8 +253,8 @@ impl SplashPrivate {
|
||||||
total_length: 650.,
|
total_length: 650.,
|
||||||
invert: true,
|
invert: true,
|
||||||
}
|
}
|
||||||
.draw(&context);
|
.draw(&pen);
|
||||||
let _ = context.stroke();
|
pen.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -225,10 +268,14 @@ impl SplashPrivate {
|
||||||
total_length: 650.,
|
total_length: 650.,
|
||||||
invert: false,
|
invert: false,
|
||||||
}
|
}
|
||||||
.draw(&context);
|
.draw(&pen);
|
||||||
let _ = context.stroke();
|
pen.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tracery = pen.finish();
|
||||||
|
let _ = context.set_source(tracery);
|
||||||
|
let _ = context.paint();
|
||||||
|
|
||||||
let background = context.pop_group().unwrap();
|
let background = context.pop_group().unwrap();
|
||||||
|
|
||||||
*self.background.borrow_mut() = background;
|
*self.background.borrow_mut() = background;
|
||||||
|
@ -394,7 +441,7 @@ struct AsymLineCutout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsymLineCutout {
|
impl AsymLineCutout {
|
||||||
fn draw(&self, context: &Context) {
|
fn draw(&self, pen: &impl Pen) {
|
||||||
let dodge = if self.invert {
|
let dodge = if self.invert {
|
||||||
self.height
|
self.height
|
||||||
} else {
|
} else {
|
||||||
|
@ -402,17 +449,17 @@ impl AsymLineCutout {
|
||||||
};
|
};
|
||||||
match self.orientation {
|
match self.orientation {
|
||||||
gtk::Orientation::Horizontal => {
|
gtk::Orientation::Horizontal => {
|
||||||
context.move_to(self.start_x, self.start_y);
|
pen.move_to(self.start_x, self.start_y);
|
||||||
context.line_to(self.start_x + self.start_length, self.start_y);
|
pen.line_to(self.start_x + self.start_length, self.start_y);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x + self.start_length + self.height,
|
self.start_x + self.start_length + self.height,
|
||||||
self.start_y + dodge,
|
self.start_y + dodge,
|
||||||
);
|
);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x + self.start_length + self.height + self.cutout_length,
|
self.start_x + self.start_length + self.height + self.cutout_length,
|
||||||
self.start_y + dodge,
|
self.start_y + dodge,
|
||||||
);
|
);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x
|
self.start_x
|
||||||
+ self.start_length
|
+ self.start_length
|
||||||
+ self.height
|
+ self.height
|
||||||
|
@ -420,20 +467,20 @@ impl AsymLineCutout {
|
||||||
+ (self.height / 2.),
|
+ (self.height / 2.),
|
||||||
self.start_y + dodge / 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 => {
|
gtk::Orientation::Vertical => {
|
||||||
context.move_to(self.start_x, self.start_y);
|
pen.move_to(self.start_x, self.start_y);
|
||||||
context.line_to(self.start_x, self.start_y + self.start_length);
|
pen.line_to(self.start_x, self.start_y + self.start_length);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x + dodge,
|
self.start_x + dodge,
|
||||||
self.start_y + self.start_length + self.height,
|
self.start_y + self.start_length + self.height,
|
||||||
);
|
);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x + dodge,
|
self.start_x + dodge,
|
||||||
self.start_y + self.start_length + self.height + self.cutout_length,
|
self.start_y + self.start_length + self.height + self.cutout_length,
|
||||||
);
|
);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x + dodge / 2.,
|
self.start_x + dodge / 2.,
|
||||||
self.start_y
|
self.start_y
|
||||||
+ self.start_length
|
+ self.start_length
|
||||||
|
@ -441,7 +488,7 @@ impl AsymLineCutout {
|
||||||
+ self.cutout_length
|
+ self.cutout_length
|
||||||
+ (self.height / 2.),
|
+ (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"),
|
_ => panic!("unknown orientation"),
|
||||||
}
|
}
|
||||||
|
@ -459,7 +506,7 @@ struct AsymLine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsymLine {
|
impl AsymLine {
|
||||||
fn draw(&self, context: &Context) {
|
fn draw(&self, pen: &impl Pen) {
|
||||||
let dodge = if self.invert {
|
let dodge = if self.invert {
|
||||||
self.height
|
self.height
|
||||||
} else {
|
} else {
|
||||||
|
@ -467,13 +514,13 @@ impl AsymLine {
|
||||||
};
|
};
|
||||||
match self.orientation {
|
match self.orientation {
|
||||||
gtk::Orientation::Horizontal => {
|
gtk::Orientation::Horizontal => {
|
||||||
context.move_to(self.start_x, self.start_y);
|
pen.move_to(self.start_x, self.start_y);
|
||||||
context.line_to(self.start_x + self.start_length, self.start_y);
|
pen.line_to(self.start_x + self.start_length, self.start_y);
|
||||||
context.line_to(
|
pen.line_to(
|
||||||
self.start_x + self.start_length + self.height,
|
self.start_x + self.start_length + self.height,
|
||||||
self.start_y + dodge,
|
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 => {}
|
gtk::Orientation::Vertical => {}
|
||||||
_ => panic!("unknown orientation"),
|
_ => panic!("unknown orientation"),
|
||||||
|
@ -481,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 {
|
struct SlashMeter {
|
||||||
orientation: gtk::Orientation,
|
orientation: gtk::Orientation,
|
||||||
start_x: f64,
|
start_x: f64,
|
||||||
|
@ -551,6 +568,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() {
|
fn main() {
|
||||||
let app = gtk::Application::builder()
|
let app = gtk::Application::builder()
|
||||||
.application_id("com.luminescent-dreams.cyberpunk-splash")
|
.application_id("com.luminescent-dreams.cyberpunk-splash")
|
||||||
|
|
Loading…
Reference in New Issue