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 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() {
|
||||
|
||||
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_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);
|
||||
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
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