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:
parent
3afeca67c5
commit
aeb72bcf22
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,10 @@ layout(set = 2, binding = 0)
|
||||
uniform texture2D t_col_light;
|
||||
layout(set = 2, binding = 1)
|
||||
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)
|
||||
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);
|
||||
// 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;
|
||||
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
|
||||
tgt_color = vec4(simple_lighting(f_pos.xyz, f_col, f_light), 1);
|
||||
|
@ -10,7 +10,8 @@
|
||||
option_get_or_insert_default,
|
||||
map_try_insert,
|
||||
slice_as_chunks,
|
||||
let_chains
|
||||
let_chains,
|
||||
generic_const_exprs
|
||||
)]
|
||||
#![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 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
|
||||
/// vector, the continuation will consume the color data and write it to the
|
||||
/// 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
|
||||
/// 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.
|
||||
///
|
||||
/// 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: Allocator,
|
||||
col_lights_size: Vec2<u16>,
|
||||
tex_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.
|
||||
///
|
||||
/// 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
|
||||
);
|
||||
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 {
|
||||
atlas,
|
||||
col_lights_size,
|
||||
tex_size,
|
||||
max_size,
|
||||
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,
|
||||
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),
|
||||
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");
|
||||
let cont = greedy_mesh(
|
||||
let cont = greedy_mesh::<_, _, _, _, _, _, _, _, _, A, _>(
|
||||
&mut self.atlas,
|
||||
&mut self.col_lights_size,
|
||||
&mut self.tex_size,
|
||||
self.max_size,
|
||||
config,
|
||||
);
|
||||
@ -401,24 +406,32 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
||||
/// potentially use a single staged upload to the GPU.
|
||||
///
|
||||
/// 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");
|
||||
let cur_size = self.col_lights_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);
|
||||
let mut atlas_texture_data = A::blank_with_size(self.tex_size);
|
||||
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 }
|
||||
}
|
||||
|
||||
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,
|
||||
col_lights_size: &mut 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,
|
||||
make_face_texel,
|
||||
}: GreedyConfig<D, FA, FL, FG, FO, FS, FP, FT>,
|
||||
) -> Box<SuspendedMesh<'a>>
|
||||
) -> Box<SuspendedMesh<'a, A>>
|
||||
where
|
||||
FA: 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,
|
||||
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),
|
||||
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");
|
||||
// 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;
|
||||
draw_col_lights(
|
||||
col_lights_info,
|
||||
draw_col_lights::<_, A>(
|
||||
atlas_texture_data,
|
||||
cur_size,
|
||||
&mut data,
|
||||
todo_rects,
|
||||
draw_delta,
|
||||
@ -727,8 +741,9 @@ fn add_to_atlas<Allocator: AtlasAllocator>(
|
||||
// to provide builtin support for what we're doing here.
|
||||
//
|
||||
// TODO: See if we can speed this up using SIMD.
|
||||
fn draw_col_lights<D>(
|
||||
(col_lights, cur_size): &mut ColLightInfo,
|
||||
fn draw_col_lights<D, A: AtlasData>(
|
||||
atlas_texture_data: &mut A,
|
||||
cur_size: Vec2<u16>,
|
||||
data: &mut D,
|
||||
todo_rects: Vec<TodoRect>,
|
||||
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_glow: impl FnMut(&mut D, Vec3<i32>) -> f32,
|
||||
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)| {
|
||||
// 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| {
|
||||
let start = cur_size.x as usize * usize::from(top + v) + usize::from(left);
|
||||
(0..width)
|
||||
.zip(&mut col_lights[start..start + usize::from(width)])
|
||||
.for_each(|(u, col_light)| {
|
||||
.zip(atlas_texture_data.slice_mut(start..start + usize::from(width)))
|
||||
.for_each(|(u, texel)| {
|
||||
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
|
||||
// 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 glow = (glowiness * 31.5) as u8;
|
||||
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,
|
||||
MeshGen,
|
||||
},
|
||||
render::{Mesh, ParticleVertex, SpriteVertex, TerrainVertex},
|
||||
render::{pipelines::FigureSpriteAtlasData, Mesh, ParticleVertex, SpriteVertex, TerrainVertex},
|
||||
scene::math,
|
||||
};
|
||||
use common::{
|
||||
@ -21,7 +21,7 @@ use vek::*;
|
||||
pub fn generate_mesh_base_vol_figure<'a: 'b, 'b, V: 'a>(
|
||||
vol: V,
|
||||
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
||||
&'b mut GreedyMesh<'a>,
|
||||
&'b mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
&'b mut Mesh<TerrainVertex>,
|
||||
Vec3<f32>,
|
||||
Vec3<f32>,
|
||||
@ -91,7 +91,7 @@ where
|
||||
|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 (glowy, shiny) = cell
|
||||
.map(|c| (c.is_glowy(), c.is_shiny()))
|
||||
@ -99,7 +99,7 @@ where
|
||||
let col = cell
|
||||
.and_then(|vox| vox.get_color())
|
||||
.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 {
|
||||
@ -118,7 +118,7 @@ where
|
||||
pub fn generate_mesh_base_vol_terrain<'a: 'b, 'b, V: 'a>(
|
||||
vol: V,
|
||||
(greedy, opaque_mesh, offs, scale, bone_idx): (
|
||||
&'b mut GreedyMesh<'a>,
|
||||
&'b mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
&'b mut Mesh<TerrainVertex>,
|
||||
Vec3<f32>,
|
||||
Vec3<f32>,
|
||||
@ -201,13 +201,13 @@ where
|
||||
},
|
||||
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 glowy = block.map(|c| c.get_glow().is_some()).unwrap_or_default();
|
||||
let col = block
|
||||
.and_then(|vox| vox.get_color())
|
||||
.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 {
|
||||
@ -223,7 +223,7 @@ where
|
||||
pub fn generate_mesh_base_vol_sprite<'a: 'b, 'b, V: 'a>(
|
||||
vol: V,
|
||||
(greedy, opaque_mesh, vertical_stripes): (
|
||||
&'b mut GreedyMesh<'a, greedy::SpriteAtlasAllocator>,
|
||||
&'b mut GreedyMesh<'a, FigureSpriteAtlasData, greedy::SpriteAtlasAllocator>,
|
||||
&'b mut Mesh<SpriteVertex>,
|
||||
bool,
|
||||
),
|
||||
@ -336,10 +336,11 @@ where
|
||||
|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 (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>(
|
||||
vol: V,
|
||||
greedy: &'b mut GreedyMesh<'a>,
|
||||
greedy: &'b mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
) -> MeshGen<ParticleVertex, ParticleVertex, TerrainVertex, ()>
|
||||
where
|
||||
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
||||
@ -421,8 +422,8 @@ where
|
||||
|atlas_pos, pos, norm, &_meta| create_opaque(atlas_pos, pos, norm),
|
||||
));
|
||||
},
|
||||
make_face_texel: move |vol: &mut V, pos, light, glow, ao| {
|
||||
TerrainVertex::make_col_light(light, glow, get_color(vol, pos), ao)
|
||||
make_face_texel: move |col_light: &mut [u8; 4], vol: &mut V, pos, light, glow, ao| {
|
||||
*col_light = TerrainVertex::make_col_light(light, glow, get_color(vol, pos), ao);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
greedy::{self, GreedyConfig, GreedyMesh},
|
||||
MeshGen,
|
||||
},
|
||||
render::{AltIndices, ColLightInfo, FluidVertex, Mesh, TerrainVertex, Vertex},
|
||||
render::{AltIndices, FluidVertex, Mesh, TerrainAtlasData, TerrainVertex, Vertex},
|
||||
scene::terrain::{BlocksOfInterest, DEEP_ALT, SHALLOW_ALT},
|
||||
};
|
||||
use common::{
|
||||
@ -235,7 +235,8 @@ pub fn generate_mesh<'a>(
|
||||
TerrainVertex,
|
||||
(
|
||||
Aabb<f32>,
|
||||
ColLightInfo,
|
||||
TerrainAtlasData,
|
||||
Vec2<u16>,
|
||||
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
||||
Arc<dyn Fn(Vec3<i32>) -> f32 + Send + Sync>,
|
||||
AltIndices,
|
||||
@ -390,6 +391,7 @@ pub fn generate_mesh<'a>(
|
||||
let get_glow = |_: &mut (), pos: Vec3<i32>| glow(pos + range.min);
|
||||
let get_color =
|
||||
|_: &mut (), pos: Vec3<i32>| flat_get(pos).get_color().unwrap_or_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 should_draw = |_: &mut (), pos: Vec3<i32>, delta: Vec3<i32>, _uv| {
|
||||
should_draw_greedy(pos, delta, &flat_get)
|
||||
@ -430,8 +432,10 @@ pub fn generate_mesh<'a>(
|
||||
FluidVertex::new(pos + mesh_delta, norm, vel.xy())
|
||||
};
|
||||
|
||||
let mut greedy =
|
||||
GreedyMesh::<guillotiere::SimpleAtlasAllocator>::new(max_size, greedy::general_config());
|
||||
let mut greedy = GreedyMesh::<TerrainAtlasData, guillotiere::SimpleAtlasAllocator>::new(
|
||||
max_size,
|
||||
greedy::general_config(),
|
||||
);
|
||||
let mut opaque_deep = Vec::new();
|
||||
let mut opaque_shallow = 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| {
|
||||
TerrainVertex::make_col_light(light, glow, get_color(data, pos), ao)
|
||||
make_face_texel: |(col_light, kind): (&mut [u8; 4], &mut u8),
|
||||
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,
|
||||
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()
|
||||
* if TerrainVertex::QUADS_INDEX.is_some() {
|
||||
@ -526,7 +536,8 @@ pub fn generate_mesh<'a>(
|
||||
Mesh::new(),
|
||||
(
|
||||
bounds,
|
||||
(col_lights, col_lights_size),
|
||||
atlas_data,
|
||||
atlas_size,
|
||||
Arc::new(light),
|
||||
Arc::new(glow),
|
||||
alt_indices,
|
||||
|
@ -46,7 +46,8 @@ pub use self::{
|
||||
TextureBindGroup as UiTextureBindGroup, UploadBatchId as UiUploadBatchId,
|
||||
Vertex as UiVertex,
|
||||
},
|
||||
GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light, Shadow,
|
||||
FigureSpriteAtlasData, GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light,
|
||||
Shadow, TerrainAtlasData,
|
||||
},
|
||||
renderer::{
|
||||
drawer::{
|
||||
@ -55,7 +56,7 @@ pub use self::{
|
||||
TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer,
|
||||
TransparentPassDrawer, UiDrawer, VolumetricPassDrawer, UI_PREMULTIPLY_PASS,
|
||||
},
|
||||
AltIndices, ColLightInfo, CullingMode, Renderer,
|
||||
AltIndices, CullingMode, Renderer,
|
||||
},
|
||||
texture::Texture,
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::{
|
||||
super::{AaMode, Bound, Consts, GlobalsLayouts, Mesh, Model},
|
||||
terrain::Vertex,
|
||||
AtlasData,
|
||||
};
|
||||
use crate::mesh::greedy::GreedyMesh;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
@ -87,7 +88,7 @@ pub struct FigureModel {
|
||||
|
||||
impl FigureModel {
|
||||
/// 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
|
||||
// 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
|
||||
@ -185,7 +186,7 @@ impl FigurePipeline {
|
||||
bind_group_layouts: &[
|
||||
&global_layout.globals,
|
||||
&global_layout.shadow_textures,
|
||||
&global_layout.col_light,
|
||||
global_layout.figure_sprite_atlas_layout.layout(),
|
||||
&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 ui;
|
||||
|
||||
use super::{Consts, Texture};
|
||||
use super::{Consts, Renderer, Texture};
|
||||
use crate::scene::camera::CameraMode;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use common::terrain::BlockKind;
|
||||
use std::marker::PhantomData;
|
||||
use vek::*;
|
||||
|
||||
pub use self::{figure::FigureSpriteAtlasData, terrain::TerrainAtlasData};
|
||||
|
||||
// TODO: auto insert these into shaders
|
||||
pub const MAX_POINT_LIGHT_COUNT: usize = 20;
|
||||
pub const MAX_FIGURE_SHADOW_COUNT: usize = 24;
|
||||
@ -278,16 +281,114 @@ pub struct ShadowTexturesBindGroup {
|
||||
|
||||
pub struct GlobalsLayouts {
|
||||
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 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 texture: Texture,
|
||||
pub textures: [Texture; S::TEXTURES],
|
||||
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 {
|
||||
pub fn base_globals_layout() -> Vec<wgpu::BindGroupLayoutEntry> {
|
||||
vec![
|
||||
@ -456,32 +557,6 @@ impl GlobalsLayouts {
|
||||
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 {
|
||||
label: None,
|
||||
entries: &[
|
||||
@ -550,8 +625,9 @@ impl GlobalsLayouts {
|
||||
|
||||
Self {
|
||||
globals,
|
||||
col_light,
|
||||
shadow_textures,
|
||||
terrain_atlas_layout: VoxelAtlasLayout::new(device),
|
||||
figure_sprite_atlas_layout: VoxelAtlasLayout::new(device),
|
||||
}
|
||||
}
|
||||
|
||||
@ -691,28 +767,35 @@ impl GlobalsLayouts {
|
||||
ShadowTexturesBindGroup { bind_group }
|
||||
}
|
||||
|
||||
pub fn bind_col_light<Locals>(
|
||||
pub fn bind_atlas_textures<Locals, S: AtlasData>(
|
||||
&self,
|
||||
device: &wgpu::Device,
|
||||
col_light: Texture,
|
||||
) -> ColLights<Locals> {
|
||||
layout: &VoxelAtlasLayout<S>,
|
||||
textures: [Texture; S::TEXTURES],
|
||||
) -> AtlasTextures<Locals, S> {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &self.col_light,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&col_light.view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&col_light.sampler),
|
||||
},
|
||||
],
|
||||
layout: layout.layout(),
|
||||
entries: &textures
|
||||
.iter()
|
||||
.enumerate()
|
||||
.flat_map(|(i, tex)| {
|
||||
[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: i as u32 * 2,
|
||||
resource: wgpu::BindingResource::TextureView(&tex.view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: i as u32 * 2 + 1,
|
||||
resource: wgpu::BindingResource::Sampler(&tex.sampler),
|
||||
},
|
||||
]
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
});
|
||||
|
||||
ColLights {
|
||||
texture: col_light,
|
||||
AtlasTextures {
|
||||
textures,
|
||||
bind_group,
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::super::{
|
||||
AaMode, Bound, ColLightInfo, Consts, DebugLayout, DebugVertex, FigureLayout, GlobalsLayouts,
|
||||
Renderer, TerrainLayout, TerrainVertex, Texture,
|
||||
AaMode, Bound, Consts, DebugLayout, DebugVertex, FigureLayout, GlobalsLayouts, TerrainLayout,
|
||||
TerrainVertex,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use vek::*;
|
||||
@ -79,55 +79,6 @@ impl Default for PointLightMatrix {
|
||||
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 pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
use super::{
|
||||
super::{
|
||||
buffer::Buffer, AaMode, GlobalsLayouts, Mesh, TerrainLayout, Texture, Vertex as VertexTrait,
|
||||
},
|
||||
lod_terrain, GlobalModel,
|
||||
super::{buffer::Buffer, AaMode, GlobalsLayouts, Mesh, TerrainLayout, Vertex as VertexTrait},
|
||||
lod_terrain, GlobalModel, Texture,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::mem;
|
||||
@ -278,7 +276,7 @@ impl SpritePipeline {
|
||||
&layout.globals,
|
||||
&global_layout.shadow_textures,
|
||||
// Note: mergable with globals
|
||||
&global_layout.col_light,
|
||||
global_layout.figure_sprite_atlas_layout.layout(),
|
||||
&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 std::mem;
|
||||
use vek::*;
|
||||
@ -237,7 +240,7 @@ impl TerrainPipeline {
|
||||
bind_group_layouts: &[
|
||||
&global_layout.globals,
|
||||
&global_layout.shadow_textures,
|
||||
&global_layout.col_light,
|
||||
global_layout.terrain_atlas_layout.layout(),
|
||||
&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 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_U32_START_VERT_LEN: u32 = 3000;
|
||||
|
||||
@ -1427,13 +1421,12 @@ impl Renderer {
|
||||
/// Update a texture with the provided offset, size, and data.
|
||||
///
|
||||
/// Currently only supports Rgba8Srgb
|
||||
pub fn update_texture(
|
||||
pub fn update_texture<T: bytemuck::Pod>(
|
||||
&mut self,
|
||||
texture: &Texture, /* <T> */
|
||||
texture: &Texture,
|
||||
offset: [u32; 2],
|
||||
size: [u32; 2],
|
||||
// TODO: be generic over pixel type
|
||||
data: &[[u8; 4]],
|
||||
data: &[T],
|
||||
) {
|
||||
texture.update(&self.queue, offset, size, bytemuck::cast_slice(data))
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ use crate::render::pipelines::rain_occlusion;
|
||||
use super::{
|
||||
super::{
|
||||
pipelines::{
|
||||
debug, figure, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel,
|
||||
GlobalsBindGroup,
|
||||
debug, figure, lod_terrain, shadow, sprite, terrain, ui, AtlasTextures,
|
||||
FigureSpriteAtlasData, GlobalModel, GlobalsBindGroup, TerrainAtlasData,
|
||||
},
|
||||
texture::Texture,
|
||||
},
|
||||
@ -90,15 +90,37 @@ impl Renderer {
|
||||
.bind_locals(&self.device, locals)
|
||||
}
|
||||
|
||||
pub fn figure_bind_col_light(&self, col_light: Texture) -> ColLights<figure::Locals> {
|
||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
||||
pub fn figure_bind_atlas_textures(
|
||||
&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> {
|
||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
||||
pub fn terrain_bind_atlas_textures(
|
||||
&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> {
|
||||
self.layouts.global.bind_col_light(&self.device, col_light)
|
||||
pub fn sprite_bind_atlas_textures(
|
||||
&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},
|
||||
pipelines::{
|
||||
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,
|
||||
},
|
||||
@ -950,7 +951,7 @@ impl<'pass> FirstPassDrawer<'pass> {
|
||||
|
||||
TerrainDrawer {
|
||||
render_pass,
|
||||
col_lights: None,
|
||||
atlas_textures: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -966,14 +967,14 @@ impl<'pass> FirstPassDrawer<'pass> {
|
||||
pub fn draw_sprites<'data: 'pass>(
|
||||
&mut self,
|
||||
globals: &'data sprite::SpriteGlobalsBindGroup,
|
||||
col_lights: &'data ColLights<sprite::Locals>,
|
||||
atlas_textures: &'data AtlasTextures<sprite::Locals, FigureSpriteAtlasData>,
|
||||
) -> SpriteDrawer<'_, 'pass> {
|
||||
let mut render_pass = self.render_pass.scope("sprites", self.borrow.device);
|
||||
|
||||
render_pass.set_pipeline(&self.pipelines.sprite.pipeline);
|
||||
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(2, &col_lights.bind_group, &[]);
|
||||
render_pass.set_bind_group(2, &atlas_textures.bind_group, &[]);
|
||||
|
||||
SpriteDrawer {
|
||||
render_pass,
|
||||
@ -1028,10 +1029,10 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
|
||||
model: SubModel<'data, terrain::Vertex>,
|
||||
locals: &'data figure::BoundLocals,
|
||||
// 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
|
||||
.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_vertex_buffer(0, model.buf());
|
||||
self.render_pass
|
||||
@ -1042,14 +1043,14 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
|
||||
#[must_use]
|
||||
pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
|
||||
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> {
|
||||
pub fn draw<'data: 'pass>(
|
||||
&mut self,
|
||||
model: &'data Model<terrain::Vertex>,
|
||||
col_lights: &'data Arc<ColLights<terrain::Locals>>,
|
||||
atlas_textures: &'data Arc<AtlasTextures<terrain::Locals, TerrainAtlasData>>,
|
||||
locals: &'data terrain::BoundLocals,
|
||||
alt_indices: &'data AltIndices,
|
||||
culling_mode: CullingMode,
|
||||
@ -1067,15 +1068,15 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
||||
|
||||
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
|
||||
// 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()
|
||||
{
|
||||
self.render_pass
|
||||
.set_bind_group(2, &col_lights.bind_group, &[]);
|
||||
self.col_lights = Some(col_lights);
|
||||
.set_bind_group(2, &atlas_textures.bind_group, &[]);
|
||||
self.atlas_textures = Some(atlas_textures);
|
||||
};
|
||||
|
||||
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},
|
||||
},
|
||||
render::{
|
||||
BoneMeshes, ColLightInfo, FigureModel, Instances, Mesh, Renderer, SpriteInstance,
|
||||
TerrainVertex,
|
||||
pipelines, BoneMeshes, FigureModel, FigureSpriteAtlasData, Instances, Mesh, Renderer,
|
||||
SpriteInstance, TerrainVertex,
|
||||
},
|
||||
scene::{
|
||||
camera::CameraMode,
|
||||
@ -42,7 +42,8 @@ use vek::*;
|
||||
/// A type produced by mesh worker threads corresponding to the information
|
||||
/// needed to mesh figures.
|
||||
pub struct MeshWorkerResponse<const N: usize> {
|
||||
col_light: ColLightInfo,
|
||||
atlas_texture_data: FigureSpriteAtlasData,
|
||||
atlas_size: Vec2<u16>,
|
||||
opaque: Mesh<TerrainVertex>,
|
||||
bounds: anim::vek::Aabb<f32>,
|
||||
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
|
||||
/// needed to mesh figures.
|
||||
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>,
|
||||
bounds: anim::vek::Aabb<f32>,
|
||||
vertex_range: [Range<u32>; N],
|
||||
@ -323,7 +327,7 @@ where
|
||||
pub fn get_model<'b>(
|
||||
&'b self,
|
||||
// TODO: If we ever convert to using an atlas here, use this.
|
||||
_col_lights: &super::FigureColLights,
|
||||
_atlas: &super::FigureAtlas,
|
||||
body: Skel::Body,
|
||||
inventory: Option<&Inventory>,
|
||||
// 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 clean(&mut self, col_lights: &mut super::FigureColLights, tick: u64)
|
||||
pub fn clean(&mut self, atlas: &mut super::FigureAtlas, tick: u64)
|
||||
where
|
||||
<Skel::Body as BodySpec>::Spec: Clone,
|
||||
{
|
||||
@ -370,7 +374,7 @@ where
|
||||
let alive = *last_used + delta > tick;
|
||||
if !alive {
|
||||
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
|
||||
@ -391,7 +395,7 @@ where
|
||||
pub fn get_or_create_model<'c>(
|
||||
&'c mut self,
|
||||
renderer: &mut Renderer,
|
||||
col_lights: &mut super::FigureColLights,
|
||||
atlas: &mut super::FigureAtlas,
|
||||
body: Skel::Body,
|
||||
inventory: Option<&Inventory>,
|
||||
extra: <Skel::Body as BodySpec>::Extra,
|
||||
@ -428,15 +432,17 @@ where
|
||||
match model {
|
||||
FigureModelEntryFuture::Pending(recv) => {
|
||||
if let Some(MeshWorkerResponse {
|
||||
col_light,
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
opaque,
|
||||
bounds,
|
||||
vertex_range,
|
||||
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
|
||||
{
|
||||
let model_entry = col_lights.create_figure(
|
||||
let model_entry = atlas.create_figure(
|
||||
renderer,
|
||||
col_light,
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
(opaque, bounds),
|
||||
vertex_range,
|
||||
);
|
||||
@ -480,7 +486,7 @@ where
|
||||
// list. Returns the vertex bounds of the meshed model within the opaque
|
||||
// mesh.
|
||||
let mut make_model = |generate_mesh: for<'a, 'b> fn(
|
||||
&mut GreedyMesh<'a>,
|
||||
&mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
&'b mut _,
|
||||
&'a _,
|
||||
_,
|
||||
@ -528,7 +534,7 @@ where
|
||||
};
|
||||
|
||||
fn generate_mesh<'a>(
|
||||
greedy: &mut GreedyMesh<'a>,
|
||||
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: &'a Segment,
|
||||
offset: Vec3<f32>,
|
||||
@ -542,7 +548,7 @@ where
|
||||
}
|
||||
|
||||
fn generate_mesh_lod_mid<'a>(
|
||||
greedy: &mut GreedyMesh<'a>,
|
||||
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: &'a Segment,
|
||||
offset: Vec3<f32>,
|
||||
@ -563,7 +569,7 @@ where
|
||||
}
|
||||
|
||||
fn generate_mesh_lod_low<'a>(
|
||||
greedy: &mut GreedyMesh<'a>,
|
||||
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: &'a Segment,
|
||||
offset: Vec3<f32>,
|
||||
@ -589,8 +595,10 @@ where
|
||||
make_model(generate_mesh_lod_low),
|
||||
];
|
||||
|
||||
let (atlas_texture_data, atlas_size) = greedy.finalize();
|
||||
slot_.store(Some(MeshWorkerResponse {
|
||||
col_light: greedy.finalize(),
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
opaque,
|
||||
bounds: figure_bounds,
|
||||
vertex_range: models,
|
||||
@ -619,7 +627,7 @@ where
|
||||
pub fn get_or_create_terrain_model<'c>(
|
||||
&'c mut self,
|
||||
renderer: &mut Renderer,
|
||||
col_lights: &mut super::FigureColLights,
|
||||
atlas: &mut super::FigureAtlas,
|
||||
body: Skel::Body,
|
||||
extra: <Skel::Body as BodySpec>::Extra,
|
||||
tick: u64,
|
||||
@ -647,7 +655,8 @@ where
|
||||
match model {
|
||||
TerrainModelEntryFuture::Pending(recv) => {
|
||||
if let Some(TerrainMeshWorkerResponse {
|
||||
col_light,
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
opaque,
|
||||
bounds,
|
||||
vertex_range,
|
||||
@ -656,9 +665,10 @@ where
|
||||
blocks_offset,
|
||||
}) = Arc::get_mut(recv).take().and_then(|cell| cell.take())
|
||||
{
|
||||
let model_entry = col_lights.create_terrain(
|
||||
let model_entry = atlas.create_terrain(
|
||||
renderer,
|
||||
col_light,
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
(opaque, bounds),
|
||||
vertex_range,
|
||||
sprite_instances,
|
||||
@ -707,7 +717,7 @@ where
|
||||
// list. Returns the vertex bounds of the meshed model within the opaque
|
||||
// mesh.
|
||||
let mut make_model = |generate_mesh: for<'a, 'b> fn(
|
||||
&mut GreedyMesh<'a>,
|
||||
&mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
&'b mut _,
|
||||
&'a _,
|
||||
_,
|
||||
@ -755,7 +765,7 @@ where
|
||||
};
|
||||
|
||||
fn generate_mesh<'a>(
|
||||
greedy: &mut GreedyMesh<'a>,
|
||||
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: &'a TerrainSegment,
|
||||
offset: Vec3<f32>,
|
||||
@ -769,7 +779,7 @@ where
|
||||
}
|
||||
|
||||
fn generate_mesh_lod_mid<'a>(
|
||||
greedy: &mut GreedyMesh<'a>,
|
||||
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: &'a TerrainSegment,
|
||||
offset: Vec3<f32>,
|
||||
@ -790,7 +800,7 @@ where
|
||||
}
|
||||
|
||||
fn generate_mesh_lod_low<'a>(
|
||||
greedy: &mut GreedyMesh<'a>,
|
||||
greedy: &mut GreedyMesh<'a, FigureSpriteAtlasData>,
|
||||
opaque_mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: &'a TerrainSegment,
|
||||
offset: Vec3<f32>,
|
||||
@ -819,13 +829,15 @@ where
|
||||
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 (atlas_texture_data, atlas_size) = greedy.finalize();
|
||||
slot_.store(Some(TerrainMeshWorkerResponse {
|
||||
col_light: greedy.finalize(),
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
opaque,
|
||||
bounds: figure_bounds,
|
||||
vertex_range: models,
|
||||
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(
|
||||
&mut instances,
|
||||
|lod, instance, _| {
|
||||
|
@ -12,11 +12,11 @@ use crate::{
|
||||
pipelines::{
|
||||
self,
|
||||
terrain::{BoundLocals as BoundTerrainLocals, Locals as TerrainLocals},
|
||||
trail, ColLights,
|
||||
trail, AtlasData, AtlasTextures, FigureSpriteAtlasData,
|
||||
},
|
||||
AltIndices, ColLightInfo, CullingMode, FigureBoneData, FigureDrawer, FigureLocals,
|
||||
FigureModel, FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer,
|
||||
SpriteDrawer, SpriteInstance, SubModel, TerrainVertex,
|
||||
AltIndices, CullingMode, FigureBoneData, FigureDrawer, FigureLocals, FigureModel,
|
||||
FigureShadowDrawer, Instances, Mesh, Quad, RenderError, Renderer, SpriteDrawer,
|
||||
SpriteInstance, SubModel, TerrainVertex,
|
||||
},
|
||||
scene::{
|
||||
camera::{Camera, CameraMode, Dependents},
|
||||
@ -80,7 +80,7 @@ pub type CameraData<'a> = (&'a Camera, f32);
|
||||
pub type FigureModelRef<'a> = (
|
||||
&'a pipelines::figure::BoundLocals,
|
||||
SubModel<'a, TerrainVertex>,
|
||||
&'a ColLights<pipelines::figure::Locals>,
|
||||
&'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData>,
|
||||
);
|
||||
|
||||
pub trait ModelEntry {
|
||||
@ -88,7 +88,7 @@ pub trait ModelEntry {
|
||||
|
||||
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
|
||||
@ -104,7 +104,7 @@ pub struct FigureModelEntry<const N: usize> {
|
||||
/// Texture used to store color/light information for this figure entry.
|
||||
/* TODO: Consider using mipmaps instead of storing multiple texture atlases for different
|
||||
* 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
|
||||
/// figure, because of LOD models.
|
||||
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()))
|
||||
}
|
||||
|
||||
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
|
||||
@ -138,7 +140,7 @@ pub struct TerrainModelEntry<const N: usize> {
|
||||
/// Texture used to store color/light information for this figure entry.
|
||||
/* TODO: Consider using mipmaps instead of storing multiple texture atlases for different
|
||||
* 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
|
||||
/// figure, because of LOD models.
|
||||
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()))
|
||||
}
|
||||
|
||||
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)]
|
||||
@ -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 {
|
||||
ModelEntryRef::Figure(e) => e.col_lights(),
|
||||
ModelEntryRef::Terrain(e) => e.col_lights(),
|
||||
ModelEntryRef::Figure(e) => e.atlas_textures(),
|
||||
ModelEntryRef::Terrain(e) => e.atlas_textures(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -498,7 +504,7 @@ impl FigureMgrStates {
|
||||
}
|
||||
|
||||
pub struct FigureMgr {
|
||||
col_lights: FigureColLights,
|
||||
atlas: FigureAtlas,
|
||||
model_cache: FigureModelCache,
|
||||
theropod_model_cache: FigureModelCache<TheropodSkeleton>,
|
||||
quadruped_small_model_cache: FigureModelCache<QuadrupedSmallSkeleton>,
|
||||
@ -523,7 +529,7 @@ pub struct FigureMgr {
|
||||
impl FigureMgr {
|
||||
pub fn new(renderer: &mut Renderer) -> Self {
|
||||
Self {
|
||||
col_lights: FigureColLights::new(renderer),
|
||||
atlas: FigureAtlas::new(renderer),
|
||||
model_cache: FigureModelCache::new(),
|
||||
theropod_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 {
|
||||
self.model_cache.watcher_reloaded()
|
||||
@ -573,7 +579,7 @@ impl FigureMgr {
|
||||
span!(_guard, "clean", "FigureManager::clean");
|
||||
|
||||
if self.any_watcher_reloaded() {
|
||||
self.col_lights.atlas.clear();
|
||||
self.atlas.atlas.clear();
|
||||
|
||||
self.model_cache.clear_models();
|
||||
self.theropod_model_cache.clear_models();
|
||||
@ -595,33 +601,26 @@ impl FigureMgr {
|
||||
self.arthropod_model_cache.clear_models();
|
||||
}
|
||||
|
||||
self.model_cache.clean(&mut self.col_lights, tick);
|
||||
self.theropod_model_cache.clean(&mut self.col_lights, tick);
|
||||
self.model_cache.clean(&mut self.atlas, tick);
|
||||
self.theropod_model_cache.clean(&mut self.atlas, tick);
|
||||
self.quadruped_small_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
.clean(&mut self.atlas, tick);
|
||||
self.quadruped_medium_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.quadruped_low_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.bird_medium_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.bird_large_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.dragon_model_cache.clean(&mut self.col_lights, tick);
|
||||
self.fish_medium_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.fish_small_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.biped_large_model_cache
|
||||
.clean(&mut self.col_lights, tick);
|
||||
self.biped_small_model_cache
|
||||
.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);
|
||||
.clean(&mut self.atlas, tick);
|
||||
self.quadruped_low_model_cache.clean(&mut self.atlas, tick);
|
||||
self.bird_medium_model_cache.clean(&mut self.atlas, tick);
|
||||
self.bird_large_model_cache.clean(&mut self.atlas, tick);
|
||||
self.dragon_model_cache.clean(&mut self.atlas, tick);
|
||||
self.fish_medium_model_cache.clean(&mut self.atlas, tick);
|
||||
self.fish_small_model_cache.clean(&mut self.atlas, tick);
|
||||
self.biped_large_model_cache.clean(&mut self.atlas, tick);
|
||||
self.biped_small_model_cache.clean(&mut self.atlas, tick);
|
||||
self.object_model_cache.clean(&mut self.atlas, tick);
|
||||
self.item_drop_model_cache.clean(&mut self.atlas, tick);
|
||||
self.ship_model_cache.clean(&mut self.atlas, tick);
|
||||
self.golem_model_cache.clean(&mut self.atlas, tick);
|
||||
self.volume_model_cache.clean(&mut self.atlas, tick);
|
||||
self.arthropod_model_cache.clean(&mut self.atlas, tick);
|
||||
}
|
||||
|
||||
pub fn update_lighting(&mut self, scene_data: &SceneData) {
|
||||
@ -1092,7 +1091,7 @@ impl FigureMgr {
|
||||
Body::Humanoid(body) => {
|
||||
let (model, skeleton_attr) = self.model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -2212,7 +2211,7 @@ impl FigureMgr {
|
||||
let (model, skeleton_attr) =
|
||||
self.quadruped_small_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -2412,7 +2411,7 @@ impl FigureMgr {
|
||||
let (model, skeleton_attr) =
|
||||
self.quadruped_medium_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -2789,7 +2788,7 @@ impl FigureMgr {
|
||||
let (model, skeleton_attr) =
|
||||
self.quadruped_low_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -3185,7 +3184,7 @@ impl FigureMgr {
|
||||
Body::BirdMedium(body) => {
|
||||
let (model, skeleton_attr) = self.bird_medium_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -3515,7 +3514,7 @@ impl FigureMgr {
|
||||
Body::FishMedium(body) => {
|
||||
let (model, skeleton_attr) = self.fish_medium_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -3598,7 +3597,7 @@ impl FigureMgr {
|
||||
Body::BipedSmall(body) => {
|
||||
let (model, skeleton_attr) = self.biped_small_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -4159,7 +4158,7 @@ impl FigureMgr {
|
||||
Body::Dragon(body) => {
|
||||
let (model, skeleton_attr) = self.dragon_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -4246,7 +4245,7 @@ impl FigureMgr {
|
||||
Body::Theropod(body) => {
|
||||
let (model, skeleton_attr) = self.theropod_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -4425,7 +4424,7 @@ impl FigureMgr {
|
||||
Body::Arthropod(body) => {
|
||||
let (model, skeleton_attr) = self.arthropod_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -4717,7 +4716,7 @@ impl FigureMgr {
|
||||
Body::BirdLarge(body) => {
|
||||
let (model, skeleton_attr) = self.bird_large_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -5040,7 +5039,7 @@ impl FigureMgr {
|
||||
Body::FishSmall(body) => {
|
||||
let (model, skeleton_attr) = self.fish_small_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -5123,7 +5122,7 @@ impl FigureMgr {
|
||||
Body::BipedLarge(body) => {
|
||||
let (model, skeleton_attr) = self.biped_large_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -5828,7 +5827,7 @@ impl FigureMgr {
|
||||
Body::Golem(body) => {
|
||||
let (model, skeleton_attr) = self.golem_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -6069,7 +6068,7 @@ impl FigureMgr {
|
||||
Body::Object(body) => {
|
||||
let (model, skeleton_attr) = self.object_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -6191,7 +6190,7 @@ impl FigureMgr {
|
||||
let item_key = item.map(ItemKey::from);
|
||||
let (model, skeleton_attr) = self.item_drop_model_cache.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -6255,7 +6254,7 @@ impl FigureMgr {
|
||||
let (model, _skeleton_attr) =
|
||||
self.volume_model_cache.get_or_create_terrain_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
vk,
|
||||
Arc::clone(vol),
|
||||
tick,
|
||||
@ -6282,7 +6281,7 @@ impl FigureMgr {
|
||||
} else if body.manifest_entry().is_some() {
|
||||
self.ship_model_cache.get_or_create_terrain_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.atlas,
|
||||
body,
|
||||
(),
|
||||
tick,
|
||||
@ -6560,7 +6559,7 @@ impl FigureMgr {
|
||||
// Don't render player
|
||||
.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,
|
||||
camera,
|
||||
character_state,
|
||||
@ -6582,7 +6581,7 @@ impl FigureMgr {
|
||||
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 = 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,
|
||||
camera,
|
||||
character_state,
|
||||
@ -6635,10 +6634,10 @@ impl FigureMgr {
|
||||
None
|
||||
},
|
||||
) {
|
||||
drawer.draw(model, bound, col_lights);
|
||||
drawer.draw(model, bound, atlas);
|
||||
/*renderer.render_player_shadow(
|
||||
model,
|
||||
&col_lights,
|
||||
&atlas,
|
||||
global,
|
||||
bone_consts,
|
||||
lod,
|
||||
@ -6677,7 +6676,7 @@ impl FigureMgr {
|
||||
let character_state = if is_viewpoint { character_state } else { None };
|
||||
|
||||
let FigureMgr {
|
||||
col_lights: ref col_lights_,
|
||||
atlas: ref atlas_,
|
||||
model_cache,
|
||||
theropod_model_cache,
|
||||
quadruped_small_model_cache,
|
||||
@ -6718,7 +6717,7 @@ impl FigureMgr {
|
||||
arthropod_states,
|
||||
},
|
||||
} = self;
|
||||
let col_lights = col_lights_;
|
||||
let atlas = atlas_;
|
||||
if let Some((bound, model_entry)) = match body {
|
||||
Body::Humanoid(body) => character_states
|
||||
.get(&entity)
|
||||
@ -6728,7 +6727,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6747,7 +6746,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
quadruped_small_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6766,7 +6765,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
quadruped_medium_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6785,7 +6784,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
quadruped_low_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6804,7 +6803,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
bird_medium_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6823,7 +6822,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
fish_medium_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6842,7 +6841,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
theropod_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6861,7 +6860,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
dragon_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6880,7 +6879,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
bird_large_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6899,7 +6898,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
fish_small_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6918,7 +6917,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
biped_large_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6937,7 +6936,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
biped_small_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6956,7 +6955,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
golem_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6975,7 +6974,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
arthropod_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -6994,7 +6993,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
object_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -7013,7 +7012,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
item_drop_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -7034,7 +7033,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
volume_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
VolumeKey { entity, mut_count },
|
||||
None,
|
||||
tick,
|
||||
@ -7054,7 +7053,7 @@ impl FigureMgr {
|
||||
state.bound(),
|
||||
ship_model_cache
|
||||
.get_model(
|
||||
col_lights,
|
||||
atlas,
|
||||
body,
|
||||
None,
|
||||
tick,
|
||||
@ -7097,7 +7096,7 @@ impl FigureMgr {
|
||||
model_entry.lod_model(0)
|
||||
};
|
||||
|
||||
Some((bound, model?, col_lights_.texture(model_entry)))
|
||||
Some((bound, model?, atlas_.texture(model_entry)))
|
||||
} else {
|
||||
// trace!("Body has no saved figure");
|
||||
None
|
||||
@ -7252,16 +7251,16 @@ impl FigureMgr {
|
||||
pub fn figure_count_visible(&self) -> usize { self.states.count_visible() }
|
||||
}
|
||||
|
||||
pub struct FigureColLights {
|
||||
pub struct FigureAtlas {
|
||||
atlas: AtlasAllocator,
|
||||
// col_lights: Texture<ColLightFmt>,
|
||||
// atlas_texture: Texture<ColLightFmt>,
|
||||
}
|
||||
|
||||
impl FigureColLights {
|
||||
impl FigureAtlas {
|
||||
pub fn new(renderer: &mut Renderer) -> Self {
|
||||
let atlas = Self::make_atlas(renderer).expect("Failed to create texture atlas for figures");
|
||||
Self {
|
||||
atlas, /* col_lights, */
|
||||
atlas, /* atlas_texture, */
|
||||
}
|
||||
}
|
||||
|
||||
@ -7269,9 +7268,9 @@ impl FigureColLights {
|
||||
pub fn texture<'a, const N: usize>(
|
||||
&'a self,
|
||||
model: ModelEntryRef<'a, N>,
|
||||
) -> &'a ColLights<pipelines::figure::Locals> {
|
||||
/* &self.col_lights */
|
||||
model.col_lights()
|
||||
) -> &'a AtlasTextures<pipelines::figure::Locals, FigureSpriteAtlasData> {
|
||||
/* &self.atlas_texture */
|
||||
model.atlas_textures()
|
||||
}
|
||||
|
||||
/// 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>(
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
(tex, tex_size): ColLightInfo,
|
||||
atlas_texture_data: FigureSpriteAtlasData,
|
||||
atlas_size: Vec2<u16>,
|
||||
(opaque, bounds): (Mesh<TerrainVertex>, math::Aabb<f32>),
|
||||
vertex_ranges: [Range<u32>; N],
|
||||
) -> FigureModelEntry<N> {
|
||||
span!(_guard, "create_figure", "FigureColLights::create_figure");
|
||||
let atlas = &mut self.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.");
|
||||
let col_lights = pipelines::shadow::create_col_lights(renderer, &(tex, tex_size));
|
||||
let col_lights = renderer.figure_bind_col_light(col_lights);
|
||||
let [atlas_textures] = atlas_texture_data.create_textures(renderer, atlas_size);
|
||||
let atlas_textures = renderer.figure_bind_atlas_textures(atlas_textures);
|
||||
let model_len = u32::try_from(opaque.vertices().len())
|
||||
.expect("The model size for this figure does not fit in a u32!");
|
||||
let model = renderer.create_model(&opaque);
|
||||
@ -7313,7 +7316,7 @@ impl FigureColLights {
|
||||
FigureModelEntry {
|
||||
_bounds: bounds,
|
||||
allocation,
|
||||
col_lights,
|
||||
atlas_textures,
|
||||
lod_vertex_ranges: vertex_ranges,
|
||||
model: FigureModel { opaque: model },
|
||||
}
|
||||
@ -7330,7 +7333,9 @@ impl FigureColLights {
|
||||
pub fn create_terrain<const N: usize>(
|
||||
&mut self,
|
||||
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>),
|
||||
vertex_ranges: [Range<u32>; N],
|
||||
sprite_instances: [Vec<SpriteInstance>; SPRITE_LOD_LEVELS],
|
||||
@ -7340,10 +7345,14 @@ impl FigureColLights {
|
||||
span!(_guard, "create_figure", "FigureColLights::create_figure");
|
||||
let atlas = &mut self.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.");
|
||||
let col_lights = pipelines::shadow::create_col_lights(renderer, &(tex, tex_size));
|
||||
let col_lights = renderer.figure_bind_col_light(col_lights);
|
||||
let [col_lights] = atlas_texture_data.create_textures(renderer, atlas_size);
|
||||
// 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())
|
||||
.expect("The model size for this figure does not fit in a u32!");
|
||||
let model = renderer.create_model(&opaque);
|
||||
@ -7364,7 +7373,7 @@ impl FigureColLights {
|
||||
TerrainModelEntry {
|
||||
_bounds: bounds,
|
||||
allocation,
|
||||
col_lights,
|
||||
atlas_textures,
|
||||
lod_vertex_ranges: vertex_ranges,
|
||||
model: FigureModel { opaque: model },
|
||||
sprite_instances,
|
||||
|
@ -1403,7 +1403,7 @@ impl Scene {
|
||||
// Draws sprites
|
||||
let mut sprite_drawer = first_pass.draw_sprites(
|
||||
&self.terrain.sprite_globals,
|
||||
&self.terrain.sprite_col_lights,
|
||||
&self.terrain.sprite_atlas_textures,
|
||||
);
|
||||
self.figure_mgr.render_sprites(
|
||||
&mut sprite_drawer,
|
||||
|
@ -1,14 +1,15 @@
|
||||
use crate::{
|
||||
mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_figure},
|
||||
render::{
|
||||
create_skybox_mesh, BoneMeshes, Consts, FigureModel, FirstPassDrawer, GlobalModel, Globals,
|
||||
GlobalsBindGroup, Light, LodData, Mesh, Model, PointLightMatrix, RainOcclusionLocals,
|
||||
Renderer, Shadow, ShadowLocals, SkyboxVertex, TerrainVertex,
|
||||
create_skybox_mesh, pipelines::FigureSpriteAtlasData, BoneMeshes, Consts, FigureModel,
|
||||
FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Mesh, Model,
|
||||
PointLightMatrix, RainOcclusionLocals, Renderer, Shadow, ShadowLocals, SkyboxVertex,
|
||||
TerrainVertex,
|
||||
},
|
||||
scene::{
|
||||
camera::{self, Camera, CameraMode},
|
||||
figure::{
|
||||
load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState,
|
||||
load_mesh, FigureAtlas, FigureModelCache, FigureModelEntry, FigureState,
|
||||
FigureUpdateCommonParameters,
|
||||
},
|
||||
},
|
||||
@ -46,7 +47,7 @@ impl ReadVol for VoidVol {
|
||||
}
|
||||
|
||||
fn generate_mesh(
|
||||
greedy: &mut GreedyMesh<'_>,
|
||||
greedy: &mut GreedyMesh<'_, FigureSpriteAtlasData>,
|
||||
mesh: &mut Mesh<TerrainVertex>,
|
||||
segment: Segment,
|
||||
offset: Vec3<f32>,
|
||||
@ -70,7 +71,7 @@ pub struct Scene {
|
||||
lod: LodData,
|
||||
map_bounds: Vec2<f32>,
|
||||
|
||||
col_lights: FigureColLights,
|
||||
figure_atlas: FigureAtlas,
|
||||
backdrop: Option<(FigureModelEntry<1>, FigureState<FixtureSkeleton>)>,
|
||||
figure_model_cache: FigureModelCache,
|
||||
figure_state: Option<FigureState<CharacterSkeleton>>,
|
||||
@ -108,7 +109,7 @@ impl Scene {
|
||||
camera.set_distance(3.4);
|
||||
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 {
|
||||
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
|
||||
// 2^27, which fits in a u32.
|
||||
let range = 0..opaque_mesh.vertices().len() as u32;
|
||||
let model =
|
||||
col_lights
|
||||
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]);
|
||||
let (atlas_texture_data, atlas_size) = greedy.finalize();
|
||||
let model = figure_atlas.create_figure(
|
||||
renderer,
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
(opaque_mesh, bounds),
|
||||
[range],
|
||||
);
|
||||
let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
|
||||
let common_params = FigureUpdateCommonParameters {
|
||||
entity: None,
|
||||
@ -182,7 +188,7 @@ impl Scene {
|
||||
);
|
||||
(model, state)
|
||||
}),
|
||||
col_lights,
|
||||
figure_atlas,
|
||||
|
||||
camera,
|
||||
|
||||
@ -283,7 +289,7 @@ impl Scene {
|
||||
)]);
|
||||
|
||||
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| {
|
||||
inventory
|
||||
@ -327,7 +333,7 @@ impl Scene {
|
||||
.figure_model_cache
|
||||
.get_or_create_model(
|
||||
renderer,
|
||||
&mut self.col_lights,
|
||||
&mut self.figure_atlas,
|
||||
body,
|
||||
inventory,
|
||||
(),
|
||||
@ -376,7 +382,7 @@ impl Scene {
|
||||
let mut figure_drawer = drawer.draw_figures();
|
||||
if let Some(body) = body {
|
||||
let model = &self.figure_model_cache.get_model(
|
||||
&self.col_lights,
|
||||
&self.figure_atlas,
|
||||
body,
|
||||
inventory,
|
||||
tick,
|
||||
@ -390,7 +396,7 @@ impl Scene {
|
||||
figure_drawer.draw(
|
||||
lod,
|
||||
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(
|
||||
lod,
|
||||
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},
|
||||
},
|
||||
render::{
|
||||
pipelines::{self, ColLights},
|
||||
AltIndices, ColLightInfo, CullingMode, FirstPassDrawer, FluidVertex, GlobalModel,
|
||||
pipelines::{self, AtlasData, AtlasTextures},
|
||||
AltIndices, CullingMode, FigureSpriteAtlasData, FirstPassDrawer, FluidVertex, GlobalModel,
|
||||
Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteDrawer,
|
||||
SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts, TerrainLocals,
|
||||
TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
|
||||
SpriteGlobalsBindGroup, SpriteInstance, SpriteVertex, SpriteVerts, TerrainAtlasData,
|
||||
TerrainLocals, TerrainShadowDrawer, TerrainVertex, SPRITE_VERT_PAGE_SIZE,
|
||||
},
|
||||
};
|
||||
|
||||
@ -80,14 +80,14 @@ pub struct TerrainChunkData {
|
||||
fluid_model: Option<Model<FluidVertex>>,
|
||||
/// If this is `None`, this texture is not allocated in the current atlas,
|
||||
/// 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
|
||||
/// purposes. The texture is reference-counted, so it will be
|
||||
/// automatically freed when no chunks are left that need it (though
|
||||
/// 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
|
||||
/// 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,
|
||||
glow_map: LightMapFn,
|
||||
sprite_instances: [(Instances<SpriteInstance>, AltIndices); SPRITE_LOD_LEVELS],
|
||||
@ -133,7 +133,8 @@ pub struct MeshWorkerResponseMesh {
|
||||
sun_occluder_z_bounds: (f32, f32),
|
||||
opaque_mesh: Mesh<TerrainVertex>,
|
||||
fluid_mesh: Mesh<FluidVertex>,
|
||||
col_lights_info: ColLightInfo,
|
||||
atlas_texture_data: TerrainAtlasData,
|
||||
atlas_size: Vec2<u16>,
|
||||
light_map: LightMapFn,
|
||||
glow_map: LightMapFn,
|
||||
alt_indices: AltIndices,
|
||||
@ -343,7 +344,15 @@ fn mesh_worker(
|
||||
opaque_mesh,
|
||||
fluid_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(
|
||||
&volume,
|
||||
(
|
||||
@ -358,7 +367,8 @@ fn mesh_worker(
|
||||
sun_occluder_z_bounds,
|
||||
opaque_mesh,
|
||||
fluid_mesh,
|
||||
col_lights_info,
|
||||
atlas_texture_data,
|
||||
atlas_size,
|
||||
light_map,
|
||||
glow_map,
|
||||
alt_indices,
|
||||
@ -496,12 +506,12 @@ pub struct Terrain<V: RectRasterableVol = TerrainChunk> {
|
||||
// Maps sprite kind + variant to data detailing how to render it
|
||||
pub sprite_data: Arc<HashMap<(SpriteKind, usize), [SpriteData; SPRITE_LOD_LEVELS]>>,
|
||||
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
|
||||
/// we allocate. Code cannot assume that this is the assigned texture
|
||||
/// for any particular chunk; look at the `texture` field in
|
||||
/// `TerrainChunkData` for that.
|
||||
col_lights: Arc<ColLights<pipelines::terrain::Locals>>,
|
||||
atlas_textures: Arc<AtlasTextures<pipelines::terrain::Locals, TerrainAtlasData>>,
|
||||
|
||||
phantom: PhantomData<V>,
|
||||
}
|
||||
@ -515,7 +525,7 @@ pub struct SpriteRenderContext {
|
||||
sprite_config: Arc<SpriteSpec>,
|
||||
// Maps sprite kind + variant to data detailing how to render it
|
||||
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>,
|
||||
}
|
||||
|
||||
@ -528,7 +538,8 @@ impl SpriteRenderContext {
|
||||
struct SpriteWorkerResponse {
|
||||
sprite_config: Arc<SpriteSpec>,
|
||||
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>,
|
||||
}
|
||||
|
||||
@ -539,7 +550,7 @@ impl SpriteRenderContext {
|
||||
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 mut greedy = GreedyMesh::<SpriteAtlasAllocator>::new(
|
||||
let mut greedy = GreedyMesh::<FigureSpriteAtlasData, SpriteAtlasAllocator>::new(
|
||||
max_size,
|
||||
crate::mesh::greedy::sprite_config(),
|
||||
);
|
||||
@ -584,7 +595,10 @@ impl SpriteRenderContext {
|
||||
scale
|
||||
}
|
||||
});
|
||||
move |greedy: &mut GreedyMesh<SpriteAtlasAllocator>,
|
||||
move |greedy: &mut GreedyMesh<
|
||||
FigureSpriteAtlasData,
|
||||
SpriteAtlasAllocator,
|
||||
>,
|
||||
sprite_mesh: &mut Mesh<SpriteVertex>| {
|
||||
prof_span!("mesh sprite");
|
||||
let lod_sprite_data = scaled.map(|lod_scale_orig| {
|
||||
@ -635,7 +649,7 @@ impl SpriteRenderContext {
|
||||
.map(|f| f(&mut greedy, &mut sprite_mesh))
|
||||
.collect();
|
||||
|
||||
let sprite_col_lights = {
|
||||
let (sprite_atlas_texture_data, sprite_atlas_size) = {
|
||||
prof_span!("finalize");
|
||||
greedy.finalize()
|
||||
};
|
||||
@ -643,7 +657,8 @@ impl SpriteRenderContext {
|
||||
SpriteWorkerResponse {
|
||||
sprite_config,
|
||||
sprite_data,
|
||||
sprite_col_lights,
|
||||
sprite_atlas_texture_data,
|
||||
sprite_atlas_size,
|
||||
sprite_mesh,
|
||||
}
|
||||
});
|
||||
@ -658,7 +673,8 @@ impl SpriteRenderContext {
|
||||
let SpriteWorkerResponse {
|
||||
sprite_config,
|
||||
sprite_data,
|
||||
sprite_col_lights,
|
||||
sprite_atlas_texture_data,
|
||||
sprite_atlas_size,
|
||||
sprite_mesh,
|
||||
} = join_handle
|
||||
.take()
|
||||
@ -669,9 +685,9 @@ impl SpriteRenderContext {
|
||||
.join()
|
||||
.unwrap();
|
||||
|
||||
let sprite_col_lights =
|
||||
pipelines::shadow::create_col_lights(renderer, &sprite_col_lights);
|
||||
let sprite_col_lights = renderer.sprite_bind_col_light(sprite_col_lights);
|
||||
let [sprite_col_lights] =
|
||||
sprite_atlas_texture_data.create_textures(renderer, sprite_atlas_size);
|
||||
let sprite_atlas_textures = renderer.sprite_bind_atlas_textures(sprite_col_lights);
|
||||
|
||||
// Write sprite model to a 1D texture
|
||||
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?
|
||||
sprite_config: Arc::clone(&sprite_config),
|
||||
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),
|
||||
}
|
||||
};
|
||||
@ -699,7 +715,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
// with worker threads that are meshing chunks.
|
||||
let (send, recv) = channel::unbounded();
|
||||
|
||||
let (atlas, col_lights) =
|
||||
let (atlas, atlas_textures) =
|
||||
Self::make_atlas(renderer).expect("Failed to create atlas texture");
|
||||
|
||||
Self {
|
||||
@ -713,20 +729,26 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
mesh_todos_active: Arc::new(AtomicU64::new(0)),
|
||||
mesh_recv_overflow: 0.0,
|
||||
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(
|
||||
global_model,
|
||||
lod_data,
|
||||
&sprite_render_context.sprite_verts_buffer,
|
||||
),
|
||||
col_lights: Arc::new(col_lights),
|
||||
atlas_textures: Arc::new(atlas_textures),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_atlas(
|
||||
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");
|
||||
let max_texture_size = renderer.max_texture_size();
|
||||
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,
|
||||
..guillotiere::AllocatorOptions::default()
|
||||
});
|
||||
let texture = renderer.create_texture_raw(
|
||||
&wgpu::TextureDescriptor {
|
||||
label: Some("Atlas texture"),
|
||||
size: wgpu::Extent3d {
|
||||
width: max_texture_size,
|
||||
height: max_texture_size,
|
||||
depth_or_array_layers: 1,
|
||||
let [col_lights, kinds] = [
|
||||
wgpu::TextureFormat::Rgba8Unorm,
|
||||
wgpu::TextureFormat::R8Unorm,
|
||||
]
|
||||
.map(|fmt| {
|
||||
renderer.create_texture_raw(
|
||||
&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,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED,
|
||||
},
|
||||
&wgpu::TextureViewDescriptor {
|
||||
label: Some("Atlas texture view"),
|
||||
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,
|
||||
},
|
||||
&wgpu::SamplerDescriptor {
|
||||
label: Some("Atlas sampler"),
|
||||
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,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let col_light = renderer.terrain_bind_col_light(texture);
|
||||
Ok((atlas, col_light))
|
||||
&wgpu::TextureViewDescriptor {
|
||||
label: Some("Color & lights atlas texture view"),
|
||||
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,
|
||||
},
|
||||
&wgpu::SamplerDescriptor {
|
||||
label: Some("Color & lights atlas texture sampler"),
|
||||
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,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
});
|
||||
let textures = renderer.terrain_bind_atlas_textures(col_lights, kinds);
|
||||
Ok((atlas, textures))
|
||||
}
|
||||
|
||||
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
|
||||
// atlas, since we don't bother tracking it at that point.
|
||||
if let Some(col_lights) = chunk.col_lights_alloc {
|
||||
self.atlas.deallocate(col_lights);
|
||||
if let Some(atlas_alloc) = chunk.atlas_alloc {
|
||||
self.atlas.deallocate(atlas_alloc);
|
||||
}
|
||||
/* let (zmin, zmax) = chunk.z_bounds;
|
||||
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)
|
||||
.unwrap_or(current_time as f32);
|
||||
// TODO: Allocate new atlas on allocation failure.
|
||||
let (tex, tex_size) = mesh.col_lights_info;
|
||||
let atlas = &mut self.atlas;
|
||||
let chunks = &mut self.chunks;
|
||||
let col_lights = &mut self.col_lights;
|
||||
let alloc_size =
|
||||
guillotiere::Size::new(i32::from(tex_size.x), i32::from(tex_size.y));
|
||||
let atlas_textures = &mut self.atlas_textures;
|
||||
let alloc_size = guillotiere::Size::new(
|
||||
i32::from(mesh.atlas_size.x),
|
||||
i32::from(mesh.atlas_size.y),
|
||||
);
|
||||
|
||||
let allocation = atlas.allocate(alloc_size).unwrap_or_else(|| {
|
||||
// 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");
|
||||
|
||||
// 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
|
||||
// always moving everything into the new chunk.
|
||||
chunks.iter_mut().for_each(|(_, chunk)| {
|
||||
chunk.col_lights_alloc = None;
|
||||
chunk.atlas_alloc = None;
|
||||
});
|
||||
*atlas = new_atlas;
|
||||
*col_lights = Arc::new(new_col_lights);
|
||||
*atlas_textures = Arc::new(new_atlas_textures);
|
||||
|
||||
atlas
|
||||
.allocate(alloc_size)
|
||||
@ -1286,19 +1315,27 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
allocation.rectangle.min.x as u32,
|
||||
allocation.rectangle.min.y as u32,
|
||||
);
|
||||
// Update col_lights texture
|
||||
renderer.update_texture(
|
||||
&col_lights.texture,
|
||||
&atlas_textures.textures[0],
|
||||
atlas_offs.into_array(),
|
||||
tex_size.map(u32::from).into_array(),
|
||||
&tex,
|
||||
mesh.atlas_size.as_().into_array(),
|
||||
&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 {
|
||||
load_time,
|
||||
opaque_model: renderer.create_model(&mesh.opaque_mesh),
|
||||
fluid_model: renderer.create_model(&mesh.fluid_mesh),
|
||||
col_lights_alloc: Some(allocation.id),
|
||||
col_lights: Arc::clone(&self.col_lights),
|
||||
atlas_alloc: Some(allocation.id),
|
||||
atlas_textures: Arc::clone(&self.atlas_textures),
|
||||
light_map: mesh.light_map,
|
||||
glow_map: mesh.glow_map,
|
||||
sprite_instances,
|
||||
@ -1705,19 +1742,19 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
Some((
|
||||
rpos,
|
||||
chunk.opaque_model.as_ref()?,
|
||||
&chunk.col_lights,
|
||||
&chunk.atlas_textures,
|
||||
&chunk.locals,
|
||||
&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'
|
||||
let culling_mode = if rpos.magnitude_squared() < NEVER_CULL_DIST.pow(2) {
|
||||
CullingMode::None
|
||||
} else {
|
||||
culling_mode
|
||||
};
|
||||
drawer.draw(model, col_lights, locals, alt_indices, culling_mode)
|
||||
drawer.draw(model, atlas_textures, locals, alt_indices, culling_mode)
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user