use error::IldaError;
pub const HEADER_SIZE : usize = 32;
pub const COLOR_PALETTE_SIZE: usize = 3;
pub const INDEXED_2D_DATA_SIZE: usize = 6;
pub const INDEXED_3D_DATA_SIZE: usize = 8;
pub const TRUE_COLOR_2D_DATA_SIZE: usize = 8;
pub const TRUE_COLOR_3D_DATA_SIZE: usize = 10;
#[allow(missing_docs)]
pub enum Format {
Unknown,
ColorPalette,
Indexed2d,
Indexed3d,
TrueColor2d,
TrueColor3d,
}
#[derive(Clone, Debug)]
pub struct Header {
pub reserved: u16,
pub format_code: u8,
pub name: Option<String>,
pub company_name: Option<String>,
pub record_count: u16,
pub number: u16,
pub total_frames: u16,
pub projector_number: u8,
pub reserved_2: u8,
}
impl Header {
pub fn get_format(&self) -> Format {
match self.format_code {
0u8 => Format::Indexed3d,
1u8 => Format::Indexed2d,
2u8 => Format::ColorPalette,
4u8 => Format::TrueColor3d,
5u8 => Format::TrueColor2d,
_ => Format::Unknown,
}
}
}
#[derive(Clone, Debug, Default)]
pub struct IndexedPoint3d {
pub x: i16,
pub y: i16,
pub z: i16,
pub status_code: u8,
pub color_index: u8,
}
impl IndexedPoint3d {
pub fn read_bytes(bytes: &[u8])
-> Result<Vec<IndexedPoint3d>, IldaError> {
if bytes.len() % INDEXED_3D_DATA_SIZE != 0 {
return Err(IldaError::InvalidData);
}
let size = bytes.len() / INDEXED_3D_DATA_SIZE;
let mut out = Vec::with_capacity(size);
for i in 0..size {
let j = i * INDEXED_3D_DATA_SIZE;
out.push(IndexedPoint3d {
x: read_i16(&bytes[j .. j+2]),
y: read_i16(&bytes[j+2 .. j+4]),
z: read_i16(&bytes[j+4 .. j+6]),
status_code: bytes[j+6],
color_index: bytes[j+7],
});
}
Ok(out)
}
pub fn is_blank(&self) -> bool {
self.status_code & 64 == 64
}
}
#[derive(Clone, Debug, Default)]
pub struct IndexedPoint2d {
pub x: i16,
pub y: i16,
pub status_code: u8,
pub color_index: u8,
}
impl IndexedPoint2d {
pub fn read_bytes(bytes: &[u8])
-> Result<Vec<IndexedPoint2d>, IldaError> {
if bytes.len() % INDEXED_2D_DATA_SIZE != 0 {
return Err(IldaError::InvalidData);
}
let size = bytes.len() / INDEXED_2D_DATA_SIZE;
let mut out = Vec::with_capacity(size);
for i in 0..size {
let j = i * INDEXED_2D_DATA_SIZE;
out.push(IndexedPoint2d {
x: read_i16(&bytes[j .. j+2]),
y: read_i16(&bytes[j+2 .. j+4]),
status_code: bytes[j+4],
color_index: bytes[j+5],
});
}
Ok(out)
}
pub fn is_blank(&self) -> bool {
self.status_code & 64 == 64
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ColorPalette {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl ColorPalette {
pub fn read_bytes(bytes: &[u8]) -> Result<Vec<ColorPalette>, IldaError> {
if bytes.len() % COLOR_PALETTE_SIZE != 0 {
return Err(IldaError::InvalidData);
}
let size = bytes.len() / COLOR_PALETTE_SIZE;
let mut out = Vec::with_capacity(size);
for i in 0..size {
let j = i * COLOR_PALETTE_SIZE;
out.push(ColorPalette {
r: bytes[j],
g: bytes[j+1],
b: bytes[j+2],
});
}
Ok(out)
}
}
#[derive(Clone, Debug, Default)]
pub struct TrueColorPoint3d {
pub x: i16,
pub y: i16,
pub z: i16,
pub status_code: u8,
pub b: u8,
pub g: u8,
pub r: u8,
}
impl TrueColorPoint3d {
pub fn read_bytes(bytes: &[u8])
-> Result<Vec<TrueColorPoint3d>, IldaError> {
if bytes.len() % TRUE_COLOR_3D_DATA_SIZE != 0 {
return Err(IldaError::InvalidData);
}
let size = bytes.len() / TRUE_COLOR_3D_DATA_SIZE;
let mut out = Vec::with_capacity(size);
for i in 0..size {
let j = i * TRUE_COLOR_3D_DATA_SIZE;
out.push(TrueColorPoint3d {
x: read_i16(&bytes[j .. j+2]),
y: read_i16(&bytes[j+2 .. j+4]),
z: read_i16(&bytes[j+4 .. j+6]),
status_code: bytes[j+6],
b: bytes[7],
g: bytes[8],
r: bytes[9],
});
}
Ok(out)
}
pub fn is_blank(&self) -> bool {
self.status_code & 64 == 64
}
}
#[derive(Clone, Debug, Default)]
pub struct TrueColorPoint2d {
pub x: i16,
pub y: i16,
pub status_code: u8,
pub b: u8,
pub g: u8,
pub r: u8,
}
impl TrueColorPoint2d {
pub fn read_bytes(bytes: &[u8])
-> Result<Vec<TrueColorPoint2d>, IldaError> {
if bytes.len() % TRUE_COLOR_2D_DATA_SIZE != 0 {
return Err(IldaError::InvalidData);
}
let size = bytes.len() / TRUE_COLOR_2D_DATA_SIZE;
let mut out = Vec::with_capacity(size);
for i in 0..size {
let j = i * TRUE_COLOR_2D_DATA_SIZE;
out.push(TrueColorPoint2d {
x: read_i16(&bytes[j .. j+2]),
y: read_i16(&bytes[j+2 .. j+4]),
status_code: bytes[j+4],
b: bytes[j+5],
g: bytes[j+6],
r: bytes[j+7],
});
}
Ok(out)
}
pub fn is_blank(&self) -> bool {
self.status_code & 64 == 64
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum IldaEntry {
HeaderEntry(Header),
TcPoint3dEntry(TrueColorPoint3d),
TcPoint2dEntry(TrueColorPoint2d),
ColorPaletteEntry(ColorPalette),
IdxPoint3dEntry(IndexedPoint3d),
IdxPoint2dEntry(IndexedPoint2d),
}
fn read_i16(bytes: &[u8]) -> i16 {
(((bytes[0] as u16) << 8) | (bytes[1] as u16)) as i16
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_indexed_2d_blanking_bit() {
let mut point = IndexedPoint2d::default();
point.status_code = 0;
assert_eq!(false, point.is_blank());
point.status_code = 128;
assert_eq!(false, point.is_blank());
point.status_code = 64;
assert_eq!(true, point.is_blank());
point.status_code = 255;
assert_eq!(true, point.is_blank());
}
#[test]
fn test_indexed_3d_blanking_bit() {
let mut point = IndexedPoint3d::default();
point.status_code = 0;
assert_eq!(false, point.is_blank());
point.status_code = 128;
assert_eq!(false, point.is_blank());
point.status_code = 64;
assert_eq!(true, point.is_blank());
point.status_code = 255;
assert_eq!(true, point.is_blank());
}
#[test]
fn test_truecolor_2d_blanking_bit() {
let mut point = TrueColorPoint2d::default();
point.status_code = 0;
assert_eq!(false, point.is_blank());
point.status_code = 128;
assert_eq!(false, point.is_blank());
point.status_code = 64;
assert_eq!(true, point.is_blank());
point.status_code = 255;
assert_eq!(true, point.is_blank());
}
#[test]
fn test_truecolor_3d_blanking_bit() {
let mut point = TrueColorPoint3d::default();
point.status_code = 0;
assert_eq!(false, point.is_blank());
point.status_code = 128;
assert_eq!(false, point.is_blank());
point.status_code = 64;
assert_eq!(true, point.is_blank());
point.status_code = 255;
assert_eq!(true, point.is_blank());
}
}