2019-06-05 15:22:06 +00:00
|
|
|
use crate::{
|
|
|
|
mesh::{vol, Meshable},
|
2019-08-14 21:28:37 +00:00
|
|
|
render::{self, FluidPipeline, Mesh, TerrainPipeline},
|
2019-06-05 15:22:06 +00:00
|
|
|
};
|
2019-01-23 20:01:58 +00:00
|
|
|
use common::{
|
2019-09-26 12:34:15 +00:00
|
|
|
terrain::Block,
|
2019-09-24 00:15:38 +00:00
|
|
|
vol::{ReadVol, RectRasterableVol, Vox},
|
2019-09-24 06:42:09 +00:00
|
|
|
volumes::vol_grid_2d::VolGrid2d,
|
2019-01-23 20:01:58 +00:00
|
|
|
};
|
2019-09-24 00:15:38 +00:00
|
|
|
use hashbrown::{HashMap, HashSet};
|
2019-06-05 15:22:06 +00:00
|
|
|
use std::fmt::Debug;
|
|
|
|
use vek::*;
|
2019-01-23 20:01:58 +00:00
|
|
|
|
|
|
|
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
2019-08-14 21:28:37 +00:00
|
|
|
type FluidVertex = <FluidPipeline as render::Pipeline>::Vertex;
|
|
|
|
|
2019-09-24 00:15:38 +00:00
|
|
|
const DIRS: [Vec2<i32>; 4] = [
|
|
|
|
Vec2 { x: 1, y: 0 },
|
|
|
|
Vec2 { x: 0, y: 1 },
|
|
|
|
Vec2 { x: -1, y: 0 },
|
|
|
|
Vec2 { x: 0, y: -1 },
|
|
|
|
];
|
|
|
|
|
|
|
|
const DIRS_3D: [Vec3<i32>; 6] = [
|
|
|
|
Vec3 { x: 1, y: 0, z: 0 },
|
|
|
|
Vec3 { x: 0, y: 1, z: 0 },
|
|
|
|
Vec3 { x: 0, y: 0, z: 1 },
|
|
|
|
Vec3 { x: -1, y: 0, z: 0 },
|
|
|
|
Vec3 { x: 0, y: -1, z: 0 },
|
|
|
|
Vec3 { x: 0, y: 0, z: -1 },
|
|
|
|
];
|
|
|
|
|
|
|
|
fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
|
|
|
|
bounds: Aabb<i32>,
|
|
|
|
vol: &VolGrid2d<V>,
|
|
|
|
) -> impl Fn(Vec3<i32>) -> f32 {
|
|
|
|
let sunlight = 24;
|
|
|
|
|
|
|
|
let outer = Aabb {
|
|
|
|
min: bounds.min - sunlight,
|
|
|
|
max: bounds.max + sunlight,
|
|
|
|
};
|
|
|
|
|
2019-10-01 06:09:27 +00:00
|
|
|
let mut vol_cached = vol.cached();
|
2019-09-29 05:53:22 +00:00
|
|
|
|
2019-09-24 00:15:38 +00:00
|
|
|
let mut voids = HashMap::new();
|
|
|
|
let mut rays = vec![outer.size().d; outer.size().product() as usize];
|
|
|
|
for x in 0..outer.size().w {
|
|
|
|
for y in 0..outer.size().h {
|
|
|
|
let mut outside = true;
|
|
|
|
for z in (0..outer.size().d).rev() {
|
2019-10-01 06:09:27 +00:00
|
|
|
let block = vol_cached
|
|
|
|
.get(outer.min + Vec3::new(x, y, z))
|
2019-09-25 10:25:32 +00:00
|
|
|
.ok()
|
|
|
|
.copied()
|
|
|
|
.unwrap_or(Block::empty());
|
|
|
|
|
|
|
|
if !block.is_air() && outside {
|
2019-09-24 00:15:38 +00:00
|
|
|
rays[(outer.size().w * y + x) as usize] = z;
|
|
|
|
outside = false;
|
|
|
|
}
|
2019-09-25 10:25:32 +00:00
|
|
|
|
|
|
|
if (block.is_air() || block.is_fluid()) && !outside {
|
|
|
|
voids.insert(Vec3::new(x, y, z), None);
|
|
|
|
}
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut opens = HashSet::new();
|
2019-09-25 10:25:32 +00:00
|
|
|
'voids: for (pos, l) in &mut voids {
|
2019-09-24 00:15:38 +00:00
|
|
|
for dir in &DIRS {
|
|
|
|
let col = Vec2::<i32>::from(*pos) + dir;
|
|
|
|
if pos.z
|
|
|
|
> *rays
|
|
|
|
.get(((outer.size().w * col.y) + col.x) as usize)
|
|
|
|
.unwrap_or(&0)
|
|
|
|
{
|
|
|
|
*l = Some(sunlight - 1);
|
|
|
|
opens.insert(*pos);
|
2019-09-25 10:25:32 +00:00
|
|
|
continue 'voids;
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-25 10:25:32 +00:00
|
|
|
|
|
|
|
if pos.z
|
|
|
|
>= *rays
|
|
|
|
.get(((outer.size().w * pos.y) + pos.x) as usize)
|
|
|
|
.unwrap_or(&0)
|
|
|
|
{
|
|
|
|
*l = Some(sunlight - 1);
|
|
|
|
opens.insert(*pos);
|
|
|
|
}
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
|
|
|
|
2019-09-24 00:29:24 +00:00
|
|
|
while opens.len() > 0 {
|
2019-09-24 00:15:38 +00:00
|
|
|
let mut new_opens = HashSet::new();
|
|
|
|
for open in &opens {
|
|
|
|
let parent_l = voids[open].unwrap_or(0);
|
|
|
|
for dir in &DIRS_3D {
|
|
|
|
let other = *open + *dir;
|
|
|
|
if !opens.contains(&other) {
|
|
|
|
if let Some(l) = voids.get_mut(&other) {
|
|
|
|
if l.unwrap_or(0) < parent_l - 1 {
|
|
|
|
new_opens.insert(other);
|
|
|
|
}
|
|
|
|
*l = Some(parent_l - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
opens = new_opens;
|
|
|
|
}
|
|
|
|
|
|
|
|
move |wpos| {
|
|
|
|
let pos = wpos - outer.min;
|
|
|
|
rays.get(((outer.size().w * pos.y) + pos.x) as usize)
|
|
|
|
.and_then(|ray| if pos.z > *ray { Some(1.0) } else { None })
|
|
|
|
.or_else(|| {
|
|
|
|
if let Some(Some(l)) = voids.get(&pos) {
|
|
|
|
Some(*l as f32 / sunlight as f32)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap_or(0.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeline, FluidPipeline>
|
|
|
|
for VolGrid2d<V>
|
2019-08-19 20:09:35 +00:00
|
|
|
{
|
2019-05-17 17:44:30 +00:00
|
|
|
type Pipeline = TerrainPipeline;
|
2019-08-14 21:28:37 +00:00
|
|
|
type TranslucentPipeline = FluidPipeline;
|
2019-05-17 17:44:30 +00:00
|
|
|
type Supplement = Aabb<i32>;
|
|
|
|
|
2019-08-14 21:28:37 +00:00
|
|
|
fn generate_mesh(
|
|
|
|
&self,
|
|
|
|
range: Self::Supplement,
|
|
|
|
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
|
|
|
let mut opaque_mesh = Mesh::new();
|
|
|
|
let mut fluid_mesh = Mesh::new();
|
2019-05-17 17:44:30 +00:00
|
|
|
|
2019-09-24 06:42:09 +00:00
|
|
|
let light = calc_light(range, self);
|
2019-09-24 00:15:38 +00:00
|
|
|
|
2019-10-01 06:09:27 +00:00
|
|
|
let mut vol_cached = self.cached();
|
|
|
|
|
2019-05-17 21:19:32 +00:00
|
|
|
for x in range.min.x + 1..range.max.x - 1 {
|
|
|
|
for y in range.min.y + 1..range.max.y - 1 {
|
2019-09-24 09:01:50 +00:00
|
|
|
let mut lights = [[[0.0; 3]; 3]; 3];
|
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
|
|
|
for k in 0..3 {
|
|
|
|
lights[k][j][i] = light(
|
|
|
|
Vec3::new(x, y, range.min.z)
|
|
|
|
+ Vec3::new(i as i32, j as i32, k as i32)
|
|
|
|
- 1,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 06:09:27 +00:00
|
|
|
let get_color = |maybe_block: Option<&Block>| {
|
|
|
|
maybe_block
|
|
|
|
.filter(|vox| vox.is_opaque())
|
|
|
|
.and_then(|vox| vox.get_color())
|
|
|
|
.map(|col| Rgba::from_opaque(col))
|
|
|
|
.unwrap_or(Rgba::zero())
|
2019-09-24 09:01:50 +00:00
|
|
|
};
|
|
|
|
|
2019-09-27 10:06:32 +00:00
|
|
|
let mut colors = [[[Rgba::zero(); 3]; 3]; 3];
|
2019-09-24 09:01:50 +00:00
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
|
|
|
for k in 0..3 {
|
2019-10-01 06:09:27 +00:00
|
|
|
colors[k][j][i] = get_color(
|
|
|
|
vol_cached
|
|
|
|
.get(
|
|
|
|
Vec3::new(x, y, range.min.z)
|
|
|
|
+ Vec3::new(i as i32, j as i32, k as i32)
|
|
|
|
- 1,
|
|
|
|
)
|
|
|
|
.ok(),
|
2019-09-24 09:01:50 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for z in range.min.z..range.max.z {
|
2019-05-17 17:44:30 +00:00
|
|
|
let pos = Vec3::new(x, y, z);
|
2019-08-14 21:28:37 +00:00
|
|
|
let offs = (pos - (range.min + 1) * Vec3::new(1, 1, 0)).map(|e| e as f32);
|
|
|
|
|
2019-09-24 09:01:50 +00:00
|
|
|
lights[0] = lights[1];
|
|
|
|
lights[1] = lights[2];
|
2019-09-24 10:28:40 +00:00
|
|
|
colors[0] = colors[1];
|
|
|
|
colors[1] = colors[2];
|
|
|
|
|
2019-09-24 09:01:50 +00:00
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
|
|
|
lights[2][j][i] = light(pos + Vec3::new(i as i32, j as i32, 2) - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
2019-10-01 06:09:27 +00:00
|
|
|
colors[2][j][i] = get_color(
|
|
|
|
vol_cached
|
|
|
|
.get(pos + Vec3::new(i as i32, j as i32, 2) - 1)
|
|
|
|
.ok(),
|
|
|
|
);
|
2019-09-24 09:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 06:09:27 +00:00
|
|
|
let block = vol_cached.get(pos).ok();
|
2019-05-17 17:44:30 +00:00
|
|
|
|
2019-05-29 11:01:02 +00:00
|
|
|
// Create mesh polygons
|
2019-09-24 09:01:50 +00:00
|
|
|
if block.map(|vox| vox.is_opaque()).unwrap_or(false) {
|
2019-05-21 22:31:38 +00:00
|
|
|
vol::push_vox_verts(
|
2019-08-14 21:28:37 +00:00
|
|
|
&mut opaque_mesh,
|
2019-05-21 22:31:38 +00:00
|
|
|
self,
|
|
|
|
pos,
|
|
|
|
offs,
|
2019-09-24 09:01:50 +00:00
|
|
|
&colors,
|
2019-06-19 14:55:26 +00:00
|
|
|
|pos, norm, col, ao, light| {
|
2019-09-24 09:01:50 +00:00
|
|
|
TerrainVertex::new(pos, norm, col, light.min(ao))
|
2019-06-19 14:55:26 +00:00
|
|
|
},
|
2019-05-21 22:31:38 +00:00
|
|
|
false,
|
2019-09-24 09:01:50 +00:00
|
|
|
&lights,
|
2019-08-14 21:28:37 +00:00
|
|
|
|vox| !vox.is_opaque(),
|
|
|
|
);
|
2019-09-24 09:01:50 +00:00
|
|
|
} else if block.map(|vox| vox.is_fluid()).unwrap_or(false) {
|
2019-08-14 21:28:37 +00:00
|
|
|
vol::push_vox_verts(
|
|
|
|
&mut fluid_mesh,
|
|
|
|
self,
|
|
|
|
pos,
|
|
|
|
offs,
|
2019-09-24 09:01:50 +00:00
|
|
|
&colors,
|
2019-08-14 21:28:37 +00:00
|
|
|
|pos, norm, col, ao, light| {
|
2019-09-24 09:01:50 +00:00
|
|
|
FluidVertex::new(pos, norm, col, light.min(ao), 0.3)
|
2019-08-14 21:28:37 +00:00
|
|
|
},
|
|
|
|
false,
|
2019-09-24 09:01:50 +00:00
|
|
|
&lights,
|
2019-08-14 21:28:37 +00:00
|
|
|
|vox| vox.is_air(),
|
2019-05-21 22:31:38 +00:00
|
|
|
);
|
2019-05-17 17:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-14 21:28:37 +00:00
|
|
|
|
|
|
|
(opaque_mesh, fluid_mesh)
|
2019-05-17 17:44:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-31 20:37:11 +00:00
|
|
|
/*
|
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
|
|
|
impl<V: BaseVol<Vox = Block> + ReadVol + Debug> Meshable for VolGrid3d<V> {
|
2019-05-12 18:33:39 +00:00
|
|
|
type Pipeline = TerrainPipeline;
|
|
|
|
type Supplement = Aabb<i32>;
|
|
|
|
|
|
|
|
fn generate_mesh(&self, range: Self::Supplement) -> Mesh<Self::Pipeline> {
|
|
|
|
let mut mesh = Mesh::new();
|
|
|
|
|
|
|
|
let mut last_chunk_pos = self.pos_key(range.min);
|
|
|
|
let mut last_chunk = self.get_key(last_chunk_pos);
|
|
|
|
|
|
|
|
let size = range.max - range.min;
|
2019-05-13 12:08:17 +00:00
|
|
|
for x in 1..size.x - 1 {
|
|
|
|
for y in 1..size.y - 1 {
|
|
|
|
for z in 1..size.z - 1 {
|
2019-05-12 18:33:39 +00:00
|
|
|
let pos = Vec3::new(x, y, z);
|
|
|
|
|
|
|
|
let new_chunk_pos = self.pos_key(range.min + pos);
|
|
|
|
if last_chunk_pos != new_chunk_pos {
|
|
|
|
last_chunk = self.get_key(new_chunk_pos);
|
|
|
|
last_chunk_pos = new_chunk_pos;
|
|
|
|
}
|
|
|
|
let offs = pos.map(|e| e as f32 - 1.0);
|
2019-05-12 20:58:37 +00:00
|
|
|
if let Some(chunk) = last_chunk {
|
|
|
|
let chunk_pos = Self::chunk_offs(range.min + pos);
|
|
|
|
if let Some(col) = chunk.get(chunk_pos).ok().and_then(|vox| vox.get_color())
|
|
|
|
{
|
|
|
|
let col = col.map(|e| e as f32 / 255.0);
|
|
|
|
|
|
|
|
vol::push_vox_verts(
|
|
|
|
&mut mesh,
|
|
|
|
self,
|
2019-05-12 22:46:36 +00:00
|
|
|
range.min + pos,
|
2019-05-12 20:58:37 +00:00
|
|
|
offs,
|
|
|
|
col,
|
|
|
|
TerrainVertex::new,
|
2019-05-13 12:08:17 +00:00
|
|
|
false,
|
2019-05-12 20:58:37 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if let Some(col) = self
|
|
|
|
.get(range.min + pos)
|
|
|
|
.ok()
|
|
|
|
.and_then(|vox| vox.get_color())
|
|
|
|
{
|
|
|
|
let col = col.map(|e| e as f32 / 255.0);
|
|
|
|
|
|
|
|
vol::push_vox_verts(
|
|
|
|
&mut mesh,
|
|
|
|
self,
|
2019-05-12 22:46:36 +00:00
|
|
|
range.min + pos,
|
2019-05-12 20:58:37 +00:00
|
|
|
offs,
|
|
|
|
col,
|
|
|
|
TerrainVertex::new,
|
2019-05-13 12:08:17 +00:00
|
|
|
false,
|
2019-05-12 20:58:37 +00:00
|
|
|
);
|
|
|
|
}
|
2019-05-12 18:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mesh
|
|
|
|
}
|
|
|
|
}
|
2019-05-31 20:37:11 +00:00
|
|
|
*/
|