diff --git a/cfg/software_as_a_bit.toml b/cfg/software_as_a_bit.toml index 1cb3f75..bcddcf0 100644 --- a/cfg/software_as_a_bit.toml +++ b/cfg/software_as_a_bit.toml @@ -93,3 +93,11 @@ until then force attention to zero. goodbye amigo sorry for the slime. """ +[[slides]] +type = "CreativeDemo" +title = "Software as a Bit" + +[[slides]] +type = "CreativeDemo" +title = "Software as a Creative Outlet" + diff --git a/fonts/droid-sans-mono.regular.ttf b/fonts/droid-sans-mono.regular.ttf new file mode 100644 index 0000000..d604425 Binary files /dev/null and b/fonts/droid-sans-mono.regular.ttf differ diff --git a/src/main.rs b/src/main.rs index dc80373..fe0474b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,9 @@ async fn main() { let args = Args::parse(); let heading = load_ttf_font("fonts/BoldPixels.ttf").await.unwrap(); - let body = load_ttf_font("fonts/ByteBounce.ttf").await.unwrap(); + let body = load_ttf_font("fonts/droid-sans-mono.regular.ttf") + .await + .unwrap(); let slide_show_theme = SlideShowTheme { title_config: TextConfigBuilder::default() @@ -57,7 +59,7 @@ async fn main() { body_config: TextConfigBuilder::default() .justification(Justified::Left) .font(&body) - .font_size(100) + .font_size(60) .color(WHITE) .build(), }; diff --git a/src/slides/config.rs b/src/slides/config.rs index 05a214d..ae9652a 100644 --- a/src/slides/config.rs +++ b/src/slides/config.rs @@ -1,4 +1,5 @@ use crate::slide::Slide; +use crate::slides::creative_demo::{CreativeDemo, CreativeDemoCfg}; use crate::slides::demo::Demo; use crate::slides::projects::Projects; use crate::slides::standard_slide::{StandardSlide, StandardSlideConfig}; @@ -14,6 +15,7 @@ pub enum SlideType { Demo, Projects, StandardSlide(StandardSlideConfig), + CreativeDemo(CreativeDemoCfg), } impl SlideType { @@ -23,6 +25,7 @@ impl SlideType { SlideType::Demo => Demo::new(), SlideType::Projects => Projects::new(), SlideType::StandardSlide(cfg) => StandardSlide::new(cfg, asset_dir).await, + SlideType::CreativeDemo(cfg) => CreativeDemo::new(cfg), } } } diff --git a/src/slides/creative_demo.rs b/src/slides/creative_demo.rs new file mode 100644 index 0000000..194b7b4 --- /dev/null +++ b/src/slides/creative_demo.rs @@ -0,0 +1,96 @@ +use crate::effects::star_field; +use crate::slide::Slide; +use crate::slide_show_config::Context; +use crate::utils::{draw_text_with_background, screen_center}; +use macroquad::color::{BLACK, Color, ORANGE, VIOLET}; +use macroquad::math::Vec2; +use macroquad::prelude::{ + BLUE, GREEN, RED, YELLOW, clear_background, +}; +use macroquad::time::get_time; +use macroquad::window::{screen_height, screen_width}; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct CreativeDemoCfg { + pub title: String, +} + +#[derive(Debug)] +pub struct CreativeDemo { + cfg: CreativeDemoCfg, + animation_state: usize, + last_update: f64, + first_display: bool, +} + +impl CreativeDemo { + pub fn new(cfg: CreativeDemoCfg) -> Box { + Box::new(Self { + cfg, + animation_state: 0, + last_update: 0.0, + first_display: false, + }) + } +} + +impl Slide for CreativeDemo { + fn display(&mut self, ctx: &Context<'_>) { + if self.first_display { + self.first_display = true; + self.last_update = get_time(); + } + clear_background(BLACK); + star_field(); + + let rainbow = [ + RED, + ORANGE, + YELLOW, + GREEN, + BLUE, + Color::from_hex(0x4B0082), + VIOLET, + ]; + let mid_point = rainbow.len() / 2; + + for ndx in (0..=self.animation_state).rev() { + if ndx == 0 { + let bg_color = rainbow[mid_point].with_alpha(0.8); + draw_text_with_background( + &self.cfg.title, + screen_center(), + &ctx.slide_show_theme.heading_config, + rainbow[mid_point], + bg_color, + ); + } else { + let offset = Vec2::new(screen_width(), -screen_height()) * 0.05 * ndx as f32; + + let ne_bg_color = rainbow[mid_point + ndx].with_alpha(0.8); + draw_text_with_background( + &self.cfg.title, + screen_center() + offset, + &ctx.slide_show_theme.heading_config, + rainbow[mid_point - ndx], + ne_bg_color, + ); + + let sw_bg_color = rainbow[mid_point - ndx].with_alpha(0.8); + draw_text_with_background( + &self.cfg.title, + screen_center() - offset, + &ctx.slide_show_theme.heading_config, + rainbow[mid_point + ndx], + sw_bg_color, + ); + } + } + + if get_time() - self.last_update > 0.5 { + self.animation_state = (self.animation_state + 1) % (mid_point + 1); + self.last_update = get_time(); + } + } +} diff --git a/src/slides/mod.rs b/src/slides/mod.rs index f927614..2762e40 100644 --- a/src/slides/mod.rs +++ b/src/slides/mod.rs @@ -5,6 +5,7 @@ use macroquad::camera::set_default_camera; use macroquad::input::{KeyCode, is_key_pressed}; pub mod config; +pub mod creative_demo; pub mod demo; pub mod projects; pub mod standard_slide; diff --git a/src/slides/standard_slide.rs b/src/slides/standard_slide.rs index fc311b7..b2c196d 100644 --- a/src/slides/standard_slide.rs +++ b/src/slides/standard_slide.rs @@ -87,12 +87,12 @@ impl Slide for StandardSlide { let body_pos = Vec2::new( screen_width() * 0.05, - screen_height() * 0.33 + info.text_dimensions.height, + screen_height() * 0.25 + info.text_dimensions.height, ); ctx.slide_show_theme.body_config.draw_text_box( &self.cfg.body, body_pos, - Vec2::new(screen_width() * 0.5, screen_height() * 0.8), + Vec2::new(screen_width() * 0.55, screen_height() * 0.8), ); if let Some(image) = &self.image { diff --git a/src/slides/title.rs b/src/slides/title.rs index 8553a3d..bc02f4e 100644 --- a/src/slides/title.rs +++ b/src/slides/title.rs @@ -2,6 +2,7 @@ use crate::effects::star_field; use crate::slide::Slide; use crate::slide_show_config::Context; use crate::text_drawer::TextConfigBuilder; +use crate::utils::draw_text_with_background; use macroquad::color::{BLACK, DARKGREEN, LIME}; use macroquad::math::Vec2; use macroquad::miniquad::window::screen_size; @@ -24,15 +25,15 @@ impl Slide for Title { fn display(&mut self, ctx: &Context<'_>) { clear_background(BLACK); star_field(); - - let title_builder: TextConfigBuilder = ctx.slide_show_theme.title_config.clone().into(); - let shadow_style = title_builder.clone().color(DARKGREEN).build(); - let title_style = title_builder.color(LIME).build(); - let center = Vec2::from(screen_size()) * 0.5; - let center_offset = center + Vec2::from(screen_size()) * 0.005; - shadow_style.draw_text(&self.title, center_offset); - title_style.draw_text(&self.title, center); + + draw_text_with_background( + &self.title, + center, + &ctx.slide_show_theme.title_config, + LIME, + DARKGREEN, + ); let subtitle_builder: TextConfigBuilder = ctx.slide_show_theme.heading_config.clone().into(); diff --git a/src/text_drawer.rs b/src/text_drawer.rs index ed48400..c07cb2b 100644 --- a/src/text_drawer.rs +++ b/src/text_drawer.rs @@ -134,6 +134,8 @@ impl<'a> TextConfig<'a> { let mut lines: Vec = text.split("\n").map(|s| s.to_string()).collect(); let mut line_pos = pos; + let standard_line_height = self.measure_text("A").height; + let mut line_ndx = 0; loop { if line_ndx >= lines.len() { @@ -141,26 +143,34 @@ impl<'a> TextConfig<'a> { } let line = &lines[line_ndx]; - let line_size = self.measure_text(line); let line: Vec<&str> = line.split(" ").collect(); let mut word_pos = line_pos; + let mut need_line_break = false; for word_ndx in 0..line.len() { let word = line[word_ndx]; - let word_info = self.draw_text(&format!("{word} "), word_pos); - word_pos.x += word_info.text_dimensions.width; - if word_pos.x > size.x { - let new_line = format!("\t\t\t{}", line[word_ndx + 1..].join(" ")); + let measure_text = self.measure_text(&format!("{word} ")); + + if measure_text.width + word_pos.x > size.x { + let new_line = format!("\t\t\t{}", line[word_ndx..].join(" ")); lines.insert(line_ndx + 1, new_line); + need_line_break = true; break; } + + let word_info = self.draw_text(&format!("{word} "), word_pos); + word_pos.x += word_info.text_dimensions.width; } line_ndx += 1; - line_pos.y += line_size.height * 1.2; + if need_line_break { + line_pos.y += standard_line_height * 1.5; + } else { + line_pos.y += standard_line_height * 2.0; + } if line_pos.y > size.y { // Stop drawing text diff --git a/src/utils.rs b/src/utils.rs index 4ef6bb0..433e6dd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,4 @@ +use crate::text_drawer::{TextConfig, TextConfigBuilder}; use macroquad::color::Color; use macroquad::math::Vec2; use macroquad::miniquad::window::screen_size; @@ -26,3 +27,19 @@ pub fn draw_rectangle_with_border( ); draw_rectangle(rect_pos.x, rect_pos.y, rect_size.x, rect_size.y, fg_color); } + +pub fn draw_text_with_background<'a>( + text: &str, + pos: Vec2, + base_config: &TextConfig<'a>, + fg_color: Color, + bg_color: Color, +) { + let title_builder: TextConfigBuilder = base_config.clone().into(); + let shadow_style = title_builder.clone().color(bg_color).build(); + let title_style = title_builder.color(fg_color).build(); + + let offset = pos + (pos * 0.005); + shadow_style.draw_text(text, offset); + title_style.draw_text(text, pos); +}