use crate::meta::attributes::{IntRect};
#[derive(Debug, Clone)]
pub struct Chunk {
pub layer_index: usize,
pub block: Block,
}
#[derive(Debug, Clone)]
pub enum Block {
ScanLine(ScanLineBlock),
Tile(TileBlock),
DeepScanLine(DeepScanLineBlock),
DeepTile(DeepTileBlock),
}
#[derive(Debug, Clone)]
pub struct ScanLineBlock {
pub y_coordinate: i32,
pub compressed_pixels: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct TileBlock {
pub coordinates: TileCoordinates,
pub compressed_pixels: Vec<u8>,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct TileCoordinates {
pub tile_index: Vec2<usize>,
pub level_index: Vec2<usize>,
}
#[derive(Debug, Clone)]
pub struct DeepScanLineBlock {
pub y_coordinate: i32,
pub decompressed_sample_data_size: usize,
pub compressed_pixel_offset_table: Vec<i8>,
pub compressed_sample_data: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct DeepTileBlock {
pub coordinates: TileCoordinates,
pub decompressed_sample_data_size: usize,
pub compressed_pixel_offset_table: Vec<i8>,
pub compressed_sample_data: Vec<u8>,
}
use crate::io::*;
impl TileCoordinates {
pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
i32::write(usize_to_i32(self.tile_index.0), write)?;
i32::write(usize_to_i32(self.tile_index.1), write)?;
i32::write(usize_to_i32(self.level_index.0), write)?;
i32::write(usize_to_i32(self.level_index.1), write)?;
Ok(())
}
pub fn read(read: &mut impl Read) -> Result<Self> {
let tile_x = i32::read(read)?;
let tile_y = i32::read(read)?;
let level_x = i32::read(read)?;
let level_y = i32::read(read)?;
if level_x > 31 || level_y > 31 {
return Err(Error::invalid("level index exceeding integer maximum"));
}
Ok(TileCoordinates {
tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?,
level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")?
})
}
pub fn to_data_indices(&self, tile_size: Vec2<usize>, max: Vec2<usize>) -> Result<IntRect> {
let start = self.tile_index * tile_size;
Ok(IntRect {
position: start.to_i32(), size: Vec2(
calculate_block_size(max.0, tile_size.0, start.0)?,
calculate_block_size(max.1, tile_size.0, start.1)?,
),
})
}
pub fn to_absolute_indices(&self, tile_size: Vec2<usize>, data_window: IntRect) -> Result<IntRect> {
let data = self.to_data_indices(tile_size, data_window.size)?;
Ok(data.with_origin(data_window.position))
}
pub fn is_largest_resolution_level(&self) -> bool {
self.level_index == Vec2(0, 0)
}
}
use crate::meta::{Header, MetaData, Blocks, calculate_block_size};
impl ScanLineBlock {
pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug");
i32::write(self.y_coordinate, write)?;
u8::write_i32_sized_slice(write, &self.compressed_pixels)?;
Ok(())
}
pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
let y_coordinate = i32::read(read)?;
let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size))?;
Ok(ScanLineBlock { y_coordinate, compressed_pixels })
}
}
impl TileBlock {
pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug");
self.coordinates.write(write)?;
u8::write_i32_sized_slice(write, &self.compressed_pixels)?;
Ok(())
}
pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
let coordinates = TileCoordinates::read(read)?;
let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size))?;
Ok(TileBlock { coordinates, compressed_pixels })
}
}
impl DeepScanLineBlock {
pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
debug_assert_ne!(self.compressed_sample_data.len(), 0, "empty blocks should not be put in the file bug");
i32::write(self.y_coordinate, write)?;
u64::write(self.compressed_pixel_offset_table.len() as u64, write)?;
u64::write(self.compressed_sample_data.len() as u64, write)?; u64::write(self.decompressed_sample_data_size as u64, write)?;
i8::write_slice(write, &self.compressed_pixel_offset_table)?;
u8::write_slice(write, &self.compressed_sample_data)?;
Ok(())
}
pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
let y_coordinate = i32::read(read)?;
let compressed_pixel_offset_table_size = u64_to_usize(u64::read(read)?);
let compressed_sample_data_size = u64_to_usize(u64::read(read)?);
let decompressed_sample_data_size = u64_to_usize(u64::read(read)?);
let compressed_pixel_offset_table = i8::read_vec(
read, compressed_pixel_offset_table_size,
6 * std::u16::MAX as usize, Some(max_block_byte_size)
)?;
let compressed_sample_data = u8::read_vec(
read, compressed_sample_data_size,
6 * std::u16::MAX as usize, Some(max_block_byte_size)
)?;
Ok(DeepScanLineBlock {
y_coordinate,
decompressed_sample_data_size,
compressed_pixel_offset_table,
compressed_sample_data,
})
}
}
impl DeepTileBlock {
pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
debug_assert_ne!(self.compressed_sample_data.len(), 0, "empty blocks should not be put in the file bug");
self.coordinates.write(write)?;
u64::write(self.compressed_pixel_offset_table.len() as u64, write)?;
u64::write(self.compressed_sample_data.len() as u64, write)?; u64::write(self.decompressed_sample_data_size as u64, write)?;
i8::write_slice(write, &self.compressed_pixel_offset_table)?;
u8::write_slice(write, &self.compressed_sample_data)?;
Ok(())
}
pub fn read(read: &mut impl Read, hard_max_block_byte_size: usize) -> Result<Self> {
let coordinates = TileCoordinates::read(read)?;
let compressed_pixel_offset_table_size = u64_to_usize(u64::read(read)?);
let compressed_sample_data_size = u64_to_usize(u64::read(read)?); let decompressed_sample_data_size = u64_to_usize(u64::read(read)?);
let compressed_pixel_offset_table = i8::read_vec(
read, compressed_pixel_offset_table_size,
6 * std::u16::MAX as usize, Some(hard_max_block_byte_size)
)?;
let compressed_sample_data = u8::read_vec(
read, compressed_sample_data_size,
6 * std::u16::MAX as usize, Some(hard_max_block_byte_size)
)?;
Ok(DeepTileBlock {
coordinates,
decompressed_sample_data_size,
compressed_pixel_offset_table,
compressed_sample_data,
})
}
}
use crate::error::{UnitResult, Result, Error, u64_to_usize, usize_to_i32};
use crate::math::Vec2;
impl Chunk {
pub fn write(&self, write: &mut impl Write, headers: &[Header]) -> UnitResult {
debug_assert!(self.layer_index < headers.len(), "layer index bug");
if headers.len() != 1 { i32::write(self.layer_index as i32, write)?; }
else { assert_eq!(self.layer_index, 0); }
match self.block {
Block::ScanLine (ref value) => value.write(write),
Block::Tile (ref value) => value.write(write),
Block::DeepScanLine (ref value) => value.write(write),
Block::DeepTile (ref value) => value.write(write),
}
}
pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> {
let layer_number = {
if meta_data.requirements.is_multilayer() { i32::read(read)? } else { 0_i32 } };
if layer_number < 0 || layer_number >= meta_data.headers.len() as i32 {
return Err(Error::invalid("chunk data part number"));
}
let layer_number = layer_number as usize;
let header = &meta_data.headers[layer_number];
let max_block_byte_size = header.max_block_byte_size();
let chunk = Chunk {
layer_index: layer_number,
block: match header.blocks {
Blocks::ScanLines if !header.deep => Block::ScanLine(ScanLineBlock::read(read, max_block_byte_size)?),
Blocks::Tiles(_) if !header.deep => Block::Tile(TileBlock::read(read, max_block_byte_size)?),
Blocks::ScanLines => Block::DeepScanLine(DeepScanLineBlock::read(read, max_block_byte_size)?),
Blocks::Tiles(_) => Block::DeepTile(DeepTileBlock::read(read, max_block_byte_size)?),
},
};
Ok(chunk)
}
}