pub mod sheet;
use self::sheet::SheetPatternTable;
use self::sheet::Sheet::*;
use std::error;
use std::fmt;
use std::io;
type PNGError = ::lodepng::ffi::Error;
#[derive(Debug)]
pub enum Error {
PNGError(PNGError),
DimensionsError(String),
PaletteError(String),
FormatError(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output: &str = match self {
&Error::PNGError(ref err) => err.as_str(),
&Error::DimensionsError(ref err) => &err,
&Error::PaletteError(ref err) => &err,
&Error::FormatError(ref err) => &err,
};
write!(f, "{}", output)
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self {
&Error::PNGError(ref err) => err.as_str(),
&Error::DimensionsError(ref err) => &err,
&Error::PaletteError(ref err) => &err,
&Error::FormatError(ref err) => &err,
}
}
}
#[derive(Clone, Debug)]
pub struct Tile {
pub name: Option<String>,
pub data: [u8; 16],
}
impl Tile {
pub fn iter(&self) -> TileIterator {
TileIterator {
row: 0,
tile: self,
}
}
pub fn from_bytes(bytes: &[u8], name: Option<&str>) -> Result<Tile, Error> {
if bytes.len() != 64 {
return Err(Error::DimensionsError(
format!("Need bytes array of size 64, got {}", bytes.len())
));
}
if let Some(item) = bytes.iter().find(|&&item| item > 3) {
return Err(Error::PaletteError(
format!("Byte out of bounds; needs to be under 4, got {}.", item)
));
}
let bytepairs: Vec<[u8; 2]> = bytes.chunks(8).map(|row| {
let byte1 =
(row[0] & 1) << 7
| (row[1] & 1) << 6
| (row[2] & 1) << 5
| (row[3] & 1) << 4
| (row[4] & 1) << 3
| (row[5] & 1) << 2
| (row[6] & 1) << 1
| row[7] & 1;
let byte2 =
(row[0] & 2) << 6
| (row[1] & 2) << 5
| (row[2] & 2) << 4
| (row[3] & 2) << 3
| (row[4] & 2) << 2
| (row[5] & 2) << 1
| row[6] & 2
| (row[7] & 2) >> 1;
[byte1, byte2]
}).collect();
let first_bytes: Vec<u8> = bytepairs.iter().map(|pair| pair.first().unwrap()).cloned().collect();
let second_bytes: Vec<u8> = bytepairs.iter().map(|pair| pair.last().unwrap()).cloned().collect();
let bytes: Vec<u8> = first_bytes.iter().chain(second_bytes.iter()).cloned().collect();
let mut data: [u8; 16] = [0; 16];
data.clone_from_slice(&bytes);
let new_name = match name {
Some(name) => Some(String::from(name)),
None => None
};
Ok(Tile {
name: new_name,
data,
})
}
}
pub struct TileIterator<'a> {
row: u8,
tile: &'a Tile,
}
impl<'a> Iterator for TileIterator<'a> {
type Item = TileRowIterator;
fn next(&mut self) -> Option<TileRowIterator> {
let row = self.row as usize;
self.row += 1;
if row > 7 {
return None;
}
let byte1 = self.tile.data[row];
let byte2 = self.tile.data[row + 8];
Some(TileRowIterator {
column: 0,
bytes: (byte1, byte2),
})
}
}
pub struct TileRowIterator {
column: u8,
bytes: (u8, u8),
}
impl Iterator for TileRowIterator {
type Item = u8;
fn next(&mut self) -> Option<u8> {
let column = self.column;
self.column += 1;
if column > 7 {
return None;
}
let andmask: u8 = 1 << (7 - column);
let first = (andmask & self.bytes.0) >> (7 - column);
let second = (andmask & self.bytes.1) >> (7 - column) << 1;
Some(first | second)
}
}
pub struct PatternTable {
pub left: Vec<Tile>,
pub right: Vec<Tile>,
}
impl PatternTable {
pub fn from_sheet_pattern_table(sheet_table: SheetPatternTable) -> Result<PatternTable, Error> {
let mut left = Vec::new();
let mut right = Vec::new();
for sheet in sheet_table.left {
let tiles = match sheet {
Animation(sprite) => sprite.pull_tiles(),
Slice(sprite) => sprite.pull_tiles(),
Simple(sprite) => sprite.pull_tiles(),
Fill(sprite) => sprite.pull_tiles(),
}?;
left.extend(tiles.into_iter());
}
for sheet in sheet_table.right {
let tiles = match sheet {
Animation(sprite) => sprite.pull_tiles(),
Slice(sprite) => sprite.pull_tiles(),
Simple(sprite) => sprite.pull_tiles(),
Fill(sprite) => sprite.pull_tiles(),
}?;
right.extend(tiles.into_iter());
}
if left.len() > 256 {
return Err(Error::DimensionsError(format!(
"left table contained too many tiles. Can not exceed 256, but has {}",
left.len())));
}
if right.len() > 256 {
return Err(Error::DimensionsError(format!(
"right table contained too many tiles. Can not exceed 256, but has {}",
right.len())));
}
let blank = Tile {name: None, data: [0u8; 16]};
while left.len() < 256 {
left.push(blank.clone());
}
while right.len() < 256 {
right.push(blank.clone());
}
Ok(PatternTable {
left,
right
})
}
pub fn write<T: io::Write>(&self, writer: &mut T) -> Result<(), io::Error>{
for ref tile in &self.left {
writer.write(&tile.data)?;
}
for ref tile in &self.right {
writer.write(&tile.data)?;
}
Ok(())
}
}