2019-01-14 17:20:36 -05:00
|
|
|
// pathfinder/renderer/src/z_buffer.rs
|
|
|
|
//
|
|
|
|
// Copyright © 2019 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Software occlusion culling.
|
|
|
|
|
2020-02-07 14:46:20 -05:00
|
|
|
use crate::gpu_data::SolidTileVertex;
|
2020-02-04 01:24:34 -05:00
|
|
|
use crate::paint::PaintMetadata;
|
2019-05-14 18:21:15 -04:00
|
|
|
use crate::scene::PathObject;
|
2019-04-11 22:38:31 -04:00
|
|
|
use crate::tile_map::DenseTileMap;
|
2019-01-14 17:20:36 -05:00
|
|
|
use crate::tiles;
|
2019-06-21 13:06:19 -04:00
|
|
|
use pathfinder_geometry::rect::RectF;
|
2020-02-05 16:59:32 -05:00
|
|
|
use pathfinder_geometry::vector::Vector2I;
|
2019-03-29 22:11:38 -04:00
|
|
|
use std::ops::Range;
|
2019-01-14 17:20:36 -05:00
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
|
|
|
|
|
|
|
pub struct ZBuffer {
|
2019-04-11 22:38:31 -04:00
|
|
|
buffer: DenseTileMap<AtomicUsize>,
|
2019-01-14 17:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ZBuffer {
|
2019-05-29 22:13:42 -04:00
|
|
|
pub fn new(view_box: RectF) -> ZBuffer {
|
2019-01-14 17:20:36 -05:00
|
|
|
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
2019-04-29 19:45:29 -04:00
|
|
|
ZBuffer {
|
|
|
|
buffer: DenseTileMap::from_builder(|_| AtomicUsize::new(0), tile_rect),
|
|
|
|
}
|
2019-01-14 17:20:36 -05:00
|
|
|
}
|
|
|
|
|
2019-06-03 15:39:29 -04:00
|
|
|
pub fn test(&self, coords: Vector2I, object_index: u32) -> bool {
|
2019-04-11 22:38:31 -04:00
|
|
|
let tile_index = self.buffer.coords_to_index_unchecked(coords);
|
|
|
|
let existing_depth = self.buffer.data[tile_index as usize].load(AtomicOrdering::SeqCst);
|
2019-01-14 17:20:36 -05:00
|
|
|
existing_depth < object_index as usize + 1
|
|
|
|
}
|
|
|
|
|
2019-06-03 15:39:29 -04:00
|
|
|
pub fn update(&self, coords: Vector2I, object_index: u16) {
|
2019-04-11 22:38:31 -04:00
|
|
|
let tile_index = self.buffer.coords_to_index_unchecked(coords);
|
|
|
|
let mut old_depth = self.buffer.data[tile_index].load(AtomicOrdering::SeqCst);
|
2019-01-14 17:20:36 -05:00
|
|
|
let new_depth = (object_index + 1) as usize;
|
|
|
|
while old_depth < new_depth {
|
2019-04-11 22:38:31 -04:00
|
|
|
let prev_depth = self.buffer.data[tile_index].compare_and_swap(
|
2019-01-14 17:20:36 -05:00
|
|
|
old_depth,
|
|
|
|
new_depth,
|
|
|
|
AtomicOrdering::SeqCst,
|
|
|
|
);
|
|
|
|
if prev_depth == old_depth {
|
|
|
|
// Successfully written.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
old_depth = prev_depth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-04 01:24:34 -05:00
|
|
|
pub fn build_solid_tiles(&self,
|
|
|
|
paths: &[PathObject],
|
|
|
|
paint_metadata: &[PaintMetadata],
|
|
|
|
object_range: Range<u32>)
|
2020-02-07 14:46:20 -05:00
|
|
|
-> Vec<SolidTileVertex> {
|
2019-01-14 17:20:36 -05:00
|
|
|
let mut solid_tiles = vec![];
|
2019-04-11 22:38:31 -04:00
|
|
|
for tile_index in 0..self.buffer.data.len() {
|
|
|
|
let depth = self.buffer.data[tile_index].load(AtomicOrdering::Relaxed);
|
|
|
|
if depth == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let tile_coords = self.buffer.index_to_coords(tile_index);
|
|
|
|
let object_index = (depth - 1) as u32;
|
|
|
|
if object_index < object_range.start || object_index >= object_range.end {
|
|
|
|
continue;
|
2019-01-14 17:20:36 -05:00
|
|
|
}
|
2019-05-14 17:28:21 -04:00
|
|
|
|
2020-02-04 01:24:34 -05:00
|
|
|
let paint_id = paths[object_index as usize].paint();
|
2020-02-07 14:46:20 -05:00
|
|
|
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
2019-05-14 17:28:21 -04:00
|
|
|
|
2020-02-07 14:46:20 -05:00
|
|
|
let tile_position = tile_coords + self.buffer.rect.origin();
|
|
|
|
let object_index = object_index as u16;
|
|
|
|
|
|
|
|
solid_tiles.extend_from_slice(&[
|
|
|
|
SolidTileVertex::new(tile_position, object_index, paint_metadata),
|
|
|
|
SolidTileVertex::new(tile_position + Vector2I::new(1, 0),
|
|
|
|
object_index,
|
|
|
|
paint_metadata),
|
|
|
|
SolidTileVertex::new(tile_position + Vector2I::new(0, 1),
|
|
|
|
object_index,
|
|
|
|
paint_metadata),
|
|
|
|
SolidTileVertex::new(tile_position + Vector2I::new(1, 1),
|
|
|
|
object_index,
|
|
|
|
paint_metadata),
|
|
|
|
]);
|
2019-01-14 17:20:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
solid_tiles
|
|
|
|
}
|
|
|
|
}
|
2019-05-14 17:28:21 -04:00
|
|
|
|
2020-02-07 14:46:20 -05:00
|
|
|
impl SolidTileVertex {
|
|
|
|
fn new(tile_position: Vector2I, object_index: u16, paint_metadata: &PaintMetadata)
|
|
|
|
-> SolidTileVertex {
|
|
|
|
let color_uv = paint_metadata.calculate_tex_coords(tile_position).scale(65535.0).to_i32();
|
|
|
|
SolidTileVertex {
|
|
|
|
tile_x: tile_position.x() as i16,
|
|
|
|
tile_y: tile_position.y() as i16,
|
2019-05-14 17:28:21 -04:00
|
|
|
object_index: object_index,
|
2020-02-07 14:46:20 -05:00
|
|
|
color_u: color_uv.x() as u16,
|
|
|
|
color_v: color_uv.y() as u16,
|
2019-06-05 17:35:46 -04:00
|
|
|
pad: 0,
|
2019-05-14 17:28:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|