diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ff2ca7a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,261 @@ +mod camera; +mod framebuffer; +mod map; +mod texture; +mod util; +mod vec2; + +use minifb::{Window, WindowOptions}; + +use camera::{Camera, Intersection}; +use framebuffer::Framebuffer; +use map::{Map, MapCell}; +use texture::{Font, Texture}; +use util::{Orientation, Side, Sprite, Step}; +use vec2::Vec2; + +use std::rc::Rc; +use std::time::Instant; + +fn main() { + let mut framebuffer = Framebuffer::new(600, 800); + let mut camera = Camera { + position: Vec2 { x: 3.0, y: 12.0 }, + direction: Vec2 { x: -1.0, y: 0.0 }, + plane: Vec2 { + x: 0.0, + y: (framebuffer.width as f64 / framebuffer.height as f64) / 2.0, + }, + height: 0.0, + }; + + let mut time = Instant::now(); + let mut old_time: Instant; + + let font = Font::load_from_bmp(&include_bytes!("../res/font.bmp").to_vec(), 8); + let textures: Vec<Rc<Texture>> = vec![ + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/eagle.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/redbrick.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/purplestone.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/greystone.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/bluestone.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/mossy.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/wood.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/colorstone.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/barrel.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/pillar.bmp").to_vec(), + )), + Rc::new(Texture::load_from_bmp( + &include_bytes!("../res/textures/greenlight.bmp").to_vec(), + )), + ]; + + let world = Map::new(&textures); + + let mut sprites = vec![ + Sprite { + position: Vec2 { x: 3.0, y: 8.0 }, + texture: textures[8].clone(), + scale_factor: Vec2 { x: 1.0, y: 1.0 }, + vertical_offset: 0.0, + distance_from_camera: 0.0, + }, + Sprite { + position: Vec2 { x: 3.0, y: 6.0 }, + texture: textures[8].clone(), + scale_factor: Vec2 { x: 1.5, y: 1.5 }, + vertical_offset: -150.0, + distance_from_camera: 0.0, + }, + ]; + + let mut window = Window::new( + "Raycasting Demo", + framebuffer.width, + framebuffer.height, + WindowOptions::default(), + ) + .unwrap(); + window.limit_update_rate(Some(std::time::Duration::from_micros(16600))); + + while window.is_open() { + framebuffer.draw_floor_and_ceiling(&camera, &world); + for x in 0..framebuffer.width { + let mut side_dist = Vec2::<f64>::new(); + let mut ray = camera.get_ray(x, framebuffer.width); + let mut map = camera.position.as_usize(); + let delta_dist = Vec2 { + x: (1.0 / ray.direction.x).abs(), + y: (1.0 / ray.direction.y).abs(), + }; + let mut side: Side; + let step = Vec2 { + x: Step::from(ray.direction.x < 0.0), + y: Step::from(ray.direction.y < 0.0), + }; + if ray.direction.x < 0.0 { + side_dist.x = (camera.position.x - (map.x as f64)) * delta_dist.x; + } else { + side_dist.x = ((map.x as f64) + 1.0 - camera.position.x) * delta_dist.x; + } + if ray.direction.y < 0.0 { + side_dist.y = (camera.position.y - (map.y as f64)) * delta_dist.y; + } else { + side_dist.y = ((map.y as f64) + 1.0 - camera.position.y) * delta_dist.y; + } + + loop { + if side_dist.x < side_dist.y { + side_dist.x += delta_dist.x; + match step.x { + Step::Left => map.x -= 1, + Step::Right => map.x += 1, + } + side = Side::X; + } else { + side_dist.y += delta_dist.y; + match step.y { + Step::Left => map.y -= 1, + Step::Right => map.y += 1, + } + side = Side::Y; + } + match world.at(&map) { + Some(MapCell::Wall { texture }) => { + ray.intersections.push(Intersection { + side: side.clone(), + step: step.clone(), + map_coordinates: map.clone(), + wall_offset: Vec2 { x: 0.0, y: 0.0 }, + }); + if !texture.has_transparency { + break; + } + } + Some(MapCell::ThinWall { + texture, + orientation, + offset_into_cell, + ceiling_texture: _, + floor_texture: _, + }) => match orientation { + Orientation::XAxis => { + if side_dist.x - (delta_dist.x / (1.0 / offset_into_cell)) > side_dist.y + { + continue; + } else { + ray.intersections.push(Intersection { + side: Side::X, + step: step.clone(), + map_coordinates: map.clone(), + wall_offset: Vec2 { + x: offset_into_cell * step.x.value() as f64, + y: 0.0, + }, + }); + if !texture.has_transparency { + break; + } + } + } + Orientation::YAxis => { + if side_dist.y - (delta_dist.y / (1.0 / offset_into_cell)) > side_dist.x + { + continue; + } else { + ray.intersections.push(Intersection { + side: Side::Y, + step: step.clone(), + map_coordinates: map.clone(), + wall_offset: Vec2 { + x: 0.0, + y: offset_into_cell * step.y.value() as f64, + }, + }); + if !texture.has_transparency { + break; + } + } + } + }, + Some(MapCell::Empty { + ceiling_texture: _, + floor_texture: _, + fog: _, + fog_color: _, + }) => continue, + None => break, + } + } + for intersection in &ray.intersections { + let perp_wall_dist = match &intersection.side { + Side::X => { + ((intersection.map_coordinates.x as f64) - camera.position.x + + intersection.wall_offset.x + + ((1 - intersection.step.x.value()) as f64) / 2.0) + / ray.direction.x + } + Side::Y => { + ((intersection.map_coordinates.y as f64) - camera.position.y + + intersection.wall_offset.y + + ((1 - intersection.step.y.value()) as f64) / 2.0) + / ray.direction.y + } + }; + if let Some(cell) = world.at(&intersection.map_coordinates) { + framebuffer.draw_wall( + &camera, + x, + perp_wall_dist, + cell, + &intersection.side, + &ray, + &world, + ); + } + } + } + framebuffer.draw_sprites(&camera, &mut sprites, &world); + old_time = time; + time = Instant::now(); + let frame_time = (time - old_time).as_secs_f64(); + framebuffer.write_ascii_string( + 0, + 0, + &format!("{:.3}", (1.0 / frame_time)).into_bytes(), + &font, + 0x00FFFFFF, + ); + framebuffer.write_ascii_string( + 0, + font.glyph_size, + &format!("x: {:.3}, y: {:.3}", camera.position.x, camera.position.y).into_bytes(), + &font, + 0x00FFFFFF, + ); + camera.update_position_with_keys(frame_time, &window, &world); + window + .update_with_buffer(&framebuffer.pixels, framebuffer.width, framebuffer.height) + .unwrap(); + framebuffer.clear_z_buffer(); + } +} |