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 { size: usize, flat_grid: Vec, } impl Grid where T: Clone { pub fn new(default: T, size: usize) -> Grid { Grid:: {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; } pub struct Observer { px_size: i32, canvas: Canvas, sdl_context: sdl2::Sdl, render_grid: Grid, } 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.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, 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(); } }