<commit_before>//! `gel` is an extension of sebcrozet's `nalgebra` crate, designed to facilitate OpenGL
//! mathematics.

extern crate num;
extern crate nalgebra;
extern crate glium;
extern crate rustc_serialize;

use glium::uniforms::{
    AsUniformValue,
    UniformValue,
    UniformBlock,
};

pub use num::{
    One,
    Zero,
};

pub use nalgebra::*;
/// A trait for objects able to be extended.
pub trait Extend<N> {
    type Output;

    fn extend(&self, N) -> Self::Output;
}

/// A trait for objects able to be truncated.
pub trait Truncate {
    type Output;

    fn truncate(&self) -> Self::Output;
}

/// A trait for objects able to construct view matrices.
pub trait LookAt<N> {
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self;
}

impl<N> Extend<N> for Vec0<N>
    where N: Copy
{
    type Output = Vec1<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec1::new(elem)
    }
}

impl<N> Extend<N> for Vec1<N>
    where N: Copy
{
    type Output = Vec2<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec2::new(self.x, elem)
    }
}

impl<N> Extend<N> for Vec2<N>
    where N: Copy
{
    type Output = Vec3<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec3::new(self.x, self.y, elem)
    }
}

impl<N> Extend<N> for Vec3<N>
    where N: Copy
{
    type Output = Vec4<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec4::new(self.x, self.y, self.z, elem)
    }
}

impl<N> Extend<N> for Vec4<N>
    where N: Copy
{
    type Output = Vec5<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec5::new(self.x, self.y, self.z, self.w, elem)
    }
}

impl<N> Extend<N> for Vec5<N>
    where N: Copy
{
    type Output = Vec6<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec6::new(self.x, self.y, self.z, self.w, self.a, elem)
    }
}

impl<N> Truncate for Vec1<N>
    where N: Copy
{
    type Output = Vec0<N>;

    fn truncate(&self) -> Self::Output {
        Vec0::new()
    }
}

impl<N> Truncate for Vec2<N>
    where N: Copy
{
    type Output = Vec1<N>;

    fn truncate(&self) -> Self::Output {
        Vec1::new(self.x)
    }
}

impl<N> Truncate for Vec3<N>
    where N: Copy
{
    type Output = Vec2<N>;

    fn truncate(&self) -> Self::Output {
        Vec2::new(self.x, self.y)
    }
}

impl<N> Truncate for Vec4<N>
    where N: Copy
{
    type Output = Vec3<N>;

    fn truncate(&self) -> Self::Output {
        Vec3::new(self.x, self.y, self.z)
    }
}

impl<N> Truncate for Vec5<N>
    where N: Copy
{
    type Output = Vec4<N>;

    fn truncate(&self) -> Self::Output {
        Vec4::new(self.x, self.y, self.z, self.w)
    }
}

impl<N> Truncate for Vec6<N>
    where N: Copy
{
    type Output = Vec5<N>;

    fn truncate(&self) -> Self::Output {
        Vec5::new(self.x, self.y, self.z, self.w, self.a)
    }
}

impl<N> Extend<N> for Pnt0<N>
    where N: Copy
{
    type Output = Pnt1<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt1::new(elem)
    }
}

impl<N> Extend<N> for Pnt1<N>
    where N: Copy
{
    type Output = Pnt2<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt2::new(self.x, elem)
    }
}

impl<N> Extend<N> for Pnt2<N>
    where N: Copy
{
    type Output = Pnt3<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt3::new(self.x, self.y, elem)
    }
}

impl<N> Extend<N> for Pnt3<N>
    where N: Copy
{
    type Output = Pnt4<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt4::new(self.x, self.y, self.z, elem)
    }
}

impl<N> Extend<N> for Pnt4<N>
    where N: Copy
{
    type Output = Pnt5<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt5::new(self.x, self.y, self.z, self.w, elem)
    }
}

impl<N> Extend<N> for Pnt5<N>
    where N: Copy
{
    type Output = Pnt6<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt6::new(self.x, self.y, self.z, self.w, self.a, elem)
    }
}

impl<N> Truncate for Pnt1<N>
    where N: Copy
{
    type Output = Pnt0<N>;

    fn truncate(&self) -> Self::Output {
        Pnt0::new()
    }
}

impl<N> Truncate for Pnt2<N>
    where N: Copy
{
    type Output = Pnt1<N>;

    fn truncate(&self) -> Self::Output {
        Pnt1::new(self.x)
    }
}

impl<N> Truncate for Pnt3<N>
    where N: Copy
{
    type Output = Pnt2<N>;

    fn truncate(&self) -> Self::Output {
        Pnt2::new(self.x, self.y)
    }
}

impl<N> Truncate for Pnt4<N>
    where N: Copy
{
    type Output = Pnt3<N>;

    fn truncate(&self) -> Self::Output {
        Pnt3::new(self.x, self.y, self.z)
    }
}

impl<N> Truncate for Pnt5<N>
    where N: Copy
{
    type Output = Pnt4<N>;

    fn truncate(&self) -> Self::Output {
        Pnt4::new(self.x, self.y, self.z, self.w)
    }
}

impl<N> Truncate for Pnt6<N>
    where N: Copy
{
    type Output = Pnt5<N>;

    fn truncate(&self) -> Self::Output {
        Pnt5::new(self.x, self.y, self.z, self.w, self.a)
    }
}

impl<N> LookAt<N> for Mat4<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {
        let f = (*target - *camera).normalize();
        let s = f.cross(up).normalize();
        let u = s.cross(&f);

        let mut result = Self::one();

        unsafe {
            result.set_fast((0, 0), s.x);
            result.set_fast((1, 0), s.y);
            result.set_fast((2, 0), s.z);
            result.set_fast((0, 1), u.x);
            result.set_fast((1, 1), u.y);
            result.set_fast((2, 1), u.z);
            result.set_fast((0, 2), -f.x);
            result.set_fast((1, 2), -f.y);
            result.set_fast((2, 2), -f.z);
            result.set_fast((3, 0), -(s.dot(camera)));
            result.set_fast((3, 1), -(u.dot(camera)));
            result.set_fast((3, 2), f.dot(camera));
        }

        result
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, RustcDecodable, RustcEncodable)]
pub struct Perspective<N> {
    mat: Mat4<N>,
}

impl<N> Perspective<N>
    where N: BaseFloat
{
    pub fn new(fov: N, aspect: N, znear: N, zfar: N) -> Perspective<N> {
        let one = N::one();
        let two = N::one() + N::one();

        let tan_half_fov = (fov / two).tan();

        let mut mat = Mat4::zero();
        unsafe {
            mat.set_fast((0, 0), one / (aspect * tan_half_fov));
            mat.set_fast((1, 1), one / (tan_half_fov));
            mat.set_fast((2, 2), -(zfar + znear) / (zfar - znear));
            mat.set_fast((2, 3), -one);
            mat.set_fast((3, 2), -(two * zfar * znear) / (zfar - znear));
        }

        Perspective {
            mat: mat,
        }
    }

    pub fn aspect(&self) -> N {
        self.mat.m22 / self.mat.m11
    }

    pub fn set_aspect(&mut self, aspect: N) {
        self.mat.m11 = self.mat.m22 / aspect;
    }

    pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
        &self.mat
    }

}

impl<N> Perspective<N>
    where N: BaseFloat + Clone
{
    pub fn to_mat(&self) -> Mat4<N> {
        self.mat.clone()
    }
}

impl AsUniformValue for Perspective<f32> {
    fn as_uniform_value(&self) -> UniformValue {
        let val = self.to_mat();
        UniformValue::Mat4(*val.as_array())
    }
}

impl UniformBlock for Perspective<f32> {
    fn matches(layout: &glium::program::BlockLayout, base_offset: usize)
        -> Result<(), glium::uniforms::LayoutMismatchError>
    {
        use glium::program::BlockLayout;
        use glium::uniforms::LayoutMismatchError;
        use glium::uniforms::UniformType;

        if let &BlockLayout::BasicType { ty, offset_in_buffer } = layout {
            if ty != UniformType::FloatMat4 {
                return Err(LayoutMismatchError::TypeMismatch {
                    expected: ty,
                    obtained: UniformType::FloatMat4,
                });
            }

            if offset_in_buffer != base_offset {
                return Err(LayoutMismatchError::OffsetMismatch {
                    expected: offset_in_buffer,
                    obtained: base_offset,
                });
            }

            Ok(())
        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: BlockLayout::BasicType {
                    ty: UniformType::FloatMat4,
                    offset_in_buffer: base_offset,
                }
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> glium::program::BlockLayout {
        use glium::program::BlockLayout;
        use glium::uniforms::UniformType;

        BlockLayout::BasicType {
            ty: UniformType::FloatMat4,
            offset_in_buffer: base_offset,
        }
    }
}
pub fn radians<N>(n: N) -> N
    where N: BaseFloat
{
    n * (N::pi() / <N as Cast<f64>>::from(180.0))
}

pub fn degrees<N>(n: N) -> N
    where N: BaseFloat
{
    n * (<N as Cast<f64>>::from(180.0) / N::pi())
}

pub fn extend<T, N>(base: T, elem: N) -> T::Output
    where T: Extend<N>
{
    base.extend(elem)
}

pub fn truncate<T>(base: T) -> T::Output
    where T: Truncate
{
    base.truncate()
}

<commit_msg>dont use set_fast<commit_after>//! `gel` is an extension of sebcrozet's `nalgebra` crate, designed to facilitate OpenGL
//! mathematics.

extern crate num;
extern crate nalgebra;
extern crate glium;
extern crate rustc_serialize;

use glium::uniforms::{
    AsUniformValue,
    UniformValue,
    UniformBlock,
};

pub use num::{
    One,
    Zero,
};

pub use nalgebra::*;
/// A trait for objects able to be extended.
pub trait Extend<N> {
    type Output;

    fn extend(&self, N) -> Self::Output;
}

/// A trait for objects able to be truncated.
pub trait Truncate {
    type Output;

    fn truncate(&self) -> Self::Output;
}

/// A trait for objects able to construct view matrices.
pub trait LookAt<N> {
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self;
}

impl<N> Extend<N> for Vec0<N>
    where N: Copy
{
    type Output = Vec1<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec1::new(elem)
    }
}

impl<N> Extend<N> for Vec1<N>
    where N: Copy
{
    type Output = Vec2<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec2::new(self.x, elem)
    }
}

impl<N> Extend<N> for Vec2<N>
    where N: Copy
{
    type Output = Vec3<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec3::new(self.x, self.y, elem)
    }
}

impl<N> Extend<N> for Vec3<N>
    where N: Copy
{
    type Output = Vec4<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec4::new(self.x, self.y, self.z, elem)
    }
}

impl<N> Extend<N> for Vec4<N>
    where N: Copy
{
    type Output = Vec5<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec5::new(self.x, self.y, self.z, self.w, elem)
    }
}

impl<N> Extend<N> for Vec5<N>
    where N: Copy
{
    type Output = Vec6<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Vec6::new(self.x, self.y, self.z, self.w, self.a, elem)
    }
}

impl<N> Truncate for Vec1<N>
    where N: Copy
{
    type Output = Vec0<N>;

    fn truncate(&self) -> Self::Output {
        Vec0::new()
    }
}

impl<N> Truncate for Vec2<N>
    where N: Copy
{
    type Output = Vec1<N>;

    fn truncate(&self) -> Self::Output {
        Vec1::new(self.x)
    }
}

impl<N> Truncate for Vec3<N>
    where N: Copy
{
    type Output = Vec2<N>;

    fn truncate(&self) -> Self::Output {
        Vec2::new(self.x, self.y)
    }
}

impl<N> Truncate for Vec4<N>
    where N: Copy
{
    type Output = Vec3<N>;

    fn truncate(&self) -> Self::Output {
        Vec3::new(self.x, self.y, self.z)
    }
}

impl<N> Truncate for Vec5<N>
    where N: Copy
{
    type Output = Vec4<N>;

    fn truncate(&self) -> Self::Output {
        Vec4::new(self.x, self.y, self.z, self.w)
    }
}

impl<N> Truncate for Vec6<N>
    where N: Copy
{
    type Output = Vec5<N>;

    fn truncate(&self) -> Self::Output {
        Vec5::new(self.x, self.y, self.z, self.w, self.a)
    }
}

impl<N> Extend<N> for Pnt0<N>
    where N: Copy
{
    type Output = Pnt1<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt1::new(elem)
    }
}

impl<N> Extend<N> for Pnt1<N>
    where N: Copy
{
    type Output = Pnt2<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt2::new(self.x, elem)
    }
}

impl<N> Extend<N> for Pnt2<N>
    where N: Copy
{
    type Output = Pnt3<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt3::new(self.x, self.y, elem)
    }
}

impl<N> Extend<N> for Pnt3<N>
    where N: Copy
{
    type Output = Pnt4<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt4::new(self.x, self.y, self.z, elem)
    }
}

impl<N> Extend<N> for Pnt4<N>
    where N: Copy
{
    type Output = Pnt5<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt5::new(self.x, self.y, self.z, self.w, elem)
    }
}

impl<N> Extend<N> for Pnt5<N>
    where N: Copy
{
    type Output = Pnt6<N>;

    fn extend(&self, elem: N) -> Self::Output {
        Pnt6::new(self.x, self.y, self.z, self.w, self.a, elem)
    }
}

impl<N> Truncate for Pnt1<N>
    where N: Copy
{
    type Output = Pnt0<N>;

    fn truncate(&self) -> Self::Output {
        Pnt0::new()
    }
}

impl<N> Truncate for Pnt2<N>
    where N: Copy
{
    type Output = Pnt1<N>;

    fn truncate(&self) -> Self::Output {
        Pnt1::new(self.x)
    }
}

impl<N> Truncate for Pnt3<N>
    where N: Copy
{
    type Output = Pnt2<N>;

    fn truncate(&self) -> Self::Output {
        Pnt2::new(self.x, self.y)
    }
}

impl<N> Truncate for Pnt4<N>
    where N: Copy
{
    type Output = Pnt3<N>;

    fn truncate(&self) -> Self::Output {
        Pnt3::new(self.x, self.y, self.z)
    }
}

impl<N> Truncate for Pnt5<N>
    where N: Copy
{
    type Output = Pnt4<N>;

    fn truncate(&self) -> Self::Output {
        Pnt4::new(self.x, self.y, self.z, self.w)
    }
}

impl<N> Truncate for Pnt6<N>
    where N: Copy
{
    type Output = Pnt5<N>;

    fn truncate(&self) -> Self::Output {
        Pnt5::new(self.x, self.y, self.z, self.w, self.a)
    }
}

impl<N> LookAt<N> for Mat4<N>
    where N: BaseFloat
{
    fn look_at(camera: &Vec3<N>, target: &Vec3<N>, up: &Vec3<N>) -> Self {
        let f = (*target - *camera).normalize();
        let s = f.cross(up).normalize();
        let u = s.cross(&f);

        let mut result = Self::one();

        result.m11 = s.x;
        result.m21 = s.y;
        result.m31 = s.z;
        result.m12 = u.x;
        result.m22 = u.y;
        result.m32 = u.z;
        result.m13 = -f.x;
        result.m23 = -f.y;
        result.m33 = -f.z;
        result.m41 = -(s.dot(camera));
        result.m42 = -(u.dot(camera));
        result.m43 = f.dot(camera);

        result
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, RustcDecodable, RustcEncodable)]
pub struct Perspective<N> {
    mat: Mat4<N>,
}

impl<N> Perspective<N>
    where N: BaseFloat
{
    pub fn new(fov: N, aspect: N, znear: N, zfar: N) -> Perspective<N> {
        let one = N::one();
        let two = N::one() + N::one();

        let tan_half_fov = (fov / two).tan();

        let mut mat = Mat4::zero();

        mat.m11 = one / (aspect * tan_half_fov);
        mat.m22 = one / (tan_half_fov);
        mat.m33 = -(zfar + znear) / (zfar - znear);
        mat.m34 = -one;
        mat.m43 = -(two * zfar * znear) / (zfar - znear);

        Perspective {
            mat: mat,
        }
    }

    pub fn aspect(&self) -> N {
        self.mat.m22 / self.mat.m11
    }

    pub fn set_aspect(&mut self, aspect: N) {
        self.mat.m11 = self.mat.m22 / aspect;
    }

    pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
        &self.mat
    }

}

impl<N> Perspective<N>
    where N: BaseFloat + Clone
{
    pub fn to_mat(&self) -> Mat4<N> {
        self.mat.clone()
    }
}

impl AsUniformValue for Perspective<f32> {
    fn as_uniform_value(&self) -> UniformValue {
        let val = self.to_mat();
        UniformValue::Mat4(*val.as_array())
    }
}

impl UniformBlock for Perspective<f32> {
    fn matches(layout: &glium::program::BlockLayout, base_offset: usize)
        -> Result<(), glium::uniforms::LayoutMismatchError>
    {
        use glium::program::BlockLayout;
        use glium::uniforms::LayoutMismatchError;
        use glium::uniforms::UniformType;

        if let &BlockLayout::BasicType { ty, offset_in_buffer } = layout {
            if ty != UniformType::FloatMat4 {
                return Err(LayoutMismatchError::TypeMismatch {
                    expected: ty,
                    obtained: UniformType::FloatMat4,
                });
            }

            if offset_in_buffer != base_offset {
                return Err(LayoutMismatchError::OffsetMismatch {
                    expected: offset_in_buffer,
                    obtained: base_offset,
                });
            }

            Ok(())
        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: BlockLayout::BasicType {
                    ty: UniformType::FloatMat4,
                    offset_in_buffer: base_offset,
                }
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> glium::program::BlockLayout {
        use glium::program::BlockLayout;
        use glium::uniforms::UniformType;

        BlockLayout::BasicType {
            ty: UniformType::FloatMat4,
            offset_in_buffer: base_offset,
        }
    }
}
pub fn radians<N>(n: N) -> N
    where N: BaseFloat
{
    n * (N::pi() / <N as Cast<f64>>::from(180.0))
}

pub fn degrees<N>(n: N) -> N
    where N: BaseFloat
{
    n * (<N as Cast<f64>>::from(180.0) / N::pi())
}

pub fn extend<T, N>(base: T, elem: N) -> T::Output
    where T: Extend<N>
{
    base.extend(elem)
}

pub fn truncate<T>(base: T) -> T::Output
    where T: Truncate
{
    base.truncate()
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(slicing_syntax)]

extern crate "rust-md2" as md2;

use md2::{SBOX, SBOXI};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::iter::range_inclusive;
use std::slice::bytes::{copy_memory, MutableByteVector};

struct ByteRange {
  v: Vec<u8>
}

impl ByteRange {
  fn new(n: uint) -> ByteRange {
    ByteRange { v: Vec::from_elem(n, 0u8) }
  }
}

impl Iterator<Vec<u8>> for ByteRange {
  fn next(&mut self) -> Option<Vec<u8>> {
    for i in range(0, self.v.len()).rev() {
      if self.v[i] == 255 {
        continue;
      }

      // Increase.
      self.v[i] += 1;

      // Zero all bytes right of the current index.
      self.v[mut i+1..].set_memory(0);

      return Some(self.v.clone());
    }

    None
  }
}

pub struct Collisions {
  map: HashMap<Vec<u8>,Vec<Vec<u8>>>
}

impl Collisions {
  pub fn new() -> Collisions {
    Collisions { map: HashMap::new() }
  }

  pub fn add(&mut self, key: Vec<u8>, msg: Vec<u8>) {
    match self.map.entry(key) {
      Vacant(entry) => { entry.set(vec!(msg)); },
      Occupied(mut entry) => { entry.get_mut().push(msg); }
    }
  }

  pub fn merge(&mut self, other: Collisions) {
    for (key, msgs) in other.map.into_iter() {
      match self.map.entry(key) {
        Vacant(entry) => { entry.set(msgs); },
        Occupied(mut entry) => { entry.get_mut().push_all(msgs[]); }
      }
    }
  }

  pub fn validate(&self) -> bool {
    self.map.values().all(|msgs| {
      let empty = [0u8, ..16];
      let mut first_hash: Option<[u8, ..16]> = None;
      let hashes = msgs.iter().map(|msg| md2::compress(&empty, msg[]));

      hashes.all(|md2| {
        first_hash.map_or_else(|| { first_hash = Some(md2); true }, |v| v == md2)
      })
    })
  }

  pub fn count(&self) -> uint {
    self.map.values().fold(0u, |count, msgs| count + msgs.len() - 1)
  }
}

pub fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
  let rows = 16 - k;
  let mut state = [[0u8, ..49], ..19];

  for row in range_inclusive(1, rows) {
    // Fill row of T1.
    for i in range(1, 17) {
      state[row][i] = SBOX[state[row][i - 1] as uint] ^ state[row - 1][i];
    }

    // Last bytes are equal.
    state[row][32] = state[row][16];
    state[row][48] = state[row][16];

    // Next t value.
    state[row + 1][0] = state[row][48] + (row as u8) - 1;
  }

  // Compute triangles.
  for col in range(0, rows) {
    for row in range_inclusive(2 + col, rows).rev() {
      state[row][32 - col - 1] = SBOXI[(state[row][32 - col] ^ state[row - 1][32 - col]) as uint];
      state[row][48 - col - 1] = SBOXI[(state[row][48 - col] ^ state[row - 1][48 - col]) as uint];
    }
  }

  state
}

pub fn find_collisions(state: &[u8], k: uint) -> Collisions {
  let rows = 16 - k;
  assert_eq!(state.len(), 48);
  let mut state = state.to_vec();
  let mut collisions = Collisions::new();

  let k = 2;
  for bytes in ByteRange::new(k) {
    copy_memory(state[mut 16..16+k], bytes[]);
    copy_memory(state[mut 16+16..16+k+16], bytes[]);

    let key = compress(state[], rows);
    let msg = decompress(state[], rows);
    collisions.add(key, msg);
  }

  collisions
}

fn compress(state: &[u8], iteration: uint) -> Vec<u8> {
  let mut t = state[47] + iteration as u8 - 1;
  let mut x = state.to_vec();

  for row in range(iteration, 18) {
    for byte in x.iter_mut() {
      *byte ^= SBOX[t as uint];
      t = *byte;
    }
    t += row as u8;
  }

  x[..16].to_vec()
}

fn decompress(state: &[u8], iteration: uint) -> Vec<u8> {
  let mut x = state.to_vec();

  for row in range(0, iteration).rev() {
    for col in range(1, 48).rev() {
      x[col] ^= SBOX[x[col - 1] as uint];
    }

    let t = x[47] + (row as u8) - 1;
    x[0] ^= SBOX[t as uint];
  }

  x[16..32].to_vec()
}

#[cfg(test)]
mod test {
  use Collisions;
  use find_collisions;
  use create_initial_state;
  use std::sync::TaskPool;

  #[test]
  fn test_k2() {
    let state = create_initial_state(2);
    let collisions = find_collisions(state[14][1..], 2);

    assert!(collisions.validate());
    assert_eq!(collisions.count(), 141);
  }

  #[test]
  fn test_k3() {
    let pool = TaskPool::new(8u);
    let (tx, rx) = channel();
    let state = create_initial_state(3);

    for byte in range(0u, 256u) {
      let txc = tx.clone();
      let mut sc = state.clone();

      pool.execute(move || {
        sc[13][19] = byte as u8;
        sc[13][35] = byte as u8;

        txc.send(find_collisions(sc[13][1..], 3));
      });
    }

    // Merge partial results.
    let mut collisions = Collisions::new();
    for partial in rx.iter().take(256u) {
      collisions.merge(partial);
    }

    assert!(collisions.validate());
    assert_eq!(collisions.count(), 32784);
  }
}
<commit_msg>introduce candidates() iterator<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(slicing_syntax)]

extern crate "rust-md2" as md2;

use md2::{SBOX, SBOXI};
use std::iter::range_inclusive;
use std::slice::bytes::{copy_memory, MutableByteVector};

struct ByteRange {
  current: Vec<u8>,
  first: bool
}

impl ByteRange {
  fn new(num_bytes: uint) -> ByteRange {
    ByteRange { current: Vec::from_elem(num_bytes, 0u8), first: true }
  }
}

impl Iterator<Vec<u8>> for ByteRange {
  fn next(&mut self) -> Option<Vec<u8>> {
    // TODO make nicer
    if self.first {
      self.first = false;
      return Some(self.current.clone());
    }

    for i in range(0, self.current.len()).rev() {
      if self.current[i] == 255 {
        continue;
      }

      // Increase.
      self.current[i] += 1;

      // Zero all bytes right of the current index.
      self.current[mut i+1..].set_memory(0);

      return Some(self.current.clone());
    }

    None
  }
}

pub struct Candidates {
  range: ByteRange,
  state: Vec<u8>,
  row: uint
}

impl Iterator<(Vec<u8>, Vec<u8>)> for Candidates {
  fn next(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
    let next = self.range.next();

    // Bail out if we tried all possible combinations.
    if next.is_none() {
      return None;
    }

    // Set bytes for current candidate.
    let bytes = next.unwrap();
    copy_memory(self.state[mut 16..18], bytes[]);
    copy_memory(self.state[mut 32..34], bytes[]);

    // TODO rename variables

    // Compute the final compression value.
    let key = compress(self.state[], self.row);

    // Compute the original message leading to this state.
    let msg = decompress(self.state[], self.row);

    Some((key, msg))
  }
}

pub fn candidates(state: &[u8], row: uint) -> Candidates {
  // Test 2^16 combinations.
  let range = ByteRange::new(2);

  Candidates { range: range, state: state.to_vec(), row: row }
}

// TODO rename function
pub fn create_initial_state(num_rows: uint) -> Vec<u8> {
  let mut state = [[0u8, ..49], ..19];

  for row in range_inclusive(1, num_rows) {
    // Fill row of T1.
    for i in range(1, 17) {
      state[row][i] = SBOX[state[row][i - 1] as uint] ^ state[row - 1][i];
    }

    // Last bytes are equal.
    state[row][32] = state[row][16];
    state[row][48] = state[row][16];

    // Next t value.
    state[row + 1][0] = state[row][48] + (row as u8) - 1;
  }

  // Compute triangles.
  for col in range(0, num_rows) {
    for row in range_inclusive(2 + col, num_rows).rev() {
      // TODO make nicer
      let byte = SBOXI[(state[row][32 - col] ^ state[row - 1][32 - col]) as uint];
      state[row][32 - col - 1] = byte;
      state[row][48 - col - 1] = byte;
    }
  }

  // TODO explain
  state[num_rows][1..].to_vec()
}

fn compress(state: &[u8], iteration: uint) -> Vec<u8> {
  let mut t = state[47] + iteration as u8 - 1;
  let mut x = state.to_vec();

  // TODO explain
  for row in range(iteration, 18) {
    for byte in x.iter_mut() {
      *byte ^= SBOX[t as uint];
      t = *byte;
    }
    t += row as u8;
  }

  x[..16].to_vec()
}

fn decompress(state: &[u8], iteration: uint) -> Vec<u8> {
  let mut x = state.to_vec();

  // TODO explain
  for row in range(0, iteration).rev() {
    for col in range(1, 48).rev() {
      x[col] ^= SBOX[x[col - 1] as uint];
    }

    let t = x[47] + (row as u8) - 1;
    x[0] ^= SBOX[t as uint];
  }

  x[16..32].to_vec()
}

#[cfg(test)]
mod test {
  use candidates;
  use create_initial_state;

  use md2::compress;
  use std::collections::HashMap;
  use std::collections::hash_map::Entry::{Occupied, Vacant};
  use std::sync::TaskPool;

  // Count the number of map entries that have more than a single message.
  // Those will compress to the same final value and thus represent collisions.
  fn count(map: &HashMap<Vec<u8>,Vec<Vec<u8>>>) -> uint {
    map.values().fold(0u, |count, msgs| count + msgs.len() - 1)
  }

  // Validate all colliding entries in the given map to ensure that those
  // messages do indeed collide when computing their compressed values.
  fn validate(map: &HashMap<Vec<u8>,Vec<Vec<u8>>>) -> bool {
    map.values().filter(|msgs| msgs.len() > 1).all(|msgs| {
      let empty = [0u8, ..16];
      // TODO rename "hash" variables
      let mut first_hash: Option<[u8, ..16]> = None;
      let hashes = msgs.iter().map(|msg| compress(&empty, msg[]));

      hashes.all(|md2| { // TODO rename |md2|
        first_hash.map_or_else(|| { first_hash = Some(md2); true }, |v| v == md2)
      })
    })
  }

  #[test]
  fn test_k2() {
    let state = create_initial_state(14);

    // There will be ~2^16 entries (minus collisions).
    let mut map = HashMap::with_capacity(256u * 256u);

    // TODO rename variables
    for (key, msg) in candidates(state[], 14) {
      match map.entry(key) {
        Vacant(entry) => { entry.set(vec!(msg)); },
        Occupied(mut entry) => { entry.get_mut().push(msg); }
      }
    }

    assert!(validate(&map));
    assert_eq!(count(&map), 141);
  }

  #[test]
  fn test_k3() {
    let pool = TaskPool::new(8u);
    let (tx, rx) = channel();
    let state = create_initial_state(13);

    for byte in range(0u, 256u) {
      let txc = tx.clone();
      let mut state = state.clone();

      pool.execute(move || {
        // TODO explain
        state[18] = byte as u8;
        state[34] = byte as u8;

        for (key, msg) in candidates(state[], 13) {
          txc.send((key, msg));
        }
      });
    }

    // There will be ~2^24 entries (minus collisions).
    let total = 256u * 256u * 256u;
    let mut map = HashMap::with_capacity(total);

    // Merge partial results.
    let mut c = 0u;
    let mut last_percent = 0;
    for (key, msg) in rx.iter().take(total) {
      match map.entry(key) {
        Vacant(entry) => { entry.set(vec!(msg)); },
        Occupied(mut entry) => { entry.get_mut().push(msg); }
      }

      let percent = c / (total / 100);
      if last_percent != percent {
        last_percent = percent;
        println!("count = {} / {} ({}%)", c, total, percent);
      }
      c += 1;
    }

    assert!(validate(&map));
    assert_eq!(count(&map), 32784);
  }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate mimir;
extern crate osm_boundaries_utils;
extern crate osmpbfreader;

use self::osm_boundaries_utils::build_boundary;
use super::OsmPbfReader;
use admin_geofinder::AdminGeoFinder;
use itertools::Itertools;
use osm_reader::osm_utils::make_centroid;
use std::cell::Cell;
use std::collections::BTreeSet;
pub type StreetsVec = Vec<mimir::Street>;

#[derive(Debug)]
pub struct AdminMatcher {
    admin_levels: BTreeSet<u32>,
}

impl AdminMatcher {
    pub fn new(levels: BTreeSet<u32>) -> AdminMatcher {
        AdminMatcher {
            admin_levels: levels,
        }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags
                    .get("boundary")
                    .map_or(false, |v| v == "administrative")
                    && rel.tags.get("admin_level").map_or(false, |lvl| {
                        self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                    })
            }
            _ => false,
        }
    }
}

pub fn administrative_regions(
    pbf: &mut OsmPbfReader,
    levels: BTreeSet<u32>,
    city_level: u32,
) -> Vec<mimir::Admin> {
    let mut administrative_regions = Vec::<mimir::Admin>::new();
    let mut insee_inserted = BTreeSet::default();
    let matcher = AdminMatcher::new(levels);
    info!("reading pbf...");
    let objects = pbf.get_objs_and_deps(|o| matcher.is_admin(o)).unwrap();
    info!("reading pbf done.");

    // load administratives regions
    for obj in objects.values() {
        if !matcher.is_admin(obj) {
            continue;
        }

        if let osmpbfreader::OsmObj::Relation(ref relation) = *obj {
            let level = relation
                .tags
                .get("admin_level")
                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    warn!(
                        "relation/{} ({}): invalid admin_level: {:?}, skipped",
                        relation.id.0,
                        relation.tags.get("name").map_or("", String::as_str),
                        relation.tags.get("admin_level")
                    );
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!(
                        "relation/{}: adminstrative region without name, skipped",
                        relation.id.0
                    );
                    continue;
                }
            };

            // admininstrative region without coordinates
            let coord_center = relation
                .refs
                .iter()
                .find(|r| r.role == "admin_centre")
                .and_then(|r| objects.get(&r.member))
                .and_then(|o| o.node())
                .map(|node| mimir::Coord::new(node.lon(), node.lat()));
            let (admin_id, insee_id) = match relation
                .tags
                .get("ref:INSEE")
                .map(|v| v.trim_left_matches('0'))
            {
                Some(val) if !insee_inserted.contains(val) => {
                    insee_inserted.insert(val.to_string());
                    (format!("admin:fr:{}", val), val)
                }
                Some(val) => {
                    let id = format!("admin:osm:{}", relation.id.0);
                    warn!(
                        "relation/{}: have the INSEE {} that is already used, using {} as id",
                        relation.id.0, val, id
                    );
                    (id, val)
                }
                None => (format!("admin:osm:{}", relation.id.0), ""),
            };

            let admin_type = get_admin_type(level, city_level);
            let zip_code = relation
                .tags
                .get("addr:postcode")
                .or_else(|| relation.tags.get("postal_code"))
                .map_or("", |val| &val[..]);
            let zip_codes = zip_code
                .split(';')
                .filter(|s| !s.is_empty())
                .map(|s| s.to_string())
                .sorted();
            let boundary = build_boundary(relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                insee: insee_id.to_string(),
                level: level,
                name: name.to_string(),
                label: format!("{}{}", name.to_string(), format_zip_codes(&zip_codes)),
                zip_codes: zip_codes,
                weight: Cell::new(0.),
                coord: coord_center.unwrap_or_else(|| make_centroid(&boundary)),
                boundary: boundary,
                admin_type: admin_type,
            };
            administrative_regions.push(admin);
        }
    }
    administrative_regions
}

pub fn get_admin_type(level: u32, city_lvl: u32) -> mimir::AdminType {
    if level == city_lvl {
        mimir::AdminType::City
    } else {
        mimir::AdminType::Unknown
    }
}

pub fn compute_admin_weight(streets: &StreetsVec, admins_geofinder: &AdminGeoFinder) {
    let mut max = 1.;
    for st in streets {
        for admin in &st.administrative_regions {
            admin.weight.set(admin.weight.get() + 1.);
            max = f64::max(max, admin.weight.get());
        }
    }

    for admin in admins_geofinder.admins_without_boundary() {
        admin.weight.set(admin.weight.get() / max);
    }
}

fn format_zip_codes(zip_codes: &[String]) -> String {
    match zip_codes.len() {
        0 => "".to_string(),
        1 => format!(" ({})", zip_codes.first().unwrap()),
        _ => format!(
            " ({}-{})",
            zip_codes.first().unwrap(),
            zip_codes.last().unwrap()
        ),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn should_return_correct_admin_type() {
        assert_eq!(
            get_admin_type(1 /*level*/, 1 /*city level*/),
            mimir::AdminType::City
        );
        assert_eq!(get_admin_type(2, 1), mimir::AdminType::Unknown);
    }
}
<commit_msg>Make get_admin_type private<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate mimir;
extern crate osm_boundaries_utils;
extern crate osmpbfreader;

use self::osm_boundaries_utils::build_boundary;
use super::OsmPbfReader;
use admin_geofinder::AdminGeoFinder;
use itertools::Itertools;
use osm_reader::osm_utils::make_centroid;
use std::cell::Cell;
use std::collections::BTreeSet;
pub type StreetsVec = Vec<mimir::Street>;

#[derive(Debug)]
pub struct AdminMatcher {
    admin_levels: BTreeSet<u32>,
}

impl AdminMatcher {
    pub fn new(levels: BTreeSet<u32>) -> AdminMatcher {
        AdminMatcher {
            admin_levels: levels,
        }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags
                    .get("boundary")
                    .map_or(false, |v| v == "administrative")
                    && rel.tags.get("admin_level").map_or(false, |lvl| {
                        self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                    })
            }
            _ => false,
        }
    }
}

pub fn administrative_regions(
    pbf: &mut OsmPbfReader,
    levels: BTreeSet<u32>,
    city_level: u32,
) -> Vec<mimir::Admin> {
    let mut administrative_regions = Vec::<mimir::Admin>::new();
    let mut insee_inserted = BTreeSet::default();
    let matcher = AdminMatcher::new(levels);
    info!("reading pbf...");
    let objects = pbf.get_objs_and_deps(|o| matcher.is_admin(o)).unwrap();
    info!("reading pbf done.");

    // load administratives regions
    for obj in objects.values() {
        if !matcher.is_admin(obj) {
            continue;
        }

        if let osmpbfreader::OsmObj::Relation(ref relation) = *obj {
            let level = relation
                .tags
                .get("admin_level")
                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    warn!(
                        "relation/{} ({}): invalid admin_level: {:?}, skipped",
                        relation.id.0,
                        relation.tags.get("name").map_or("", String::as_str),
                        relation.tags.get("admin_level")
                    );
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!(
                        "relation/{}: adminstrative region without name, skipped",
                        relation.id.0
                    );
                    continue;
                }
            };

            // admininstrative region without coordinates
            let coord_center = relation
                .refs
                .iter()
                .find(|r| r.role == "admin_centre")
                .and_then(|r| objects.get(&r.member))
                .and_then(|o| o.node())
                .map(|node| mimir::Coord::new(node.lon(), node.lat()));
            let (admin_id, insee_id) = match relation
                .tags
                .get("ref:INSEE")
                .map(|v| v.trim_left_matches('0'))
            {
                Some(val) if !insee_inserted.contains(val) => {
                    insee_inserted.insert(val.to_string());
                    (format!("admin:fr:{}", val), val)
                }
                Some(val) => {
                    let id = format!("admin:osm:{}", relation.id.0);
                    warn!(
                        "relation/{}: have the INSEE {} that is already used, using {} as id",
                        relation.id.0, val, id
                    );
                    (id, val)
                }
                None => (format!("admin:osm:{}", relation.id.0), ""),
            };

            let admin_type = get_admin_type(level, city_level);
            let zip_code = relation
                .tags
                .get("addr:postcode")
                .or_else(|| relation.tags.get("postal_code"))
                .map_or("", |val| &val[..]);
            let zip_codes = zip_code
                .split(';')
                .filter(|s| !s.is_empty())
                .map(|s| s.to_string())
                .sorted();
            let boundary = build_boundary(relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                insee: insee_id.to_string(),
                level: level,
                name: name.to_string(),
                label: format!("{}{}", name.to_string(), format_zip_codes(&zip_codes)),
                zip_codes: zip_codes,
                weight: Cell::new(0.),
                coord: coord_center.unwrap_or_else(|| make_centroid(&boundary)),
                boundary: boundary,
                admin_type: admin_type,
            };
            administrative_regions.push(admin);
        }
    }
    administrative_regions
}

fn get_admin_type(level: u32, city_lvl: u32) -> mimir::AdminType {
    if level == city_lvl {
        mimir::AdminType::City
    } else {
        mimir::AdminType::Unknown
    }
}

pub fn compute_admin_weight(streets: &StreetsVec, admins_geofinder: &AdminGeoFinder) {
    let mut max = 1.;
    for st in streets {
        for admin in &st.administrative_regions {
            admin.weight.set(admin.weight.get() + 1.);
            max = f64::max(max, admin.weight.get());
        }
    }

    for admin in admins_geofinder.admins_without_boundary() {
        admin.weight.set(admin.weight.get() / max);
    }
}

fn format_zip_codes(zip_codes: &[String]) -> String {
    match zip_codes.len() {
        0 => "".to_string(),
        1 => format!(" ({})", zip_codes.first().unwrap()),
        _ => format!(
            " ({}-{})",
            zip_codes.first().unwrap(),
            zip_codes.last().unwrap()
        ),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn should_return_correct_admin_type() {
        assert_eq!(
            get_admin_type(1 /*level*/, 1 /*city level*/),
            mimir::AdminType::City
        );
        assert_eq!(get_admin_type(2, 1), mimir::AdminType::Unknown);
    }
}
<|endoftext|>


<commit_before>use core::cell::Cell;
use core::clone::Clone;
use core::mem;
use core::ops::DerefMut;
use core::option::*;

#[test]
fn test_get_ptr() {
    unsafe {
        let x: Box<_> = box 0;
        let addr_x: *const isize = mem::transmute(&*x);
        let opt = Some(x);
        let y = opt.unwrap();
        let addr_y: *const isize = mem::transmute(&*y);
        assert_eq!(addr_x, addr_y);
    }
}

#[test]
fn test_get_str() {
    let x = "test".to_string();
    let addr_x = x.as_ptr();
    let opt = Some(x);
    let y = opt.unwrap();
    let addr_y = y.as_ptr();
    assert_eq!(addr_x, addr_y);
}

#[test]
fn test_get_resource() {
    use core::cell::RefCell;
    use std::rc::Rc;

    struct R {
        i: Rc<RefCell<isize>>,
    }

    impl Drop for R {
        fn drop(&mut self) {
            let ii = &*self.i;
            let i = *ii.borrow();
            *ii.borrow_mut() = i + 1;
        }
    }

    fn r(i: Rc<RefCell<isize>>) -> R {
        R { i }
    }

    let i = Rc::new(RefCell::new(0));
    {
        let x = r(i.clone());
        let opt = Some(x);
        let _y = opt.unwrap();
    }
    assert_eq!(*i.borrow(), 1);
}

#[test]
fn test_option_dance() {
    let x = Some(());
    let mut y = Some(5);
    let mut y2 = 0;
    for _x in x {
        y2 = y.take().unwrap();
    }
    assert_eq!(y2, 5);
    assert!(y.is_none());
}

#[test]
#[should_panic]
fn test_option_too_much_dance() {
    struct A;
    let mut y = Some(A);
    let _y2 = y.take().unwrap();
    let _y3 = y.take().unwrap();
}

#[test]
fn test_and() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.and(Some(2)), Some(2));
    assert_eq!(x.and(None::<isize>), None);

    let x: Option<isize> = None;
    assert_eq!(x.and(Some(2)), None);
    assert_eq!(x.and(None::<isize>), None);
}

#[test]
fn test_and_then() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
    assert_eq!(x.and_then(|_| None::<isize>), None);

    let x: Option<isize> = None;
    assert_eq!(x.and_then(|x| Some(x + 1)), None);
    assert_eq!(x.and_then(|_| None::<isize>), None);
}

#[test]
fn test_or() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.or(Some(2)), Some(1));
    assert_eq!(x.or(None), Some(1));

    let x: Option<isize> = None;
    assert_eq!(x.or(Some(2)), Some(2));
    assert_eq!(x.or(None), None);
}

#[test]
fn test_or_else() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.or_else(|| Some(2)), Some(1));
    assert_eq!(x.or_else(|| None), Some(1));

    let x: Option<isize> = None;
    assert_eq!(x.or_else(|| Some(2)), Some(2));
    assert_eq!(x.or_else(|| None), None);
}

#[test]
fn test_unwrap() {
    assert_eq!(Some(1).unwrap(), 1);
    let s = Some("hello".to_string()).unwrap();
    assert_eq!(s, "hello");
}

#[test]
#[should_panic]
fn test_unwrap_panic1() {
    let x: Option<isize> = None;
    x.unwrap();
}

#[test]
#[should_panic]
fn test_unwrap_panic2() {
    let x: Option<String> = None;
    x.unwrap();
}

#[test]
fn test_unwrap_or() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.unwrap_or(2), 1);

    let x: Option<isize> = None;
    assert_eq!(x.unwrap_or(2), 2);
}

#[test]
fn test_unwrap_or_else() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.unwrap_or_else(|| 2), 1);

    let x: Option<isize> = None;
    assert_eq!(x.unwrap_or_else(|| 2), 2);
}

#[test]
fn test_unwrap_unchecked() {
    assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1);
    let s = unsafe { Some("hello".to_string()).unwrap_unchecked() };
    assert_eq!(s, "hello");
}

#[test]
fn test_iter() {
    let val = 5;

    let x = Some(val);
    let mut it = x.iter();

    assert_eq!(it.size_hint(), (1, Some(1)));
    assert_eq!(it.next(), Some(&val));
    assert_eq!(it.size_hint(), (0, Some(0)));
    assert!(it.next().is_none());

    let mut it = (&x).into_iter();
    assert_eq!(it.next(), Some(&val));
}

#[test]
fn test_mut_iter() {
    let mut val = 5;
    let new_val = 11;

    let mut x = Some(val);
    {
        let mut it = x.iter_mut();

        assert_eq!(it.size_hint(), (1, Some(1)));

        match it.next() {
            Some(interior) => {
                assert_eq!(*interior, val);
                *interior = new_val;
            }
            None => assert!(false),
        }

        assert_eq!(it.size_hint(), (0, Some(0)));
        assert!(it.next().is_none());
    }
    assert_eq!(x, Some(new_val));

    let mut y = Some(val);
    let mut it = (&mut y).into_iter();
    assert_eq!(it.next(), Some(&mut val));
}

#[test]
fn test_ord() {
    let small = Some(1.0f64);
    let big = Some(5.0f64);
    let nan = Some(0.0f64 / 0.0);
    assert!(!(nan < big));
    assert!(!(nan > big));
    assert!(small < big);
    assert!(None < big);
    assert!(big > None);
}

#[test]
fn test_collect() {
    let v: Option<Vec<isize>> = (0..0).map(|_| Some(0)).collect();
    assert!(v == Some(vec![]));

    let v: Option<Vec<isize>> = (0..3).map(|x| Some(x)).collect();
    assert!(v == Some(vec![0, 1, 2]));

    let v: Option<Vec<isize>> = (0..3).map(|x| if x > 1 { None } else { Some(x) }).collect();
    assert!(v == None);

    // test that it does not take more elements than it needs
    let mut functions: [Box<dyn Fn() -> Option<()>>; 3] =
        [box || Some(()), box || None, box || panic!()];

    let v: Option<Vec<()>> = functions.iter_mut().map(|f| (*f)()).collect();

    assert!(v == None);
}

#[test]
fn test_copied() {
    let val = 1;
    let val_ref = &val;
    let opt_none: Option<&'static u32> = None;
    let opt_ref = Some(&val);
    let opt_ref_ref = Some(&val_ref);

    // None works
    assert_eq!(opt_none.clone(), None);
    assert_eq!(opt_none.copied(), None);

    // Immutable ref works
    assert_eq!(opt_ref.clone(), Some(&val));
    assert_eq!(opt_ref.copied(), Some(1));

    // Double Immutable ref works
    assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
    assert_eq!(opt_ref_ref.clone().copied(), Some(&val));
    assert_eq!(opt_ref_ref.copied().copied(), Some(1));
}

#[test]
fn test_cloned() {
    let val = 1;
    let val_ref = &val;
    let opt_none: Option<&'static u32> = None;
    let opt_ref = Some(&val);
    let opt_ref_ref = Some(&val_ref);

    // None works
    assert_eq!(opt_none.clone(), None);
    assert_eq!(opt_none.cloned(), None);

    // Immutable ref works
    assert_eq!(opt_ref.clone(), Some(&val));
    assert_eq!(opt_ref.cloned(), Some(1));

    // Double Immutable ref works
    assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
    assert_eq!(opt_ref_ref.clone().cloned(), Some(&val));
    assert_eq!(opt_ref_ref.cloned().cloned(), Some(1));
}

#[test]
fn test_try() {
    fn try_option_some() -> Option<u8> {
        let val = Some(1)?;
        Some(val)
    }
    assert_eq!(try_option_some(), Some(1));

    fn try_option_none() -> Option<u8> {
        let val = None?;
        Some(val)
    }
    assert_eq!(try_option_none(), None);
}

#[test]
fn test_option_as_deref() {
    // Some: &Option<T: Deref>::Some(T) -> Option<&T::Deref::Target>::Some(&*T)
    let ref_option = &Some(&42);
    assert_eq!(ref_option.as_deref(), Some(&42));

    let ref_option = &Some(String::from("a result"));
    assert_eq!(ref_option.as_deref(), Some("a result"));

    let ref_option = &Some(vec![1, 2, 3, 4, 5]);
    assert_eq!(ref_option.as_deref(), Some([1, 2, 3, 4, 5].as_slice()));

    // None: &Option<T: Deref>>::None -> None
    let ref_option: &Option<&i32> = &None;
    assert_eq!(ref_option.as_deref(), None);
}

#[test]
fn test_option_as_deref_mut() {
    // Some: &mut Option<T: Deref>::Some(T) -> Option<&mut T::Deref::Target>::Some(&mut *T)
    let mut val = 42;
    let ref_option = &mut Some(&mut val);
    assert_eq!(ref_option.as_deref_mut(), Some(&mut 42));

    let ref_option = &mut Some(String::from("a result"));
    assert_eq!(ref_option.as_deref_mut(), Some(String::from("a result").deref_mut()));

    let ref_option = &mut Some(vec![1, 2, 3, 4, 5]);
    assert_eq!(ref_option.as_deref_mut(), Some([1, 2, 3, 4, 5].as_mut_slice()));

    // None: &mut Option<T: Deref>>::None -> None
    let ref_option: &mut Option<&mut i32> = &mut None;
    assert_eq!(ref_option.as_deref_mut(), None);
}

#[test]
fn test_replace() {
    let mut x = Some(2);
    let old = x.replace(5);

    assert_eq!(x, Some(5));
    assert_eq!(old, Some(2));

    let mut x = None;
    let old = x.replace(3);

    assert_eq!(x, Some(3));
    assert_eq!(old, None);
}

#[test]
fn option_const() {
    // test that the methods of `Option` are usable in a const context

    const OPTION: Option<usize> = Some(32);

    const REF: Option<&usize> = OPTION.as_ref();
    assert_eq!(REF, Some(&32));

    const IS_SOME: bool = OPTION.is_some();
    assert!(IS_SOME);

    const IS_NONE: bool = OPTION.is_none();
    assert!(!IS_NONE);
}

#[test]
fn test_unwrap_drop() {
    struct Dtor<'a> {
        x: &'a Cell<isize>,
    }

    impl<'a> std::ops::Drop for Dtor<'a> {
        fn drop(&mut self) {
            self.x.set(self.x.get() - 1);
        }
    }

    fn unwrap<T>(o: Option<T>) -> T {
        match o {
            Some(v) => v,
            None => panic!(),
        }
    }

    let x = &Cell::new(1);

    {
        let b = Some(Dtor { x });
        let _c = unwrap(b);
    }

    assert_eq!(x.get(), 0);
}

#[test]
pub fn option_ext() {
    let thing = "{{ f }}";
    let f = thing.find("{{");

    if f.is_none() {
        println!("None!");
    }
}
<commit_msg>Added some basic tests for `Option::unzip()` and `Option::zip()` (I noticed that zip had no tests)<commit_after>use core::cell::Cell;
use core::clone::Clone;
use core::mem;
use core::ops::DerefMut;
use core::option::*;

#[test]
fn test_get_ptr() {
    unsafe {
        let x: Box<_> = box 0;
        let addr_x: *const isize = mem::transmute(&*x);
        let opt = Some(x);
        let y = opt.unwrap();
        let addr_y: *const isize = mem::transmute(&*y);
        assert_eq!(addr_x, addr_y);
    }
}

#[test]
fn test_get_str() {
    let x = "test".to_string();
    let addr_x = x.as_ptr();
    let opt = Some(x);
    let y = opt.unwrap();
    let addr_y = y.as_ptr();
    assert_eq!(addr_x, addr_y);
}

#[test]
fn test_get_resource() {
    use core::cell::RefCell;
    use std::rc::Rc;

    struct R {
        i: Rc<RefCell<isize>>,
    }

    impl Drop for R {
        fn drop(&mut self) {
            let ii = &*self.i;
            let i = *ii.borrow();
            *ii.borrow_mut() = i + 1;
        }
    }

    fn r(i: Rc<RefCell<isize>>) -> R {
        R { i }
    }

    let i = Rc::new(RefCell::new(0));
    {
        let x = r(i.clone());
        let opt = Some(x);
        let _y = opt.unwrap();
    }
    assert_eq!(*i.borrow(), 1);
}

#[test]
fn test_option_dance() {
    let x = Some(());
    let mut y = Some(5);
    let mut y2 = 0;
    for _x in x {
        y2 = y.take().unwrap();
    }
    assert_eq!(y2, 5);
    assert!(y.is_none());
}

#[test]
#[should_panic]
fn test_option_too_much_dance() {
    struct A;
    let mut y = Some(A);
    let _y2 = y.take().unwrap();
    let _y3 = y.take().unwrap();
}

#[test]
fn test_and() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.and(Some(2)), Some(2));
    assert_eq!(x.and(None::<isize>), None);

    let x: Option<isize> = None;
    assert_eq!(x.and(Some(2)), None);
    assert_eq!(x.and(None::<isize>), None);
}

#[test]
fn test_and_then() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
    assert_eq!(x.and_then(|_| None::<isize>), None);

    let x: Option<isize> = None;
    assert_eq!(x.and_then(|x| Some(x + 1)), None);
    assert_eq!(x.and_then(|_| None::<isize>), None);
}

#[test]
fn test_or() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.or(Some(2)), Some(1));
    assert_eq!(x.or(None), Some(1));

    let x: Option<isize> = None;
    assert_eq!(x.or(Some(2)), Some(2));
    assert_eq!(x.or(None), None);
}

#[test]
fn test_or_else() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.or_else(|| Some(2)), Some(1));
    assert_eq!(x.or_else(|| None), Some(1));

    let x: Option<isize> = None;
    assert_eq!(x.or_else(|| Some(2)), Some(2));
    assert_eq!(x.or_else(|| None), None);
}

#[test]
fn test_unwrap() {
    assert_eq!(Some(1).unwrap(), 1);
    let s = Some("hello".to_string()).unwrap();
    assert_eq!(s, "hello");
}

#[test]
#[should_panic]
fn test_unwrap_panic1() {
    let x: Option<isize> = None;
    x.unwrap();
}

#[test]
#[should_panic]
fn test_unwrap_panic2() {
    let x: Option<String> = None;
    x.unwrap();
}

#[test]
fn test_unwrap_or() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.unwrap_or(2), 1);

    let x: Option<isize> = None;
    assert_eq!(x.unwrap_or(2), 2);
}

#[test]
fn test_unwrap_or_else() {
    let x: Option<isize> = Some(1);
    assert_eq!(x.unwrap_or_else(|| 2), 1);

    let x: Option<isize> = None;
    assert_eq!(x.unwrap_or_else(|| 2), 2);
}

#[test]
fn test_unwrap_unchecked() {
    assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1);
    let s = unsafe { Some("hello".to_string()).unwrap_unchecked() };
    assert_eq!(s, "hello");
}

#[test]
fn test_iter() {
    let val = 5;

    let x = Some(val);
    let mut it = x.iter();

    assert_eq!(it.size_hint(), (1, Some(1)));
    assert_eq!(it.next(), Some(&val));
    assert_eq!(it.size_hint(), (0, Some(0)));
    assert!(it.next().is_none());

    let mut it = (&x).into_iter();
    assert_eq!(it.next(), Some(&val));
}

#[test]
fn test_mut_iter() {
    let mut val = 5;
    let new_val = 11;

    let mut x = Some(val);
    {
        let mut it = x.iter_mut();

        assert_eq!(it.size_hint(), (1, Some(1)));

        match it.next() {
            Some(interior) => {
                assert_eq!(*interior, val);
                *interior = new_val;
            }
            None => assert!(false),
        }

        assert_eq!(it.size_hint(), (0, Some(0)));
        assert!(it.next().is_none());
    }
    assert_eq!(x, Some(new_val));

    let mut y = Some(val);
    let mut it = (&mut y).into_iter();
    assert_eq!(it.next(), Some(&mut val));
}

#[test]
fn test_ord() {
    let small = Some(1.0f64);
    let big = Some(5.0f64);
    let nan = Some(0.0f64 / 0.0);
    assert!(!(nan < big));
    assert!(!(nan > big));
    assert!(small < big);
    assert!(None < big);
    assert!(big > None);
}

#[test]
fn test_collect() {
    let v: Option<Vec<isize>> = (0..0).map(|_| Some(0)).collect();
    assert!(v == Some(vec![]));

    let v: Option<Vec<isize>> = (0..3).map(|x| Some(x)).collect();
    assert!(v == Some(vec![0, 1, 2]));

    let v: Option<Vec<isize>> = (0..3).map(|x| if x > 1 { None } else { Some(x) }).collect();
    assert!(v == None);

    // test that it does not take more elements than it needs
    let mut functions: [Box<dyn Fn() -> Option<()>>; 3] =
        [box || Some(()), box || None, box || panic!()];

    let v: Option<Vec<()>> = functions.iter_mut().map(|f| (*f)()).collect();

    assert!(v == None);
}

#[test]
fn test_copied() {
    let val = 1;
    let val_ref = &val;
    let opt_none: Option<&'static u32> = None;
    let opt_ref = Some(&val);
    let opt_ref_ref = Some(&val_ref);

    // None works
    assert_eq!(opt_none.clone(), None);
    assert_eq!(opt_none.copied(), None);

    // Immutable ref works
    assert_eq!(opt_ref.clone(), Some(&val));
    assert_eq!(opt_ref.copied(), Some(1));

    // Double Immutable ref works
    assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
    assert_eq!(opt_ref_ref.clone().copied(), Some(&val));
    assert_eq!(opt_ref_ref.copied().copied(), Some(1));
}

#[test]
fn test_cloned() {
    let val = 1;
    let val_ref = &val;
    let opt_none: Option<&'static u32> = None;
    let opt_ref = Some(&val);
    let opt_ref_ref = Some(&val_ref);

    // None works
    assert_eq!(opt_none.clone(), None);
    assert_eq!(opt_none.cloned(), None);

    // Immutable ref works
    assert_eq!(opt_ref.clone(), Some(&val));
    assert_eq!(opt_ref.cloned(), Some(1));

    // Double Immutable ref works
    assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
    assert_eq!(opt_ref_ref.clone().cloned(), Some(&val));
    assert_eq!(opt_ref_ref.cloned().cloned(), Some(1));
}

#[test]
fn test_try() {
    fn try_option_some() -> Option<u8> {
        let val = Some(1)?;
        Some(val)
    }
    assert_eq!(try_option_some(), Some(1));

    fn try_option_none() -> Option<u8> {
        let val = None?;
        Some(val)
    }
    assert_eq!(try_option_none(), None);
}

#[test]
fn test_option_as_deref() {
    // Some: &Option<T: Deref>::Some(T) -> Option<&T::Deref::Target>::Some(&*T)
    let ref_option = &Some(&42);
    assert_eq!(ref_option.as_deref(), Some(&42));

    let ref_option = &Some(String::from("a result"));
    assert_eq!(ref_option.as_deref(), Some("a result"));

    let ref_option = &Some(vec![1, 2, 3, 4, 5]);
    assert_eq!(ref_option.as_deref(), Some([1, 2, 3, 4, 5].as_slice()));

    // None: &Option<T: Deref>>::None -> None
    let ref_option: &Option<&i32> = &None;
    assert_eq!(ref_option.as_deref(), None);
}

#[test]
fn test_option_as_deref_mut() {
    // Some: &mut Option<T: Deref>::Some(T) -> Option<&mut T::Deref::Target>::Some(&mut *T)
    let mut val = 42;
    let ref_option = &mut Some(&mut val);
    assert_eq!(ref_option.as_deref_mut(), Some(&mut 42));

    let ref_option = &mut Some(String::from("a result"));
    assert_eq!(ref_option.as_deref_mut(), Some(String::from("a result").deref_mut()));

    let ref_option = &mut Some(vec![1, 2, 3, 4, 5]);
    assert_eq!(ref_option.as_deref_mut(), Some([1, 2, 3, 4, 5].as_mut_slice()));

    // None: &mut Option<T: Deref>>::None -> None
    let ref_option: &mut Option<&mut i32> = &mut None;
    assert_eq!(ref_option.as_deref_mut(), None);
}

#[test]
fn test_replace() {
    let mut x = Some(2);
    let old = x.replace(5);

    assert_eq!(x, Some(5));
    assert_eq!(old, Some(2));

    let mut x = None;
    let old = x.replace(3);

    assert_eq!(x, Some(3));
    assert_eq!(old, None);
}

#[test]
fn option_const() {
    // test that the methods of `Option` are usable in a const context

    const OPTION: Option<usize> = Some(32);

    const REF: Option<&usize> = OPTION.as_ref();
    assert_eq!(REF, Some(&32));

    const IS_SOME: bool = OPTION.is_some();
    assert!(IS_SOME);

    const IS_NONE: bool = OPTION.is_none();
    assert!(!IS_NONE);
}

#[test]
fn test_unwrap_drop() {
    struct Dtor<'a> {
        x: &'a Cell<isize>,
    }

    impl<'a> std::ops::Drop for Dtor<'a> {
        fn drop(&mut self) {
            self.x.set(self.x.get() - 1);
        }
    }

    fn unwrap<T>(o: Option<T>) -> T {
        match o {
            Some(v) => v,
            None => panic!(),
        }
    }

    let x = &Cell::new(1);

    {
        let b = Some(Dtor { x });
        let _c = unwrap(b);
    }

    assert_eq!(x.get(), 0);
}

#[test]
fn option_ext() {
    let thing = "{{ f }}";
    let f = thing.find("{{");

    if f.is_none() {
        println!("None!");
    }
}

#[test]
fn zip_options() {
    let x = Some(10);
    let y = Some("foo");
    let z: Option<usize> = None;

    assert_eq!(x.zip(y), Some((10, "foo")));
    assert_eq!(x.zip(z), None);
    assert_eq!(z.zip(x), None);
}

#[test]
fn unzip_options() {
    let x = Some((10, "foo"));
    let y = None::<(bool, i32)>;

    assert_eq!(x.unzip(), (Some(10), Some("foo")));
    assert_eq!(y.unzip(), (None, None));
}

#[test]
fn zip_unzip_roundtrip() {
    let x = Some(10);
    let y = Some("foo");

    let z = x.zip(y);
    assert_eq!(z, Some((10, "foo")));

    let a = z.unzip();
    assert_eq!(a, (x, y));
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::comm::{
  Port,
  Chan
};
use std;
use glfw;

pub struct CursorPosEvent {
  x: f32,
  y: f32
}

struct CursorPosContext {
  chan: Chan<CursorPosEvent>
}

impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, _: &glfw::Window, xpos: f64, ypos: f64) {
    self.chan.send(CursorPosEvent {
      x: xpos as f32,
      y: ypos as f32
    });
  }
}

pub struct KeyEvent {
  key: glfw::Key,
  action: glfw::Action
}

struct KeyContext {
  chan: Chan<KeyEvent>
}

impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    _:      &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    self.chan.send(KeyEvent {
      key: key,
      action: action
    });
  }
}

pub struct EventPorts {
  key_event_port: Port<KeyEvent>,
  cursor_pos_event_port: Port<CursorPosEvent>,
}

impl EventPorts {
  pub fn new(glfw_win: &glfw::Window) -> EventPorts {
    let (key_event_port, key_event_chan) = Chan::new();
    let (cursor_pos_event_port, cursor_pos_chan) = Chan::new();

    let event_ports = EventPorts {
      key_event_port: key_event_port,
      cursor_pos_event_port: cursor_pos_event_port,
    };

    glfw_win.set_key_callback(
      ~KeyContext{chan: key_event_chan});
    glfw_win.set_cursor_pos_callback(
      ~CursorPosContext{chan: cursor_pos_chan});

    event_ports
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>EventPorts::new(): Style fixes<commit_after>// See LICENSE file for copyright and license details.

use std::comm::{
  Port,
  Chan
};
use std;
use glfw;

pub struct CursorPosEvent {
  x: f32,
  y: f32
}

struct CursorPosContext {
  chan: Chan<CursorPosEvent>
}

impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, _: &glfw::Window, xpos: f64, ypos: f64) {
    self.chan.send(CursorPosEvent {
      x: xpos as f32,
      y: ypos as f32
    });
  }
}

pub struct KeyEvent {
  key: glfw::Key,
  action: glfw::Action
}

struct KeyContext {
  chan: Chan<KeyEvent>
}

impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    _:      &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    self.chan.send(KeyEvent {
      key: key,
      action: action
    });
  }
}

pub struct EventPorts {
  key_event_port: Port<KeyEvent>,
  cursor_pos_event_port: Port<CursorPosEvent>,
}

impl EventPorts {
  pub fn new(glfw_win: &glfw::Window) -> EventPorts {
    let (key_event_port, key_event_chan) = Chan::new();
    let (cursor_pos_event_port, cursor_pos_chan) = Chan::new();
    glfw_win.set_key_callback(
      ~KeyContext{chan: key_event_chan});
    glfw_win.set_cursor_pos_callback(
      ~CursorPosContext{chan: cursor_pos_chan});
    EventPorts {
      key_event_port: key_event_port,
      cursor_pos_event_port: cursor_pos_event_port,
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>use std::f32::consts::PI;
use std::fs::File;
use std::os::raw::c_void;
use std::path::Path;
use std::process;
use std::time::Instant;

use cgmath::{ Point3 };
use gl;
use glutin;
use glutin::{
    MouseScrollDelta,
    MouseButton,
    GlContext,
    VirtualKeyCode,
    WindowEvent,
};
use glutin::ElementState::*;

use gltf_importer;
use gltf_importer::config::ValidationStrategy;
use image::{DynamicImage, ImageFormat};

use controls::{CameraControls, OrbitControls, NavState};
use controls::CameraMovement::*;
use framebuffer::Framebuffer;
use render::*;
use render::math::*;
use utils::{print_elapsed, FrameTimer, gl_check_error};

// TODO!: complete and pass through draw calls? or get rid of multiple shaders?
// How about state ordering anyway?
// struct DrawState {
//     current_shader: ShaderFlags,
//     back_face_culling_enabled: bool
// }

pub struct GltfViewer {
    width: u32,
    height: u32,

    controls: CameraControls,
    orbit_controls: OrbitControls,
    first_mouse: bool,
    last_x: f32,
    last_y: f32,
    events_loop: Option<glutin::EventsLoop>,
    gl_window: Option<glutin::GlWindow>,

    // TODO!: get rid of scene?
    root: Root,
    scene: Scene,

    delta_time: f64, // seconds
    last_frame: Instant,

    render_timer: FrameTimer,
}

impl GltfViewer {
    pub fn new(source: &str, width: u32, height: u32, headless: bool) -> GltfViewer {
        let (events_loop, gl_window, width, height) =
            if headless {
                let headless_context = glutin::HeadlessRendererBuilder::new(width, height).build().unwrap();
                unsafe { headless_context.make_current().unwrap() }
                gl::load_with(|symbol| headless_context.get_proc_address(symbol) as *const _);
                let framebuffer = Framebuffer::new(width, height);
                framebuffer.bind();
                unsafe { gl::Viewport(0, 0, width as i32, height as i32); }

                (None, None, width, height) // TODO: real height (retina?)
            }
            else {
                // glutin: initialize and configure
                let events_loop = glutin::EventsLoop::new();

                // TODO?: hints for 4.1, core profile, forward compat
                let window = glutin::WindowBuilder::new()
                        .with_title("gltf-viewer")
                        .with_dimensions(width, height)
                        .with_visibility(true);

                let context = glutin::ContextBuilder::new()
                    .with_vsync(true);
                let gl_window = glutin::GlWindow::new(window, context, &events_loop).unwrap();

                // Real dimensions might be much higher on High-DPI displays
                let (real_width, real_height) = gl_window.get_inner_size().unwrap();

                unsafe { gl_window.make_current().unwrap(); }

                // gl: load all OpenGL function pointers
                gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);

                (Some(events_loop), Some(gl_window), real_width, real_height)
            };

        // TODO!!: tmp duplicated camera controls
        let mut controls = CameraControls {
            position: Point3::new(0.0, 0.0, 2.0),
            camera: Camera::default(),
            ..CameraControls::default()
        };
        controls.camera.fovy = 60.0;
        controls.camera.update_aspect_ratio(width as f32 / height as f32); // updates projection matrix

        let mut orbit_controls = OrbitControls::new(
            Point3::new(0.0, 0.0, 2.0), width as f32, height as f32
        );
        orbit_controls.camera = Camera::default();
        orbit_controls.camera.fovy = 60.0;
        orbit_controls.camera.update_aspect_ratio(width as f32 / height as f32); // updates projection matrix

        let first_mouse = true;
        let last_x: f32 = width as f32 / 2.0;
        let last_y: f32 = height as f32 / 2.0;

        unsafe {
            gl::ClearColor(0.0, 1.0, 0.0, 1.0); // green for debugging
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            if headless {
                // transparent background for screenshots
                gl::ClearColor(0.0, 0.0, 0.0, 0.0);
            }
            else {
                gl::ClearColor(0.1, 0.2, 0.3, 1.0);
            }

            gl::Enable(gl::DEPTH_TEST);

            // TODO: keyboard switch?
            // draw in wireframe
            // gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
        };

        let (root, scene) = Self::load(source);
        let mut viewer = GltfViewer {
            width,
            height,

            controls,
            orbit_controls,
            first_mouse, last_x, last_y,

            events_loop,
            gl_window,

            root,
            scene,

            delta_time: 0.0, // seconds
            last_frame: Instant::now(),

            render_timer: FrameTimer::new("rendering", 300),
        };
        unsafe { gl_check_error!(); }

        // TODO!!!: completely broken (using gltf camera)
        if false && !viewer.root.camera_nodes.is_empty() {
            // Take first camera node
            let cam_node = &viewer.root.get_camera_node(0);
            viewer.controls.set_camera(
                cam_node.camera.as_ref().unwrap(),
                &cam_node.final_transform);
        } else {
            viewer.set_camera_from_bounds();
        }

        viewer
    }

    pub fn load(source: &str) -> (Root, Scene) {
        let mut start_time = Instant::now();
        // TODO!: http source
        // let gltf =
        if source.starts_with("http") {
            panic!("not implemented: HTTP support temporarily removed.")
            // let http_source = HttpSource::new(source);
            // let import = gltf::Import::custom(http_source, Default::default());
            // let gltf = import_gltf(import);
            // println!(); // to end the "progress dots"
            // gltf
        }
        //     else {
        let config = gltf_importer::Config { validation_strategy: ValidationStrategy::Complete };
        let (gltf, buffers) = match gltf_importer::import_with_config(source, config) {
            Ok((gltf, buffers)) => (gltf, buffers),
            Err(err) => {
                error!("glTF import failed: {:?}", err);
                if let gltf_importer::Error::Io(_) = err {
                    error!("Hint: Are the .bin file(s) referenced by the .gltf file available?")
                }
                process::exit(1)
            },
        };

        print_elapsed("Imported glTF in ", &start_time);
        start_time = Instant::now();

        // load first scene
        if gltf.scenes().len() > 1 {
            warn!("Found more than 1 scene, can only load first at the moment.")
        }
        let base_path = Path::new(source);
        let mut root = Root::from_gltf(&gltf, &buffers, base_path);
        let scene = Scene::from_gltf(&gltf.scenes().nth(0).unwrap(), &mut root);
        print_elapsed(&format!("Loaded scene with {} nodes, {} meshes in ",
                gltf.nodes().count(), root.meshes.len()), &start_time);

        (root, scene)
    }

    /// determine "nice" camera perspective from bounding box. Inspired by donmccurdy/three-gltf-viewer
    fn set_camera_from_bounds(&mut self) {
        // TODO!!: fix bounds/camera computation (many models NOT centered)
        let bounds = &self.scene.bounds;
        let size = bounds.size().magnitude();
        let center = bounds.center();

        // TODO!: move cam instead?
        let _obj_pos_modifier = -center;

        let _max_distance = size * 10.0;
        // TODO: x,y addition optional, z optionally minus instead
        let cam_pos = Point3::new(
            center.x + size / 2.0,
            center.y + size / 5.0,
            center.z + size / 2.0,
        );
        let _near = size / 100.0;
        let _far = size * 100.0;

        // TODO!! TMP duplication (orbit controls)
        self.orbit_controls.position = cam_pos;
        self.orbit_controls.target = Point3::from_vec(center);

        self.controls.position = cam_pos;
        self.controls.center = Some(Point3::from_vec(center));

        // TODO!: set near, far, max_distance, obj_pos_modifier...
    }

    pub fn start_render_loop(&mut self) {
        loop {
            // per-frame time logic
            // NOTE: Deliberately ignoring the seconds of `elapsed()`
            self.delta_time = f64::from(self.last_frame.elapsed().subsec_nanos()) / 1_000_000_000.0;
            self.last_frame = Instant::now();

            // events
            let keep_running = process_events(
                &mut self.events_loop.as_mut().unwrap(), self.gl_window.as_mut().unwrap(),
                &mut self.controls, &mut self.orbit_controls,
                &mut self.width, &mut self.height);
            if !keep_running { break }

            self.controls.update(self.delta_time); // navigation

            self.draw();

            self.gl_window.as_ref().unwrap().swap_buffers().unwrap();
        }
    }

    // Returns whether to keep running
    pub fn draw(&mut self) {
        // render
        unsafe {
            self.render_timer.start();

            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            let cam_params = self.orbit_controls.camera_params();
            self.scene.draw(&mut self.root, &cam_params);

            self.render_timer.end();
        }
    }

    pub fn screenshot(&mut self, filename: &str, width: u32, height: u32) {
        self.draw();

        let mut img = DynamicImage::new_rgba8(width, height);
        unsafe {
            let pixels = img.as_mut_rgba8().unwrap();
            gl::PixelStorei(gl::PACK_ALIGNMENT, 1);
            gl::ReadPixels(0, 0, width as i32, height as i32, gl::RGBA,
                gl::UNSIGNED_BYTE, pixels.as_mut_ptr() as *mut c_void);
            gl_check_error!();
        }

        let img = img.flipv();

        let mut file = File::create(filename).unwrap();
        if let Err(err) = img.save(&mut file, ImageFormat::PNG) {
            error!("{}", err);
        }
        else {
            println!("Saved {}x{} screenshot to {}", width, height, filename);
        }
    }
    pub fn multiscreenshot(&mut self, filename: &str, width: u32, height: u32, count: u32) {
        let min_angle : f32 = 0.0 ;
        let max_angle : f32 =  2.0 * PI ;
        let increment_angle : f32 = ((max_angle - min_angle)/(count as f32)) as f32;
        for i in 1..(count+1) {
            self.orbit_controls.rotate_object(increment_angle);
            let dot = filename.rfind(".").unwrap_or_else(|| filename.len());
            let mut actual_name = filename.to_string();
            actual_name.insert_str(dot, &format!("_{}", i));
            self.screenshot(&actual_name[..], width,height);
        }
    }
}

#[allow(too_many_arguments)]
fn process_events(
    events_loop: &mut glutin::EventsLoop,
    gl_window: &glutin::GlWindow,
    mut controls: &mut CameraControls,
    orbit_controls: &mut OrbitControls,
    width: &mut u32,
    height: &mut u32) -> bool
{
    let mut keep_running = true;
    #[allow(single_match)]
    events_loop.poll_events(|event| {
        match event {
            glutin::Event::WindowEvent{ event, .. } => match event {
                WindowEvent::Closed => keep_running = false,
                WindowEvent::Resized(w, h) => {
                    gl_window.resize(w, h);
                    *width = w;
                    *height = h;
                    let w = w as f32;
                    let h = h as f32;
                    orbit_controls.camera.update_aspect_ratio(w / h);
                    orbit_controls.screen_width = w;
                    orbit_controls.screen_height = h;
                },
                WindowEvent::DroppedFile(_path_buf) => (), // TODO: drag file in
                WindowEvent::MouseInput { button, state: Pressed, ..} => {
                    match button {
                        MouseButton::Left => {
                            orbit_controls.state = NavState::Rotating;
                        },
                        MouseButton::Right => {
                            orbit_controls.state = NavState::Panning;
                        },
                        _ => ()
                    }
                },
                WindowEvent::MouseInput { button, state: Released, ..} => {
                    match (button, orbit_controls.state.clone()) {
                        (MouseButton::Left, NavState::Rotating) | (MouseButton::Right, NavState::Panning) => {
                            orbit_controls.state = NavState::None;
                            orbit_controls.handle_mouse_up();
                        },
                        _ => ()
                    }
                }
                WindowEvent::CursorMoved { position: (xpos, ypos), .. } => {
                    let (xpos, ypos) = (xpos as f32, ypos as f32);
                    orbit_controls.handle_mouse_move(xpos, ypos);
                },
                WindowEvent::MouseWheel { delta: MouseScrollDelta::PixelDelta(_xoffset, yoffset), .. } => {
                    // TODO: need to handle LineDelta case too?
                    orbit_controls.process_mouse_scroll(yoffset);
                }
                WindowEvent::KeyboardInput { input, .. } => {
                    keep_running = process_input(input, &mut controls);
                }
                _ => ()
            },
            _ => ()
        }
    });

    keep_running
}

fn process_input(input: glutin::KeyboardInput, camera: &mut CameraControls) -> bool {
    let pressed = match input.state {
        Pressed => true,
        Released => false
    };
    if let Some(code) = input.virtual_keycode {
        match code {
            VirtualKeyCode::Escape if pressed => return false,
            VirtualKeyCode::W => camera.process_keyboard(FORWARD, pressed),
            VirtualKeyCode::S => camera.process_keyboard(BACKWARD, pressed),
            VirtualKeyCode::A => camera.process_keyboard(LEFT, pressed),
            VirtualKeyCode::D => camera.process_keyboard(RIGHT, pressed),
            _ => ()
        }
    }
    true
}
<commit_msg>explicilty specify opengl 3.3 core<commit_after>use std::f32::consts::PI;
use std::fs::File;
use std::os::raw::c_void;
use std::path::Path;
use std::process;
use std::time::Instant;

use cgmath::{ Point3 };
use gl;
use glutin;
use glutin::{
    Api,
    MouseScrollDelta,
    MouseButton,
    GlContext,
    GlRequest,
    GlProfile,
    VirtualKeyCode,
    WindowEvent,
};
use glutin::ElementState::*;

use gltf_importer;
use gltf_importer::config::ValidationStrategy;
use image::{DynamicImage, ImageFormat};

use controls::{CameraControls, OrbitControls, NavState};
use controls::CameraMovement::*;
use framebuffer::Framebuffer;
use render::*;
use render::math::*;
use utils::{print_elapsed, FrameTimer, gl_check_error};

// TODO!: complete and pass through draw calls? or get rid of multiple shaders?
// How about state ordering anyway?
// struct DrawState {
//     current_shader: ShaderFlags,
//     back_face_culling_enabled: bool
// }

pub struct GltfViewer {
    width: u32,
    height: u32,

    controls: CameraControls,
    orbit_controls: OrbitControls,
    first_mouse: bool,
    last_x: f32,
    last_y: f32,
    events_loop: Option<glutin::EventsLoop>,
    gl_window: Option<glutin::GlWindow>,

    // TODO!: get rid of scene?
    root: Root,
    scene: Scene,

    delta_time: f64, // seconds
    last_frame: Instant,

    render_timer: FrameTimer,
}

impl GltfViewer {
    pub fn new(source: &str, width: u32, height: u32, headless: bool) -> GltfViewer {
        let gl_request = GlRequest::Specific(Api::OpenGl, (3, 3));
        let gl_profile = GlProfile::Core;
        let (events_loop, gl_window, width, height) =
            if headless {
                let headless_context = glutin::HeadlessRendererBuilder::new(width, height)
                    .with_gl(gl_request)
                    .with_gl_profile(gl_profile)
                    .build()
                    .unwrap();
                unsafe { headless_context.make_current().unwrap() }
                gl::load_with(|symbol| headless_context.get_proc_address(symbol) as *const _);
                let framebuffer = Framebuffer::new(width, height);
                framebuffer.bind();
                unsafe { gl::Viewport(0, 0, width as i32, height as i32); }

                (None, None, width, height) // TODO: real height (retina?)
            }
            else {
                // glutin: initialize and configure
                let events_loop = glutin::EventsLoop::new();

                // TODO?: hints for 4.1, core profile, forward compat
                let window = glutin::WindowBuilder::new()
                        .with_title("gltf-viewer")
                        .with_dimensions(width, height)
                        .with_visibility(true);

                let context = glutin::ContextBuilder::new()
                    .with_gl(gl_request)
                    .with_gl_profile(gl_profile)
                    .with_vsync(true);
                let gl_window = glutin::GlWindow::new(window, context, &events_loop).unwrap();

                // Real dimensions might be much higher on High-DPI displays
                let (real_width, real_height) = gl_window.get_inner_size().unwrap();

                unsafe { gl_window.make_current().unwrap(); }

                // gl: load all OpenGL function pointers
                gl::load_with(|symbol| gl_window.get_proc_address(symbol) as *const _);

                (Some(events_loop), Some(gl_window), real_width, real_height)
            };

        // TODO!!: tmp duplicated camera controls
        let mut controls = CameraControls {
            position: Point3::new(0.0, 0.0, 2.0),
            camera: Camera::default(),
            ..CameraControls::default()
        };
        controls.camera.fovy = 60.0;
        controls.camera.update_aspect_ratio(width as f32 / height as f32); // updates projection matrix

        let mut orbit_controls = OrbitControls::new(
            Point3::new(0.0, 0.0, 2.0), width as f32, height as f32
        );
        orbit_controls.camera = Camera::default();
        orbit_controls.camera.fovy = 60.0;
        orbit_controls.camera.update_aspect_ratio(width as f32 / height as f32); // updates projection matrix

        let first_mouse = true;
        let last_x: f32 = width as f32 / 2.0;
        let last_y: f32 = height as f32 / 2.0;

        unsafe {
            gl::ClearColor(0.0, 1.0, 0.0, 1.0); // green for debugging
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            if headless {
                // transparent background for screenshots
                gl::ClearColor(0.0, 0.0, 0.0, 0.0);
            }
            else {
                gl::ClearColor(0.1, 0.2, 0.3, 1.0);
            }

            gl::Enable(gl::DEPTH_TEST);

            // TODO: keyboard switch?
            // draw in wireframe
            // gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
        };

        let (root, scene) = Self::load(source);
        let mut viewer = GltfViewer {
            width,
            height,

            controls,
            orbit_controls,
            first_mouse, last_x, last_y,

            events_loop,
            gl_window,

            root,
            scene,

            delta_time: 0.0, // seconds
            last_frame: Instant::now(),

            render_timer: FrameTimer::new("rendering", 300),
        };
        unsafe { gl_check_error!(); }

        // TODO!!!: completely broken (using gltf camera)
        if false && !viewer.root.camera_nodes.is_empty() {
            // Take first camera node
            let cam_node = &viewer.root.get_camera_node(0);
            viewer.controls.set_camera(
                cam_node.camera.as_ref().unwrap(),
                &cam_node.final_transform);
        } else {
            viewer.set_camera_from_bounds();
        }

        viewer
    }

    pub fn load(source: &str) -> (Root, Scene) {
        let mut start_time = Instant::now();
        // TODO!: http source
        // let gltf =
        if source.starts_with("http") {
            panic!("not implemented: HTTP support temporarily removed.")
            // let http_source = HttpSource::new(source);
            // let import = gltf::Import::custom(http_source, Default::default());
            // let gltf = import_gltf(import);
            // println!(); // to end the "progress dots"
            // gltf
        }
        //     else {
        let config = gltf_importer::Config { validation_strategy: ValidationStrategy::Complete };
        let (gltf, buffers) = match gltf_importer::import_with_config(source, config) {
            Ok((gltf, buffers)) => (gltf, buffers),
            Err(err) => {
                error!("glTF import failed: {:?}", err);
                if let gltf_importer::Error::Io(_) = err {
                    error!("Hint: Are the .bin file(s) referenced by the .gltf file available?")
                }
                process::exit(1)
            },
        };

        print_elapsed("Imported glTF in ", &start_time);
        start_time = Instant::now();

        // load first scene
        if gltf.scenes().len() > 1 {
            warn!("Found more than 1 scene, can only load first at the moment.")
        }
        let base_path = Path::new(source);
        let mut root = Root::from_gltf(&gltf, &buffers, base_path);
        let scene = Scene::from_gltf(&gltf.scenes().nth(0).unwrap(), &mut root);
        print_elapsed(&format!("Loaded scene with {} nodes, {} meshes in ",
                gltf.nodes().count(), root.meshes.len()), &start_time);

        (root, scene)
    }

    /// determine "nice" camera perspective from bounding box. Inspired by donmccurdy/three-gltf-viewer
    fn set_camera_from_bounds(&mut self) {
        // TODO!!: fix bounds/camera computation (many models NOT centered)
        let bounds = &self.scene.bounds;
        let size = bounds.size().magnitude();
        let center = bounds.center();

        // TODO!: move cam instead?
        let _obj_pos_modifier = -center;

        let _max_distance = size * 10.0;
        // TODO: x,y addition optional, z optionally minus instead
        let cam_pos = Point3::new(
            center.x + size / 2.0,
            center.y + size / 5.0,
            center.z + size / 2.0,
        );
        let _near = size / 100.0;
        let _far = size * 100.0;

        // TODO!! TMP duplication (orbit controls)
        self.orbit_controls.position = cam_pos;
        self.orbit_controls.target = Point3::from_vec(center);

        self.controls.position = cam_pos;
        self.controls.center = Some(Point3::from_vec(center));

        // TODO!: set near, far, max_distance, obj_pos_modifier...
    }

    pub fn start_render_loop(&mut self) {
        loop {
            // per-frame time logic
            // NOTE: Deliberately ignoring the seconds of `elapsed()`
            self.delta_time = f64::from(self.last_frame.elapsed().subsec_nanos()) / 1_000_000_000.0;
            self.last_frame = Instant::now();

            // events
            let keep_running = process_events(
                &mut self.events_loop.as_mut().unwrap(), self.gl_window.as_mut().unwrap(),
                &mut self.controls, &mut self.orbit_controls,
                &mut self.width, &mut self.height);
            if !keep_running { break }

            self.controls.update(self.delta_time); // navigation

            self.draw();

            self.gl_window.as_ref().unwrap().swap_buffers().unwrap();
        }
    }

    // Returns whether to keep running
    pub fn draw(&mut self) {
        // render
        unsafe {
            self.render_timer.start();

            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            let cam_params = self.orbit_controls.camera_params();
            self.scene.draw(&mut self.root, &cam_params);

            self.render_timer.end();
        }
    }

    pub fn screenshot(&mut self, filename: &str, width: u32, height: u32) {
        self.draw();

        let mut img = DynamicImage::new_rgba8(width, height);
        unsafe {
            let pixels = img.as_mut_rgba8().unwrap();
            gl::PixelStorei(gl::PACK_ALIGNMENT, 1);
            gl::ReadPixels(0, 0, width as i32, height as i32, gl::RGBA,
                gl::UNSIGNED_BYTE, pixels.as_mut_ptr() as *mut c_void);
            gl_check_error!();
        }

        let img = img.flipv();

        let mut file = File::create(filename).unwrap();
        if let Err(err) = img.save(&mut file, ImageFormat::PNG) {
            error!("{}", err);
        }
        else {
            println!("Saved {}x{} screenshot to {}", width, height, filename);
        }
    }
    pub fn multiscreenshot(&mut self, filename: &str, width: u32, height: u32, count: u32) {
        let min_angle : f32 = 0.0 ;
        let max_angle : f32 =  2.0 * PI ;
        let increment_angle : f32 = ((max_angle - min_angle)/(count as f32)) as f32;
        for i in 1..(count+1) {
            self.orbit_controls.rotate_object(increment_angle);
            let dot = filename.rfind(".").unwrap_or_else(|| filename.len());
            let mut actual_name = filename.to_string();
            actual_name.insert_str(dot, &format!("_{}", i));
            self.screenshot(&actual_name[..], width,height);
        }
    }
}

#[allow(too_many_arguments)]
fn process_events(
    events_loop: &mut glutin::EventsLoop,
    gl_window: &glutin::GlWindow,
    mut controls: &mut CameraControls,
    orbit_controls: &mut OrbitControls,
    width: &mut u32,
    height: &mut u32) -> bool
{
    let mut keep_running = true;
    #[allow(single_match)]
    events_loop.poll_events(|event| {
        match event {
            glutin::Event::WindowEvent{ event, .. } => match event {
                WindowEvent::Closed => keep_running = false,
                WindowEvent::Resized(w, h) => {
                    gl_window.resize(w, h);
                    *width = w;
                    *height = h;
                    let w = w as f32;
                    let h = h as f32;
                    orbit_controls.camera.update_aspect_ratio(w / h);
                    orbit_controls.screen_width = w;
                    orbit_controls.screen_height = h;
                },
                WindowEvent::DroppedFile(_path_buf) => (), // TODO: drag file in
                WindowEvent::MouseInput { button, state: Pressed, ..} => {
                    match button {
                        MouseButton::Left => {
                            orbit_controls.state = NavState::Rotating;
                        },
                        MouseButton::Right => {
                            orbit_controls.state = NavState::Panning;
                        },
                        _ => ()
                    }
                },
                WindowEvent::MouseInput { button, state: Released, ..} => {
                    match (button, orbit_controls.state.clone()) {
                        (MouseButton::Left, NavState::Rotating) | (MouseButton::Right, NavState::Panning) => {
                            orbit_controls.state = NavState::None;
                            orbit_controls.handle_mouse_up();
                        },
                        _ => ()
                    }
                }
                WindowEvent::CursorMoved { position: (xpos, ypos), .. } => {
                    let (xpos, ypos) = (xpos as f32, ypos as f32);
                    orbit_controls.handle_mouse_move(xpos, ypos);
                },
                WindowEvent::MouseWheel { delta: MouseScrollDelta::PixelDelta(_xoffset, yoffset), .. } => {
                    // TODO: need to handle LineDelta case too?
                    orbit_controls.process_mouse_scroll(yoffset);
                }
                WindowEvent::KeyboardInput { input, .. } => {
                    keep_running = process_input(input, &mut controls);
                }
                _ => ()
            },
            _ => ()
        }
    });

    keep_running
}

fn process_input(input: glutin::KeyboardInput, camera: &mut CameraControls) -> bool {
    let pressed = match input.state {
        Pressed => true,
        Released => false
    };
    if let Some(code) = input.virtual_keycode {
        match code {
            VirtualKeyCode::Escape if pressed => return false,
            VirtualKeyCode::W => camera.process_keyboard(FORWARD, pressed),
            VirtualKeyCode::S => camera.process_keyboard(BACKWARD, pressed),
            VirtualKeyCode::A => camera.process_keyboard(LEFT, pressed),
            VirtualKeyCode::D => camera.process_keyboard(RIGHT, pressed),
            _ => ()
        }
    }
    true
}
<|endoftext|>