mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Include an associated Config type in the atlas trait which is provided when creating the atlas
This commit is contained in:
@ -80,14 +80,11 @@ pub type SuspendedMesh<'a> = dyn for<'r> FnOnce(&'r mut ColLightInfo) + 'a;
|
|||||||
/// Abstraction over different atlas allocators. Useful to swap out the
|
/// Abstraction over different atlas allocators. Useful to swap out the
|
||||||
/// allocator implementation for specific cases (e.g. sprites).
|
/// allocator implementation for specific cases (e.g. sprites).
|
||||||
pub trait AtlasAllocator {
|
pub trait AtlasAllocator {
|
||||||
//type Rect;
|
type Config;
|
||||||
// TODO: add as parameter to `with_max_size`, also we may want to experiment
|
|
||||||
// with each use case: terrain, figures, etc to find the optimal config
|
|
||||||
//type Config;
|
|
||||||
|
|
||||||
/// Creates a new instance of this atlas allocator taking into account the
|
/// Creates a new instance of this atlas allocator taking into account the
|
||||||
/// provided max size;
|
/// provided max size;
|
||||||
fn with_max_size(max_size: Vec2<u16>) -> Self;
|
fn with_max_size(max_size: Vec2<u16>, config: Self::Config) -> Self;
|
||||||
|
|
||||||
/// Allocates a rectangle of the given size.
|
/// Allocates a rectangle of the given size.
|
||||||
// TODO: don't use guillotiere type here
|
// TODO: don't use guillotiere type here
|
||||||
@ -104,29 +101,42 @@ fn guillotiere_size<T: Into<i32>>(size: Vec2<T>) -> guillotiere::Size {
|
|||||||
guillotiere::Size::new(size.x.into(), size.y.into())
|
guillotiere::Size::new(size.x.into(), size.y.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AtlasAllocator for guillotiere::SimpleAtlasAllocator {
|
/// Currently used by terrain/particles/figures
|
||||||
fn with_max_size(max_size: Vec2<u16>) -> Self {
|
pub fn general_config() -> guillotiere::AllocatorOptions {
|
||||||
// TODO: Collect information to see if we can choose a good value here. These
|
// TODO: Collect information to see if we can choose a good value here. These
|
||||||
// current values were optimized for sprites, but we are using a
|
// current values were optimized for sprites, but we are using a
|
||||||
// different allocator for them so different values might be better
|
// different allocator for them so different values might be better
|
||||||
// here.
|
// here.
|
||||||
let large_size_threshold = 8; //256.min(min_max_dim / 2 + 1);
|
let large_size_threshold = 8; //256.min(min_max_dim / 2 + 1);
|
||||||
let small_size_threshold = 3; //33.min(large_size_threshold / 2 + 1);
|
let small_size_threshold = 3; //33.min(large_size_threshold / 2 + 1);
|
||||||
// (12, 3) 24.5
|
|
||||||
// (12, 2) 33.2
|
|
||||||
// (12, 4) 27.2
|
|
||||||
// (14, 3) 25.6
|
|
||||||
// (10, 3) 20.9
|
|
||||||
// (8, 3) 17.9
|
|
||||||
// (6, 3) 18.0
|
|
||||||
// (5, 3) 18.0
|
|
||||||
let size = guillotiere_size(Vec2::new(32, 32)).min(guillotiere_size(max_size));
|
|
||||||
|
|
||||||
guillotiere::SimpleAtlasAllocator::with_options(size, &guillotiere::AllocatorOptions {
|
guillotiere::AllocatorOptions {
|
||||||
alignment: guillotiere::Size::new(1, 1),
|
alignment: guillotiere::Size::new(1, 1),
|
||||||
small_size_threshold,
|
small_size_threshold,
|
||||||
large_size_threshold,
|
large_size_threshold,
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sprite_config() -> guillotiere::AllocatorOptions {
|
||||||
|
// TODO: Collect information to see if we can choose a better value here (these
|
||||||
|
// values were picked before switching to this tiled implementation). I
|
||||||
|
// suspect these are still near optimal though.
|
||||||
|
let large_size_threshold = 8;
|
||||||
|
let small_size_threshold = 3;
|
||||||
|
|
||||||
|
guillotiere::AllocatorOptions {
|
||||||
|
alignment: guillotiere::Size::new(1, 1),
|
||||||
|
small_size_threshold,
|
||||||
|
large_size_threshold,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtlasAllocator for guillotiere::SimpleAtlasAllocator {
|
||||||
|
type Config = guillotiere::AllocatorOptions;
|
||||||
|
|
||||||
|
fn with_max_size(max_size: Vec2<u16>, config: Self::Config) -> Self {
|
||||||
|
let size = guillotiere_size(Vec2::new(32, 32)).min(guillotiere_size(max_size));
|
||||||
|
guillotiere::SimpleAtlasAllocator::with_options(size, &config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a rectangle of the given size.
|
/// Allocates a rectangle of the given size.
|
||||||
@ -146,6 +156,7 @@ impl AtlasAllocator for guillotiere::SimpleAtlasAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct GuillotiereTiled {
|
pub struct GuillotiereTiled {
|
||||||
|
options: guillotiere::AllocatorOptions,
|
||||||
// Each tile is Self::TILE_SIZE (unless max size is not aligned to this, in which case the
|
// Each tile is Self::TILE_SIZE (unless max size is not aligned to this, in which case the
|
||||||
// tiles that reach the max size are truncated below this value).
|
// tiles that reach the max size are truncated below this value).
|
||||||
allocator: guillotiere::SimpleAtlasAllocator,
|
allocator: guillotiere::SimpleAtlasAllocator,
|
||||||
@ -179,20 +190,6 @@ impl GuillotiereTiled {
|
|||||||
// 2048 10.49s n/a packing (didn't fill up)
|
// 2048 10.49s n/a packing (didn't fill up)
|
||||||
const TILE_SIZE: u16 = 512;
|
const TILE_SIZE: u16 = 512;
|
||||||
|
|
||||||
fn allocator_options() -> guillotiere::AllocatorOptions {
|
|
||||||
// TODO: Collect information to see if we can choose a better value here (these
|
|
||||||
// values were picked before switching to this tiled implementation). I
|
|
||||||
// suspect these are still near optimal though.
|
|
||||||
let large_size_threshold = 8;
|
|
||||||
let small_size_threshold = 3;
|
|
||||||
|
|
||||||
guillotiere::AllocatorOptions {
|
|
||||||
alignment: guillotiere::Size::new(1, 1),
|
|
||||||
small_size_threshold,
|
|
||||||
large_size_threshold,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_tile(&mut self) {
|
fn next_tile(&mut self) {
|
||||||
if self.current.is_some() {
|
if self.current.is_some() {
|
||||||
prof_span!("stats");
|
prof_span!("stats");
|
||||||
@ -206,7 +203,7 @@ impl GuillotiereTiled {
|
|||||||
self.current = if let Some(offset) = self.free_tiles.pop() {
|
self.current = if let Some(offset) = self.free_tiles.pop() {
|
||||||
self.allocator.reset(
|
self.allocator.reset(
|
||||||
guillotiere_size(Vec2::broadcast(Self::TILE_SIZE)),
|
guillotiere_size(Vec2::broadcast(Self::TILE_SIZE)),
|
||||||
&Self::allocator_options(),
|
&self.options,
|
||||||
);
|
);
|
||||||
self.used_in_current_tile = 0;
|
self.used_in_current_tile = 0;
|
||||||
Some(offset)
|
Some(offset)
|
||||||
@ -217,14 +214,16 @@ impl GuillotiereTiled {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AtlasAllocator for GuillotiereTiled {
|
impl AtlasAllocator for GuillotiereTiled {
|
||||||
fn with_max_size(max_size: Vec2<u16>) -> Self {
|
type Config = guillotiere::AllocatorOptions;
|
||||||
|
|
||||||
|
fn with_max_size(max_size: Vec2<u16>, config: Self::Config) -> Self {
|
||||||
let size =
|
let size =
|
||||||
guillotiere_size(Vec2::broadcast(Self::TILE_SIZE)).min(guillotiere_size(max_size));
|
guillotiere_size(Vec2::broadcast(Self::TILE_SIZE)).min(guillotiere_size(max_size));
|
||||||
|
|
||||||
let allocator =
|
let allocator = guillotiere::SimpleAtlasAllocator::with_options(size, &config);
|
||||||
guillotiere::SimpleAtlasAllocator::with_options(size, &Self::allocator_options());
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
options: config,
|
||||||
allocator,
|
allocator,
|
||||||
free_tiles: Vec::new(),
|
free_tiles: Vec::new(),
|
||||||
size: Vec2::new(1, 1),
|
size: Vec2::new(1, 1),
|
||||||
@ -338,7 +337,7 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
|||||||
/// to have at least 2 bits of the normal; thus, it can only take up at
|
/// to have at least 2 bits of the normal; thus, it can only take up at
|
||||||
/// most 30 bits total, meaning we are restricted to "only" at most 2^15
|
/// most 30 bits total, meaning we are restricted to "only" at most 2^15
|
||||||
/// × 2^15 atlases even if the hardware supports larger ones.
|
/// × 2^15 atlases even if the hardware supports larger ones.
|
||||||
pub fn new(max_size: Vec2<u16>) -> Self {
|
pub fn new(max_size: Vec2<u16>, config: Allocator::Config) -> Self {
|
||||||
span!(_guard, "new", "GreedyMesh::new");
|
span!(_guard, "new", "GreedyMesh::new");
|
||||||
let min_max_dim = max_size.reduce_min();
|
let min_max_dim = max_size.reduce_min();
|
||||||
assert!(
|
assert!(
|
||||||
@ -347,7 +346,7 @@ impl<'a, Allocator: AtlasAllocator> GreedyMesh<'a, Allocator> {
|
|||||||
min_max_dim,
|
min_max_dim,
|
||||||
max_size
|
max_size
|
||||||
);
|
);
|
||||||
let atlas = Allocator::with_max_size(max_size);
|
let atlas = Allocator::with_max_size(max_size, config);
|
||||||
let col_lights_size = Vec2::new(1, 1);
|
let col_lights_size = Vec2::new(1, 1);
|
||||||
Self {
|
Self {
|
||||||
atlas,
|
atlas,
|
||||||
@ -657,7 +656,6 @@ fn add_to_atlas<Allocator: AtlasAllocator>(
|
|||||||
max_size: Vec2<u16>,
|
max_size: Vec2<u16>,
|
||||||
cur_size: &mut Vec2<u16>,
|
cur_size: &mut Vec2<u16>,
|
||||||
) -> guillotiere::Rectangle {
|
) -> guillotiere::Rectangle {
|
||||||
//prof_span!("add_to_atlas");
|
|
||||||
// TODO: Check this conversion.
|
// TODO: Check this conversion.
|
||||||
let atlas_rect = loop {
|
let atlas_rect = loop {
|
||||||
// NOTE: Conversion to u16 is safe because he x, y, and z dimensions for any
|
// NOTE: Conversion to u16 is safe because he x, y, and z dimensions for any
|
||||||
|
@ -388,7 +388,10 @@ pub fn generate_mesh<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug + '
|
|||||||
|atlas_pos, pos, norm, meta| TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta);
|
|atlas_pos, pos, norm, meta| TerrainVertex::new(atlas_pos, pos + mesh_delta, norm, meta);
|
||||||
let create_transparent = |_atlas_pos, pos, norm| FluidVertex::new(pos + mesh_delta, norm);
|
let create_transparent = |_atlas_pos, pos, norm| FluidVertex::new(pos + mesh_delta, norm);
|
||||||
|
|
||||||
let mut greedy = GreedyMesh::<guillotiere::SimpleAtlasAllocator>::new(max_size);
|
let mut greedy = GreedyMesh::<guillotiere::SimpleAtlasAllocator>::new(
|
||||||
|
max_size,
|
||||||
|
crate::mesh::greedy::general_config(),
|
||||||
|
);
|
||||||
let mut opaque_mesh = Mesh::new();
|
let mut opaque_mesh = Mesh::new();
|
||||||
let mut fluid_mesh = Mesh::new();
|
let mut fluid_mesh = Mesh::new();
|
||||||
greedy.push(GreedyConfig {
|
greedy.push(GreedyConfig {
|
||||||
|
@ -93,7 +93,7 @@ impl FigureModel {
|
|||||||
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
// of the atlas coordinates, which is why we "only" allow 1 << 15 per
|
||||||
// coordinate instead of 1 << 16.
|
// coordinate instead of 1 << 16.
|
||||||
let max_size = Vec2::new((1 << 15) - 1, (1 << 15) - 1);
|
let max_size = Vec2::new((1 << 15) - 1, (1 << 15) - 1);
|
||||||
GreedyMesh::new(max_size)
|
GreedyMesh::new(max_size, crate::mesh::greedy::general_config())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1600,7 +1600,7 @@ fn default_cache(renderer: &mut Renderer) -> HashMap<&'static str, Model<Particl
|
|||||||
// particles in a single atlas.
|
// particles in a single atlas.
|
||||||
let max_texture_size = renderer.max_texture_size();
|
let max_texture_size = renderer.max_texture_size();
|
||||||
let max_size = Vec2::from(u16::try_from(max_texture_size).unwrap_or(u16::MAX));
|
let max_size = Vec2::from(u16::try_from(max_texture_size).unwrap_or(u16::MAX));
|
||||||
let mut greedy = GreedyMesh::new(max_size);
|
let mut greedy = GreedyMesh::new(max_size, crate::mesh::greedy::general_config());
|
||||||
|
|
||||||
let segment = Segment::from(&vox.read().0);
|
let segment = Segment::from(&vox.read().0);
|
||||||
let segment_size = segment.size();
|
let segment_size = segment.size();
|
||||||
|
@ -444,7 +444,10 @@ impl SpriteRenderContext {
|
|||||||
Arc::<SpriteSpec>::load_expect("voxygen.voxel.sprite_manifest").cloned();
|
Arc::<SpriteSpec>::load_expect("voxygen.voxel.sprite_manifest").cloned();
|
||||||
|
|
||||||
let max_size = Vec2::from(u16::try_from(max_texture_size).unwrap_or(u16::MAX));
|
let max_size = Vec2::from(u16::try_from(max_texture_size).unwrap_or(u16::MAX));
|
||||||
let mut greedy = GreedyMesh::<SpriteAtlasAllocator>::new(max_size);
|
let mut greedy = GreedyMesh::<SpriteAtlasAllocator>::new(
|
||||||
|
max_size,
|
||||||
|
crate::mesh::greedy::sprite_config(),
|
||||||
|
);
|
||||||
let mut sprite_mesh = Mesh::new();
|
let mut sprite_mesh = Mesh::new();
|
||||||
// NOTE: Tracks the start vertex of the next model to be meshed.
|
// NOTE: Tracks the start vertex of the next model to be meshed.
|
||||||
let sprite_data: HashMap<(SpriteKind, usize), _> = SpriteKind::into_enum_iter()
|
let sprite_data: HashMap<(SpriteKind, usize), _> = SpriteKind::into_enum_iter()
|
||||||
|
Reference in New Issue
Block a user