use std::collections::HashMap; use sfml::system::Vector2f; use sfml::window::{ ContextSettings, Event, Style, }; use sfml::graphics::{ RenderWindow, RenderTarget, Texture, Image, Color, Rect, }; use sfml::graphics::{ RectangleShape, Transformable, }; #[derive(RustEmbed)] #[folder = "res/maps"] pub struct MapAssets; #[derive(Debug)] pub struct Graphics { window: RenderWindow, running: bool, // loaded resources tilesets: HashMap, textures: HashMap, } impl Graphics { pub fn new() -> Graphics { let default_window_size = (1280, 720); let default_framerate = 80; let context_settings = ContextSettings { antialiasing_level: 0, ..Default::default() }; let mut window = RenderWindow::new( default_window_size, "Subconscious", Style::CLOSE, &context_settings ); window.set_framerate_limit(default_framerate); window.set_vertical_sync_enabled(true); return Graphics { window: window, running: true, tilesets: HashMap::new(), textures: HashMap::new(), }; } pub fn is_running(self: &mut Self) -> bool { return self.running; } pub fn render(self: &mut Self, state: &crate::game::State) { // background let bgcolor = match state.map.background_colour { Some(color) => Color::rgb(color.red, color.green, color.blue), None => Color::BLACK, }; self.window.clear(&bgcolor); // render map // for each tile for y in 0 .. state.map.height { for x in 0 .. state.map.width { // for each layer for layer in &state.map.layers { let tmx_tile = layer.tiles[y as usize][x as usize]; // blank tile if tmx_tile <= 0 { continue; } let tmx_tileset = state.map.get_tileset_by_gid(tmx_tile).unwrap(); // load tileset if not loaded yet // TODO: load in a separate thread? if !self.tilesets.contains_key(&tmx_tileset.first_gid) { // TODO: replace with iter or error message assert_eq!(tmx_tileset.images.len(), 1); // load tileset image let tmx_image = &tmx_tileset.images[0]; let asset = MapAssets::get(&tmx_image.source).unwrap(); let image = Image::from_memory(asset.as_ref()).unwrap(); // load tiles (textures) let tileset_width = tmx_image.width as u32 / tmx_tileset.tile_width; let tileset_height = tmx_image.height as u32 / tmx_tileset.tile_height; for ty in 0 .. tileset_height { for tx in 0 .. tileset_width { let texture = Texture::from_image_with_rect( &image, &Rect::new( (tx * tmx_tileset.tile_width) as i32, (ty * tmx_tileset.tile_height) as i32, tmx_tileset.tile_width as i32, tmx_tileset.tile_height as i32 ) ).unwrap(); // save tile texture self.textures.insert( tmx_tileset.first_gid + ty * tileset_width + tx, texture ); } } // save tileset image self.tilesets.insert(tmx_tileset.first_gid, image); } // draw! // TODO: check map render order let texture = self.textures.get(&tmx_tile).unwrap(); let mut tile_rect = RectangleShape::with_texture(texture); tile_rect.set_size(Vector2f { x: tmx_tileset.tile_width as f32, y: tmx_tileset.tile_height as f32 }); tile_rect.set_position(Vector2f { x: (x * tmx_tileset.tile_width) as f32, y: (y * tmx_tileset.tile_height) as f32 }); self.window.draw(&tile_rect); } } } self.window.display(); } pub fn update(self: &mut Self) { while let Some(ev) = self.window.poll_event() { match ev { Event::Closed => { self.window.close(); self.running = false; }, _ => {}, } } } }