2020-09-26 13:55:01 +00:00
|
|
|
use crate::{span, vol::ReadVol};
|
2019-04-23 22:48:31 +00:00
|
|
|
use vek::*;
|
|
|
|
|
2020-09-26 13:55:01 +00:00
|
|
|
pub trait RayUntil<V> = FnMut(&V) -> bool;
|
|
|
|
pub trait RayForEach<V> = FnMut(&V, Vec3<i32>);
|
2019-04-23 22:48:31 +00:00
|
|
|
|
2020-07-05 12:39:28 +00:00
|
|
|
pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach<V::Vox>> {
|
2019-04-23 22:48:31 +00:00
|
|
|
vol: &'a V,
|
|
|
|
from: Vec3<f32>,
|
|
|
|
to: Vec3<f32>,
|
|
|
|
until: F,
|
2019-08-07 17:17:04 +00:00
|
|
|
for_each: Option<G>,
|
2019-04-23 22:48:31 +00:00
|
|
|
max_iter: usize,
|
2019-05-12 05:37:10 +00:00
|
|
|
ignore_error: bool,
|
2019-04-23 22:48:31 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 12:39:28 +00:00
|
|
|
impl<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach<V::Vox>> Ray<'a, V, F, G> {
|
2019-04-23 22:48:31 +00:00
|
|
|
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
|
|
|
|
Self {
|
|
|
|
vol,
|
|
|
|
from,
|
|
|
|
to,
|
|
|
|
until,
|
2019-08-07 17:17:04 +00:00
|
|
|
for_each: None,
|
2019-04-23 22:48:31 +00:00
|
|
|
max_iter: 100,
|
2019-05-12 05:37:10 +00:00
|
|
|
ignore_error: false,
|
2019-04-23 22:48:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
pub fn until(self, f: F) -> Ray<'a, V, F, G> { Ray { until: f, ..self } }
|
2019-04-23 22:48:31 +00:00
|
|
|
|
2020-07-05 12:39:28 +00:00
|
|
|
pub fn for_each<H: RayForEach<V::Vox>>(self, f: H) -> Ray<'a, V, F, H> {
|
2019-08-07 17:17:04 +00:00
|
|
|
Ray {
|
|
|
|
for_each: Some(f),
|
|
|
|
vol: self.vol,
|
|
|
|
from: self.from,
|
|
|
|
to: self.to,
|
|
|
|
until: self.until,
|
|
|
|
max_iter: self.max_iter,
|
|
|
|
ignore_error: self.ignore_error,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-23 22:48:31 +00:00
|
|
|
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
|
|
|
self.max_iter = max_iter;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-05-12 05:37:10 +00:00
|
|
|
pub fn ignore_error(mut self) -> Self {
|
|
|
|
self.ignore_error = true;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
common: Rework volume API
See the doc comments in `common/src/vol.rs` for more information on
the API itself.
The changes include:
* Consistent `Err`/`Error` naming.
* Types are named `...Error`.
* `enum` variants are named `...Err`.
* Rename `VolMap{2d, 3d}` -> `VolGrid{2d, 3d}`. This is in preparation
to an upcoming change where a “map” in the game related sense will
be added.
* Add volume iterators. There are two types of them:
* _Position_ iterators obtained from the trait `IntoPosIterator`
using the method
`fn pos_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...`
which returns an iterator over `Vec3<i32>`.
* _Volume_ iterators obtained from the trait `IntoVolIterator`
using the method
`fn vol_iter(self, lower_bound: Vec3<i32>, upper_bound: Vec3<i32>) -> ...`
which returns an iterator over `(Vec3<i32>, &Self::Vox)`.
Those traits will usually be implemented by references to volume
types (i.e. `impl IntoVolIterator<'a> for &'a T` where `T` is some
type which usually implements several volume traits, such as `Chunk`).
* _Position_ iterators iterate over the positions valid for that
volume.
* _Volume_ iterators do the same but return not only the position
but also the voxel at that position, in each iteration.
* Introduce trait `RectSizedVol` for the use case which we have with
`Chonk`: A `Chonk` is sized only in x and y direction.
* Introduce traits `RasterableVol`, `RectRasterableVol`
* `RasterableVol` represents a volume that is compile-time sized and has
its lower bound at `(0, 0, 0)`. The name `RasterableVol` was chosen
because such a volume can be used with `VolGrid3d`.
* `RectRasterableVol` represents a volume that is compile-time sized at
least in x and y direction and has its lower bound at `(0, 0, z)`.
There's no requirement on he lower bound or size in z direction.
The name `RectRasterableVol` was chosen because such a volume can be
used with `VolGrid2d`.
2019-09-03 22:23:29 +00:00
|
|
|
pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Error>) {
|
2020-09-07 04:59:16 +00:00
|
|
|
span!(_guard, "cast", "Ray::cast");
|
2019-04-23 22:48:31 +00:00
|
|
|
// TODO: Fully test this!
|
|
|
|
|
|
|
|
const PLANCK: f32 = 0.001;
|
|
|
|
|
|
|
|
let mut dist = 0.0;
|
|
|
|
let dir = (self.to - self.from).normalized();
|
2019-05-05 15:17:57 +00:00
|
|
|
let max = (self.to - self.from).magnitude();
|
2019-04-23 22:48:31 +00:00
|
|
|
|
|
|
|
for _ in 0..self.max_iter {
|
2019-06-06 14:48:41 +00:00
|
|
|
let pos = self.from + dir * dist;
|
|
|
|
let ipos = pos.map(|e| e.floor() as i32);
|
2019-04-23 22:48:31 +00:00
|
|
|
|
2019-05-17 09:22:32 +00:00
|
|
|
// Allow one iteration above max.
|
2019-05-12 17:43:55 +00:00
|
|
|
if dist > max {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-05 12:39:28 +00:00
|
|
|
let vox = self.vol.get(ipos);
|
|
|
|
|
2019-08-07 17:17:04 +00:00
|
|
|
// for_each
|
|
|
|
if let Some(g) = &mut self.for_each {
|
2020-07-05 12:39:28 +00:00
|
|
|
if let Ok(vox) = vox {
|
|
|
|
g(vox, ipos);
|
|
|
|
}
|
2019-08-07 17:17:04 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 12:39:28 +00:00
|
|
|
match vox.map(|vox| (vox, (self.until)(vox))) {
|
2019-04-24 17:33:04 +00:00
|
|
|
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
2019-05-12 05:37:10 +00:00
|
|
|
Err(err) if !self.ignore_error => return (dist, Err(err)),
|
2020-02-01 20:39:39 +00:00
|
|
|
_ => {},
|
2019-04-23 22:48:31 +00:00
|
|
|
}
|
|
|
|
|
2019-04-29 20:37:19 +00:00
|
|
|
let deltas =
|
2019-05-05 15:17:57 +00:00
|
|
|
(dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.abs().fract())) / dir;
|
2019-04-23 22:48:31 +00:00
|
|
|
|
|
|
|
dist += deltas.reduce(f32::min).max(PLANCK);
|
|
|
|
}
|
|
|
|
|
2019-04-24 17:33:04 +00:00
|
|
|
(dist, Ok(None))
|
2019-04-23 22:48:31 +00:00
|
|
|
}
|
|
|
|
}
|