Added terrain sprite LoD

This commit is contained in:
Joshua Barretto 2020-04-24 15:20:16 +01:00
parent 8a855ea423
commit b2c8dc0806
9 changed files with 329 additions and 223 deletions

View File

@ -2,7 +2,7 @@ pub mod cell;
pub mod mat_cell;
pub use mat_cell::Material;
use self::{cell::Cell, mat_cell::MatCell};
pub use self::{cell::Cell, mat_cell::MatCell};
use crate::{
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
volumes::dyna::Dyna,

View File

@ -1,4 +1,4 @@
use crate::ray::Ray;
use crate::{ray::Ray, volumes::scaled::Scaled};
use std::fmt::Debug;
use vek::*;
@ -24,6 +24,13 @@ pub trait Vox: Sized + Clone + PartialEq {
pub trait BaseVol {
type Vox: Vox;
type Error: Debug;
fn scaled_by(&self, scale: Vec3<f32>) -> Scaled<Self>
where
Self: Sized,
{
Scaled { inner: self, scale }
}
}
/// Implementing `BaseVol` for any `&'a BaseVol` makes it possible to implement
@ -159,6 +166,7 @@ where
/// Unfortunately we can't just implement `IntoIterator` in this generic way
/// because it's defined in another crate. That's actually the only reason why
/// the trait `IntoFullVolIterator` exists.
// TODO: See whether relaxed orphan rules permit this to be replaced now
impl<'a, T: 'a + SizedVol> IntoFullVolIterator<'a> for &'a T
where
Self: IntoVolIterator<'a>,

View File

@ -1,4 +1,5 @@
pub mod chunk;
pub mod dyna;
pub mod scaled;
pub mod vol_grid_2d;
pub mod vol_grid_3d;

View File

@ -0,0 +1,47 @@
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox};
use vek::*;
pub struct Scaled<'a, V> {
pub inner: &'a V,
pub scale: Vec3<f32>,
}
impl<'a, V: BaseVol> BaseVol for Scaled<'a, V> {
type Error = V::Error;
type Vox = V::Vox;
}
impl<'a, V: ReadVol> ReadVol for Scaled<'a, V> {
#[inline(always)]
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error> {
let pos = pos.map2(self.scale, |e, scale| (e as f32 / scale).trunc() as i32);
let search_size = (Vec3::one() / self.scale).map(|e: f32| e.ceil() as i32);
(-search_size.x / 2..search_size.x / 2)
.map(|i| {
(-search_size.y / 2..search_size.y / 2).map(move |j| {
(-search_size.z / 2..search_size.z / 2).map(move |k| Vec3::new(i, j, k))
})
})
.flatten()
.flatten()
.map(|offs| self.inner.get(pos + offs))
.find(|vox| vox.as_ref().map(|v| !v.is_empty()).unwrap_or(false))
.unwrap_or_else(|| self.inner.get(pos))
}
}
impl<'a, V: SizedVol> SizedVol for Scaled<'a, V> {
#[inline(always)]
fn lower_bound(&self) -> Vec3<i32> {
self.inner
.lower_bound()
.map2(self.scale, |e, scale| (e as f32 * scale).floor() as i32)
}
#[inline(always)]
fn upper_bound(&self) -> Vec3<i32> {
self.inner
.upper_bound()
.map2(self.scale, |e, scale| (e as f32 * scale).floor() as i32)
}
}

View File

@ -4,14 +4,14 @@ mod vol;
use crate::render::{self, Mesh};
pub trait Meshable<P: render::Pipeline, T: render::Pipeline> {
pub trait Meshable<'a, P: render::Pipeline, T: render::Pipeline> {
type Pipeline: render::Pipeline;
type TranslucentPipeline: render::Pipeline;
type Supplement;
// Generate meshes - one opaque, one translucent
fn generate_mesh(
&self,
&'a self,
supp: Self::Supplement,
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>);
}

View File

@ -3,27 +3,43 @@ use crate::{
render::{self, FigurePipeline, Mesh, SpritePipeline},
};
use common::{
figure::Segment,
figure::Cell,
util::{linear_to_srgb, srgb_to_linear},
vol::{IntoFullVolIterator, ReadVol, Vox},
vol::{BaseVol, ReadVol, SizedVol, Vox},
};
use vek::*;
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
impl Meshable<FigurePipeline, FigurePipeline> for Segment {
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;
type Supplement = Vec3<f32>;
type Supplement = (Vec3<f32>, Vec3<f32>);
type TranslucentPipeline = FigurePipeline;
fn generate_mesh(
&self,
offs: Self::Supplement,
&'a self,
(offs, scale): Self::Supplement,
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut mesh = Mesh::new();
for (pos, vox) in self.full_vol_iter() {
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).unwrap()));
for (pos, vox) in vol_iter {
if let Some(col) = vox.get_color() {
vol::push_vox_verts(
&mut mesh,
@ -32,7 +48,7 @@ impl Meshable<FigurePipeline, FigurePipeline> for Segment {
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|origin, norm, col, light, ao| {
FigureVertex::new(
origin,
origin * scale,
norm,
linear_to_srgb(srgb_to_linear(col) * light),
ao,
@ -62,18 +78,34 @@ impl Meshable<FigurePipeline, FigurePipeline> for Segment {
}
}
impl Meshable<SpritePipeline, SpritePipeline> for Segment {
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>, */
{
type Pipeline = SpritePipeline;
type Supplement = Vec3<f32>;
type Supplement = (Vec3<f32>, Vec3<f32>);
type TranslucentPipeline = SpritePipeline;
fn generate_mesh(
&self,
offs: Self::Supplement,
&'a self,
(offs, scale): Self::Supplement,
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut mesh = Mesh::new();
for (pos, vox) in self.full_vol_iter() {
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).unwrap()));
for (pos, vox) in vol_iter {
if let Some(col) = vox.get_color() {
vol::push_vox_verts(
&mut mesh,
@ -82,7 +114,7 @@ impl Meshable<SpritePipeline, SpritePipeline> for Segment {
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|origin, norm, col, light, ao| {
SpriteVertex::new(
origin,
origin * scale,
norm,
linear_to_srgb(srgb_to_linear(col) * light),
ao,

View File

@ -198,15 +198,15 @@ fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
}
}
impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeline, FluidPipeline>
for VolGrid2d<V>
impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
Meshable<'a, TerrainPipeline, FluidPipeline> for VolGrid2d<V>
{
type Pipeline = TerrainPipeline;
type Supplement = Aabb<i32>;
type TranslucentPipeline = FluidPipeline;
fn generate_mesh(
&self,
&'a self,
range: Self::Supplement,
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
let mut light = calc_light(range, self);

View File

@ -55,7 +55,7 @@ fn graceful_load_mat_segment_flipped(mesh_name: &str) -> MatSegment {
}
fn generate_mesh(segment: &Segment, offset: Vec3<f32>) -> Mesh<FigurePipeline> {
Meshable::<FigurePipeline, FigurePipeline>::generate_mesh(segment, offset).0
Meshable::<FigurePipeline, FigurePipeline>::generate_mesh(segment, (offset, Vec3::one())).0
}
pub fn load_mesh(mesh_name: &str, position: Vec3<f32>) -> Mesh<FigurePipeline> {

File diff suppressed because it is too large Load Diff