microworlds-rs/src/lib.rs

125 lines
3.7 KiB
Rust

use sdl2::render::Canvas;
use sdl2::pixels::Color;
use sdl2::video::Window;
use sdl2::rect::Rect;
use std::{thread, time};
use std::time::{SystemTime};
pub mod life;
pub const BLACK: Color = Color::RGB(0, 0, 0);
pub const WHITE: Color = Color::RGB(255, 255, 255);
pub struct Grid<T: Clone> {
size: usize,
flat_grid: Vec<T>,
}
impl<T> Grid<T>
where T: Clone
{
pub fn new(default: T, size: usize) -> Grid<T> {
Grid::<T> {size: size, flat_grid: vec![default; size*size]}
}
pub fn get(&self, y: usize, x: usize) -> &T {
&self.flat_grid[ y*self.size + x ]
}
pub fn set(&mut self, y: usize, x: usize, val: T) {
self.flat_grid[ y*self.size + x ] = val;
}
pub fn size(&self) -> usize {
self.size
}
}
#[derive(Clone)]
pub struct Patch {
pub color: Color,
}
pub trait Engine {
fn evolve(&mut self) -> Grid<Patch>;
}
pub struct Observer {
px_size: i32,
canvas: Canvas<Window>,
sdl_context: sdl2::Sdl,
render_grid: Grid<Patch>,
}
impl Observer {
pub fn new(px_size: i32, num_patches: u32) -> Observer {
let size: usize = (num_patches/px_size as u32) as usize;
println!("Window: {}x{} at {} px per cell", num_patches, num_patches, px_size);
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("Microworlds", num_patches, num_patches).build().unwrap();
// setup initial black render grid
let render_grid = Grid::new(Patch {color: BLACK}, size);
// Let's create a Canvas which we will use to draw in our Window
let canvas : Canvas<Window> = window.into_canvas()
.present_vsync() //< this means the screen cannot
// render faster than your display rate (usually 60Hz or 144Hz)
.build().unwrap();
Observer { px_size: px_size, canvas: canvas, sdl_context: sdl_context, render_grid: render_grid }
}
pub fn sim(&mut self, mut engine: Box<dyn Engine>, steps_per_sec: u64) {
let mut frame = 0;
let mut event_pump = self.sdl_context.event_pump().unwrap();
let period = time::Duration::from_millis(1000 / steps_per_sec);
'main: loop {
for event in event_pump.poll_iter() {
match event {
sdl2::event::Event::Quit {..} => break 'main,
_ => {},
}
}
let start_rend = SystemTime::now();
self.render();
let render_time = start_rend.elapsed().unwrap();
let start_evo = SystemTime::now();
self.render_grid = engine.evolve();
let evo_time = start_evo.elapsed().unwrap();
let total_time = start_rend.elapsed().unwrap();
frame += 1;
println!("frame: {} - render time: {:?} | evolve time: {:?} | total time: {:?}", frame, render_time, evo_time, total_time);
if total_time < period {
thread::sleep(period - total_time);
}
}
}
fn render(&mut self) {
self.canvas.set_draw_color(BLACK);
self.canvas.clear();
for y in 0..self.render_grid.size() {
for x in 0..self.render_grid.size() {
self.canvas.set_draw_color(self.render_grid.get(y, x).color);
match self.canvas.fill_rect(Rect::new(x as i32 * self.px_size, y as i32 * self.px_size, self.px_size as u32, self.px_size as u32)) {
Ok(()) => (),
Err(err) => {
println!("Error on canvas.fill_rect: {}", err);
return;
}
};
}
}
self.canvas.present();
}
}