diff --git a/cfg/01_author_intro.toml b/cfg/01_author_intro.toml new file mode 100644 index 0000000..695c705 --- /dev/null +++ b/cfg/01_author_intro.toml @@ -0,0 +1,7 @@ +title = "Who am I? (Please help)" +image = "cfg/img/joey_headshot.png" +body = """ +* Joey Hines - Onboard Software Engineer at Loft Orbital +* Writes code everyday like a nerd +* Makes real money, mainly by wasting VC's money +""" \ No newline at end of file diff --git a/cfg/02_things_i_have_worked_on.toml b/cfg/02_things_i_have_worked_on.toml new file mode 100644 index 0000000..391d8ee --- /dev/null +++ b/cfg/02_things_i_have_worked_on.toml @@ -0,0 +1,7 @@ +title = "What I do at work" +image = "cfg/img/methanesat.png" +body = """ +* Write Flight Software (FSW) for some very successful satellites +* Collabroate with diffrent teams to execute on satellite missions +* Keep the work equivalent of #fucky-wucky up to date +""" \ No newline at end of file diff --git a/cfg/03_me_outside_work.toml b/cfg/03_me_outside_work.toml new file mode 100644 index 0000000..6848f26 --- /dev/null +++ b/cfg/03_me_outside_work.toml @@ -0,0 +1,9 @@ +title = "Who am I? (Outside Work B-))" +image = "cfg/img/joey_and_molly.png" +body = """ +* Joey Hines - Nerd +* Has a girlfriend (nice) +* Likes TTRPGS and Boardgames +* Writes code like a nerd +* Keep #fucky-wucky Up to Date +""" \ No newline at end of file diff --git a/cfg/img/joey_and_molly.png b/cfg/img/joey_and_molly.png new file mode 100644 index 0000000..33f46ca Binary files /dev/null and b/cfg/img/joey_and_molly.png differ diff --git a/cfg/img/joey_headshot.png b/cfg/img/joey_headshot.png new file mode 100644 index 0000000..baf98ab Binary files /dev/null and b/cfg/img/joey_headshot.png differ diff --git a/cfg/img/methanesat.png b/cfg/img/methanesat.png new file mode 100644 index 0000000..2312547 Binary files /dev/null and b/cfg/img/methanesat.png differ diff --git a/src/main.rs b/src/main.rs index 9473e24..2dc51df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,13 +3,16 @@ mod slide; mod slide_show_config; mod slides; mod text_drawer; - -use macroquad::prelude::*; +mod utils; use crate::slide_show_config::{Context, SlideShowTheme}; use crate::slides::Slideshow; +use crate::slides::demo::Demo; +use crate::slides::standard_slide::StandardSlide; use crate::slides::title::Title; use crate::text_drawer::{Justified, TextConfigBuilder}; +use macroquad::prelude::*; +use std::path::PathBuf; fn window_conf() -> Conf { Conf { @@ -38,12 +41,12 @@ async fn main() { .justification(Justified::CenterHorizontal) .font(&heading) .color(WHITE) - .font_size(100) + .font_size(150) .build(), body_config: TextConfigBuilder::default() .justification(Justified::Left) .font(&body) - .font_size(50) + .font_size(100) .color(WHITE) .build(), }; @@ -51,6 +54,10 @@ async fn main() { let mut slideshow = Slideshow::new(Context::new(slide_show_theme)); slideshow.add_slide(Title::new("Software As a Bit".to_string())); + slideshow.add_slide(Demo::new()); + slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/01_author_intro.toml")).await); + slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/02_things_i_have_worked_on.toml")).await); + slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/03_me_outside_work.toml")).await); loop { if slideshow.handle_slide_show() { diff --git a/src/slides/demo.rs b/src/slides/demo.rs new file mode 100644 index 0000000..be3b059 --- /dev/null +++ b/src/slides/demo.rs @@ -0,0 +1,57 @@ +use crate::effects::star_field; +use crate::slide::Slide; +use crate::slide_show_config::Context; +use crate::utils::screen_center; +use macroquad::color::BLACK; +use macroquad::prelude::*; + +#[derive(Debug, Default)] +pub struct Demo { + camera_angle: f32, +} + +impl Demo { + pub fn new() -> Box { + Box::new(Self::default()) + } +} + +impl Slide for Demo { + fn display(&mut self, ctx: &Context<'_>) { + clear_background(BLACK); + star_field(); + + push_camera_state(); + + let camera_x = self.camera_angle.sin() * 20.0; + let camera_z = self.camera_angle.cos() * 20.0; + set_camera(&Camera3D { + position: vec3(camera_x, 15., camera_z), + up: vec3(0., 1., 0.), + target: vec3(0.0, 0.0, 0.0), + ..Default::default() + }); + + draw_sphere_wires(vec3(0.0, 0.0, 0.0), 6.0, None, RED); + + draw_sphere_wires(vec3(15.0, 0.0, 0.0), 2.0, None, RED); + + draw_sphere_wires(vec3(0.0, 0.0, 15.0), 2.0, None, RED); + + draw_sphere_wires(vec3(-15.0, 0.0, 0.0), 2.0, None, RED); + + draw_sphere_wires(vec3(0.0, 0.0, -15.0), 2.0, None, RED); + + draw_sphere_wires(vec3(15.0, 0.0, 0.0), 2.0, None, RED); + + let diff = 1.0 * get_frame_time(); + self.camera_angle = (self.camera_angle + diff) % 360.0; + + pop_camera_state(); + + ctx + .slide_show_theme + .heading_config + .draw_text("This Ain't No Powerpoint", screen_center()); + } +} diff --git a/src/slides/mod.rs b/src/slides/mod.rs index 60911d8..f0a4ed0 100644 --- a/src/slides/mod.rs +++ b/src/slides/mod.rs @@ -1,7 +1,10 @@ use crate::slide::Slide; use crate::slide_show_config::Context; +use macroquad::camera::set_default_camera; use macroquad::input::{KeyCode, is_key_pressed}; +pub mod demo; +pub mod standard_slide; pub mod title; pub struct Slideshow<'a> { @@ -24,9 +27,15 @@ impl<'a> Slideshow<'a> { } pub fn handle_slide_show(&mut self) -> bool { + set_default_camera(); if is_key_pressed(KeyCode::Escape) { return true; - }; + } else if is_key_pressed(KeyCode::Right) { + self.current_slide += 1; + } else if is_key_pressed(KeyCode::Left) { + self.current_slide = self.current_slide.saturating_sub(1); + } + self.current_slide = self.current_slide.clamp(0, self.slides.len() - 1); self.slides[self.current_slide].display(&self.ctx); diff --git a/src/slides/standard_slide.rs b/src/slides/standard_slide.rs new file mode 100644 index 0000000..24a6070 --- /dev/null +++ b/src/slides/standard_slide.rs @@ -0,0 +1,92 @@ +use crate::effects::star_field; +use crate::slide::Slide; +use crate::slide_show_config::Context; +use config::Config; +use macroquad::color::{BLACK, WHITE}; +use macroquad::file::load_file; +use macroquad::math::Vec2; +use macroquad::prelude::{Texture2D, clear_background, load_texture, draw_texture, draw_texture_ex, DrawTextureParams}; +use macroquad::window::{screen_height, screen_width}; +use serde::Deserialize; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Deserialize)] +pub struct StandardSlideConfig { + title: String, + body: String, + image: Option, +} + +impl StandardSlideConfig { + pub fn new(src: &str) -> Result { + let cfg = Config::builder() + .add_source(config::File::from_str(src, config::FileFormat::Toml)) + .build()?; + + cfg.try_deserialize() + } +} + +#[derive(Debug)] +pub struct StandardSlide { + cfg: StandardSlideConfig, + image: Option, +} + +impl StandardSlide { + pub async fn new(cfg_path: &Path) -> Box { + let cfg_bytes = load_file(cfg_path.to_str().unwrap()).await.unwrap(); + let cfg_str = String::from_utf8(cfg_bytes).unwrap(); + let cfg = StandardSlideConfig::new(&cfg_str).unwrap(); + + let image = if let Some(image_path) = &cfg.image { + Some(load_texture(image_path.to_str().unwrap()).await.unwrap()) + } else { + None + }; + + Box::new(Self { cfg, image }) + } +} + +impl Slide for StandardSlide { + fn display(&mut self, ctx: &Context<'_>) { + clear_background(BLACK); + star_field(); + + let title_pos = Vec2::new(screen_width() * 0.5, screen_height() * 0.10); + let info = ctx + .slide_show_theme + .heading_config + .draw_text(&self.cfg.title, title_pos); + + let body_pos = Vec2::new( + screen_width() * 0.05, + screen_height() * 0.33 + 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), + ); + + + if let Some(image) = &self.image { + let size = image.size(); + let image_center_pos = Vec2::new(screen_width() * 0.75, screen_height() * 0.5); + + let target_image_size = Vec2::new(screen_width() * 0.33, screen_height() * 0.66); + + let scale = f32::min(target_image_size.x / size.x, target_image_size.y / size.y); + + let new_image_size = size * scale; + + let image_pos = image_center_pos - new_image_size * 0.5; + + draw_texture_ex(image, image_pos.x, image_pos.y, WHITE, DrawTextureParams { + dest_size: Some(new_image_size), + ..Default::default() + }); + } + } +} diff --git a/src/slides/title.rs b/src/slides/title.rs index b2adddd..8553a3d 100644 --- a/src/slides/title.rs +++ b/src/slides/title.rs @@ -34,20 +34,22 @@ impl Slide for Title { shadow_style.draw_text(&self.title, center_offset); title_style.draw_text(&self.title, center); + let subtitle_builder: TextConfigBuilder = + ctx.slide_show_theme.heading_config.clone().into(); + let subtitle_style = subtitle_builder.font_size(100).build(); + let author_pos = center + Vec2::new(0.0, screen_height() * 0.33); - ctx.slide_show_theme - .heading_config - .draw_text("By Joey Hines", author_pos); + subtitle_style.draw_text("By Joey Hines", author_pos); let bits = ["0", "1"]; - let bit_text_size = ctx.slide_show_theme.heading_config.measure_text("0"); + let bit_text_size = subtitle_style.measure_text("0"); let count_needed = (screen_width() / bit_text_size.width).ceil() as usize; let mut bit_pos = Vec2::new(0.0, center.y) + Vec2::new(0.0, screen_height() * 0.05); for _ in 0..count_needed { let bit = bits.choose().unwrap(); - let info = ctx.slide_show_theme.heading_config.draw_text(bit, bit_pos); + let info = subtitle_style.draw_text(bit, bit_pos); bit_pos = info.pos + Vec2::new(info.text_dimensions.width, 0.0); } diff --git a/src/text_drawer.rs b/src/text_drawer.rs index 8814881..ed48400 100644 --- a/src/text_drawer.rs +++ b/src/text_drawer.rs @@ -130,6 +130,54 @@ impl<'a> TextConfig<'a> { } } + pub fn draw_text_box(&self, text: &str, pos: Vec2, size: Vec2) -> TextInfo { + let mut lines: Vec = text.split("\n").map(|s| s.to_string()).collect(); + let mut line_pos = pos; + + let mut line_ndx = 0; + loop { + if line_ndx >= lines.len() { + break; + } + + 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; + + 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(" ")); + lines.insert(line_ndx + 1, new_line); + break; + } + } + + line_ndx += 1; + + line_pos.y += line_size.height * 1.2; + + if line_pos.y > size.y { + // Stop drawing text + break; + } + } + + TextInfo { + text_dimensions: TextDimensions { + width: size.x, + height: size.y, + offset_y: 0.0, + }, + pos, + } + } + pub fn measure_text(&self, text: &str) -> TextDimensions { measure_text(text, self.font, self.font_size, self.font_scale) } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..46e8cad --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,6 @@ +use macroquad::math::Vec2; +use macroquad::miniquad::window::screen_size; + +pub fn screen_center() -> Vec2 { + Vec2::from(screen_size()) * 0.5 +}