mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added support for block kinds in shaders
This commit is contained in:
@ -651,8 +651,14 @@ vec3 greedy_extract_col_light_attr(texture2D t_col_light, sampler s_col_light, v
|
|||||||
return srgb_to_linear(f_col);
|
return srgb_to_linear(f_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 greedy_extract_col_light_terrain(texture2D t_col_light, sampler s_col_light, vec2 f_uv_pos, out float f_light, out float f_glow, out float f_ao, out float f_sky_exposure) {
|
vec3 greedy_extract_col_light_kind_terrain(
|
||||||
|
texture2D t_col_light, sampler s_col_light,
|
||||||
|
texture2D t_kind, sampler s_kind,
|
||||||
|
vec2 f_uv_pos,
|
||||||
|
out float f_light, out float f_glow, out float f_ao, out float f_sky_exposure, out uint f_kind
|
||||||
|
) {
|
||||||
float _f_attr;
|
float _f_attr;
|
||||||
|
f_kind = uint(texelFetch(sampler2D(t_kind, s_kind), ivec2(f_uv_pos), 0).r * 256);
|
||||||
return greedy_extract_col_light_attr(t_col_light, s_col_light, f_uv_pos, f_light, f_glow, f_ao, _f_attr, f_sky_exposure);
|
return greedy_extract_col_light_attr(t_col_light, s_col_light, f_uv_pos, f_light, f_glow, f_ao, _f_attr, f_sky_exposure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,10 @@ layout(set = 2, binding = 0)
|
|||||||
uniform texture2D t_col_light;
|
uniform texture2D t_col_light;
|
||||||
layout(set = 2, binding = 1)
|
layout(set = 2, binding = 1)
|
||||||
uniform sampler s_col_light;
|
uniform sampler s_col_light;
|
||||||
|
layout(set = 2, binding = 2)
|
||||||
|
uniform texture2D t_kind;
|
||||||
|
layout(set = 2, binding = 3)
|
||||||
|
uniform sampler s_kind;
|
||||||
|
|
||||||
layout (std140, set = 3, binding = 0)
|
layout (std140, set = 3, binding = 0)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
@ -86,7 +90,8 @@ void main() {
|
|||||||
// vec4 f_col_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0)));//(f_uv_pos/* + 0.5*/) / texSize);
|
// vec4 f_col_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0)));//(f_uv_pos/* + 0.5*/) / texSize);
|
||||||
// float f_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0))).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
// float f_light = textureProj(t_col_light, vec3(f_uv_pos + 0.5, textureSize(t_col_light, 0))).a;//1.0;//f_col_light.a * 4.0;// f_light = float(v_col_light & 0x3Fu) / 64.0;
|
||||||
float f_light, f_glow, f_ao, f_sky_exposure;
|
float f_light, f_glow, f_ao, f_sky_exposure;
|
||||||
vec3 f_col = greedy_extract_col_light_terrain(t_col_light, s_col_light, f_uv_pos, f_light, f_glow, f_ao, f_sky_exposure);
|
uint f_kind;
|
||||||
|
vec3 f_col = greedy_extract_col_light_kind_terrain(t_col_light, s_col_light, t_kind, s_kind, f_uv_pos, f_light, f_glow, f_ao, f_sky_exposure, f_kind);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_BAREMINIMUM
|
#ifdef EXPERIMENTAL_BAREMINIMUM
|
||||||
tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_light), 1);
|
tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_light), 1);
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
option_get_or_insert_default,
|
option_get_or_insert_default,
|
||||||
map_try_insert,
|
map_try_insert,
|
||||||
slice_as_chunks,
|
slice_as_chunks,
|
||||||
let_chains
|
let_chains,
|
||||||
|
generic_const_exprs
|
||||||
)]
|
)]
|
||||||
#![recursion_limit = "2048"]
|
#![recursion_limit = "2048"]
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::render::{mesh::Quad, ColLightInfo, TerrainVertex, Vertex};
|
use crate::render::{mesh::Quad, pipelines::AtlasData, Vertex};
|
||||||
use common_base::{prof_span, span};
|
use common_base::{prof_span, span};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ pub struct GreedyConfig<D, FA, FL, FG, FO, FS, FP, FT> {
|
|||||||
/// coloring part as a continuation. When called with a final tile size and
|
/// coloring part as a continuation. When called with a final tile size and
|
||||||
/// vector, the continuation will consume the color data and write it to the
|
/// vector, the continuation will consume the color data and write it to the
|
||||||
/// vector.
|
/// vector.
|
||||||
pub type SuspendedMesh<'a> = dyn for<'r> FnOnce(&'r mut ColLightInfo) + 'a;
|
pub type SuspendedMesh<'a, A> = dyn for<'r> FnOnce(&'r mut A, Vec2<u16>) + 'a;
|
||||||
|
|
||||||
/// Abstraction over different atlas allocators. Useful to swap out the
|
/// Abstraction over different atlas allocators. Useful to swap out the
|
||||||
/// allocator implementation for specific cases (e.g. sprites).
|
/// allocator implementation for specific cases (e.g. sprites).
|
||||||
@ -316,15 +316,19 @@ pub type SpriteAtlasAllocator = GuillotiereTiled;
|
|||||||
/// Shared state for a greedy mesh, potentially passed along to multiple models.
|
/// Shared state for a greedy mesh, potentially passed along to multiple models.
|
||||||
///
|
///
|
||||||
/// For an explanation of why we want this, see `SuspendedMesh`.
|
/// For an explanation of why we want this, see `SuspendedMesh`.
|
||||||
pub struct GreedyMesh<'a, Allocator: AtlasAllocator = guillotiere::SimpleAtlasAllocator> {
|
pub struct GreedyMesh<
|
||||||
|
'a,
|
||||||
|
A: AtlasData,
|
||||||
|
Allocator: AtlasAllocator = guillotiere::SimpleAtlasAllocator,
|
||||||
|
> {
|
||||||
//atlas: guillotiere::SimpleAtlasAllocator,
|
//atlas: guillotiere::SimpleAtlasAllocator,
|
||||||
atlas: Allocator,
|
atlas: Allocator,
|
||||||
col_lights_size: Vec2<u16>,
|
tex_size: Vec2<u16>,
|
||||||
max_size: Vec2<u16>,
|
max_size: Vec2<u16>,
|
||||||
suspended: Vec<Box<SuspendedMesh<'a>>>,
|
suspended: Vec<Box<SuspendedMesh<'a, A>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
impl<'a, A: AtlasData, Allocator: AtlasAllocator> GreedyMesh<'a, A, Allocator> {
|
||||||
/// Construct a new greedy mesher.
|
/// Construct a new greedy mesher.
|
||||||
///
|
///
|
||||||
/// Takes as input the maximum allowable size of the texture atlas used to
|
/// Takes as input the maximum allowable size of the texture atlas used to
|
||||||
@ -350,10 +354,10 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
|||||||
max_size
|
max_size
|
||||||
);
|
);
|
||||||
let atlas = Allocator::with_max_size(max_size, config);
|
let atlas = Allocator::with_max_size(max_size, config);
|
||||||
let col_lights_size = Vec2::new(1, 1);
|
let tex_size = Vec2::new(1, 1);
|
||||||
Self {
|
Self {
|
||||||
atlas,
|
atlas,
|
||||||
col_lights_size,
|
tex_size,
|
||||||
max_size,
|
max_size,
|
||||||
suspended: Vec::new(),
|
suspended: Vec::new(),
|
||||||
}
|
}
|
||||||
@ -380,12 +384,13 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
|||||||
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + 'a,
|
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + 'a,
|
||||||
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
|
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
|
||||||
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
|
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
|
||||||
FT: for<'r> FnMut(&'r mut D, Vec3<i32>, u8, u8, bool) -> [u8; 4] + 'a,
|
FT: for<'r> FnMut(<A::SliceMut<'_> as Iterator>::Item, &'r mut D, Vec3<i32>, u8, u8, bool)
|
||||||
|
+ 'a,
|
||||||
{
|
{
|
||||||
span!(_guard, "push", "GreedyMesh::push");
|
span!(_guard, "push", "GreedyMesh::push");
|
||||||
let cont = greedy_mesh(
|
let cont = greedy_mesh::<_, _, _, _, _, _, _, _, _, A, _>(
|
||||||
&mut self.atlas,
|
&mut self.atlas,
|
||||||
&mut self.col_lights_size,
|
&mut self.tex_size,
|
||||||
self.max_size,
|
self.max_size,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
@ -401,24 +406,32 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
|||||||
/// potentially use a single staged upload to the GPU.
|
/// potentially use a single staged upload to the GPU.
|
||||||
///
|
///
|
||||||
/// Returns the ColLightsInfo corresponding to the constructed atlas.
|
/// Returns the ColLightsInfo corresponding to the constructed atlas.
|
||||||
pub fn finalize(self) -> ColLightInfo {
|
pub fn finalize(self) -> (A, Vec2<u16>) {
|
||||||
span!(_guard, "finalize", "GreedyMesh::finalize");
|
span!(_guard, "finalize", "GreedyMesh::finalize");
|
||||||
let cur_size = self.col_lights_size;
|
let mut atlas_texture_data = A::blank_with_size(self.tex_size);
|
||||||
let col_lights = vec![
|
|
||||||
TerrainVertex::make_col_light(254, 0, Rgb::broadcast(254), true);
|
|
||||||
cur_size.x as usize * cur_size.y as usize
|
|
||||||
];
|
|
||||||
let mut col_lights_info = (col_lights, cur_size);
|
|
||||||
self.suspended.into_iter().for_each(|cont| {
|
self.suspended.into_iter().for_each(|cont| {
|
||||||
cont(&mut col_lights_info);
|
cont(&mut atlas_texture_data, self.tex_size);
|
||||||
});
|
});
|
||||||
col_lights_info
|
(atlas_texture_data, self.tex_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_size(&self) -> Vec2<u16> { self.max_size }
|
pub fn max_size(&self) -> Vec2<u16> { self.max_size }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn greedy_mesh<'a, M: PartialEq, D: 'a, FA, FL, FG, FO, FS, FP, FT, Allocator: AtlasAllocator>(
|
fn greedy_mesh<
|
||||||
|
'a,
|
||||||
|
M: PartialEq,
|
||||||
|
D: 'a,
|
||||||
|
FA,
|
||||||
|
FL,
|
||||||
|
FG,
|
||||||
|
FO,
|
||||||
|
FS,
|
||||||
|
FP,
|
||||||
|
FT,
|
||||||
|
A: AtlasData,
|
||||||
|
Allocator: AtlasAllocator,
|
||||||
|
>(
|
||||||
atlas: &mut Allocator,
|
atlas: &mut Allocator,
|
||||||
col_lights_size: &mut Vec2<u16>,
|
col_lights_size: &mut Vec2<u16>,
|
||||||
max_size: Vec2<u16>,
|
max_size: Vec2<u16>,
|
||||||
@ -435,7 +448,7 @@ fn greedy_mesh<'a, M: PartialEq, D: 'a, FA, FL, FG, FO, FS, FP, FT, Allocator: A
|
|||||||
mut push_quad,
|
mut push_quad,
|
||||||
make_face_texel,
|
make_face_texel,
|
||||||
}: GreedyConfig<D, FA, FL, FG, FO, FS, FP, FT>,
|
}: GreedyConfig<D, FA, FL, FG, FO, FS, FP, FT>,
|
||||||
) -> Box<SuspendedMesh<'a>>
|
) -> Box<SuspendedMesh<'a, A>>
|
||||||
where
|
where
|
||||||
FA: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
|
FA: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
|
||||||
FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
|
FL: for<'r> FnMut(&'r mut D, Vec3<i32>) -> f32 + 'a,
|
||||||
@ -443,7 +456,7 @@ where
|
|||||||
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + 'a,
|
FO: for<'r> FnMut(&'r mut D, Vec3<i32>) -> bool + 'a,
|
||||||
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
|
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
|
||||||
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
|
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
|
||||||
FT: for<'r> FnMut(&'r mut D, Vec3<i32>, u8, u8, bool) -> [u8; 4] + 'a,
|
FT: for<'r> FnMut(<A::SliceMut<'_> as Iterator>::Item, &'r mut D, Vec3<i32>, u8, u8, bool) + 'a,
|
||||||
{
|
{
|
||||||
span!(_guard, "greedy_mesh");
|
span!(_guard, "greedy_mesh");
|
||||||
// TODO: Collect information to see if we can choose a good value here.
|
// TODO: Collect information to see if we can choose a good value here.
|
||||||
@ -572,10 +585,11 @@ where
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Box::new(move |col_lights_info| {
|
Box::new(move |atlas_texture_data, cur_size| {
|
||||||
let mut data = data;
|
let mut data = data;
|
||||||
draw_col_lights(
|
draw_col_lights::<_, A>(
|
||||||
col_lights_info,
|
atlas_texture_data,
|
||||||
|
cur_size,
|
||||||
&mut data,
|
&mut data,
|
||||||
todo_rects,
|
todo_rects,
|
||||||
draw_delta,
|
draw_delta,
|
||||||
@ -727,8 +741,9 @@ fn add_to_atlas<Allocator: AtlasAllocator>(
|
|||||||
// to provide builtin support for what we're doing here.
|
// to provide builtin support for what we're doing here.
|
||||||
//
|
//
|
||||||
// TODO: See if we can speed this up using SIMD.
|
// TODO: See if we can speed this up using SIMD.
|
||||||
fn draw_col_lights<D>(
|
fn draw_col_lights<D, A: AtlasData>(
|
||||||
(col_lights, cur_size): &mut ColLightInfo,
|
atlas_texture_data: &mut A,
|
||||||
|
cur_size: Vec2<u16>,
|
||||||
data: &mut D,
|
data: &mut D,
|
||||||
todo_rects: Vec<TodoRect>,
|
todo_rects: Vec<TodoRect>,
|
||||||
draw_delta: Vec3<i32>,
|
draw_delta: Vec3<i32>,
|
||||||
@ -736,7 +751,14 @@ 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, bool) -> [u8; 4],
|
mut make_face_texel: impl FnMut(
|
||||||
|
<A::SliceMut<'_> as Iterator>::Item,
|
||||||
|
&mut D,
|
||||||
|
Vec3<i32>,
|
||||||
|
u8,
|
||||||
|
u8,
|
||||||
|
bool,
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
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
|
||||||
@ -751,8 +773,8 @@ fn draw_col_lights<D>(
|
|||||||
(0..height).for_each(|v| {
|
(0..height).for_each(|v| {
|
||||||
let start = cur_size.x as usize * 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(atlas_texture_data.slice_mut(start..start + usize::from(width)))
|
||||||
.for_each(|(u, col_light)| {
|
.for_each(|(u, texel)| {
|
||||||
let pos = pos + uv.x * i32::from(u) + uv.y * i32::from(v);
|
let pos = pos + uv.x * i32::from(u) + uv.y * i32::from(v);
|
||||||
// TODO: Consider optimizing to take advantage of the fact that this whole
|
// TODO: Consider optimizing to take advantage of the fact that this whole
|
||||||
// face should be facing nothing but air (this is not currently true, but
|
// face should be facing nothing but air (this is not currently true, but
|
||||||
@ -822,7 +844,7 @@ fn draw_col_lights<D>(
|
|||||||
let light = (darkness * 31.5) as u8;
|
let light = (darkness * 31.5) as u8;
|
||||||
let glow = (glowiness * 31.5) as u8;
|
let glow = (glowiness * 31.5) as u8;
|
||||||
let ao = ao > 0.7;
|
let ao = ao > 0.7;
|
||||||
*col_light = make_face_texel(data, pos, light, glow, ao);
|
make_face_texel(texel, data, pos, light, glow, ao);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
terrain::FaceKind,
|
terrain::FaceKind,
|
||||||
MeshGen,
|
MeshGen,
|
||||||
},
|
},
|
||||||
render::{Mesh, ParticleVertex, SpriteVertex, TerrainVertex},
|
render::{pipelines::FigureSpriteAtlasData, Mesh, ParticleVertex, SpriteVertex, TerrainVertex},
|
||||||
scene::math,
|
scene::math,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -21,7 +21,7 @@ use vek::*;
|
|||||||
pub fn generate_mesh_base_vol_figure<'a: 'b, 'b, V: 'a>(
|
pub fn generate_mesh_base_vol_figure<'a: 'b, 'b, V: 'a>(
|
||||||
vol: V,
|
vol: V,
|
||||||
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
||||||
&'b mut GreedyMesh<'a>,
|
&'b mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
&'b mut Mesh<TerrainVertex>,
|
&'b mut Mesh<TerrainVertex>,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
@ -91,7 +91,7 @@ where
|
|||||||
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
make_face_texel: |vol: &mut V, pos, light, _, _| {
|
make_face_texel: |col_light: &mut [u8; 4], vol: &mut V, pos, light, _, _| {
|
||||||
let cell = vol.get(pos).ok();
|
let cell = vol.get(pos).ok();
|
||||||
let (glowy, shiny) = cell
|
let (glowy, shiny) = cell
|
||||||
.map(|c| (c.is_glowy(), c.is_shiny()))
|
.map(|c| (c.is_glowy(), c.is_shiny()))
|
||||||
@ -99,7 +99,7 @@ where
|
|||||||
let col = cell
|
let col = cell
|
||||||
.and_then(|vox| vox.get_color())
|
.and_then(|vox| vox.get_color())
|
||||||
.unwrap_or_else(Rgb::zero);
|
.unwrap_or_else(Rgb::zero);
|
||||||
TerrainVertex::make_col_light_figure(light, glowy, shiny, col)
|
*col_light = TerrainVertex::make_col_light_figure(light, glowy, shiny, col);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
let bounds = math::Aabb {
|
let bounds = math::Aabb {
|
||||||
@ -118,7 +118,7 @@ where
|
|||||||
pub fn generate_mesh_base_vol_terrain<'a: 'b, 'b, V: 'a>(
|
pub fn generate_mesh_base_vol_terrain<'a: 'b, 'b, V: 'a>(
|
||||||
vol: V,
|
vol: V,
|
||||||
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
||||||
&'b mut GreedyMesh<'a>,
|
&'b mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
&'b mut Mesh<TerrainVertex>,
|
&'b mut Mesh<TerrainVertex>,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
Vec3<f32>,
|
Vec3<f32>,
|
||||||
@ -201,13 +201,13 @@ where
|
|||||||
},
|
},
|
||||||
FaceKind::Fluid => {},
|
FaceKind::Fluid => {},
|
||||||
},
|
},
|
||||||
make_face_texel: |vol: &mut V, pos, light, _, _| {
|
make_face_texel: |col_light: &mut [u8; 4], vol: &mut V, pos, light, _, _| {
|
||||||
let block = vol.get(pos).ok();
|
let block = vol.get(pos).ok();
|
||||||
let glowy = block.map(|c| c.get_glow().is_some()).unwrap_or_default();
|
let glowy = block.map(|c| c.get_glow().is_some()).unwrap_or_default();
|
||||||
let col = block
|
let col = block
|
||||||
.and_then(|vox| vox.get_color())
|
.and_then(|vox| vox.get_color())
|
||||||
.unwrap_or_else(Rgb::zero);
|
.unwrap_or_else(Rgb::zero);
|
||||||
TerrainVertex::make_col_light_figure(light, glowy, false, col)
|
*col_light = TerrainVertex::make_col_light_figure(light, glowy, false, col);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
let bounds = math::Aabb {
|
let bounds = math::Aabb {
|
||||||
@ -223,7 +223,7 @@ where
|
|||||||
pub fn generate_mesh_base_vol_sprite<'a: 'b, 'b, V: 'a>(
|
pub fn generate_mesh_base_vol_sprite<'a: 'b, 'b, V: 'a>(
|
||||||
vol: V,
|
vol: V,
|
||||||
(greedy, opaque_mesh, vertical_stripes): (
|
(greedy, opaque_mesh, vertical_stripes): (
|
||||||
&'b mut GreedyMesh<'a, greedy::SpriteAtlasAllocator>,
|
&'b mut GreedyMesh<'a, FigureSpriteAtlasData, greedy::SpriteAtlasAllocator>,
|
||||||
&'b mut Mesh<SpriteVertex>,
|
&'b mut Mesh<SpriteVertex>,
|
||||||
bool,
|
bool,
|
||||||
),
|
),
|
||||||
@ -336,10 +336,11 @@ where
|
|||||||
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
|atlas_pos, pos, norm, &meta| create_opaque(atlas_pos, pos, norm, meta),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
make_face_texel: move |flat: &mut _, pos, light, _glow, _ao| {
|
make_face_texel: move |col_light: &mut [u8; 4], flat: &mut _, pos, light, _glow, _ao| {
|
||||||
let cell = flat_get(flat, pos);
|
let cell = flat_get(flat, pos);
|
||||||
let (glowy, shiny) = (cell.is_glowy(), cell.is_shiny());
|
let (glowy, shiny) = (cell.is_glowy(), cell.is_shiny());
|
||||||
TerrainVertex::make_col_light_figure(light, glowy, shiny, get_color(flat, pos))
|
*col_light =
|
||||||
|
TerrainVertex::make_col_light_figure(light, glowy, shiny, get_color(flat, pos));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -348,7 +349,7 @@ where
|
|||||||
|
|
||||||
pub fn generate_mesh_base_vol_particle<'a: 'b, 'b, V: 'a>(
|
pub fn generate_mesh_base_vol_particle<'a: 'b, 'b, V: 'a>(
|
||||||
vol: V,
|
vol: V,
|
||||||
greedy: &'b mut GreedyMesh<'a>,
|
greedy: &'b mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
) -> MeshGen<ParticleVertex, ParticleVertex, TerrainVertex, ()>
|
) -> MeshGen<ParticleVertex, ParticleVertex, TerrainVertex, ()>
|
||||||
where
|
where
|
||||||
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
||||||
@ -421,8 +422,8 @@ where
|
|||||||
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
make_face_texel: move |vol: &mut V, pos, light, glow, ao| {
|
make_face_texel: move |col_light: &mut [u8; 4], vol: &mut V, pos, light, glow, ao| {
|
||||||
TerrainVertex::make_col_light(light, glow, get_color(vol, pos), ao)
|
*col_light = TerrainVertex::make_col_light(light, glow, get_color(vol, pos), ao);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
greedy::{self, GreedyConfig, GreedyMesh},
|
greedy::{self, GreedyConfig, GreedyMesh},
|
||||||
MeshGen,
|
MeshGen,
|
||||||
},
|
},
|
||||||
render::{AltIndices, ColLightInfo, FluidVertex, Mesh, TerrainVertex, Vertex},
|
render::{AltIndices, FluidVertex, Mesh, TerrainAtlasData, TerrainVertex, Vertex},
|
||||||
scene::terrain::{BlocksOfInterest, DEEP_ALT, SHALLOW_ALT},
|
scene::terrain::{BlocksOfInterest, DEEP_ALT, SHALLOW_ALT},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -235,7 +235,8 @@ pub fn generate_mesh<'a>(
|
|||||||
TerrainVertex,
|
TerrainVertex,
|
||||||
(
|
(
|
||||||
Aabb<f32>,
|
Aabb<f32>,
|
||||||
ColLightInfo,
|
TerrainAtlasData,
|
||||||
|
Vec2<u16>,
|
||||||
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>,
|
||||||
AltIndices,
|
AltIndices,
|
||||||
@ -390,6 +391,7 @@ pub fn generate_mesh<'a>(
|
|||||||
let get_glow = |_: &mut (), pos: Vec3<i32>| glow(pos + range.min);
|
let get_glow = |_: &mut (), pos: Vec3<i32>| glow(pos + range.min);
|
||||||
let get_color =
|
let get_color =
|
||||||
|_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or_else(Rgb::zero);
|
|_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or_else(Rgb::zero);
|
||||||
|
let get_kind = |_: &mut (), pos: Vec3<i32>| flat_get(pos).kind() as u8;
|
||||||
let get_opacity = |_: &mut (), pos: Vec3<i32>| !flat_get(pos).is_opaque();
|
let get_opacity = |_: &mut (), pos: Vec3<i32>| !flat_get(pos).is_opaque();
|
||||||
let should_draw = |_: &mut (), pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
let should_draw = |_: &mut (), pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
||||||
should_draw_greedy(pos, delta, &flat_get)
|
should_draw_greedy(pos, delta, &flat_get)
|
||||||
@ -430,8 +432,10 @@ pub fn generate_mesh<'a>(
|
|||||||
FluidVertex::new(pos + mesh_delta, norm, vel.xy())
|
FluidVertex::new(pos + mesh_delta, norm, vel.xy())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut greedy =
|
let mut greedy = GreedyMesh::<TerrainAtlasData, guillotiere::SimpleAtlasAllocator>::new(
|
||||||
GreedyMesh::<guillotiere::SimpleAtlasAllocator>::new(max_size, greedy::general_config());
|
max_size,
|
||||||
|
greedy::general_config(),
|
||||||
|
);
|
||||||
let mut opaque_deep = Vec::new();
|
let mut opaque_deep = Vec::new();
|
||||||
let mut opaque_shallow = Vec::new();
|
let mut opaque_shallow = Vec::new();
|
||||||
let mut opaque_surface = Vec::new();
|
let mut opaque_surface = Vec::new();
|
||||||
@ -486,8 +490,14 @@ pub fn generate_mesh<'a>(
|
|||||||
));
|
));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
make_face_texel: |data: &mut (), pos, light, glow, ao| {
|
make_face_texel: |(col_light, kind): (&mut [u8; 4], &mut u8),
|
||||||
TerrainVertex::make_col_light(light, glow, get_color(data, pos), ao)
|
data: &mut (),
|
||||||
|
pos,
|
||||||
|
light,
|
||||||
|
glow,
|
||||||
|
ao| {
|
||||||
|
*col_light = TerrainVertex::make_col_light(light, glow, get_color(data, pos), ao);
|
||||||
|
*kind = get_kind(data, pos);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -496,7 +506,7 @@ pub fn generate_mesh<'a>(
|
|||||||
min: min_bounds,
|
min: min_bounds,
|
||||||
max: max_bounds + min_bounds,
|
max: max_bounds + min_bounds,
|
||||||
};
|
};
|
||||||
let (col_lights, col_lights_size) = greedy.finalize();
|
let (atlas_data, atlas_size) = greedy.finalize();
|
||||||
|
|
||||||
let deep_end = opaque_deep.len()
|
let deep_end = opaque_deep.len()
|
||||||
* if TerrainVertex::QUADS_INDEX.is_some() {
|
* if TerrainVertex::QUADS_INDEX.is_some() {
|
||||||
@ -526,7 +536,8 @@ pub fn generate_mesh<'a>(
|
|||||||
Mesh::new(),
|
Mesh::new(),
|
||||||
(
|
(
|
||||||
bounds,
|
bounds,
|
||||||
(col_lights, col_lights_size),
|
atlas_data,
|
||||||
|
atlas_size,
|
||||||
Arc::new(light),
|
Arc::new(light),
|
||||||
Arc::new(glow),
|
Arc::new(glow),
|
||||||
alt_indices,
|
alt_indices,
|
||||||
|
@ -46,7 +46,8 @@ pub use self::{
|
|||||||
TextureBindGroup as UiTextureBindGroup, UploadBatchId as UiUploadBatchId,
|
TextureBindGroup as UiTextureBindGroup, UploadBatchId as UiUploadBatchId,
|
||||||
Vertex as UiVertex,
|
Vertex as UiVertex,
|
||||||
},
|
},
|
||||||
GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light, Shadow,
|
FigureSpriteAtlasData, GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light,
|
||||||
|
Shadow, TerrainAtlasData,
|
||||||
},
|
},
|
||||||
renderer::{
|
renderer::{
|
||||||
drawer::{
|
drawer::{
|
||||||
@ -55,7 +56,7 @@ pub use self::{
|
|||||||
TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer,
|
TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer,
|
||||||
TransparentPassDrawer, UiDrawer, VolumetricPassDrawer, UI_PREMULTIPLY_PASS,
|
TransparentPassDrawer, UiDrawer, VolumetricPassDrawer, UI_PREMULTIPLY_PASS,
|
||||||
},
|
},
|
||||||
AltIndices, ColLightInfo, CullingMode, Renderer,
|
AltIndices, CullingMode, Renderer,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{
|
use super::{
|
||||||
super::{AaMode, Bound, Consts, GlobalsLayouts, Mesh, Model},
|
super::{AaMode, Bound, Consts, GlobalsLayouts, Mesh, Model},
|
||||||
terrain::Vertex,
|
terrain::Vertex,
|
||||||
|
AtlasData,
|
||||||
};
|
};
|
||||||
use crate::mesh::greedy::GreedyMesh;
|
use crate::mesh::greedy::GreedyMesh;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
@ -87,7 +88,7 @@ pub struct FigureModel {
|
|||||||
|
|
||||||
impl FigureModel {
|
impl FigureModel {
|
||||||
/// Start a greedy mesh designed for figure bones.
|
/// Start a greedy mesh designed for figure bones.
|
||||||
pub fn make_greedy<'a>() -> GreedyMesh<'a> {
|
pub fn make_greedy<'a>() -> GreedyMesh<'a, FigureSpriteAtlasData> {
|
||||||
// NOTE: Required because we steal two bits from the normal in the shadow uint
|
// 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
|
// 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
|
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
||||||
@ -185,7 +186,7 @@ impl FigurePipeline {
|
|||||||
bind_group_layouts: &[
|
bind_group_layouts: &[
|
||||||
&global_layout.globals,
|
&global_layout.globals,
|
||||||
&global_layout.shadow_textures,
|
&global_layout.shadow_textures,
|
||||||
&global_layout.col_light,
|
global_layout.figure_sprite_atlas_layout.layout(),
|
||||||
&layout.locals,
|
&layout.locals,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -253,3 +254,57 @@ impl FigurePipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents texture that can be converted into texture atlases for figures
|
||||||
|
/// and sprites.
|
||||||
|
pub struct FigureSpriteAtlasData {
|
||||||
|
pub col_lights: Vec<[u8; 4]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtlasData for FigureSpriteAtlasData {
|
||||||
|
type SliceMut<'a> = std::slice::IterMut<'a, [u8; 4]>;
|
||||||
|
|
||||||
|
const TEXTURES: usize = 1;
|
||||||
|
|
||||||
|
fn blank_with_size(sz: Vec2<u16>) -> Self {
|
||||||
|
let col_lights =
|
||||||
|
vec![Vertex::make_col_light(254, 0, Rgb::broadcast(254), true); sz.as_().product()];
|
||||||
|
Self { col_lights }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_texture_data(&self) -> [(wgpu::TextureFormat, &[u8]); Self::TEXTURES] {
|
||||||
|
[(
|
||||||
|
wgpu::TextureFormat::Rgba8Unorm,
|
||||||
|
bytemuck::cast_slice(self.col_lights.as_slice()),
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout() -> Vec<wgpu::BindGroupLayoutEntry> {
|
||||||
|
vec![
|
||||||
|
// col lights
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler {
|
||||||
|
filtering: true,
|
||||||
|
comparison: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slice_mut(&mut self, range: std::ops::Range<usize>) -> Self::SliceMut<'_> {
|
||||||
|
self.col_lights[range].iter_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,12 +16,15 @@ pub mod terrain;
|
|||||||
pub mod trail;
|
pub mod trail;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
use super::{Consts, Texture};
|
use super::{Consts, Renderer, Texture};
|
||||||
use crate::scene::camera::CameraMode;
|
use crate::scene::camera::CameraMode;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use common::terrain::BlockKind;
|
use common::terrain::BlockKind;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
|
pub use self::{figure::FigureSpriteAtlasData, terrain::TerrainAtlasData};
|
||||||
|
|
||||||
// TODO: auto insert these into shaders
|
// TODO: auto insert these into shaders
|
||||||
pub const MAX_POINT_LIGHT_COUNT: usize = 20;
|
pub const MAX_POINT_LIGHT_COUNT: usize = 20;
|
||||||
pub const MAX_FIGURE_SHADOW_COUNT: usize = 24;
|
pub const MAX_FIGURE_SHADOW_COUNT: usize = 24;
|
||||||
@ -278,16 +281,114 @@ pub struct ShadowTexturesBindGroup {
|
|||||||
|
|
||||||
pub struct GlobalsLayouts {
|
pub struct GlobalsLayouts {
|
||||||
pub globals: wgpu::BindGroupLayout,
|
pub globals: wgpu::BindGroupLayout,
|
||||||
pub col_light: wgpu::BindGroupLayout,
|
pub figure_sprite_atlas_layout: VoxelAtlasLayout<FigureSpriteAtlasData>,
|
||||||
|
pub terrain_atlas_layout: VoxelAtlasLayout<TerrainAtlasData>,
|
||||||
pub shadow_textures: wgpu::BindGroupLayout,
|
pub shadow_textures: wgpu::BindGroupLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ColLights<Locals> {
|
/// A type representing a set of textures that have the same atlas layout and
|
||||||
|
/// pertain to a greedy voxel structure.
|
||||||
|
pub struct AtlasTextures<Locals, S: AtlasData>
|
||||||
|
where
|
||||||
|
[(); S::TEXTURES]:,
|
||||||
|
{
|
||||||
pub(super) bind_group: wgpu::BindGroup,
|
pub(super) bind_group: wgpu::BindGroup,
|
||||||
pub texture: Texture,
|
pub textures: [Texture; S::TEXTURES],
|
||||||
phantom: std::marker::PhantomData<Locals>,
|
phantom: std::marker::PhantomData<Locals>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VoxelAtlasLayout<S: AtlasData>(wgpu::BindGroupLayout, PhantomData<S>);
|
||||||
|
|
||||||
|
impl<S: AtlasData> VoxelAtlasLayout<S> {
|
||||||
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
|
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: None,
|
||||||
|
entries: &S::layout(),
|
||||||
|
});
|
||||||
|
|
||||||
|
Self(layout, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layout(&self) -> &wgpu::BindGroupLayout { &self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait implemented by texture atlas groups.
|
||||||
|
///
|
||||||
|
/// Terrain, figures, sprites, etc. all use texture atlases but have different
|
||||||
|
/// requirements, such as that layers provided by each atlas. This trait
|
||||||
|
/// abstracts over these cases.
|
||||||
|
pub trait AtlasData {
|
||||||
|
/// The number of texture channels that this atlas has.
|
||||||
|
const TEXTURES: usize;
|
||||||
|
/// Abstracts over a slice into the texture data, as returned by
|
||||||
|
/// [`AtlasData::slice_mut`].
|
||||||
|
type SliceMut<'a>: Iterator
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Return blank atlas data upon which texels can be applied.
|
||||||
|
fn blank_with_size(sz: Vec2<u16>) -> Self;
|
||||||
|
|
||||||
|
/// Return an array of texture formats and data for each texture layer in
|
||||||
|
/// the atlas.
|
||||||
|
fn as_texture_data(&self) -> [(wgpu::TextureFormat, &[u8]); Self::TEXTURES];
|
||||||
|
|
||||||
|
/// Return a layout entry that corresponds to the texture layers in the
|
||||||
|
/// atlas.
|
||||||
|
fn layout() -> Vec<wgpu::BindGroupLayoutEntry>;
|
||||||
|
|
||||||
|
/// Take a sub-slice of the texture data for each layer in the atlas.
|
||||||
|
fn slice_mut(&mut self, range: std::ops::Range<usize>) -> Self::SliceMut<'_>;
|
||||||
|
|
||||||
|
/// Create textures on the GPU corresponding to the layers in the atlas.
|
||||||
|
fn create_textures(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
atlas_size: Vec2<u16>,
|
||||||
|
) -> [Texture; Self::TEXTURES] {
|
||||||
|
self.as_texture_data().map(|(fmt, data)| {
|
||||||
|
let texture_info = wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: u32::from(atlas_size.x),
|
||||||
|
height: u32::from(atlas_size.y),
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: fmt,
|
||||||
|
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
|
||||||
|
};
|
||||||
|
|
||||||
|
let sampler_info = wgpu::SamplerDescriptor {
|
||||||
|
label: None,
|
||||||
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
|
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||||
|
mag_filter: wgpu::FilterMode::Linear,
|
||||||
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
|
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||||
|
border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let view_info = wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: Some(fmt),
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
mip_level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.create_texture_with_data_raw(&texture_info, &view_info, &sampler_info, data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GlobalsLayouts {
|
impl GlobalsLayouts {
|
||||||
pub fn base_globals_layout() -> Vec<wgpu::BindGroupLayoutEntry> {
|
pub fn base_globals_layout() -> Vec<wgpu::BindGroupLayoutEntry> {
|
||||||
vec![
|
vec![
|
||||||
@ -456,32 +557,6 @@ impl GlobalsLayouts {
|
|||||||
entries: &Self::base_globals_layout(),
|
entries: &Self::base_globals_layout(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let col_light = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
label: None,
|
|
||||||
entries: &[
|
|
||||||
// col lights
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Texture {
|
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
multisampled: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Sampler {
|
|
||||||
filtering: true,
|
|
||||||
comparison: false,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let shadow_textures = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let shadow_textures = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
entries: &[
|
entries: &[
|
||||||
@ -550,8 +625,9 @@ impl GlobalsLayouts {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
globals,
|
globals,
|
||||||
col_light,
|
|
||||||
shadow_textures,
|
shadow_textures,
|
||||||
|
terrain_atlas_layout: VoxelAtlasLayout::new(device),
|
||||||
|
figure_sprite_atlas_layout: VoxelAtlasLayout::new(device),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,28 +767,35 @@ impl GlobalsLayouts {
|
|||||||
ShadowTexturesBindGroup { bind_group }
|
ShadowTexturesBindGroup { bind_group }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_col_light<Locals>(
|
pub fn bind_atlas_textures<Locals, S: AtlasData>(
|
||||||
&self,
|
&self,
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
col_light: Texture,
|
layout: &VoxelAtlasLayout<S>,
|
||||||
) -> ColLights<Locals> {
|
textures: [Texture; S::TEXTURES],
|
||||||
|
) -> AtlasTextures<Locals, S> {
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
layout: &self.col_light,
|
layout: layout.layout(),
|
||||||
entries: &[
|
entries: &textures
|
||||||
wgpu::BindGroupEntry {
|
.iter()
|
||||||
binding: 0,
|
.enumerate()
|
||||||
resource: wgpu::BindingResource::TextureView(&col_light.view),
|
.flat_map(|(i, tex)| {
|
||||||
},
|
[
|
||||||
wgpu::BindGroupEntry {
|
wgpu::BindGroupEntry {
|
||||||
binding: 1,
|
binding: i as u32 * 2,
|
||||||
resource: wgpu::BindingResource::Sampler(&col_light.sampler),
|
resource: wgpu::BindingResource::TextureView(&tex.view),
|
||||||
},
|
},
|
||||||
],
|
wgpu::BindGroupEntry {
|
||||||
|
binding: i as u32 * 2 + 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&tex.sampler),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
});
|
});
|
||||||
|
|
||||||
ColLights {
|
AtlasTextures {
|
||||||
texture: col_light,
|
textures,
|
||||||
bind_group,
|
bind_group,
|
||||||
phantom: std::marker::PhantomData,
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
AaMode, Bound, ColLightInfo, Consts, DebugLayout, DebugVertex, FigureLayout, GlobalsLayouts,
|
AaMode, Bound, Consts, DebugLayout, DebugVertex, FigureLayout, GlobalsLayouts, TerrainLayout,
|
||||||
Renderer, TerrainLayout, TerrainVertex, Texture,
|
TerrainVertex,
|
||||||
};
|
};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -79,55 +79,6 @@ impl Default for PointLightMatrix {
|
|||||||
fn default() -> Self { Self::new(Mat4::identity()) }
|
fn default() -> Self { Self::new(Mat4::identity()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_col_lights(
|
|
||||||
renderer: &mut Renderer,
|
|
||||||
(col_lights, col_lights_size): &ColLightInfo,
|
|
||||||
) -> Texture {
|
|
||||||
let texture_info = wgpu::TextureDescriptor {
|
|
||||||
label: None,
|
|
||||||
size: wgpu::Extent3d {
|
|
||||||
width: u32::from(col_lights_size.x),
|
|
||||||
height: u32::from(col_lights_size.y),
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
},
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
|
||||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
|
|
||||||
};
|
|
||||||
|
|
||||||
let sampler_info = wgpu::SamplerDescriptor {
|
|
||||||
label: None,
|
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
|
||||||
mag_filter: wgpu::FilterMode::Linear,
|
|
||||||
min_filter: wgpu::FilterMode::Linear,
|
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
|
||||||
border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let view_info = wgpu::TextureViewDescriptor {
|
|
||||||
label: None,
|
|
||||||
format: Some(wgpu::TextureFormat::Rgba8Unorm),
|
|
||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
|
||||||
aspect: wgpu::TextureAspect::All,
|
|
||||||
base_mip_level: 0,
|
|
||||||
mip_level_count: None,
|
|
||||||
base_array_layer: 0,
|
|
||||||
array_layer_count: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
renderer.create_texture_with_data_raw(
|
|
||||||
&texture_info,
|
|
||||||
&view_info,
|
|
||||||
&sampler_info,
|
|
||||||
bytemuck::cast_slice(col_lights),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ShadowFigurePipeline {
|
pub struct ShadowFigurePipeline {
|
||||||
pub pipeline: wgpu::RenderPipeline,
|
pub pipeline: wgpu::RenderPipeline,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{buffer::Buffer, AaMode, GlobalsLayouts, Mesh, TerrainLayout, Vertex as VertexTrait},
|
||||||
buffer::Buffer, AaMode, GlobalsLayouts, Mesh, TerrainLayout, Texture, Vertex as VertexTrait,
|
lod_terrain, GlobalModel, Texture,
|
||||||
},
|
|
||||||
lod_terrain, GlobalModel,
|
|
||||||
};
|
};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -278,7 +276,7 @@ impl SpritePipeline {
|
|||||||
&layout.globals,
|
&layout.globals,
|
||||||
&global_layout.shadow_textures,
|
&global_layout.shadow_textures,
|
||||||
// Note: mergable with globals
|
// Note: mergable with globals
|
||||||
&global_layout.col_light,
|
global_layout.figure_sprite_atlas_layout.layout(),
|
||||||
&terrain_layout.locals,
|
&terrain_layout.locals,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use super::super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait};
|
use super::{
|
||||||
|
super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait},
|
||||||
|
AtlasData,
|
||||||
|
};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -237,7 +240,7 @@ impl TerrainPipeline {
|
|||||||
bind_group_layouts: &[
|
bind_group_layouts: &[
|
||||||
&global_layout.globals,
|
&global_layout.globals,
|
||||||
&global_layout.shadow_textures,
|
&global_layout.shadow_textures,
|
||||||
&global_layout.col_light,
|
global_layout.terrain_atlas_layout.layout(),
|
||||||
&layout.locals,
|
&layout.locals,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -305,3 +308,84 @@ impl TerrainPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents texture that can be converted into texture atlases for terrain.
|
||||||
|
pub struct TerrainAtlasData {
|
||||||
|
pub col_lights: Vec<[u8; 4]>,
|
||||||
|
pub kinds: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtlasData for TerrainAtlasData {
|
||||||
|
type SliceMut<'a> =
|
||||||
|
std::iter::Zip<std::slice::IterMut<'a, [u8; 4]>, std::slice::IterMut<'a, u8>>;
|
||||||
|
|
||||||
|
const TEXTURES: usize = 2;
|
||||||
|
|
||||||
|
fn blank_with_size(sz: Vec2<u16>) -> Self {
|
||||||
|
let col_lights =
|
||||||
|
vec![Vertex::make_col_light(254, 0, Rgb::broadcast(254), true); sz.as_().product()];
|
||||||
|
let kinds = vec![0; sz.as_().product()];
|
||||||
|
Self { col_lights, kinds }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_texture_data(&self) -> [(wgpu::TextureFormat, &[u8]); Self::TEXTURES] {
|
||||||
|
[
|
||||||
|
(
|
||||||
|
wgpu::TextureFormat::Rgba8Unorm,
|
||||||
|
bytemuck::cast_slice(&self.col_lights),
|
||||||
|
),
|
||||||
|
(wgpu::TextureFormat::R8Unorm, &self.kinds),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout() -> Vec<wgpu::BindGroupLayoutEntry> {
|
||||||
|
vec![
|
||||||
|
// col lights
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler {
|
||||||
|
filtering: true,
|
||||||
|
comparison: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
// kind
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 2,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 3,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler {
|
||||||
|
filtering: true,
|
||||||
|
comparison: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slice_mut(&mut self, range: std::ops::Range<usize>) -> Self::SliceMut<'_> {
|
||||||
|
self.col_lights[range.clone()]
|
||||||
|
.iter_mut()
|
||||||
|
.zip(self.kinds[range].iter_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -40,12 +40,6 @@ use std::sync::Arc;
|
|||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
// TODO: yeet this somewhere else
|
|
||||||
/// A type representing data that can be converted to an immutable texture map
|
|
||||||
/// of ColLight data (used for texture atlases created during greedy meshing).
|
|
||||||
// TODO: revert to u16
|
|
||||||
pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u16>);
|
|
||||||
|
|
||||||
const QUAD_INDEX_BUFFER_U16_START_VERT_LEN: u16 = 3000;
|
const QUAD_INDEX_BUFFER_U16_START_VERT_LEN: u16 = 3000;
|
||||||
const QUAD_INDEX_BUFFER_U32_START_VERT_LEN: u32 = 3000;
|
const QUAD_INDEX_BUFFER_U32_START_VERT_LEN: u32 = 3000;
|
||||||
|
|
||||||
@ -1427,13 +1421,12 @@ impl Renderer {
|
|||||||
/// Update a texture with the provided offset, size, and data.
|
/// Update a texture with the provided offset, size, and data.
|
||||||
///
|
///
|
||||||
/// Currently only supports Rgba8Srgb
|
/// Currently only supports Rgba8Srgb
|
||||||
pub fn update_texture(
|
pub fn update_texture<T: bytemuck::Pod>(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture: &Texture, /* <T> */
|
texture: &Texture,
|
||||||
offset: [u32; 2],
|
offset: [u32; 2],
|
||||||
size: [u32; 2],
|
size: [u32; 2],
|
||||||
// TODO: be generic over pixel type
|
data: &[T],
|
||||||
data: &[[u8; 4]],
|
|
||||||
) {
|
) {
|
||||||
texture.update(&self.queue, offset, size, bytemuck::cast_slice(data))
|
texture.update(&self.queue, offset, size, bytemuck::cast_slice(data))
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ use crate::render::pipelines::rain_occlusion;
|
|||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
pipelines::{
|
pipelines::{
|
||||||
debug, figure, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel,
|
debug, figure, lod_terrain, shadow, sprite, terrain, ui, AtlasTextures,
|
||||||
GlobalsBindGroup,
|
FigureSpriteAtlasData, GlobalModel, GlobalsBindGroup, TerrainAtlasData,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
},
|
},
|
||||||
@ -90,15 +90,37 @@ impl Renderer {
|
|||||||
.bind_locals(&self.device, locals)
|
.bind_locals(&self.device, locals)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn figure_bind_col_light(&self, col_light: Texture) -> ColLights<figure::Locals> {
|
pub fn figure_bind_atlas_textures(
|
||||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
&self,
|
||||||
|
col_light: Texture,
|
||||||
|
) -> AtlasTextures<figure::Locals, FigureSpriteAtlasData> {
|
||||||
|
self.layouts.global.bind_atlas_textures(
|
||||||
|
&self.device,
|
||||||
|
&self.layouts.global.figure_sprite_atlas_layout,
|
||||||
|
[col_light],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn terrain_bind_col_light(&self, col_light: Texture) -> ColLights<terrain::Locals> {
|
pub fn terrain_bind_atlas_textures(
|
||||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
&self,
|
||||||
|
col_light: Texture,
|
||||||
|
kinds: Texture,
|
||||||
|
) -> AtlasTextures<terrain::Locals, TerrainAtlasData> {
|
||||||
|
self.layouts.global.bind_atlas_textures(
|
||||||
|
&self.device,
|
||||||
|
&self.layouts.global.terrain_atlas_layout,
|
||||||
|
[col_light, kinds],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sprite_bind_col_light(&self, col_light: Texture) -> ColLights<sprite::Locals> {
|
pub fn sprite_bind_atlas_textures(
|
||||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
&self,
|
||||||
|
col_light: Texture,
|
||||||
|
) -> AtlasTextures<sprite::Locals, FigureSpriteAtlasData> {
|
||||||
|
self.layouts.global.bind_atlas_textures(
|
||||||
|
&self.device,
|
||||||
|
&self.layouts.global.figure_sprite_atlas_layout,
|
||||||
|
[col_light],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ use super::{
|
|||||||
model::{DynamicModel, Model, SubModel},
|
model::{DynamicModel, Model, SubModel},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow,
|
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow,
|
||||||
skybox, sprite, terrain, trail, ui, ColLights, GlobalsBindGroup,
|
skybox, sprite, terrain, trail, ui, AtlasTextures, FigureSpriteAtlasData,
|
||||||
|
GlobalsBindGroup, TerrainAtlasData,
|
||||||
},
|
},
|
||||||
AltIndices, CullingMode,
|
AltIndices, CullingMode,
|
||||||
},
|
},
|
||||||
@ -950,7 +951,7 @@ impl<'pass> FirstPassDrawer<'pass> {
|
|||||||
|
|
||||||
TerrainDrawer {
|
TerrainDrawer {
|
||||||
render_pass,
|
render_pass,
|
||||||
col_lights: None,
|
atlas_textures: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,14 +967,14 @@ impl<'pass> FirstPassDrawer<'pass> {
|
|||||||
pub fn draw_sprites<'data: 'pass>(
|
pub fn draw_sprites<'data: 'pass>(
|
||||||
&mut self,
|
&mut self,
|
||||||
globals: &'data sprite::SpriteGlobalsBindGroup,
|
globals: &'data sprite::SpriteGlobalsBindGroup,
|
||||||
col_lights: &'data ColLights<sprite::Locals>,
|
atlas_textures: &'data AtlasTextures<sprite::Locals, FigureSpriteAtlasData>,
|
||||||
) -> SpriteDrawer<'_, 'pass> {
|
) -> SpriteDrawer<'_, 'pass> {
|
||||||
let mut render_pass = self.render_pass.scope("sprites", self.borrow.device);
|
let mut render_pass = self.render_pass.scope("sprites", self.borrow.device);
|
||||||
|
|
||||||
render_pass.set_pipeline(&self.pipelines.sprite.pipeline);
|
render_pass.set_pipeline(&self.pipelines.sprite.pipeline);
|
||||||
set_quad_index_buffer::<sprite::Vertex>(&mut render_pass, self.borrow);
|
set_quad_index_buffer::<sprite::Vertex>(&mut render_pass, self.borrow);
|
||||||
render_pass.set_bind_group(0, &globals.bind_group, &[]);
|
render_pass.set_bind_group(0, &globals.bind_group, &[]);
|
||||||
render_pass.set_bind_group(2, &col_lights.bind_group, &[]);
|
render_pass.set_bind_group(2, &atlas_textures.bind_group, &[]);
|
||||||
|
|
||||||
SpriteDrawer {
|
SpriteDrawer {
|
||||||
render_pass,
|
render_pass,
|
||||||
@ -1028,10 +1029,10 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
|
|||||||
model: SubModel<'data, terrain::Vertex>,
|
model: SubModel<'data, terrain::Vertex>,
|
||||||
locals: &'data figure::BoundLocals,
|
locals: &'data figure::BoundLocals,
|
||||||
// TODO: don't rebind this every time once they are shared between figures
|
// TODO: don't rebind this every time once they are shared between figures
|
||||||
col_lights: &'data ColLights<figure::Locals>,
|
atlas_textures: &'data AtlasTextures<figure::Locals, FigureSpriteAtlasData>,
|
||||||
) {
|
) {
|
||||||
self.render_pass
|
self.render_pass
|
||||||
.set_bind_group(2, &col_lights.bind_group, &[]);
|
.set_bind_group(2, &atlas_textures.bind_group, &[]);
|
||||||
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
|
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
|
||||||
self.render_pass.set_vertex_buffer(0, model.buf());
|
self.render_pass.set_vertex_buffer(0, model.buf());
|
||||||
self.render_pass
|
self.render_pass
|
||||||
@ -1042,14 +1043,14 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
|
pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
|
||||||
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
|
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
|
||||||
col_lights: Option<&'pass_ref Arc<ColLights<terrain::Locals>>>,
|
atlas_textures: Option<&'pass_ref Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
||||||
pub fn draw<'data: 'pass>(
|
pub fn draw<'data: 'pass>(
|
||||||
&mut self,
|
&mut self,
|
||||||
model: &'data Model<terrain::Vertex>,
|
model: &'data Model<terrain::Vertex>,
|
||||||
col_lights: &'data Arc<ColLights<terrain::Locals>>,
|
atlas_textures: &'data Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>,
|
||||||
locals: &'data terrain::BoundLocals,
|
locals: &'data terrain::BoundLocals,
|
||||||
alt_indices: &'data AltIndices,
|
alt_indices: &'data AltIndices,
|
||||||
culling_mode: CullingMode,
|
culling_mode: CullingMode,
|
||||||
@ -1067,15 +1068,15 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
|||||||
|
|
||||||
let submodel = model.submodel(index_range);
|
let submodel = model.submodel(index_range);
|
||||||
|
|
||||||
if self.col_lights
|
if self.atlas_textures
|
||||||
// Check if we are still using the same atlas texture as the previous drawn
|
// Check if we are still using the same atlas texture as the previous drawn
|
||||||
// chunk
|
// chunk
|
||||||
.filter(|current_col_lights| Arc::ptr_eq(current_col_lights, col_lights))
|
.filter(|current_atlas_textures| Arc::ptr_eq(current_atlas_textures, atlas_textures))
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
self.render_pass
|
self.render_pass
|
||||||
.set_bind_group(2, &col_lights.bind_group, &[]);
|
.set_bind_group(2, &atlas_textures.bind_group, &[]);
|
||||||
self.col_lights = Some(col_lights);
|
self.atlas_textures = Some(atlas_textures);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
|
self.render_pass.set_bind_group(3, &locals.bind_group, &[]);
|
||||||
|
@ -8,8 +8,8 @@ use crate::{
|
|||||||
segment::{generate_mesh_base_vol_figure, generate_mesh_base_vol_terrain},
|
segment::{generate_mesh_base_vol_figure, generate_mesh_base_vol_terrain},
|
||||||
},
|
},
|
||||||
render::{
|
render::{
|
||||||
BoneMeshes, ColLightInfo, FigureModel, Instances, Mesh, Renderer, SpriteInstance,
|
pipelines, BoneMeshes, FigureModel, FigureSpriteAtlasData, Instances, Mesh, Renderer,
|
||||||
TerrainVertex,
|
SpriteInstance, TerrainVertex,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::CameraMode,
|
camera::CameraMode,
|
||||||
@ -42,7 +42,8 @@ use vek::*;
|
|||||||
/// A type produced by mesh worker threads corresponding to the information
|
/// A type produced by mesh worker threads corresponding to the information
|
||||||
/// needed to mesh figures.
|
/// needed to mesh figures.
|
||||||
pub struct MeshWorkerResponse<const N: usize> {
|
pub struct MeshWorkerResponse<const N: usize> {
|
||||||
col_light: ColLightInfo,
|
atlas_texture_data: FigureSpriteAtlasData,
|
||||||
|
atlas_size: Vec2<u16>,
|
||||||
opaque: Mesh<TerrainVertex>,
|
opaque: Mesh<TerrainVertex>,
|
||||||
bounds: anim::vek::Aabb<f32>,
|
bounds: anim::vek::Aabb<f32>,
|
||||||
vertex_range: [Range<u32>; N],
|
vertex_range: [Range<u32>; N],
|
||||||
@ -51,7 +52,10 @@ pub struct MeshWorkerResponse<const N: usize> {
|
|||||||
/// A type produced by mesh worker threads corresponding to the information
|
/// A type produced by mesh worker threads corresponding to the information
|
||||||
/// needed to mesh figures.
|
/// needed to mesh figures.
|
||||||
pub struct TerrainMeshWorkerResponse<const N: usize> {
|
pub struct TerrainMeshWorkerResponse<const N: usize> {
|
||||||
col_light: ColLightInfo,
|
// TODO: This probably needs fixing to use `TerrainAtlasData`. However, right now, we just
|
||||||
|
// treat volume entities like regular figures for the sake of rendering.
|
||||||
|
atlas_texture_data: FigureSpriteAtlasData,
|
||||||
|
atlas_size: Vec2<u16>,
|
||||||
opaque: Mesh<TerrainVertex>,
|
opaque: Mesh<TerrainVertex>,
|
||||||
bounds: anim::vek::Aabb<f32>,
|
bounds: anim::vek::Aabb<f32>,
|
||||||
vertex_range: [Range<u32>; N],
|
vertex_range: [Range<u32>; N],
|
||||||
@ -323,7 +327,7 @@ where
|
|||||||
pub fn get_model<'b>(
|
pub fn get_model<'b>(
|
||||||
&'b self,
|
&'b self,
|
||||||
// TODO: If we ever convert to using an atlas here, use this.
|
// TODO: If we ever convert to using an atlas here, use this.
|
||||||
_col_lights: &super::FigureColLights,
|
_atlas: &super::FigureAtlas,
|
||||||
body: Skel::Body,
|
body: Skel::Body,
|
||||||
inventory: Option<&Inventory>,
|
inventory: Option<&Inventory>,
|
||||||
// TODO: Consider updating the tick by putting it in a Cell.
|
// TODO: Consider updating the tick by putting it in a Cell.
|
||||||
@ -358,7 +362,7 @@ where
|
|||||||
|
|
||||||
pub fn clear_models(&mut self) { self.models.clear(); }
|
pub fn clear_models(&mut self) { self.models.clear(); }
|
||||||
|
|
||||||
pub fn clean(&mut self, col_lights: &mut super::FigureColLights, tick: u64)
|
pub fn clean(&mut self, atlas: &mut super::FigureAtlas, tick: u64)
|
||||||
where
|
where
|
||||||
<Skel::Body as BodySpec>::Spec: Clone,
|
<Skel::Body as BodySpec>::Spec: Clone,
|
||||||
{
|
{
|
||||||
@ -370,7 +374,7 @@ where
|
|||||||
let alive = *last_used + delta > tick;
|
let alive = *last_used + delta > tick;
|
||||||
if !alive {
|
if !alive {
|
||||||
if let Some(model_entry) = model_entry.get_done() {
|
if let Some(model_entry) = model_entry.get_done() {
|
||||||
col_lights.atlas.deallocate(model_entry.allocation().id);
|
atlas.atlas.deallocate(model_entry.allocation().id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alive
|
alive
|
||||||
@ -391,7 +395,7 @@ where
|
|||||||
pub fn get_or_create_model<'c>(
|
pub fn get_or_create_model<'c>(
|
||||||
&'c mut self,
|
&'c mut self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
col_lights: &mut super::FigureColLights,
|
atlas: &mut super::FigureAtlas,
|
||||||
body: Skel::Body,
|
body: Skel::Body,
|
||||||
inventory: Option<&Inventory>,
|
inventory: Option<&Inventory>,
|
||||||
extra: <Skel::Body as BodySpec>::Extra,
|
extra: <Skel::Body as BodySpec>::Extra,
|
||||||
@ -428,15 +432,17 @@ where
|
|||||||
match model {
|
match model {
|
||||||
FigureModelEntryFuture::Pending(recv) => {
|
FigureModelEntryFuture::Pending(recv) => {
|
||||||
if let Some(MeshWorkerResponse {
|
if let Some(MeshWorkerResponse {
|
||||||
col_light,
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
opaque,
|
opaque,
|
||||||
bounds,
|
bounds,
|
||||||
vertex_range,
|
vertex_range,
|
||||||
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
|
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
|
||||||
{
|
{
|
||||||
let model_entry = col_lights.create_figure(
|
let model_entry = atlas.create_figure(
|
||||||
renderer,
|
renderer,
|
||||||
col_light,
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
(opaque, bounds),
|
(opaque, bounds),
|
||||||
vertex_range,
|
vertex_range,
|
||||||
);
|
);
|
||||||
@ -480,7 +486,7 @@ where
|
|||||||
// list. Returns the vertex bounds of the meshed model within the opaque
|
// list. Returns the vertex bounds of the meshed model within the opaque
|
||||||
// mesh.
|
// mesh.
|
||||||
let mut make_model = |generate_mesh: for<'a, 'b> fn(
|
let mut make_model = |generate_mesh: for<'a, 'b> fn(
|
||||||
&mut GreedyMesh<'a>,
|
&mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
&'b mut _,
|
&'b mut _,
|
||||||
&'a _,
|
&'a _,
|
||||||
_,
|
_,
|
||||||
@ -528,7 +534,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn generate_mesh<'a>(
|
fn generate_mesh<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: &'a Segment,
|
segment: &'a Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -542,7 +548,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh_lod_mid<'a>(
|
fn generate_mesh_lod_mid<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: &'a Segment,
|
segment: &'a Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -563,7 +569,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh_lod_low<'a>(
|
fn generate_mesh_lod_low<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: &'a Segment,
|
segment: &'a Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -589,8 +595,10 @@ where
|
|||||||
make_model(generate_mesh_lod_low),
|
make_model(generate_mesh_lod_low),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let (atlas_texture_data, atlas_size) = greedy.finalize();
|
||||||
slot_.store(Some(MeshWorkerResponse {
|
slot_.store(Some(MeshWorkerResponse {
|
||||||
col_light: greedy.finalize(),
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
opaque,
|
opaque,
|
||||||
bounds: figure_bounds,
|
bounds: figure_bounds,
|
||||||
vertex_range: models,
|
vertex_range: models,
|
||||||
@ -619,7 +627,7 @@ where
|
|||||||
pub fn get_or_create_terrain_model<'c>(
|
pub fn get_or_create_terrain_model<'c>(
|
||||||
&'c mut self,
|
&'c mut self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
col_lights: &mut super::FigureColLights,
|
atlas: &mut super::FigureAtlas,
|
||||||
body: Skel::Body,
|
body: Skel::Body,
|
||||||
extra: <Skel::Body as BodySpec>::Extra,
|
extra: <Skel::Body as BodySpec>::Extra,
|
||||||
tick: u64,
|
tick: u64,
|
||||||
@ -647,7 +655,8 @@ where
|
|||||||
match model {
|
match model {
|
||||||
TerrainModelEntryFuture::Pending(recv) => {
|
TerrainModelEntryFuture::Pending(recv) => {
|
||||||
if let Some(TerrainMeshWorkerResponse {
|
if let Some(TerrainMeshWorkerResponse {
|
||||||
col_light,
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
opaque,
|
opaque,
|
||||||
bounds,
|
bounds,
|
||||||
vertex_range,
|
vertex_range,
|
||||||
@ -656,9 +665,10 @@ where
|
|||||||
blocks_offset,
|
blocks_offset,
|
||||||
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
|
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
|
||||||
{
|
{
|
||||||
let model_entry = col_lights.create_terrain(
|
let model_entry = atlas.create_terrain(
|
||||||
renderer,
|
renderer,
|
||||||
col_light,
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
(opaque, bounds),
|
(opaque, bounds),
|
||||||
vertex_range,
|
vertex_range,
|
||||||
sprite_instances,
|
sprite_instances,
|
||||||
@ -707,7 +717,7 @@ where
|
|||||||
// list. Returns the vertex bounds of the meshed model within the opaque
|
// list. Returns the vertex bounds of the meshed model within the opaque
|
||||||
// mesh.
|
// mesh.
|
||||||
let mut make_model = |generate_mesh: for<'a, 'b> fn(
|
let mut make_model = |generate_mesh: for<'a, 'b> fn(
|
||||||
&mut GreedyMesh<'a>,
|
&mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
&'b mut _,
|
&'b mut _,
|
||||||
&'a _,
|
&'a _,
|
||||||
_,
|
_,
|
||||||
@ -755,7 +765,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn generate_mesh<'a>(
|
fn generate_mesh<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: &'a TerrainSegment,
|
segment: &'a TerrainSegment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -769,7 +779,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh_lod_mid<'a>(
|
fn generate_mesh_lod_mid<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: &'a TerrainSegment,
|
segment: &'a TerrainSegment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -790,7 +800,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh_lod_low<'a>(
|
fn generate_mesh_lod_low<'a>(
|
||||||
greedy: &mut GreedyMesh<'a>,
|
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: &'a TerrainSegment,
|
segment: &'a TerrainSegment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -819,13 +829,15 @@ where
|
|||||||
let (dyna, offset) = &meshes[0].as_ref().unwrap();
|
let (dyna, offset) = &meshes[0].as_ref().unwrap();
|
||||||
let block_iter = dyna.vol_iter(Vec3::zero(), dyna.sz.as_()).map(|(pos, block)| (pos, *block));
|
let block_iter = dyna.vol_iter(Vec3::zero(), dyna.sz.as_()).map(|(pos, block)| (pos, *block));
|
||||||
|
|
||||||
|
let (atlas_texture_data, atlas_size) = greedy.finalize();
|
||||||
slot_.store(Some(TerrainMeshWorkerResponse {
|
slot_.store(Some(TerrainMeshWorkerResponse {
|
||||||
col_light: greedy.finalize(),
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
opaque,
|
opaque,
|
||||||
bounds: figure_bounds,
|
bounds: figure_bounds,
|
||||||
vertex_range: models,
|
vertex_range: models,
|
||||||
sprite_instances: {
|
sprite_instances: {
|
||||||
let mut instances = from_fn(|_| Vec::new());
|
let mut instances = from_fn::<Vec<pipelines::sprite::Instance>, SPRITE_LOD_LEVELS, _>(|_| Vec::new());
|
||||||
get_sprite_instances(
|
get_sprite_instances(
|
||||||
&mut instances,
|
&mut instances,
|
||||||
|lod, instance, _| {
|
|lod, instance, _| {
|
||||||
|
@ -12,11 +12,11 @@ use crate::{
|
|||||||
pipelines::{
|
pipelines::{
|
||||||
self,
|
self,
|
||||||
terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
||||||
trail, ColLights,
|
trail, AtlasData, AtlasTextures, FigureSpriteAtlasData,
|
||||||
},
|
},
|
||||||
AltIndices, ColLightInfo, CullingMode, FigureBoneData, FigureDrawer, FigureLocals,
|
AltIndices, CullingMode, FigureBoneData, FigureDrawer, FigureLocals, FigureModel,
|
||||||
FigureModel, FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer,
|
FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer, SpriteDrawer,
|
||||||
SpriteDrawer, SpriteInstance, SubModel, TerrainVertex,
|
SpriteInstance, SubModel, TerrainVertex,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::{Camera, CameraMode, Dependents},
|
camera::{Camera, CameraMode, Dependents},
|
||||||
@ -80,7 +80,7 @@ pub type CameraData<'a> = (&'a Camera, f32);
|
|||||||
pub type FigureModelRef<'a> = (
|
pub type FigureModelRef<'a> = (
|
||||||
&'a pipelines::figure::BoundLocals,
|
&'a pipelines::figure::BoundLocals,
|
||||||
SubModel<'a, TerrainVertex>,
|
SubModel<'a, TerrainVertex>,
|
||||||
&'a ColLights<pipelines::figure::Locals>,
|
&'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
|
||||||
);
|
);
|
||||||
|
|
||||||
pub trait ModelEntry {
|
pub trait ModelEntry {
|
||||||
@ -88,7 +88,7 @@ pub trait ModelEntry {
|
|||||||
|
|
||||||
fn lod_model(&self, lod: usize) -> Option<SubModel<TerrainVertex>>;
|
fn lod_model(&self, lod: usize) -> Option<SubModel<TerrainVertex>>;
|
||||||
|
|
||||||
fn col_lights(&self) -> &ColLights<pipelines::figure::Locals>;
|
fn atlas_textures(&self) -> &AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entry holding enough information to draw or destroy a figure in a
|
/// An entry holding enough information to draw or destroy a figure in a
|
||||||
@ -104,7 +104,7 @@ pub struct FigureModelEntry<const N: usize> {
|
|||||||
/// Texture used to store color/light information for this figure entry.
|
/// Texture used to store color/light information for this figure entry.
|
||||||
/* TODO: Consider using mipmaps instead of storing multiple texture atlases for different
|
/* TODO: Consider using mipmaps instead of storing multiple texture atlases for different
|
||||||
* LOD levels. */
|
* LOD levels. */
|
||||||
col_lights: ColLights<pipelines::figure::Locals>,
|
atlas_textures: AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
|
||||||
/// Vertex ranges stored in this figure entry; there may be several for one
|
/// Vertex ranges stored in this figure entry; there may be several for one
|
||||||
/// figure, because of LOD models.
|
/// figure, because of LOD models.
|
||||||
lod_vertex_ranges: [Range<u32>; N],
|
lod_vertex_ranges: [Range<u32>; N],
|
||||||
@ -122,7 +122,9 @@ impl<const N: usize> ModelEntry for FigureModelEntry<N> {
|
|||||||
.map(|m| m.submodel(self.lod_vertex_ranges[lod].clone()))
|
.map(|m| m.submodel(self.lod_vertex_ranges[lod].clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_lights(&self) -> &ColLights<pipelines::figure::Locals> { &self.col_lights }
|
fn atlas_textures(&self) -> &AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
|
||||||
|
&self.atlas_textures
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entry holding enough information to draw or destroy a figure in a
|
/// An entry holding enough information to draw or destroy a figure in a
|
||||||
@ -138,7 +140,7 @@ pub struct TerrainModelEntry<const N: usize> {
|
|||||||
/// Texture used to store color/light information for this figure entry.
|
/// Texture used to store color/light information for this figure entry.
|
||||||
/* TODO: Consider using mipmaps instead of storing multiple texture atlases for different
|
/* TODO: Consider using mipmaps instead of storing multiple texture atlases for different
|
||||||
* LOD levels. */
|
* LOD levels. */
|
||||||
col_lights: ColLights<pipelines::figure::Locals>,
|
atlas_textures: AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
|
||||||
/// Vertex ranges stored in this figure entry; there may be several for one
|
/// Vertex ranges stored in this figure entry; there may be several for one
|
||||||
/// figure, because of LOD models.
|
/// figure, because of LOD models.
|
||||||
lod_vertex_ranges: [Range<u32>; N],
|
lod_vertex_ranges: [Range<u32>; N],
|
||||||
@ -162,7 +164,9 @@ impl<const N: usize> ModelEntry for TerrainModelEntry<N> {
|
|||||||
.map(|m| m.submodel(self.lod_vertex_ranges[lod].clone()))
|
.map(|m| m.submodel(self.lod_vertex_ranges[lod].clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_lights(&self) -> &ColLights<pipelines::figure::Locals> { &self.col_lights }
|
fn atlas_textures(&self) -> &AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
|
||||||
|
&self.atlas_textures
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -179,10 +183,12 @@ impl<'a, const N: usize> ModelEntryRef<'a, N> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn col_lights(&self) -> &'a ColLights<pipelines::figure::Locals> {
|
fn atlas_textures(
|
||||||
|
&self,
|
||||||
|
) -> &'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
|
||||||
match self {
|
match self {
|
||||||
ModelEntryRef::Figure(e) => e.col_lights(),
|
ModelEntryRef::Figure(e) => e.atlas_textures(),
|
||||||
ModelEntryRef::Terrain(e) => e.col_lights(),
|
ModelEntryRef::Terrain(e) => e.atlas_textures(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,7 +504,7 @@ impl FigureMgrStates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct FigureMgr {
|
pub struct FigureMgr {
|
||||||
col_lights: FigureColLights,
|
atlas: FigureAtlas,
|
||||||
model_cache: FigureModelCache,
|
model_cache: FigureModelCache,
|
||||||
theropod_model_cache: FigureModelCache<TheropodSkeleton>,
|
theropod_model_cache: FigureModelCache<TheropodSkeleton>,
|
||||||
quadruped_small_model_cache: FigureModelCache<QuadrupedSmallSkeleton>,
|
quadruped_small_model_cache: FigureModelCache<QuadrupedSmallSkeleton>,
|
||||||
@ -523,7 +529,7 @@ pub struct FigureMgr {
|
|||||||
impl FigureMgr {
|
impl FigureMgr {
|
||||||
pub fn new(renderer: &mut Renderer) -> Self {
|
pub fn new(renderer: &mut Renderer) -> Self {
|
||||||
Self {
|
Self {
|
||||||
col_lights: FigureColLights::new(renderer),
|
atlas: FigureAtlas::new(renderer),
|
||||||
model_cache: FigureModelCache::new(),
|
model_cache: FigureModelCache::new(),
|
||||||
theropod_model_cache: FigureModelCache::new(),
|
theropod_model_cache: FigureModelCache::new(),
|
||||||
quadruped_small_model_cache: FigureModelCache::new(),
|
quadruped_small_model_cache: FigureModelCache::new(),
|
||||||
@ -546,7 +552,7 @@ impl FigureMgr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn col_lights(&self) -> &FigureColLights { &self.col_lights }
|
pub fn atlas(&self) -> &FigureAtlas { &self.atlas }
|
||||||
|
|
||||||
fn any_watcher_reloaded(&mut self) -> bool {
|
fn any_watcher_reloaded(&mut self) -> bool {
|
||||||
self.model_cache.watcher_reloaded()
|
self.model_cache.watcher_reloaded()
|
||||||
@ -573,7 +579,7 @@ impl FigureMgr {
|
|||||||
span!(_guard, "clean", "FigureManager::clean");
|
span!(_guard, "clean", "FigureManager::clean");
|
||||||
|
|
||||||
if self.any_watcher_reloaded() {
|
if self.any_watcher_reloaded() {
|
||||||
self.col_lights.atlas.clear();
|
self.atlas.atlas.clear();
|
||||||
|
|
||||||
self.model_cache.clear_models();
|
self.model_cache.clear_models();
|
||||||
self.theropod_model_cache.clear_models();
|
self.theropod_model_cache.clear_models();
|
||||||
@ -595,33 +601,26 @@ impl FigureMgr {
|
|||||||
self.arthropod_model_cache.clear_models();
|
self.arthropod_model_cache.clear_models();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.model_cache.clean(&mut self.col_lights, tick);
|
self.model_cache.clean(&mut self.atlas, tick);
|
||||||
self.theropod_model_cache.clean(&mut self.col_lights, tick);
|
self.theropod_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.quadruped_small_model_cache
|
self.quadruped_small_model_cache
|
||||||
.clean(&mut self.col_lights, tick);
|
.clean(&mut self.atlas, tick);
|
||||||
self.quadruped_medium_model_cache
|
self.quadruped_medium_model_cache
|
||||||
.clean(&mut self.col_lights, tick);
|
.clean(&mut self.atlas, tick);
|
||||||
self.quadruped_low_model_cache
|
self.quadruped_low_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
self.bird_medium_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.bird_medium_model_cache
|
self.bird_large_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
self.dragon_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.bird_large_model_cache
|
self.fish_medium_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
self.fish_small_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.dragon_model_cache.clean(&mut self.col_lights, tick);
|
self.biped_large_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.fish_medium_model_cache
|
self.biped_small_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
self.object_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.fish_small_model_cache
|
self.item_drop_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
self.ship_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.biped_large_model_cache
|
self.golem_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
self.volume_model_cache.clean(&mut self.atlas, tick);
|
||||||
self.biped_small_model_cache
|
self.arthropod_model_cache.clean(&mut self.atlas, tick);
|
||||||
.clean(&mut self.col_lights, tick);
|
|
||||||
self.object_model_cache.clean(&mut self.col_lights, tick);
|
|
||||||
self.item_drop_model_cache.clean(&mut self.col_lights, tick);
|
|
||||||
self.ship_model_cache.clean(&mut self.col_lights, tick);
|
|
||||||
self.golem_model_cache.clean(&mut self.col_lights, tick);
|
|
||||||
self.volume_model_cache.clean(&mut self.col_lights, tick);
|
|
||||||
self.arthropod_model_cache.clean(&mut self.col_lights, tick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_lighting(&mut self, scene_data: &SceneData) {
|
pub fn update_lighting(&mut self, scene_data: &SceneData) {
|
||||||
@ -1092,7 +1091,7 @@ impl FigureMgr {
|
|||||||
Body::Humanoid(body) => {
|
Body::Humanoid(body) => {
|
||||||
let (model, skeleton_attr) = self.model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -2212,7 +2211,7 @@ impl FigureMgr {
|
|||||||
let (model, skeleton_attr) =
|
let (model, skeleton_attr) =
|
||||||
self.quadruped_small_model_cache.get_or_create_model(
|
self.quadruped_small_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -2412,7 +2411,7 @@ impl FigureMgr {
|
|||||||
let (model, skeleton_attr) =
|
let (model, skeleton_attr) =
|
||||||
self.quadruped_medium_model_cache.get_or_create_model(
|
self.quadruped_medium_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -2789,7 +2788,7 @@ impl FigureMgr {
|
|||||||
let (model, skeleton_attr) =
|
let (model, skeleton_attr) =
|
||||||
self.quadruped_low_model_cache.get_or_create_model(
|
self.quadruped_low_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -3185,7 +3184,7 @@ impl FigureMgr {
|
|||||||
Body::BirdMedium(body) => {
|
Body::BirdMedium(body) => {
|
||||||
let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -3515,7 +3514,7 @@ impl FigureMgr {
|
|||||||
Body::FishMedium(body) => {
|
Body::FishMedium(body) => {
|
||||||
let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -3598,7 +3597,7 @@ impl FigureMgr {
|
|||||||
Body::BipedSmall(body) => {
|
Body::BipedSmall(body) => {
|
||||||
let (model, skeleton_attr) = self.biped_small_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.biped_small_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -4159,7 +4158,7 @@ impl FigureMgr {
|
|||||||
Body::Dragon(body) => {
|
Body::Dragon(body) => {
|
||||||
let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -4246,7 +4245,7 @@ impl FigureMgr {
|
|||||||
Body::Theropod(body) => {
|
Body::Theropod(body) => {
|
||||||
let (model, skeleton_attr) = self.theropod_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.theropod_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -4425,7 +4424,7 @@ impl FigureMgr {
|
|||||||
Body::Arthropod(body) => {
|
Body::Arthropod(body) => {
|
||||||
let (model, skeleton_attr) = self.arthropod_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.arthropod_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -4717,7 +4716,7 @@ impl FigureMgr {
|
|||||||
Body::BirdLarge(body) => {
|
Body::BirdLarge(body) => {
|
||||||
let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -5040,7 +5039,7 @@ impl FigureMgr {
|
|||||||
Body::FishSmall(body) => {
|
Body::FishSmall(body) => {
|
||||||
let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -5123,7 +5122,7 @@ impl FigureMgr {
|
|||||||
Body::BipedLarge(body) => {
|
Body::BipedLarge(body) => {
|
||||||
let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -5828,7 +5827,7 @@ impl FigureMgr {
|
|||||||
Body::Golem(body) => {
|
Body::Golem(body) => {
|
||||||
let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -6069,7 +6068,7 @@ impl FigureMgr {
|
|||||||
Body::Object(body) => {
|
Body::Object(body) => {
|
||||||
let (model, skeleton_attr) = self.object_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.object_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -6191,7 +6190,7 @@ impl FigureMgr {
|
|||||||
let item_key = item.map(ItemKey::from);
|
let item_key = item.map(ItemKey::from);
|
||||||
let (model, skeleton_attr) = self.item_drop_model_cache.get_or_create_model(
|
let (model, skeleton_attr) = self.item_drop_model_cache.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -6255,7 +6254,7 @@ impl FigureMgr {
|
|||||||
let (model, _skeleton_attr) =
|
let (model, _skeleton_attr) =
|
||||||
self.volume_model_cache.get_or_create_terrain_model(
|
self.volume_model_cache.get_or_create_terrain_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
vk,
|
vk,
|
||||||
Arc::clone(vol),
|
Arc::clone(vol),
|
||||||
tick,
|
tick,
|
||||||
@ -6282,7 +6281,7 @@ impl FigureMgr {
|
|||||||
} else if body.manifest_entry().is_some() {
|
} else if body.manifest_entry().is_some() {
|
||||||
self.ship_model_cache.get_or_create_terrain_model(
|
self.ship_model_cache.get_or_create_terrain_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.atlas,
|
||||||
body,
|
body,
|
||||||
(),
|
(),
|
||||||
tick,
|
tick,
|
||||||
@ -6560,7 +6559,7 @@ impl FigureMgr {
|
|||||||
// Don't render player
|
// Don't render player
|
||||||
.filter(|(entity, _, _, _, _, _, _)| *entity != viewpoint_entity)
|
.filter(|(entity, _, _, _, _, _, _)| *entity != viewpoint_entity)
|
||||||
{
|
{
|
||||||
if let Some((bound, model, col_lights)) = self.get_model_for_render(
|
if let Some((bound, model, atlas)) = self.get_model_for_render(
|
||||||
tick,
|
tick,
|
||||||
camera,
|
camera,
|
||||||
character_state,
|
character_state,
|
||||||
@ -6582,7 +6581,7 @@ impl FigureMgr {
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
drawer.draw(model, bound, col_lights);
|
drawer.draw(model, bound, atlas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6616,7 +6615,7 @@ impl FigureMgr {
|
|||||||
let inventory_storage = ecs.read_storage::<Inventory>();
|
let inventory_storage = ecs.read_storage::<Inventory>();
|
||||||
let inventory = inventory_storage.get(viewpoint_entity);
|
let inventory = inventory_storage.get(viewpoint_entity);
|
||||||
|
|
||||||
if let Some((bound, model, col_lights)) = self.get_model_for_render(
|
if let Some((bound, model, atlas)) = self.get_model_for_render(
|
||||||
tick,
|
tick,
|
||||||
camera,
|
camera,
|
||||||
character_state,
|
character_state,
|
||||||
@ -6635,10 +6634,10 @@ impl FigureMgr {
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
drawer.draw(model, bound, col_lights);
|
drawer.draw(model, bound, atlas);
|
||||||
/*renderer.render_player_shadow(
|
/*renderer.render_player_shadow(
|
||||||
model,
|
model,
|
||||||
&col_lights,
|
&atlas,
|
||||||
global,
|
global,
|
||||||
bone_consts,
|
bone_consts,
|
||||||
lod,
|
lod,
|
||||||
@ -6677,7 +6676,7 @@ impl FigureMgr {
|
|||||||
let character_state = if is_viewpoint { character_state } else { None };
|
let character_state = if is_viewpoint { character_state } else { None };
|
||||||
|
|
||||||
let FigureMgr {
|
let FigureMgr {
|
||||||
col_lights: ref col_lights_,
|
atlas: ref atlas_,
|
||||||
model_cache,
|
model_cache,
|
||||||
theropod_model_cache,
|
theropod_model_cache,
|
||||||
quadruped_small_model_cache,
|
quadruped_small_model_cache,
|
||||||
@ -6718,7 +6717,7 @@ impl FigureMgr {
|
|||||||
arthropod_states,
|
arthropod_states,
|
||||||
},
|
},
|
||||||
} = self;
|
} = self;
|
||||||
let col_lights = col_lights_;
|
let atlas = atlas_;
|
||||||
if let Some((bound, model_entry)) = match body {
|
if let Some((bound, model_entry)) = match body {
|
||||||
Body::Humanoid(body) => character_states
|
Body::Humanoid(body) => character_states
|
||||||
.get(&entity)
|
.get(&entity)
|
||||||
@ -6728,7 +6727,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
model_cache
|
model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6747,7 +6746,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
quadruped_small_model_cache
|
quadruped_small_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6766,7 +6765,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
quadruped_medium_model_cache
|
quadruped_medium_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6785,7 +6784,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
quadruped_low_model_cache
|
quadruped_low_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6804,7 +6803,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
bird_medium_model_cache
|
bird_medium_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6823,7 +6822,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
fish_medium_model_cache
|
fish_medium_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6842,7 +6841,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
theropod_model_cache
|
theropod_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6861,7 +6860,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
dragon_model_cache
|
dragon_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6880,7 +6879,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
bird_large_model_cache
|
bird_large_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6899,7 +6898,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
fish_small_model_cache
|
fish_small_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6918,7 +6917,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
biped_large_model_cache
|
biped_large_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6937,7 +6936,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
biped_small_model_cache
|
biped_small_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6956,7 +6955,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
golem_model_cache
|
golem_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6975,7 +6974,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
arthropod_model_cache
|
arthropod_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -6994,7 +6993,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
object_model_cache
|
object_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -7013,7 +7012,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
item_drop_model_cache
|
item_drop_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -7034,7 +7033,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
volume_model_cache
|
volume_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
VolumeKey { entity, mut_count },
|
VolumeKey { entity, mut_count },
|
||||||
None,
|
None,
|
||||||
tick,
|
tick,
|
||||||
@ -7054,7 +7053,7 @@ impl FigureMgr {
|
|||||||
state.bound(),
|
state.bound(),
|
||||||
ship_model_cache
|
ship_model_cache
|
||||||
.get_model(
|
.get_model(
|
||||||
col_lights,
|
atlas,
|
||||||
body,
|
body,
|
||||||
None,
|
None,
|
||||||
tick,
|
tick,
|
||||||
@ -7097,7 +7096,7 @@ impl FigureMgr {
|
|||||||
model_entry.lod_model(0)
|
model_entry.lod_model(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((bound, model?, col_lights_.texture(model_entry)))
|
Some((bound, model?, atlas_.texture(model_entry)))
|
||||||
} else {
|
} else {
|
||||||
// trace!("Body has no saved figure");
|
// trace!("Body has no saved figure");
|
||||||
None
|
None
|
||||||
@ -7252,16 +7251,16 @@ impl FigureMgr {
|
|||||||
pub fn figure_count_visible(&self) -> usize { self.states.count_visible() }
|
pub fn figure_count_visible(&self) -> usize { self.states.count_visible() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FigureColLights {
|
pub struct FigureAtlas {
|
||||||
atlas: AtlasAllocator,
|
atlas: AtlasAllocator,
|
||||||
// col_lights: Texture<ColLightFmt>,
|
// atlas_texture: Texture<ColLightFmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FigureColLights {
|
impl FigureAtlas {
|
||||||
pub fn new(renderer: &mut Renderer) -> Self {
|
pub fn new(renderer: &mut Renderer) -> Self {
|
||||||
let atlas = Self::make_atlas(renderer).expect("Failed to create texture atlas for figures");
|
let atlas = Self::make_atlas(renderer).expect("Failed to create texture atlas for figures");
|
||||||
Self {
|
Self {
|
||||||
atlas, /* col_lights, */
|
atlas, /* atlas_texture, */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7269,9 +7268,9 @@ impl FigureColLights {
|
|||||||
pub fn texture<'a, const N: usize>(
|
pub fn texture<'a, const N: usize>(
|
||||||
&'a self,
|
&'a self,
|
||||||
model: ModelEntryRef<'a, N>,
|
model: ModelEntryRef<'a, N>,
|
||||||
) -> &'a ColLights<pipelines::figure::Locals> {
|
) -> &'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
|
||||||
/* &self.col_lights */
|
/* &self.atlas_texture */
|
||||||
model.col_lights()
|
model.atlas_textures()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: Panics if the opaque model's length does not fit in a u32.
|
/// NOTE: Panics if the opaque model's length does not fit in a u32.
|
||||||
@ -7285,17 +7284,21 @@ impl FigureColLights {
|
|||||||
pub fn create_figure<const N: usize>(
|
pub fn create_figure<const N: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
(tex, tex_size): ColLightInfo,
|
atlas_texture_data: FigureSpriteAtlasData,
|
||||||
|
atlas_size: Vec2<u16>,
|
||||||
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
|
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
|
||||||
vertex_ranges: [Range<u32>; N],
|
vertex_ranges: [Range<u32>; N],
|
||||||
) -> FigureModelEntry<N> {
|
) -> FigureModelEntry<N> {
|
||||||
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(tex_size.x as i32, tex_size.y as i32))
|
.allocate(guillotiere::Size::new(
|
||||||
|
atlas_size.x as i32,
|
||||||
|
atlas_size.y as i32,
|
||||||
|
))
|
||||||
.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 [atlas_textures] = atlas_texture_data.create_textures(renderer, atlas_size);
|
||||||
let col_lights = renderer.figure_bind_col_light(col_lights);
|
let atlas_textures = renderer.figure_bind_atlas_textures(atlas_textures);
|
||||||
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);
|
||||||
@ -7313,7 +7316,7 @@ impl FigureColLights {
|
|||||||
FigureModelEntry {
|
FigureModelEntry {
|
||||||
_bounds: bounds,
|
_bounds: bounds,
|
||||||
allocation,
|
allocation,
|
||||||
col_lights,
|
atlas_textures,
|
||||||
lod_vertex_ranges: vertex_ranges,
|
lod_vertex_ranges: vertex_ranges,
|
||||||
model: FigureModel { opaque: model },
|
model: FigureModel { opaque: model },
|
||||||
}
|
}
|
||||||
@ -7330,7 +7333,9 @@ impl FigureColLights {
|
|||||||
pub fn create_terrain<const N: usize>(
|
pub fn create_terrain<const N: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
(tex, tex_size): ColLightInfo,
|
// TODO: Use `TerrainAtlasData`
|
||||||
|
atlas_texture_data: FigureSpriteAtlasData,
|
||||||
|
atlas_size: Vec2<u16>,
|
||||||
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
|
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
|
||||||
vertex_ranges: [Range<u32>; N],
|
vertex_ranges: [Range<u32>; N],
|
||||||
sprite_instances: [Vec<SpriteInstance>; SPRITE_LOD_LEVELS],
|
sprite_instances: [Vec<SpriteInstance>; SPRITE_LOD_LEVELS],
|
||||||
@ -7340,10 +7345,14 @@ 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(tex_size.x as i32, tex_size.y as i32))
|
.allocate(guillotiere::Size::new(
|
||||||
|
atlas_size.x as i32,
|
||||||
|
atlas_size.y as i32,
|
||||||
|
))
|
||||||
.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] = atlas_texture_data.create_textures(renderer, atlas_size);
|
||||||
let col_lights = renderer.figure_bind_col_light(col_lights);
|
// TODO: Use `kinds` texture for volume entities
|
||||||
|
let atlas_textures = renderer.figure_bind_atlas_textures(col_lights);
|
||||||
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);
|
||||||
@ -7364,7 +7373,7 @@ impl FigureColLights {
|
|||||||
TerrainModelEntry {
|
TerrainModelEntry {
|
||||||
_bounds: bounds,
|
_bounds: bounds,
|
||||||
allocation,
|
allocation,
|
||||||
col_lights,
|
atlas_textures,
|
||||||
lod_vertex_ranges: vertex_ranges,
|
lod_vertex_ranges: vertex_ranges,
|
||||||
model: FigureModel { opaque: model },
|
model: FigureModel { opaque: model },
|
||||||
sprite_instances,
|
sprite_instances,
|
||||||
|
@ -1403,7 +1403,7 @@ impl Scene {
|
|||||||
// Draws sprites
|
// Draws sprites
|
||||||
let mut sprite_drawer = first_pass.draw_sprites(
|
let mut sprite_drawer = first_pass.draw_sprites(
|
||||||
&self.terrain.sprite_globals,
|
&self.terrain.sprite_globals,
|
||||||
&self.terrain.sprite_col_lights,
|
&self.terrain.sprite_atlas_textures,
|
||||||
);
|
);
|
||||||
self.figure_mgr.render_sprites(
|
self.figure_mgr.render_sprites(
|
||||||
&mut sprite_drawer,
|
&mut sprite_drawer,
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_figure},
|
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_figure},
|
||||||
render::{
|
render::{
|
||||||
create_skybox_mesh, BoneMeshes, Consts, FigureModel, FirstPassDrawer, GlobalModel, Globals,
|
create_skybox_mesh, pipelines::FigureSpriteAtlasData, BoneMeshes, Consts, FigureModel,
|
||||||
GlobalsBindGroup, Light, LodData, Mesh, Model, PointLightMatrix, RainOcclusionLocals,
|
FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Mesh, Model,
|
||||||
Renderer, Shadow, ShadowLocals, SkyboxVertex, TerrainVertex,
|
PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex,
|
||||||
|
TerrainVertex,
|
||||||
},
|
},
|
||||||
scene::{
|
scene::{
|
||||||
camera::{self, Camera, CameraMode},
|
camera::{self, Camera, CameraMode},
|
||||||
figure::{
|
figure::{
|
||||||
load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState,
|
load_mesh, FigureAtlas, FigureModelCache, FigureModelEntry, FigureState,
|
||||||
FigureUpdateCommonParameters,
|
FigureUpdateCommonParameters,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -46,7 +47,7 @@ impl ReadVol for VoidVol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_mesh(
|
fn generate_mesh(
|
||||||
greedy: &mut GreedyMesh<'_>,
|
greedy: &mut GreedyMesh<'_, FigureSpriteAtlasData>,
|
||||||
mesh: &mut Mesh<TerrainVertex>,
|
mesh: &mut Mesh<TerrainVertex>,
|
||||||
segment: Segment,
|
segment: Segment,
|
||||||
offset: Vec3<f32>,
|
offset: Vec3<f32>,
|
||||||
@ -70,7 +71,7 @@ pub struct Scene {
|
|||||||
lod: LodData,
|
lod: LodData,
|
||||||
map_bounds: Vec2<f32>,
|
map_bounds: Vec2<f32>,
|
||||||
|
|
||||||
col_lights: FigureColLights,
|
figure_atlas: FigureAtlas,
|
||||||
backdrop: Option<(FigureModelEntry<1>, FigureState<FixtureSkeleton>)>,
|
backdrop: Option<(FigureModelEntry<1>, FigureState<FixtureSkeleton>)>,
|
||||||
figure_model_cache: FigureModelCache,
|
figure_model_cache: FigureModelCache,
|
||||||
figure_state: Option<FigureState<CharacterSkeleton>>,
|
figure_state: Option<FigureState<CharacterSkeleton>>,
|
||||||
@ -108,7 +109,7 @@ impl Scene {
|
|||||||
camera.set_distance(3.4);
|
camera.set_distance(3.4);
|
||||||
camera.set_orientation(Vec3::new(start_angle, 0.0, 0.0));
|
camera.set_orientation(Vec3::new(start_angle, 0.0, 0.0));
|
||||||
|
|
||||||
let mut col_lights = FigureColLights::new(renderer);
|
let mut figure_atlas = FigureAtlas::new(renderer);
|
||||||
|
|
||||||
let data = GlobalModel {
|
let data = GlobalModel {
|
||||||
globals: renderer.create_consts(&[Globals::default()]),
|
globals: renderer.create_consts(&[Globals::default()]),
|
||||||
@ -147,9 +148,14 @@ impl Scene {
|
|||||||
// total size is bounded by 2^24 * 3 * 1.5 which is bounded by
|
// total size is bounded by 2^24 * 3 * 1.5 which is bounded by
|
||||||
// 2^27, which fits in a u32.
|
// 2^27, which fits in a u32.
|
||||||
let range = 0..opaque_mesh.vertices().len() as u32;
|
let range = 0..opaque_mesh.vertices().len() as u32;
|
||||||
let model =
|
let (atlas_texture_data, atlas_size) = greedy.finalize();
|
||||||
col_lights
|
let model = figure_atlas.create_figure(
|
||||||
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]);
|
renderer,
|
||||||
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
|
(opaque_mesh, bounds),
|
||||||
|
[range],
|
||||||
|
);
|
||||||
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
|
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
|
||||||
let common_params = FigureUpdateCommonParameters {
|
let common_params = FigureUpdateCommonParameters {
|
||||||
entity: None,
|
entity: None,
|
||||||
@ -182,7 +188,7 @@ impl Scene {
|
|||||||
);
|
);
|
||||||
(model, state)
|
(model, state)
|
||||||
}),
|
}),
|
||||||
col_lights,
|
figure_atlas,
|
||||||
|
|
||||||
camera,
|
camera,
|
||||||
|
|
||||||
@ -283,7 +289,7 @@ impl Scene {
|
|||||||
)]);
|
)]);
|
||||||
|
|
||||||
self.figure_model_cache
|
self.figure_model_cache
|
||||||
.clean(&mut self.col_lights, scene_data.tick);
|
.clean(&mut self.figure_atlas, scene_data.tick);
|
||||||
|
|
||||||
let item_info = |equip_slot| {
|
let item_info = |equip_slot| {
|
||||||
inventory
|
inventory
|
||||||
@ -327,7 +333,7 @@ impl Scene {
|
|||||||
.figure_model_cache
|
.figure_model_cache
|
||||||
.get_or_create_model(
|
.get_or_create_model(
|
||||||
renderer,
|
renderer,
|
||||||
&mut self.col_lights,
|
&mut self.figure_atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
(),
|
(),
|
||||||
@ -376,7 +382,7 @@ impl Scene {
|
|||||||
let mut figure_drawer = drawer.draw_figures();
|
let mut figure_drawer = drawer.draw_figures();
|
||||||
if let Some(body) = body {
|
if let Some(body) = body {
|
||||||
let model = &self.figure_model_cache.get_model(
|
let model = &self.figure_model_cache.get_model(
|
||||||
&self.col_lights,
|
&self.figure_atlas,
|
||||||
body,
|
body,
|
||||||
inventory,
|
inventory,
|
||||||
tick,
|
tick,
|
||||||
@ -390,7 +396,7 @@ impl Scene {
|
|||||||
figure_drawer.draw(
|
figure_drawer.draw(
|
||||||
lod,
|
lod,
|
||||||
figure_state.bound(),
|
figure_state.bound(),
|
||||||
self.col_lights.texture(ModelEntryRef::Figure(model)),
|
self.figure_atlas.texture(ModelEntryRef::Figure(model)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,7 +407,7 @@ impl Scene {
|
|||||||
figure_drawer.draw(
|
figure_drawer.draw(
|
||||||
lod,
|
lod,
|
||||||
state.bound(),
|
state.bound(),
|
||||||
self.col_lights.texture(ModelEntryRef::Figure(model)),
|
self.figure_atlas.texture(ModelEntryRef::Figure(model)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ use crate::{
|
|||||||
terrain::{generate_mesh, SUNLIGHT, SUNLIGHT_INV},
|
terrain::{generate_mesh, SUNLIGHT, SUNLIGHT_INV},
|
||||||
},
|
},
|
||||||
render::{
|
render::{
|
||||||
pipelines::{self, ColLights},
|
pipelines::{self, AtlasData, AtlasTextures},
|
||||||
AltIndices, ColLightInfo, CullingMode, FirstPassDrawer, FluidVertex, GlobalModel,
|
AltIndices, CullingMode, FigureSpriteAtlasData, FirstPassDrawer, FluidVertex, GlobalModel,
|
||||||
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteDrawer,
|
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteDrawer,
|
||||||
SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts, TerrainLocals,
|
SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts, TerrainAtlasData,
|
||||||
TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
|
TerrainLocals, TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,14 +80,14 @@ pub struct TerrainChunkData {
|
|||||||
fluid_model: Option<Model<FluidVertex>>,
|
fluid_model: Option<Model<FluidVertex>>,
|
||||||
/// If this is `None`, this texture is not allocated in the current atlas,
|
/// If this is `None`, this texture is not allocated in the current atlas,
|
||||||
/// and therefore there is no need to free its allocation.
|
/// and therefore there is no need to free its allocation.
|
||||||
col_lights_alloc: Option<guillotiere::AllocId>,
|
atlas_alloc: Option<guillotiere::AllocId>,
|
||||||
/// The actual backing texture for this chunk. Use this for rendering
|
/// The actual backing texture for this chunk. Use this for rendering
|
||||||
/// purposes. The texture is reference-counted, so it will be
|
/// purposes. The texture is reference-counted, so it will be
|
||||||
/// automatically freed when no chunks are left that need it (though
|
/// automatically freed when no chunks are left that need it (though
|
||||||
/// shadow chunks will still keep it alive; we could deal with this by
|
/// shadow chunks will still keep it alive; we could deal with this by
|
||||||
/// making this an `Option`, but it probably isn't worth it since they
|
/// making this an `Option`, but it probably isn't worth it since they
|
||||||
/// shouldn't be that much more nonlocal than regular chunks).
|
/// shouldn't be that much more nonlocal than regular chunks).
|
||||||
col_lights: Arc<ColLights<pipelines::terrain::Locals>>,
|
atlas_textures: Arc<AtlasTextures<pipelines::terrain::Locals, TerrainAtlasData>>,
|
||||||
light_map: LightMapFn,
|
light_map: LightMapFn,
|
||||||
glow_map: LightMapFn,
|
glow_map: LightMapFn,
|
||||||
sprite_instances: [(Instances<SpriteInstance>, AltIndices); SPRITE_LOD_LEVELS],
|
sprite_instances: [(Instances<SpriteInstance>, AltIndices); SPRITE_LOD_LEVELS],
|
||||||
@ -133,7 +133,8 @@ pub struct MeshWorkerResponseMesh {
|
|||||||
sun_occluder_z_bounds: (f32, f32),
|
sun_occluder_z_bounds: (f32, f32),
|
||||||
opaque_mesh: Mesh<TerrainVertex>,
|
opaque_mesh: Mesh<TerrainVertex>,
|
||||||
fluid_mesh: Mesh<FluidVertex>,
|
fluid_mesh: Mesh<FluidVertex>,
|
||||||
col_lights_info: ColLightInfo,
|
atlas_texture_data: TerrainAtlasData,
|
||||||
|
atlas_size: Vec2<u16>,
|
||||||
light_map: LightMapFn,
|
light_map: LightMapFn,
|
||||||
glow_map: LightMapFn,
|
glow_map: LightMapFn,
|
||||||
alt_indices: AltIndices,
|
alt_indices: AltIndices,
|
||||||
@ -343,7 +344,15 @@ fn mesh_worker(
|
|||||||
opaque_mesh,
|
opaque_mesh,
|
||||||
fluid_mesh,
|
fluid_mesh,
|
||||||
_shadow_mesh,
|
_shadow_mesh,
|
||||||
(bounds, col_lights_info, light_map, glow_map, alt_indices, sun_occluder_z_bounds),
|
(
|
||||||
|
bounds,
|
||||||
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
|
light_map,
|
||||||
|
glow_map,
|
||||||
|
alt_indices,
|
||||||
|
sun_occluder_z_bounds,
|
||||||
|
),
|
||||||
) = generate_mesh(
|
) = generate_mesh(
|
||||||
&volume,
|
&volume,
|
||||||
(
|
(
|
||||||
@ -358,7 +367,8 @@ fn mesh_worker(
|
|||||||
sun_occluder_z_bounds,
|
sun_occluder_z_bounds,
|
||||||
opaque_mesh,
|
opaque_mesh,
|
||||||
fluid_mesh,
|
fluid_mesh,
|
||||||
col_lights_info,
|
atlas_texture_data,
|
||||||
|
atlas_size,
|
||||||
light_map,
|
light_map,
|
||||||
glow_map,
|
glow_map,
|
||||||
alt_indices,
|
alt_indices,
|
||||||
@ -496,12 +506,12 @@ pub struct Terrain<V: RectRasterableVol = TerrainChunk> {
|
|||||||
// Maps sprite kind + variant to data detailing how to render it
|
// Maps sprite kind + variant to data detailing how to render it
|
||||||
pub sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
pub sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
||||||
pub sprite_globals: SpriteGlobalsBindGroup,
|
pub sprite_globals: SpriteGlobalsBindGroup,
|
||||||
pub sprite_col_lights: Arc<ColLights<pipelines::sprite::Locals>>,
|
pub sprite_atlas_textures: Arc<AtlasTextures<pipelines::sprite::Locals, FigureSpriteAtlasData>>,
|
||||||
/// As stated previously, this is always the very latest texture into which
|
/// As stated previously, this is always the very latest texture into which
|
||||||
/// we allocate. Code cannot assume that this is the assigned texture
|
/// we allocate. Code cannot assume that this is the assigned texture
|
||||||
/// for any particular chunk; look at the `texture` field in
|
/// for any particular chunk; look at the `texture` field in
|
||||||
/// `TerrainChunkData` for that.
|
/// `TerrainChunkData` for that.
|
||||||
col_lights: Arc<ColLights<pipelines::terrain::Locals>>,
|
atlas_textures: Arc<AtlasTextures<pipelines::terrain::Locals, TerrainAtlasData>>,
|
||||||
|
|
||||||
phantom: PhantomData<V>,
|
phantom: PhantomData<V>,
|
||||||
}
|
}
|
||||||
@ -515,7 +525,7 @@ pub struct SpriteRenderContext {
|
|||||||
sprite_config: Arc<SpriteSpec>,
|
sprite_config: Arc<SpriteSpec>,
|
||||||
// Maps sprite kind + variant to data detailing how to render it
|
// Maps sprite kind + variant to data detailing how to render it
|
||||||
sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
||||||
sprite_col_lights: Arc<ColLights<pipelines::sprite::Locals>>,
|
sprite_atlas_textures: Arc<AtlasTextures<pipelines::sprite::Locals, FigureSpriteAtlasData>>,
|
||||||
sprite_verts_buffer: Arc<SpriteVerts>,
|
sprite_verts_buffer: Arc<SpriteVerts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +538,8 @@ impl SpriteRenderContext {
|
|||||||
struct SpriteWorkerResponse {
|
struct SpriteWorkerResponse {
|
||||||
sprite_config: Arc<SpriteSpec>,
|
sprite_config: Arc<SpriteSpec>,
|
||||||
sprite_data: HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>,
|
sprite_data: HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>,
|
||||||
sprite_col_lights: ColLightInfo,
|
sprite_atlas_texture_data: FigureSpriteAtlasData,
|
||||||
|
sprite_atlas_size: Vec2<u16>,
|
||||||
sprite_mesh: Mesh<SpriteVertex>,
|
sprite_mesh: Mesh<SpriteVertex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,7 +550,7 @@ impl SpriteRenderContext {
|
|||||||
Arc::<SpriteSpec>::load_expect("voxygen.voxel.sprite_manifest").cloned();
|
Arc::<SpriteSpec>::load_expect("voxygen.voxel.sprite_manifest").cloned();
|
||||||
|
|
||||||
let max_size = Vec2::from(u16::try_from(max_texture_size).unwrap_or(u16::MAX));
|
let max_size = Vec2::from(u16::try_from(max_texture_size).unwrap_or(u16::MAX));
|
||||||
let mut greedy = GreedyMesh::<SpriteAtlasAllocator>::new(
|
let mut greedy = GreedyMesh::<FigureSpriteAtlasData, SpriteAtlasAllocator>::new(
|
||||||
max_size,
|
max_size,
|
||||||
crate::mesh::greedy::sprite_config(),
|
crate::mesh::greedy::sprite_config(),
|
||||||
);
|
);
|
||||||
@ -584,7 +595,10 @@ impl SpriteRenderContext {
|
|||||||
scale
|
scale
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
move |greedy: &mut GreedyMesh<SpriteAtlasAllocator>,
|
move |greedy: &mut GreedyMesh<
|
||||||
|
FigureSpriteAtlasData,
|
||||||
|
SpriteAtlasAllocator,
|
||||||
|
>,
|
||||||
sprite_mesh: &mut Mesh<SpriteVertex>| {
|
sprite_mesh: &mut Mesh<SpriteVertex>| {
|
||||||
prof_span!("mesh sprite");
|
prof_span!("mesh sprite");
|
||||||
let lod_sprite_data = scaled.map(|lod_scale_orig| {
|
let lod_sprite_data = scaled.map(|lod_scale_orig| {
|
||||||
@ -635,7 +649,7 @@ impl SpriteRenderContext {
|
|||||||
.map(|f| f(&mut greedy, &mut sprite_mesh))
|
.map(|f| f(&mut greedy, &mut sprite_mesh))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let sprite_col_lights = {
|
let (sprite_atlas_texture_data, sprite_atlas_size) = {
|
||||||
prof_span!("finalize");
|
prof_span!("finalize");
|
||||||
greedy.finalize()
|
greedy.finalize()
|
||||||
};
|
};
|
||||||
@ -643,7 +657,8 @@ impl SpriteRenderContext {
|
|||||||
SpriteWorkerResponse {
|
SpriteWorkerResponse {
|
||||||
sprite_config,
|
sprite_config,
|
||||||
sprite_data,
|
sprite_data,
|
||||||
sprite_col_lights,
|
sprite_atlas_texture_data,
|
||||||
|
sprite_atlas_size,
|
||||||
sprite_mesh,
|
sprite_mesh,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -658,7 +673,8 @@ impl SpriteRenderContext {
|
|||||||
let SpriteWorkerResponse {
|
let SpriteWorkerResponse {
|
||||||
sprite_config,
|
sprite_config,
|
||||||
sprite_data,
|
sprite_data,
|
||||||
sprite_col_lights,
|
sprite_atlas_texture_data,
|
||||||
|
sprite_atlas_size,
|
||||||
sprite_mesh,
|
sprite_mesh,
|
||||||
} = join_handle
|
} = join_handle
|
||||||
.take()
|
.take()
|
||||||
@ -669,9 +685,9 @@ impl SpriteRenderContext {
|
|||||||
.join()
|
.join()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let sprite_col_lights =
|
let [sprite_col_lights] =
|
||||||
pipelines::shadow::create_col_lights(renderer, &sprite_col_lights);
|
sprite_atlas_texture_data.create_textures(renderer, sprite_atlas_size);
|
||||||
let sprite_col_lights = renderer.sprite_bind_col_light(sprite_col_lights);
|
let sprite_atlas_textures = renderer.sprite_bind_atlas_textures(sprite_col_lights);
|
||||||
|
|
||||||
// Write sprite model to a 1D texture
|
// Write sprite model to a 1D texture
|
||||||
let sprite_verts_buffer = renderer.create_sprite_verts(sprite_mesh);
|
let sprite_verts_buffer = renderer.create_sprite_verts(sprite_mesh);
|
||||||
@ -680,7 +696,7 @@ impl SpriteRenderContext {
|
|||||||
// TODO: these are all Arcs, would it makes sense to factor out the Arc?
|
// TODO: these are all Arcs, would it makes sense to factor out the Arc?
|
||||||
sprite_config: Arc::clone(&sprite_config),
|
sprite_config: Arc::clone(&sprite_config),
|
||||||
sprite_data: Arc::new(sprite_data),
|
sprite_data: Arc::new(sprite_data),
|
||||||
sprite_col_lights: Arc::new(sprite_col_lights),
|
sprite_atlas_textures: Arc::new(sprite_atlas_textures),
|
||||||
sprite_verts_buffer: Arc::new(sprite_verts_buffer),
|
sprite_verts_buffer: Arc::new(sprite_verts_buffer),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -699,7 +715,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
// with worker threads that are meshing chunks.
|
// with worker threads that are meshing chunks.
|
||||||
let (send, recv) = channel::unbounded();
|
let (send, recv) = channel::unbounded();
|
||||||
|
|
||||||
let (atlas, col_lights) =
|
let (atlas, atlas_textures) =
|
||||||
Self::make_atlas(renderer).expect("Failed to create atlas texture");
|
Self::make_atlas(renderer).expect("Failed to create atlas texture");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -713,20 +729,26 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
mesh_todos_active: Arc::new(AtomicU64::new(0)),
|
mesh_todos_active: Arc::new(AtomicU64::new(0)),
|
||||||
mesh_recv_overflow: 0.0,
|
mesh_recv_overflow: 0.0,
|
||||||
sprite_data: sprite_render_context.sprite_data,
|
sprite_data: sprite_render_context.sprite_data,
|
||||||
sprite_col_lights: sprite_render_context.sprite_col_lights,
|
sprite_atlas_textures: sprite_render_context.sprite_atlas_textures,
|
||||||
sprite_globals: renderer.bind_sprite_globals(
|
sprite_globals: renderer.bind_sprite_globals(
|
||||||
global_model,
|
global_model,
|
||||||
lod_data,
|
lod_data,
|
||||||
&sprite_render_context.sprite_verts_buffer,
|
&sprite_render_context.sprite_verts_buffer,
|
||||||
),
|
),
|
||||||
col_lights: Arc::new(col_lights),
|
atlas_textures: Arc::new(atlas_textures),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_atlas(
|
fn make_atlas(
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
) -> Result<(AtlasAllocator, ColLights<pipelines::terrain::Locals>), RenderError> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
AtlasAllocator,
|
||||||
|
AtlasTextures<pipelines::terrain::Locals, TerrainAtlasData>,
|
||||||
|
),
|
||||||
|
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 = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
|
let atlas_size = guillotiere::Size::new(max_texture_size as i32, max_texture_size as i32);
|
||||||
@ -736,50 +758,56 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
large_size_threshold: 1024,
|
large_size_threshold: 1024,
|
||||||
..guillotiere::AllocatorOptions::default()
|
..guillotiere::AllocatorOptions::default()
|
||||||
});
|
});
|
||||||
let texture = renderer.create_texture_raw(
|
let [col_lights, kinds] = [
|
||||||
&wgpu::TextureDescriptor {
|
wgpu::TextureFormat::Rgba8Unorm,
|
||||||
label: Some("Atlas texture"),
|
wgpu::TextureFormat::R8Unorm,
|
||||||
size: wgpu::Extent3d {
|
]
|
||||||
width: max_texture_size,
|
.map(|fmt| {
|
||||||
height: max_texture_size,
|
renderer.create_texture_raw(
|
||||||
depth_or_array_layers: 1,
|
&wgpu::TextureDescriptor {
|
||||||
|
label: Some("Color & lights atlas texture"),
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: max_texture_size,
|
||||||
|
height: max_texture_size,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: fmt,
|
||||||
|
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
||||||
},
|
},
|
||||||
mip_level_count: 1,
|
&wgpu::TextureViewDescriptor {
|
||||||
sample_count: 1,
|
label: Some("Color & lights atlas texture view"),
|
||||||
dimension: wgpu::TextureDimension::D2,
|
format: Some(fmt),
|
||||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
aspect: wgpu::TextureAspect::All,
|
||||||
},
|
base_mip_level: 0,
|
||||||
&wgpu::TextureViewDescriptor {
|
mip_level_count: None,
|
||||||
label: Some("Atlas texture view"),
|
base_array_layer: 0,
|
||||||
format: Some(wgpu::TextureFormat::Rgba8Unorm),
|
array_layer_count: None,
|
||||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
},
|
||||||
aspect: wgpu::TextureAspect::All,
|
&wgpu::SamplerDescriptor {
|
||||||
base_mip_level: 0,
|
label: Some("Color & lights atlas texture sampler"),
|
||||||
mip_level_count: None,
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
base_array_layer: 0,
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
array_layer_count: None,
|
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||||
},
|
mag_filter: wgpu::FilterMode::Linear,
|
||||||
&wgpu::SamplerDescriptor {
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
label: Some("Atlas sampler"),
|
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
..Default::default()
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
},
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
)
|
||||||
mag_filter: wgpu::FilterMode::Linear,
|
});
|
||||||
min_filter: wgpu::FilterMode::Linear,
|
let textures = renderer.terrain_bind_atlas_textures(col_lights, kinds);
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
Ok((atlas, textures))
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let col_light = renderer.terrain_bind_col_light(texture);
|
|
||||||
Ok((atlas, col_light))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_chunk_meta(&mut self, _pos: Vec2<i32>, chunk: &TerrainChunkData) {
|
fn remove_chunk_meta(&mut self, _pos: Vec2<i32>, chunk: &TerrainChunkData) {
|
||||||
// No need to free the allocation if the chunk is not allocated in the current
|
// No need to free the allocation if the chunk is not allocated in the current
|
||||||
// atlas, since we don't bother tracking it at that point.
|
// atlas, since we don't bother tracking it at that point.
|
||||||
if let Some(col_lights) = chunk.col_lights_alloc {
|
if let Some(atlas_alloc) = chunk.atlas_alloc {
|
||||||
self.atlas.deallocate(col_lights);
|
self.atlas.deallocate(atlas_alloc);
|
||||||
}
|
}
|
||||||
/* let (zmin, zmax) = chunk.z_bounds;
|
/* let (zmin, zmax) = chunk.z_bounds;
|
||||||
self.z_index_up.remove(Vec3::from(zmin, pos.x, pos.y));
|
self.z_index_up.remove(Vec3::from(zmin, pos.x, pos.y));
|
||||||
@ -1250,16 +1278,17 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
.map(|chunk| chunk.load_time)
|
.map(|chunk| chunk.load_time)
|
||||||
.unwrap_or(current_time as f32);
|
.unwrap_or(current_time as f32);
|
||||||
// TODO: Allocate new atlas on allocation failure.
|
// TODO: Allocate new atlas on allocation failure.
|
||||||
let (tex, tex_size) = mesh.col_lights_info;
|
|
||||||
let atlas = &mut self.atlas;
|
let atlas = &mut self.atlas;
|
||||||
let chunks = &mut self.chunks;
|
let chunks = &mut self.chunks;
|
||||||
let col_lights = &mut self.col_lights;
|
let atlas_textures = &mut self.atlas_textures;
|
||||||
let alloc_size =
|
let alloc_size = guillotiere::Size::new(
|
||||||
guillotiere::Size::new(i32::from(tex_size.x), i32::from(tex_size.y));
|
i32::from(mesh.atlas_size.x),
|
||||||
|
i32::from(mesh.atlas_size.y),
|
||||||
|
);
|
||||||
|
|
||||||
let allocation = atlas.allocate(alloc_size).unwrap_or_else(|| {
|
let allocation = atlas.allocate(alloc_size).unwrap_or_else(|| {
|
||||||
// Atlas allocation failure: try allocating a new texture and atlas.
|
// Atlas allocation failure: try allocating a new texture and atlas.
|
||||||
let (new_atlas, new_col_lights) =
|
let (new_atlas, new_atlas_textures) =
|
||||||
Self::make_atlas(renderer).expect("Failed to create atlas texture");
|
Self::make_atlas(renderer).expect("Failed to create atlas texture");
|
||||||
|
|
||||||
// We reset the atlas and clear allocations from existing chunks,
|
// We reset the atlas and clear allocations from existing chunks,
|
||||||
@ -1271,10 +1300,10 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
// TODO: Consider attempting defragmentation first rather than just
|
// TODO: Consider attempting defragmentation first rather than just
|
||||||
// always moving everything into the new chunk.
|
// always moving everything into the new chunk.
|
||||||
chunks.iter_mut().for_each(|(_, chunk)| {
|
chunks.iter_mut().for_each(|(_, chunk)| {
|
||||||
chunk.col_lights_alloc = None;
|
chunk.atlas_alloc = None;
|
||||||
});
|
});
|
||||||
*atlas = new_atlas;
|
*atlas = new_atlas;
|
||||||
*col_lights = Arc::new(new_col_lights);
|
*atlas_textures = Arc::new(new_atlas_textures);
|
||||||
|
|
||||||
atlas
|
atlas
|
||||||
.allocate(alloc_size)
|
.allocate(alloc_size)
|
||||||
@ -1286,19 +1315,27 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
allocation.rectangle.min.x as u32,
|
allocation.rectangle.min.x as u32,
|
||||||
allocation.rectangle.min.y as u32,
|
allocation.rectangle.min.y as u32,
|
||||||
);
|
);
|
||||||
|
// Update col_lights texture
|
||||||
renderer.update_texture(
|
renderer.update_texture(
|
||||||
&col_lights.texture,
|
&atlas_textures.textures[0],
|
||||||
atlas_offs.into_array(),
|
atlas_offs.into_array(),
|
||||||
tex_size.map(u32::from).into_array(),
|
mesh.atlas_size.as_().into_array(),
|
||||||
&tex,
|
&mesh.atlas_texture_data.col_lights,
|
||||||
|
);
|
||||||
|
// Update kinds texture
|
||||||
|
renderer.update_texture(
|
||||||
|
&atlas_textures.textures[1],
|
||||||
|
atlas_offs.into_array(),
|
||||||
|
mesh.atlas_size.as_().into_array(),
|
||||||
|
&mesh.atlas_texture_data.kinds,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.insert_chunk(response.pos, TerrainChunkData {
|
self.insert_chunk(response.pos, TerrainChunkData {
|
||||||
load_time,
|
load_time,
|
||||||
opaque_model: renderer.create_model(&mesh.opaque_mesh),
|
opaque_model: renderer.create_model(&mesh.opaque_mesh),
|
||||||
fluid_model: renderer.create_model(&mesh.fluid_mesh),
|
fluid_model: renderer.create_model(&mesh.fluid_mesh),
|
||||||
col_lights_alloc: Some(allocation.id),
|
atlas_alloc: Some(allocation.id),
|
||||||
col_lights: Arc::clone(&self.col_lights),
|
atlas_textures: Arc::clone(&self.atlas_textures),
|
||||||
light_map: mesh.light_map,
|
light_map: mesh.light_map,
|
||||||
glow_map: mesh.glow_map,
|
glow_map: mesh.glow_map,
|
||||||
sprite_instances,
|
sprite_instances,
|
||||||
@ -1705,19 +1742,19 @@ impl<V: RectRasterableVol> Terrain<V> {
|
|||||||
Some((
|
Some((
|
||||||
rpos,
|
rpos,
|
||||||
chunk.opaque_model.as_ref()?,
|
chunk.opaque_model.as_ref()?,
|
||||||
&chunk.col_lights,
|
&chunk.atlas_textures,
|
||||||
&chunk.locals,
|
&chunk.locals,
|
||||||
&chunk.alt_indices,
|
&chunk.alt_indices,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.for_each(|(rpos, model, col_lights, locals, alt_indices)| {
|
.for_each(|(rpos, model, atlas_textures, locals, alt_indices)| {
|
||||||
// Always draw all of close chunks to avoid terrain 'popping'
|
// Always draw all of close chunks to avoid terrain 'popping'
|
||||||
let culling_mode = if rpos.magnitude_squared() < NEVER_CULL_DIST.pow(2) {
|
let culling_mode = if rpos.magnitude_squared() < NEVER_CULL_DIST.pow(2) {
|
||||||
CullingMode::None
|
CullingMode::None
|
||||||
} else {
|
} else {
|
||||||
culling_mode
|
culling_mode
|
||||||
};
|
};
|
||||||
drawer.draw(model, col_lights, locals, alt_indices, culling_mode)
|
drawer.draw(model, atlas_textures, locals, alt_indices, culling_mode)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user