Factor out Z-buffering into a separate object

This commit is contained in:
Patrick Walton 2019-01-06 11:32:17 -08:00
parent b2432b3a7f
commit 8854ffb5ec
1 changed files with 62 additions and 26 deletions

View File

@ -1084,6 +1084,7 @@ impl BuiltScene {
} }
} }
#[inline(never)]
fn from_objects_and_shaders(view_box: &Rect<f32>, fn from_objects_and_shaders(view_box: &Rect<f32>,
objects: &[BuiltObject], objects: &[BuiltObject],
shaders: Vec<ObjectShader>) shaders: Vec<ObjectShader>)
@ -1091,32 +1092,10 @@ impl BuiltScene {
let mut scene = BuiltScene::new(view_box, shaders); let mut scene = BuiltScene::new(view_box, shaders);
scene.add_batch(); scene.add_batch();
let tile_area = scene.tile_rect.size.width as usize * scene.tile_rect.size.height as usize;
let mut z_buffer = vec![0; tile_area];
// Initialize z-buffer, and fill solid tiles. // Initialize z-buffer, and fill solid tiles.
for (object_index, object) in objects.iter().enumerate().rev() { let mut z_buffer = ZBuffer::new(&scene.tile_rect.size);
for solid_tile_index in object.solid_tiles.ones() { z_buffer.cull(&scene, objects);
let tile = &object.tiles[solid_tile_index]; z_buffer.push_solid_tiles(&mut scene, objects);
if tile.backdrop == 0 {
// Tile is transparent and can't be solid.
continue
}
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
if z_buffer[scene_tile_index as usize] > object_index as u32 {
// Occluded.
continue
}
z_buffer[scene_tile_index as usize] = object_index as u32;
scene.solid_tiles.push(SolidTileScenePrimitive {
tile_x: tile.tile_x,
tile_y: tile.tile_y,
shader: object.shader,
});
}
}
// Build batches. // Build batches.
let mut object_tile_index_to_scene_mask_tile_index = vec![]; let mut object_tile_index_to_scene_mask_tile_index = vec![];
@ -1134,7 +1113,7 @@ impl BuiltScene {
// Cull occluded tiles. // Cull occluded tiles.
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y); let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
if z_buffer[scene_tile_index as usize] as usize > object_index { if !z_buffer.test(scene_tile_index, object_index as u16) {
object_tile_index_to_scene_mask_tile_index.push(BLANK); object_tile_index_to_scene_mask_tile_index.push(BLANK);
continue; continue;
} }
@ -1199,6 +1178,63 @@ impl BuiltScene {
} }
} }
// Culling
struct ZBuffer {
buffer: Vec<u16>,
}
impl ZBuffer {
fn new(tile_size: &Size2D<i16>) -> ZBuffer {
ZBuffer {
buffer: vec![0; tile_size.width as usize * tile_size.height as usize],
}
}
fn test(&self, scene_tile_index: u32, object_index: u16) -> bool {
self.buffer[scene_tile_index as usize] < object_index + 1
}
#[inline(never)]
fn cull(&mut self, scene: &BuiltScene, objects: &[BuiltObject]) {
for (object_index, object) in objects.iter().enumerate().rev() {
for solid_tile_index in object.solid_tiles.ones() {
let tile = &object.tiles[solid_tile_index];
if tile.backdrop == 0 {
// Tile is transparent and can't be solid.
continue
}
let scene_tile_index = scene.scene_tile_index(tile.tile_x, tile.tile_y);
if self.test(scene_tile_index, object_index as u16) {
self.buffer[scene_tile_index as usize] = (object_index + 1) as u16;
}
}
}
}
#[inline(never)]
fn push_solid_tiles(&self, scene: &mut BuiltScene, objects: &[BuiltObject]) {
let tile_rect = scene.tile_rect;
for scene_tile_y in 0..tile_rect.size.height {
for scene_tile_x in 0..tile_rect.size.width {
let scene_tile_index = scene_tile_y as usize * tile_rect.size.width as usize +
scene_tile_x as usize;
let depth = self.buffer[scene_tile_index];
if depth == 0 {
continue
}
let object_index = (depth - 1) as usize;
scene.solid_tiles.push(SolidTileScenePrimitive {
tile_x: scene_tile_x + tile_rect.origin.x,
tile_y: scene_tile_y + tile_rect.origin.y,
shader: objects[object_index].shader,
});
}
}
}
}
// Primitives // Primitives
#[derive(Debug)] #[derive(Debug)]