Basic slide setup
This commit is contained in:
parent
090c8a6849
commit
1751dfaa62
7
cfg/01_author_intro.toml
Normal file
7
cfg/01_author_intro.toml
Normal file
@ -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
|
||||||
|
"""
|
||||||
7
cfg/02_things_i_have_worked_on.toml
Normal file
7
cfg/02_things_i_have_worked_on.toml
Normal file
@ -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
|
||||||
|
"""
|
||||||
9
cfg/03_me_outside_work.toml
Normal file
9
cfg/03_me_outside_work.toml
Normal file
@ -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
|
||||||
|
"""
|
||||||
BIN
cfg/img/joey_and_molly.png
Normal file
BIN
cfg/img/joey_and_molly.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 MiB |
BIN
cfg/img/joey_headshot.png
Normal file
BIN
cfg/img/joey_headshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 MiB |
BIN
cfg/img/methanesat.png
Normal file
BIN
cfg/img/methanesat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 529 KiB |
15
src/main.rs
15
src/main.rs
@ -3,13 +3,16 @@ mod slide;
|
|||||||
mod slide_show_config;
|
mod slide_show_config;
|
||||||
mod slides;
|
mod slides;
|
||||||
mod text_drawer;
|
mod text_drawer;
|
||||||
|
mod utils;
|
||||||
use macroquad::prelude::*;
|
|
||||||
|
|
||||||
use crate::slide_show_config::{Context, SlideShowTheme};
|
use crate::slide_show_config::{Context, SlideShowTheme};
|
||||||
use crate::slides::Slideshow;
|
use crate::slides::Slideshow;
|
||||||
|
use crate::slides::demo::Demo;
|
||||||
|
use crate::slides::standard_slide::StandardSlide;
|
||||||
use crate::slides::title::Title;
|
use crate::slides::title::Title;
|
||||||
use crate::text_drawer::{Justified, TextConfigBuilder};
|
use crate::text_drawer::{Justified, TextConfigBuilder};
|
||||||
|
use macroquad::prelude::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn window_conf() -> Conf {
|
fn window_conf() -> Conf {
|
||||||
Conf {
|
Conf {
|
||||||
@ -38,12 +41,12 @@ async fn main() {
|
|||||||
.justification(Justified::CenterHorizontal)
|
.justification(Justified::CenterHorizontal)
|
||||||
.font(&heading)
|
.font(&heading)
|
||||||
.color(WHITE)
|
.color(WHITE)
|
||||||
.font_size(100)
|
.font_size(150)
|
||||||
.build(),
|
.build(),
|
||||||
body_config: TextConfigBuilder::default()
|
body_config: TextConfigBuilder::default()
|
||||||
.justification(Justified::Left)
|
.justification(Justified::Left)
|
||||||
.font(&body)
|
.font(&body)
|
||||||
.font_size(50)
|
.font_size(100)
|
||||||
.color(WHITE)
|
.color(WHITE)
|
||||||
.build(),
|
.build(),
|
||||||
};
|
};
|
||||||
@ -51,6 +54,10 @@ async fn main() {
|
|||||||
let mut slideshow = Slideshow::new(Context::new(slide_show_theme));
|
let mut slideshow = Slideshow::new(Context::new(slide_show_theme));
|
||||||
|
|
||||||
slideshow.add_slide(Title::new("Software As a Bit".to_string()));
|
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 {
|
loop {
|
||||||
if slideshow.handle_slide_show() {
|
if slideshow.handle_slide_show() {
|
||||||
|
|||||||
57
src/slides/demo.rs
Normal file
57
src/slides/demo.rs
Normal file
@ -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<Self> {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,10 @@
|
|||||||
use crate::slide::Slide;
|
use crate::slide::Slide;
|
||||||
use crate::slide_show_config::Context;
|
use crate::slide_show_config::Context;
|
||||||
|
use macroquad::camera::set_default_camera;
|
||||||
use macroquad::input::{KeyCode, is_key_pressed};
|
use macroquad::input::{KeyCode, is_key_pressed};
|
||||||
|
|
||||||
|
pub mod demo;
|
||||||
|
pub mod standard_slide;
|
||||||
pub mod title;
|
pub mod title;
|
||||||
|
|
||||||
pub struct Slideshow<'a> {
|
pub struct Slideshow<'a> {
|
||||||
@ -24,9 +27,15 @@ impl<'a> Slideshow<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_slide_show(&mut self) -> bool {
|
pub fn handle_slide_show(&mut self) -> bool {
|
||||||
|
set_default_camera();
|
||||||
if is_key_pressed(KeyCode::Escape) {
|
if is_key_pressed(KeyCode::Escape) {
|
||||||
return true;
|
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);
|
self.slides[self.current_slide].display(&self.ctx);
|
||||||
|
|
||||||
|
|||||||
92
src/slides/standard_slide.rs
Normal file
92
src/slides/standard_slide.rs
Normal file
@ -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<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StandardSlideConfig {
|
||||||
|
pub fn new(src: &str) -> Result<Self, config::ConfigError> {
|
||||||
|
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<Texture2D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StandardSlide {
|
||||||
|
pub async fn new(cfg_path: &Path) -> Box<Self> {
|
||||||
|
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()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -34,20 +34,22 @@ impl Slide for Title {
|
|||||||
shadow_style.draw_text(&self.title, center_offset);
|
shadow_style.draw_text(&self.title, center_offset);
|
||||||
title_style.draw_text(&self.title, center);
|
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);
|
let author_pos = center + Vec2::new(0.0, screen_height() * 0.33);
|
||||||
ctx.slide_show_theme
|
subtitle_style.draw_text("By Joey Hines", author_pos);
|
||||||
.heading_config
|
|
||||||
.draw_text("By Joey Hines", author_pos);
|
|
||||||
|
|
||||||
let bits = ["0", "1"];
|
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 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);
|
let mut bit_pos = Vec2::new(0.0, center.y) + Vec2::new(0.0, screen_height() * 0.05);
|
||||||
for _ in 0..count_needed {
|
for _ in 0..count_needed {
|
||||||
let bit = bits.choose().unwrap();
|
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);
|
bit_pos = info.pos + Vec2::new(info.text_dimensions.width, 0.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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<String> = 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 {
|
pub fn measure_text(&self, text: &str) -> TextDimensions {
|
||||||
measure_text(text, self.font, self.font_size, self.font_scale)
|
measure_text(text, self.font, self.font_size, self.font_scale)
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/utils.rs
Normal file
6
src/utils.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user