mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
More fixes
This commit is contained in:
parent
05d97e2f2f
commit
3502699732
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6063,6 +6063,7 @@ dependencies = [
|
|||||||
name = "veloren-voxygen-anim"
|
name = "veloren-voxygen-anim"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
"find_folder",
|
"find_folder",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libloading 0.7.0",
|
"libloading 0.7.0",
|
||||||
|
@ -20,3 +20,4 @@ libloading = {version = "0.7", optional = true}
|
|||||||
notify = {version = "5.0.0-pre.2", optional = true}
|
notify = {version = "5.0.0-pre.2", optional = true}
|
||||||
tracing = {version = "0.1", optional = true}
|
tracing = {version = "0.1", optional = true}
|
||||||
vek = {version = "=0.14.1", features = ["serde"]}
|
vek = {version = "=0.14.1", features = ["serde"]}
|
||||||
|
bytemuck = { version="1.4", features=["derive"] }
|
||||||
|
@ -75,16 +75,19 @@ pub use dyn_lib::init;
|
|||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use self::vek::*;
|
use self::vek::*;
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
type MatRaw = [[f32; 4]; 4];
|
type MatRaw = [[f32; 4]; 4];
|
||||||
|
|
||||||
pub type FigureBoneData = (MatRaw, MatRaw);
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable, Default)]
|
||||||
|
pub struct FigureBoneData(pub MatRaw, pub MatRaw);
|
||||||
|
|
||||||
pub const MAX_BONE_COUNT: usize = 16;
|
pub const MAX_BONE_COUNT: usize = 16;
|
||||||
|
|
||||||
fn make_bone(mat: Mat4<f32>) -> FigureBoneData {
|
fn make_bone(mat: Mat4<f32>) -> FigureBoneData {
|
||||||
let normal = mat.map_cols(Vec4::normalized);
|
let normal = mat.map_cols(Vec4::normalized);
|
||||||
(mat.into_col_arrays(), normal.into_col_arrays())
|
FigureBoneData(mat.into_col_arrays(), normal.into_col_arrays())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Bone = Transform<f32, f32, f32>;
|
pub type Bone = Transform<f32, f32, f32>;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use crate::render::{self, mesh::Quad, ColLightFmt, ColLightInfo, TerrainPipeline};
|
use crate::render::{mesh::Quad, ColLightInfo, TerrainVertex, Vertex};
|
||||||
use common_base::span;
|
use common_base::span;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
|
||||||
|
|
||||||
type TodoRect = (
|
type TodoRect = (
|
||||||
Vec3<i32>,
|
Vec3<i32>,
|
||||||
Vec2<Vec3<u16>>,
|
Vec2<Vec3<u16>>,
|
||||||
@ -84,7 +82,7 @@ pub type SuspendedMesh<'a> = dyn for<'r> FnOnce(&'r mut ColLightInfo) + 'a;
|
|||||||
/// For an explanation of why we want this, see `SuspendedMesh`.
|
/// For an explanation of why we want this, see `SuspendedMesh`.
|
||||||
pub struct GreedyMesh<'a> {
|
pub struct GreedyMesh<'a> {
|
||||||
atlas: guillotiere::SimpleAtlasAllocator,
|
atlas: guillotiere::SimpleAtlasAllocator,
|
||||||
col_lights_size: Vec2<u16>,
|
col_lights_size: Vec2<u32>,
|
||||||
max_size: guillotiere::Size,
|
max_size: guillotiere::Size,
|
||||||
suspended: Vec<Box<SuspendedMesh<'a>>>,
|
suspended: Vec<Box<SuspendedMesh<'a>>>,
|
||||||
}
|
}
|
||||||
@ -123,7 +121,7 @@ impl<'a> GreedyMesh<'a> {
|
|||||||
small_size_threshold,
|
small_size_threshold,
|
||||||
large_size_threshold,
|
large_size_threshold,
|
||||||
});
|
});
|
||||||
let col_lights_size = Vec2::new(1u16, 1u16);
|
let col_lights_size = Vec2::new(1, 1);
|
||||||
Self {
|
Self {
|
||||||
atlas,
|
atlas,
|
||||||
col_lights_size,
|
col_lights_size,
|
||||||
@ -178,7 +176,7 @@ impl<'a> GreedyMesh<'a> {
|
|||||||
let cur_size = self.col_lights_size;
|
let cur_size = self.col_lights_size;
|
||||||
let col_lights = vec![
|
let col_lights = vec![
|
||||||
TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254));
|
TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254));
|
||||||
usize::from(cur_size.x) * usize::from(cur_size.y)
|
cur_size.x as usize * cur_size.y as usize
|
||||||
];
|
];
|
||||||
let mut col_lights_info = (col_lights, cur_size);
|
let mut col_lights_info = (col_lights, cur_size);
|
||||||
self.suspended.into_iter().for_each(|cont| {
|
self.suspended.into_iter().for_each(|cont| {
|
||||||
@ -192,7 +190,7 @@ impl<'a> GreedyMesh<'a> {
|
|||||||
|
|
||||||
fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FO, FS, FP, FT>(
|
fn greedy_mesh<'a, M: PartialEq, D: 'a, FL, FG, FO, FS, FP, FT>(
|
||||||
atlas: &mut guillotiere::SimpleAtlasAllocator,
|
atlas: &mut guillotiere::SimpleAtlasAllocator,
|
||||||
col_lights_size: &mut Vec2<u16>,
|
col_lights_size: &mut Vec2<u32>,
|
||||||
max_size: guillotiere::Size,
|
max_size: guillotiere::Size,
|
||||||
GreedyConfig {
|
GreedyConfig {
|
||||||
mut data,
|
mut data,
|
||||||
@ -430,7 +428,7 @@ fn add_to_atlas(
|
|||||||
norm: Vec3<i16>,
|
norm: Vec3<i16>,
|
||||||
faces_forward: bool,
|
faces_forward: bool,
|
||||||
max_size: guillotiere::Size,
|
max_size: guillotiere::Size,
|
||||||
cur_size: &mut Vec2<u16>,
|
cur_size: &mut Vec2<u32>,
|
||||||
) -> guillotiere::Rectangle {
|
) -> guillotiere::Rectangle {
|
||||||
// TODO: Check this conversion.
|
// TODO: Check this conversion.
|
||||||
let atlas_rect;
|
let atlas_rect;
|
||||||
@ -475,8 +473,8 @@ fn add_to_atlas(
|
|||||||
// a u16 and we never grew the atlas, meaning all valid coordinates within the
|
// a u16 and we never grew the atlas, meaning all valid coordinates within the
|
||||||
// atlas also fit into a u16.
|
// atlas also fit into a u16.
|
||||||
*cur_size = Vec2::new(
|
*cur_size = Vec2::new(
|
||||||
cur_size.x.max(atlas_rect.max.x as u16),
|
cur_size.x.max(atlas_rect.max.x as u32),
|
||||||
cur_size.y.max(atlas_rect.max.y as u16),
|
cur_size.y.max(atlas_rect.max.y as u32),
|
||||||
);
|
);
|
||||||
|
|
||||||
// NOTE: pos can be converted safely from usize to i32 because all legal block
|
// NOTE: pos can be converted safely from usize to i32 because all legal block
|
||||||
@ -507,7 +505,7 @@ fn draw_col_lights<D>(
|
|||||||
mut get_light: impl FnMut(&mut D, Vec3<i32>) -> f32,
|
mut get_light: impl FnMut(&mut D, Vec3<i32>) -> f32,
|
||||||
mut get_glow: impl FnMut(&mut D, Vec3<i32>) -> f32,
|
mut get_glow: impl FnMut(&mut D, Vec3<i32>) -> f32,
|
||||||
mut get_opacity: impl FnMut(&mut D, Vec3<i32>) -> bool,
|
mut get_opacity: impl FnMut(&mut D, Vec3<i32>) -> bool,
|
||||||
mut make_face_texel: impl FnMut(&mut D, Vec3<i32>, u8, u8) -> <<ColLightFmt as gfx::format::Formatted>::Surface as gfx::format::SurfaceTyped>::DataType,
|
mut make_face_texel: impl FnMut(&mut D, Vec3<i32>, u8, u8) -> [u8; 4],
|
||||||
) {
|
) {
|
||||||
todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| {
|
todo_rects.into_iter().for_each(|(pos, uv, rect, delta)| {
|
||||||
// NOTE: Conversions are safe because width, height, and offset must be
|
// NOTE: Conversions are safe because width, height, and offset must be
|
||||||
@ -520,7 +518,7 @@ fn draw_col_lights<D>(
|
|||||||
let uv = uv.map(|e| e.map(i32::from));
|
let uv = uv.map(|e| e.map(i32::from));
|
||||||
let pos = pos + draw_delta;
|
let pos = pos + draw_delta;
|
||||||
(0..height).for_each(|v| {
|
(0..height).for_each(|v| {
|
||||||
let start = usize::from(cur_size.x) * usize::from(top + v) + usize::from(left);
|
let start = cur_size.x as usize * usize::from(top + v) + usize::from(left);
|
||||||
(0..width)
|
(0..width)
|
||||||
.zip(&mut col_lights[start..start + usize::from(width)])
|
.zip(&mut col_lights[start..start + usize::from(width)])
|
||||||
.for_each(|(u, col_light)| {
|
.for_each(|(u, col_light)| {
|
||||||
@ -622,14 +620,14 @@ fn create_quad_greedy<M>(
|
|||||||
push_quad(atlas_pos, dim, origin, draw_dim, norm, meta);
|
push_quad(atlas_pos, dim, origin, draw_dim, norm, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_quad<O: render::Pipeline, M>(
|
pub fn create_quad<O: Vertex, M>(
|
||||||
atlas_pos: Vec2<u16>,
|
atlas_pos: Vec2<u16>,
|
||||||
dim: Vec2<Vec2<u16>>,
|
dim: Vec2<Vec2<u16>>,
|
||||||
origin: Vec3<f32>,
|
origin: Vec3<f32>,
|
||||||
draw_dim: Vec2<Vec3<f32>>,
|
draw_dim: Vec2<Vec3<f32>>,
|
||||||
norm: Vec3<f32>,
|
norm: Vec3<f32>,
|
||||||
meta: &M,
|
meta: &M,
|
||||||
create_vertex: impl Fn(Vec2<u16>, Vec3<f32>, Vec3<f32>, &M) -> O::Vertex,
|
create_vertex: impl Fn(Vec2<u16>, Vec3<f32>, Vec3<f32>, &M) -> O,
|
||||||
) -> Quad<O> {
|
) -> Quad<O> {
|
||||||
Quad::new(
|
Quad::new(
|
||||||
create_vertex(atlas_pos, origin, norm, meta),
|
create_vertex(atlas_pos, origin, norm, meta),
|
||||||
|
@ -2,25 +2,6 @@ pub mod greedy;
|
|||||||
pub mod segment;
|
pub mod segment;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
|
|
||||||
use crate::render::{self, Mesh};
|
use crate::render::Mesh;
|
||||||
|
|
||||||
pub type MeshGen<P, T, M> = (
|
pub type MeshGen<V, T, S, R> = (Mesh<V>, Mesh<T>, Mesh<S>, R);
|
||||||
Mesh<<M as Meshable<P, T>>::Pipeline>,
|
|
||||||
Mesh<<M as Meshable<P, T>>::TranslucentPipeline>,
|
|
||||||
Mesh<<M as Meshable<P, T>>::ShadowPipeline>,
|
|
||||||
<M as Meshable<P, T>>::Result,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// FIXME: Remove this whole trait at some point. This "abstraction" is never
|
|
||||||
/// abstracted over, and is organized completely differently from how we
|
|
||||||
/// actually mesh things nowadays.
|
|
||||||
pub trait Meshable<P: render::Pipeline, T> {
|
|
||||||
type Pipeline: render::Pipeline;
|
|
||||||
type TranslucentPipeline: render::Pipeline;
|
|
||||||
type ShadowPipeline: render::Pipeline;
|
|
||||||
type Supplement;
|
|
||||||
type Result;
|
|
||||||
|
|
||||||
// Generate meshes - one opaque, one translucent, one shadow
|
|
||||||
fn generate_mesh(self, supp: Self::Supplement) -> MeshGen<P, T, Self>;
|
|
||||||
}
|
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{
|
mesh::{
|
||||||
greedy::{self, GreedyConfig, GreedyMesh},
|
greedy::{self, GreedyConfig, GreedyMesh},
|
||||||
MeshGen, Meshable,
|
MeshGen,
|
||||||
},
|
|
||||||
render::{
|
|
||||||
self, FigurePipeline, Mesh, ParticlePipeline, ShadowPipeline, SpritePipeline,
|
|
||||||
TerrainPipeline,
|
|
||||||
},
|
},
|
||||||
|
render::{Mesh, ParticleVertex, SpriteVertex, TerrainVertex},
|
||||||
scene::math,
|
scene::math,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -16,353 +13,315 @@ use common::{
|
|||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
|
// /// NOTE: bone_idx must be in [0, 15] (may be bumped to [0, 31] at some
|
||||||
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
// /// point).
|
||||||
type ParticleVertex = <ParticlePipeline as render::Pipeline>::Vertex;
|
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||||
|
// TODO: this function name...
|
||||||
impl<'a: 'b, 'b, V: 'a> Meshable<FigurePipeline, &'b mut GreedyMesh<'a>> for V
|
pub fn generate_mesh_base_vol_terrain<'a: 'b, 'b, V: 'a>(
|
||||||
where
|
vol: V,
|
||||||
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
||||||
/* TODO: Use VolIterator instead of manually iterating
|
|
||||||
* &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>,
|
|
||||||
* &'a V: BaseVol<Vox=Cell>, */
|
|
||||||
{
|
|
||||||
type Pipeline = TerrainPipeline;
|
|
||||||
type Result = math::Aabb<f32>;
|
|
||||||
type ShadowPipeline = ShadowPipeline;
|
|
||||||
/// NOTE: bone_idx must be in [0, 15] (may be bumped to [0, 31] at some
|
|
||||||
/// point).
|
|
||||||
type Supplement = (
|
|
||||||
&'b mut GreedyMesh<'a>,
|
&'b mut GreedyMesh<'a>,
|
||||||
&'b mut Mesh<Self::Pipeline>,
|
&'b mut Mesh<TerrainVertex>,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
u8,
|
u8,
|
||||||
);
|
),
|
||||||
type TranslucentPipeline = FigurePipeline;
|
) -> MeshGen<TerrainVertex, TerrainVertex, TerrainVertex, math::Aabb<f32>>
|
||||||
|
|
||||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
|
||||||
fn generate_mesh(
|
|
||||||
self,
|
|
||||||
(greedy, opaque_mesh, offs, scale, bone_idx): Self::Supplement,
|
|
||||||
) -> MeshGen<FigurePipeline, &'b mut GreedyMesh<'a>, Self> {
|
|
||||||
assert!(bone_idx <= 15, "Bone index for figures must be in [0, 15]");
|
|
||||||
|
|
||||||
let max_size = greedy.max_size();
|
|
||||||
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
|
||||||
// in order to store the bone index. The two bits are instead taken out
|
|
||||||
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
|
||||||
// coordinate instead of 1 << 16.
|
|
||||||
assert!(max_size.width.max(max_size.height) < 1 << 15);
|
|
||||||
|
|
||||||
let lower_bound = self.lower_bound();
|
|
||||||
let upper_bound = self.upper_bound();
|
|
||||||
assert!(
|
|
||||||
lower_bound.x <= upper_bound.x
|
|
||||||
&& lower_bound.y <= upper_bound.y
|
|
||||||
&& lower_bound.z <= upper_bound.z
|
|
||||||
);
|
|
||||||
// NOTE: Figure sizes should be no more than 512 along each axis.
|
|
||||||
let greedy_size = upper_bound - lower_bound + 1;
|
|
||||||
assert!(greedy_size.x <= 512 && greedy_size.y <= 512 && greedy_size.z <= 512);
|
|
||||||
// NOTE: Cast to usize is safe because of previous check, since all values fit
|
|
||||||
// into u16 which is safe to cast to usize.
|
|
||||||
let greedy_size = greedy_size.as_::<usize>();
|
|
||||||
let greedy_size_cross = greedy_size;
|
|
||||||
let draw_delta = lower_bound;
|
|
||||||
|
|
||||||
let get_light = |vol: &mut V, pos: Vec3<i32>| {
|
|
||||||
if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) {
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let get_glow = |_vol: &mut V, _pos: Vec3<i32>| 0.0;
|
|
||||||
let get_opacity =
|
|
||||||
|vol: &mut V, pos: Vec3<i32>| vol.get(pos).map_or(true, |vox| vox.is_empty());
|
|
||||||
let should_draw = |vol: &mut V, pos: Vec3<i32>, delta: Vec3<i32>, uv| {
|
|
||||||
should_draw_greedy(pos, delta, uv, |vox| {
|
|
||||||
vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty())
|
|
||||||
})
|
|
||||||
};
|
|
||||||
let create_opaque = |atlas_pos, pos, norm| {
|
|
||||||
TerrainVertex::new_figure(atlas_pos, (pos + offs) * scale, norm, bone_idx)
|
|
||||||
};
|
|
||||||
|
|
||||||
greedy.push(GreedyConfig {
|
|
||||||
data: self,
|
|
||||||
draw_delta,
|
|
||||||
greedy_size,
|
|
||||||
greedy_size_cross,
|
|
||||||
get_light,
|
|
||||||
get_glow,
|
|
||||||
get_opacity,
|
|
||||||
should_draw,
|
|
||||||
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| {
|
|
||||||
opaque_mesh.push_quad(greedy::create_quad(
|
|
||||||
atlas_origin,
|
|
||||||
dim,
|
|
||||||
origin,
|
|
||||||
draw_dim,
|
|
||||||
norm,
|
|
||||||
meta,
|
|
||||||
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
make_face_texel: |vol: &mut V, pos, light, _| {
|
|
||||||
let cell = vol.get(pos).ok();
|
|
||||||
let (glowy, shiny) = cell
|
|
||||||
.map(|c| (c.is_glowy(), c.is_shiny()))
|
|
||||||
.unwrap_or_default();
|
|
||||||
let col = cell.and_then(|vox| vox.get_color()).unwrap_or(Rgb::zero());
|
|
||||||
TerrainVertex::make_col_light_figure(light, glowy, shiny, col)
|
|
||||||
},
|
|
||||||
});
|
|
||||||
let bounds = math::Aabb {
|
|
||||||
// NOTE: Casts are safe since lower_bound and upper_bound both fit in a i16.
|
|
||||||
min: math::Vec3::from((lower_bound.as_::<f32>() + offs) * scale),
|
|
||||||
max: math::Vec3::from((upper_bound.as_::<f32>() + offs) * scale),
|
|
||||||
}
|
|
||||||
.made_valid();
|
|
||||||
|
|
||||||
(Mesh::new(), Mesh::new(), Mesh::new(), bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a: 'b, 'b, V: 'a> Meshable<SpritePipeline, &'b mut GreedyMesh<'a>> for V
|
|
||||||
where
|
where
|
||||||
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
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;
|
assert!(bone_idx <= 15, "Bone index for figures must be in [0, 15]");
|
||||||
type Result = ();
|
let max_size = greedy.max_size();
|
||||||
type ShadowPipeline = ShadowPipeline;
|
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
||||||
type Supplement = (&'b mut GreedyMesh<'a>, &'b mut Mesh<Self::Pipeline>, bool);
|
// in order to store the bone index. The two bits are instead taken out
|
||||||
type TranslucentPipeline = SpritePipeline;
|
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
||||||
|
// coordinate instead of 1 << 16.
|
||||||
|
assert!(max_size.width.max(max_size.height) < 1 << 15);
|
||||||
|
|
||||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
let lower_bound = vol.lower_bound();
|
||||||
fn generate_mesh(
|
let upper_bound = vol.upper_bound();
|
||||||
self,
|
assert!(
|
||||||
(greedy, opaque_mesh, vertical_stripes): Self::Supplement,
|
lower_bound.x <= upper_bound.x
|
||||||
) -> MeshGen<SpritePipeline, &'b mut GreedyMesh<'a>, Self> {
|
&& lower_bound.y <= upper_bound.y
|
||||||
let max_size = greedy.max_size();
|
&& lower_bound.z <= upper_bound.z
|
||||||
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
);
|
||||||
// in order to store the bone index. The two bits are instead taken out
|
// NOTE: Figure sizes should be no more than 512 along each axis.
|
||||||
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
let greedy_size = upper_bound - lower_bound + 1;
|
||||||
// coordinate instead of 1 << 16.
|
assert!(greedy_size.x <= 512 && greedy_size.y <= 512 && greedy_size.z <= 512);
|
||||||
assert!(max_size.width.max(max_size.height) < 1 << 16);
|
// NOTE: Cast to usize is safe because of previous check, since all values fit
|
||||||
|
// into u16 which is safe to cast to usize.
|
||||||
|
let greedy_size = greedy_size.as_::<usize>();
|
||||||
|
let greedy_size_cross = greedy_size;
|
||||||
|
let draw_delta = lower_bound;
|
||||||
|
|
||||||
let lower_bound = self.lower_bound();
|
let get_light = |vol: &mut V, pos: Vec3<i32>| {
|
||||||
let upper_bound = self.upper_bound();
|
if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) {
|
||||||
assert!(
|
1.0
|
||||||
lower_bound.x <= upper_bound.x
|
} else {
|
||||||
&& lower_bound.y <= upper_bound.y
|
0.0
|
||||||
&& lower_bound.z <= upper_bound.z
|
}
|
||||||
);
|
};
|
||||||
// Lower bound coordinates must fit in an i16 (which means upper bound
|
let get_glow = |_vol: &mut V, _pos: Vec3<i32>| 0.0;
|
||||||
// coordinates fit as integers in a f23).
|
let get_opacity = |vol: &mut V, pos: Vec3<i32>| vol.get(pos).map_or(true, |vox| vox.is_empty());
|
||||||
assert!(
|
let should_draw = |vol: &mut V, pos: Vec3<i32>, delta: Vec3<i32>, uv| {
|
||||||
i16::try_from(lower_bound.x).is_ok()
|
should_draw_greedy(pos, delta, uv, |vox| {
|
||||||
&& i16::try_from(lower_bound.y).is_ok()
|
vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty())
|
||||||
&& i16::try_from(lower_bound.z).is_ok(),
|
})
|
||||||
"Sprite offsets should fit in i16",
|
};
|
||||||
);
|
let create_opaque = |atlas_pos, pos, norm| {
|
||||||
let greedy_size = upper_bound - lower_bound + 1;
|
TerrainVertex::new_figure(atlas_pos, (pos + offs) * scale, norm, bone_idx)
|
||||||
// TODO: Should this be 16, 16, 64?
|
};
|
||||||
assert!(
|
|
||||||
greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 64,
|
|
||||||
"Sprite size out of bounds: {:?} ≤ (31, 31, 63)",
|
|
||||||
greedy_size - 1
|
|
||||||
);
|
|
||||||
|
|
||||||
let (flat, flat_get) = {
|
greedy.push(GreedyConfig {
|
||||||
let (w, h, d) = (greedy_size + 2).into_tuple();
|
data: vol,
|
||||||
let flat = {
|
draw_delta,
|
||||||
let vol = self;
|
greedy_size,
|
||||||
|
greedy_size_cross,
|
||||||
|
get_light,
|
||||||
|
get_glow,
|
||||||
|
get_opacity,
|
||||||
|
should_draw,
|
||||||
|
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| {
|
||||||
|
opaque_mesh.push_quad(greedy::create_quad(
|
||||||
|
atlas_origin,
|
||||||
|
dim,
|
||||||
|
origin,
|
||||||
|
draw_dim,
|
||||||
|
norm,
|
||||||
|
meta,
|
||||||
|
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
make_face_texel: |vol: &mut V, pos, light, _| {
|
||||||
|
let cell = vol.get(pos).ok();
|
||||||
|
let (glowy, shiny) = cell
|
||||||
|
.map(|c| (c.is_glowy(), c.is_shiny()))
|
||||||
|
.unwrap_or_default();
|
||||||
|
let col = cell.and_then(|vox| vox.get_color()).unwrap_or(Rgb::zero());
|
||||||
|
TerrainVertex::make_col_light_figure(light, glowy, shiny, col)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
let bounds = math::Aabb {
|
||||||
|
// NOTE: Casts are safe since lower_bound and upper_bound both fit in a i16.
|
||||||
|
min: math::Vec3::from((lower_bound.as_::<f32>() + offs) * scale),
|
||||||
|
max: math::Vec3::from((upper_bound.as_::<f32>() + offs) * scale),
|
||||||
|
}
|
||||||
|
.made_valid();
|
||||||
|
|
||||||
let mut flat = vec![Cell::empty(); (w * h * d) as usize];
|
(Mesh::new(), Mesh::new(), Mesh::new(), bounds)
|
||||||
let mut i = 0;
|
}
|
||||||
for x in -1..greedy_size.x + 1 {
|
|
||||||
for y in -1..greedy_size.y + 1 {
|
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||||
for z in -1..greedy_size.z + 1 {
|
pub fn generate_mesh_base_vol_sprite<'a: 'b, 'b, V: 'a>(
|
||||||
let wpos = lower_bound + Vec3::new(x, y, z);
|
vol: V,
|
||||||
let block = vol.get(wpos).map(|b| *b).unwrap_or(Cell::empty());
|
(greedy, opaque_mesh, vertical_stripes): (
|
||||||
flat[i] = block;
|
&'b mut GreedyMesh<'a>,
|
||||||
i += 1;
|
&'b mut Mesh<SpriteVertex>,
|
||||||
}
|
bool,
|
||||||
|
),
|
||||||
|
) -> MeshGen<SpriteVertex, SpriteVertex, TerrainVertex, ()>
|
||||||
|
where
|
||||||
|
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
||||||
|
{
|
||||||
|
let max_size = greedy.max_size();
|
||||||
|
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
||||||
|
// in order to store the bone index. The two bits are instead taken out
|
||||||
|
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
||||||
|
// coordinate instead of 1 << 16.
|
||||||
|
assert!(max_size.width.max(max_size.height) < 1 << 16);
|
||||||
|
|
||||||
|
let lower_bound = vol.lower_bound();
|
||||||
|
let upper_bound = vol.upper_bound();
|
||||||
|
assert!(
|
||||||
|
lower_bound.x <= upper_bound.x
|
||||||
|
&& lower_bound.y <= upper_bound.y
|
||||||
|
&& lower_bound.z <= upper_bound.z
|
||||||
|
);
|
||||||
|
// Lower bound coordinates must fit in an i16 (which means upper bound
|
||||||
|
// coordinates fit as integers in a f23).
|
||||||
|
assert!(
|
||||||
|
i16::try_from(lower_bound.x).is_ok()
|
||||||
|
&& i16::try_from(lower_bound.y).is_ok()
|
||||||
|
&& i16::try_from(lower_bound.z).is_ok(),
|
||||||
|
"Sprite offsets should fit in i16",
|
||||||
|
);
|
||||||
|
let greedy_size = upper_bound - lower_bound + 1;
|
||||||
|
// TODO: Should this be 16, 16, 64?
|
||||||
|
assert!(
|
||||||
|
greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 64,
|
||||||
|
"Sprite size out of bounds: {:?} ≤ (31, 31, 63)",
|
||||||
|
greedy_size - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let (flat, flat_get) = {
|
||||||
|
let (w, h, d) = (greedy_size + 2).into_tuple();
|
||||||
|
let flat = {
|
||||||
|
let mut flat = vec![Cell::empty(); (w * h * d) as usize];
|
||||||
|
let mut i = 0;
|
||||||
|
for x in -1..greedy_size.x + 1 {
|
||||||
|
for y in -1..greedy_size.y + 1 {
|
||||||
|
for z in -1..greedy_size.z + 1 {
|
||||||
|
let wpos = lower_bound + Vec3::new(x, y, z);
|
||||||
|
let block = vol.get(wpos).map(|b| *b).unwrap_or(Cell::empty());
|
||||||
|
flat[i] = block;
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flat
|
|
||||||
};
|
|
||||||
|
|
||||||
let flat_get = move |flat: &Vec<Cell>, Vec3 { x, y, z }| match flat
|
|
||||||
.get((x * h * d + y * d + z) as usize)
|
|
||||||
.copied()
|
|
||||||
{
|
|
||||||
Some(b) => b,
|
|
||||||
None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h),
|
|
||||||
};
|
|
||||||
|
|
||||||
(flat, flat_get)
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE: Cast to usize is safe because of previous check, since all values fit
|
|
||||||
// into u16 which is safe to cast to usize.
|
|
||||||
let greedy_size = greedy_size.as_::<usize>();
|
|
||||||
|
|
||||||
let greedy_size_cross = greedy_size;
|
|
||||||
let draw_delta = Vec3::new(1, 1, 1);
|
|
||||||
|
|
||||||
let get_light = move |flat: &mut _, pos: Vec3<i32>| {
|
|
||||||
if flat_get(flat, pos).is_empty() {
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
}
|
||||||
};
|
flat
|
||||||
let get_glow = |_flat: &mut _, _pos: Vec3<i32>| 0.0;
|
|
||||||
let get_color = move |flat: &mut _, pos: Vec3<i32>| {
|
|
||||||
flat_get(flat, pos).get_color().unwrap_or(Rgb::zero())
|
|
||||||
};
|
|
||||||
let get_opacity = move |flat: &mut _, pos: Vec3<i32>| flat_get(flat, pos).is_empty();
|
|
||||||
let should_draw = move |flat: &mut _, pos: Vec3<i32>, delta: Vec3<i32>, uv| {
|
|
||||||
should_draw_greedy_ao(vertical_stripes, pos, delta, uv, |vox| flat_get(flat, vox))
|
|
||||||
};
|
|
||||||
// NOTE: Fits in i16 (much lower actually) so f32 is no problem (and the final
|
|
||||||
// position, pos + mesh_delta, is guaranteed to fit in an f32).
|
|
||||||
let mesh_delta = lower_bound.as_::<f32>();
|
|
||||||
let create_opaque = |atlas_pos, pos: Vec3<f32>, norm, _meta| {
|
|
||||||
SpriteVertex::new(atlas_pos, pos + mesh_delta, norm)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
greedy.push(GreedyConfig {
|
let flat_get = move |flat: &Vec<Cell>, Vec3 { x, y, z }| match flat
|
||||||
data: flat,
|
.get((x * h * d + y * d + z) as usize)
|
||||||
draw_delta,
|
.copied()
|
||||||
greedy_size,
|
{
|
||||||
greedy_size_cross,
|
Some(b) => b,
|
||||||
get_light,
|
None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h),
|
||||||
get_glow,
|
};
|
||||||
get_opacity,
|
|
||||||
should_draw,
|
|
||||||
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &bool| {
|
|
||||||
opaque_mesh.push_quad(greedy::create_quad(
|
|
||||||
atlas_origin,
|
|
||||||
dim,
|
|
||||||
origin,
|
|
||||||
draw_dim,
|
|
||||||
norm,
|
|
||||||
meta,
|
|
||||||
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
make_face_texel: move |flat: &mut _, pos, light, glow| {
|
|
||||||
TerrainVertex::make_col_light(light, glow, get_color(flat, pos))
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
(Mesh::new(), Mesh::new(), Mesh::new(), ())
|
(flat, flat_get)
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// NOTE: Cast to usize is safe because of previous check, since all values fit
|
||||||
|
// into u16 which is safe to cast to usize.
|
||||||
|
let greedy_size = greedy_size.as_::<usize>();
|
||||||
|
|
||||||
|
let greedy_size_cross = greedy_size;
|
||||||
|
let draw_delta = Vec3::new(1, 1, 1);
|
||||||
|
|
||||||
|
let get_light = move |flat: &mut _, pos: Vec3<i32>| {
|
||||||
|
if flat_get(flat, pos).is_empty() {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let get_glow = |_flat: &mut _, _pos: Vec3<i32>| 0.0;
|
||||||
|
let get_color =
|
||||||
|
move |flat: &mut _, pos: Vec3<i32>| flat_get(flat, pos).get_color().unwrap_or(Rgb::zero());
|
||||||
|
let get_opacity = move |flat: &mut _, pos: Vec3<i32>| flat_get(flat, pos).is_empty();
|
||||||
|
let should_draw = move |flat: &mut _, pos: Vec3<i32>, delta: Vec3<i32>, uv| {
|
||||||
|
should_draw_greedy_ao(vertical_stripes, pos, delta, uv, |vox| flat_get(flat, vox))
|
||||||
|
};
|
||||||
|
// NOTE: Fits in i16 (much lower actually) so f32 is no problem (and the final
|
||||||
|
// position, pos + mesh_delta, is guaranteed to fit in an f32).
|
||||||
|
let mesh_delta = lower_bound.as_::<f32>();
|
||||||
|
let create_opaque = |atlas_pos, pos: Vec3<f32>, norm, _meta| {
|
||||||
|
SpriteVertex::new(atlas_pos, pos + mesh_delta, norm)
|
||||||
|
};
|
||||||
|
|
||||||
|
greedy.push(GreedyConfig {
|
||||||
|
data: flat,
|
||||||
|
draw_delta,
|
||||||
|
greedy_size,
|
||||||
|
greedy_size_cross,
|
||||||
|
get_light,
|
||||||
|
get_glow,
|
||||||
|
get_opacity,
|
||||||
|
should_draw,
|
||||||
|
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &bool| {
|
||||||
|
opaque_mesh.push_quad(greedy::create_quad(
|
||||||
|
atlas_origin,
|
||||||
|
dim,
|
||||||
|
origin,
|
||||||
|
draw_dim,
|
||||||
|
norm,
|
||||||
|
meta,
|
||||||
|
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
make_face_texel: move |flat: &mut _, pos, light, glow| {
|
||||||
|
TerrainVertex::make_col_light(light, glow, get_color(flat, pos))
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
(Mesh::new(), Mesh::new(), Mesh::new(), ())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a: 'b, 'b, V: 'a> Meshable<ParticlePipeline, &'b mut GreedyMesh<'a>> for V
|
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||||
|
pub fn generate_mesh_base_vol_particle<'a: 'b, 'b, V: 'a>(
|
||||||
|
vol: V,
|
||||||
|
greedy: &'b mut GreedyMesh<'a>,
|
||||||
|
) -> MeshGen<ParticleVertex, ParticleVertex, TerrainVertex, ()>
|
||||||
where
|
where
|
||||||
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
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 = ParticlePipeline;
|
let max_size = greedy.max_size();
|
||||||
type Result = ();
|
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
||||||
type ShadowPipeline = ShadowPipeline;
|
// in order to store the bone index. The two bits are instead taken out
|
||||||
type Supplement = &'b mut GreedyMesh<'a>;
|
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
||||||
type TranslucentPipeline = ParticlePipeline;
|
// coordinate instead of 1 << 16.
|
||||||
|
assert!(max_size.width.max(max_size.height) < 1 << 16);
|
||||||
|
|
||||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
let lower_bound = vol.lower_bound();
|
||||||
fn generate_mesh(
|
let upper_bound = vol.upper_bound();
|
||||||
self,
|
assert!(
|
||||||
greedy: Self::Supplement,
|
lower_bound.x <= upper_bound.x
|
||||||
) -> MeshGen<ParticlePipeline, &'b mut GreedyMesh<'a>, Self> {
|
&& lower_bound.y <= upper_bound.y
|
||||||
let max_size = greedy.max_size();
|
&& lower_bound.z <= upper_bound.z
|
||||||
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
);
|
||||||
// in order to store the bone index. The two bits are instead taken out
|
let greedy_size = upper_bound - lower_bound + 1;
|
||||||
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
assert!(
|
||||||
// coordinate instead of 1 << 16.
|
greedy_size.x <= 16 && greedy_size.y <= 16 && greedy_size.z <= 64,
|
||||||
assert!(max_size.width.max(max_size.height) < 1 << 16);
|
"Particle size out of bounds: {:?} ≤ (15, 15, 63)",
|
||||||
|
greedy_size - 1
|
||||||
|
);
|
||||||
|
// NOTE: Cast to usize is safe because of previous check, since all values fit
|
||||||
|
// into u16 which is safe to cast to usize.
|
||||||
|
let greedy_size = greedy_size.as_::<usize>();
|
||||||
|
|
||||||
let lower_bound = self.lower_bound();
|
let greedy_size_cross = greedy_size;
|
||||||
let upper_bound = self.upper_bound();
|
let draw_delta = lower_bound;
|
||||||
assert!(
|
|
||||||
lower_bound.x <= upper_bound.x
|
|
||||||
&& lower_bound.y <= upper_bound.y
|
|
||||||
&& lower_bound.z <= upper_bound.z
|
|
||||||
);
|
|
||||||
let greedy_size = upper_bound - lower_bound + 1;
|
|
||||||
assert!(
|
|
||||||
greedy_size.x <= 16 && greedy_size.y <= 16 && greedy_size.z <= 64,
|
|
||||||
"Particle size out of bounds: {:?} ≤ (15, 15, 63)",
|
|
||||||
greedy_size - 1
|
|
||||||
);
|
|
||||||
// NOTE: Cast to usize is safe because of previous check, since all values fit
|
|
||||||
// into u16 which is safe to cast to usize.
|
|
||||||
let greedy_size = greedy_size.as_::<usize>();
|
|
||||||
|
|
||||||
let greedy_size_cross = greedy_size;
|
let get_light = |vol: &mut V, pos: Vec3<i32>| {
|
||||||
let draw_delta = lower_bound;
|
if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let get_glow = |_vol: &mut V, _pos: Vec3<i32>| 0.0;
|
||||||
|
let get_color = |vol: &mut V, pos: Vec3<i32>| {
|
||||||
|
vol.get(pos)
|
||||||
|
.ok()
|
||||||
|
.and_then(|vox| vox.get_color())
|
||||||
|
.unwrap_or(Rgb::zero())
|
||||||
|
};
|
||||||
|
let get_opacity = |vol: &mut V, pos: Vec3<i32>| vol.get(pos).map_or(true, |vox| vox.is_empty());
|
||||||
|
let should_draw = |vol: &mut V, pos: Vec3<i32>, delta: Vec3<i32>, uv| {
|
||||||
|
should_draw_greedy(pos, delta, uv, |vox| {
|
||||||
|
vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty())
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let create_opaque = |_atlas_pos, pos: Vec3<f32>, norm| ParticleVertex::new(pos, norm);
|
||||||
|
|
||||||
let get_light = |vol: &mut V, pos: Vec3<i32>| {
|
let mut opaque_mesh = Mesh::new();
|
||||||
if vol.get(pos).map(|vox| vox.is_empty()).unwrap_or(true) {
|
greedy.push(GreedyConfig {
|
||||||
1.0
|
data: vol,
|
||||||
} else {
|
draw_delta,
|
||||||
0.0
|
greedy_size,
|
||||||
}
|
greedy_size_cross,
|
||||||
};
|
get_light,
|
||||||
let get_glow = |_vol: &mut V, _pos: Vec3<i32>| 0.0;
|
get_glow,
|
||||||
let get_color = |vol: &mut V, pos: Vec3<i32>| {
|
get_opacity,
|
||||||
vol.get(pos)
|
should_draw,
|
||||||
.ok()
|
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| {
|
||||||
.and_then(|vox| vox.get_color())
|
opaque_mesh.push_quad(greedy::create_quad(
|
||||||
.unwrap_or(Rgb::zero())
|
atlas_origin,
|
||||||
};
|
dim,
|
||||||
let get_opacity =
|
origin,
|
||||||
|vol: &mut V, pos: Vec3<i32>| vol.get(pos).map_or(true, |vox| vox.is_empty());
|
draw_dim,
|
||||||
let should_draw = |vol: &mut V, pos: Vec3<i32>, delta: Vec3<i32>, uv| {
|
norm,
|
||||||
should_draw_greedy(pos, delta, uv, |vox| {
|
meta,
|
||||||
vol.get(vox).map(|vox| *vox).unwrap_or(Cell::empty())
|
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
||||||
})
|
));
|
||||||
};
|
},
|
||||||
let create_opaque = |_atlas_pos, pos: Vec3<f32>, norm| ParticleVertex::new(pos, norm);
|
make_face_texel: move |vol: &mut V, pos, light, glow| {
|
||||||
|
TerrainVertex::make_col_light(light, glow, get_color(vol, pos))
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
let mut opaque_mesh = Mesh::new();
|
(opaque_mesh, Mesh::new(), Mesh::new(), ())
|
||||||
greedy.push(GreedyConfig {
|
|
||||||
data: self,
|
|
||||||
draw_delta,
|
|
||||||
greedy_size,
|
|
||||||
greedy_size_cross,
|
|
||||||
get_light,
|
|
||||||
get_glow,
|
|
||||||
get_opacity,
|
|
||||||
should_draw,
|
|
||||||
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &()| {
|
|
||||||
opaque_mesh.push_quad(greedy::create_quad(
|
|
||||||
atlas_origin,
|
|
||||||
dim,
|
|
||||||
origin,
|
|
||||||
draw_dim,
|
|
||||||
norm,
|
|
||||||
meta,
|
|
||||||
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
make_face_texel: move |vol: &mut V, pos, light, glow| {
|
|
||||||
TerrainVertex::make_col_light(light, glow, get_color(vol, pos))
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
(opaque_mesh, Mesh::new(), Mesh::new(), ())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_draw_greedy(
|
fn should_draw_greedy(
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{
|
mesh::{
|
||||||
greedy::{self, GreedyConfig, GreedyMesh},
|
greedy::{self, GreedyConfig, GreedyMesh},
|
||||||
MeshGen, Meshable,
|
MeshGen,
|
||||||
},
|
},
|
||||||
render::{self, ColLightInfo, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline},
|
render::{ColLightInfo, FluidVertex, Mesh, TerrainVertex},
|
||||||
scene::terrain::BlocksOfInterest,
|
scene::terrain::BlocksOfInterest,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -17,9 +17,6 @@ use std::{collections::VecDeque, fmt::Debug, sync::Arc};
|
|||||||
use tracing::error;
|
use tracing::error;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
|
||||||
type FluidVertex = <FluidPipeline as render::Pipeline>::Vertex;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum FaceKind {
|
enum FaceKind {
|
||||||
/// Opaque face that is facing something non-opaque; either
|
/// Opaque face that is facing something non-opaque; either
|
||||||
@ -225,243 +222,234 @@ fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>
|
#[allow(clippy::collapsible_if)]
|
||||||
Meshable<TerrainPipeline, FluidPipeline> for &'a VolGrid2d<V>
|
#[allow(clippy::many_single_char_names)]
|
||||||
{
|
#[allow(clippy::needless_range_loop)] // TODO: Pending review in #587
|
||||||
type Pipeline = TerrainPipeline;
|
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||||
#[allow(clippy::type_complexity)]
|
pub fn generate_mesh<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + 'static>(
|
||||||
type Result = (
|
vol: &'a VolGrid2d<V>,
|
||||||
|
(range, max_texture_size): (Aabb<i32>, Vec2<u16>),
|
||||||
|
(range, max_texture_size, _boi): (Aabb<i32>, Vec2<u16>, &'a BlocksOfInterest),
|
||||||
|
) -> MeshGen<
|
||||||
|
TerrainVertex,
|
||||||
|
FluidVertex,
|
||||||
|
TerrainVertex,
|
||||||
|
(
|
||||||
Aabb<f32>,
|
Aabb<f32>,
|
||||||
ColLightInfo,
|
ColLightInfo,
|
||||||
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
||||||
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
||||||
|
),
|
||||||
|
> {
|
||||||
|
span!(
|
||||||
|
_guard,
|
||||||
|
"generate_mesh",
|
||||||
|
"<&VolGrid2d as Meshable<_, _>>::generate_mesh"
|
||||||
);
|
);
|
||||||
type ShadowPipeline = ShadowPipeline;
|
|
||||||
type Supplement = (Aabb<i32>, Vec2<u16>, &'a BlocksOfInterest);
|
|
||||||
type TranslucentPipeline = FluidPipeline;
|
|
||||||
|
|
||||||
#[allow(clippy::collapsible_if)]
|
// Find blocks that should glow
|
||||||
#[allow(clippy::many_single_char_names)]
|
// TODO: Search neighbouring chunks too!
|
||||||
#[allow(clippy::needless_range_loop)] // TODO: Pending review in #587
|
// let glow_blocks = boi.lights
|
||||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
// .iter()
|
||||||
fn generate_mesh(
|
// .map(|(pos, glow)| (*pos + range.min.xy(), *glow));
|
||||||
self,
|
/* DefaultVolIterator::new(self, range.min - MAX_LIGHT_DIST, range.max + MAX_LIGHT_DIST)
|
||||||
(range, max_texture_size, _boi): Self::Supplement,
|
.filter_map(|(pos, block)| block.get_glow().map(|glow| (pos, glow))); */
|
||||||
) -> MeshGen<TerrainPipeline, FluidPipeline, Self> {
|
|
||||||
span!(
|
|
||||||
_guard,
|
|
||||||
"generate_mesh",
|
|
||||||
"<&VolGrid2d as Meshable<_, _>>::generate_mesh"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find blocks that should glow
|
let mut glow_blocks = Vec::new();
|
||||||
// TODO: Search neighbouring chunks too!
|
|
||||||
// let glow_blocks = boi.lights
|
|
||||||
// .iter()
|
|
||||||
// .map(|(pos, glow)| (*pos + range.min.xy(), *glow));
|
|
||||||
/* DefaultVolIterator::new(self, range.min - MAX_LIGHT_DIST, range.max + MAX_LIGHT_DIST)
|
|
||||||
.filter_map(|(pos, block)| block.get_glow().map(|glow| (pos, glow))); */
|
|
||||||
|
|
||||||
let mut glow_blocks = Vec::new();
|
// TODO: This expensive, use BlocksOfInterest instead
|
||||||
|
let mut volume = self.cached();
|
||||||
// TODO: This expensive, use BlocksOfInterest instead
|
for x in -MAX_LIGHT_DIST..range.size().w + MAX_LIGHT_DIST {
|
||||||
let mut volume = self.cached();
|
for y in -MAX_LIGHT_DIST..range.size().h + MAX_LIGHT_DIST {
|
||||||
for x in -MAX_LIGHT_DIST..range.size().w + MAX_LIGHT_DIST {
|
for z in -1..range.size().d + 1 {
|
||||||
for y in -MAX_LIGHT_DIST..range.size().h + MAX_LIGHT_DIST {
|
let wpos = range.min + Vec3::new(x, y, z);
|
||||||
for z in -1..range.size().d + 1 {
|
volume
|
||||||
let wpos = range.min + Vec3::new(x, y, z);
|
.get(wpos)
|
||||||
volume
|
.ok()
|
||||||
.get(wpos)
|
.and_then(|b| b.get_glow())
|
||||||
.ok()
|
.map(|glow| glow_blocks.push((wpos, glow)));
|
||||||
.and_then(|b| b.get_glow())
|
|
||||||
.map(|glow| glow_blocks.push((wpos, glow)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate chunk lighting (sunlight defaults to 1.0, glow to 0.0)
|
// Calculate chunk lighting (sunlight defaults to 1.0, glow to 0.0)
|
||||||
let light = calc_light(true, SUNLIGHT, range, self, core::iter::empty());
|
let light = calc_light(true, SUNLIGHT, range, self, core::iter::empty());
|
||||||
let glow = calc_light(false, 0, range, self, glow_blocks.into_iter());
|
let glow = calc_light(false, 0, range, self, glow_blocks.into_iter());
|
||||||
|
|
||||||
let mut opaque_limits = None::<Limits>;
|
let mut opaque_limits = None::<Limits>;
|
||||||
let mut fluid_limits = None::<Limits>;
|
let mut fluid_limits = None::<Limits>;
|
||||||
let mut air_limits = None::<Limits>;
|
let mut air_limits = None::<Limits>;
|
||||||
let flat_get = {
|
let flat_get = {
|
||||||
span!(_guard, "copy to flat array");
|
span!(_guard, "copy to flat array");
|
||||||
let (w, h, d) = range.size().into_tuple();
|
let (w, h, d) = range.size().into_tuple();
|
||||||
// z can range from -1..range.size().d + 1
|
// z can range from -1..range.size().d + 1
|
||||||
let d = d + 2;
|
let d = d + 2;
|
||||||
let flat = {
|
let flat = {
|
||||||
let mut volume = self.cached();
|
let mut volume = vol.cached();
|
||||||
|
const AIR: Block = Block::air(common::terrain::sprite::SpriteKind::Empty);
|
||||||
const AIR: Block = Block::air(common::terrain::sprite::SpriteKind::Empty);
|
// TODO: Once we can manage it sensibly, consider using something like
|
||||||
|
// Option<Block> instead of just assuming air.
|
||||||
// TODO: Once we can manage it sensibly, consider using something like
|
let mut flat = vec![AIR; (w * h * d) as usize];
|
||||||
// Option<Block> instead of just assuming air.
|
let mut i = 0;
|
||||||
let mut flat = vec![AIR; (w * h * d) as usize];
|
for x in 0..range.size().w {
|
||||||
let mut i = 0;
|
for y in 0..range.size().h {
|
||||||
for x in 0..range.size().w {
|
for z in -1..range.size().d + 1 {
|
||||||
for y in 0..range.size().h {
|
let wpos = range.min + Vec3::new(x, y, z);
|
||||||
for z in -1..range.size().d + 1 {
|
let block = volume
|
||||||
let wpos = range.min + Vec3::new(x, y, z);
|
.get(wpos)
|
||||||
let block = volume
|
.map(|b| *b)
|
||||||
.get(wpos)
|
// TODO: Replace with None or some other more reasonable value,
|
||||||
.map(|b| *b)
|
// since it's not clear this will work properly with liquid.
|
||||||
// TODO: Replace with None or some other more reasonable value,
|
.unwrap_or(AIR);
|
||||||
// since it's not clear this will work properly with liquid.
|
if block.is_opaque() {
|
||||||
.unwrap_or(AIR);
|
opaque_limits = opaque_limits
|
||||||
if block.is_opaque() {
|
.map(|l| l.including(z))
|
||||||
opaque_limits = opaque_limits
|
.or_else(|| Some(Limits::from_value(z)));
|
||||||
.map(|l| l.including(z))
|
} else if block.is_liquid() {
|
||||||
.or_else(|| Some(Limits::from_value(z)));
|
fluid_limits = fluid_limits
|
||||||
} else if block.is_liquid() {
|
.map(|l| l.including(z))
|
||||||
fluid_limits = fluid_limits
|
.or_else(|| Some(Limits::from_value(z)));
|
||||||
.map(|l| l.including(z))
|
} else {
|
||||||
.or_else(|| Some(Limits::from_value(z)));
|
// Assume air
|
||||||
} else {
|
air_limits = air_limits
|
||||||
// Assume air
|
.map(|l| l.including(z))
|
||||||
air_limits = air_limits
|
.or_else(|| Some(Limits::from_value(z)));
|
||||||
.map(|l| l.including(z))
|
};
|
||||||
.or_else(|| Some(Limits::from_value(z)));
|
flat[i] = block;
|
||||||
};
|
i += 1;
|
||||||
flat[i] = block;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flat
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {}", x, y, z, d, h),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
flat
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constrain iterated area
|
move |Vec3 { x, y, z }| {
|
||||||
let (z_start, z_end) = match (air_limits, fluid_limits, opaque_limits) {
|
// z can range from -1..range.size().d + 1
|
||||||
(Some(air), Some(fluid), Some(opaque)) => air.three_way_intersection(fluid, opaque),
|
let z = z + 1;
|
||||||
(Some(air), Some(fluid), None) => air.intersection(fluid),
|
match flat.get((x * h * d + y * d + z) as usize).copied() {
|
||||||
(Some(air), None, Some(opaque)) => air.intersection(opaque),
|
Some(b) => b,
|
||||||
(None, Some(fluid), Some(opaque)) => fluid.intersection(opaque),
|
None => panic!("x {} y {} z {} d {} h {}", x, y, z, d, h),
|
||||||
// No interfaces (Note: if there are multiple fluid types this could change)
|
}
|
||||||
(Some(_), None, None) | (None, Some(_), None) | (None, None, Some(_)) => None,
|
|
||||||
(None, None, None) => {
|
|
||||||
error!("Impossible unless given an input AABB that has a height of zero");
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
.map_or((0, 0), |limits| {
|
};
|
||||||
let (start, end) = limits.into_tuple();
|
|
||||||
let start = start.max(0);
|
|
||||||
let end = end.min(range.size().d - 1).max(start);
|
|
||||||
(start, end)
|
|
||||||
});
|
|
||||||
|
|
||||||
let max_size =
|
// Constrain iterated area
|
||||||
guillotiere::Size::new(i32::from(max_texture_size.x), i32::from(max_texture_size.y));
|
let (z_start, z_end) = match (air_limits, fluid_limits, opaque_limits) {
|
||||||
assert!(z_end >= z_start);
|
(Some(air), Some(fluid), Some(opaque)) => air.three_way_intersection(fluid, opaque),
|
||||||
let greedy_size = Vec3::new(range.size().w - 2, range.size().h - 2, z_end - z_start + 1);
|
(Some(air), Some(fluid), None) => air.intersection(fluid),
|
||||||
// NOTE: Terrain sizes are limited to 32 x 32 x 16384 (to fit in 24 bits: 5 + 5
|
(Some(air), None, Some(opaque)) => air.intersection(opaque),
|
||||||
// + 14). FIXME: Make this function fallible, since the terrain
|
(None, Some(fluid), Some(opaque)) => fluid.intersection(opaque),
|
||||||
// information might be dynamically generated which would make this hard
|
// No interfaces (Note: if there are multiple fluid types this could change)
|
||||||
// to enforce.
|
(Some(_), None, None) | (None, Some(_), None) | (None, None, Some(_)) => None,
|
||||||
assert!(greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 16384);
|
(None, None, None) => {
|
||||||
// NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16,
|
error!("Impossible unless given an input AABB that has a height of zero");
|
||||||
// which always fits into a f32.
|
None
|
||||||
let max_bounds: Vec3<f32> = greedy_size.as_::<f32>();
|
},
|
||||||
// NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16,
|
|
||||||
// which always fits into a usize.
|
|
||||||
let greedy_size = greedy_size.as_::<usize>();
|
|
||||||
let greedy_size_cross = Vec3::new(greedy_size.x - 1, greedy_size.y - 1, greedy_size.z);
|
|
||||||
let draw_delta = Vec3::new(1, 1, z_start);
|
|
||||||
|
|
||||||
let get_light = |_: &mut (), pos: Vec3<i32>| {
|
|
||||||
if flat_get(pos).is_opaque() {
|
|
||||||
0.0
|
|
||||||
} else {
|
|
||||||
light(pos + range.min)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let get_glow = |_: &mut (), pos: Vec3<i32>| glow(pos + range.min);
|
|
||||||
let get_color =
|
|
||||||
|_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or(Rgb::zero());
|
|
||||||
let get_opacity = |_: &mut (), pos: Vec3<i32>| !flat_get(pos).is_opaque();
|
|
||||||
let flat_get = |pos| flat_get(pos);
|
|
||||||
let should_draw = |_: &mut (), pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
|
||||||
should_draw_greedy(pos, delta, flat_get)
|
|
||||||
};
|
|
||||||
// NOTE: Conversion to f32 is fine since this i32 is actually in bounds for u16.
|
|
||||||
let mesh_delta = Vec3::new(0.0, 0.0, (z_start + range.min.z) as f32);
|
|
||||||
let create_opaque = |atlas_pos, pos, norm, meta| {
|
|
||||||
TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta)
|
|
||||||
};
|
|
||||||
let create_transparent = |_atlas_pos, pos, norm| FluidVertex::new(pos + mesh_delta, norm);
|
|
||||||
|
|
||||||
let mut greedy = GreedyMesh::new(max_size);
|
|
||||||
let mut opaque_mesh = Mesh::new();
|
|
||||||
let mut fluid_mesh = Mesh::new();
|
|
||||||
greedy.push(GreedyConfig {
|
|
||||||
data: (),
|
|
||||||
draw_delta,
|
|
||||||
greedy_size,
|
|
||||||
greedy_size_cross,
|
|
||||||
get_light,
|
|
||||||
get_glow,
|
|
||||||
get_opacity,
|
|
||||||
should_draw,
|
|
||||||
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &FaceKind| match meta {
|
|
||||||
FaceKind::Opaque(meta) => {
|
|
||||||
opaque_mesh.push_quad(greedy::create_quad(
|
|
||||||
atlas_origin,
|
|
||||||
dim,
|
|
||||||
origin,
|
|
||||||
draw_dim,
|
|
||||||
norm,
|
|
||||||
meta,
|
|
||||||
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
FaceKind::Fluid => {
|
|
||||||
fluid_mesh.push_quad(greedy::create_quad(
|
|
||||||
atlas_origin,
|
|
||||||
dim,
|
|
||||||
origin,
|
|
||||||
draw_dim,
|
|
||||||
norm,
|
|
||||||
&(),
|
|
||||||
|atlas_pos, pos, norm, &_meta| create_transparent(atlas_pos, pos, norm),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
make_face_texel: |data: &mut (), pos, light, glow| {
|
|
||||||
TerrainVertex::make_col_light(light, glow, get_color(data, pos))
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let min_bounds = mesh_delta;
|
|
||||||
let bounds = Aabb {
|
|
||||||
min: min_bounds,
|
|
||||||
max: max_bounds + min_bounds,
|
|
||||||
};
|
|
||||||
let (col_lights, col_lights_size) = greedy.finalize();
|
|
||||||
|
|
||||||
(
|
|
||||||
opaque_mesh,
|
|
||||||
fluid_mesh,
|
|
||||||
Mesh::new(),
|
|
||||||
(
|
|
||||||
bounds,
|
|
||||||
(col_lights, col_lights_size),
|
|
||||||
Arc::new(light),
|
|
||||||
Arc::new(glow),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
.map_or((0, 0), |limits| {
|
||||||
|
let (start, end) = limits.into_tuple();
|
||||||
|
let start = start.max(0);
|
||||||
|
let end = end.min(range.size().d - 1).max(start);
|
||||||
|
(start, end)
|
||||||
|
});
|
||||||
|
|
||||||
|
let max_size =
|
||||||
|
guillotiere::Size::new(i32::from(max_texture_size.x), i32::from(max_texture_size.y));
|
||||||
|
assert!(z_end >= z_start);
|
||||||
|
let greedy_size = Vec3::new(range.size().w - 2, range.size().h - 2, z_end - z_start + 1);
|
||||||
|
// NOTE: Terrain sizes are limited to 32 x 32 x 16384 (to fit in 24 bits: 5 + 5
|
||||||
|
// + 14). FIXME: Make this function fallible, since the terrain
|
||||||
|
// information might be dynamically generated which would make this hard
|
||||||
|
// to enforce.
|
||||||
|
assert!(greedy_size.x <= 32 && greedy_size.y <= 32 && greedy_size.z <= 16384);
|
||||||
|
// NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16,
|
||||||
|
// which always fits into a f32.
|
||||||
|
let max_bounds: Vec3<f32> = greedy_size.as_::<f32>();
|
||||||
|
// NOTE: Cast is safe by prior assertion on greedy_size; it fits into a u16,
|
||||||
|
// which always fits into a usize.
|
||||||
|
let greedy_size = greedy_size.as_::<usize>();
|
||||||
|
let greedy_size_cross = Vec3::new(greedy_size.x - 1, greedy_size.y - 1, greedy_size.z);
|
||||||
|
let draw_delta = Vec3::new(1, 1, z_start);
|
||||||
|
|
||||||
|
let get_light = |_: &mut (), pos: Vec3<i32>| {
|
||||||
|
if flat_get(pos).is_opaque() {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
light(pos + range.min)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let get_glow = |_: &mut (), pos: Vec3<i32>| glow(pos + range.min);
|
||||||
|
let get_color = |_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or(Rgb::zero());
|
||||||
|
let get_opacity = |_: &mut (), pos: Vec3<i32>| !flat_get(pos).is_opaque();
|
||||||
|
let flat_get = |pos| flat_get(pos);
|
||||||
|
let should_draw = |_: &mut (), pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
||||||
|
should_draw_greedy(pos, delta, flat_get)
|
||||||
|
};
|
||||||
|
// NOTE: Conversion to f32 is fine since this i32 is actually in bounds for u16.
|
||||||
|
let mesh_delta = Vec3::new(0.0, 0.0, (z_start + range.min.z) as f32);
|
||||||
|
let create_opaque =
|
||||||
|
|atlas_pos, pos, norm, meta| TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta);
|
||||||
|
let create_transparent = |_atlas_pos, pos, norm| FluidVertex::new(pos + mesh_delta, norm);
|
||||||
|
|
||||||
|
let mut greedy = GreedyMesh::new(max_size);
|
||||||
|
let mut opaque_mesh = Mesh::new();
|
||||||
|
let mut fluid_mesh = Mesh::new();
|
||||||
|
greedy.push(GreedyConfig {
|
||||||
|
data: (),
|
||||||
|
draw_delta,
|
||||||
|
greedy_size,
|
||||||
|
greedy_size_cross,
|
||||||
|
get_light,
|
||||||
|
get_glow,
|
||||||
|
get_opacity,
|
||||||
|
should_draw,
|
||||||
|
push_quad: |atlas_origin, dim, origin, draw_dim, norm, meta: &FaceKind| match meta {
|
||||||
|
FaceKind::Opaque(meta) => {
|
||||||
|
opaque_mesh.push_quad(greedy::create_quad(
|
||||||
|
atlas_origin,
|
||||||
|
dim,
|
||||||
|
origin,
|
||||||
|
draw_dim,
|
||||||
|
norm,
|
||||||
|
meta,
|
||||||
|
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
FaceKind::Fluid => {
|
||||||
|
fluid_mesh.push_quad(greedy::create_quad(
|
||||||
|
atlas_origin,
|
||||||
|
dim,
|
||||||
|
origin,
|
||||||
|
draw_dim,
|
||||||
|
norm,
|
||||||
|
&(),
|
||||||
|
|atlas_pos, pos, norm, &_meta| create_transparent(atlas_pos, pos, norm),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
make_face_texel: |data: &mut (), pos, light, glow| {
|
||||||
|
TerrainVertex::make_col_light(light, glow, get_color(data, pos))
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let min_bounds = mesh_delta;
|
||||||
|
let bounds = Aabb {
|
||||||
|
min: min_bounds,
|
||||||
|
max: max_bounds + min_bounds,
|
||||||
|
};
|
||||||
|
let (col_lights, col_lights_size) = greedy.finalize();
|
||||||
|
|
||||||
|
(
|
||||||
|
opaque_mesh,
|
||||||
|
fluid_mesh,
|
||||||
|
Mesh::new(),
|
||||||
|
(
|
||||||
|
bounds,
|
||||||
|
(col_lights, col_lights_size),
|
||||||
|
Arc::new(light),
|
||||||
|
Arc::new(glow),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: Make sure to reflect any changes to how meshing is performanced in
|
/// NOTE: Make sure to reflect any changes to how meshing is performanced in
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Buffer<T: Copy + Pod> {
|
pub struct Buffer<T: Copy + Pod> {
|
||||||
pub buf: wgpu::Buffer,
|
pub buf: wgpu::Buffer,
|
||||||
// bytes
|
// bytes
|
||||||
@ -10,7 +9,7 @@ pub struct Buffer<T: Copy + Pod> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + Pod> Buffer<T> {
|
impl<T: Copy + Pod> Buffer<T> {
|
||||||
pub fn new(device: &mut wgpu::Device, cap: usize, usage: wgpu::BufferUsage) -> Self {
|
pub fn new(device: &wgpu::Device, cap: u64, usage: wgpu::BufferUsage) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buf: device.create_buffer(&wgpu::BufferDescriptor {
|
buf: device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
@ -23,8 +22,8 @@ impl<T: Copy + Pod> Buffer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_data(device: &mut wgpu::Device, usage: wgpu::BufferUsage, data: &[T]) -> Self {
|
pub fn new_with_data(device: &wgpu::Device, usage: wgpu::BufferUsage, data: &[T]) -> Self {
|
||||||
let contents = data.as_bytes();
|
let contents = bytemuck::cast_slice(data);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
@ -37,15 +36,9 @@ impl<T: Copy + Pod> Buffer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, vals: &[T], offset: u64) {
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
vals: &[T],
|
|
||||||
offset: usize,
|
|
||||||
) {
|
|
||||||
if !vals.is_empty() {
|
if !vals.is_empty() {
|
||||||
queue.write_buffer(&self.buf, offset, vals.as_bytes())
|
queue.write_buffer(&self.buf, offset, bytemuck::cast_slice(vals))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,29 +4,22 @@ use bytemuck::Pod;
|
|||||||
/// A handle to a series of constants sitting on the GPU. This is used to hold
|
/// A handle to a series of constants sitting on the GPU. This is used to hold
|
||||||
/// information used in the rendering process that does not change throughout a
|
/// information used in the rendering process that does not change throughout a
|
||||||
/// single render pass.
|
/// single render pass.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Consts<T: Copy + Pod> {
|
pub struct Consts<T: Copy + Pod> {
|
||||||
buf: Buffer<T>,
|
buf: Buffer<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + Pod> Consts<T> {
|
impl<T: Copy + Pod> Consts<T> {
|
||||||
/// Create a new `Const<T>`.
|
/// Create a new `Const<T>`.
|
||||||
pub fn new(device: &mut wgpu::Device, len: usize) -> Self {
|
pub fn new(device: &wgpu::Device, len: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buf: Buffer::new(device, len, wgpu::BufferUsage::UNIFORM),
|
buf: Buffer::new(device, len, wgpu::BufferUsage::UNIFORM),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the GPU-side value represented by this constant handle.
|
/// Update the GPU-side value represented by this constant handle.
|
||||||
pub fn update(
|
pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, vals: &[T], offset: u64) {
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
vals: &[T],
|
|
||||||
offset: usize,
|
|
||||||
) {
|
|
||||||
self.buf.update(device, queue, vals, offset)
|
self.buf.update(device, queue, vals, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf }
|
pub fn buf(&self) -> &wgpu::Buffer { &self.buf.buf }
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
use super::{buffer::Buffer, RenderError};
|
use super::buffer::Buffer;
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
|
|
||||||
/// Represents a mesh that has been sent to the GPU.
|
/// Represents a mesh that has been sent to the GPU.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Instances<T: Copy + Pod> {
|
pub struct Instances<T: Copy + Pod> {
|
||||||
buf: Buffer<T>,
|
buf: Buffer<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Copy + Pod> Instances<T> {
|
impl<T: Copy + Pod> Instances<T> {
|
||||||
pub fn new(device: &mut wgpu::Device, len: usize) -> Self {
|
pub fn new(device: &wgpu::Device, len: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buf: Buffer::new(device, len, wgpu::BufferUsage::VERTEX),
|
buf: Buffer::new(device, len, wgpu::BufferUsage::VERTEX),
|
||||||
}
|
}
|
||||||
@ -16,15 +15,9 @@ impl<T: Copy + Pod> Instances<T> {
|
|||||||
|
|
||||||
pub fn count(&self) -> usize { self.buf.count() }
|
pub fn count(&self) -> usize { self.buf.count() }
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, vals: &[T], offset: u64) {
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
vals: &[T],
|
|
||||||
offset: usize,
|
|
||||||
) -> Result<(), RenderError> {
|
|
||||||
self.buf.update(device, queue, vals, offset)
|
self.buf.update(device, queue, vals, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf }
|
pub fn buf(&self) -> &wgpu::Buffer { &self.buf.buf }
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{buffer::Buffer, mesh::Mesh, RenderError, Vertex};
|
use super::{buffer::Buffer, mesh::Mesh, Vertex};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
/// Represents a mesh that has been sent to the GPU.
|
/// Represents a mesh that has been sent to the GPU.
|
||||||
@ -24,7 +24,7 @@ impl<V: Vertex> Model<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_dynamic(device: &wgpu::Device, size: usize) -> Self {
|
pub fn new_dynamic(device: &wgpu::Device, size: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
vbuf: Buffer::new(device, size, wgpu::BufferUsage::VERTEX),
|
vbuf: Buffer::new(device, size, wgpu::BufferUsage::VERTEX),
|
||||||
}
|
}
|
||||||
@ -45,10 +45,10 @@ impl<V: Vertex> Model<V> {
|
|||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
mesh: &Mesh<V>,
|
mesh: &Mesh<V>,
|
||||||
offset: usize,
|
offset: u64,
|
||||||
) -> Result<(), RenderError> {
|
) {
|
||||||
self.buf.update(device, queue, mesh.vertices(), offset)
|
self.vbuf.update(device, queue, mesh.vertices(), offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buf(&self) -> &wgpu::Buffer { self.vbuf.buf }
|
pub fn buf(&self) -> &wgpu::Buffer { &self.vbuf.buf }
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ use super::{
|
|||||||
terrain::Vertex,
|
terrain::Vertex,
|
||||||
};
|
};
|
||||||
use crate::mesh::greedy::GreedyMesh;
|
use crate::mesh::greedy::GreedyMesh;
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Locals {
|
pub struct Locals {
|
||||||
model_mat: [[f32; 4]; 4],
|
model_mat: [[f32; 4]; 4],
|
||||||
highlight_col: [f32; 4],
|
highlight_col: [f32; 4],
|
||||||
@ -19,7 +19,7 @@ pub struct Locals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct BoneData {
|
pub struct BoneData {
|
||||||
bone_mat: [[f32; 4]; 4],
|
bone_mat: [[f32; 4]; 4],
|
||||||
normals_mat: [[f32; 4]; 4],
|
normals_mat: [[f32; 4]; 4],
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts};
|
use super::super::{AaMode, GlobalsLayouts};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pos_norm: u32,
|
pos_norm: u32,
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts, Renderer, Texture};
|
use super::super::{AaMode, GlobalsLayouts, Renderer, Texture};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pos: [f32; 2],
|
pos: [f32; 2],
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ pub struct LodData {
|
|||||||
impl LodData {
|
impl LodData {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
map_size: Vec2<u16>,
|
map_size: Vec2<u32>,
|
||||||
lod_base: &[u32],
|
lod_base: &[u32],
|
||||||
lod_alt: &[u32],
|
lod_alt: &[u32],
|
||||||
lod_horizon: &[u32],
|
lod_horizon: &[u32],
|
||||||
@ -72,28 +72,41 @@ impl LodData {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut view_info = wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
};
|
||||||
|
|
||||||
let map = renderer.create_texture_with_data_raw(
|
let map = renderer.create_texture_with_data_raw(
|
||||||
&texture_info,
|
&texture_info,
|
||||||
|
&view_info,
|
||||||
&sampler_info,
|
&sampler_info,
|
||||||
map_size.x * 4,
|
map_size.x * 4,
|
||||||
[map_size.x, map_size.y],
|
bytemuck::cast_slice(lod_base),
|
||||||
lod_base.as_bytes(),
|
|
||||||
);
|
);
|
||||||
texture_info = wgpu::TextureFormat::Rg16Uint;
|
texture_info.format = wgpu::TextureFormat::Rg16Uint;
|
||||||
|
view_info.format = Some(wgpu::TextureFormat::Rg16Uint);
|
||||||
let alt = renderer.create_texture_with_data_raw(
|
let alt = renderer.create_texture_with_data_raw(
|
||||||
&texture_info,
|
&texture_info,
|
||||||
|
&view_info,
|
||||||
&sampler_info,
|
&sampler_info,
|
||||||
map_size.x * 4,
|
map_size.x * 4,
|
||||||
[map_size.x, map_size.y],
|
bytemuck::cast_slice(lod_base),
|
||||||
lod_base.as_bytes(),
|
|
||||||
);
|
);
|
||||||
texture_info = wgpu::TextureFormat::Rgba8Unorm;
|
texture_info.format = wgpu::TextureFormat::Rgba8Unorm;
|
||||||
|
view_info.format = Some(wgpu::TextureFormat::Rg16Uint);
|
||||||
let horizon = renderer.create_texture_with_data_raw(
|
let horizon = renderer.create_texture_with_data_raw(
|
||||||
&texture_info,
|
&texture_info,
|
||||||
|
&view_info,
|
||||||
&sampler_info,
|
&sampler_info,
|
||||||
map_size.x * 4,
|
map_size.x * 4,
|
||||||
[map_size.x, map_size.y],
|
bytemuck::cast_slice(lod_base),
|
||||||
lod_base.as_bytes(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -12,7 +12,7 @@ pub mod ui;
|
|||||||
|
|
||||||
use super::Consts;
|
use super::Consts;
|
||||||
use crate::scene::camera::CameraMode;
|
use crate::scene::camera::CameraMode;
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use common::terrain::BlockKind;
|
use common::terrain::BlockKind;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ pub const MAX_FIGURE_SHADOW_COUNT: usize = 24;
|
|||||||
pub const MAX_DIRECTED_LIGHT_COUNT: usize = 6;
|
pub const MAX_DIRECTED_LIGHT_COUNT: usize = 6;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Globals {
|
pub struct Globals {
|
||||||
view_mat: [[f32; 4]; 4],
|
view_mat: [[f32; 4]; 4],
|
||||||
proj_mat: [[f32; 4]; 4],
|
proj_mat: [[f32; 4]; 4],
|
||||||
@ -55,14 +55,14 @@ pub struct Globals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Light {
|
pub struct Light {
|
||||||
pos: [f32; 4],
|
pub pos: [f32; 4],
|
||||||
col: [f32; 4],
|
pub col: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Shadow {
|
pub struct Shadow {
|
||||||
pos_radius: [f32; 4],
|
pos_radius: [f32; 4],
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts};
|
use super::super::{AaMode, GlobalsLayouts};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pos: [f32; 3],
|
pos: [f32; 3],
|
||||||
// ____BBBBBBBBGGGGGGGGRRRRRRRR
|
// ____BBBBBBBBGGGGGGGGRRRRRRRR
|
||||||
@ -79,7 +79,7 @@ impl ParticleMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
// created_at time, so we can calculate time relativity, needed for relative animation.
|
// created_at time, so we can calculate time relativity, needed for relative animation.
|
||||||
// can save 32 bits per instance, for particles that are not relatively animated.
|
// can save 32 bits per instance, for particles that are not relatively animated.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts, Mesh, Tri};
|
use super::super::{AaMode, GlobalsLayouts, Mesh, Tri};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -23,7 +23,7 @@ impl Locals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pub pos: [f32; 2],
|
pub pos: [f32; 2],
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ use super::super::{
|
|||||||
AaMode, ColLightInfo, FigureLayout, GlobalsLayouts, Renderer, TerrainLayout, TerrainVertex,
|
AaMode, ColLightInfo, FigureLayout, GlobalsLayouts, Renderer, TerrainLayout, TerrainVertex,
|
||||||
Texture,
|
Texture,
|
||||||
};
|
};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Locals {
|
pub struct Locals {
|
||||||
shadow_matrices: [[f32; 4]; 4],
|
shadow_matrices: [[f32; 4]; 4],
|
||||||
texture_mats: [[f32; 4]; 4],
|
texture_mats: [[f32; 4]; 4],
|
||||||
@ -80,12 +80,23 @@ pub fn create_col_lights(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let view_info = wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
};
|
||||||
|
|
||||||
renderer.create_texture_with_data_raw(
|
renderer.create_texture_with_data_raw(
|
||||||
&texture_info,
|
&texture_info,
|
||||||
|
&view_info,
|
||||||
&sampler_info,
|
&sampler_info,
|
||||||
col_lights_size.x * 4,
|
col_lights_size.x * 4,
|
||||||
[col_lights_size.x, col_lights_size.y],
|
bytemuck::cast_slice(&col_lights),
|
||||||
col_lights.as_bytes(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts, Mesh, Quad};
|
use super::super::{AaMode, GlobalsLayouts, Mesh, Quad};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pub pos: [f32; 3],
|
pub pos: [f32; 3],
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts, TerrainLayout};
|
use super::super::{AaMode, GlobalsLayouts, TerrainLayout};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pos: [f32; 3],
|
pos: [f32; 3],
|
||||||
// Because we try to restrict terrain sprite data to a 128×128 block
|
// Because we try to restrict terrain sprite data to a 128×128 block
|
||||||
@ -70,7 +70,7 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
pos_ori: u32,
|
pos_ori: u32,
|
||||||
inst_mat0: [f32; 4],
|
inst_mat0: [f32; 4],
|
||||||
@ -122,7 +122,7 @@ impl Default for Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Locals {
|
pub struct Locals {
|
||||||
// Each matrix performs rotatation, translation, and scaling, relative to the sprite
|
// Each matrix performs rotatation, translation, and scaling, relative to the sprite
|
||||||
// origin, for all sprite instances. The matrix will be in an array indexed by the
|
// origin, for all sprite instances. The matrix will be in an array indexed by the
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts};
|
use super::super::{AaMode, GlobalsLayouts};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pos_norm: u32,
|
pos_norm: u32,
|
||||||
atlas_pos: u32,
|
atlas_pos: u32,
|
||||||
@ -118,7 +118,7 @@ impl Vertex {
|
|||||||
self.pos_norm = (self.pos_norm & !(0xF << 27)) | ((bone_idx as u32 & 0xF) << 27);
|
self.pos_norm = (self.pos_norm & !(0xF << 27)) | ((bone_idx as u32 & 0xF) << 27);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> {
|
pub fn desc<'a>() -> wgpu::VertexBufferDescriptor<'a> {
|
||||||
use std::mem;
|
use std::mem;
|
||||||
wgpu::VertexBufferDescriptor {
|
wgpu::VertexBufferDescriptor {
|
||||||
stride: mem::size_of::<Self>() as wgpu::BufferAddress,
|
stride: mem::size_of::<Self>() as wgpu::BufferAddress,
|
||||||
@ -129,7 +129,7 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Locals {
|
pub struct Locals {
|
||||||
model_offs: [f32; 3],
|
model_offs: [f32; 3],
|
||||||
load_time: f32,
|
load_time: f32,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use super::super::{AaMode, GlobalsLayouts, Quad, Tri};
|
use super::super::{AaMode, GlobalsLayouts, Quad, Tri};
|
||||||
use bytemuck::Pod;
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pos: [f32; 2],
|
pos: [f32; 2],
|
||||||
uv: [f32; 2],
|
uv: [f32; 2],
|
||||||
@ -24,7 +24,7 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, Pod)]
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
pub struct Locals {
|
pub struct Locals {
|
||||||
pos: [f32; 4],
|
pos: [f32; 4],
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ use vek::*;
|
|||||||
|
|
||||||
/// A type representing data that can be converted to an immutable texture map
|
/// A type representing data that can be converted to an immutable texture map
|
||||||
/// of ColLight data (used for texture atlases created during greedy meshing).
|
/// of ColLight data (used for texture atlases created during greedy meshing).
|
||||||
pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u16>);
|
pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u32>);
|
||||||
|
|
||||||
/// Load from a GLSL file.
|
/// Load from a GLSL file.
|
||||||
pub struct Glsl(String);
|
pub struct Glsl(String);
|
||||||
@ -150,11 +150,9 @@ impl assets::Compound for Shaders {
|
|||||||
pub struct ShadowMapRenderer {
|
pub struct ShadowMapRenderer {
|
||||||
// directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
// directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
// point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
// point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
directed_depth_stencil_view: wgpu::TextureView,
|
directed_depth_stencil: Texture,
|
||||||
directed_sampler: wgpu::Sampler,
|
|
||||||
|
|
||||||
point_depth_stencil_view: wgpu::TextureView,
|
point_depth_stencil: Texture,
|
||||||
point_sampler: wgpu::Sampler,
|
|
||||||
|
|
||||||
point_pipeline: shadow::ShadowPipeline,
|
point_pipeline: shadow::ShadowPipeline,
|
||||||
terrain_directed_pipeline: shadow::ShadowPipeline,
|
terrain_directed_pipeline: shadow::ShadowPipeline,
|
||||||
@ -179,7 +177,9 @@ pub struct Layouts {
|
|||||||
/// rendering subsystem and contains any state necessary to interact with the
|
/// rendering subsystem and contains any state necessary to interact with the
|
||||||
/// GPU, along with pipeline state objects (PSOs) needed to renderer different
|
/// GPU, along with pipeline state objects (PSOs) needed to renderer different
|
||||||
/// kinds of models to the screen.
|
/// kinds of models to the screen.
|
||||||
pub struct Renderer {
|
pub struct Renderer<'a> {
|
||||||
|
window: &'a winit::window::Window,
|
||||||
|
|
||||||
device: wgpu::Device,
|
device: wgpu::Device,
|
||||||
queue: wgpu::Queue,
|
queue: wgpu::Queue,
|
||||||
swap_chain: wgpu::SwapChain,
|
swap_chain: wgpu::SwapChain,
|
||||||
@ -218,13 +218,10 @@ pub struct Renderer {
|
|||||||
mode: RenderMode,
|
mode: RenderMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl<'a> Renderer<'a> {
|
||||||
/// Create a new `Renderer` from a variety of backend-specific components
|
/// Create a new `Renderer` from a variety of backend-specific components
|
||||||
/// and the window targets.
|
/// and the window targets.
|
||||||
pub async fn new(
|
pub fn new(window: &'a winit::window::Window, mode: RenderMode) -> Result<Self, RenderError> {
|
||||||
window: &winit::window::Window,
|
|
||||||
mode: RenderMode,
|
|
||||||
) -> Result<Self, RenderError> {
|
|
||||||
// Enable seamless cubemaps globally, where available--they are essentially a
|
// Enable seamless cubemaps globally, where available--they are essentially a
|
||||||
// strict improvement on regular cube maps.
|
// strict improvement on regular cube maps.
|
||||||
//
|
//
|
||||||
@ -241,29 +238,27 @@ impl Renderer {
|
|||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
let surface = unsafe { instance.create_surface(window) };
|
let surface = unsafe { instance.create_surface(window) };
|
||||||
|
|
||||||
let adapter = instance
|
let adapter = futures::executor::block_on(instance.request_adapter(
|
||||||
.request_adapter(wgpu::RequestAdapterOptionsBase {
|
&wgpu::RequestAdapterOptionsBase {
|
||||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||||
compatible_surface: Some(surface),
|
compatible_surface: Some(&surface),
|
||||||
})
|
},
|
||||||
.await
|
))
|
||||||
.ok_or(RenderError::CouldNotFindAdapter)?;
|
.ok_or(RenderError::CouldNotFindAdapter)?;
|
||||||
|
|
||||||
use wgpu::{Features, Limits};
|
use wgpu::{Features, Limits};
|
||||||
|
|
||||||
let (device, queue) = adapter
|
let (device, queue) = futures::executor::block_on(adapter.request_device(
|
||||||
.request_device(
|
&wgpu::DeviceDescriptor {
|
||||||
wgpu::DeviceDescriptor {
|
// TODO
|
||||||
// TODO
|
features: Features::DEPTH_CLAMPING | Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||||
features: Features::DEPTH_CLAMPING | Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
limits: Limits::default(),
|
||||||
limits: Limits::default(),
|
shader_validation: true,
|
||||||
shader_validation: true,
|
},
|
||||||
},
|
None,
|
||||||
None,
|
))?;
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let info = device.get_info();
|
let info = adapter.get_info();
|
||||||
info!(
|
info!(
|
||||||
?info.name,
|
?info.name,
|
||||||
?info.vendor,
|
?info.vendor,
|
||||||
@ -276,8 +271,8 @@ impl Renderer {
|
|||||||
let sc_desc = wgpu::SwapChainDescriptor {
|
let sc_desc = wgpu::SwapChainDescriptor {
|
||||||
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||||
width: dims.0,
|
width: dims.width,
|
||||||
height: dims.1,
|
height: dims.height,
|
||||||
present_mode: wgpu::PresentMode::Immediate,
|
present_mode: wgpu::PresentMode::Immediate,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -285,7 +280,7 @@ impl Renderer {
|
|||||||
|
|
||||||
let shadow_views = Self::create_shadow_views(
|
let shadow_views = Self::create_shadow_views(
|
||||||
&device,
|
&device,
|
||||||
(dims.0, dims.1),
|
(dims.width, dims.height),
|
||||||
&ShadowMapMode::try_from(mode.shadow).unwrap_or_default(),
|
&ShadowMapMode::try_from(mode.shadow).unwrap_or_default(),
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -334,14 +329,10 @@ impl Renderer {
|
|||||||
point_shadow_pipeline,
|
point_shadow_pipeline,
|
||||||
terrain_directed_shadow_pipeline,
|
terrain_directed_shadow_pipeline,
|
||||||
figure_directed_shadow_pipeline,
|
figure_directed_shadow_pipeline,
|
||||||
) = create_pipelines(
|
) = create_pipelines(&device, &layouts, &mode, &sc_desc, shadow_views.is_some())?;
|
||||||
&device,
|
|
||||||
&layouts & mode,
|
|
||||||
shadow_views.is_some(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) =
|
let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) =
|
||||||
Self::create_rt_views(&device, (dims.0, dims.1), &mode)?;
|
Self::create_rt_views(&device, (dims.width, dims.height), &mode)?;
|
||||||
|
|
||||||
let shadow_map = if let (
|
let shadow_map = if let (
|
||||||
Some(point_pipeline),
|
Some(point_pipeline),
|
||||||
@ -354,25 +345,16 @@ impl Renderer {
|
|||||||
figure_directed_shadow_pipeline,
|
figure_directed_shadow_pipeline,
|
||||||
shadow_views,
|
shadow_views,
|
||||||
) {
|
) {
|
||||||
let (
|
let (point_depth_stencil, directed_depth_stencil) = shadow_views;
|
||||||
point_depth_stencil_view,
|
|
||||||
point_res,
|
|
||||||
point_sampler,
|
|
||||||
directed_depth_stencil_view,
|
|
||||||
directed_res,
|
|
||||||
directed_sampler,
|
|
||||||
) = shadow_views;
|
|
||||||
|
|
||||||
let layout = shadow::ShadowLayout::new(&device);
|
let layout = shadow::ShadowLayout::new(&device);
|
||||||
|
|
||||||
Some(ShadowMapRenderer {
|
Some(ShadowMapRenderer {
|
||||||
directed_depth_stencil_view,
|
directed_depth_stencil,
|
||||||
directed_sampler,
|
|
||||||
|
|
||||||
// point_encoder: factory.create_command_buffer().into(),
|
// point_encoder: factory.create_command_buffer().into(),
|
||||||
// directed_encoder: factory.create_command_buffer().into(),
|
// directed_encoder: factory.create_command_buffer().into(),
|
||||||
point_depth_stencil_view,
|
point_depth_stencil,
|
||||||
point_sampler,
|
|
||||||
|
|
||||||
point_pipeline,
|
point_pipeline,
|
||||||
terrain_directed_pipeline,
|
terrain_directed_pipeline,
|
||||||
@ -405,6 +387,8 @@ impl Renderer {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
window,
|
||||||
|
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
swap_chain,
|
swap_chain,
|
||||||
@ -472,43 +456,24 @@ impl Renderer {
|
|||||||
|
|
||||||
/// Resize internal render targets to match window render target dimensions.
|
/// Resize internal render targets to match window render target dimensions.
|
||||||
pub fn on_resize(&mut self) -> Result<(), RenderError> {
|
pub fn on_resize(&mut self) -> Result<(), RenderError> {
|
||||||
let dims = self.win_color_view.get_dimensions();
|
let dims = self.window.inner_size();
|
||||||
|
|
||||||
// Avoid panics when creating texture with w,h of 0,0.
|
// Avoid panics when creating texture with w,h of 0,0.
|
||||||
if dims.0 != 0 && dims.1 != 0 {
|
if dims.width != 0 && dims.height != 0 {
|
||||||
let (
|
let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) =
|
||||||
tgt_color_view,
|
Self::create_rt_views(&mut self.device, (dims.width, dims.height), &self.mode)?;
|
||||||
tgt_depth_stencil_view,
|
self.win_depth_view = win_depth_view;
|
||||||
tgt_color_pp_view,
|
|
||||||
tgt_color_res,
|
|
||||||
tgt_depth_res,
|
|
||||||
tgt_color_res_pp,
|
|
||||||
) = Self::create_rt_views(&mut self.factory, (dims.0, dims.1), &self.mode)?;
|
|
||||||
self.tgt_color_res = tgt_color_res;
|
|
||||||
self.tgt_depth_res = tgt_depth_res;
|
|
||||||
self.tgt_color_res_pp = tgt_color_res_pp;
|
|
||||||
self.tgt_color_view = tgt_color_view;
|
self.tgt_color_view = tgt_color_view;
|
||||||
self.tgt_depth_stencil_view = tgt_depth_stencil_view;
|
self.tgt_depth_stencil_view = tgt_depth_stencil_view;
|
||||||
self.tgt_color_pp_view = tgt_color_pp_view;
|
self.tgt_color_pp_view = tgt_color_pp_view;
|
||||||
if let (Some(shadow_map), ShadowMode::Map(mode)) =
|
if let (Some(shadow_map), ShadowMode::Map(mode)) =
|
||||||
(self.shadow_map.as_mut(), self.mode.shadow)
|
(self.shadow_map.as_mut(), self.mode.shadow)
|
||||||
{
|
{
|
||||||
match Self::create_shadow_views(&mut self.factory, (dims.0, dims.1), &mode) {
|
match Self::create_shadow_views(&mut self.device, (dims.width, dims.height), &mode)
|
||||||
Ok((
|
{
|
||||||
point_depth_stencil_view,
|
Ok((point_depth_stencil, directed_depth_stencil)) => {
|
||||||
point_res,
|
shadow_map.point_depth_stencil = point_depth_stencil;
|
||||||
point_sampler,
|
shadow_map.directed_depth_stencil = directed_depth_stencil;
|
||||||
directed_depth_stencil_view,
|
|
||||||
directed_res,
|
|
||||||
directed_sampler,
|
|
||||||
)) => {
|
|
||||||
shadow_map.point_depth_stencil_view = point_depth_stencil_view;
|
|
||||||
shadow_map.point_res = point_res;
|
|
||||||
shadow_map.point_sampler = point_sampler;
|
|
||||||
|
|
||||||
shadow_map.directed_depth_stencil_view = directed_depth_stencil_view;
|
|
||||||
shadow_map.directed_res = directed_res;
|
|
||||||
shadow_map.directed_sampler = directed_sampler;
|
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("Could not create shadow map views: {:?}", err);
|
warn!("Could not create shadow map views: {:?}", err);
|
||||||
@ -522,7 +487,7 @@ impl Renderer {
|
|||||||
|
|
||||||
fn create_rt_views(
|
fn create_rt_views(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
size: (u16, u16),
|
size: (u32, u32),
|
||||||
mode: &RenderMode,
|
mode: &RenderMode,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
@ -565,9 +530,10 @@ impl Renderer {
|
|||||||
label: None,
|
label: None,
|
||||||
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
aspect: wgpu::TextureAspect::Color,
|
// TODO: why is this not Color?
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
base_mip_level: 0,
|
base_mip_level: 0,
|
||||||
level_count: Some(levels),
|
level_count: None,
|
||||||
base_array_layer: 0,
|
base_array_layer: 0,
|
||||||
array_layer_count: None,
|
array_layer_count: None,
|
||||||
})
|
})
|
||||||
@ -596,7 +562,7 @@ impl Renderer {
|
|||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
aspect: wgpu::TextureAspect::DepthOnly,
|
aspect: wgpu::TextureAspect::DepthOnly,
|
||||||
base_mip_level: 0,
|
base_mip_level: 0,
|
||||||
level_count: Some(levels),
|
level_count: None,
|
||||||
base_array_layer: 0,
|
base_array_layer: 0,
|
||||||
array_layer_count: None,
|
array_layer_count: None,
|
||||||
});
|
});
|
||||||
@ -620,7 +586,7 @@ impl Renderer {
|
|||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
aspect: wgpu::TextureAspect::DepthOnly,
|
aspect: wgpu::TextureAspect::DepthOnly,
|
||||||
base_mip_level: 0,
|
base_mip_level: 0,
|
||||||
level_count: Some(levels),
|
level_count: None,
|
||||||
base_array_layer: 0,
|
base_array_layer: 0,
|
||||||
array_layer_count: None,
|
array_layer_count: None,
|
||||||
});
|
});
|
||||||
@ -639,28 +605,20 @@ impl Renderer {
|
|||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn create_shadow_views(
|
fn create_shadow_views(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
size: (u16, u16),
|
size: (u32, u32),
|
||||||
mode: &ShadowMapMode,
|
mode: &ShadowMapMode,
|
||||||
) -> Result<
|
) -> Result<(Texture, Texture), RenderError> {
|
||||||
(
|
|
||||||
wgpu::TextureView,
|
|
||||||
wgpu::Sampler,
|
|
||||||
wgpu::TextureView,
|
|
||||||
wgpu::Sampler,
|
|
||||||
),
|
|
||||||
RenderError,
|
|
||||||
> {
|
|
||||||
// (Attempt to) apply resolution factor to shadow map resolution.
|
// (Attempt to) apply resolution factor to shadow map resolution.
|
||||||
let resolution_factor = mode.resolution.clamped(0.25, 4.0);
|
let resolution_factor = mode.resolution.clamped(0.25, 4.0);
|
||||||
|
|
||||||
let max_texture_size = Self::max_texture_size_raw(device);
|
let max_texture_size = Self::max_texture_size_raw(device);
|
||||||
// Limit to max texture size, rather than erroring.
|
// Limit to max texture size, rather than erroring.
|
||||||
let size = Vec2::new(size.0, size.1).map(|e| {
|
let size = Vec2::new(size.0, size.1).map(|e| {
|
||||||
let size = f32::from(e) * resolution_factor;
|
let size = e as f32 * resolution_factor;
|
||||||
// NOTE: We know 0 <= e since we clamped the resolution factor to be between
|
// NOTE: We know 0 <= e since we clamped the resolution factor to be between
|
||||||
// 0.25 and 4.0.
|
// 0.25 and 4.0.
|
||||||
if size <= f32::from(max_texture_size) {
|
if size <= max_texture_size as f32 {
|
||||||
size as u16
|
size as u32
|
||||||
} else {
|
} else {
|
||||||
max_texture_size
|
max_texture_size
|
||||||
}
|
}
|
||||||
@ -669,7 +627,7 @@ impl Renderer {
|
|||||||
let levels = 1;
|
let levels = 1;
|
||||||
// Limit to max texture size rather than erroring.
|
// Limit to max texture size rather than erroring.
|
||||||
let two_size = size.map(|e| {
|
let two_size = size.map(|e| {
|
||||||
u16::checked_next_power_of_two(e)
|
u32::checked_next_power_of_two(e)
|
||||||
.filter(|&e| e <= max_texture_size)
|
.filter(|&e| e <= max_texture_size)
|
||||||
.unwrap_or(max_texture_size)
|
.unwrap_or(max_texture_size)
|
||||||
});
|
});
|
||||||
@ -688,17 +646,17 @@ impl Renderer {
|
|||||||
// diag_size would be 0 too). And it must be <= diag_size,
|
// diag_size would be 0 too). And it must be <= diag_size,
|
||||||
// since min_size <= max_size. Therefore, if diag_size fits in a
|
// since min_size <= max_size. Therefore, if diag_size fits in a
|
||||||
// u16, so does diag_cross_size.
|
// u16, so does diag_cross_size.
|
||||||
(diag_size as u16, diag_cross_size as u16)
|
(diag_size as u32, diag_cross_size as u32)
|
||||||
} else {
|
} else {
|
||||||
// Limit to max texture resolution rather than error.
|
// Limit to max texture resolution rather than error.
|
||||||
(max_texture_size as u16, max_texture_size as u16)
|
(max_texture_size as u32, max_texture_size as u32)
|
||||||
};
|
};
|
||||||
let diag_two_size = u16::checked_next_power_of_two(diag_size)
|
let diag_two_size = u32::checked_next_power_of_two(diag_size)
|
||||||
.filter(|&e| e <= max_texture_size)
|
.filter(|&e| e <= max_texture_size)
|
||||||
// Limit to max texture resolution rather than error.
|
// Limit to max texture resolution rather than error.
|
||||||
.unwrap_or(max_texture_size);
|
.unwrap_or(max_texture_size);
|
||||||
|
|
||||||
let point_shadow_tex = device.create_texture(&wgpu::TextureDescriptor {
|
let point_shadow_tex = wgpu::TextureDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: diag_two_size / 4,
|
width: diag_two_size / 4,
|
||||||
@ -710,20 +668,9 @@ impl Renderer {
|
|||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: wgpu::TextureFormat::Depth24Plus,
|
format: wgpu::TextureFormat::Depth24Plus,
|
||||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
||||||
});
|
};
|
||||||
|
|
||||||
let point_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor {
|
let directed_shadow_tex = wgpu::TextureDescriptor {
|
||||||
label: None,
|
|
||||||
format: Some(wgpu::TextureFormat::Depth24Plus),
|
|
||||||
dimension: Some(wgpu::TextureViewDimension::Cube),
|
|
||||||
aspect: wgpu::TextureAspect::DepthOnly,
|
|
||||||
base_mip_level: 0,
|
|
||||||
level_count: Some(levels),
|
|
||||||
base_array_layer: 0,
|
|
||||||
array_layer_count: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let directed_shadow_tex = device.create_texture(&wgpu::TextureDescriptor {
|
|
||||||
label: None,
|
label: None,
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: diag_two_size,
|
width: diag_two_size,
|
||||||
@ -735,18 +682,18 @@ impl Renderer {
|
|||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: wgpu::TextureFormat::Depth24Plus,
|
format: wgpu::TextureFormat::Depth24Plus,
|
||||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
||||||
});
|
};
|
||||||
|
|
||||||
let directed_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor {
|
let mut view_info = wgpu::TextureViewDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
format: Some(wgpu::TextureFormat::Depth24Plus),
|
format: Some(wgpu::TextureFormat::Depth24Plus),
|
||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
aspect: wgpu::TextureAspect::DepthOnly,
|
aspect: wgpu::TextureAspect::DepthOnly,
|
||||||
base_mip_level: 0,
|
base_mip_level: 0,
|
||||||
level_count: Some(levels),
|
level_count: None,
|
||||||
base_array_layer: 0,
|
base_array_layer: 0,
|
||||||
array_layer_count: None,
|
array_layer_count: None,
|
||||||
});
|
};
|
||||||
|
|
||||||
let sampler_info = wgpu::SamplerDescriptor {
|
let sampler_info = wgpu::SamplerDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
@ -760,57 +707,52 @@ impl Renderer {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let point_shadow_tex_sampler = device.create_sampler(&sampler_info);
|
let point_tgt_shadow =
|
||||||
let directed_shadow_tex_sampler = device.create_sampler(&sampler_info);
|
Texture::new_raw(device, &point_shadow_tex, &view_info, &sampler_info);
|
||||||
|
view_info.dimension = Some(wgpu::TextureViewDimension::Cube);
|
||||||
|
let directed_shadow_tex =
|
||||||
|
Texture::new_raw(device, &directed_shadow_tex, &view_info, &sampler_info);
|
||||||
|
|
||||||
Ok((
|
Ok((point_tgt_shadow, directed_shadow_tex))
|
||||||
point_tgt_shadow_view,
|
|
||||||
point_shadow_tex_sampler,
|
|
||||||
directed_tgt_shadow_view,
|
|
||||||
directed_shadow_tex_sampler,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the resolution of the render target.
|
/// Get the resolution of the render target.
|
||||||
/// Note: the change after a resize can be delayed so
|
pub fn get_resolution(&self) -> Vec2<u32> {
|
||||||
/// don't rely on this value being constant between resize events
|
let dims = self.window.inner_size();
|
||||||
pub fn get_resolution(&self) -> Vec2<u16> {
|
|
||||||
Vec2::new(
|
Vec2::new(dims.width, dims.height)
|
||||||
self.win_color_view.get_dimensions().0,
|
|
||||||
self.win_color_view.get_dimensions().1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the resolution of the shadow render target.
|
/// Get the resolution of the shadow render target.
|
||||||
pub fn get_shadow_resolution(&self) -> (Vec2<u16>, Vec2<u16>) {
|
pub fn get_shadow_resolution(&self) -> (Vec2<u32>, Vec2<u32>) {
|
||||||
if let Some(shadow_map) = &self.shadow_map {
|
if let Some(shadow_map) = &self.shadow_map {
|
||||||
let point_dims = shadow_map.point_depth_stencil_view.get_dimensions();
|
let point_dims = shadow_map.point_depth_stencil.get_dimensions();
|
||||||
let directed_dims = shadow_map.directed_depth_stencil_view.get_dimensions();
|
let directed_dims = shadow_map.directed_depth_stencil.get_dimensions();
|
||||||
(
|
(
|
||||||
Vec2::new(point_dims.0, point_dims.1),
|
Vec2::new(point_dims.width, point_dims.height),
|
||||||
Vec2::new(directed_dims.0, directed_dims.1),
|
Vec2::new(directed_dims.width, directed_dims.height),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(Vec2::new(1, 1), Vec2::new(1, 1))
|
(Vec2::new(1, 1), Vec2::new(1, 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue the clearing of the shadow targets ready for a new frame to be
|
// /// Queue the clearing of the shadow targets ready for a new frame to be
|
||||||
/// rendered.
|
// /// rendered.
|
||||||
pub fn clear_shadows(&mut self) {
|
// pub fn clear_shadows(&mut self) {
|
||||||
span!(_guard, "clear_shadows", "Renderer::clear_shadows");
|
// span!(_guard, "clear_shadows", "Renderer::clear_shadows");
|
||||||
if !self.mode.shadow.is_map() {
|
// if !self.mode.shadow.is_map() {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
if let Some(shadow_map) = self.shadow_map.as_mut() {
|
// if let Some(shadow_map) = self.shadow_map.as_mut() {
|
||||||
// let point_encoder = &mut shadow_map.point_encoder;
|
// // let point_encoder = &mut shadow_map.point_encoder;
|
||||||
let point_encoder = &mut self.encoder;
|
// let point_encoder = &mut self.encoder;
|
||||||
point_encoder.clear_depth(&shadow_map.point_depth_stencil_view, 1.0);
|
// point_encoder.clear_depth(&shadow_map.point_depth_stencil_view, 1.0);
|
||||||
// let directed_encoder = &mut shadow_map.directed_encoder;
|
// // let directed_encoder = &mut shadow_map.directed_encoder;
|
||||||
let directed_encoder = &mut self.encoder;
|
// let directed_encoder = &mut self.encoder;
|
||||||
directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view, 1.0);
|
// directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view,
|
||||||
}
|
// 1.0); }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// NOTE: Supported by Vulkan (by default), DirectX 10+ (it seems--it's hard
|
/// NOTE: Supported by Vulkan (by default), DirectX 10+ (it seems--it's hard
|
||||||
/// to find proof of this, but Direct3D 10 apparently does it by
|
/// to find proof of this, but Direct3D 10 apparently does it by
|
||||||
@ -839,15 +781,6 @@ impl Renderer {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue the clearing of the depth target ready for a new frame to be
|
|
||||||
/// rendered.
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
span!(_guard, "clear", "Renderer::clear");
|
|
||||||
self.encoder.clear_depth(&self.tgt_depth_stencil_view, 1.0);
|
|
||||||
// self.encoder.clear_stencil(&self.tgt_depth_stencil_view, 0);
|
|
||||||
self.encoder.clear_depth(&self.win_depth_view, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// /// Set up shadow rendering.
|
// /// Set up shadow rendering.
|
||||||
// pub fn start_shadows(&mut self) {
|
// pub fn start_shadows(&mut self) {
|
||||||
// if !self.mode.shadow.is_map() {
|
// if !self.mode.shadow.is_map() {
|
||||||
@ -879,8 +812,7 @@ impl Renderer {
|
|||||||
/// items.
|
/// items.
|
||||||
pub fn flush(&mut self) {
|
pub fn flush(&mut self) {
|
||||||
span!(_guard, "flush", "Renderer::flush");
|
span!(_guard, "flush", "Renderer::flush");
|
||||||
self.encoder.flush(&mut self.device);
|
self.device.poll(wgpu::Maintain::Poll);
|
||||||
self.device.cleanup();
|
|
||||||
|
|
||||||
// If the shaders files were changed attempt to recreate the shaders
|
// If the shaders files were changed attempt to recreate the shaders
|
||||||
if self.shaders.reloaded() {
|
if self.shaders.reloaded() {
|
||||||
@ -891,9 +823,11 @@ impl Renderer {
|
|||||||
/// Recreate the pipelines
|
/// Recreate the pipelines
|
||||||
fn recreate_pipelines(&mut self) {
|
fn recreate_pipelines(&mut self) {
|
||||||
match create_pipelines(
|
match create_pipelines(
|
||||||
&mut self.factory,
|
&self.device,
|
||||||
|
&self.layouts,
|
||||||
&self.shaders.read(),
|
&self.shaders.read(),
|
||||||
&self.mode,
|
&self.mode,
|
||||||
|
&self.sc_desc,
|
||||||
self.shadow_map.is_some(),
|
self.shadow_map.is_some(),
|
||||||
) {
|
) {
|
||||||
Ok((
|
Ok((
|
||||||
@ -907,7 +841,7 @@ impl Renderer {
|
|||||||
lod_terrain_pipeline,
|
lod_terrain_pipeline,
|
||||||
clouds_pipeline,
|
clouds_pipeline,
|
||||||
postprocess_pipeline,
|
postprocess_pipeline,
|
||||||
player_shadow_pipeline,
|
//player_shadow_pipeline,
|
||||||
point_shadow_pipeline,
|
point_shadow_pipeline,
|
||||||
terrain_directed_shadow_pipeline,
|
terrain_directed_shadow_pipeline,
|
||||||
figure_directed_shadow_pipeline,
|
figure_directed_shadow_pipeline,
|
||||||
@ -922,7 +856,7 @@ impl Renderer {
|
|||||||
self.lod_terrain_pipeline = lod_terrain_pipeline;
|
self.lod_terrain_pipeline = lod_terrain_pipeline;
|
||||||
self.clouds_pipeline = clouds_pipeline;
|
self.clouds_pipeline = clouds_pipeline;
|
||||||
self.postprocess_pipeline = postprocess_pipeline;
|
self.postprocess_pipeline = postprocess_pipeline;
|
||||||
self.player_shadow_pipeline = player_shadow_pipeline;
|
//self.player_shadow_pipeline = player_shadow_pipeline;
|
||||||
if let (
|
if let (
|
||||||
Some(point_pipeline),
|
Some(point_pipeline),
|
||||||
Some(terrain_directed_pipeline),
|
Some(terrain_directed_pipeline),
|
||||||
@ -948,14 +882,14 @@ impl Renderer {
|
|||||||
&mut self,
|
&mut self,
|
||||||
vals: &[T],
|
vals: &[T],
|
||||||
) -> Result<Consts<T>, RenderError> {
|
) -> Result<Consts<T>, RenderError> {
|
||||||
let mut consts = Consts::new(&mut self.factory, vals.len());
|
let mut consts = Consts::new(&self.device, vals.len() as u64);
|
||||||
consts.update(&mut self.encoder, vals, 0)?;
|
consts.update(&self.device, &self.queue, vals, 0);
|
||||||
Ok(consts)
|
Ok(consts)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a set of constants with the provided values.
|
/// Update a set of constants with the provided values.
|
||||||
pub fn update_consts<T: Copy + bytemuck::Pod>(&mut self, consts: &mut Consts<T>, vals: &[T]) {
|
pub fn update_consts<T: Copy + bytemuck::Pod>(&mut self, consts: &mut Consts<T>, vals: &[T]) {
|
||||||
consts.update(&mut self.encoder, vals, 0)
|
consts.update(&self.device, &self.queue, vals, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new set of instances with the provided values.
|
/// Create a new set of instances with the provided values.
|
||||||
@ -963,39 +897,31 @@ impl Renderer {
|
|||||||
&mut self,
|
&mut self,
|
||||||
vals: &[T],
|
vals: &[T],
|
||||||
) -> Result<Instances<T>, RenderError> {
|
) -> Result<Instances<T>, RenderError> {
|
||||||
let mut instances = Instances::new(&mut self.factory, vals.len())?;
|
let mut instances = Instances::new(&self.device, vals.len() as u64);
|
||||||
instances.update(&mut self.encoder, vals)?;
|
instances.update(&self.device, &self.queue, vals, 0);
|
||||||
Ok(instances)
|
Ok(instances)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new model from the provided mesh.
|
/// Create a new model from the provided mesh.
|
||||||
pub fn create_model<V: Vertex>(&mut self, mesh: &Mesh<V>) -> Result<Model<V>, RenderError> {
|
pub fn create_model<V: Vertex>(&mut self, mesh: &Mesh<V>) -> Result<Model<V>, RenderError> {
|
||||||
Ok(Model::new(&mut self.factory, mesh))
|
Ok(Model::new(&self.device, mesh))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new dynamic model with the specified size.
|
/// Create a new dynamic model with the specified size.
|
||||||
pub fn create_dynamic_model<V: Vertex>(
|
pub fn create_dynamic_model<V: Vertex>(&mut self, size: u64) -> Model<V> {
|
||||||
&mut self,
|
Model::new_dynamic(&self.device, size)
|
||||||
size: usize,
|
|
||||||
) -> Result<Model<V>, RenderError> {
|
|
||||||
Model::new(&self.device, size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a dynamic model with a mesh and a offset.
|
/// Update a dynamic model with a mesh and a offset.
|
||||||
pub fn update_model<V: Vertex>(
|
pub fn update_model<V: Vertex>(&mut self, model: &Model<V>, mesh: &Mesh<V>, offset: u64) {
|
||||||
&mut self,
|
model.update(&self.device, &self.queue, mesh, offset)
|
||||||
model: &Model<V>,
|
|
||||||
mesh: &Mesh<V>,
|
|
||||||
offset: usize,
|
|
||||||
) -> Result<(), RenderError> {
|
|
||||||
model.update(&mut self.encoder, mesh, offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the maximum supported texture size.
|
/// Return the maximum supported texture size.
|
||||||
pub fn max_texture_size(&self) -> u16 { Self::max_texture_size_raw(&self.factory) }
|
pub fn max_texture_size(&self) -> u32 { Self::max_texture_size_raw(&self.device) }
|
||||||
|
|
||||||
/// Return the maximum supported texture size from the factory.
|
/// Return the maximum supported texture size from the factory.
|
||||||
fn max_texture_size_raw(device: &wgpu::Device) -> u16 {
|
fn max_texture_size_raw(_device: &wgpu::Device) -> u32 {
|
||||||
// This value is temporary as there are plans to include a way to get this in
|
// This value is temporary as there are plans to include a way to get this in
|
||||||
// wgpu this is just a sane standard for now
|
// wgpu this is just a sane standard for now
|
||||||
8192
|
8192
|
||||||
@ -1004,18 +930,19 @@ impl Renderer {
|
|||||||
/// Create a new immutable texture from the provided image.
|
/// Create a new immutable texture from the provided image.
|
||||||
pub fn create_texture_with_data_raw(
|
pub fn create_texture_with_data_raw(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_info: wgpu::TextureDescriptor,
|
texture_info: &wgpu::TextureDescriptor,
|
||||||
sampler_info: wgpu::SamplerDescriptor,
|
view_info: &wgpu::TextureViewDescriptor,
|
||||||
|
sampler_info: &wgpu::SamplerDescriptor,
|
||||||
bytes_per_row: u32,
|
bytes_per_row: u32,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Texture {
|
) -> Texture {
|
||||||
let tex = Texture::new_raw(&self.device, texture_info, sampler_info);
|
let tex = Texture::new_raw(&self.device, &texture_info, &view_info, &sampler_info);
|
||||||
|
|
||||||
tex.update(
|
tex.update(
|
||||||
&self.device,
|
&self.device,
|
||||||
&self.queue,
|
&self.queue,
|
||||||
[0; 2],
|
[0; 2],
|
||||||
[texture_info.size.x, texture_info.size.y],
|
[texture_info.size.width, texture_info.size.height],
|
||||||
data,
|
data,
|
||||||
bytes_per_row,
|
bytes_per_row,
|
||||||
);
|
);
|
||||||
@ -1026,10 +953,11 @@ impl Renderer {
|
|||||||
/// Create a new raw texture.
|
/// Create a new raw texture.
|
||||||
pub fn create_texture_raw(
|
pub fn create_texture_raw(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_info: wgpu::TextureDescriptor,
|
texture_info: &wgpu::TextureDescriptor,
|
||||||
sampler_info: wgpu::SamplerDescriptor,
|
view_info: &wgpu::TextureViewDescriptor,
|
||||||
|
sampler_info: &wgpu::SamplerDescriptor,
|
||||||
) -> Texture {
|
) -> Texture {
|
||||||
Texture::new_raw(&self.device, texture_info, sampler_info)
|
Texture::new_raw(&self.device, texture_info, view_info, sampler_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new texture from the provided image.
|
/// Create a new texture from the provided image.
|
||||||
@ -1040,7 +968,7 @@ impl Renderer {
|
|||||||
image: &image::DynamicImage,
|
image: &image::DynamicImage,
|
||||||
filter_method: Option<FilterMode>,
|
filter_method: Option<FilterMode>,
|
||||||
address_mode: Option<AddressMode>,
|
address_mode: Option<AddressMode>,
|
||||||
) -> Texture {
|
) -> Result<Texture, RenderError> {
|
||||||
Texture::new(
|
Texture::new(
|
||||||
&self.device,
|
&self.device,
|
||||||
&self.queue,
|
&self.queue,
|
||||||
@ -1054,8 +982,8 @@ impl Renderer {
|
|||||||
/// specified dimensions.
|
/// specified dimensions.
|
||||||
///
|
///
|
||||||
/// Currently only supports Rgba8Srgb
|
/// Currently only supports Rgba8Srgb
|
||||||
pub fn create_dynamic_texture(&mut self, dims: Vec2<u16>) -> Texture {
|
pub fn create_dynamic_texture(&mut self, dims: Vec2<u32>) -> Texture {
|
||||||
Texture::new_dynamic(&mut self.factory, dims.x, dims.y)
|
Texture::new_dynamic(&self.device, dims.x, dims.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a texture with the provided offset, size, and data.
|
/// Update a texture with the provided offset, size, and data.
|
||||||
@ -1064,8 +992,8 @@ impl Renderer {
|
|||||||
pub fn update_texture(
|
pub fn update_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture: &Texture, /* <T> */
|
texture: &Texture, /* <T> */
|
||||||
offset: [u16; 2],
|
offset: [u32; 2],
|
||||||
size: [u16; 2],
|
size: [u32; 2],
|
||||||
// TODO
|
// TODO
|
||||||
// data: &[<<T as gfx::format::Formatted>::Surface as
|
// data: &[<<T as gfx::format::Formatted>::Surface as
|
||||||
// gfx::format::SurfaceTyped>::DataType], ) -> Result<(), RenderError>
|
// gfx::format::SurfaceTyped>::DataType], ) -> Result<(), RenderError>
|
||||||
@ -1078,7 +1006,14 @@ impl Renderer {
|
|||||||
data: &[[u8; 4]],
|
data: &[[u8; 4]],
|
||||||
bytes_per_row: u32,
|
bytes_per_row: u32,
|
||||||
) {
|
) {
|
||||||
texture.update(&mut self.encoder, offset, size, data, bytes_per_row)
|
texture.update(
|
||||||
|
&self.device,
|
||||||
|
&self.queue,
|
||||||
|
offset,
|
||||||
|
size,
|
||||||
|
bytemuck::cast_slice(data),
|
||||||
|
bytes_per_row,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a download buffer, downloads the win_color_view, and converts to
|
/// Creates a download buffer, downloads the win_color_view, and converts to
|
||||||
@ -1945,18 +1880,18 @@ fn create_pipelines(
|
|||||||
options.set_optimization_level(OptimizationLevel::Performance);
|
options.set_optimization_level(OptimizationLevel::Performance);
|
||||||
options.set_include_callback(move |name, _, shader_name, _| {
|
options.set_include_callback(move |name, _, shader_name, _| {
|
||||||
Ok(ResolvedInclude {
|
Ok(ResolvedInclude {
|
||||||
resolved_name: name,
|
resolved_name: name.to_string(),
|
||||||
content: match name {
|
content: match name {
|
||||||
"constants.glsl" => constants,
|
"constants.glsl" => constants,
|
||||||
"globals.glsl" => globals,
|
"globals.glsl" => *globals,
|
||||||
"shadows.glsl" => shadows,
|
"shadows.glsl" => *shadows,
|
||||||
"sky.glsl" => sky,
|
"sky.glsl" => *sky,
|
||||||
"light.glsl" => light,
|
"light.glsl" => *light,
|
||||||
"srgb.glsl" => srgb,
|
"srgb.glsl" => *srgb,
|
||||||
"random.glsl" => &random,
|
"random.glsl" => *random,
|
||||||
"lod.glsl" => &lod,
|
"lod.glsl" => *lod,
|
||||||
"anti-aliasing.glsl" => &anti_alias,
|
"anti-aliasing.glsl" => *anti_alias,
|
||||||
"cloud.glsl" => &cloud,
|
"cloud.glsl" => *cloud,
|
||||||
other => return Err(format!("Include {} is not defined", other)),
|
other => return Err(format!("Include {} is not defined", other)),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -1975,7 +1910,7 @@ fn create_pipelines(
|
|||||||
let figure_vert_mod = create_shader_module(
|
let figure_vert_mod = create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
figure_vert,
|
&figure_vert,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"figure-vert.glsl",
|
"figure-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
@ -1984,7 +1919,7 @@ fn create_pipelines(
|
|||||||
let terrain_point_shadow_vert_mod = create_shader_module(
|
let terrain_point_shadow_vert_mod = create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
terrain_point_shadow_vert,
|
&terrain_point_shadow_vert,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"light-shadows-vert.glsl",
|
"light-shadows-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
@ -1993,7 +1928,7 @@ fn create_pipelines(
|
|||||||
let terrain_directed_shadow_vert_mod = create_shader_module(
|
let terrain_directed_shadow_vert_mod = create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
terrain_directed_shadow_vert,
|
&terrain_directed_shadow_vert,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"light-shadows-directed-vert.glsl",
|
"light-shadows-directed-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
@ -2002,7 +1937,7 @@ fn create_pipelines(
|
|||||||
let figure_directed_shadow_vert_mod = create_shader_module(
|
let figure_directed_shadow_vert_mod = create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
figure_directed_shadow_vert,
|
&figure_directed_shadow_vert,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"light-shadows-figure-vert.glsl",
|
"light-shadows-figure-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
@ -2022,24 +1957,24 @@ fn create_pipelines(
|
|||||||
// Construct a pipeline for rendering skyboxes
|
// Construct a pipeline for rendering skyboxes
|
||||||
let skybox_pipeline = skybox::SkyboxPipeline::new(
|
let skybox_pipeline = skybox::SkyboxPipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.skybox_vert.read().0,
|
shaders.skybox_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"skybox-vert.glsl",
|
"skybox-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.skybox_frag.read().0,
|
shaders.skybox_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"skybox-frag.glsl",
|
"skybox-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2047,55 +1982,57 @@ fn create_pipelines(
|
|||||||
let figure_pipeline = figure::FigurePipeline::new(
|
let figure_pipeline = figure::FigurePipeline::new(
|
||||||
device,
|
device,
|
||||||
&figure_vert_mod,
|
&figure_vert_mod,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.figure_frag.read().0,
|
shaders.figure_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"figure-frag.glsl",
|
"figure-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
|
&layouts.figure,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Construct a pipeline for rendering terrain
|
// Construct a pipeline for rendering terrain
|
||||||
let terrain_pipeline = terrain::TerrainPipeline::new(
|
let terrain_pipeline = terrain::TerrainPipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.terrain_vert.read().0,
|
shaders.terrain_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"terrain-vert.glsl",
|
"terrain-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.terrain_frag.read().0,
|
shaders.terrain_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"terrain-frag.glsl",
|
"terrain-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
|
&layouts.terrain,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Construct a pipeline for rendering fluids
|
// Construct a pipeline for rendering fluids
|
||||||
let fluid_pipeline = fluid::FluidPipeline::new(
|
let fluid_pipeline = fluid::FluidPipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.fluid_vert.read().0,
|
shaders.fluid_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"terrain-vert.glsl",
|
"terrain-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
match mode.fluid {
|
match mode.fluid {
|
||||||
@ -2105,105 +2042,109 @@ fn create_pipelines(
|
|||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"fluid-frag.glsl",
|
"fluid-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
|
&layouts.fluid,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Construct a pipeline for rendering sprites
|
// Construct a pipeline for rendering sprites
|
||||||
let sprite_pipeline = sprite::SpritePipeline::new(
|
let sprite_pipeline = sprite::SpritePipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.sprite_vert.read().0,
|
shaders.sprite_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"sprite-vert.glsl",
|
"sprite-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.sprite_frag.read().0,
|
shaders.sprite_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"sprite-frag.glsl",
|
"sprite-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
|
&layouts.sprite,
|
||||||
|
&layouts.terrain,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Construct a pipeline for rendering particles
|
// Construct a pipeline for rendering particles
|
||||||
let particle_pipeline = particle::ParticlePipeline::new(
|
let particle_pipeline = particle::ParticlePipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.particle_vert.read().0,
|
shaders.particle_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"particle-vert.glsl",
|
"particle-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.particle_frag.read().0,
|
shaders.particle_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"particle-frag.glsl",
|
"particle-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Construct a pipeline for rendering UI elements
|
// Construct a pipeline for rendering UI elements
|
||||||
let ui_pipeline = ui::UIPipeline::new(
|
let ui_pipeline = ui::UIPipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.ui_vert.read().0,
|
shaders.ui_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"ui-vert.glsl",
|
"ui-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.ui_frag.read().0,
|
shaders.ui_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"ui-frag.glsl",
|
"ui-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
|
&layouts.ui,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Construct a pipeline for rendering terrain
|
// Construct a pipeline for rendering terrain
|
||||||
let lod_terrain_pipeline = lod_terrain::LodTerrainPipeline::new(
|
let lod_terrain_pipeline = lod_terrain::LodTerrainPipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.lod_terrain_vert.read().0,
|
shaders.lod_terrain_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"lod-terrain-vert.glsl",
|
"lod-terrain-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.lod_terrain_frag.read().0,
|
shaders.lod_terrain_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"lod-terrain-frag.glsl",
|
"lod-terrain-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2221,24 +2162,25 @@ fn create_pipelines(
|
|||||||
// Construct a pipeline for rendering our post-processing
|
// Construct a pipeline for rendering our post-processing
|
||||||
let postprocess_pipeline = postprocess::PostProcessPipeline::new(
|
let postprocess_pipeline = postprocess::PostProcessPipeline::new(
|
||||||
device,
|
device,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.postprocess_vert.read().0,
|
shaders.postprocess_vert.read().0,
|
||||||
ShaderKind::Vertex,
|
ShaderKind::Vertex,
|
||||||
"postprocess-vert.glsl",
|
"postprocess-vert.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
create_shader_module(
|
&create_shader_module(
|
||||||
device,
|
device,
|
||||||
&mut compiler,
|
&mut compiler,
|
||||||
shaders.postprocess_frag.read().0,
|
shaders.postprocess_frag.read().0,
|
||||||
ShaderKind::Fragment,
|
ShaderKind::Fragment,
|
||||||
"postprocess-frag.glsl",
|
"postprocess-frag.glsl",
|
||||||
&options,
|
&options,
|
||||||
),
|
)?,
|
||||||
sc_desc,
|
sc_desc,
|
||||||
layouts,
|
&layouts.global,
|
||||||
|
&layouts.postprocess,
|
||||||
mode.aa,
|
mode.aa,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2368,5 +2310,9 @@ pub fn create_shader_module(
|
|||||||
|
|
||||||
let spv = compiler.compile_into_spirv(source, kind, file_name, "main", Some(options))?;
|
let spv = compiler.compile_into_spirv(source, kind, file_name, "main", Some(options))?;
|
||||||
|
|
||||||
Ok(device.create_shader_module(wgpu::ShaderModule::SpirV(Cow::Bowrrowed(spv.as_binary()))))
|
Ok(
|
||||||
|
device.create_shader_module(wgpu::ShaderModuleSource::SpirV(Cow::Borrowed(
|
||||||
|
spv.as_binary(),
|
||||||
|
))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ use wgpu::Extent3d;
|
|||||||
|
|
||||||
/// Represents an image that has been uploaded to the GPU.
|
/// Represents an image that has been uploaded to the GPU.
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
pub tex: wgpu::TextureView,
|
pub tex: wgpu::Texture,
|
||||||
|
pub view: wgpu::TextureView,
|
||||||
pub sampler: wgpu::Sampler,
|
pub sampler: wgpu::Sampler,
|
||||||
size: Extent3d,
|
size: Extent3d,
|
||||||
}
|
}
|
||||||
@ -49,7 +50,7 @@ impl Texture {
|
|||||||
mip_level: 0,
|
mip_level: 0,
|
||||||
origin: wgpu::Origin3d::ZERO,
|
origin: wgpu::Origin3d::ZERO,
|
||||||
},
|
},
|
||||||
&[buffer.as_slice()],
|
buffer.as_slice(),
|
||||||
wgpu::TextureDataLayout {
|
wgpu::TextureDataLayout {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
bytes_per_row: image.width() * 4,
|
bytes_per_row: image.width() * 4,
|
||||||
@ -73,21 +74,33 @@ impl Texture {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let view = tex.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tex,
|
tex,
|
||||||
|
view,
|
||||||
sampler: device.create_sampler(&sampler_info),
|
sampler: device.create_sampler(&sampler_info),
|
||||||
size,
|
size,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_dynamic(device: &wgpu::Device, width: u16, height: u16) -> Self {
|
pub fn new_dynamic(device: &wgpu::Device, width: u32, height: u32) -> Self {
|
||||||
let size = wgpu::Extent3d {
|
let size = wgpu::Extent3d {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let tex_info = device.create_texture(&wgpu::TextureDescriptor {
|
let tex_info = wgpu::TextureDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size,
|
size,
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
@ -95,7 +108,7 @@ impl Texture {
|
|||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
||||||
});
|
};
|
||||||
|
|
||||||
let sampler_info = wgpu::SamplerDescriptor {
|
let sampler_info = wgpu::SamplerDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
@ -108,19 +121,35 @@ impl Texture {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::new_raw(device, tex_info, sampler_info)
|
let view_info = wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::new_raw(device, &tex_info, &view_info, &sampler_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_raw(
|
pub fn new_raw(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
texture_info: wgpu::TextureDescriptor,
|
texture_info: &wgpu::TextureDescriptor,
|
||||||
sampler_info: wgpu::SamplerDescriptor,
|
view_info: &wgpu::TextureViewDescriptor,
|
||||||
|
sampler_info: &wgpu::SamplerDescriptor,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Ok(Self {
|
let tex = device.create_texture(texture_info);
|
||||||
tex: device.create_texture(&texture_info),
|
let view = tex.create_view(view_info);
|
||||||
sampler: device.create_sampler(&sampler_info),
|
|
||||||
|
Self {
|
||||||
|
tex,
|
||||||
|
view,
|
||||||
|
sampler: device.create_sampler(sampler_info),
|
||||||
size: texture_info.size,
|
size: texture_info.size,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a texture with the given data (used for updating the glyph cache
|
/// Update a texture with the given data (used for updating the glyph cache
|
||||||
@ -129,11 +158,11 @@ impl Texture {
|
|||||||
&self,
|
&self,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
offset: [u16; 2],
|
offset: [u32; 2],
|
||||||
size: [u16; 2],
|
size: [u32; 2],
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
bytes_per_row: u32,
|
bytes_per_row: u32,
|
||||||
) -> Result<(), RenderError> {
|
) {
|
||||||
// TODO: Only works for 2D images
|
// TODO: Only works for 2D images
|
||||||
queue.write_texture(
|
queue.write_texture(
|
||||||
wgpu::TextureCopyViewBase {
|
wgpu::TextureCopyViewBase {
|
||||||
@ -146,12 +175,10 @@ impl Texture {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
// TODO: I heard some rumors that there are other
|
|
||||||
// formats that are not Rgba8
|
|
||||||
wgpu::TextureDataLayout {
|
wgpu::TextureDataLayout {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
bytes_per_row,
|
bytes_per_row,
|
||||||
rows_per_image: self.size.y,
|
rows_per_image: self.size.height,
|
||||||
},
|
},
|
||||||
wgpu::Extent3d {
|
wgpu::Extent3d {
|
||||||
width: size[0],
|
width: size[0],
|
||||||
|
@ -168,19 +168,19 @@ fn handle_main_events_cleared(
|
|||||||
if let Some(last) = states.last_mut() {
|
if let Some(last) = states.last_mut() {
|
||||||
span!(guard, "Render");
|
span!(guard, "Render");
|
||||||
let renderer = global_state.window.renderer_mut();
|
let renderer = global_state.window.renderer_mut();
|
||||||
// Clear the shadow maps.
|
// // Clear the shadow maps.
|
||||||
renderer.clear_shadows();
|
// renderer.clear_shadows();
|
||||||
// Clear the screen
|
// // Clear the screen
|
||||||
renderer.clear();
|
// renderer.clear();
|
||||||
// Render the screen using the global renderer
|
// Render the screen using the global renderer
|
||||||
last.render(renderer, &global_state.settings);
|
last.render(renderer, &global_state.settings);
|
||||||
// Finish the frame.
|
// Finish the frame.
|
||||||
global_state.window.renderer_mut().flush();
|
// global_state.window.renderer_mut().flush();
|
||||||
// Display the frame on the window.
|
// // Display the frame on the window.
|
||||||
global_state
|
// global_state
|
||||||
.window
|
// .window
|
||||||
.swap_buffers()
|
// .swap_buffers()
|
||||||
.expect("Failed to swap window buffers!");
|
// .expect("Failed to swap window buffers!");
|
||||||
drop(guard);
|
drop(guard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::{load::BodySpec, FigureModelEntry};
|
use super::{load::BodySpec, FigureModelEntry};
|
||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, Meshable},
|
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain},
|
||||||
render::{BoneMeshes, ColLightInfo, FigureModel, Mesh, Renderer, TerrainVertex},
|
render::{BoneMeshes, ColLightInfo, FigureModel, Mesh, Renderer, TerrainVertex},
|
||||||
scene::camera::CameraMode,
|
scene::camera::CameraMode,
|
||||||
};
|
};
|
||||||
@ -476,11 +476,10 @@ where
|
|||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
bone_idx: u8,
|
bone_idx: u8,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let (opaque, _, _, bounds) =
|
let (opaque, _, _, bounds) = generate_mesh_base_vol_terrain(
|
||||||
Meshable::<TerrainVertex, &mut GreedyMesh>::generate_mesh(
|
segment,
|
||||||
segment,
|
(greedy, opaque_mesh, offset, Vec3::one(), bone_idx),
|
||||||
(greedy, opaque_mesh, offset, Vec3::one(), bone_idx),
|
);
|
||||||
);
|
|
||||||
(opaque, bounds)
|
(opaque, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,17 +491,16 @@ where
|
|||||||
bone_idx: u8,
|
bone_idx: u8,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let lod_scale = 0.6;
|
let lod_scale = 0.6;
|
||||||
let (opaque, _, _, bounds) =
|
let (opaque, _, _, bounds) = generate_mesh_base_vol_terrain(
|
||||||
Meshable::<TerrainVertex, &mut GreedyMesh>::generate_mesh(
|
segment.scaled_by(Vec3::broadcast(lod_scale)),
|
||||||
segment.scaled_by(Vec3::broadcast(lod_scale)),
|
(
|
||||||
(
|
greedy,
|
||||||
greedy,
|
opaque_mesh,
|
||||||
opaque_mesh,
|
offset * lod_scale,
|
||||||
offset * lod_scale,
|
Vec3::one() / lod_scale,
|
||||||
Vec3::one() / lod_scale,
|
bone_idx,
|
||||||
bone_idx,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
(opaque, bounds)
|
(opaque, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,17 +512,16 @@ where
|
|||||||
bone_idx: u8,
|
bone_idx: u8,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let lod_scale = 0.3;
|
let lod_scale = 0.3;
|
||||||
let (opaque, _, _, bounds) =
|
let (opaque, _, _, bounds) = generate_mesh_base_vol_terrain(
|
||||||
Meshable::<TerrainVertex, &mut GreedyMesh>::generate_mesh(
|
segment.scaled_by(Vec3::broadcast(lod_scale)),
|
||||||
segment.scaled_by(Vec3::broadcast(lod_scale)),
|
(
|
||||||
(
|
greedy,
|
||||||
greedy,
|
opaque_mesh,
|
||||||
opaque_mesh,
|
offset * lod_scale,
|
||||||
offset * lod_scale,
|
Vec3::one() / lod_scale,
|
||||||
Vec3::one() / lod_scale,
|
bone_idx,
|
||||||
bone_idx,
|
),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
(opaque, bounds)
|
(opaque, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5230,12 +5230,9 @@ impl FigureColLights {
|
|||||||
span!(_guard, "create_figure", "FigureColLights::create_figure");
|
span!(_guard, "create_figure", "FigureColLights::create_figure");
|
||||||
let atlas = &mut self.atlas;
|
let atlas = &mut self.atlas;
|
||||||
let allocation = atlas
|
let allocation = atlas
|
||||||
.allocate(guillotiere::Size::new(
|
.allocate(guillotiere::Size::new(tex_size.x as i32, tex_size.y as i32))
|
||||||
i32::from(tex_size.x),
|
|
||||||
i32::from(tex_size.y),
|
|
||||||
))
|
|
||||||
.expect("Not yet implemented: allocate new atlas on allocation failure.");
|
.expect("Not yet implemented: allocate new atlas on allocation failure.");
|
||||||
let col_lights = pipelines::shadow::create_col_lights(renderer, &(tex, tex_size))?;
|
let col_lights = pipelines::shadow::create_col_lights(renderer, &(tex, tex_size));
|
||||||
let model_len = u32::try_from(opaque.vertices().len())
|
let model_len = u32::try_from(opaque.vertices().len())
|
||||||
.expect("The model size for this figure does not fit in a u32!");
|
.expect("The model size for this figure does not fit in a u32!");
|
||||||
let model = renderer.create_model(&opaque)?;
|
let model = renderer.create_model(&opaque)?;
|
||||||
@ -5262,8 +5259,7 @@ impl FigureColLights {
|
|||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn make_atlas(renderer: &mut Renderer) -> Result<AtlasAllocator, RenderError> {
|
fn make_atlas(renderer: &mut Renderer) -> Result<AtlasAllocator, RenderError> {
|
||||||
let max_texture_size = renderer.max_texture_size();
|
let max_texture_size = renderer.max_texture_size();
|
||||||
let atlas_size =
|
let atlas_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
|
||||||
guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size));
|
|
||||||
let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions {
|
let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions {
|
||||||
// TODO: Verify some good empirical constants.
|
// TODO: Verify some good empirical constants.
|
||||||
small_size_threshold: 32,
|
small_size_threshold: 32,
|
||||||
@ -5286,7 +5282,7 @@ impl FigureColLights {
|
|||||||
(0, 0),
|
(0, 0),
|
||||||
gfx::format::Swizzle::new(),
|
gfx::format::Swizzle::new(),
|
||||||
gfx::texture::SamplerInfo::new(
|
gfx::texture::SamplerInfo::new(
|
||||||
gfx::texture::FilterMethod::Bilinear,
|
gfx::texture::FilterMetho>:Bilinear,
|
||||||
gfx::texture::WrapMode::Clamp,
|
gfx::texture::WrapMode::Clamp,
|
||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
@ -5467,18 +5463,16 @@ impl<S: Skeleton> FigureState<S> {
|
|||||||
self.last_light,
|
self.last_light,
|
||||||
self.last_glow,
|
self.last_glow,
|
||||||
);
|
);
|
||||||
renderer.update_consts(&mut self.locals, &[locals]).unwrap();
|
renderer.update_consts(&mut self.locals, &[locals]);
|
||||||
|
|
||||||
let lantern_offset = anim::compute_matrices(&self.skeleton, mat, buf);
|
let lantern_offset = anim::compute_matrices(&self.skeleton, mat, buf);
|
||||||
|
|
||||||
let new_bone_consts = figure_bone_data_from_anim(buf);
|
let new_bone_consts = figure_bone_data_from_anim(buf);
|
||||||
|
|
||||||
renderer
|
renderer.update_consts(
|
||||||
.update_consts(
|
&mut self.meta.bone_consts,
|
||||||
&mut self.meta.bone_consts,
|
&new_bone_consts[0..S::BONE_COUNT],
|
||||||
&new_bone_consts[0..S::BONE_COUNT],
|
);
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
self.lantern_offset = lantern_offset;
|
self.lantern_offset = lantern_offset;
|
||||||
|
|
||||||
let smoothing = (5.0 * dt).min(1.0);
|
let smoothing = (5.0 * dt).min(1.0);
|
||||||
|
@ -26,7 +26,7 @@ impl Lod {
|
|||||||
model: None,
|
model: None,
|
||||||
data: LodData::new(
|
data: LodData::new(
|
||||||
renderer,
|
renderer,
|
||||||
client.world_data().chunk_size(),
|
client.world_data().chunk_size().as_(),
|
||||||
client.world_data().lod_base.raw(),
|
client.world_data().lod_base.raw(),
|
||||||
client.world_data().lod_alt.raw(),
|
client.world_data().lod_alt.raw(),
|
||||||
client.world_data().lod_horizon.raw(),
|
client.world_data().lod_horizon.raw(),
|
||||||
|
@ -584,9 +584,7 @@ impl Scene {
|
|||||||
);
|
);
|
||||||
lights.sort_by_key(|light| light.get_pos().distance_squared(player_pos) as i32);
|
lights.sort_by_key(|light| light.get_pos().distance_squared(player_pos) as i32);
|
||||||
lights.truncate(MAX_LIGHT_COUNT);
|
lights.truncate(MAX_LIGHT_COUNT);
|
||||||
renderer
|
renderer.update_consts(&mut self.data.lights, &lights);
|
||||||
.update_consts(&mut self.data.lights, &lights)
|
|
||||||
.expect("Failed to update light constants");
|
|
||||||
|
|
||||||
// Update event lights
|
// Update event lights
|
||||||
let dt = ecs.fetch::<DeltaTime>().0;
|
let dt = ecs.fetch::<DeltaTime>().0;
|
||||||
@ -623,9 +621,7 @@ impl Scene {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
shadows.sort_by_key(|shadow| shadow.get_pos().distance_squared(player_pos) as i32);
|
shadows.sort_by_key(|shadow| shadow.get_pos().distance_squared(player_pos) as i32);
|
||||||
shadows.truncate(MAX_SHADOW_COUNT);
|
shadows.truncate(MAX_SHADOW_COUNT);
|
||||||
renderer
|
renderer.update_consts(&mut self.data.shadows, &shadows);
|
||||||
.update_consts(&mut self.data.shadows, &shadows)
|
|
||||||
.expect("Failed to update light constants");
|
|
||||||
|
|
||||||
// Remember to put the new loaded distance back in the scene.
|
// Remember to put the new loaded distance back in the scene.
|
||||||
self.loaded_distance = loaded_distance;
|
self.loaded_distance = loaded_distance;
|
||||||
@ -636,48 +632,42 @@ impl Scene {
|
|||||||
let focus_off = focus_pos.map(|e| e.trunc());
|
let focus_off = focus_pos.map(|e| e.trunc());
|
||||||
|
|
||||||
// Update global constants.
|
// Update global constants.
|
||||||
renderer
|
renderer.update_consts(&mut self.data.globals, &[Globals::new(
|
||||||
.update_consts(&mut self.data.globals, &[Globals::new(
|
view_mat,
|
||||||
view_mat,
|
proj_mat,
|
||||||
proj_mat,
|
cam_pos,
|
||||||
cam_pos,
|
focus_pos,
|
||||||
focus_pos,
|
self.loaded_distance,
|
||||||
self.loaded_distance,
|
self.lod.get_data().tgt_detail as f32,
|
||||||
self.lod.get_data().tgt_detail as f32,
|
self.map_bounds,
|
||||||
self.map_bounds,
|
time_of_day,
|
||||||
time_of_day,
|
scene_data.state.get_time(),
|
||||||
scene_data.state.get_time(),
|
renderer.get_resolution().as_(),
|
||||||
renderer.get_resolution(),
|
Vec2::new(SHADOW_NEAR, SHADOW_FAR),
|
||||||
Vec2::new(SHADOW_NEAR, SHADOW_FAR),
|
lights.len(),
|
||||||
lights.len(),
|
shadows.len(),
|
||||||
shadows.len(),
|
NUM_DIRECTED_LIGHTS,
|
||||||
NUM_DIRECTED_LIGHTS,
|
scene_data
|
||||||
scene_data
|
.state
|
||||||
.state
|
.terrain()
|
||||||
.terrain()
|
.get((cam_pos + focus_off).map(|e| e.floor() as i32))
|
||||||
.get((cam_pos + focus_off).map(|e| e.floor() as i32))
|
.map(|b| b.kind())
|
||||||
.map(|b| b.kind())
|
.unwrap_or(BlockKind::Air),
|
||||||
.unwrap_or(BlockKind::Air),
|
self.select_pos.map(|e| e - focus_off.map(|e| e as i32)),
|
||||||
self.select_pos.map(|e| e - focus_off.map(|e| e as i32)),
|
scene_data.gamma,
|
||||||
scene_data.gamma,
|
scene_data.exposure,
|
||||||
scene_data.exposure,
|
scene_data.ambiance,
|
||||||
scene_data.ambiance,
|
self.camera.get_mode(),
|
||||||
self.camera.get_mode(),
|
scene_data.sprite_render_distance as f32 - 20.0,
|
||||||
scene_data.sprite_render_distance as f32 - 20.0,
|
)]);
|
||||||
)])
|
renderer.update_consts(&mut self.clouds.locals, &[CloudsLocals::new(
|
||||||
.expect("Failed to update global constants");
|
proj_mat_inv,
|
||||||
renderer
|
view_mat_inv,
|
||||||
.update_consts(&mut self.clouds.locals, &[CloudsLocals::new(
|
)]);
|
||||||
proj_mat_inv,
|
renderer.update_consts(&mut self.postprocess.locals, &[PostProcessLocals::new(
|
||||||
view_mat_inv,
|
proj_mat_inv,
|
||||||
)])
|
view_mat_inv,
|
||||||
.expect("Failed to update cloud locals");
|
)]);
|
||||||
renderer
|
|
||||||
.update_consts(&mut self.postprocess.locals, &[PostProcessLocals::new(
|
|
||||||
proj_mat_inv,
|
|
||||||
view_mat_inv,
|
|
||||||
)])
|
|
||||||
.expect("Failed to update post-process locals");
|
|
||||||
|
|
||||||
// Maintain LoD.
|
// Maintain LoD.
|
||||||
self.lod.maintain(renderer);
|
self.lod.maintain(renderer);
|
||||||
@ -985,9 +975,7 @@ impl Scene {
|
|||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
renderer
|
renderer.update_consts(&mut self.data.shadow_mats, &shadow_mats);
|
||||||
.update_consts(&mut self.data.shadow_mats, &shadow_mats)
|
|
||||||
.expect("Failed to update light constants");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove unused figures.
|
// Remove unused figures.
|
||||||
@ -1028,10 +1016,10 @@ impl Scene {
|
|||||||
|
|
||||||
// would instead have this as an extension.
|
// would instead have this as an extension.
|
||||||
if renderer.render_mode().shadow.is_map() && (is_daylight || !light_data.1.is_empty()) {
|
if renderer.render_mode().shadow.is_map() && (is_daylight || !light_data.1.is_empty()) {
|
||||||
if is_daylight {
|
// if is_daylight {
|
||||||
// Set up shadow mapping.
|
// // Set up shadow mapping.
|
||||||
renderer.start_shadows();
|
// renderer.start_shadows();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Render terrain shadows.
|
// Render terrain shadows.
|
||||||
self.terrain
|
self.terrain
|
||||||
@ -1041,10 +1029,10 @@ impl Scene {
|
|||||||
self.figure_mgr
|
self.figure_mgr
|
||||||
.render_shadows(renderer, state, tick, global, light_data, camera_data);
|
.render_shadows(renderer, state, tick, global, light_data, camera_data);
|
||||||
|
|
||||||
if is_daylight {
|
// if is_daylight {
|
||||||
// Flush shadows.
|
// // Flush shadows.
|
||||||
renderer.flush_shadows();
|
// renderer.flush_shadows();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
let lod = self.lod.get_data();
|
let lod = self.lod.get_data();
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::{terrain::BlocksOfInterest, SceneData, Terrain};
|
use super::{terrain::BlocksOfInterest, SceneData, Terrain};
|
||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, Meshable},
|
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_particle},
|
||||||
render::{
|
render::{
|
||||||
pipelines::particle::ParticleMode, GlobalModel, Instances, Light, LodData, Model,
|
pipelines::particle::ParticleMode, GlobalModel, Instances, Light, LodData, Model,
|
||||||
ParticleInstance, ParticleVertex, Renderer,
|
ParticleInstance, ParticleVertex, Renderer,
|
||||||
@ -1220,14 +1220,12 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model<Particl
|
|||||||
// NOTE: If we add texturing we may eventually try to share it among all
|
// NOTE: If we add texturing we may eventually try to share it among all
|
||||||
// particles in a single atlas.
|
// particles in a single atlas.
|
||||||
let max_texture_size = renderer.max_texture_size();
|
let max_texture_size = renderer.max_texture_size();
|
||||||
let max_size =
|
let max_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
|
||||||
guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size));
|
|
||||||
let mut greedy = GreedyMesh::new(max_size);
|
let mut greedy = GreedyMesh::new(max_size);
|
||||||
|
|
||||||
let segment = Segment::from(&vox.read().0);
|
let segment = Segment::from(&vox.read().0);
|
||||||
let segment_size = segment.size();
|
let segment_size = segment.size();
|
||||||
let mut mesh =
|
let mesh = generate_mesh_base_vol_particle(segment, &mut greedy).0;
|
||||||
Meshable::<ParticleVertex, &mut GreedyMesh>::generate_mesh(segment, &mut greedy).0;
|
|
||||||
// Center particle vertices around origin
|
// Center particle vertices around origin
|
||||||
for vert in mesh.vertices_mut() {
|
for vert in mesh.vertices_mut() {
|
||||||
vert.pos[0] -= segment_size.x as f32 / 2.0;
|
vert.pos[0] -= segment_size.x as f32 / 2.0;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, Meshable},
|
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain},
|
||||||
render::{
|
render::{
|
||||||
create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals, Consts,
|
create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals, Consts,
|
||||||
FigureModel, GlobalModel, Globals, Light, Mesh, Model, PostProcessLocals,
|
FigureModel, GlobalModel, Globals, Light, Mesh, Model, PostProcessLocals,
|
||||||
@ -51,10 +51,7 @@ fn generate_mesh<'a>(
|
|||||||
bone_idx: u8,
|
bone_idx: u8,
|
||||||
) -> BoneMeshes {
|
) -> BoneMeshes {
|
||||||
let (opaque, _, /* shadow */ _, bounds) =
|
let (opaque, _, /* shadow */ _, bounds) =
|
||||||
Meshable::<TerrainVertex, &mut GreedyMesh>::generate_mesh(
|
generate_mesh_base_vol_terrain(segment, (greedy, mesh, offset, Vec3::one(), bone_idx));
|
||||||
segment,
|
|
||||||
(greedy, mesh, offset, Vec3::one(), bone_idx),
|
|
||||||
);
|
|
||||||
(opaque /* , shadow */, bounds)
|
(opaque /* , shadow */, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +149,7 @@ impl Scene {
|
|||||||
&alt_image,
|
&alt_image,
|
||||||
&horizon_image,
|
&horizon_image,
|
||||||
1,
|
1,
|
||||||
map_border.into(),
|
//map_border.into(),
|
||||||
),
|
),
|
||||||
map_bounds,
|
map_bounds,
|
||||||
|
|
||||||
@ -271,7 +268,7 @@ impl Scene {
|
|||||||
const SHADOW_NEAR: f32 = 1.0;
|
const SHADOW_NEAR: f32 = 1.0;
|
||||||
const SHADOW_FAR: f32 = 25.0;
|
const SHADOW_FAR: f32 = 25.0;
|
||||||
|
|
||||||
if let Err(e) = renderer.update_consts(&mut self.data.globals, &[Globals::new(
|
renderer.update_consts(&mut self.data.globals, &[Globals::new(
|
||||||
view_mat,
|
view_mat,
|
||||||
proj_mat,
|
proj_mat,
|
||||||
cam_pos,
|
cam_pos,
|
||||||
@ -281,7 +278,7 @@ impl Scene {
|
|||||||
self.map_bounds,
|
self.map_bounds,
|
||||||
TIME,
|
TIME,
|
||||||
scene_data.time,
|
scene_data.time,
|
||||||
renderer.get_resolution(),
|
renderer.get_resolution().as_(),
|
||||||
Vec2::new(SHADOW_NEAR, SHADOW_FAR),
|
Vec2::new(SHADOW_NEAR, SHADOW_FAR),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -293,9 +290,7 @@ impl Scene {
|
|||||||
scene_data.ambiance,
|
scene_data.ambiance,
|
||||||
self.camera.get_mode(),
|
self.camera.get_mode(),
|
||||||
250.0,
|
250.0,
|
||||||
)]) {
|
)]);
|
||||||
error!(?e, "Renderer failed to update");
|
|
||||||
}
|
|
||||||
|
|
||||||
self.figure_model_cache
|
self.figure_model_cache
|
||||||
.clean(&mut self.col_lights, scene_data.tick);
|
.clean(&mut self.col_lights, scene_data.tick);
|
||||||
|
@ -2,7 +2,11 @@ mod watcher;
|
|||||||
pub use self::watcher::{BlocksOfInterest, Interaction};
|
pub use self::watcher::{BlocksOfInterest, Interaction};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, terrain::SUNLIGHT, Meshable},
|
mesh::{
|
||||||
|
greedy::GreedyMesh,
|
||||||
|
segment::generate_mesh_base_vol_sprite,
|
||||||
|
terrain::{generate_mesh, SUNLIGHT},
|
||||||
|
},
|
||||||
render::{
|
render::{
|
||||||
pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, Mesh, Model,
|
pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, Mesh, Model,
|
||||||
RenderError, Renderer, SpriteInstance, SpriteLocals, SpriteVertex, TerrainLocals,
|
RenderError, Renderer, SpriteInstance, SpriteLocals, SpriteVertex, TerrainLocals,
|
||||||
@ -30,7 +34,6 @@ use std::sync::{
|
|||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
use tracing::warn;
|
|
||||||
use treeculler::{BVol, Frustum, AABB};
|
use treeculler::{BVol, Frustum, AABB};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -174,17 +177,21 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
|
|||||||
) -> MeshWorkerResponse {
|
) -> MeshWorkerResponse {
|
||||||
span!(_guard, "mesh_worker");
|
span!(_guard, "mesh_worker");
|
||||||
let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk);
|
let blocks_of_interest = BlocksOfInterest::from_chunk(&chunk);
|
||||||
|
|
||||||
let mesh;
|
let mesh;
|
||||||
let (light_map, glow_map) = if let Some((light_map, glow_map)) = &skip_remesh {
|
let (light_map, glow_map) = if let Some((light_map, glow_map)) = &skip_remesh {
|
||||||
mesh = None;
|
mesh = None;
|
||||||
(&**light_map, &**glow_map)
|
(&**light_map, &**glow_map)
|
||||||
} else {
|
} else {
|
||||||
let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info, light_map, glow_map)) =
|
let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info, light_map, glow_map)) =
|
||||||
volume.generate_mesh((
|
generate_mesh(
|
||||||
range,
|
&volume,
|
||||||
Vec2::new(max_texture_size, max_texture_size),
|
(
|
||||||
&blocks_of_interest,
|
range,
|
||||||
));
|
Vec2::new(max_texture_size, max_texture_size),
|
||||||
|
&blocks_of_interest,
|
||||||
|
),
|
||||||
|
);
|
||||||
mesh = Some(MeshWorkerResponseMesh {
|
mesh = Some(MeshWorkerResponseMesh {
|
||||||
// TODO: Take sprite bounds into account somehow?
|
// TODO: Take sprite bounds into account somehow?
|
||||||
z_bounds: (bounds.min.z, bounds.max.z),
|
z_bounds: (bounds.min.z, bounds.max.z),
|
||||||
@ -198,6 +205,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug + '
|
|||||||
let mesh = mesh.as_ref().unwrap();
|
let mesh = mesh.as_ref().unwrap();
|
||||||
(&*mesh.light_map, &*mesh.glow_map)
|
(&*mesh.light_map, &*mesh.glow_map)
|
||||||
};
|
};
|
||||||
|
|
||||||
MeshWorkerResponse {
|
MeshWorkerResponse {
|
||||||
pos,
|
pos,
|
||||||
// Extract sprite locations from volume
|
// Extract sprite locations from volume
|
||||||
@ -363,8 +371,7 @@ impl SpriteRenderContext {
|
|||||||
let sprite_config =
|
let sprite_config =
|
||||||
Arc::<SpriteSpec>::load_expect("voxygen.voxel.sprite_manifest").cloned();
|
Arc::<SpriteSpec>::load_expect("voxygen.voxel.sprite_manifest").cloned();
|
||||||
|
|
||||||
let max_size =
|
let max_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
|
||||||
guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size));
|
|
||||||
let mut greedy = GreedyMesh::new(max_size);
|
let mut greedy = GreedyMesh::new(max_size);
|
||||||
let mut locals_buffer = [SpriteLocals::default(); 8];
|
let mut locals_buffer = [SpriteLocals::default(); 8];
|
||||||
let sprite_config_ = &sprite_config;
|
let sprite_config_ = &sprite_config;
|
||||||
@ -400,14 +407,15 @@ impl SpriteRenderContext {
|
|||||||
)
|
)
|
||||||
.unwrap_or(zero);
|
.unwrap_or(zero);
|
||||||
let max_model_size = Vec3::new(31.0, 31.0, 63.0);
|
let max_model_size = Vec3::new(31.0, 31.0, 63.0);
|
||||||
let model_scale = max_model_size.map2(model_size, |max_sz: f32, cur_sz| {
|
let model_scale =
|
||||||
let scale = max_sz / max_sz.max(cur_sz as f32);
|
max_model_size.map2(model_size, |max_sz: f32, cur_sz| {
|
||||||
if scale < 1.0 && (cur_sz as f32 * scale).ceil() > max_sz {
|
let scale = max_sz / max_sz.max(cur_sz as f32);
|
||||||
scale - 0.001
|
if scale < 1.0 && (cur_sz as f32 * scale).ceil() > max_sz {
|
||||||
} else {
|
scale - 0.001
|
||||||
scale
|
} else {
|
||||||
}
|
scale
|
||||||
});
|
}
|
||||||
|
});
|
||||||
let sprite_mat: Mat4<f32> =
|
let sprite_mat: Mat4<f32> =
|
||||||
Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE);
|
Mat4::translation_3d(offset).scaled_3d(SPRITE_SCALE);
|
||||||
move |greedy: &mut GreedyMesh| {
|
move |greedy: &mut GreedyMesh| {
|
||||||
@ -421,14 +429,15 @@ impl SpriteRenderContext {
|
|||||||
Vec3::broadcast(1.0)
|
Vec3::broadcast(1.0)
|
||||||
} else {
|
} else {
|
||||||
lod_axes * lod_scale_orig
|
lod_axes * lod_scale_orig
|
||||||
+ lod_axes
|
+ lod_axes.map(|e| {
|
||||||
.map(|e| if e == 0.0 { 1.0 } else { 0.0 })
|
if e == 0.0 { 1.0 } else { 0.0 }
|
||||||
|
})
|
||||||
};
|
};
|
||||||
// Mesh generation exclusively acts using side effects; it
|
// Mesh generation exclusively acts using side effects;
|
||||||
// has no
|
// it has no
|
||||||
// interesting return value, but updates the mesh.
|
// interesting return value, but updates the mesh.
|
||||||
let mut opaque_mesh = Mesh::new();
|
let mut opaque_mesh = Mesh::new();
|
||||||
Meshable::<SpriteVertex, &mut GreedyMesh>::generate_mesh(
|
generate_mesh_base_vol_sprite(
|
||||||
Segment::from(&model.read().0).scaled_by(lod_scale),
|
Segment::from(&model.read().0).scaled_by(lod_scale),
|
||||||
(greedy, &mut opaque_mesh, false),
|
(greedy, &mut opaque_mesh, false),
|
||||||
);
|
);
|
||||||
@ -438,8 +447,9 @@ impl SpriteRenderContext {
|
|||||||
sprite_mat * Mat4::scaling_3d(sprite_scale);
|
sprite_mat * Mat4::scaling_3d(sprite_scale);
|
||||||
locals_buffer.iter_mut().enumerate().for_each(
|
locals_buffer.iter_mut().enumerate().for_each(
|
||||||
|(ori, locals)| {
|
|(ori, locals)| {
|
||||||
let sprite_mat = sprite_mat
|
let sprite_mat = sprite_mat.rotated_z(
|
||||||
.rotated_z(f32::consts::PI * 0.25 * ori as f32);
|
f32::consts::PI * 0.25 * ori as f32,
|
||||||
|
);
|
||||||
*locals = SpriteLocals::new(
|
*locals = SpriteLocals::new(
|
||||||
sprite_mat,
|
sprite_mat,
|
||||||
sprite_scale,
|
sprite_scale,
|
||||||
@ -522,8 +532,7 @@ impl SpriteRenderContext {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let sprite_col_lights =
|
let sprite_col_lights =
|
||||||
pipelines::shadow::create_col_lights(renderer, &sprite_col_lights)
|
pipelines::shadow::create_col_lights(renderer, &sprite_col_lights);
|
||||||
.expect("Failed to upload sprite color and light data to the GPU!");
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sprite_config: Arc::clone(&sprite_config),
|
sprite_config: Arc::clone(&sprite_config),
|
||||||
@ -573,8 +582,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
) -> Result<(AtlasAllocator, Texture /* <ColLightFmt> */), RenderError> {
|
) -> Result<(AtlasAllocator, Texture /* <ColLightFmt> */), RenderError> {
|
||||||
span!(_guard, "make_atlas", "Terrain::make_atlas");
|
span!(_guard, "make_atlas", "Terrain::make_atlas");
|
||||||
let max_texture_size = renderer.max_texture_size();
|
let max_texture_size = renderer.max_texture_size();
|
||||||
let atlas_size =
|
let atlas_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
|
||||||
guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size));
|
|
||||||
let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions {
|
let atlas = AtlasAllocator::with_options(atlas_size, &guillotiere::AllocatorOptions {
|
||||||
// TODO: Verify some good empirical constants.
|
// TODO: Verify some good empirical constants.
|
||||||
small_size_threshold: 128,
|
small_size_threshold: 128,
|
||||||
@ -582,7 +590,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
..guillotiere::AllocatorOptions::default()
|
..guillotiere::AllocatorOptions::default()
|
||||||
});
|
});
|
||||||
let texture = renderer.create_texture_raw(
|
let texture = renderer.create_texture_raw(
|
||||||
wgpu::TextureDescriptor {
|
&wgpu::TextureDescriptor {
|
||||||
label: Some("Atlas texture"),
|
label: Some("Atlas texture"),
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: max_texture_size,
|
width: max_texture_size,
|
||||||
@ -595,7 +603,17 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
||||||
},
|
},
|
||||||
wgpu::SamplerDescriptor {
|
&wgpu::TextureViewDescriptor {
|
||||||
|
label: Some("Atlas texture view"),
|
||||||
|
format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D1),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
},
|
||||||
|
&wgpu::SamplerDescriptor {
|
||||||
label: Some("Atlas sampler"),
|
label: Some("Atlas sampler"),
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
@ -605,7 +623,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
);
|
||||||
Ok((atlas, texture))
|
Ok((atlas, texture))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -955,7 +973,6 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the area of the terrain we want. Because meshing needs to compute things
|
|
||||||
// like ambient occlusion and edge elision, we also need the borders
|
// like ambient occlusion and edge elision, we also need the borders
|
||||||
// of the chunk's neighbours too (hence the `- 1` and `+ 1`).
|
// of the chunk's neighbours too (hence the `- 1` and `+ 1`).
|
||||||
let aabr = Aabr {
|
let aabr = Aabr {
|
||||||
@ -1022,7 +1039,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
skip_remesh,
|
skip_remesh,
|
||||||
started_tick,
|
started_tick,
|
||||||
volume,
|
volume,
|
||||||
max_texture_size,
|
max_texture_size as u16,
|
||||||
chunk,
|
chunk,
|
||||||
aabb,
|
aabb,
|
||||||
&sprite_data,
|
&sprite_data,
|
||||||
@ -1080,8 +1097,9 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
let col_lights = &mut self.col_lights;
|
let col_lights = &mut self.col_lights;
|
||||||
let allocation = atlas
|
let allocation = atlas
|
||||||
.allocate(guillotiere::Size::new(
|
.allocate(guillotiere::Size::new(
|
||||||
i32::from(tex_size.x),
|
tex_size.x as i32, /* TODO: adjust ColLightInfo to avoid the
|
||||||
i32::from(tex_size.y),
|
* cast here? */
|
||||||
|
tex_size.y as i32,
|
||||||
))
|
))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
// Atlas allocation failure: try allocating a new texture and atlas.
|
// Atlas allocation failure: try allocating a new texture and atlas.
|
||||||
@ -1104,25 +1122,25 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
|
|
||||||
atlas
|
atlas
|
||||||
.allocate(guillotiere::Size::new(
|
.allocate(guillotiere::Size::new(
|
||||||
i32::from(tex_size.x),
|
tex_size.x as i32, /* TODO: adjust ColLightInfo to avoid
|
||||||
i32::from(tex_size.y),
|
* the
|
||||||
|
* cast here? */
|
||||||
|
tex_size.y as i32,
|
||||||
))
|
))
|
||||||
.expect("Chunk data does not fit in a texture of maximum size.")
|
.expect("Chunk data does not fit in a texture of maximum size.")
|
||||||
});
|
});
|
||||||
|
|
||||||
// NOTE: Cast is safe since the origin was a u16.
|
// NOTE: Cast is safe since the origin was a u16.
|
||||||
let atlas_offs = Vec2::new(
|
let atlas_offs = Vec2::new(
|
||||||
allocation.rectangle.min.x as u16,
|
allocation.rectangle.min.x as u32,
|
||||||
allocation.rectangle.min.y as u16,
|
allocation.rectangle.min.y as u32,
|
||||||
);
|
);
|
||||||
if let Err(err) = renderer.update_texture(
|
renderer.update_texture(
|
||||||
col_lights,
|
col_lights,
|
||||||
atlas_offs.into_array(),
|
atlas_offs.into_array(),
|
||||||
tex_size.into_array(),
|
tex_size.into_array(),
|
||||||
&tex,
|
&tex,
|
||||||
) {
|
);
|
||||||
warn!("Failed to update texture: {:?}", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.insert_chunk(response.pos, TerrainChunkData {
|
self.insert_chunk(response.pos, TerrainChunkData {
|
||||||
load_time,
|
load_time,
|
||||||
@ -1152,8 +1170,8 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
)
|
)
|
||||||
.into_array(),
|
.into_array(),
|
||||||
atlas_offs: Vec4::new(
|
atlas_offs: Vec4::new(
|
||||||
i32::from(atlas_offs.x),
|
atlas_offs.x as i32,
|
||||||
i32::from(atlas_offs.y),
|
atlas_offs.y as i32,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
@ -518,7 +518,7 @@ impl KeyMouse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
renderer: Renderer,
|
renderer: Renderer<'static>,
|
||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
cursor_grabbed: bool,
|
cursor_grabbed: bool,
|
||||||
pub pan_sensitivity: u32,
|
pub pan_sensitivity: u32,
|
||||||
@ -574,7 +574,7 @@ impl Window {
|
|||||||
// .map_err(|err| Error::BackendError(Box::new(err)))?
|
// .map_err(|err| Error::BackendError(Box::new(err)))?
|
||||||
// .init_gfx::<WinColorFmt, WinDepthFmt>();
|
// .init_gfx::<WinColorFmt, WinDepthFmt>();
|
||||||
|
|
||||||
let window = win_builder.build(&event_loop)?;
|
let window = win_builder.build(&event_loop).unwrap();
|
||||||
|
|
||||||
let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?;
|
let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?;
|
||||||
|
|
||||||
@ -658,7 +658,7 @@ impl Window {
|
|||||||
|
|
||||||
pub fn renderer(&self) -> &Renderer { &self.renderer }
|
pub fn renderer(&self) -> &Renderer { &self.renderer }
|
||||||
|
|
||||||
pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer }
|
pub fn renderer_mut(&mut self) -> &mut Renderer<'static> { &mut self.renderer }
|
||||||
|
|
||||||
pub fn resolve_deduplicated_events(&mut self, settings: &mut Settings) {
|
pub fn resolve_deduplicated_events(&mut self, settings: &mut Settings) {
|
||||||
// Handle screenshots and toggling fullscreen
|
// Handle screenshots and toggling fullscreen
|
||||||
@ -938,9 +938,9 @@ impl Window {
|
|||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => self.events.push(Event::Close),
|
WindowEvent::CloseRequested => self.events.push(Event::Close),
|
||||||
WindowEvent::Resized(physical) => {
|
WindowEvent::Resized(physical) => {
|
||||||
let (mut color_view, mut depth_view) = self.renderer.win_views_mut();
|
// let (mut color_view, mut depth_view) = self.renderer.win_views_mut();
|
||||||
self.window.resize(physical);
|
// self.window.resize(physical);
|
||||||
self.window.update_gfx(&mut color_view, &mut depth_view);
|
// self.window.update_gfx(&mut color_view, &mut depth_view);
|
||||||
self.renderer.on_resize().unwrap();
|
self.renderer.on_resize().unwrap();
|
||||||
// TODO: update users of this event with the fact that it is now the physical
|
// TODO: update users of this event with the fact that it is now the physical
|
||||||
// size
|
// size
|
||||||
@ -1084,32 +1084,24 @@ impl Window {
|
|||||||
/// Moves cursor by an offset
|
/// Moves cursor by an offset
|
||||||
pub fn offset_cursor(&self, d: Vec2<f32>) {
|
pub fn offset_cursor(&self, d: Vec2<f32>) {
|
||||||
if d != Vec2::zero() {
|
if d != Vec2::zero() {
|
||||||
if let Err(err) =
|
if let Err(err) = self
|
||||||
self.window
|
.window
|
||||||
.window()
|
.set_cursor_position(winit::dpi::LogicalPosition::new(
|
||||||
.set_cursor_position(winit::dpi::LogicalPosition::new(
|
d.x as f64 + self.cursor_position.x,
|
||||||
d.x as f64 + self.cursor_position.x,
|
d.y as f64 + self.cursor_position.y,
|
||||||
d.y as f64 + self.cursor_position.y,
|
))
|
||||||
))
|
|
||||||
{
|
{
|
||||||
error!("Error setting cursor position: {:?}", err);
|
error!("Error setting cursor position: {:?}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap_buffers(&self) -> Result<(), Error> {
|
|
||||||
span!(_guard, "swap_buffers", "Window::swap_buffers");
|
|
||||||
self.window
|
|
||||||
.swap_buffers()
|
|
||||||
.map_err(|err| Error::BackendError(Box::new(err)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_cursor_grabbed(&self) -> bool { self.cursor_grabbed }
|
pub fn is_cursor_grabbed(&self) -> bool { self.cursor_grabbed }
|
||||||
|
|
||||||
pub fn grab_cursor(&mut self, grab: bool) {
|
pub fn grab_cursor(&mut self, grab: bool) {
|
||||||
self.cursor_grabbed = grab;
|
self.cursor_grabbed = grab;
|
||||||
self.window.window().set_cursor_visible(!grab);
|
self.window.set_cursor_visible(!grab);
|
||||||
let _ = self.window.window().set_cursor_grab(grab);
|
let _ = self.window.set_cursor_grab(grab);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves mouse cursor to center of screen
|
/// Moves mouse cursor to center of screen
|
||||||
@ -1155,8 +1147,7 @@ impl Window {
|
|||||||
// the correct resolution already, load that value, otherwise filter it
|
// the correct resolution already, load that value, otherwise filter it
|
||||||
// in this iteration
|
// in this iteration
|
||||||
let correct_res = correct_res.unwrap_or_else(|| {
|
let correct_res = correct_res.unwrap_or_else(|| {
|
||||||
let window = self.window.window();
|
self.window
|
||||||
window
|
|
||||||
.current_monitor()
|
.current_monitor()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.video_modes()
|
.video_modes()
|
||||||
@ -1308,7 +1299,6 @@ impl Window {
|
|||||||
|
|
||||||
self
|
self
|
||||||
.window
|
.window
|
||||||
.window()
|
|
||||||
.current_monitor().unwrap()
|
.current_monitor().unwrap()
|
||||||
.video_modes()
|
.video_modes()
|
||||||
// Prefer bit depth over refresh rate
|
// Prefer bit depth over refresh rate
|
||||||
@ -1320,7 +1310,7 @@ impl Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fullscreen_mode(&mut self, fullscreen: FullScreenSettings) {
|
pub fn set_fullscreen_mode(&mut self, fullscreen: FullScreenSettings) {
|
||||||
let window = self.window.window();
|
let window = self.window;
|
||||||
self.fullscreen = fullscreen;
|
self.fullscreen = fullscreen;
|
||||||
window.set_fullscreen(fullscreen.enabled.then(|| match fullscreen.mode {
|
window.set_fullscreen(fullscreen.enabled.then(|| match fullscreen.mode {
|
||||||
FullscreenMode::Exclusive => {
|
FullscreenMode::Exclusive => {
|
||||||
@ -1342,20 +1332,17 @@ impl Window {
|
|||||||
pub fn logical_size(&self) -> Vec2<f64> {
|
pub fn logical_size(&self) -> Vec2<f64> {
|
||||||
let (w, h) = self
|
let (w, h) = self
|
||||||
.window
|
.window
|
||||||
.window()
|
|
||||||
.inner_size()
|
.inner_size()
|
||||||
.to_logical::<f64>(self.window.window().scale_factor())
|
.to_logical::<f64>(self.window.scale_factor())
|
||||||
.into();
|
.into();
|
||||||
Vec2::new(w, h)
|
Vec2::new(w, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_size(&mut self, new_size: Vec2<u16>) {
|
pub fn set_size(&mut self, new_size: Vec2<u16>) {
|
||||||
self.window
|
self.window.set_inner_size(winit::dpi::LogicalSize::new(
|
||||||
.window()
|
new_size.x as f64,
|
||||||
.set_inner_size(winit::dpi::LogicalSize::new(
|
new_size.y as f64,
|
||||||
new_size.x as f64,
|
));
|
||||||
new_size.y as f64,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&mut self, event: Event) { self.events.push(event) }
|
pub fn send_event(&mut self, event: Event) { self.events.push(event) }
|
||||||
|
Loading…
Reference in New Issue
Block a user