use color::default_color_index;
use data::IldaEntry;
use error::IldaError;
use parser::read_bytes;
use parser::read_file;
use point::SimplePoint;
#[derive(Clone)]
pub struct Animation {
frames: Vec<Frame>,
}
#[derive(Clone)]
pub struct Frame {
points: Vec<SimplePoint>,
frame_name: Option<String>,
company_name: Option<String>,
}
impl Animation {
pub fn read_file(filename: &str) -> Result<Animation, IldaError> {
let entries = read_file(filename)?;
Animation::process_entries(entries)
}
pub fn read_bytes(ilda_bytes: &[u8]) -> Result<Animation, IldaError> {
let entries = read_bytes(ilda_bytes)?;
Animation::process_entries(entries)
}
pub fn into_frame_iter<'a>(&'a self) -> AnimationFrameIterator<'a> {
AnimationFrameIterator { animation: self, index: 0 }
}
pub fn into_point_iter<'a>(&'a self) -> AnimationPointIterator<'a> {
AnimationPointIterator {
animation: self,
current_frame: self.frames.get(0),
frame_index: 0,
point_index: 0,
}
}
pub fn get_frames(&self) -> &Vec<Frame> {
&self.frames
}
pub fn frame_count(&self) -> usize {
self.frames.len()
}
pub fn get_frame(&self, position: usize) -> Option<&Frame> {
self.frames.get(position)
}
fn process_entries(entries: Vec<IldaEntry>) -> Result<Animation, IldaError> {
let mut frames = Vec::new();
let mut current_frame = None;
for entry in entries {
match entry {
IldaEntry::HeaderEntry(mut header) => {
if current_frame.is_some() {
let frame = current_frame.take().unwrap();
frames.push(frame);
}
current_frame = Some(Frame {
points: Vec::new(),
frame_name: header.name.take(),
company_name: header.company_name.take(),
});
continue;
},
_ => {},
}
let mut frame = match current_frame {
None => return Err(IldaError::InvalidData),
Some(ref mut frame) => frame,
};
let point = ilda_entry_to_point(entry)?;
frame.points.push(point);
}
match current_frame.take() {
None => {},
Some(frame) => frames.push(frame),
}
if frames.is_empty() {
return Err(IldaError::NoData);
}
Ok(Animation {
frames: frames,
})
}
}
pub fn ilda_entry_to_point(entry: IldaEntry) -> Result<SimplePoint, IldaError> {
match entry {
IldaEntry::HeaderEntry(_) => {
Err(IldaError::InvalidData)
},
IldaEntry::ColorPaletteEntry(_) => {
Err(IldaError::Unsupported)
},
IldaEntry::TcPoint2dEntry(point) => {
Ok(SimplePoint {
x: point.x,
y: point.y,
r: point.r,
g: point.g,
b: point.b,
is_blank: point.is_blank(),
})
},
IldaEntry::TcPoint3dEntry(point) => {
Ok(SimplePoint {
x: point.x,
y: point.y,
r: point.r,
g: point.g,
b: point.b,
is_blank: point.is_blank(),
})
},
IldaEntry::IdxPoint2dEntry(point) => {
let color = default_color_index(point.color_index);
Ok(SimplePoint {
x: point.x,
y: point.y,
r: color.r,
g: color.g,
b: color.b,
is_blank: point.is_blank(),
})
},
IldaEntry::IdxPoint3dEntry(point) => {
let color = default_color_index(point.color_index);
Ok(SimplePoint {
x: point.x,
y: point.y,
r: color.r,
g: color.g,
b: color.b,
is_blank: point.is_blank(),
})
},
}
}
impl Frame {
pub fn get_points(&self) -> &Vec<SimplePoint> {
&self.points
}
pub fn point_count(&self) -> usize {
self.points.len()
}
pub fn get_point(&self, position: usize) -> Option<&SimplePoint> {
self.points.get(position)
}
}
pub struct AnimationFrameIterator<'a> {
animation: &'a Animation,
index: usize,
}
pub struct AnimationPointIterator<'a> {
animation: &'a Animation,
current_frame: Option<&'a Frame>, frame_index: usize,
point_index: usize,
}
impl <'a> AnimationPointIterator<'a> {
fn next_point_for_frame(&mut self) -> Option<&'a SimplePoint> {
match self.current_frame {
None => return None, Some(frame) => {
match frame.get_point(self.point_index) {
Some(point) => {
self.point_index += 1;
Some(point)
},
None => None,
}
},
}
}
fn next_frame(&mut self) -> Option<&'a Frame> {
self.frame_index += 1;
self.point_index = 0;
self.current_frame = self.animation.get_frame(self.frame_index);
self.current_frame
}
}
pub struct FramePointIterator<'a> {
frame: &'a Frame,
index: usize,
}
impl<'a> IntoIterator for &'a Frame {
type IntoIter = FramePointIterator<'a>;
type Item = &'a SimplePoint;
fn into_iter(self) -> Self::IntoIter {
FramePointIterator { frame: self, index: 0 }
}
}
impl<'a> Iterator for AnimationFrameIterator<'a> {
type Item = &'a Frame;
fn next(&mut self) -> Option<Self::Item> {
let item = self.animation.get_frame(self.index);
self.index += 1;
item
}
}
impl<'a> Iterator for AnimationPointIterator<'a> {
type Item = &'a SimplePoint;
fn next(&mut self) -> Option<Self::Item> {
self.next_point_for_frame().or_else(|| {
self.next_frame();
self.next_point_for_frame()
})
}
}
impl<'a> Iterator for FramePointIterator<'a> {
type Item = &'a SimplePoint;
fn next(&mut self) -> Option<Self::Item> {
let item = self.frame.get_point(self.index);
self.index += 1;
item
}
}
#[cfg(test)]
mod tests {
use super::*;
use data::IldaEntry;
use data::IndexedPoint2d;
use data::TrueColorPoint2d;
#[test]
fn test_animation_frame_iterator() {
fn frame(num_points: usize) -> Frame {
let mut points = Vec::new();
for _i in 0..num_points {
points.push(SimplePoint::default());
}
Frame {
points: points,
frame_name: None,
company_name: None,
}
}
let animation = Animation {
frames: vec![frame(1), frame(2), frame(3)],
};
let mut iter = animation.into_frame_iter();
let frame = iter.next();
assert!(frame.is_some());
assert_eq!(1, frame.unwrap().point_count());
let frame = iter.next();
assert!(frame.is_some());
assert_eq!(2, frame.unwrap().point_count());
let frame = iter.next();
assert!(frame.is_some());
assert_eq!(3, frame.unwrap().point_count());
let frame = iter.next();
assert!(frame.is_none());
}
#[test]
fn test_animation_point_iterator() {
let frame1 = frame(vec![point(0), point(1), point(2)]);
let frame2 = frame(vec![point(3), point(4)]);
let frame3 = frame(vec![point(5)]);
let frame4 = frame(vec![point(6), point(7)]);
let animation = Animation {
frames: vec![frame1, frame2, frame3, frame4],
};
let values: Vec<_> = animation.into_point_iter()
.map(|point| point.r)
.collect();
let expected = vec![0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(expected, values);
}
#[test]
fn test_frame_point_iterator() {
let frame = frame(vec![point(0), point(1), point(2), point(3), point(4)]);
let values: Vec<_> = frame.into_iter()
.map(|point| point.r)
.collect();
let expected = vec![0, 1, 2, 3, 4];
assert_eq!(expected, values);
}
#[test]
fn test_ilda_entry_to_point_true_color() {
let ilda_point = TrueColorPoint2d::default();
let entry = IldaEntry::TcPoint2dEntry(ilda_point);
let point = ilda_entry_to_point(entry).unwrap();
assert_eq!(point.r, 0);
assert_eq!(point.g, 0);
assert_eq!(point.b, 0);
assert_eq!(point.x, 0);
assert_eq!(point.y, 0);
assert_eq!(point.is_blank, false);
let mut ilda_point = TrueColorPoint2d::default();
ilda_point.r = 255;
ilda_point.g = 127;
ilda_point.b = 32;
ilda_point.x = 10_000;
ilda_point.y = -10_000;
ilda_point.status_code = 64;
let entry = IldaEntry::TcPoint2dEntry(ilda_point);
let point = ilda_entry_to_point(entry).unwrap();
assert_eq!(point.r, 255);
assert_eq!(point.g, 127);
assert_eq!(point.b, 32);
assert_eq!(point.x, 10_000);
assert_eq!(point.y, -10_000);
assert_eq!(point.is_blank, true);
}
#[test]
fn test_ilda_entry_to_point_indexed() {
let ilda_point = IndexedPoint2d::default();
let entry = IldaEntry::IdxPoint2dEntry(ilda_point);
let point = ilda_entry_to_point(entry).unwrap();
assert_eq!(point.r, 255); assert_eq!(point.g, 0);
assert_eq!(point.b, 0);
assert_eq!(point.x, 0);
assert_eq!(point.y, 0);
assert_eq!(point.is_blank, false);
let mut ilda_point = IndexedPoint2d::default();
ilda_point.x = 10_000;
ilda_point.y = -10_000;
ilda_point.status_code = 64;
ilda_point.color_index = 57;
let entry = IldaEntry::IdxPoint2dEntry(ilda_point);
let point = ilda_entry_to_point(entry).unwrap();
assert_eq!(point.r, 255);
assert_eq!(point.g, 224);
assert_eq!(point.b, 224);
assert_eq!(point.x, 10_000);
assert_eq!(point.y, -10_000);
assert_eq!(point.is_blank, true);
}
fn point(color: u8) -> SimplePoint {
SimplePoint {
x: 0,
y: 0,
r: color,
g: color,
b: color,
is_blank: false,
}
}
fn frame(points: Vec<SimplePoint>) -> Frame {
Frame {
points: points,
frame_name: None,
company_name: None,
}
}
}