mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
optimize sprites in compressed chunks
This commit is contained in:
parent
b4ac1f7036
commit
c5ddf73dc2
@ -184,9 +184,11 @@ impl<'a, VIE: VoxelImageDecoding> VoxelImageDecoding for &'a VIE {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct QuadPngEncoding<const RESOLUTION_DIVIDER: u32>();
|
||||
pub struct QuadPngEncoding<const RESOLUTION_DIVIDER: u32, const HASH_CONS_SPRITES: bool>();
|
||||
|
||||
impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
|
||||
impl<const N: u32, const HASH_CONS_SPRITES: bool> VoxelImageEncoding
|
||||
for QuadPngEncoding<N, HASH_CONS_SPRITES>
|
||||
{
|
||||
type Output = CompressedData<(Vec<u8>, [usize; 3], Vec<[u8; 3]>)>;
|
||||
type Workspace = (
|
||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||
@ -194,6 +196,7 @@ impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
|
||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||
ImageBuffer<image::Rgb<u8>, Vec<u8>>,
|
||||
Vec<[u8; 3]>,
|
||||
HashMap<[u8; 3], u16>,
|
||||
);
|
||||
|
||||
fn create(width: u32, height: u32) -> Self::Workspace {
|
||||
@ -203,6 +206,7 @@ impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
|
||||
ImageBuffer::new(width, height),
|
||||
ImageBuffer::new(width / N, height / N),
|
||||
Vec::new(),
|
||||
HashMap::new(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -221,12 +225,24 @@ impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
|
||||
kind: BlockKind,
|
||||
sprite_data: [u8; 3],
|
||||
) {
|
||||
let index: u16 =
|
||||
ws.4.len()
|
||||
.try_into()
|
||||
.expect("Cannot have more than 2^16 sprites in one chunk");
|
||||
let index = index.to_be_bytes();
|
||||
ws.4.push(sprite_data);
|
||||
let index = if HASH_CONS_SPRITES {
|
||||
let index = ws.5.entry(sprite_data).or_insert_with(|| {
|
||||
let index =
|
||||
ws.4.len()
|
||||
.try_into()
|
||||
.expect("Cannot have more than 2^16 sprites in one chunk");
|
||||
ws.4.push(sprite_data);
|
||||
index
|
||||
});
|
||||
index.to_be_bytes()
|
||||
} else {
|
||||
let index: u16 =
|
||||
ws.4.len()
|
||||
.try_into()
|
||||
.expect("Cannot have more than 2^16 sprites in one chunk");
|
||||
ws.4.push(sprite_data);
|
||||
index.to_be_bytes()
|
||||
};
|
||||
|
||||
ws.0.put_pixel(x, y, image::Luma([kind as u8]));
|
||||
ws.1.put_pixel(x, y, image::Luma([index[0]]));
|
||||
@ -323,7 +339,9 @@ const fn gen_lanczos_lookup<const N: u32, const R: u32>(
|
||||
array
|
||||
}
|
||||
|
||||
impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
|
||||
impl<const N: u32, const HASH_CONS_SPRITES: bool> VoxelImageDecoding
|
||||
for QuadPngEncoding<N, HASH_CONS_SPRITES>
|
||||
{
|
||||
fn start(data: &Self::Output) -> Option<Self::Workspace> {
|
||||
use image::codecs::png::PngDecoder;
|
||||
let (quad, indices, sprite_data) = data.decompress()?;
|
||||
@ -337,7 +355,7 @@ impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
|
||||
let b = image_from_bytes(PngDecoder::new(&quad[ranges[1].clone()]).ok()?)?;
|
||||
let c = image_from_bytes(PngDecoder::new(&quad[ranges[2].clone()]).ok()?)?;
|
||||
let d = image_from_bytes(PngDecoder::new(&quad[ranges[3].clone()]).ok()?)?;
|
||||
Some((a, b, c, d, sprite_data))
|
||||
Some((a, b, c, d, sprite_data, HashMap::new()))
|
||||
}
|
||||
|
||||
fn get_block(ws: &Self::Workspace, x: u32, y: u32, is_border: bool) -> Block {
|
||||
@ -461,9 +479,11 @@ impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct TriPngEncoding<const AVERAGE_PALETTE: bool>();
|
||||
pub struct TriPngEncoding<const AVERAGE_PALETTE: bool, const HASH_CONS_SPRITES: bool>();
|
||||
|
||||
impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_PALETTE> {
|
||||
impl<const AVERAGE_PALETTE: bool, const HASH_CONS_SPRITES: bool> VoxelImageEncoding
|
||||
for TriPngEncoding<AVERAGE_PALETTE, HASH_CONS_SPRITES>
|
||||
{
|
||||
type Output = CompressedData<(Vec<u8>, Vec<Rgb<u8>>, [usize; 3], Vec<[u8; 3]>)>;
|
||||
type Workspace = (
|
||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||
@ -471,6 +491,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
|
||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||
HashMap<BlockKind, HashMap<Rgb<u8>, usize>>,
|
||||
Vec<[u8; 3]>,
|
||||
HashMap<[u8; 3], u16>,
|
||||
);
|
||||
|
||||
fn create(width: u32, height: u32) -> Self::Workspace {
|
||||
@ -480,6 +501,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
|
||||
ImageBuffer::new(width, height),
|
||||
HashMap::new(),
|
||||
Vec::new(),
|
||||
HashMap::new(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -500,12 +522,24 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
|
||||
kind: BlockKind,
|
||||
sprite_data: [u8; 3],
|
||||
) {
|
||||
let index: u16 =
|
||||
ws.4.len()
|
||||
.try_into()
|
||||
.expect("Cannot have more than 2^16 sprites in one chunk");
|
||||
let index = index.to_be_bytes();
|
||||
ws.4.push(sprite_data);
|
||||
let index = if HASH_CONS_SPRITES {
|
||||
let index = ws.5.entry(sprite_data).or_insert_with(|| {
|
||||
let index =
|
||||
ws.4.len()
|
||||
.try_into()
|
||||
.expect("Cannot have more than 2^16 sprites in one chunk");
|
||||
ws.4.push(sprite_data);
|
||||
index
|
||||
});
|
||||
index.to_be_bytes()
|
||||
} else {
|
||||
let index: u16 =
|
||||
ws.4.len()
|
||||
.try_into()
|
||||
.expect("Cannot have more than 2^16 sprites in one chunk");
|
||||
ws.4.push(sprite_data);
|
||||
index.to_be_bytes()
|
||||
};
|
||||
|
||||
ws.0.put_pixel(x, y, image::Luma([kind as u8]));
|
||||
ws.1.put_pixel(x, y, image::Luma([index[0]]));
|
||||
@ -561,7 +595,9 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
|
||||
}
|
||||
}
|
||||
|
||||
impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_PALETTE> {
|
||||
impl<const AVERAGE_PALETTE: bool, const HASH_CONS_SPRITE: bool> VoxelImageDecoding
|
||||
for TriPngEncoding<AVERAGE_PALETTE, HASH_CONS_SPRITE>
|
||||
{
|
||||
fn start(data: &Self::Output) -> Option<Self::Workspace> {
|
||||
use image::codecs::png::PngDecoder;
|
||||
let (quad, palette, indices, sprite_data) = data.decompress()?;
|
||||
@ -585,7 +621,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_
|
||||
}
|
||||
}
|
||||
|
||||
Some((a, b, c, d, sprite_data))
|
||||
Some((a, b, c, d, sprite_data, HashMap::new()))
|
||||
}
|
||||
|
||||
fn get_block(ws: &Self::Workspace, x: u32, y: u32, _: bool) -> Block {
|
||||
|
@ -83,8 +83,17 @@ pub type ServerRegisterAnswer = Result<(), RegisterError>;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum SerializedTerrainChunk {
|
||||
DeflatedChonk(CompressedData<TerrainChunk>),
|
||||
QuadPng(WireChonk<QuadPngEncoding<4>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>),
|
||||
TriPng(WireChonk<TriPngEncoding<false>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>),
|
||||
QuadPng(
|
||||
WireChonk<QuadPngEncoding<4, true>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>,
|
||||
),
|
||||
TriPng(
|
||||
WireChonk<
|
||||
TriPngEncoding<false, true>,
|
||||
WidePacking<true>,
|
||||
TerrainChunkMeta,
|
||||
TerrainChunkSize,
|
||||
>,
|
||||
),
|
||||
}
|
||||
|
||||
impl SerializedTerrainChunk {
|
||||
|
@ -21,6 +21,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
io::{Read, Write},
|
||||
mem,
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
@ -980,10 +981,33 @@ fn main() {
|
||||
let pngchonk_post = Instant::now();
|
||||
|
||||
sizes.extend_from_slice(&[
|
||||
("jpegchonkgrid", jpegchonkgrid.0.len() as f32 / n as f32),
|
||||
("jpegchonktall", jpegchonktall.0.len() as f32 / n as f32),
|
||||
("jpegchonkflip", jpegchonkflip.0.len() as f32 / n as f32),
|
||||
("pngchonk", pngchonk.0.len() as f32 / n as f32),
|
||||
(
|
||||
"jpegchonkgrid",
|
||||
(jpegchonkgrid.0.len()
|
||||
+ jpegchonkgrid.1.len() * mem::size_of::<[u8; 3]>())
|
||||
as f32
|
||||
/ n as f32,
|
||||
),
|
||||
(
|
||||
"jpegchonktall",
|
||||
(jpegchonktall.0.len()
|
||||
+ jpegchonktall.1.len() * mem::size_of::<[u8; 3]>())
|
||||
as f32
|
||||
/ n as f32,
|
||||
),
|
||||
(
|
||||
"jpegchonkflip",
|
||||
(jpegchonkflip.0.len()
|
||||
+ jpegchonkflip.1.len() * mem::size_of::<[u8; 3]>())
|
||||
as f32
|
||||
/ n as f32,
|
||||
),
|
||||
(
|
||||
"pngchonk",
|
||||
(pngchonk.0.len() + pngchonk.1.len() * mem::size_of::<[u8; 3]>())
|
||||
as f32
|
||||
/ n as f32,
|
||||
),
|
||||
]);
|
||||
#[rustfmt::skip]
|
||||
timings.extend_from_slice(&[
|
||||
@ -1026,7 +1050,7 @@ fn main() {
|
||||
|
||||
let quadpngfull_pre = Instant::now();
|
||||
let quadpngfull = image_terrain_chonk(
|
||||
&QuadPngEncoding::<1>(),
|
||||
&QuadPngEncoding::<1, true>(),
|
||||
TallPacking { flip_y: true },
|
||||
&chunk,
|
||||
)
|
||||
@ -1035,7 +1059,7 @@ fn main() {
|
||||
|
||||
let quadpnghalf_pre = Instant::now();
|
||||
let quadpnghalf = image_terrain_chonk(
|
||||
&QuadPngEncoding::<2>(),
|
||||
&QuadPngEncoding::<2, true>(),
|
||||
TallPacking { flip_y: true },
|
||||
&chunk,
|
||||
)
|
||||
@ -1044,30 +1068,55 @@ fn main() {
|
||||
|
||||
let quadpngquarttall_pre = Instant::now();
|
||||
let quadpngquarttall = image_terrain_chonk(
|
||||
&QuadPngEncoding::<4>(),
|
||||
&QuadPngEncoding::<4, false>(),
|
||||
TallPacking { flip_y: true },
|
||||
&chunk,
|
||||
)
|
||||
.unwrap();
|
||||
let quadpngquarttall_post = Instant::now();
|
||||
let quadpngquarttallhash_pre = Instant::now();
|
||||
let quadpngquarttallhash = image_terrain_chonk(
|
||||
&QuadPngEncoding::<4, true>(),
|
||||
TallPacking { flip_y: true },
|
||||
&chunk,
|
||||
)
|
||||
.unwrap();
|
||||
let quadpngquarttallhash_post = Instant::now();
|
||||
|
||||
let quadpngquartwide_pre = Instant::now();
|
||||
let quadpngquartwide =
|
||||
image_terrain_chonk(&QuadPngEncoding::<4>(), WidePacking::<true>(), &chunk)
|
||||
.unwrap();
|
||||
let quadpngquartwide = image_terrain_chonk(
|
||||
&QuadPngEncoding::<4, true>(),
|
||||
WidePacking::<true>(),
|
||||
&chunk,
|
||||
)
|
||||
.unwrap();
|
||||
let quadpngquartwide_post = Instant::now();
|
||||
|
||||
let tripngaverage_pre = Instant::now();
|
||||
let tripngaverage =
|
||||
image_terrain_chonk(&TriPngEncoding::<true>(), WidePacking::<true>(), &chunk)
|
||||
.unwrap();
|
||||
let tripngaverage = image_terrain_chonk(
|
||||
&TriPngEncoding::<true, true>(),
|
||||
WidePacking::<true>(),
|
||||
&chunk,
|
||||
)
|
||||
.unwrap();
|
||||
let tripngaverage_post = Instant::now();
|
||||
|
||||
let tripngconst_pre = Instant::now();
|
||||
let tripngconst =
|
||||
image_terrain_chonk(&TriPngEncoding::<false>(), WidePacking::<true>(), &chunk)
|
||||
.unwrap();
|
||||
let tripngconst_post = Instant::now();
|
||||
let tripngconstbump_pre = Instant::now();
|
||||
let tripngconstbump = image_terrain_chonk(
|
||||
&TriPngEncoding::<false, false>(),
|
||||
WidePacking::<true>(),
|
||||
&chunk,
|
||||
)
|
||||
.unwrap();
|
||||
let tripngconstbump_post = Instant::now();
|
||||
let tripngconsthash_pre = Instant::now();
|
||||
let tripngconsthash = image_terrain_chonk(
|
||||
&TriPngEncoding::<false, true>(),
|
||||
WidePacking::<true>(),
|
||||
&chunk,
|
||||
)
|
||||
.unwrap();
|
||||
let tripngconsthash_post = Instant::now();
|
||||
|
||||
let palette_kdtree_pre = Instant::now();
|
||||
let palette_kdtree = image_terrain_chonk(
|
||||
@ -1092,9 +1141,11 @@ fn main() {
|
||||
("quadpngfull", quadpngfull.data.len() as f32 / n as f32),
|
||||
("quadpnghalf", quadpnghalf.data.len() as f32 / n as f32),
|
||||
("quadpngquarttall", quadpngquarttall.data.len() as f32 / n as f32),
|
||||
("quadpngquarttallhash", quadpngquarttallhash.data.len() as f32 / n as f32),
|
||||
("quadpngquartwide", quadpngquartwide.data.len() as f32 / n as f32),
|
||||
("tripngaverage", tripngaverage.data.len() as f32 / n as f32),
|
||||
("tripngconst", tripngconst.data.len() as f32 / n as f32),
|
||||
("tripngconstbump", tripngconstbump.data.len() as f32 / n as f32),
|
||||
("tripngconsthash", tripngconsthash.data.len() as f32 / n as f32),
|
||||
("palette_kdtree", palette_kdtree.data.len() as f32 / n as f32),
|
||||
("palette_rtree", palette_rtree.data.len() as f32 / n as f32),
|
||||
]);
|
||||
@ -1114,9 +1165,11 @@ fn main() {
|
||||
("quadpngfull", (quadpngfull_post - quadpngfull_pre).subsec_nanos()),
|
||||
("quadpnghalf", (quadpnghalf_post - quadpnghalf_pre).subsec_nanos()),
|
||||
("quadpngquarttall", (quadpngquarttall_post - quadpngquarttall_pre).subsec_nanos()),
|
||||
("quadpngquarttallhash", (quadpngquarttallhash_post - quadpngquarttallhash_pre).subsec_nanos()),
|
||||
("quadpngquartwide", (quadpngquartwide_post - quadpngquartwide_pre).subsec_nanos()),
|
||||
("tripngaverage", (tripngaverage_post - tripngaverage_pre).subsec_nanos()),
|
||||
("tripngconst", (tripngconst_post - tripngconst_pre).subsec_nanos()),
|
||||
("tripngconstbump", (tripngconstbump_post - tripngconstbump_pre).subsec_nanos()),
|
||||
("tripngconsthash", (tripngconsthash_post - tripngconsthash_pre).subsec_nanos()),
|
||||
("palette_kdtree", (palette_kdtree_post - palette_kdtree_pre).subsec_nanos()),
|
||||
("palette_rtree", (palette_rtree_post - palette_rtree_pre).subsec_nanos()),
|
||||
]);
|
||||
@ -1156,7 +1209,7 @@ fn main() {
|
||||
.entry(chunk.get_max_z() - chunk.get_min_z())
|
||||
.or_insert((0, 0.0));
|
||||
bucket.0 += 1;
|
||||
bucket.1 += (tripngconst_post - tripngconst_pre).subsec_nanos() as f32;
|
||||
bucket.1 += (tripngconstbump_post - tripngconstbump_pre).subsec_nanos() as f32;
|
||||
}
|
||||
if true {
|
||||
let bucket = z_buckets
|
||||
|
Loading…
Reference in New Issue
Block a user