<commit_before>use types::{Point};
use std::io::prelude::*;
use std::mem;
use std::fmt;
use byteorder::{self,ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian};
use error::Error;

#[derive(PartialEq, Clone, Debug)]
pub struct EwkbPoint {
    pub x: f64,
    pub y: f64,
    pub srid: Option<i32>,
}

#[derive(PartialEq, Clone, Debug)]
pub struct EwkbLineString {
    pub points: Vec<EwkbPoint>,
    pub srid: Option<i32>,
}

pub trait EwkbGeometryType: fmt::Debug + Sized {
    type PointType: Point;

    fn opt_srid(&self) -> Option<i32> {
        None
    }
    fn set_srid(&mut self, _srid: Option<i32>) {
    }

    fn type_id(&self) -> u32;

    fn read_ewkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
        let byte_order = try!(raw.read_i8());
        let is_be = byte_order == 0i8;

        let type_id = try!(read_u32(raw, is_be));
        let mut srid: Option<i32> = None;
        if type_id & 0x20000000 == 0x20000000 {
           srid = Some(try!(read_i32(raw, is_be)));
        }
        let ewkb = Self::read_ewkb_body(raw, is_be);
        ewkb.map(|mut val| { val.set_srid(srid); val } )
    }

    fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error>;

    fn write_ewkb<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        // use LE
        try!(w.write_u8(0x01));
        let type_id = self.type_id();
        try!(w.write_u32::<LittleEndian>(type_id));
        self.opt_srid().map(|srid| w.write_i32::<LittleEndian>(srid));
        try!(self.write_ewkb_body(w));
        Ok(())
    }
    fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error>;

    fn to_hex_ewkb(&self) -> String {
        let mut buf: Vec<u8> = Vec::new();
        let _ = self.write_ewkb(&mut buf).unwrap();
        let hex: String = buf.iter().fold(String::new(), |s, &b| s + &format!("{:02X}", b));
        hex
    }
}

impl From<byteorder::Error> for Error {
    fn from(e: byteorder::Error) -> Error {
        Error::Read(format!("error while reading: {:?}", e))
    }
}

fn read_u32<R: Read>(raw: &mut R, is_be: bool) -> Result<u32, Error> {
    Ok(try!(
        if is_be { raw.read_u32::<BigEndian>() }
        else { raw.read_u32::<LittleEndian>() }
        ))
}

fn read_i32<R: Read>(raw: &mut R, is_be: bool) -> Result<i32, Error> {
    Ok(try!(
        if is_be { raw.read_i32::<BigEndian>() }
        else { raw.read_i32::<LittleEndian>() }
        ))
}

fn read_f64<R: Read>(raw: &mut R, is_be: bool) -> Result<f64, Error> {
    Ok(try!(
        if is_be { raw.read_f64::<BigEndian>() }
        else { raw.read_f64::<LittleEndian>() }
        ))
}

impl EwkbPoint {
    fn has_z() -> bool { false }
    fn has_m() -> bool { false }
    fn wkb_type_id(has_srid: bool) -> u32 {
        let mut type_ = 0x0000_0001_u32;
        if has_srid {
            type_ |= 0x20000000;
        }
        if Self::has_z() {
            type_ |= 0x80000000;
        }
        if Self::has_m() {
            type_ != 0x40000000;
        }
        type_
    }
    fn new_from_opt_vals(x: f64, y: f64, _z: Option<f64>, _m: Option<f64>) -> Self {
        EwkbPoint { x: x, y: y, srid: None }
    }
}

impl Point for EwkbPoint {
    fn x(&self) -> f64 {
        unsafe { *mem::transmute::<_, *const f64>(self) }
    }
    fn y(&self) -> f64 {
        unsafe { *mem::transmute::<_, *const f64>(self).offset(1) }
    }
}

impl EwkbGeometryType for EwkbPoint {
    type PointType = EwkbPoint;

    fn opt_srid(&self) -> Option<i32> {
        self.srid
    }
    fn set_srid(&mut self, srid: Option<i32>) {
        self.srid = srid;
    }
    fn type_id(&self) -> u32 {
        Self::wkb_type_id(self.opt_srid().is_some())
    }
    fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error> {
        let x = try!(read_f64(raw, is_be));
        let y = try!(read_f64(raw, is_be));
        let z = if Self::has_z() {
            Some(try!(read_f64(raw, is_be)))
        } else {
            None
        };
        let m = if Self::has_m() {
            Some(try!(read_f64(raw, is_be)))
        } else {
            None
        };
        Ok(Self::new_from_opt_vals(x, y, z, m))
    }

    fn write_ewkb<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        // use LE
        try!(w.write_u8(0x01));
        try!(w.write_u32::<LittleEndian>(self.type_id()));
        self.opt_srid().map(|srid| w.write_i32::<LittleEndian>(srid));
        try!(self.write_ewkb_body(w));
        Ok(())
    }

    fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        // lol
        let x = unsafe { *mem::transmute::<_, *const f64>(self) };
        let y = unsafe { *mem::transmute::<_, *const f64>(self).offset(1) };
        try!(w.write_f64::<LittleEndian>(x));
        try!(w.write_f64::<LittleEndian>(y));
        self.opt_z().map(|z| w.write_f64::<LittleEndian>(z));
        self.opt_m().map(|m| w.write_f64::<LittleEndian>(m));
        Ok(())
    }
}

impl EwkbGeometryType for EwkbLineString {
    type PointType = EwkbPoint;

    fn opt_srid(&self) -> Option<i32> {
        self.srid
    }
    fn set_srid(&mut self, srid: Option<i32>) {
        self.srid = srid;
    }

    fn type_id(&self) -> u32 {
        let type_id = EwkbPoint::wkb_type_id(self.opt_srid().is_some());
        (type_id & 0xffff_ff00) | 0x02
    }

    fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error> {
        let mut points: Vec<EwkbPoint> = vec![];
        let size = try!(read_u32(raw, is_be)) as usize;
        for _ in 0..size {
            points.push(EwkbPoint::read_ewkb_body(raw, is_be).unwrap());
        }
        Ok(EwkbLineString {points: points, srid: None})
    }

    fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        try!(w.write_u32::<LittleEndian>(self.points.len() as u32));
        for point in self.points.iter() {
            let wkb = EwkbPoint { x: point.x, y: point.y, srid: None };
            try!(wkb.write_ewkb_body(w));
        }
        Ok(())
    }
}

#[test]
fn test_geom_to_wkb() {
    // 'POINT (10 -20)'
    let point = EwkbPoint { x: 10.0, y: -20.0, srid: None };
    assert_eq!(point.to_hex_ewkb(), "0101000000000000000000244000000000000034C0");

    // 'SRID=4326;POINT (10 -20)'
    let point = EwkbPoint { x: 10.0, y: -20.0, srid: Some(4326) };
    assert_eq!(point.to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");

    let p = |x, y| EwkbPoint { x: x, y: y, srid: None };
    // 'LINESTRING (10 -20, -0 -0.5)'
    let line = EwkbLineString {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
    assert_eq!(line.to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");

    // 'SRID=4326;LINESTRING (10 -20, -0 -0.5)'
    let line = EwkbLineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
    assert_eq!(line.to_hex_ewkb(), "0102000020E610000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}

#[test]
fn test_wkb_to_geom() {
    // 'POINT (10 -20)'
    let mut point_ewkb: &[u8] = &[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192];
    let point = EwkbPoint::read_ewkb(&mut point_ewkb).unwrap();
    assert_eq!(point.to_hex_ewkb(), "0101000000000000000000244000000000000034C0");

    // 'LINESTRING (10 -20, -0 -0.5)'
    let mut line_ewkb: &[u8] = &[1, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 191];
    let line = EwkbLineString::read_ewkb(&mut line_ewkb).unwrap();
    assert_eq!(line.to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}
<commit_msg>Duplicate write_ewkb method removed<commit_after>use types::{Point};
use std::io::prelude::*;
use std::mem;
use std::fmt;
use byteorder::{self,ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian};
use error::Error;

#[derive(PartialEq, Clone, Debug)]
pub struct EwkbPoint {
    pub x: f64,
    pub y: f64,
    pub srid: Option<i32>,
}

#[derive(PartialEq, Clone, Debug)]
pub struct EwkbLineString {
    pub points: Vec<EwkbPoint>,
    pub srid: Option<i32>,
}

pub trait EwkbGeometryType: fmt::Debug + Sized {
    type PointType: Point;

    fn opt_srid(&self) -> Option<i32> {
        None
    }
    fn set_srid(&mut self, _srid: Option<i32>) {
    }

    fn type_id(&self) -> u32;

    fn read_ewkb<R: Read>(raw: &mut R) -> Result<Self, Error> {
        let byte_order = try!(raw.read_i8());
        let is_be = byte_order == 0i8;

        let type_id = try!(read_u32(raw, is_be));
        let mut srid: Option<i32> = None;
        if type_id & 0x20000000 == 0x20000000 {
           srid = Some(try!(read_i32(raw, is_be)));
        }
        let ewkb = Self::read_ewkb_body(raw, is_be);
        ewkb.map(|mut val| { val.set_srid(srid); val } )
    }

    fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error>;

    fn write_ewkb<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        // use LE
        try!(w.write_u8(0x01));
        let type_id = self.type_id();
        try!(w.write_u32::<LittleEndian>(type_id));
        self.opt_srid().map(|srid| w.write_i32::<LittleEndian>(srid));
        try!(self.write_ewkb_body(w));
        Ok(())
    }
    fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error>;

    fn to_hex_ewkb(&self) -> String {
        let mut buf: Vec<u8> = Vec::new();
        let _ = self.write_ewkb(&mut buf).unwrap();
        let hex: String = buf.iter().fold(String::new(), |s, &b| s + &format!("{:02X}", b));
        hex
    }
}

impl From<byteorder::Error> for Error {
    fn from(e: byteorder::Error) -> Error {
        Error::Read(format!("error while reading: {:?}", e))
    }
}

fn read_u32<R: Read>(raw: &mut R, is_be: bool) -> Result<u32, Error> {
    Ok(try!(
        if is_be { raw.read_u32::<BigEndian>() }
        else { raw.read_u32::<LittleEndian>() }
        ))
}

fn read_i32<R: Read>(raw: &mut R, is_be: bool) -> Result<i32, Error> {
    Ok(try!(
        if is_be { raw.read_i32::<BigEndian>() }
        else { raw.read_i32::<LittleEndian>() }
        ))
}

fn read_f64<R: Read>(raw: &mut R, is_be: bool) -> Result<f64, Error> {
    Ok(try!(
        if is_be { raw.read_f64::<BigEndian>() }
        else { raw.read_f64::<LittleEndian>() }
        ))
}

impl EwkbPoint {
    fn has_z() -> bool { false }
    fn has_m() -> bool { false }
    fn wkb_type_id(has_srid: bool) -> u32 {
        let mut type_ = 0x0000_0001_u32;
        if has_srid {
            type_ |= 0x20000000;
        }
        if Self::has_z() {
            type_ |= 0x80000000;
        }
        if Self::has_m() {
            type_ != 0x40000000;
        }
        type_
    }
    fn new_from_opt_vals(x: f64, y: f64, _z: Option<f64>, _m: Option<f64>) -> Self {
        EwkbPoint { x: x, y: y, srid: None }
    }
}

impl Point for EwkbPoint {
    fn x(&self) -> f64 {
        unsafe { *mem::transmute::<_, *const f64>(self) }
    }
    fn y(&self) -> f64 {
        unsafe { *mem::transmute::<_, *const f64>(self).offset(1) }
    }
}

impl EwkbGeometryType for EwkbPoint {
    type PointType = EwkbPoint;

    fn opt_srid(&self) -> Option<i32> {
        self.srid
    }
    fn set_srid(&mut self, srid: Option<i32>) {
        self.srid = srid;
    }
    fn type_id(&self) -> u32 {
        Self::wkb_type_id(self.opt_srid().is_some())
    }
    fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error> {
        let x = try!(read_f64(raw, is_be));
        let y = try!(read_f64(raw, is_be));
        let z = if Self::has_z() {
            Some(try!(read_f64(raw, is_be)))
        } else {
            None
        };
        let m = if Self::has_m() {
            Some(try!(read_f64(raw, is_be)))
        } else {
            None
        };
        Ok(Self::new_from_opt_vals(x, y, z, m))
    }

    fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        // lol
        let x = unsafe { *mem::transmute::<_, *const f64>(self) };
        let y = unsafe { *mem::transmute::<_, *const f64>(self).offset(1) };
        try!(w.write_f64::<LittleEndian>(x));
        try!(w.write_f64::<LittleEndian>(y));
        self.opt_z().map(|z| w.write_f64::<LittleEndian>(z));
        self.opt_m().map(|m| w.write_f64::<LittleEndian>(m));
        Ok(())
    }
}

impl EwkbGeometryType for EwkbLineString {
    type PointType = EwkbPoint;

    fn opt_srid(&self) -> Option<i32> {
        self.srid
    }
    fn set_srid(&mut self, srid: Option<i32>) {
        self.srid = srid;
    }

    fn type_id(&self) -> u32 {
        let type_id = EwkbPoint::wkb_type_id(self.opt_srid().is_some());
        (type_id & 0xffff_ff00) | 0x02
    }

    fn read_ewkb_body<R: Read>(raw: &mut R, is_be: bool) -> Result<Self, Error> {
        let mut points: Vec<EwkbPoint> = vec![];
        let size = try!(read_u32(raw, is_be)) as usize;
        for _ in 0..size {
            points.push(EwkbPoint::read_ewkb_body(raw, is_be).unwrap());
        }
        Ok(EwkbLineString {points: points, srid: None})
    }

    fn write_ewkb_body<W: Write+?Sized>(&self, w: &mut W) -> Result<(), Error> {
        try!(w.write_u32::<LittleEndian>(self.points.len() as u32));
        for point in self.points.iter() {
            let wkb = EwkbPoint { x: point.x, y: point.y, srid: None };
            try!(wkb.write_ewkb_body(w));
        }
        Ok(())
    }
}

#[test]
fn test_geom_to_wkb() {
    // 'POINT (10 -20)'
    let point = EwkbPoint { x: 10.0, y: -20.0, srid: None };
    assert_eq!(point.to_hex_ewkb(), "0101000000000000000000244000000000000034C0");

    // 'SRID=4326;POINT (10 -20)'
    let point = EwkbPoint { x: 10.0, y: -20.0, srid: Some(4326) };
    assert_eq!(point.to_hex_ewkb(), "0101000020E6100000000000000000244000000000000034C0");

    let p = |x, y| EwkbPoint { x: x, y: y, srid: None };
    // 'LINESTRING (10 -20, -0 -0.5)'
    let line = EwkbLineString {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
    assert_eq!(line.to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");

    // 'SRID=4326;LINESTRING (10 -20, -0 -0.5)'
    let line = EwkbLineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
    assert_eq!(line.to_hex_ewkb(), "0102000020E610000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}

#[test]
fn test_wkb_to_geom() {
    // 'POINT (10 -20)'
    let mut point_ewkb: &[u8] = &[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192];
    let point = EwkbPoint::read_ewkb(&mut point_ewkb).unwrap();
    assert_eq!(point.to_hex_ewkb(), "0101000000000000000000244000000000000034C0");

    // 'LINESTRING (10 -20, -0 -0.5)'
    let mut line_ewkb: &[u8] = &[1, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 64, 0, 0, 0, 0, 0, 0, 52, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 191];
    let line = EwkbLineString::read_ewkb(&mut line_ewkb).unwrap();
    assert_eq!(line.to_hex_ewkb(), "010200000002000000000000000000244000000000000034C00000000000000000000000000000E0BF");
}
<|endoftext|>


<commit_before>use serde_json::from_reader;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use compositing::RenderLayer;
use resource::{Load, LoadError, Result, ResCache};

/// Time.
pub type Time = f64;

pub struct Clip<'a, 'b> where 'a: 'b {
  gen_render_layer: Box<Fn(Time) -> RenderLayer<'a> + 'b>
}

impl<'a, 'b> Clip<'a, 'b> {
  pub fn new<F>(f: F) -> Self where F: 'b + Fn(Time) -> RenderLayer<'a> {
    Clip {
      gen_render_layer: Box::new(f)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'c Clip<'a, 'b>
}

impl<'a, 'b, 'c> Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'c Clip<'a, 'b>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  cuts: Vec<Cut<'a, 'b, 'c>>
}

impl<'a, 'b, 'c> Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a, 'b, 'c>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Cut<'a, 'b, 'c>]> for Track<'a, 'b, 'c> {
  fn from(cuts: &'d [Cut<'a, 'b, 'c>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  tracks: Vec<Track<'a, 'b, 'c>>,
}

impl<'a, 'b, 'c> Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  /// Turn a TimelineManifest into a Timeline by providing a mapping between clips’ names and real
  /// clips.
  pub fn from_manifest(manifest: &TimelineManifest, mapping: &HashMap<String, &'c Clip<'a, 'b>>) -> Self {
    let mut timeline = Self::new();

    for track_manifest in &manifest.tracks {
      let mut track = Track::new();

      for cut_manifest in &track_manifest.cuts {
        let in_time = cut_manifest.in_time;
        let out_time = cut_manifest.out_time;
        let inst_time = cut_manifest.inst_time;

        if let Some(clip) = mapping.get(&cut_manifest.clip).cloned() {
          track.add_cut(Cut::new(in_time, out_time, inst_time, clip));
        } else {
          warn!("the clip {:?} doesn’t exist", cut_manifest.clip);
        }
      }

      timeline.add_track(track);
    }

    timeline
  }

  pub fn add_track(&mut self, track: Track<'a, 'b, 'c>) {
    self.tracks.push(track);
  }

  // TODO: currently, we play the first track we find; add transition support
  pub fn play(&self, t: Time) -> Option<RenderLayer<'a>> {
    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          return Some((cut.clip.gen_render_layer)(t));
        }
      }
    }

    None
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Track<'a, 'b, 'c>]> for Timeline<'a, 'b, 'c> {
  fn from(tracks: &'d [Track<'a, 'b, 'c>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TimelineManifest {
  pub tracks: Vec<TrackManifest>
}

impl Load for TimelineManifest {
  type Args = ();

  const TY_STR: &'static str = "edit";

  fn load<P>(path: P, _: &mut ResCache, _: Self::Args) -> Result<Self> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading timeline: {:?}", path);

    let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
    from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TrackManifest {
  pub cuts: Vec<CutManifest>
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct CutManifest {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: String
}
<commit_msg>Clips don’t return RenderLayer anymore, but Nodes.<commit_after>use serde_json::from_reader;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use compositing::Node;
use resource::{Load, LoadError, Result, ResCache};

/// Time.
pub type Time = f64;

pub struct Clip<'a, 'b> where 'a: 'b {
  gen_node: Box<Fn(Time) -> Node<'a> + 'b>
}

impl<'a, 'b> Clip<'a, 'b> {
  pub fn new<F>(f: F) -> Self where F: 'b + Fn(Time) -> Node<'a> {
    Clip {
      gen_node: Box::new(f)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'c Clip<'a, 'b>
}

impl<'a, 'b, 'c> Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'c Clip<'a, 'b>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  cuts: Vec<Cut<'a, 'b, 'c>>
}

impl<'a, 'b, 'c> Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a, 'b, 'c>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Cut<'a, 'b, 'c>]> for Track<'a, 'b, 'c> {
  fn from(cuts: &'d [Cut<'a, 'b, 'c>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  tracks: Vec<Track<'a, 'b, 'c>>,
}

impl<'a, 'b, 'c> Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  /// Turn a TimelineManifest into a Timeline by providing a mapping between clips’ names and real
  /// clips.
  pub fn from_manifest(manifest: &TimelineManifest, mapping: &HashMap<String, &'c Clip<'a, 'b>>) -> Self {
    let mut timeline = Self::new();

    for track_manifest in &manifest.tracks {
      let mut track = Track::new();

      for cut_manifest in &track_manifest.cuts {
        let in_time = cut_manifest.in_time;
        let out_time = cut_manifest.out_time;
        let inst_time = cut_manifest.inst_time;

        if let Some(clip) = mapping.get(&cut_manifest.clip).cloned() {
          track.add_cut(Cut::new(in_time, out_time, inst_time, clip));
        } else {
          warn!("the clip {:?} doesn’t exist", cut_manifest.clip);
        }
      }

      timeline.add_track(track);
    }

    timeline
  }

  pub fn add_track(&mut self, track: Track<'a, 'b, 'c>) {
    self.tracks.push(track);
  }

  // TODO: currently, we play the first track we find; add transition support
  pub fn play(&self, t: Time) -> Option<Node<'a>> {
    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          return Some((cut.clip.gen_node)(t));
        }
      }
    }

    None
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Track<'a, 'b, 'c>]> for Timeline<'a, 'b, 'c> {
  fn from(tracks: &'d [Track<'a, 'b, 'c>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TimelineManifest {
  pub tracks: Vec<TrackManifest>
}

impl Load for TimelineManifest {
  type Args = ();

  const TY_STR: &'static str = "edit";

  fn load<P>(path: P, _: &mut ResCache, _: Self::Args) -> Result<Self> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading timeline: {:?}", path);

    let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
    from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TrackManifest {
  pub cuts: Vec<CutManifest>
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct CutManifest {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: String
}
<|endoftext|>


<commit_before>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count { $x; }
        }
        $ctx.vi_count = 0;
    };
    ( $ctx:ident, $operation:expr, $step:expr ) => {
        match $ctx.vi_count {
            0 => { $operation; }
            _ => {
                $operation;
                for _ in 1..$ctx.vi_count { $step; $operation; }
            }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_left_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    vi_repeat!(ctx, ctx.buf.move_left());
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    vi_repeat!(ctx, ctx.buf.move_right());
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.vi_count = 0;
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.vi_count = 0;
                    ctx.buf.move_end();
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.incr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.decr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_back());
                    Cont(false)
                }
                instr::Instr::MoveWordWsLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws_back());
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    vi_repeat!(
                        ctx,
                        ctx.buf.replace_chars_at_cursor(text.clone()),
                        {
                            ctx.buf.move_right();
                            ctx.buf.exclude_eol();
                        }
                    );
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<commit_msg>stop repeat operation if commands return false<commit_after>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count {
                if !$x {
                    break;
                }
            },
        }
        $ctx.vi_count = 0;
    };
    ( $ctx:ident, $operation:expr, $step:expr ) => {
        match $ctx.vi_count {
            0 => { $operation; }
            _ => {
                if $operation {
                    for _ in 1..$ctx.vi_count {
                        if !$step {
                            break;
                        }
                        if !$operation {
                            break;
                        }
                    }
                }
            }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_left_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    vi_repeat!(ctx, ctx.buf.move_left());
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    vi_repeat!(ctx, ctx.buf.move_right());
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.vi_count = 0;
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.vi_count = 0;
                    ctx.buf.move_end();
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    vi_repeat!(ctx, {
                        let end = ctx.history_cursor.incr();
                        if end {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                        end
                    });
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    vi_repeat!(ctx, {
                        let end = ctx.history_cursor.decr();
                        if end {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                        end
                    });
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordWsRight => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::MoveWordLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_back());
                    Cont(false)
                }
                instr::Instr::MoveWordWsLeft => {
                    vi_repeat!(ctx, ctx.buf.move_word_ws_back());
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    vi_repeat!(
                        ctx,
                        {
                            ctx.buf.replace_chars_at_cursor(text.clone());
                            true
                        },
                        {
                            ctx.buf.move_right();
                            ctx.buf.exclude_eol()
                        }
                    );
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, Read, Write};

#[allow(dead_code)]
/// Helper function for reading from a file. Reads from `filename` and returns a `Vec<u8>`.
pub fn read_file(filename: &str) -> Vec<u8> {
    let mut reader = File::open(filename).ok().expect("Unable to open file");
    let mut buf: Vec<u8> = vec![];
    reader.read_to_end(&mut buf).unwrap();

    buf
}

#[allow(dead_code)]
/// Helper function for writing to a file. Writes `contents` to `filename`.
pub fn write_file(filename: String, contents: Vec<u8>) -> Result<(), io::Error> {
    let mut file = try!(File::create(filename));
    try!(file.write_all(&contents[..]));
    Ok(())
}

#[allow(dead_code)]
/// Helper function for writing to a file. Writes `contents` to `filename`.
pub fn write_file_slice(filename: String, contents: &[u8]) -> Result<(), io::Error> {
    let mut file = try!(File::create(filename));
    try!(file.write_all(contents));
    Ok(())
}

#[allow(dead_code)]
/// Takes a `&[u8]` and returns a `Vec<u8>` containing all values until the first 0.
pub fn get_nonzero_bytes(data: &[u8]) -> Vec<u8> {
    let mut buf: Vec<u8> = vec![];
    for ch in data {
        if *ch == 0u8 {
            break;
        } else {
            buf.push(*ch);
        }
    }

    buf
}
<commit_msg>Add file_exists fn, rework other file functions<commit_after>use std::fs::File;
use std::io::{self, Read, Write};

#[allow(dead_code)]
/// Helper function for reading from a file. Reads from `filename` and returns a `Vec<u8>`.
pub fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> {
    let mut f = try!(File::open(filename));
    let mut buf: Vec<u8> = vec![];
    try!(f.read_to_end(&mut buf));

    Ok(buf)
}

/// Returns `true` if `filename` exists, `false` otherwise.
pub fn file_exists(filename: &str) -> bool {
    match File::open(filename) {
        Ok(_) => true,
        Err(_) => false,
    }
}

#[allow(dead_code)]
/// Helper function for writing to a file. Writes `contents` to `filename`.
pub fn write_file(filename: &str, data: &[u8]) -> Result<(), io::Error> {
    let mut file = try!(File::create(filename));
    try!(file.write_all(data));
    Ok(())
}

#[allow(dead_code)]
/// Takes a `&[u8]` and returns a `Vec<u8>` containing all values until the first 0.
pub fn get_nonzero_bytes(data: &[u8]) -> Vec<u8> {
    let mut buf: Vec<u8> = vec![];
    for ch in data {
        if *ch == 0u8 {
            break;
        } else {
            buf.push(*ch);
        }
    }

    buf
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use std::f32::NAN;
use std::cmp;

#[derive(Debug, Clone)]
pub struct DngDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> DngDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> DngDecoder<'a> {
    DngDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for DngDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let ifds = self.tiff.find_ifds_with_tag(Tag::Compression).into_iter().filter(|ifd| {
      let compression = (**ifd).find_entry(Tag::Compression).unwrap().get_u32(0);
      let subsampled = match (**ifd).find_entry(Tag::NewSubFileType) {
        Some(e) => e.get_u32(0) & 1 != 0,
        None => false,
      };
      !subsampled && (compression == 7 || compression == 1 || compression == 0x884c)
    }).collect::<Vec<&TiffIFD>>();
    let raw = ifds[0];
    let width = fetch_tag!(raw, Tag::ImageWidth).get_u32(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_u32(0);

    let image = match fetch_tag!(raw, Tag::Compression).get_u32(0) {
      1 => try!(self.decode_uncompressed(raw, width as usize, height as usize)),
      7 => try!(self.decode_compressed(raw, width as usize, height as usize)),
      c => return Err(format!("Don't know how to read DNGs with compression {}", c).to_string()),
    };

    ok_image(camera, width, height, try!(self.get_wb()), image)
  }
}

impl<'a> DngDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  pub fn decode_uncompressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_u32(0) as usize;
    let src = &self.buffer[offset..];

    match fetch_tag!(raw, Tag::BitsPerSample).get_u32(0) {
      16  => Ok(decode_16le(src, width, height)),
      bps => Err(format!("DNG: Don't know about {} bps images", bps).to_string()),
    }
  }

  pub fn decode_compressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    if raw.has_entry(Tag::StripOffsets) { // We're in a normal offset situation
      let offsets = fetch_tag!(raw, Tag::StripOffsets);
      if offsets.count() != 1 {
        return Err("DNG: files with more than one slice not supported yet".to_string())
      }
      let offset = offsets.get_u32(0) as usize;
      let src = &self.buffer[offset..];
      let mut out = vec![0 as u16; width*height];
      let decompressor = try!(LjpegDecompressor::new(src, true));
      try!(decompressor.decode(&mut out, 0, width, width, height));
      Ok(out)
    } else if raw.has_entry(Tag::TileOffsets) { // They've gone with tiling
      let twidth = fetch_tag!(raw, Tag::TileWidth).get_u32(0) as usize;
      let tlength = fetch_tag!(raw, Tag::TileLength).get_u32(0) as usize;
      let offsets = fetch_tag!(raw, Tag::TileOffsets);
      let coltiles = (width-1)/twidth + 1;
      let rowtiles = (height-1)/tlength + 1;
      if coltiles*rowtiles != offsets.count() as usize {
        return Err(format!("DNG: trying to decode {} tiles from {} offsets",
                           coltiles*rowtiles, offsets.count()).to_string())
      }

      let mut out = vec![0 as u16; width*height];
      for (row,strip) in out.chunks_mut(tlength*width).enumerate() {
        for col in 0..coltiles {
          let offset = offsets.get_u32(row*coltiles+col) as usize;
          let src = &self.buffer[offset..];
          // We don't use bigtable here as the tiles are two small to amortize the setup cost
          let decompressor = try!(LjpegDecompressor::new(src, true));
          let bwidth = cmp::min(width, (col+1)*twidth) - col*twidth;
          let blength = cmp::min(height, (row+1)*tlength) - row*tlength;
          try!(decompressor.decode(strip, col*twidth, width, bwidth, blength));
        }
      }

      Ok(out)
    } else {
      Err("DNG: didn't find tiles or strips".to_string())
    }
  }
}
<commit_msg>DNG: use threading for tiled processing<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use std::f32::NAN;
use std::cmp;

#[derive(Debug, Clone)]
pub struct DngDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> DngDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> DngDecoder<'a> {
    DngDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for DngDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let ifds = self.tiff.find_ifds_with_tag(Tag::Compression).into_iter().filter(|ifd| {
      let compression = (**ifd).find_entry(Tag::Compression).unwrap().get_u32(0);
      let subsampled = match (**ifd).find_entry(Tag::NewSubFileType) {
        Some(e) => e.get_u32(0) & 1 != 0,
        None => false,
      };
      !subsampled && (compression == 7 || compression == 1 || compression == 0x884c)
    }).collect::<Vec<&TiffIFD>>();
    let raw = ifds[0];
    let width = fetch_tag!(raw, Tag::ImageWidth).get_u32(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_u32(0);

    let image = match fetch_tag!(raw, Tag::Compression).get_u32(0) {
      1 => try!(self.decode_uncompressed(raw, width as usize, height as usize)),
      7 => try!(self.decode_compressed(raw, width as usize, height as usize)),
      c => return Err(format!("Don't know how to read DNGs with compression {}", c).to_string()),
    };

    ok_image(camera, width, height, try!(self.get_wb()), image)
  }
}

impl<'a> DngDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  pub fn decode_uncompressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_u32(0) as usize;
    let src = &self.buffer[offset..];

    match fetch_tag!(raw, Tag::BitsPerSample).get_u32(0) {
      16  => Ok(decode_16le(src, width, height)),
      bps => Err(format!("DNG: Don't know about {} bps images", bps).to_string()),
    }
  }

  pub fn decode_compressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    if raw.has_entry(Tag::StripOffsets) { // We're in a normal offset situation
      let offsets = fetch_tag!(raw, Tag::StripOffsets);
      if offsets.count() != 1 {
        return Err("DNG: files with more than one slice not supported yet".to_string())
      }
      let offset = offsets.get_u32(0) as usize;
      let src = &self.buffer[offset..];
      let mut out = vec![0 as u16; width*height];
      let decompressor = try!(LjpegDecompressor::new(src, true));
      try!(decompressor.decode(&mut out, 0, width, width, height));
      Ok(out)
    } else if raw.has_entry(Tag::TileOffsets) { // They've gone with tiling
      let twidth = fetch_tag!(raw, Tag::TileWidth).get_u32(0) as usize;
      let tlength = fetch_tag!(raw, Tag::TileLength).get_u32(0) as usize;
      let offsets = fetch_tag!(raw, Tag::TileOffsets);
      let coltiles = (width-1)/twidth + 1;
      let rowtiles = (height-1)/tlength + 1;
      if coltiles*rowtiles != offsets.count() as usize {
        return Err(format!("DNG: trying to decode {} tiles from {} offsets",
                           coltiles*rowtiles, offsets.count()).to_string())
      }

      Ok(decode_threaded_multiline(width, height, tlength, &(|strip: &mut [u16], row| {
        let row = row / tlength;
        for col in 0..coltiles {
          let offset = offsets.get_u32(row*coltiles+col) as usize;
          let src = &self.buffer[offset..];
          // We don't use bigtable here as the tiles are two small to amortize the setup cost
          let decompressor = LjpegDecompressor::new(src, true).unwrap();
          let bwidth = cmp::min(width, (col+1)*twidth) - col*twidth;
          let blength = cmp::min(height, (row+1)*tlength) - row*tlength;
          decompressor.decode(strip, col*twidth, width, bwidth, blength).unwrap();
        }
      })))
    } else {
      Err("DNG: didn't find tiles or strips".to_string())
    }
  }
}
<|endoftext|>


<commit_before>
//! This module provides various utilities for rendering text.

use gl;
use gl::types::*;
use rusttype;
use rusttype::{Scale, Rect, point, GlyphId, PositionedGlyph};
use rusttype::gpu_cache::*;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::fs::File;
use std::str::Chars;
use cable_math::Vec2;
use texture::*;
use buffer::*;
use shader::*;
use util::graphics;

const CACHE_SIZE: u32 = 512;

/// A font. This struct can be used both to store data in and to draw data from a [`DrawCache`].
/// Usually a [`CachedFont`] will be more convenient.
///
/// [`DrawCache`]:  struct.DrawCache.html
/// [`CachedFont`]: struct.CachedFont.html
pub struct Font<'a> {
    font: rusttype::Font<'a>,
    cache: Cache,
    cache_texture: Texture,
    shader: Shader,
}

impl<'a> Font<'a> {
    /// Constructs a new font from the given font file. The file should be in either trutype (`.ttf`) or
    /// opentype (`.otf`) format. See [rusttype documentation](https://docs.rs/rusttype) for a complete
    /// overview of font support.
    pub fn from_file<P>(p: P) -> io::Result<Font<'a>> where P: AsRef<Path> {
        let mut file = File::open(p)?;

        let mut data = Vec::new();
        let _bytes_read = file.read_to_end(&mut data)?;

        let font_collection = rusttype::FontCollection::from_bytes(data);
        let font = font_collection.font_at(0).unwrap();

        let cache = Cache::new(CACHE_SIZE, CACHE_SIZE, 0.1, 0.1);

        let mut cache_texture = Texture::new();
        cache_texture.initialize(CACHE_SIZE, CACHE_SIZE, TextureFormat::R_8);
        cache_texture.set_swizzle_mask((SwizzleComp::One, SwizzleComp::One, SwizzleComp::One, SwizzleComp::Red));

        Ok(Font {
            font: font,
            cache: cache,
            cache_texture: cache_texture,
            shader: build_font_shader(),
        })
    }

    /// Calculates the width, in pixels, of the given string if it where to be
    /// rendered at the given size. This takes newlines into acount, meaning that
    /// for a multiline string this will return the length of the longest line.
    pub fn get_width(&self, text: &str, text_size: f32) -> f32 {
        let iter = PosGlyphIter::new(text, &self.font, Scale::uniform(text_size), Vec2::zero());
        iter.map(|glyph| glyph.unpositioned().h_metrics().advance_width).sum()
    }

    /// Writes data needed to render the given text into the given render cache. Multiple pieces of
    /// text can be written into the render cache before rendering it. This allows for efficient
    /// rendering of large sets of text.
    pub fn cache(&mut self, draw_cache: &mut DrawCache, text: &str, text_size: f32, offset: Vec2<f32>) {
        let iter = PosGlyphIter::new(text, &self.font, Scale::uniform(text_size), offset);

        // Push textures to GPU
        {
            for glyph in iter.clone() {
                self.cache.queue_glyph(0, glyph);
            }
            let ref mut tex = self.cache_texture;
            self.cache.cache_queued(|rect, data| {
                tex.load_data_to_region(data,
                                        rect.min.x, rect.min.y,
                                        rect.width(), rect.height());
            }).unwrap();
        }

        // Push render data to GPU
        for glyph in iter {
            if let Ok(Some((uv, pos))) = self.cache.rect_for(0, &glyph) {
                FontVert::to_buffer(&mut draw_cache.buffer_data, pos, uv);
            }
        }
    }

    /// Draws teh data stored in the given draw cache. Note that you should call
    /// [`DrawCache::update_vbo`] before drawing a cache, and you probably want to
    /// call [`DrawCache::clear`] afterwards.
    ///
    /// [`DrawCache::update_vbo`]:  struct.DrawCache.html#method.update_vbo
    /// [`DrawCache::clear`]:       struct.DrawCache.html#method.clear
    pub fn draw_cache(&mut self, cache: &DrawCache) {
        graphics::set_blending(Some(graphics::BlendSettings::default()));
        self.shader.bind();
        self.cache_texture.bind(0);
        cache.buffer.draw();
        graphics::set_blending(None);
    }
}

/// A draw cache contains the raw data that is sent to the GPU when rendering font. This struct is
/// used to temporarily store data during cached rendering. Large amounts of text can be written to
/// the cache and then drawn with a single rendercall, allowing for more efficient rendering.
///
/// The cache can be filled with [`Font::cache`], and its contents can be drawn with [`Font::draw_cache`].
/// Note that the internal vertex buffer needs to be updated with [`DrawCache::update_vbo`] before
/// rendering. You probably also want to clear the buffer with [`DrawCache::clear`] after rendering,
/// otherwise the same data will be redrawn in the next frame.
///
/// Note that a cache should only ever be used with a single [`Font`] per call to [`Font::draw_cache`].
/// This is because a `DrawCache` has no knowledge of which font provided the data stored in it. Failing
/// to comply to this rule will lead to garbled text beeing rendered.
///
/// If you do not need the `Font` - `DrawCache` separation you might want to concider using
/// [`CachedFont`] instead, as it provides a draw cache and a font in a
/// single cohesive package.
///
/// [`Font`]:                   struct.Font.html
/// [`Font::cache`]:            struct.Font.html#method.cache
/// [`Font::draw_cache`]:       struct.Font.html#method.draw_cache
/// [`DrawCache::update_vbo`]:  struct.DrawCache.html#method.update_vbo
/// [`DrawCache::clear`]:       struct.DrawCache.html#method.clear
/// [`CachedFont`]:             struct.CachedFont.html
pub struct DrawCache {
    buffer: VertexBuffer<FontVert>,
    buffer_data: Vec<FontVert>,
}

impl DrawCache {
    /// Constructs a new, empty, draw cache
    pub fn new() -> DrawCache {
        DrawCache {
            buffer: VertexBuffer::with_capacity(PrimitiveMode::Triangles, BufferUsage::DynamicDraw, 500),
            buffer_data: Vec::with_capacity(500),
        }
    }

    /// When drawing to this cache, data is by default stored on the CPU side. This method moves
    /// data over to the GPU.
    pub fn update_vbo(&mut self) {
        self.buffer.clear();
        self.buffer.put(0, &self.buffer_data);
    }

    /// Removes all data from this cache. Note that this does not call any expensive operations,
    /// it simply sets the size of the internal buffers to 0.
    pub fn clear(&mut self) {
        self.buffer.clear();
        self.buffer_data.clear();
    }
}

/// A thin wrapper around a [`Font`] coupled with a [`DrawCache`]. This is intended for simple text
/// rendering, and is probably adequate for most usecases.
///
/// # Example
/// ```rust,ignore
/// use gondola::font::CachedFont;
/// use cable_math::Vec2;
///
/// let mut font = CachedFont::from_file("assets/comic_sans.ttf").unwrap();
///
/// loop {
///     // Main logic goes here ...
///     font.cache("Hello world\nTesting", 14.0, Vec2::new(50.0, 50.0));
///     font.cache("ax² + bx + c = 0", 14.0, Vec2::new(50.0, 100.0));
///     font.draw();
/// }
/// ```
///
/// [`Font`]:       struct.Font.html
/// [`DrawCache`]:  struct.DrawCache.html
pub struct CachedFont<'a> {
    font: Font<'a>,
    draw_cache: DrawCache,
}

impl<'a> CachedFont<'a> {
    /// Constructs a new cached font from the given font file. The file should be in either trutype (`.ttf`)
    /// or opentype (`.otf`) format. See [rusttype documentation](https://docs.rs/rusttype) for a complete
    /// overview of font support.
    pub fn from_file<P>(p: P) -> io::Result<CachedFont<'a>> where P: AsRef<Path> {
        Ok(CachedFont {
            font: Font::from_file(p)?,
            draw_cache: DrawCache::new(),
        })
    }

    /// Adds the given piece of text to the internal draw cache. Cached text can be drawn with
    /// [`draw`](struct.CachedFont.html#method.draw). Usually you want to cache all text you want
    /// to draw in a given frame and then draw it all in a single call.
    pub fn cache(&mut self, text: &str, size: f32, pos: Vec2<f32>) {
        self.font.cache(&mut self.draw_cache, text, size, pos);
    }

    /// Draws all text in the internal cache and then clears the cache
    pub fn draw(&mut self) {
        self.draw_cache.update_vbo();
        self.font.draw_cache(&self.draw_cache);
        self.draw_cache.clear();
    }

    pub fn font(&self) -> &Font<'a> { &self.font }
    pub fn font_mut(&mut self) -> &mut Font<'a> { &mut self.font }
}
#[derive(Debug)]
#[repr(C)]
struct FontVert {
    pos: Vec2<f32>,
    uv: Vec2<f32>,
}
// We cannot use the custom derive from within this crate
impl Vertex for FontVert {
    fn bytes_per_vertex() -> usize { 16 }
    fn setup_attrib_pointers() {
        unsafe {
            gl::EnableVertexAttribArray(0);
            gl::VertexAttribPointer(0, 2, gl::FLOAT,
                                    false as GLboolean,
                                    16 as GLsizei, 0 as *const GLvoid);
            gl::EnableVertexAttribArray(1);
            gl::VertexAttribPointer(1, 2, gl::FLOAT,
                                    false as GLboolean,
                                    16 as GLsizei, 8 as *const GLvoid);
        }
    }
    // Not used, we manualy declare inputs in the shader
    fn gen_shader_input_decl() -> String { String::new() }
}
const VERT_SRC: &'static str = "
    #version 330 core

    layout(location = 0) in vec2 pos;
    layout(location = 1) in vec2 uv;

    out vec2 vert_uv;

    // Matrix block is inserted automatically

    void main() {
        gl_Position = mvp * vec4(pos, 0.0, 1.0);
        vert_uv = uv;
    }
";
const FRAG_SRC: &'static str = "
    #version 330 core

    in vec2 vert_uv;
    out vec4 color;

    uniform sampler2D tex_sampler;

    void main() {
        color = texture2D(tex_sampler, vert_uv);
    }
";
fn build_font_shader() -> Shader {
    let mut proto = ShaderPrototype::new_prototype(VERT_SRC, "", FRAG_SRC);
    proto.bind_to_matrix_storage();
    match proto.build() {
        Ok(shader) => shader,
        Err(err) => {
            println!("{}", err); // Print the error properly
            panic!();
        }
    }
}
impl FontVert {
    fn to_buffer(data: &mut Vec<FontVert>, pos: Rect<i32>, uv: Rect<f32>) {
        let x1 = pos.min.x as f32;
        let x2 = pos.max.x as f32;
        let y1 = pos.min.y as f32;
        let y2 = pos.max.y as f32;
        data.push(FontVert {
            pos: Vec2::new(x1, y1),
            uv: Vec2::new(uv.min.x, uv.min.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x2, y1),
            uv: Vec2::new(uv.max.x, uv.min.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x2, y2),
            uv: Vec2::new(uv.max.x, uv.max.y),
        });

        data.push(FontVert {
            pos: Vec2::new(x1, y1),
            uv: Vec2::new(uv.min.x, uv.min.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x2, y2),
            uv: Vec2::new(uv.max.x, uv.max.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x1, y2),
            uv: Vec2::new(uv.min.x, uv.max.y),
        });
    }
}

#[derive(Clone)]
struct PosGlyphIter<'a: 'b, 'b> {
    text: Chars<'b>,

    font: &'b rusttype::Font<'a>,
    scale: Scale,

    offset: Vec2<f32>,
    caret: Vec2<f32>,
    last_glyph: Option<GlyphId>,
    vertical_advance: f32,
}
impl<'a: 'b, 'b> PosGlyphIter<'a, 'b> {
    fn new(text: &'b str, font: &'a rusttype::Font<'b>, scale: Scale, offset: Vec2<f32>) -> PosGlyphIter<'a, 'b> {
        let v_metrics = font.v_metrics(scale);
        let vertical_advance = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;

        PosGlyphIter {
            text: text.chars(),

            font: font,
            scale: scale,

            caret: offset,
            offset: offset,
            last_glyph: None,
            vertical_advance: vertical_advance,
        }
    }
}
impl<'a: 'b, 'b> Iterator for PosGlyphIter<'a, 'b> {
    type Item = PositionedGlyph<'b>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(c) = self.text.next() {
            // Move to new line
            if c.is_control() {
                if c == '\n' {
                    self.caret.x = self.offset.x;
                    self.caret.y += self.vertical_advance;
                    self.last_glyph = None; //No kerning after newline
                }
                continue;
            }

            let glyph = if let Some(glyph) = self.font.glyph(c) {
                glyph
            } else {
                continue;
            };

            // Apply kerning
            if let Some(prev) = self.last_glyph.take() {
                self.caret.x += self.font.pair_kerning(self.scale, prev, glyph.id());
            }
            self.last_glyph = Some(glyph.id());

            let glyph = glyph
                .scaled(self.scale)
                .positioned(point(self.caret.x, self.caret.y));
            self.caret.x += glyph.unpositioned().h_metrics().advance_width;
            return Some(glyph);
        }
        None
    }
}

<commit_msg>More minor font fixes<commit_after>
//! This module provides various utilities for rendering text.

// Note to self: There is a problem with the current font rendering system. When storing data
// in a draw cache, we write data to the cache texture. If the cache texture is to small we will
// end up overwriting the original data in the texture with new data before rendering. If this
// happens we can probably solve the problem by simply increasing the cache texture size.

use gl;
use gl::types::*;
use rusttype;
use rusttype::{Scale, Rect, point, GlyphId, PositionedGlyph};
use rusttype::gpu_cache::*;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::fs::File;
use std::str::Chars;
use cable_math::Vec2;
use texture::*;
use buffer::*;
use shader::*;
use util::graphics;

const CACHE_TEX_SIZE: u32 = 1024; // More than 99% of GPUs support this texture size: http://feedback.wildfiregames.com/report/opengl/feature/GL_MAX_TEXTURE_SIZE
const VERTS_PER_CHAR: usize = 6;
const CACHE_SIZE: usize = 500;

/// A font. This struct can be used both to store data in and to draw data from a [`DrawCache`].
/// Usually a [`CachedFont`] will be more convenient.
///
/// [`DrawCache`]:  struct.DrawCache.html
/// [`CachedFont`]: struct.CachedFont.html
pub struct Font<'a> {
    font: rusttype::Font<'a>,
    cache: Cache,
    cache_texture: Texture,
    shader: Shader,
}

impl<'a> Font<'a> {
    /// Constructs a new font from the given font file. The file should be in either trutype (`.ttf`) or
    /// opentype (`.otf`) format. See [rusttype documentation](https://docs.rs/rusttype) for a complete
    /// overview of font support.
    pub fn from_file<P>(p: P) -> io::Result<Font<'a>> where P: AsRef<Path> {
        let mut file = File::open(p)?;

        let mut data = Vec::new();
        let _bytes_read = file.read_to_end(&mut data)?;

        let font_collection = rusttype::FontCollection::from_bytes(data);
        let font = font_collection.font_at(0).unwrap();

        let cache = Cache::new(CACHE_TEX_SIZE, CACHE_TEX_SIZE, 0.1, 0.1);

        let mut cache_texture = Texture::new();
        cache_texture.initialize(CACHE_TEX_SIZE, CACHE_TEX_SIZE, TextureFormat::R_8);
        cache_texture.set_swizzle_mask((SwizzleComp::One, SwizzleComp::One, SwizzleComp::One, SwizzleComp::Red));

        Ok(Font {
            font: font,
            cache: cache,
            cache_texture: cache_texture,
            shader: build_font_shader(),
        })
    }

    /// Calculates the width, in pixels, of the given string if it where to be
    /// rendered at the given size. This takes newlines into acount, meaning that
    /// for a multiline string this will return the length of the longest line.
    pub fn get_width(&self, text: &str, text_size: f32) -> f32 {
        let iter = PosGlyphIter::new(text, &self.font, Scale::uniform(text_size), Vec2::zero());
        iter.map(|glyph| glyph.unpositioned().h_metrics().advance_width).sum()
    }

    /// Writes data needed to render the given text into the given render cache. Multiple pieces of
    /// text can be written into the render cache before rendering it. This allows for efficient
    /// rendering of large sets of text.
    pub fn cache(&mut self, draw_cache: &mut DrawCache, text: &str, text_size: f32, offset: Vec2<f32>) {
        let iter = PosGlyphIter::new(text, &self.font, Scale::uniform(text_size), offset);

        // Push textures to GPU
        {
            for glyph in iter.clone() {
                self.cache.queue_glyph(0, glyph);
            }
            let ref mut tex = self.cache_texture;
            self.cache.cache_queued(|rect, data| {
                tex.load_data_to_region(data,
                                        rect.min.x, rect.min.y,
                                        rect.width(), rect.height());
            }).unwrap();
        }

        // Push render data to GPU
        for glyph in iter {
            if let Ok(Some((uv, pos))) = self.cache.rect_for(0, &glyph) {
                FontVert::to_buffer(&mut draw_cache.buffer_data, pos, uv);
            }
        }
    }

    /// Draws teh data stored in the given draw cache. Note that you should call
    /// [`DrawCache::update_vbo`] before drawing a cache, and you probably want to
    /// call [`DrawCache::clear`] afterwards.
    ///
    /// [`DrawCache::update_vbo`]:  struct.DrawCache.html#method.update_vbo
    /// [`DrawCache::clear`]:       struct.DrawCache.html#method.clear
    pub fn draw_cache(&mut self, cache: &DrawCache) {
        graphics::set_blending(Some(graphics::BlendSettings::default()));
        self.shader.bind();
        self.cache_texture.bind(0);
        cache.buffer.draw();
        graphics::set_blending(None);
    }
}

/// A draw cache contains the raw data that is sent to the GPU when rendering font. This struct is
/// used to temporarily store data during cached rendering. Large amounts of text can be written to
/// the cache and then drawn with a single rendercall, allowing for more efficient rendering.
///
/// The cache can be filled with [`Font::cache`], and its contents can be drawn with [`Font::draw_cache`].
/// Note that the internal vertex buffer needs to be updated with [`DrawCache::update_vbo`] before
/// rendering. You probably also want to clear the buffer with [`DrawCache::clear`] after rendering,
/// otherwise the same data will be redrawn in the next frame.
///
/// Note that a cache should only ever be used with a single [`Font`] per call to [`Font::draw_cache`].
/// This is because a `DrawCache` has no knowledge of which font provided the data stored in it. Failing
/// to comply to this rule will lead to garbled text beeing rendered.
///
/// If you do not need the `Font` - `DrawCache` separation you might want to concider using
/// [`CachedFont`] instead, as it provides a draw cache and a font in a
/// single cohesive package.
///
/// [`Font`]:                   struct.Font.html
/// [`Font::cache`]:            struct.Font.html#method.cache
/// [`Font::draw_cache`]:       struct.Font.html#method.draw_cache
/// [`DrawCache::update_vbo`]:  struct.DrawCache.html#method.update_vbo
/// [`DrawCache::clear`]:       struct.DrawCache.html#method.clear
/// [`CachedFont`]:             struct.CachedFont.html
pub struct DrawCache {
    buffer: VertexBuffer<FontVert>,
    buffer_data: Vec<FontVert>,
}

impl DrawCache {
    /// Constructs a new, empty, draw cache
    pub fn new() -> DrawCache {
        let vertices = VERTS_PER_CHAR * CACHE_SIZE;
        DrawCache {
            buffer: VertexBuffer::with_capacity(PrimitiveMode::Triangles, BufferUsage::DynamicDraw, vertices),
            buffer_data: Vec::with_capacity(vertices),
        }
    }

    /// When drawing to this cache, data is by default stored on the CPU side. This method moves
    /// data over to the GPU.
    pub fn update_vbo(&mut self) {
        self.buffer.clear();
        self.buffer.put(0, &self.buffer_data);
    }

    /// Removes all data from this cache. Note that this does not call any expensive operations,
    /// it simply sets the size of the internal buffers to 0.
    pub fn clear(&mut self) {
        self.buffer.clear();
        self.buffer_data.clear();
    }
}

/// A thin wrapper around a [`Font`] coupled with a [`DrawCache`]. This is intended for simple text
/// rendering, and is probably adequate for most usecases.
///
/// # Example
/// ```rust,ignore
/// use gondola::font::CachedFont;
/// use cable_math::Vec2;
///
/// let mut font = CachedFont::from_file("assets/comic_sans.ttf").unwrap();
///
/// loop {
///     // Main logic goes here ...
///     font.cache("Hello world\nTesting", 14.0, Vec2::new(50.0, 50.0));
///     font.cache("ax² + bx + c = 0", 14.0, Vec2::new(50.0, 100.0));
///     font.draw();
/// }
/// ```
///
/// [`Font`]:       struct.Font.html
/// [`DrawCache`]:  struct.DrawCache.html
pub struct CachedFont<'a> {
    font: Font<'a>,
    draw_cache: DrawCache,
}

impl<'a> CachedFont<'a> {
    /// Constructs a new cached font from the given font file. The file should be in either trutype (`.ttf`)
    /// or opentype (`.otf`) format. See [rusttype documentation](https://docs.rs/rusttype) for a complete
    /// overview of font support.
    pub fn from_file<P>(p: P) -> io::Result<CachedFont<'a>> where P: AsRef<Path> {
        Ok(CachedFont {
            font: Font::from_file(p)?,
            draw_cache: DrawCache::new(),
        })
    }

    /// Adds the given piece of text to the internal draw cache. Cached text can be drawn with
    /// [`draw`](struct.CachedFont.html#method.draw). Usually you want to cache all text you want
    /// to draw in a given frame and then draw it all in a single call.
    pub fn cache(&mut self, text: &str, size: f32, pos: Vec2<f32>) {
        self.font.cache(&mut self.draw_cache, text, size, pos);
    }

    /// Draws all text in the internal cache and then clears the cache
    pub fn draw(&mut self) {
        self.draw_cache.update_vbo();
        self.font.draw_cache(&self.draw_cache);
        self.draw_cache.clear();
    }

    pub fn font(&self) -> &Font<'a> { &self.font }
    pub fn font_mut(&mut self) -> &mut Font<'a> { &mut self.font }
}
#[derive(Debug)]
#[repr(C)]
struct FontVert {
    pos: Vec2<f32>,
    uv: Vec2<f32>,
}
// We cannot use the custom derive from within this crate
impl Vertex for FontVert {
    fn bytes_per_vertex() -> usize { 16 }
    fn setup_attrib_pointers() {
        unsafe {
            gl::EnableVertexAttribArray(0);
            gl::VertexAttribPointer(0, 2, gl::FLOAT,
                                    false as GLboolean,
                                    16 as GLsizei, 0 as *const GLvoid);
            gl::EnableVertexAttribArray(1);
            gl::VertexAttribPointer(1, 2, gl::FLOAT,
                                    false as GLboolean,
                                    16 as GLsizei, 8 as *const GLvoid);
        }
    }
    // Not used, we manualy declare inputs in the shader
    fn gen_shader_input_decl() -> String { String::new() }
}
const VERT_SRC: &'static str = "
    #version 330 core

    layout(location = 0) in vec2 pos;
    layout(location = 1) in vec2 uv;

    out vec2 vert_uv;

    // Matrix block is inserted automatically

    void main() {
        gl_Position = mvp * vec4(pos, 0.0, 1.0);
        vert_uv = uv;
    }
";
const FRAG_SRC: &'static str = "
    #version 330 core

    in vec2 vert_uv;
    out vec4 color;

    uniform sampler2D tex_sampler;

    void main() {
        color = texture2D(tex_sampler, vert_uv);
    }
";
fn build_font_shader() -> Shader {
    let mut proto = ShaderPrototype::new_prototype(VERT_SRC, "", FRAG_SRC);
    proto.bind_to_matrix_storage();
    match proto.build() {
        Ok(shader) => shader,
        Err(err) => {
            println!("{}", err); // Print the error properly
            panic!();
        }
    }
}
impl FontVert {
    fn to_buffer(data: &mut Vec<FontVert>, pos: Rect<i32>, uv: Rect<f32>) {
        let x1 = pos.min.x as f32;
        let x2 = pos.max.x as f32;
        let y1 = pos.min.y as f32;
        let y2 = pos.max.y as f32;
        data.push(FontVert {
            pos: Vec2::new(x1, y1),
            uv: Vec2::new(uv.min.x, uv.min.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x2, y1),
            uv: Vec2::new(uv.max.x, uv.min.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x2, y2),
            uv: Vec2::new(uv.max.x, uv.max.y),
        });

        data.push(FontVert {
            pos: Vec2::new(x1, y1),
            uv: Vec2::new(uv.min.x, uv.min.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x2, y2),
            uv: Vec2::new(uv.max.x, uv.max.y),
        });
        data.push(FontVert {
            pos: Vec2::new(x1, y2),
            uv: Vec2::new(uv.min.x, uv.max.y),
        });
    }
}

#[derive(Clone)]
struct PosGlyphIter<'a: 'b, 'b> {
    text: Chars<'b>,

    font: &'b rusttype::Font<'a>,
    scale: Scale,

    offset: Vec2<f32>,
    caret: Vec2<f32>,
    last_glyph: Option<GlyphId>,
    vertical_advance: f32,
}
impl<'a: 'b, 'b> PosGlyphIter<'a, 'b> {
    fn new(text: &'b str, font: &'a rusttype::Font<'b>, scale: Scale, offset: Vec2<f32>) -> PosGlyphIter<'a, 'b> {
        let v_metrics = font.v_metrics(scale);
        let vertical_advance = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;

        PosGlyphIter {
            text: text.chars(),

            font: font,
            scale: scale,

            caret: offset,
            offset: offset,
            last_glyph: None,
            vertical_advance: vertical_advance,
        }
    }
}
impl<'a: 'b, 'b> Iterator for PosGlyphIter<'a, 'b> {
    type Item = PositionedGlyph<'b>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(c) = self.text.next() {
            // Move to new line
            if c.is_control() {
                if c == '\n' {
                    self.caret.x = self.offset.x;
                    self.caret.y += self.vertical_advance;
                    self.last_glyph = None; //No kerning after newline
                }
                continue;
            }

            let glyph = if let Some(glyph) = self.font.glyph(c) {
                glyph
            } else {
                continue;
            };

            // Apply kerning
            if let Some(prev) = self.last_glyph.take() {
                self.caret.x += self.font.pair_kerning(self.scale, prev, glyph.id());
            }
            self.last_glyph = Some(glyph.id());

            let glyph = glyph
                .scaled(self.scale)
                .positioned(point(self.caret.x, self.caret.y));
            self.caret.x += glyph.unpositioned().h_metrics().advance_width;
            return Some(glyph);
        }
        None
    }
}

<|endoftext|>


<commit_before>use state::State;
use resources::{ResourceManager, TextureManager, FontManager};

use std::path::Path;
use std::thread;
use std::time::Duration;

use sdl2;
use sdl2::pixels::Color;
use sdl2::event::Event::*;
use sdl2::rect::Rect;
use sdl2::keyboard::Keycode::*;
use sdl2::render::TextureQuery;
use sdl2_ttf;
use rand::{self, Rng, Rand};
use rand::distributions::{IndependentSample, Range};

pub struct Game<S: State> {
    states: Vec<S>
}

impl<S: State> Game<S> {
    pub fn new(initial_state: S) -> Game<S> {
        Game {
            states: vec![initial_state]
        }
    }

    pub fn push_state(&mut self, state: S) {
        self.states.push(state);
    }

    pub fn pop_state() {}

    fn get_active_state(&mut self) -> Option<&mut S> {
        self.states.last_mut()
    }

    pub fn run(&mut self) {
        let screen_width = 800;
        let screen_height = 600;

        let mut rng = rand::thread_rng();
        let sdl_context = sdl2::init().unwrap();
        let mut timer = sdl_context.timer().unwrap();
        let mut event_pump = sdl_context.event_pump().unwrap();
        let video = sdl_context.video().unwrap();

        let mut resource_manager = ResourceManager::new().unwrap();

        resource_manager.load_font("DejaVuSerif", "resources/DejaVuSerif.ttf").unwrap();

        let mut font = resource_manager.get_font("DejaVuSerif", 128).unwrap();
        let surface = font.render("ruffel")
                          .blended(Color::rand(&mut rng))
                          .unwrap();

        let window = video.window("Ruffel", 800, 600)
                          .position_centered()
                          .opengl()
                          .build()
                          .unwrap();

        let mut renderer = window.renderer()
                                 .accelerated()
                                 .build()
                                 .unwrap();

        let mut font_texture = renderer.create_texture_from_surface(&surface).unwrap();

        let TextureQuery { width, height, .. } = font_texture.query();

        // If the example text is too big for the screen, downscale it (and center irregardless)
        let padding = 64;

        // Initialize State handlers
        for s in &mut self.states {
            s.load();
        }

        let mut done = false;
        let mut delta = Duration::new(0, 0);
        while !done {
            let start_time = timer.ticks();

            for event in event_pump.poll_iter() {
                match event {
                    Quit { .. } => done = true,
                    KeyDown { keycode, .. } => {
                        match keycode {
                            Some(Escape) => done = true,
                            _ => {}
                        }
                    }
                    _ => {}
                }
            }

            let between = Range::new(0, 400);
            let target = Rect::new(between.ind_sample(&mut rng),
                                   50,
                                   between.ind_sample(&mut rng) as u32,
                                   500);
            renderer.set_draw_color(Color::rand(&mut rng));
            renderer.clear();
            renderer.copy(&mut font_texture, None, Some(target));
            renderer.present();

            if let Some(active_state) = self.get_active_state() {
                active_state.update(delta);
                active_state.draw();
            } else {
                done = true;
            }

            let end_time = timer.ticks();
            delta = Duration::from_millis((end_time - start_time) as u64);
            thread::sleep_ms(1000 / 60);
        }
    }
}
<commit_msg>Add helper method to assist with font rendering<commit_after>use state::State;
use resources::{ResourceManager, TextureManager, FontManager};
use GameError;

use std::path::Path;
use std::thread;
use std::time::Duration;

use sdl2;
use sdl2::pixels::Color;
use sdl2::event::Event::*;
use sdl2::rect::Rect;
use sdl2::keyboard::Keycode::*;
use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::surface::Surface;
use sdl2_ttf::PartialRendering;
use rand::{self, Rng, Rand};
use rand::distributions::{IndependentSample, Range};

pub struct Game<S: State> {
    states: Vec<S>
}

impl<S: State> Game<S> {
    pub fn new(initial_state: S) -> Game<S> {
        Game {
            states: vec![initial_state]
        }
    }

    pub fn push_state(&mut self, state: S) {
        self.states.push(state);
    }

    pub fn pop_state() {}

    fn get_active_state(&mut self) -> Option<&mut S> {
        self.states.last_mut()
    }

    pub fn run(&mut self) {
        let screen_width = 800;
        let screen_height = 600;

        let mut rng = rand::thread_rng();
        let sdl_context = sdl2::init().unwrap();
        let mut timer = sdl_context.timer().unwrap();
        let mut event_pump = sdl_context.event_pump().unwrap();
        let video = sdl_context.video().unwrap();

        let mut resource_manager = ResourceManager::new().unwrap();

        let window = video.window("Ruffel", 800, 600)
                          .position_centered()
                          .opengl()
                          .build()
                          .unwrap();

        let mut renderer = window.renderer()
                                 .accelerated()
                                 .build()
                                 .unwrap();

        resource_manager.load_font("DejaVuSerif", "resources/DejaVuSerif.ttf").unwrap();

        let mut font_texture1 =
            create_font_surface("roffl", "DejaVuSerif", 128, &mut resource_manager)
                            .unwrap()
                            .blended(Color::rand(&mut rng))
                            .map_err(|_| GameError::Lolwtf)
                            .and_then(|s| renderer.create_texture_from_surface(&s)
                                                  .map_err(|_| GameError::Lolwtf)).unwrap();

        let mut font_texture2 =
            create_font_surface("fizzbazz", "DejaVuSerif", 72, &mut resource_manager)
                            .unwrap()
                            .blended(Color::rand(&mut rng))
                            .map_err(|_| GameError::Lolwtf)
                            .and_then(|s| renderer.create_texture_from_surface(&s)
                                                  .map_err(|_| GameError::Lolwtf)).unwrap();

        // If the example text is too big for the screen, downscale it (and center irregardless)
        let padding = 64;

        // Initialize State handlers
        for s in &mut self.states {
            s.load();
        }

        let mut done = false;
        let mut delta = Duration::new(0, 0);
        while !done {
            let start_time = timer.ticks();

            for event in event_pump.poll_iter() {
                match event {
                    Quit { .. } => done = true,
                    KeyDown { keycode, .. } => {
                        match keycode {
                            Some(Escape) => done = true,
                            _ => {}
                        }
                    }
                    _ => {}
                }
            }

            let between = Range::new(0, 400);
            let target = Rect::new(between.ind_sample(&mut rng),
                                   50,
                                   between.ind_sample(&mut rng) as u32,
                                   500);
            renderer.set_draw_color(Color::rand(&mut rng));
            renderer.clear();
            renderer.copy(&mut font_texture1, None, Some(target));
            renderer.copy(&mut font_texture2, None, Some(target));
            renderer.present();

            if let Some(active_state) = self.get_active_state() {
                active_state.update(delta);
                active_state.draw();
            } else {
                done = true;
            }

            let end_time = timer.ticks();
            delta = Duration::from_millis((end_time - start_time) as u64);
            thread::sleep_ms(1000 / 60);
        }
    }
}

fn create_font_surface<'a>(text: &'a str,
                       font_name: &str,
                       size: u16,
                       resource_manager: &'a mut ResourceManager) -> Result<PartialRendering<'a>, GameError> {
    let mut font = try!(resource_manager.get_font(font_name, size));
    Ok(font.render(text))
}
<|endoftext|>