veloren/voxygen/src/mesh/segment.rs

173 lines
6.1 KiB
Rust
Raw Normal View History

use crate::{
mesh::{vol, Meshable},
2019-08-19 20:09:35 +00:00
render::{self, FigurePipeline, Mesh, SpritePipeline},
};
use common::{
2020-04-24 14:20:16 +00:00
figure::Cell,
2019-08-04 19:54:08 +00:00
util::{linear_to_srgb, srgb_to_linear},
2020-04-24 14:20:16 +00:00
vol::{BaseVol, ReadVol, SizedVol, Vox},
};
use vek::*;
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
2019-08-19 20:09:35 +00:00
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
2020-04-24 14:20:16 +00:00
impl<'a, V: 'a> Meshable<'a, FigurePipeline, FigurePipeline> for V
where
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
/* TODO: Use VolIterator instead of manually iterating
* &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>,
* &'a V: BaseVol<Vox=Cell>, */
{
type Pipeline = FigurePipeline;
2020-04-24 14:20:16 +00:00
type Supplement = (Vec3<f32>, Vec3<f32>);
type TranslucentPipeline = FigurePipeline;
#[allow(clippy::needless_range_loop)] // TODO: Pending review in #587
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
fn generate_mesh(
2020-04-24 14:20:16 +00:00
&'a self,
(offs, scale): Self::Supplement,
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut mesh = Mesh::new();
2020-04-24 14:20:16 +00:00
let vol_iter = (self.lower_bound().x..self.upper_bound().x)
.map(|i| {
(self.lower_bound().y..self.upper_bound().y).map(move |j| {
(self.lower_bound().z..self.upper_bound().z).map(move |k| Vec3::new(i, j, k))
})
})
.flatten()
.flatten()
.map(|pos| (pos, self.get(pos).map(|x| *x).unwrap_or(Vox::empty())));
2020-04-24 14:20:16 +00:00
for (pos, vox) in vol_iter {
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
if let Some(col) = vox.get_color() {
vol::push_vox_verts(
&mut mesh,
faces_to_make(self, pos, true, |vox| vox.is_empty()),
offs + pos.map(|e| e as f32),
2019-09-27 10:06:32 +00:00
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|origin, norm, col, light, ao| {
2019-08-04 19:54:08 +00:00
FigureVertex::new(
2020-04-24 14:20:16 +00:00
origin * scale,
2019-08-04 19:54:08 +00:00
norm,
linear_to_srgb(srgb_to_linear(col) * light),
ao,
2019-08-04 19:54:08 +00:00
0,
)
2019-06-19 14:55:26 +00:00
},
2019-09-24 06:03:40 +00:00
&{
let mut ls = [[[None; 3]; 3]; 3];
2019-09-24 06:03:40 +00:00
for x in 0..3 {
for y in 0..3 {
for z in 0..3 {
2020-04-23 14:01:37 +00:00
ls[z][y][x] = self
2019-09-24 06:03:40 +00:00
.get(pos + Vec3::new(x as i32, y as i32, z as i32) - 1)
.map(|v| v.is_empty())
.unwrap_or(true)
2020-04-23 14:01:37 +00:00
.then_some(1.0);
2019-09-24 06:03:40 +00:00
}
}
}
ls
},
);
}
}
(mesh, Mesh::new())
}
}
2019-08-19 20:09:35 +00:00
2020-04-24 14:20:16 +00:00
impl<'a, V: 'a> Meshable<'a, SpritePipeline, SpritePipeline> for V
where
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
/* TODO: Use VolIterator instead of manually iterating
* &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>,
* &'a V: BaseVol<Vox=Cell>, */
{
2019-08-19 20:09:35 +00:00
type Pipeline = SpritePipeline;
2020-04-24 14:20:16 +00:00
type Supplement = (Vec3<f32>, Vec3<f32>);
type TranslucentPipeline = SpritePipeline;
2019-08-19 20:09:35 +00:00
#[allow(clippy::needless_range_loop)] // TODO: Pending review in #587
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
2019-08-19 20:09:35 +00:00
fn generate_mesh(
2020-04-24 14:20:16 +00:00
&'a self,
(offs, scale): Self::Supplement,
2019-08-19 20:09:35 +00:00
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut mesh = Mesh::new();
2020-04-24 14:20:16 +00:00
let vol_iter = (self.lower_bound().x..self.upper_bound().x)
.map(|i| {
(self.lower_bound().y..self.upper_bound().y).map(move |j| {
(self.lower_bound().z..self.upper_bound().z).map(move |k| Vec3::new(i, j, k))
})
})
.flatten()
.flatten()
.map(|pos| (pos, self.get(pos).map(|x| *x).unwrap_or(Vox::empty())));
2020-04-24 14:20:16 +00:00
for (pos, vox) in vol_iter {
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
if let Some(col) = vox.get_color() {
2019-08-19 20:09:35 +00:00
vol::push_vox_verts(
&mut mesh,
faces_to_make(self, pos, true, |vox| vox.is_empty()),
2019-08-19 20:09:35 +00:00
offs + pos.map(|e| e as f32),
2019-09-27 10:06:32 +00:00
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|origin, norm, col, light, ao| {
2019-08-19 20:09:35 +00:00
SpriteVertex::new(
2020-04-24 14:20:16 +00:00
origin * scale,
2019-08-19 20:09:35 +00:00
norm,
linear_to_srgb(srgb_to_linear(col) * light),
ao,
2019-08-19 20:09:35 +00:00
)
},
2020-04-14 01:32:58 +00:00
&{
let mut ls = [[[None; 3]; 3]; 3];
2020-04-14 01:32:58 +00:00
for x in 0..3 {
for y in 0..3 {
for z in 0..3 {
2020-04-23 14:01:37 +00:00
ls[z][y][x] = self
2020-04-14 01:32:58 +00:00
.get(pos + Vec3::new(x as i32, y as i32, z as i32) - 1)
.map(|v| v.is_empty())
.unwrap_or(true)
2020-04-23 14:01:37 +00:00
.then_some(1.0);
2020-04-14 01:32:58 +00:00
}
}
}
ls
},
2019-08-19 20:09:35 +00:00
);
}
}
(mesh, Mesh::new())
}
}
/// Use the 6 voxels/blocks surrounding the one at the specified position
/// to detemine which faces should be drawn
fn faces_to_make<V: ReadVol>(
seg: &V,
pos: Vec3<i32>,
error_makes_face: bool,
should_add: impl Fn(&V::Vox) -> bool,
) -> [bool; 6] {
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
let make_face = |offset| {
seg.get(pos + offset)
.map(|v| should_add(v))
.unwrap_or(error_makes_face)
};
[
make_face(-x),
make_face(x),
make_face(-y),
make_face(y),
make_face(-z),
make_face(z),
]
}