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::{
|
2020-01-18 05:24:48 +00:00
|
|
|
terrain::{Block, BlockKind},
|
2019-09-24 00:15:38 +00:00
|
|
|
vol::{ReadVol, RectRasterableVol, Vox},
|
2020-01-12 05:50:58 +00:00
|
|
|
volumes::vol_grid_2d::{CachedVolGrid2d, VolGrid2d},
|
2019-01-23 20:01:58 +00:00
|
|
|
};
|
2020-01-12 05:50:58 +00:00
|
|
|
use std::{collections::VecDeque, fmt::Debug};
|
2019-06-05 15:22:06 +00:00
|
|
|
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;
|
|
|
|
|
2020-01-18 05:24:48 +00:00
|
|
|
trait Blendable {
|
|
|
|
fn is_blended(&self) -> bool;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Blendable for BlockKind {
|
|
|
|
fn is_blended(&self) -> bool {
|
|
|
|
match self {
|
2020-02-07 19:53:38 +00:00
|
|
|
_ => false,
|
2020-01-18 05:24:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-24 00:15:38 +00:00
|
|
|
fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
|
|
|
|
bounds: Aabb<i32>,
|
|
|
|
vol: &VolGrid2d<V>,
|
2020-04-16 13:42:20 +00:00
|
|
|
) -> impl FnMut(Vec3<i32>) -> Option<f32> + '_ {
|
2020-01-19 20:48:57 +00:00
|
|
|
const UNKNOWN: u8 = 255;
|
2020-01-12 05:50:58 +00:00
|
|
|
const OPAQUE: u8 = 254;
|
2020-01-07 02:00:03 +00:00
|
|
|
const SUNLIGHT: u8 = 24;
|
2019-09-24 00:15:38 +00:00
|
|
|
|
|
|
|
let outer = Aabb {
|
2020-01-12 04:51:19 +00:00
|
|
|
min: bounds.min - Vec3::new(SUNLIGHT as i32 - 1, SUNLIGHT as i32 - 1, 1),
|
|
|
|
max: bounds.max + Vec3::new(SUNLIGHT as i32 - 1, SUNLIGHT as i32 - 1, 1),
|
2019-09-24 00:15:38 +00:00
|
|
|
};
|
|
|
|
|
2019-10-01 06:09:27 +00:00
|
|
|
let mut vol_cached = vol.cached();
|
2019-09-29 05:53:22 +00:00
|
|
|
|
2020-01-19 20:48:57 +00:00
|
|
|
let mut light_map = vec![UNKNOWN; outer.size().product() as usize];
|
2020-01-12 05:50:58 +00:00
|
|
|
let lm_idx = {
|
|
|
|
let (w, h, _) = outer.clone().size().into_tuple();
|
|
|
|
move |x, y, z| (z * h * w + x * h + y) as usize
|
2020-01-07 02:00:03 +00:00
|
|
|
};
|
2020-01-12 05:50:58 +00:00
|
|
|
// Light propagation queue
|
|
|
|
let mut prop_que = VecDeque::new();
|
2020-01-12 06:23:21 +00:00
|
|
|
// Start sun rays
|
2019-09-24 00:15:38 +00:00
|
|
|
for x in 0..outer.size().w {
|
|
|
|
for y in 0..outer.size().h {
|
2020-01-12 05:50:58 +00:00
|
|
|
let z = outer.size().d - 1;
|
|
|
|
let is_air = vol_cached
|
|
|
|
.get(outer.min + Vec3::new(x, y, z))
|
|
|
|
.ok()
|
|
|
|
.map_or(false, |b| b.is_air());
|
|
|
|
|
|
|
|
light_map[lm_idx(x, y, z)] = if is_air {
|
|
|
|
if vol_cached
|
|
|
|
.get(outer.min + Vec3::new(x, y, z - 1))
|
2019-09-25 10:25:32 +00:00
|
|
|
.ok()
|
2020-01-12 05:50:58 +00:00
|
|
|
.map_or(false, |b| b.is_air())
|
|
|
|
{
|
|
|
|
light_map[lm_idx(x, y, z - 1)] = SUNLIGHT;
|
2020-01-19 23:14:07 +00:00
|
|
|
prop_que.push_back((x as u8, y as u8, z as u16));
|
2020-01-12 05:50:58 +00:00
|
|
|
}
|
|
|
|
SUNLIGHT
|
|
|
|
} else {
|
|
|
|
OPAQUE
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2019-09-25 10:25:32 +00:00
|
|
|
|
2020-01-12 05:50:58 +00:00
|
|
|
// Determines light propagation
|
|
|
|
let propagate = |src: u8,
|
|
|
|
dest: &mut u8,
|
|
|
|
pos: Vec3<i32>,
|
|
|
|
prop_que: &mut VecDeque<_>,
|
|
|
|
vol: &mut CachedVolGrid2d<V>| {
|
|
|
|
if *dest != OPAQUE {
|
2020-01-19 20:48:57 +00:00
|
|
|
if *dest == UNKNOWN {
|
2020-01-12 05:50:58 +00:00
|
|
|
if vol
|
|
|
|
.get(outer.min + pos)
|
|
|
|
.ok()
|
|
|
|
.map_or(false, |b| b.is_air() || b.is_fluid())
|
|
|
|
{
|
|
|
|
*dest = src - 1;
|
|
|
|
// Can't propagate further
|
|
|
|
if *dest > 1 {
|
2020-01-19 23:14:07 +00:00
|
|
|
prop_que.push_back((pos.x as u8, pos.y as u8, pos.z as u16));
|
2019-10-14 09:48:40 +00:00
|
|
|
}
|
2020-01-12 05:50:58 +00:00
|
|
|
} else {
|
|
|
|
*dest = OPAQUE;
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
2020-01-12 05:50:58 +00:00
|
|
|
} else if *dest < src - 1 {
|
|
|
|
*dest = src - 1;
|
|
|
|
// Can't propagate further
|
|
|
|
if *dest > 1 {
|
2020-01-19 23:14:07 +00:00
|
|
|
prop_que.push_back((pos.x as u8, pos.y as u8, pos.z as u16));
|
2019-09-25 10:25:32 +00:00
|
|
|
}
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-12 05:50:58 +00:00
|
|
|
};
|
2019-09-24 00:15:38 +00:00
|
|
|
|
2020-01-12 05:50:58 +00:00
|
|
|
// Propage light
|
|
|
|
while let Some(pos) = prop_que.pop_front() {
|
2020-01-19 23:14:07 +00:00
|
|
|
let pos = Vec3::new(pos.0 as i32, pos.1 as i32, pos.2 as i32);
|
2020-01-12 05:50:58 +00:00
|
|
|
let light = light_map[lm_idx(pos.x, pos.y, pos.z)];
|
|
|
|
|
|
|
|
// If ray propagate downwards at full strength
|
|
|
|
if light == SUNLIGHT {
|
|
|
|
// Down is special cased and we know up is a ray
|
|
|
|
// Special cased ray propagation
|
|
|
|
let pos = Vec3::new(pos.x, pos.y, pos.z - 1);
|
|
|
|
let (is_air, is_fluid) = vol_cached
|
|
|
|
.get(outer.min + pos)
|
|
|
|
.ok()
|
|
|
|
.map_or((false, false), |b| (b.is_air(), b.is_fluid()));
|
|
|
|
light_map[lm_idx(pos.x, pos.y, pos.z)] = if is_air {
|
2020-01-19 23:14:07 +00:00
|
|
|
prop_que.push_back((pos.x as u8, pos.y as u8, pos.z as u16));
|
2020-01-12 05:50:58 +00:00
|
|
|
SUNLIGHT
|
|
|
|
} else if is_fluid {
|
2020-01-19 23:14:07 +00:00
|
|
|
prop_que.push_back((pos.x as u8, pos.y as u8, pos.z as u16));
|
2020-01-12 05:50:58 +00:00
|
|
|
SUNLIGHT - 1
|
|
|
|
} else {
|
|
|
|
OPAQUE
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Up
|
|
|
|
// Bounds checking
|
|
|
|
if pos.z + 1 < outer.size().d {
|
|
|
|
propagate(
|
|
|
|
light,
|
|
|
|
light_map.get_mut(lm_idx(pos.x, pos.y, pos.z + 1)).unwrap(),
|
|
|
|
Vec3::new(pos.x, pos.y, pos.z + 1),
|
|
|
|
&mut prop_que,
|
|
|
|
&mut vol_cached,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
// Down
|
|
|
|
if pos.z > 0 {
|
|
|
|
propagate(
|
|
|
|
light,
|
|
|
|
light_map.get_mut(lm_idx(pos.x, pos.y, pos.z - 1)).unwrap(),
|
|
|
|
Vec3::new(pos.x, pos.y, pos.z - 1),
|
|
|
|
&mut prop_que,
|
|
|
|
&mut vol_cached,
|
|
|
|
)
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-12 05:50:58 +00:00
|
|
|
// The XY directions
|
|
|
|
if pos.y + 1 < outer.size().h {
|
|
|
|
propagate(
|
|
|
|
light,
|
|
|
|
light_map.get_mut(lm_idx(pos.x, pos.y + 1, pos.z)).unwrap(),
|
|
|
|
Vec3::new(pos.x, pos.y + 1, pos.z),
|
|
|
|
&mut prop_que,
|
|
|
|
&mut vol_cached,
|
|
|
|
)
|
2019-09-25 10:25:32 +00:00
|
|
|
}
|
2020-01-12 05:50:58 +00:00
|
|
|
if pos.y > 0 {
|
|
|
|
propagate(
|
|
|
|
light,
|
|
|
|
light_map.get_mut(lm_idx(pos.x, pos.y - 1, pos.z)).unwrap(),
|
|
|
|
Vec3::new(pos.x, pos.y - 1, pos.z),
|
|
|
|
&mut prop_que,
|
|
|
|
&mut vol_cached,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if pos.x + 1 < outer.size().w {
|
|
|
|
propagate(
|
|
|
|
light,
|
|
|
|
light_map.get_mut(lm_idx(pos.x + 1, pos.y, pos.z)).unwrap(),
|
|
|
|
Vec3::new(pos.x + 1, pos.y, pos.z),
|
|
|
|
&mut prop_que,
|
|
|
|
&mut vol_cached,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if pos.x > 0 {
|
|
|
|
propagate(
|
|
|
|
light,
|
|
|
|
light_map.get_mut(lm_idx(pos.x - 1, pos.y, pos.z)).unwrap(),
|
|
|
|
Vec3::new(pos.x - 1, pos.y, pos.z),
|
|
|
|
&mut prop_que,
|
|
|
|
&mut vol_cached,
|
|
|
|
)
|
2019-09-24 00:15:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
move |wpos| {
|
2020-04-16 13:42:20 +00:00
|
|
|
if vol_cached
|
|
|
|
.get(wpos)
|
|
|
|
.map(|block| block.is_opaque())
|
|
|
|
.unwrap_or(false)
|
|
|
|
{
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let pos = wpos - outer.min;
|
|
|
|
Some(light_map
|
|
|
|
.get(lm_idx(pos.x, pos.y, pos.z))
|
|
|
|
.filter(|l| **l != OPAQUE && **l != UNKNOWN)
|
|
|
|
.map(|l| *l as f32 / SUNLIGHT as f32)
|
|
|
|
.unwrap_or(0.0))
|
|
|
|
}
|
2019-09-24 00:15:38 +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: 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;
|
|
|
|
type Supplement = Aabb<i32>;
|
2020-02-01 20:39:39 +00:00
|
|
|
type TranslucentPipeline = FluidPipeline;
|
2019-05-17 17:44:30 +00:00
|
|
|
|
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
|
|
|
|
2020-04-16 13:42:20 +00:00
|
|
|
let mut light = calc_light(range, self);
|
2019-09-24 00:15:38 +00:00
|
|
|
|
2020-01-12 05:54:41 +00:00
|
|
|
let mut lowest_opaque = range.size().d;
|
|
|
|
let mut highest_opaque = 0;
|
|
|
|
let mut lowest_fluid = range.size().d;
|
|
|
|
let mut highest_fluid = 0;
|
|
|
|
let mut lowest_air = range.size().d;
|
|
|
|
let mut highest_air = 0;
|
2020-01-12 05:50:58 +00:00
|
|
|
let flat_get = {
|
|
|
|
let (w, h, d) = range.size().into_tuple();
|
|
|
|
// z can range from -1..range.size().d + 1
|
|
|
|
let d = d + 2;
|
2020-01-12 06:23:21 +00:00
|
|
|
let flat = {
|
|
|
|
let mut volume = self.cached();
|
|
|
|
let mut flat = vec![Block::empty(); (w * h * d) as usize];
|
|
|
|
let mut i = 0;
|
|
|
|
for x in 0..range.size().w {
|
|
|
|
for y in 0..range.size().h {
|
|
|
|
for z in -1..range.size().d + 1 {
|
2020-01-18 04:05:26 +00:00
|
|
|
let block = volume
|
|
|
|
.get(range.min + Vec3::new(x, y, z))
|
|
|
|
.map(|b| *b)
|
|
|
|
.unwrap_or(Block::empty());
|
2020-01-12 06:23:21 +00:00
|
|
|
if block.is_opaque() {
|
|
|
|
lowest_opaque = lowest_opaque.min(z);
|
|
|
|
highest_opaque = highest_opaque.max(z);
|
|
|
|
} else if block.is_fluid() {
|
|
|
|
lowest_fluid = lowest_fluid.min(z);
|
|
|
|
highest_fluid = highest_fluid.max(z);
|
|
|
|
} else {
|
|
|
|
// Assume air
|
|
|
|
lowest_air = lowest_air.min(z);
|
|
|
|
highest_air = highest_air.max(z);
|
|
|
|
};
|
|
|
|
flat[i] = block;
|
|
|
|
i += 1;
|
|
|
|
}
|
2020-01-12 05:50:58 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-12 06:23:21 +00:00
|
|
|
flat
|
|
|
|
};
|
2020-01-12 05:50:58 +00:00
|
|
|
|
|
|
|
move |Vec3 { x, y, z }| {
|
|
|
|
// z can range from -1..range.size().d + 1
|
|
|
|
let z = z + 1;
|
|
|
|
match flat.get((x * h * d + y * d + z) as usize).copied() {
|
|
|
|
Some(b) => b,
|
|
|
|
None => panic!("x {} y {} z {} d {} h {}"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2019-10-01 06:09:27 +00:00
|
|
|
|
2020-01-12 05:54:41 +00:00
|
|
|
// TODO: figure out why this has to be -2 instead of -1
|
2020-01-12 06:23:21 +00:00
|
|
|
// Constrain iterated area
|
2020-01-12 05:54:41 +00:00
|
|
|
let z_start = if (lowest_air > lowest_opaque && lowest_air <= lowest_fluid)
|
|
|
|
|| (lowest_air > lowest_fluid && lowest_air <= lowest_opaque)
|
|
|
|
{
|
|
|
|
lowest_air - 2
|
|
|
|
} else if lowest_fluid > lowest_opaque && lowest_fluid <= lowest_air {
|
|
|
|
lowest_fluid - 2
|
|
|
|
} else if lowest_fluid > lowest_air && lowest_fluid <= lowest_opaque {
|
|
|
|
lowest_fluid - 1
|
|
|
|
} else {
|
|
|
|
lowest_opaque - 1
|
|
|
|
}
|
|
|
|
.max(0);
|
|
|
|
let z_end = if (highest_air < highest_opaque && highest_air >= highest_fluid)
|
|
|
|
|| (highest_air < highest_fluid && highest_air >= highest_opaque)
|
|
|
|
{
|
|
|
|
highest_air + 1
|
|
|
|
} else if highest_fluid < highest_opaque && highest_fluid >= highest_air {
|
|
|
|
highest_fluid + 1
|
|
|
|
} else if highest_fluid < highest_air && highest_fluid >= highest_opaque {
|
|
|
|
highest_fluid
|
|
|
|
} else {
|
|
|
|
highest_opaque
|
|
|
|
}
|
|
|
|
.min(range.size().d - 1);
|
2020-01-12 05:50:58 +00:00
|
|
|
for x in 1..range.size().w - 1 {
|
|
|
|
for y in 1..range.size().w - 1 {
|
2020-04-16 13:42:20 +00:00
|
|
|
let mut lights = [[[None; 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 {
|
|
|
|
lights[k][j][i] = light(
|
2020-01-12 05:54:41 +00:00
|
|
|
Vec3::new(x + range.min.x, y + range.min.y, z_start + range.min.z)
|
2019-09-24 09:01:50 +00:00
|
|
|
+ Vec3::new(i as i32, j as i32, k as i32)
|
|
|
|
- 1,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-18 05:24:48 +00:00
|
|
|
let get_color = |maybe_block: Option<&Block>, neighbour: bool| {
|
2019-10-01 06:09:27 +00:00
|
|
|
maybe_block
|
2020-01-18 05:24:48 +00:00
|
|
|
.filter(|vox| vox.is_opaque() && (!neighbour || vox.is_blended()))
|
2019-10-01 06:09:27 +00:00
|
|
|
.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-10-25 00:02:29 +00:00
|
|
|
let mut blocks = [[[None; 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 {
|
2020-01-12 06:23:21 +00:00
|
|
|
let block = Some(flat_get(
|
|
|
|
Vec3::new(x, y, z_start) + Vec3::new(i as i32, j as i32, k as i32)
|
|
|
|
- 1,
|
|
|
|
));
|
2019-10-25 00:02:29 +00:00
|
|
|
blocks[k][j][i] = block;
|
2019-09-24 09:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-12 05:54:41 +00:00
|
|
|
for z in z_start..z_end + 1 {
|
2019-05-17 17:44:30 +00:00
|
|
|
let pos = Vec3::new(x, y, z);
|
2020-01-12 05:54:41 +00:00
|
|
|
let offs = (pos - Vec3::new(1, 1, -range.min.z)).map(|e| e as f32);
|
2019-08-14 21:28:37 +00:00
|
|
|
|
2019-09-24 09:01:50 +00:00
|
|
|
lights[0] = lights[1];
|
|
|
|
lights[1] = lights[2];
|
2019-10-25 00:02:29 +00:00
|
|
|
blocks[0] = blocks[1];
|
|
|
|
blocks[1] = blocks[2];
|
2019-09-24 10:28:40 +00:00
|
|
|
|
2019-09-24 09:01:50 +00:00
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
2020-01-12 05:54:41 +00:00
|
|
|
lights[2][j][i] =
|
|
|
|
light(pos + range.min + Vec3::new(i as i32, j as i32, 2) - 1);
|
2019-09-24 09:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
2020-01-12 06:23:21 +00:00
|
|
|
let block = Some(flat_get(pos + Vec3::new(i as i32, j as i32, 2) - 1));
|
2019-10-25 00:02:29 +00:00
|
|
|
blocks[2][j][i] = block;
|
2019-09-24 09:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-25 00:02:29 +00:00
|
|
|
let block = blocks[1][1][1];
|
2020-01-18 05:24:48 +00:00
|
|
|
let colors = if block.map_or(false, |vox| vox.is_blended()) {
|
|
|
|
let mut colors = [[[Rgba::zero(); 3]; 3]; 3];
|
|
|
|
for i in 0..3 {
|
|
|
|
for j in 0..3 {
|
|
|
|
for k in 0..3 {
|
|
|
|
colors[i][j][k] = get_color(
|
|
|
|
blocks[i][j][k].as_ref(),
|
|
|
|
i != 1 || j != 1 || k != 1,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
colors
|
|
|
|
} else {
|
|
|
|
[[[get_color(blocks[1][1][1].as_ref(), false); 3]; 3]; 3]
|
|
|
|
};
|
2019-05-17 17:44:30 +00:00
|
|
|
|
2019-05-29 11:01:02 +00:00
|
|
|
// Create mesh polygons
|
2020-01-18 05:24:48 +00:00
|
|
|
if block.map_or(false, |vox| vox.is_opaque()) {
|
2019-05-21 22:31:38 +00:00
|
|
|
vol::push_vox_verts(
|
2019-08-14 21:28:37 +00:00
|
|
|
&mut opaque_mesh,
|
2019-10-25 00:02:29 +00:00
|
|
|
faces_to_make(&blocks, false, |vox| !vox.is_opaque()),
|
2019-05-21 22:31:38 +00:00
|
|
|
offs,
|
2020-01-18 05:24:48 +00:00
|
|
|
&colors,
|
2020-04-16 13:42:20 +00:00
|
|
|
|pos, norm, col, light, ao| {
|
|
|
|
//let light = (light.min(ao) * 255.0) as u32;
|
|
|
|
let light = (light * 255.0) as u32;
|
|
|
|
let ao = (ao * 255.0) as u32;
|
2019-11-19 13:20:20 +00:00
|
|
|
let norm = if norm.x != 0.0 {
|
2020-02-01 20:39:39 +00:00
|
|
|
if norm.x < 0.0 { 0 } else { 1 }
|
2019-11-19 13:20:20 +00:00
|
|
|
} else if norm.y != 0.0 {
|
2020-02-01 20:39:39 +00:00
|
|
|
if norm.y < 0.0 { 2 } else { 3 }
|
2019-11-19 13:20:20 +00:00
|
|
|
} else {
|
2020-02-01 20:39:39 +00:00
|
|
|
if norm.z < 0.0 { 4 } else { 5 }
|
2019-11-19 13:20:20 +00:00
|
|
|
};
|
2020-04-16 13:42:20 +00:00
|
|
|
TerrainVertex::new(norm, light, ao, pos, col)
|
2019-06-19 14:55:26 +00:00
|
|
|
},
|
2019-09-24 09:01:50 +00:00
|
|
|
&lights,
|
2019-08-14 21:28:37 +00:00
|
|
|
);
|
2020-01-18 05:24:48 +00:00
|
|
|
} else if block.map_or(false, |vox| vox.is_fluid()) {
|
2019-08-14 21:28:37 +00:00
|
|
|
vol::push_vox_verts(
|
|
|
|
&mut fluid_mesh,
|
2019-10-25 00:02:29 +00:00
|
|
|
faces_to_make(&blocks, false, |vox| vox.is_air()),
|
2019-08-14 21:28:37 +00:00
|
|
|
offs,
|
2019-09-24 09:01:50 +00:00
|
|
|
&colors,
|
2020-04-16 13:42:20 +00:00
|
|
|
|pos, norm, col, light, _ao| {
|
2019-10-08 11:07:10 +00:00
|
|
|
FluidVertex::new(pos, norm, col, light, 0.3)
|
2019-08-14 21:28:37 +00:00
|
|
|
},
|
2019-09-24 09:01:50 +00:00
|
|
|
&lights,
|
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-10-25 00:02:29 +00:00
|
|
|
/// Use the 6 voxels/blocks surrounding the center
|
|
|
|
/// to detemine which faces should be drawn
|
|
|
|
/// Unlike the one in segments.rs this uses a provided array of blocks instead
|
|
|
|
/// of retrieving from a volume
|
|
|
|
/// blocks[z][y][x]
|
|
|
|
fn faces_to_make(
|
|
|
|
blocks: &[[[Option<Block>; 3]; 3]; 3],
|
|
|
|
error_makes_face: bool,
|
|
|
|
should_add: impl Fn(Block) -> bool,
|
|
|
|
) -> [bool; 6] {
|
|
|
|
// Faces to draw
|
|
|
|
let make_face = |opt_v: Option<Block>| opt_v.map(|v| should_add(v)).unwrap_or(error_makes_face);
|
|
|
|
[
|
|
|
|
make_face(blocks[1][1][0]),
|
|
|
|
make_face(blocks[1][1][2]),
|
|
|
|
make_face(blocks[1][0][1]),
|
|
|
|
make_face(blocks[1][2][1]),
|
|
|
|
make_face(blocks[0][1][1]),
|
|
|
|
make_face(blocks[2][1][1]),
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|