use std::collections::HashMap; use sfml::system::Vector2f; use sfml::window::{ ContextSettings, Event, Style, }; use sfml::graphics::{ RenderWindow, RenderTarget, Drawable, Texture, Image, Color, Rect, }; use sfml::graphics::{ RectangleShape, Transformable, }; #[derive(RustEmbed)] #[folder = "res/maps"] pub struct MapAssets; pub fn start() -> RenderWindow { 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 window; } pub fn render(window: &mut RenderWindow, 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, }; window.clear(&bgcolor); // render map // loaded textures // TODO: cache outside of this function let mut tilesets: HashMap = HashMap::new(); let mut textures: HashMap = HashMap::new(); // 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]; 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 !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 textures.insert( tmx_tileset.first_gid + ty * tileset_width + tx, texture ); } } // save tileset image tilesets.insert(tmx_tileset.first_gid, image); } // draw! // TODO: check map render order let texture = 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 }); window.draw(&tile_rect); } } } window.display(); } pub fn update(window: &mut RenderWindow) { while let Some(ev) = window.poll_event() { match ev { Event::Closed => window.close(), _ => {}, } } }