use neurodoom::map::MapData;
use neurodoom::math::*;
use neurodoom::render::sprites::ThingRef;
use neurodoom::render::{Renderer, SemanticClass};
use neurodoom::tables::FINESINE;
use neurodoom::texture::TextureData;
use neurodoom::wad::Wad;
fn load_wad() -> Vec<u8> {
let path = std::env::var("DOOM_WAD")
.unwrap_or_else(|_| "doom1.wad".to_string());
std::fs::read(&path).unwrap_or_else(|e| panic!("failed to read WAD at {path}: {e}"))
}
fn setup() -> (MapData, TextureData, i32, i32, u32) {
let data = load_wad();
let wad = Wad::parse(&data).unwrap();
let mut map = MapData::load(&wad, "E1M1").unwrap();
let textures = TextureData::load(&wad).unwrap();
map.resolve_textures(&textures);
let p1 = map.things.iter().find(|t| t.type_num == 1).unwrap();
let x = (p1.x as Fixed) << FRACBITS;
let y = (p1.y as Fixed) << FRACBITS;
let angle = ((p1.angle as u64) * ANG90 as u64 / 90) as u32;
(map, textures, x, y, angle)
}
#[test]
fn render_e1m1_no_panic() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
}
#[test]
fn framebuffer_not_empty() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
renderer.indexed_to_rgba(&textures);
let nonzero = renderer.rgba.iter().filter(|&&b| b != 0).count();
assert!(nonzero > 1000, "framebuffer seems mostly empty: {nonzero} nonzero bytes");
}
#[test]
fn semantic_has_walls() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let wall_count = renderer
.semantic
.iter()
.filter(|&&c| c == SemanticClass::Wall as u8)
.count();
assert!(wall_count > 0, "no Wall pixels in semantic buffer");
}
#[test]
fn semantic_has_doors() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let door_count = renderer
.semantic
.iter()
.filter(|&&c| c == SemanticClass::Door as u8)
.count();
println!("Door pixels: {door_count}");
}
#[test]
fn depth_buffer_has_values() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let nonzero = renderer.depth.iter().filter(|&&d| d != 0).count();
assert!(nonzero > 0, "depth buffer is all zeros");
}
#[test]
fn semantic_has_floor() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let floor_count = renderer
.semantic
.iter()
.filter(|&&c| c == SemanticClass::Floor as u8)
.count();
assert!(floor_count > 0, "no Floor pixels in semantic buffer");
}
#[test]
fn semantic_has_ceiling() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let ceiling_count = renderer
.semantic
.iter()
.filter(|&&c| c == SemanticClass::Ceiling as u8)
.count();
assert!(ceiling_count > 0, "no Ceiling pixels in semantic buffer");
}
#[test]
fn depth_increases_with_distance() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let center_x = SCREENWIDTH / 2;
let center_y = SCREENHEIGHT / 2;
let idx = center_y * SCREENWIDTH + center_x;
let center_depth = renderer.depth[idx];
println!("Center pixel depth: {center_depth}");
if renderer.semantic[idx] == SemanticClass::Wall as u8 {
assert!(center_depth > 0, "wall at center should have positive depth");
}
}
#[test]
fn sprites_render_items() {
let (map, textures, x, y, angle) = setup();
let mut renderer = Renderer::new();
let view_z = map.sectors[map.subsectors[0].sector as usize].floor_height + 41 * FRACUNIT;
renderer.render_player_view(&map, &textures, &neurodoom::render::ViewParams { x, y, z: view_z, angle });
let ang_idx = (angle >> ANGLETOFINESHIFT) as usize;
let thing_x = x + fixed_mul(48 * FRACUNIT, neurodoom::math::finecosine(ang_idx));
let thing_y = y + fixed_mul(48 * FRACUNIT, FINESINE[ang_idx]);
let thing_z = map.sectors[map.subsectors[0].sector as usize].floor_height;
renderer.floor_clip.fill(SCREENHEIGHT as i16);
renderer.ceiling_clip.fill(-1);
renderer.drawsegs.clear();
assert!(!textures.sprites.is_empty(), "no sprite defs loaded");
let things = [ThingRef {
x: thing_x,
y: thing_y,
z: thing_z,
angle: 0,
sprite_num: 0,
frame: 0,
flags: 0,
mobj_type: 100, light_level: 160,
}];
renderer.draw_things(&things, &textures);
assert!(!renderer.vissprites.is_empty(), "sprite was not projected");
let item_count = renderer
.semantic
.iter()
.filter(|&&c| c == SemanticClass::Item as u8)
.count();
assert!(item_count > 0, "no Item pixels drawn (vissprites: {})", renderer.vissprites.len());
}