store sprite data separately for compressed chunks

This commit is contained in:
Maxicarlos08 2024-01-26 10:16:47 +01:00
parent fd2e45cfde
commit e2c2e1bce1
No known key found for this signature in database
2 changed files with 50 additions and 41 deletions

View File

@ -1,5 +1,5 @@
use common::{ use common::{
terrain::{chonk::Chonk, Block, BlockKind, SpriteKind}, terrain::{chonk::Chonk, Block, BlockKind},
vol::{BaseVol, ReadVol, RectVolSize, WriteVol}, vol::{BaseVol, ReadVol, RectVolSize, WriteVol},
volumes::vol_grid_2d::VolGrid2d, volumes::vol_grid_2d::VolGrid2d,
}; };
@ -132,8 +132,7 @@ pub trait VoxelImageEncoding {
x: u32, x: u32,
y: u32, y: u32,
kind: BlockKind, kind: BlockKind,
sprite: SpriteKind, sprite_data: [u8; 3],
ori: Option<u8>,
); );
fn finish(ws: &Self::Workspace) -> Option<Self::Output>; fn finish(ws: &Self::Workspace) -> Option<Self::Output>;
} }
@ -168,10 +167,9 @@ impl<'a, VIE: VoxelImageEncoding> VoxelImageEncoding for &'a VIE {
x: u32, x: u32,
y: u32, y: u32,
kind: BlockKind, kind: BlockKind,
sprite: SpriteKind, sprite_data: [u8; 3],
ori: Option<u8>,
) { ) {
(*self).put_sprite(ws, x, y, kind, sprite, ori) (*self).put_sprite(ws, x, y, kind, sprite_data)
} }
fn finish(ws: &Self::Workspace) -> Option<Self::Output> { VIE::finish(ws) } fn finish(ws: &Self::Workspace) -> Option<Self::Output> { VIE::finish(ws) }
@ -189,12 +187,13 @@ impl<'a, VIE: VoxelImageDecoding> VoxelImageDecoding for &'a VIE {
pub struct QuadPngEncoding<const RESOLUTION_DIVIDER: u32>(); pub struct QuadPngEncoding<const RESOLUTION_DIVIDER: u32>();
impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> { impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
type Output = CompressedData<(Vec<u8>, [usize; 3])>; type Output = CompressedData<(Vec<u8>, [usize; 3], Vec<[u8; 3]>)>;
type Workspace = ( type Workspace = (
ImageBuffer<image::Luma<u8>, Vec<u8>>, ImageBuffer<image::Luma<u8>, Vec<u8>>,
ImageBuffer<image::Luma<u8>, Vec<u8>>, ImageBuffer<image::Luma<u8>, Vec<u8>>,
ImageBuffer<image::Luma<u8>, Vec<u8>>, ImageBuffer<image::Luma<u8>, Vec<u8>>,
ImageBuffer<image::Rgb<u8>, Vec<u8>>, ImageBuffer<image::Rgb<u8>, Vec<u8>>,
Vec<[u8; 3]>,
); );
fn create(width: u32, height: u32) -> Self::Workspace { fn create(width: u32, height: u32) -> Self::Workspace {
@ -203,6 +202,7 @@ impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
ImageBuffer::new(width, height), ImageBuffer::new(width, height),
ImageBuffer::new(width, height), ImageBuffer::new(width, height),
ImageBuffer::new(width / N, height / N), ImageBuffer::new(width / N, height / N),
Vec::new(),
) )
} }
@ -219,12 +219,18 @@ impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
x: u32, x: u32,
y: u32, y: u32,
kind: BlockKind, kind: BlockKind,
sprite: SpriteKind, sprite_data: [u8; 3],
ori: Option<u8>,
) { ) {
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);
ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.0.put_pixel(x, y, image::Luma([kind as u8]));
ws.1.put_pixel(x, y, image::Luma([sprite as u8])); ws.1.put_pixel(x, y, image::Luma([index[0]]));
ws.2.put_pixel(x, y, image::Luma([ori.unwrap_or(0)])); ws.2.put_pixel(x, y, image::Luma([index[1]]));
} }
fn finish(ws: &Self::Workspace) -> Option<Self::Output> { fn finish(ws: &Self::Workspace) -> Option<Self::Output> {
@ -261,7 +267,7 @@ impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
.ok()?; .ok()?;
} }
Some(CompressedData::compress(&(buf, indices), 4)) Some(CompressedData::compress(&(buf, indices, ws.4.clone()), 4))
} }
} }
@ -320,7 +326,7 @@ const fn gen_lanczos_lookup<const N: u32, const R: u32>(
impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> { impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
fn start(data: &Self::Output) -> Option<Self::Workspace> { fn start(data: &Self::Output) -> Option<Self::Workspace> {
use image::codecs::png::PngDecoder; use image::codecs::png::PngDecoder;
let (quad, indices) = data.decompress()?; let (quad, indices, sprite_data) = data.decompress()?;
let ranges: [_; 4] = [ let ranges: [_; 4] = [
0..indices[0], 0..indices[0],
indices[0]..indices[1], indices[0]..indices[1],
@ -331,7 +337,7 @@ impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
let b = image_from_bytes(PngDecoder::new(&quad[ranges[1].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 c = image_from_bytes(PngDecoder::new(&quad[ranges[2].clone()]).ok()?)?;
let d = image_from_bytes(PngDecoder::new(&quad[ranges[3].clone()]).ok()?)?; let d = image_from_bytes(PngDecoder::new(&quad[ranges[3].clone()]).ok()?)?;
Some((a, b, c, d)) Some((a, b, c, d, sprite_data))
} }
fn get_block(ws: &Self::Workspace, x: u32, y: u32, is_border: bool) -> Block { fn get_block(ws: &Self::Workspace, x: u32, y: u32, is_border: bool) -> Block {
@ -444,14 +450,9 @@ impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
b: rgb.z as u8, b: rgb.z as u8,
}) })
} else { } else {
let mut block = Block::new(kind, Rgb { r: 0, g: 0, b: 0 }); let index =
if let Some(spritekind) = SpriteKind::from_u8(ws.1.get_pixel(x, y).0[0]) { u16::from_be_bytes([ws.1.get_pixel(x, y).0[0], ws.2.get_pixel(x, y).0[0]]);
block = block.with_sprite(spritekind); Block::from_raw(kind, ws.4[index as usize])
}
if let Some(oriblock) = block.with_ori(ws.2.get_pixel(x, y).0[0]) {
block = oriblock;
}
block
} }
} else { } else {
Block::empty() Block::empty()
@ -463,12 +464,13 @@ impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
pub struct TriPngEncoding<const AVERAGE_PALETTE: bool>(); pub struct TriPngEncoding<const AVERAGE_PALETTE: bool>();
impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_PALETTE> { impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_PALETTE> {
type Output = CompressedData<(Vec<u8>, Vec<Rgb<u8>>, [usize; 3])>; type Output = CompressedData<(Vec<u8>, Vec<Rgb<u8>>, [usize; 3], Vec<[u8; 3]>)>;
type Workspace = ( type Workspace = (
ImageBuffer<image::Luma<u8>, Vec<u8>>, ImageBuffer<image::Luma<u8>, Vec<u8>>,
ImageBuffer<image::Luma<u8>, Vec<u8>>, ImageBuffer<image::Luma<u8>, Vec<u8>>,
ImageBuffer<image::Luma<u8>, Vec<u8>>, ImageBuffer<image::Luma<u8>, Vec<u8>>,
HashMap<BlockKind, HashMap<Rgb<u8>, usize>>, HashMap<BlockKind, HashMap<Rgb<u8>, usize>>,
Vec<[u8; 3]>,
); );
fn create(width: u32, height: u32) -> Self::Workspace { fn create(width: u32, height: u32) -> Self::Workspace {
@ -477,6 +479,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
ImageBuffer::new(width, height), ImageBuffer::new(width, height),
ImageBuffer::new(width, height), ImageBuffer::new(width, height),
HashMap::new(), HashMap::new(),
Vec::new(),
) )
} }
@ -495,12 +498,18 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
x: u32, x: u32,
y: u32, y: u32,
kind: BlockKind, kind: BlockKind,
sprite: SpriteKind, sprite_data: [u8; 3],
ori: Option<u8>,
) { ) {
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);
ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.0.put_pixel(x, y, image::Luma([kind as u8]));
ws.1.put_pixel(x, y, image::Luma([sprite as u8])); ws.1.put_pixel(x, y, image::Luma([index[0]]));
ws.2.put_pixel(x, y, image::Luma([ori.unwrap_or(0)])); ws.2.put_pixel(x, y, image::Luma([index[1]]));
} }
fn finish(ws: &Self::Workspace) -> Option<Self::Output> { fn finish(ws: &Self::Workspace) -> Option<Self::Output> {
@ -545,14 +554,17 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
Vec::new() Vec::new()
}; };
Some(CompressedData::compress(&(buf, palette, indices), 4)) Some(CompressedData::compress(
&(buf, palette, indices, ws.4.clone()),
4,
))
} }
} }
impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_PALETTE> { impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_PALETTE> {
fn start(data: &Self::Output) -> Option<Self::Workspace> { fn start(data: &Self::Output) -> Option<Self::Workspace> {
use image::codecs::png::PngDecoder; use image::codecs::png::PngDecoder;
let (quad, palette, indices) = data.decompress()?; let (quad, palette, indices, sprite_data) = data.decompress()?;
let ranges: [_; 3] = [ let ranges: [_; 3] = [
0..indices[0], 0..indices[0],
indices[0]..indices[1], indices[0]..indices[1],
@ -573,7 +585,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_
} }
} }
Some((a, b, c, d)) Some((a, b, c, d, sprite_data))
} }
fn get_block(ws: &Self::Workspace, x: u32, y: u32, _: bool) -> Block { fn get_block(ws: &Self::Workspace, x: u32, y: u32, _: bool) -> Block {
@ -662,14 +674,9 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_
}; };
Block::new(kind, rgb) Block::new(kind, rgb)
} else { } else {
let mut block = Block::new(kind, Rgb { r: 0, g: 0, b: 0 }); let index =
if let Some(spritekind) = SpriteKind::from_u8(ws.1.get_pixel(x, y).0[0]) { u16::from_be_bytes([ws.1.get_pixel(x, y).0[0], ws.2.get_pixel(x, y).0[0]]);
block = block.with_sprite(spritekind); Block::from_raw(kind, ws.4[index as usize])
}
if let Some(oriblock) = block.with_ori(ws.2.get_pixel(x, y).0[0]) {
block = oriblock;
}
block
} }
} else { } else {
Block::empty() Block::empty()
@ -754,8 +761,10 @@ pub fn image_terrain<
(Some(rgb), None) => { (Some(rgb), None) => {
VIE::put_solid(vie, &mut image, i, j, *block, rgb); VIE::put_solid(vie, &mut image, i, j, *block, rgb);
}, },
(None, Some(sprite)) => { (None, Some(_)) => {
VIE::put_sprite(vie, &mut image, i, j, *block, sprite, block.get_ori()); let data = block.to_u32().to_be_bytes();
VIE::put_sprite(vie, &mut image, i, j, *block, [data[1], data[2], data[3]]);
}, },
_ => panic!( _ => panic!(
"attr being used for color vs sprite is mutually exclusive (and that's \ "attr being used for color vs sprite is mutually exclusive (and that's \

View File

@ -157,7 +157,7 @@ impl Block {
/* Constructors */ /* Constructors */
#[inline] #[inline]
pub(super) const fn from_raw(kind: BlockKind, data: [u8; 3]) -> Self { Self { kind, data } } pub const fn from_raw(kind: BlockKind, data: [u8; 3]) -> Self { Self { kind, data } }
// TODO: Rename to `filled`, make caller guarantees stronger // TODO: Rename to `filled`, make caller guarantees stronger
#[inline] #[inline]