#![deny(
missing_docs,
missing_debug_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications
)]
pub struct Engine<'a> {
pub name: String,
pub size: (u32, u32, u32),
pub screen: Window,
event_pump: sdl2::EventPump,
timer: std::time::SystemTime,
frame_count: u64,
frame_timer: f64,
pub elapsed: f64,
key_pressed: std::collections::HashSet<sdl2::keyboard::Keycode>,
key_hold: std::collections::HashSet<sdl2::keyboard::Keycode>,
key_release: std::collections::HashSet<sdl2::keyboard::Keycode>,
pub main: &'a (dyn Fn(&mut Engine) -> Result<(), String>),
}
impl<'a> std::fmt::Debug for Engine<'a> {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
return write!(fmt, "Engine {{ pub name: {:?}, pub size: {:?}, pub screen: {:?}, event_pump: sdl2::EventPump, timer: {:?}, frame_count: {:?}, frame_timer: {:?}, pub elapsed: {:?}, key_pressed: {:?}, key_hold: {:?}, key_release: {:?}, main: &(dyn Fn(&mut Engine) -> Result<(),String>) }}",
self.name,
self.size,
self.screen,
self.timer,
self.frame_count,
self.frame_timer,
self.elapsed,
self.key_pressed,
self.key_hold,
self.key_release
);
}
}
impl<'a> Engine<'a> {
pub fn new(
name: &str,
size: (u32, u32, u32),
main: &'a (dyn Fn(&mut Engine) -> Result<(), String>),
) -> Result<Engine<'a>, String> {
let sdl_ctx = sdl2::init()?;
let video_subsystem = sdl_ctx.video()?;
let screen = initialize(video_subsystem, size.0, size.1, size.2, String::from(name))
.map_err(|err| err.to_string())?;
let event_pump = sdl_ctx.event_pump()?;
Ok(Engine {
name: String::from(name),
size: size,
main: main,
screen: screen,
event_pump: event_pump,
timer: std::time::SystemTime::now(),
frame_count: 0,
frame_timer: 0.0,
elapsed: 0.0,
key_pressed: std::collections::HashSet::new(),
key_hold: std::collections::HashSet::new(),
key_release: std::collections::HashSet::new(),
})
}
pub fn new_frame(&mut self) -> Result<bool, String> {
self.elapsed = (std::time::SystemTime::now()
.duration_since(self.timer)
.map_err(|err| err.to_string())?)
.as_secs_f64();
self.timer = std::time::SystemTime::now();
self.frame_timer += self.elapsed;
self.frame_count += 1;
if self.frame_timer > 1.0 {
self.frame_timer -= 1.0;
self.screen
.update_title(&self.name.as_ref(), self.frame_count)?;
self.frame_count = 0
}
for key in &self.key_pressed {
self.key_hold.insert(*key);
}
self.key_pressed.clear();
self.key_release.clear();
for event in self.event_pump.poll_iter() {
match event {
sdl2::event::Event::Quit {..} => return Ok(false),
sdl2::event::Event::KeyDown { keycode: Some(keycode), repeat, ..} => {
if !repeat {
self.key_pressed.insert(keycode);
}
},
sdl2::event::Event::KeyUp {keycode: Some(keycode), ..} => {
self.key_release.insert(keycode);
self.key_hold.remove(&keycode);
self.key_pressed.remove(&keycode);
}
_ => {},
}
}
Ok(true)
}
pub fn start(&mut self) -> Result<(), String> {
(self.main)(self).map_err(|err| err.to_string())?;
Ok(())
}
pub fn get_key_state(&self, key: sdl2::keyboard::Keycode) -> KeyState {
if self.key_pressed.contains(&key) {
return KeyState::Pressed;
}
if self.key_hold.contains(&key) {
return KeyState::Held;
}
if self.key_release.contains(&key) {
return KeyState::Released;
}
return KeyState::None;
}
pub fn get_pressed(&self) -> std::collections::HashSet<sdl2::keyboard::Keycode> {
self.key_pressed.clone()
}
pub fn get_held(&self) -> std::collections::HashSet<sdl2::keyboard::Keycode> {
self.key_hold.clone()
}
pub fn get_released(&self) -> std::collections::HashSet<sdl2::keyboard::Keycode> {
self.key_release.clone()
}
pub fn is_pressed(&self, key: sdl2::keyboard::Keycode) -> bool {
self.key_pressed.contains(&key)
}
pub fn is_held(&self, key: sdl2::keyboard::Keycode) -> bool {
self.key_hold.contains(&key)
}
pub fn is_released(&self, key: sdl2::keyboard::Keycode) -> bool {
self.key_release.contains(&key)
}
}
#[derive(Eq, PartialEq, Debug)]
pub enum KeyState {
None,
Held,
Pressed,
Released,
}
use sdl2::rect::Rect;
#[derive(Debug, Copy, Clone)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
pub const WHITE: Color = Color {
r: 255,
g: 255,
b: 255,
a: 255,
};
pub const GREY: Color = Color {
r: 192,
g: 192,
b: 192,
a: 255,
};
pub const DARK_GREY: Color = Color {
r: 128,
g: 128,
b: 128,
a: 255,
};
pub const VERY_DARK_GREY: Color = Color {
r: 64,
g: 64,
b: 64,
a: 255,
};
pub const RED: Color = Color {
r: 255,
g: 0,
b: 0,
a: 255,
};
pub const DARK_RED: Color = Color {
r: 128,
g: 0,
b: 0,
a: 255,
};
pub const VERY_DARK_RED: Color = Color {
r: 64,
g: 0,
b: 0,
a: 255,
};
pub const YELLOW: Color = Color {
r: 255,
g: 255,
b: 0,
a: 255,
};
pub const DARK_YELLOW: Color = Color {
r: 128,
g: 128,
b: 0,
a: 255,
};
pub const VERY_DARK_YELLOW: Color = Color {
r: 64,
g: 64,
b: 0,
a: 255,
};
pub const GREEN: Color = Color {
r: 0,
g: 255,
b: 0,
a: 255,
};
pub const DARK_GREEN: Color = Color {
r: 0,
g: 128,
b: 0,
a: 255,
};
pub const VERY_DARK_GREEN: Color = Color {
r: 0,
g: 64,
b: 0,
a: 255,
};
pub const CYAN: Color = Color {
r: 0,
g: 255,
b: 255,
a: 255,
};
pub const DARK_CYAN: Color = Color {
r: 0,
g: 128,
b: 128,
a: 255,
};
pub const VERY_DARK_CYAN: Color = Color {
r: 0,
g: 64,
b: 64,
a: 255,
};
pub const BLUE: Color = Color {
r: 0,
g: 0,
b: 255,
a: 255,
};
pub const DARK_BLUE: Color = Color {
r: 0,
g: 0,
b: 128,
a: 255,
};
pub const VERY_DARK_BLUE: Color = Color {
r: 0,
g: 0,
b: 64,
a: 255,
};
pub const MAGENTA: Color = Color {
r: 255,
g: 0,
b: 255,
a: 255,
};
pub const DARK_MAGENTA: Color = Color {
r: 128,
g: 0,
b: 128,
a: 255,
};
pub const VERY_DARK_MAGENTA: Color = Color {
r: 64,
g: 0,
b: 64,
a: 255,
};
pub const BLACK: Color = Color {
r: 0,
g: 0,
b: 0,
a: 255,
};
pub fn new(r: u8, g: u8, b: u8) -> Color {
Color { r, g, b, a: 255 }
}
pub fn new_alpha(r: u8, g: u8, b: u8, a: u8) -> Color {
Color { r, g, b, a }
}
pub fn to_pixel_color(&self) -> sdl2::pixels::Color {
sdl2::pixels::Color::RGBA(self.r, self.g, self.b, self.a)
}
}
pub struct Window {
pub canv: sdl2::render::Canvas<sdl2::video::Window>,
pub height: u32,
pub width: u32,
pub px_size: u32,
pub name: String,
}
impl std::fmt::Debug for Window {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
return write!(fmt, "Window {{ pub self.canv: sdl2::render::Canvas<sdl2::video::Window>, pub height: {:?}, pub width: {:?}, pub px_size: {:?}, pub name: {:?} }}",
self.height,
self.width,
self.px_size,
self.name
);
}
}
impl Window {
pub fn new(
canvas: sdl2::render::Canvas<sdl2::video::Window>,
w: u32,
h: u32,
pixel_size: u32,
name: String,
) -> Window {
Window {
canv: canvas,
width: w,
height: h,
px_size: pixel_size,
name: name,
}
}
fn ptsp(&self, num: i32) -> i32 {
((num) * self.px_size as i32)
}
pub fn clear(&mut self, col: Color) {
self.canv.set_draw_color(col.to_pixel_color());
self.canv.clear();
}
pub fn draw(&mut self, x: i32, y: i32, col: Color) -> Result<(), String> {
self.canv.set_draw_color(col.to_pixel_color());
self.canv
.fill_rect(Rect::new(
self.ptsp(x),
self.ptsp(y),
self.px_size,
self.px_size,
))
.map_err(|err| err.to_string())?;
Ok(())
}
pub fn fill_rect(&mut self, x: i32, y: i32, w: i32, h: i32, col: Color) -> Result<(), String> {
self.canv.set_draw_color(col.to_pixel_color());
self.canv
.fill_rect(Rect::new(
self.ptsp(x),
self.ptsp(y),
self.ptsp(w) as u32,
self.ptsp(h) as u32,
))
.map_err(|err| err.to_string())?;
Ok(())
}
pub fn update(&mut self) {
self.canv.present();
}
pub fn update_title(&mut self, title: &str, frame_count: u64) -> Result<(), String> {
self.canv
.window_mut()
.set_title(format!("{} - {}fps", title, frame_count).as_ref())
.map_err(|err| err.to_string())?;
Ok(())
}
}
pub fn initialize(
video_subsystem: sdl2::VideoSubsystem,
width: u32,
height: u32,
pixsize: u32,
name: String,
) -> Result<Window, String> {
let window = video_subsystem
.window(name.as_ref(), width * pixsize, height * pixsize)
.opengl()
.build()
.map_err(|err| err.to_string())?;
let canvas: sdl2::render::Canvas<sdl2::video::Window> = window
.into_canvas()
.build()
.map_err(|err| err.to_string())?;
Ok(Window::new(canvas, width, height, pixsize, name))
}