Add resolution downscaling to QuadPng's color channel, and use half-resolution QuadPng ingame.

This commit is contained in:
Avi Weinstock 2021-04-23 21:31:06 -04:00
parent f81539cb00
commit a220cc569e
4 changed files with 113 additions and 27 deletions

View File

@ -316,7 +316,6 @@ impl VoxelImageDecoding for MixedEncoding {
indices[1]..indices[2],
indices[2]..quad.len(),
];
tracing::info!("{:?} {:?}", ranges, indices);
let a = image_from_bytes(PngDecoder::new(&quad[ranges[0].clone()]).ok()?)?;
let b = image_from_bytes(PngDecoder::new(&quad[ranges[1].clone()]).ok()?)?;
let c = image_from_bytes(PngDecoder::new(&quad[ranges[2].clone()]).ok()?)?;
@ -350,9 +349,9 @@ impl VoxelImageDecoding for MixedEncoding {
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct QuadPngEncoding;
pub struct QuadPngEncoding<const RESOLUTION_DIVIDER: u32>();
impl VoxelImageEncoding for QuadPngEncoding {
impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
type Output = CompressedData<(Vec<u8>, [usize; 3])>;
#[allow(clippy::type_complexity)]
type Workspace = (
@ -367,7 +366,7 @@ impl VoxelImageEncoding for QuadPngEncoding {
ImageBuffer::new(width, height),
ImageBuffer::new(width, height),
ImageBuffer::new(width, height),
ImageBuffer::new(width, height),
ImageBuffer::new(width / N, height / N),
)
}
@ -375,7 +374,7 @@ impl VoxelImageEncoding for QuadPngEncoding {
ws.0.put_pixel(x, y, image::Luma([kind as u8]));
ws.1.put_pixel(x, y, image::Luma([0]));
ws.2.put_pixel(x, y, image::Luma([0]));
ws.3.put_pixel(x, y, image::Rgb([rgb.r, rgb.g, rgb.b]));
ws.3.put_pixel(x / N, y / N, image::Rgb([rgb.r, rgb.g, rgb.b]));
}
fn put_sprite(
@ -389,7 +388,6 @@ impl VoxelImageEncoding for QuadPngEncoding {
ws.0.put_pixel(x, y, image::Luma([kind as u8]));
ws.1.put_pixel(x, y, image::Luma([sprite as u8]));
ws.2.put_pixel(x, y, image::Luma([ori.unwrap_or(0)]));
ws.3.put_pixel(x, y, image::Rgb([0; 3]));
}
fn finish(ws: &Self::Workspace) -> Option<Self::Output> {
@ -430,6 +428,48 @@ impl VoxelImageEncoding for QuadPngEncoding {
}
}
impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
fn start(data: &Self::Output) -> Option<Self::Workspace> {
use image::codecs::png::PngDecoder;
let (quad, indices) = data.decompress()?;
let ranges: [_; 4] = [
0..indices[0],
indices[0]..indices[1],
indices[1]..indices[2],
indices[2]..quad.len(),
];
let a = image_from_bytes(PngDecoder::new(&quad[ranges[0].clone()]).ok()?)?;
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))
}
fn get_block(ws: &Self::Workspace, x: u32, y: u32) -> Block {
if let Some(kind) = BlockKind::from_u8(ws.0.get_pixel(x, y).0[0]) {
if kind.is_filled() {
let rgb = ws.3.get_pixel(x / N, y / N);
Block::new(kind, Rgb {
r: rgb[0],
g: rgb[1],
b: rgb[2],
})
} else {
let mut block = Block::new(kind, Rgb { r: 0, g: 0, b: 0 });
if let Some(spritekind) = SpriteKind::from_u8(ws.1.get_pixel(x, y).0[0]) {
block = block.with_sprite(spritekind);
}
if let Some(oriblock) = block.with_ori(ws.2.get_pixel(x, y).0[0]) {
block = oriblock;
}
block
}
} else {
Block::empty()
}
}
}
pub fn image_terrain_chonk<S: RectVolSize, M: Clone, P: PackingFormula, VIE: VoxelImageEncoding>(
vie: VIE,
packing: P,
@ -480,7 +520,6 @@ pub fn image_terrain<
lo: Vec3<u32>,
hi: Vec3<u32>,
) -> Option<VIE::Output> {
tracing::info!("image_terrain: {:?} {:?}", lo, hi);
let dims = Vec3::new(
hi.x.wrapping_sub(lo.x),
hi.y.wrapping_sub(lo.y),

View File

@ -9,7 +9,7 @@ pub use self::{
client::{ClientGeneral, ClientMsg, ClientRegister, ClientType},
compression::{
CompressedData, GridLtrPacking, JpegEncoding, MixedEncoding, PackingFormula, PngEncoding,
TallPacking, VoxelImageEncoding, WireChonk,
QuadPngEncoding, TallPacking, VoxelImageEncoding, WireChonk,
},
ecs_packet::EcsCompPacket,
server::{

View File

@ -1,6 +1,6 @@
use super::{
world_msg::EconomyInfo, ClientType, CompressedData, EcsCompPacket, MixedEncoding, PingMsg,
TallPacking, WireChonk,
QuadPngEncoding, TallPacking, WireChonk,
};
use crate::sync;
use common::{
@ -70,6 +70,7 @@ pub type ServerRegisterAnswer = Result<(), RegisterError>;
pub enum SerializedTerrainChunk {
DeflatedChonk(CompressedData<TerrainChunk>),
PngPngPngJpeg(WireChonk<MixedEncoding, TallPacking, TerrainChunkMeta, TerrainChunkSize>),
QuadPng(WireChonk<QuadPngEncoding<2>, TallPacking, TerrainChunkMeta, TerrainChunkSize>),
}
impl SerializedTerrainChunk {
@ -77,7 +78,7 @@ impl SerializedTerrainChunk {
Self::DeflatedChonk(CompressedData::compress(chunk, 5))
}
pub fn image(chunk: &TerrainChunk) -> Self {
pub fn jpeg(chunk: &TerrainChunk) -> Self {
if let Some(wc) = WireChonk::from_chonk(MixedEncoding, TallPacking { flip_y: true }, chunk)
{
Self::PngPngPngJpeg(wc)
@ -87,10 +88,22 @@ impl SerializedTerrainChunk {
}
}
pub fn image(chunk: &TerrainChunk) -> Self {
if let Some(wc) =
WireChonk::from_chonk(QuadPngEncoding(), TallPacking { flip_y: true }, chunk)
{
Self::QuadPng(wc)
} else {
warn!("Image encoding failure occurred, falling back to deflate");
Self::deflate(chunk)
}
}
pub fn to_chunk(&self) -> Option<TerrainChunk> {
match self {
Self::DeflatedChonk(chonk) => chonk.decompress(),
Self::PngPngPngJpeg(wc) => wc.to_chonk(),
Self::QuadPng(wc) => wc.to_chonk(),
}
}
}

View File

@ -1,16 +1,15 @@
use common::{
spiral::Spiral2d,
terrain::{chonk::Chonk, Block, BlockKind, SpriteKind},
vol::{BaseVol, IntoVolIterator, ReadVol, RectVolSize, SizedVol, WriteVol},
vol::{IntoVolIterator, RectVolSize, SizedVol, WriteVol},
volumes::{
dyna::{Access, ColumnAccess, Dyna},
vol_grid_2d::VolGrid2d,
},
};
use common_net::msg::compression::{
image_terrain, image_terrain_chonk, image_terrain_volgrid, CompressedData, GridLtrPacking,
JpegEncoding, MixedEncoding, PackingFormula, PngEncoding, QuadPngEncoding, TallPacking,
VoxelImageEncoding,
image_terrain_chonk, image_terrain_volgrid, CompressedData, GridLtrPacking, JpegEncoding,
MixedEncoding, PngEncoding, QuadPngEncoding, TallPacking, VoxelImageEncoding,
};
use hashbrown::HashMap;
use image::ImageBuffer;
@ -329,8 +328,8 @@ fn main() {
));
for (sitename, sitepos) in sites.iter() {
let mut totals = [0.0; 13];
let mut total_timings = [0.0; 10];
let mut totals = [0.0; 15];
let mut total_timings = [0.0; 12];
let mut count = 0;
let mut volgrid = VolGrid2d::new().unwrap();
for (i, spiralpos) in Spiral2d::new()
@ -420,11 +419,32 @@ fn main() {
.unwrap();
let mixeddense_post = Instant::now();
let quadpng_pre = Instant::now();
let quadpng =
image_terrain_chonk(QuadPngEncoding, TallPacking { flip_y: true }, &chunk)
.unwrap();
let quadpng_post = Instant::now();
let quadpngfull_pre = Instant::now();
let quadpngfull = image_terrain_chonk(
QuadPngEncoding::<1>(),
TallPacking { flip_y: true },
&chunk,
)
.unwrap();
let quadpngfull_post = Instant::now();
let quadpnghalf_pre = Instant::now();
let quadpnghalf = image_terrain_chonk(
QuadPngEncoding::<2>(),
TallPacking { flip_y: true },
&chunk,
)
.unwrap();
let quadpnghalf_post = Instant::now();
let quadpngquart_pre = Instant::now();
let quadpngquart = image_terrain_chonk(
QuadPngEncoding::<4>(),
TallPacking { flip_y: true },
&chunk,
)
.unwrap();
let quadpngquart_post = Instant::now();
let pngchonk_pre = Instant::now();
let pngchonk = image_terrain_chonk(PngEncoding, GridLtrPacking, &chunk).unwrap();
@ -443,7 +463,9 @@ fn main() {
mixedchonk.0.len() as f32 / n as f32,
mixeddeflate.data.len() as f32 / n as f32,
mixeddense.0.len() as f32 / n as f32,
quadpng.data.len() as f32 / n as f32,
quadpngfull.data.len() as f32 / n as f32,
quadpnghalf.data.len() as f32 / n as f32,
quadpngquart.data.len() as f32 / n as f32,
pngchonk.len() as f32 / n as f32,
];
let best_idx = sizes
@ -466,7 +488,9 @@ fn main() {
(mixedchonk_post - mixedchonk_pre).subsec_nanos(),
(mixeddeflate_post - mixedchonk_pre).subsec_nanos(),
(mixeddense_post - mixeddense_pre).subsec_nanos(),
(quadpng_post - quadpng_pre).subsec_nanos(),
(quadpngfull_post - quadpngfull_pre).subsec_nanos(),
(quadpnghalf_post - quadpnghalf_pre).subsec_nanos(),
(quadpngquart_post - quadpngquart_pre).subsec_nanos(),
(pngchonk_post - pngchonk_pre).subsec_nanos(),
];
trace!(
@ -542,8 +566,10 @@ fn main() {
println!("Average mixedchonk: {}", totals[8] / count as f32);
println!("Average mixeddeflate: {}", totals[9] / count as f32);
println!("Average mixeddense: {}", totals[10] / count as f32);
println!("Average quadpng: {}", totals[11] / count as f32);
println!("Average pngchonk: {}", totals[12] / count as f32);
println!("Average quadpngfull: {}", totals[11] / count as f32);
println!("Average quadpnghalf: {}", totals[12] / count as f32);
println!("Average quadpngquart: {}", totals[13] / count as f32);
println!("Average pngchonk: {}", totals[14] / count as f32);
println!("");
println!(
"Average lz4_chonk nanos : {:02}",
@ -578,13 +604,21 @@ fn main() {
total_timings[7] / count as f32
);
println!(
"Average quadpng nanos: {:02}",
"Average quadpngfull nanos: {:02}",
total_timings[8] / count as f32
);
println!(
"Average pngchonk nanos: {:02}",
"Average quadpnghalf nanos: {:02}",
total_timings[9] / count as f32
);
println!(
"Average quadpngquart nanos: {:02}",
total_timings[10] / count as f32
);
println!(
"Average pngchonk nanos: {:02}",
total_timings[11] / count as f32
);
println!("-----");
}
if i % 256 == 0 {