<commit_before>use super::super::request::Request;
use super::super::response::Response;
use super::super::middleware::{Middleware, Continue, Unwind, Status};
use super::super::alloy::Alloy;

use super::Chain;

/// The default `Chain` used by `Iron`.
/// `StackChain` runs each `Request` through all `Middleware` in its stack.
/// When it hits `Middleware` which returns `Unwind`, it passes
/// the `Request` back up through all `Middleware` it has hit so far.
pub struct StackChain {
    /// The storage used by `StackChain` to hold all `Middleware`
    /// that have been `linked` to it.
    stack: Vec<Box<Middleware + Send>>,
    exit_stack: Vec<Box<Middleware + Send>>
}

impl Clone for StackChain {
    fn clone(&self) -> StackChain {
        StackChain {
            stack: self.stack.clone(),
            exit_stack: self.exit_stack.clone()
        }
    }
}

/// `StackChain` is a `Chain`
impl Chain for StackChain {
    fn chain_enter(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // The `exit_stack` will hold all `Middleware` that are passed through
        // in the enter loop. This is so we know to take exactly the same
        // path through `Middleware` in reverse order than we did on the way in.
        self.exit_stack = vec![];

        'enter: for middleware in self.stack.mut_iter() {
            match middleware.enter(request, response, alloy) {
                Unwind   => return Unwind,
                // Mark the middleware for traversal on exit.
                Continue => self.exit_stack.push(middleware.clone_box())
            }
        }

        Continue
    }

    fn chain_exit(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // Reverse the stack so we go through in the reverse order.
        // i.e. LIFO.
        self.exit_stack.reverse();
        // Call each middleware's exit handler.
        'exit: for middleware in self.exit_stack.mut_iter() {
            let _ = middleware.exit(request, response, alloy);
        }

        Continue
    }

    /// Add `Middleware` to the `Chain`.
    fn link<M: Middleware>(&mut self, middleware: M) {
        self.stack.push(box middleware);
    }

    /// Create a new instance of `StackChain`.
    fn new() -> StackChain {
        StackChain {
            stack: vec![],
            exit_stack: vec![]
        }
    }
}

#[cfg(test)]
mod test {
    pub use super::*;
    pub use super::super::super::request::Request;
    pub use super::super::super::response::Response;
    pub use super::super::super::alloy::Alloy;
    pub use super::super::super::middleware::{Middleware, Status, Continue};
    pub use std::sync::{Arc, Mutex};

    #[deriving(Clone)]
    pub struct CallCount {
        enter: Arc<Mutex<u64>>,
        exit: Arc<Mutex<u64>>
    }

    impl Middleware for CallCount {
        fn enter(&mut self, _req: &mut Request,
                 _res: &mut Response, _alloy: &mut Alloy) -> Status {
            let mut enter = self.enter.lock();
            *enter += 1;
            Continue
        }

        fn exit(&mut self, _req: &mut Request,
                _res: &mut Response, _alloy: &mut Alloy) -> Status {
            let mut exit = self.exit.lock();
            *exit += 1;
            Continue
        }
    }

    mod dispatch {
        use super::{CallCount, Arc, Mutex};
        use super::super::StackChain;
        use super::super::super::Chain;
        use std::mem::{uninitialized};

        #[test]
        fn calls_middleware_enter() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*enter.lock(), 1);
        }

        #[test]
        fn calls_middleware_exit() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*exit.lock(), 1);
        }

        #[test]
        fn calls_all_middleware_enter_exit() {
            let mut testchain: StackChain = Chain::new();
            let enter_exits: Vector<(Arc<Mutex<u64>>, Arc<Mutex<u64>>)> = vec![];

            for num in range(0, 10) {
                let (enter, exit) = (Arc::new(Mutex::new(0)), Arc::new(Mutex::new(0)));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            }

            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }

            for (enter, exit) in enter_exits.move_iter() {
                assert_eq!(*enter.lock(), 1);
                assert_eq!(*exit.lock(), 1);
            }
        }
    }
}

<commit_msg>(test) Tested chain_enter.<commit_after>use super::super::request::Request;
use super::super::response::Response;
use super::super::middleware::{Middleware, Continue, Unwind, Status};
use super::super::alloy::Alloy;

use super::Chain;

/// The default `Chain` used by `Iron`.
/// `StackChain` runs each `Request` through all `Middleware` in its stack.
/// When it hits `Middleware` which returns `Unwind`, it passes
/// the `Request` back up through all `Middleware` it has hit so far.
pub struct StackChain {
    /// The storage used by `StackChain` to hold all `Middleware`
    /// that have been `linked` to it.
    stack: Vec<Box<Middleware + Send>>,
    exit_stack: Vec<Box<Middleware + Send>>
}

impl Clone for StackChain {
    fn clone(&self) -> StackChain {
        StackChain {
            stack: self.stack.clone(),
            exit_stack: self.exit_stack.clone()
        }
    }
}

/// `StackChain` is a `Chain`
impl Chain for StackChain {
    fn chain_enter(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // The `exit_stack` will hold all `Middleware` that are passed through
        // in the enter loop. This is so we know to take exactly the same
        // path through `Middleware` in reverse order than we did on the way in.
        self.exit_stack = vec![];

        'enter: for middleware in self.stack.mut_iter() {
            match middleware.enter(request, response, alloy) {
                Unwind   => return Unwind,
                // Mark the middleware for traversal on exit.
                Continue => self.exit_stack.push(middleware.clone_box())
            }
        }

        Continue
    }

    fn chain_exit(&mut self,
             request: &mut Request,
             response: &mut Response,
             alloy: &mut Alloy) -> Status {
        // Reverse the stack so we go through in the reverse order.
        // i.e. LIFO.
        self.exit_stack.reverse();
        // Call each middleware's exit handler.
        'exit: for middleware in self.exit_stack.mut_iter() {
            let _ = middleware.exit(request, response, alloy);
        }

        Continue
    }

    /// Add `Middleware` to the `Chain`.
    fn link<M: Middleware>(&mut self, middleware: M) {
        self.stack.push(box middleware);
    }

    /// Create a new instance of `StackChain`.
    fn new() -> StackChain {
        StackChain {
            stack: vec![],
            exit_stack: vec![]
        }
    }
}

#[cfg(test)]
mod test {
    pub use super::*;
    pub use super::super::super::request::Request;
    pub use super::super::super::response::Response;
    pub use super::super::super::alloy::Alloy;
    pub use super::super::super::middleware::{Middleware, Status, Continue};
    pub use std::sync::{Arc, Mutex};

    #[deriving(Clone)]
    pub struct CallCount {
        enter: Arc<Mutex<u64>>,
        exit: Arc<Mutex<u64>>
    }

    impl Middleware for CallCount {
        fn enter(&mut self, _req: &mut Request,
                 _res: &mut Response, _alloy: &mut Alloy) -> Status {
            let mut enter = self.enter.lock();
            *enter += 1;
            Continue
        }

        fn exit(&mut self, _req: &mut Request,
                _res: &mut Response, _alloy: &mut Alloy) -> Status {
            let mut exit = self.exit.lock();
            *exit += 1;
            Continue
        }
    }

    mod dispatch {
        use super::{CallCount, Arc, Mutex};
        use super::super::StackChain;
        use super::super::super::Chain;
        use std::mem::{uninitialized};

        #[test]
        fn calls_middleware_enter() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*enter.lock(), 1);
        }

        #[test]
        fn calls_middleware_exit() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*exit.lock(), 1);
        }

        #[test]
        fn calls_all_middleware_enter_exit() {
            let mut testchain: StackChain = Chain::new();
            let enter_exits: Vec<(Arc<Mutex<u64>>, Arc<Mutex<u64>>)> = vec![];

            for _ in range(0, 10) {
                let (enter, exit) = (Arc::new(Mutex::new(0)), Arc::new(Mutex::new(0)));
                testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            }

            unsafe {
                let _ = testchain.dispatch(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }

            for (enter, exit) in enter_exits.move_iter() {
                assert_eq!(*enter.lock(), 1);
                assert_eq!(*exit.lock(), 1);
            }
        }
    }

    mod chain_enter {
        use super::{CallCount, Arc, Mutex};
        use super::super::StackChain;
        use super::super::super::Chain;
        use std::mem::{uninitialized};

        #[test]
        fn calls_middleware_enter() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.chain_enter(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*enter.lock(), 1);
        }

        #[test]
        fn doesnt_call_middleware_exit() {
            let mut testchain: StackChain = Chain::new();
            let enter = Arc::new(Mutex::new(0));
            let exit = Arc::new(Mutex::new(0));
            testchain.link(CallCount { enter: enter.clone(), exit: exit.clone() });
            unsafe {
                let _ = testchain.chain_enter(
                    uninitialized(),
                    uninitialized(),
                    uninitialized()
                );
            }
            assert_eq!(*exit.lock(), 0);
        }
    }
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate neovim;

use std::old_io::{File, FileMode, FileAccess};

mod ffi {
    pub use libc::{c_int, c_uchar, c_void};
    pub use libc::funcs::posix88::unistd::{close, pipe, read, write};
    pub use libc::types::os::arch::c95::size_t;
}

fn send_message(fd: ffi::c_int, command: &str) {
    let mut arr = neovim::Array::new();
    arr.add_string(command);
    let msg = neovim::serialize_message(1, "vim_command", &arr);
    let msg_ptr = msg.as_slice().as_ptr() as *const ffi::c_void;
    unsafe { ffi::write(fd, msg_ptr, msg.len() as ffi::size_t) };
}

fn recv_message(fd: ffi::c_int) -> Option<neovim::Array> {
    let mut buf : [ffi::c_uchar; 1024] = [0; 1024];
    let n = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut ffi::c_void, 1024) };
    if n < 0 {
        return None;
    }
    unsafe {
        let v = Vec::from_raw_buf(buf.as_ptr(), n as usize);
        let s = String::from_utf8_unchecked(v);
        Some(neovim::deserialize_message(&s))
    }
}

fn main() {
    // two pairs of anonymous pipes for msgpack-rpc between the logger and nvim
    let mut nvim_log : [ffi::c_int; 2] = [0; 2]; // to nvim from logger
    let mut log_nvim : [ffi::c_int; 2] = [0; 2]; // to logger from nvim
    unsafe {
        ffi::pipe(nvim_log.as_mut_ptr());
        ffi::pipe(log_nvim.as_mut_ptr());
    };

    // listen for events in a separate thread and log them
    ::std::thread::Thread::spawn(move || {
        // listen for bufenter events
        send_message(nvim_log[1], "au BufEnter * call rpcnotify(1, \"bufenter\", bufname(\"\"))");

        // receive messages
        let mut file = File::open_mode(&Path::new("events.log"), FileMode::Append, FileAccess::Write);
        while let Some(recv_arr) = recv_message(log_nvim[0]) {
            if recv_arr.len() > 0 {
                file.write_all(format!("{:?}\n", recv_arr).into_bytes().as_slice());
            }
        }
    });

    // start nvim
    let mut args = Vec::new();
    for arg in ::std::env::args() {
        args.push(arg);
    }
    neovim::main_setup(&args);
    neovim::channel_from_fds(nvim_log[0], log_nvim[1]);
    neovim::main_loop();
}
<commit_msg>Make example log absolute file paths<commit_after>extern crate libc;
extern crate neovim;

use std::old_io::{File, FileMode, FileAccess};

mod ffi {
    pub use libc::{c_int, c_uchar, c_void};
    pub use libc::funcs::posix88::unistd::{close, pipe, read, write};
    pub use libc::types::os::arch::c95::size_t;
}

fn send_message(fd: ffi::c_int, command: &str) {
    let mut arr = neovim::Array::new();
    arr.add_string(command);
    let msg = neovim::serialize_message(1, "vim_command", &arr);
    let msg_ptr = msg.as_slice().as_ptr() as *const ffi::c_void;
    unsafe { ffi::write(fd, msg_ptr, msg.len() as ffi::size_t) };
}

fn recv_message(fd: ffi::c_int) -> Option<neovim::Array> {
    let mut buf : [ffi::c_uchar; 1024] = [0; 1024];
    let n = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut ffi::c_void, 1024) };
    if n < 0 {
        return None;
    }
    unsafe {
        let v = Vec::from_raw_buf(buf.as_ptr(), n as usize);
        let s = String::from_utf8_unchecked(v);
        Some(neovim::deserialize_message(&s))
    }
}

fn main() {
    // two pairs of anonymous pipes for msgpack-rpc between the logger and nvim
    let mut nvim_log : [ffi::c_int; 2] = [0; 2]; // to nvim from logger
    let mut log_nvim : [ffi::c_int; 2] = [0; 2]; // to logger from nvim
    unsafe {
        ffi::pipe(nvim_log.as_mut_ptr());
        ffi::pipe(log_nvim.as_mut_ptr());
    };

    // listen for events in a separate thread and log them
    ::std::thread::Thread::spawn(move || {
        // listen for bufenter events
        send_message(nvim_log[1], "au BufEnter * call rpcnotify(1, 'bufenter', fnamemodify(bufname(''), ':p'))");

        // receive messages
        let mut file = File::open_mode(&Path::new("events.log"), FileMode::Append, FileAccess::Write);
        while let Some(recv_arr) = recv_message(log_nvim[0]) {
            if recv_arr.len() > 0 {
                file.write_all(format!("{:?}\n", recv_arr).into_bytes().as_slice());
            }
        }
    });

    // start nvim
    let mut args = Vec::new();
    for arg in ::std::env::args() {
        args.push(arg);
    }
    neovim::main_setup(&args);
    neovim::channel_from_fds(nvim_log[0], log_nvim[1]);
    neovim::main_loop();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;

#[allow(unused_imports)]
use glium::{glutin, Surface};

mod support;

#[derive(Copy, Clone, Debug)]
struct PerInstance {
    pub id: u32,
    pub w_position: (f32, f32, f32),
    pub color: (f32, f32, f32),
}
implement_vertex!(PerInstance, id, w_position, color);

fn main() {
    // building the display, ie. the main object
    let event_loop = glutin::event_loop::EventLoop::new();
    let wb = glutin::window::WindowBuilder::new();
    let cb = glutin::ContextBuilder::new().with_depth_buffer(24);
    let display = glium::Display::new(wb, cb, &event_loop).unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                out vec3 v_normal;
                out vec3 v_color;

                void main() {
                    v_normal = normal;
                    v_color = color;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                in vec3 v_color;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * v_color;
                    f_color = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    // the picking program
    let picking_program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                flat out uint v_id;

                void main() {
                    v_id = id;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                flat in uint v_id;
                out uint f_id;

                void main() {
                    f_id = v_id;
                }
            ",
        },
    ).unwrap();

    let mut camera = support::camera::CameraState::new();
    camera.set_position((0.0, 0.0, -1.5));
    camera.set_direction((0.0, 0.0, 1.0));

    //id's must be unique and != 0
    let mut per_instance = vec![
        PerInstance { id: 1, w_position: (-1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 2, w_position: ( 0.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 3, w_position: ( 1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
    ];
    per_instance.sort_by(|a, b| a.id.cmp(&b.id));
    let original = per_instance.clone();

    let mut picking_attachments: Option<(glium::texture::UnsignedTexture2d, glium::framebuffer::DepthRenderBuffer)> = None;
    let picking_pbo: glium::texture::pixel_buffer::PixelBuffer<u32>
        = glium::texture::pixel_buffer::PixelBuffer::new_empty(&display, 1);

    let mut cursor_position: Option<(i32, i32)> = None;

    // the main loop
    support::start_loop(event_loop, move |events| {
        camera.update();

        // determine which object has been picked at the previous frame
        let picked_object = {
            let data = picking_pbo.read().map(|d| d[0]).unwrap_or(0);
            if data != 0 {
                per_instance.binary_search_by(|x| x.id.cmp(&data)).ok()
            } else {
                None
            }
        };

        per_instance = original.clone();
        if let Some(index) = picked_object {
            per_instance[index as usize] = PerInstance {
                id: per_instance[index as usize].id,
                w_position: per_instance[index as usize].w_position,
                color: (0.0, 1.0, 0.0)
            };
        }

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        let per_instance_buffer = glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap();

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);

        //update picking texture
        if picking_attachments.is_none() || (
            picking_attachments.as_ref().unwrap().0.get_width(),
            picking_attachments.as_ref().unwrap().0.get_height().unwrap()
        ) != target.get_dimensions() {
            let (width, height) = target.get_dimensions();
            picking_attachments = Some((
                glium::texture::UnsignedTexture2d::empty_with_format(
                    &display,
                    glium::texture::UncompressedUintFormat::U32,
                    glium::texture::MipmapsOption::NoMipmap,
                    width, height,
                ).unwrap(),
                glium::framebuffer::DepthRenderBuffer::new(
                    &display,
                    glium::texture::DepthFormat::F32,
                    width, height,
                ).unwrap()
            ))
        }

        // drawing the models and pass the picking texture
        if let Some((ref picking_texture, ref depth_buffer)) = picking_attachments {
            //clearing the picking texture
            picking_texture.main_level().first_layer().into_image(None).unwrap().raw_clear_buffer([0u32, 0, 0, 0]);

            let mut picking_target = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, picking_texture, depth_buffer).unwrap();
            picking_target.clear_depth(1.0);
            picking_target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                        &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                        &picking_program, &uniforms, &params).unwrap();
        }
        target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // committing into the picking pbo
        if let (Some(cursor), Some(&(ref picking_texture, _))) = (cursor_position, picking_attachments.as_ref()) {
            let read_target = glium::Rect {
                left: (cursor.0 - 1) as u32,
                bottom: picking_texture.get_height().unwrap() - std::cmp::max(cursor.1 - 1, 0) as u32,
                width: 1,
                height: 1,
            };

            if read_target.left < picking_texture.get_width()
            && read_target.bottom < picking_texture.get_height().unwrap() {
                picking_texture.main_level()
                    .first_layer()
                    .into_image(None).unwrap()
                    .raw_read_to_pixel_buffer(&read_target, &picking_pbo);
            } else {
                picking_pbo.write(&[0]);
            }
        } else {
            picking_pbo.write(&[0]);
        }

        let mut action = support::Action::Continue;

        // polling and handling the events received by the window
        for event in events {
            match event {
                glutin::event::Event::WindowEvent { event, .. } => match event {
                    glutin::event::WindowEvent::CloseRequested => action = support::Action::Stop,
                    glutin::event::WindowEvent::CursorMoved { position, .. } => {
                        let hidpi_factor = display.gl_window().window().hidpi_factor();
                        cursor_position = Some(position.to_physical(hidpi_factor).into());
                    }
                    ev => camera.process_input(&ev),
                },
                _ => (),
            }
        };

        action
    });
}
<commit_msg>[example/picking] Use saturating subtraction to avoid crash<commit_after>#[macro_use]
extern crate glium;

#[allow(unused_imports)]
use glium::{glutin, Surface};

mod support;

#[derive(Copy, Clone, Debug)]
struct PerInstance {
    pub id: u32,
    pub w_position: (f32, f32, f32),
    pub color: (f32, f32, f32),
}
implement_vertex!(PerInstance, id, w_position, color);

fn main() {
    // building the display, ie. the main object
    let event_loop = glutin::event_loop::EventLoop::new();
    let wb = glutin::window::WindowBuilder::new();
    let cb = glutin::ContextBuilder::new().with_depth_buffer(24);
    let display = glium::Display::new(wb, cb, &event_loop).unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                out vec3 v_normal;
                out vec3 v_color;

                void main() {
                    v_normal = normal;
                    v_color = color;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                in vec3 v_color;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * v_color;
                    f_color = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    // the picking program
    let picking_program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                flat out uint v_id;

                void main() {
                    v_id = id;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                flat in uint v_id;
                out uint f_id;

                void main() {
                    f_id = v_id;
                }
            ",
        },
    ).unwrap();

    let mut camera = support::camera::CameraState::new();
    camera.set_position((0.0, 0.0, -1.5));
    camera.set_direction((0.0, 0.0, 1.0));

    //id's must be unique and != 0
    let mut per_instance = vec![
        PerInstance { id: 1, w_position: (-1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 2, w_position: ( 0.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 3, w_position: ( 1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
    ];
    per_instance.sort_by(|a, b| a.id.cmp(&b.id));
    let original = per_instance.clone();

    let mut picking_attachments: Option<(glium::texture::UnsignedTexture2d, glium::framebuffer::DepthRenderBuffer)> = None;
    let picking_pbo: glium::texture::pixel_buffer::PixelBuffer<u32>
        = glium::texture::pixel_buffer::PixelBuffer::new_empty(&display, 1);

    let mut cursor_position: Option<(i32, i32)> = None;

    // the main loop
    support::start_loop(event_loop, move |events| {
        camera.update();

        // determine which object has been picked at the previous frame
        let picked_object = {
            let data = picking_pbo.read().map(|d| d[0]).unwrap_or(0);
            if data != 0 {
                per_instance.binary_search_by(|x| x.id.cmp(&data)).ok()
            } else {
                None
            }
        };

        per_instance = original.clone();
        if let Some(index) = picked_object {
            per_instance[index as usize] = PerInstance {
                id: per_instance[index as usize].id,
                w_position: per_instance[index as usize].w_position,
                color: (0.0, 1.0, 0.0)
            };
        }

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        let per_instance_buffer = glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap();

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);

        //update picking texture
        if picking_attachments.is_none() || (
            picking_attachments.as_ref().unwrap().0.get_width(),
            picking_attachments.as_ref().unwrap().0.get_height().unwrap()
        ) != target.get_dimensions() {
            let (width, height) = target.get_dimensions();
            picking_attachments = Some((
                glium::texture::UnsignedTexture2d::empty_with_format(
                    &display,
                    glium::texture::UncompressedUintFormat::U32,
                    glium::texture::MipmapsOption::NoMipmap,
                    width, height,
                ).unwrap(),
                glium::framebuffer::DepthRenderBuffer::new(
                    &display,
                    glium::texture::DepthFormat::F32,
                    width, height,
                ).unwrap()
            ))
        }

        // drawing the models and pass the picking texture
        if let Some((ref picking_texture, ref depth_buffer)) = picking_attachments {
            //clearing the picking texture
            picking_texture.main_level().first_layer().into_image(None).unwrap().raw_clear_buffer([0u32, 0, 0, 0]);

            let mut picking_target = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, picking_texture, depth_buffer).unwrap();
            picking_target.clear_depth(1.0);
            picking_target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                        &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                        &picking_program, &uniforms, &params).unwrap();
        }
        target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // committing into the picking pbo
        if let (Some(cursor), Some(&(ref picking_texture, _))) = (cursor_position, picking_attachments.as_ref()) {
            let read_target = glium::Rect {
                left: (cursor.0 - 1) as u32,
                bottom: picking_texture.get_height().unwrap().saturating_sub(std::cmp::max(cursor.1 - 1, 0) as u32),
                width: 1,
                height: 1,
            };

            if read_target.left < picking_texture.get_width()
            && read_target.bottom < picking_texture.get_height().unwrap() {
                picking_texture.main_level()
                    .first_layer()
                    .into_image(None).unwrap()
                    .raw_read_to_pixel_buffer(&read_target, &picking_pbo);
            } else {
                picking_pbo.write(&[0]);
            }
        } else {
            picking_pbo.write(&[0]);
        }

        let mut action = support::Action::Continue;

        // polling and handling the events received by the window
        for event in events {
            match event {
                glutin::event::Event::WindowEvent { event, .. } => match event {
                    glutin::event::WindowEvent::CloseRequested => action = support::Action::Stop,
                    glutin::event::WindowEvent::CursorMoved { position, .. } => {
                        let hidpi_factor = display.gl_window().window().hidpi_factor();
                        cursor_position = Some(position.to_physical(hidpi_factor).into());
                    }
                    ev => camera.process_input(&ev),
                },
                _ => (),
            }
        };

        action
    });
}
<|endoftext|>


<commit_before>extern crate camera_controllers;
extern crate cgmath;
extern crate collision;
extern crate fps_counter;
extern crate gfx;
extern crate gfx_smaa;
extern crate gfx_text;
extern crate piston_window;
extern crate terra;
extern crate vecmath;

use std::time::Instant;

use fps_counter::FPSCounter;
use piston_window::*;
use camera_controllers::{Camera, FirstPerson, FirstPersonSettings};
use collision::Frustum;
use cgmath::*;
use vecmath::vec3_dot;

use terra::{QuadTreeBuilder, TextureQuality, VertexQuality};

fn compute_projection_matrix(w: &PistonWindow) -> Matrix4<f32> {
    let draw_size = w.window.draw_size();
    PerspectiveFov {
        fovy: Rad((90.0f32 * 9.0 / 16.0).to_radians()),
        near: 100.0,
        far: 50000000.0,
        aspect: (draw_size.width as f32) / (draw_size.height as f32),
    }.into()
}

fn compute_view_matrix(c: Camera) -> Matrix4<f32> {
    let p = c.position;
    let r = c.right;
    let u = c.up;
    let f = c.forward;

    #[cfg_attr(rustfmt, rustfmt_skip)]
    Matrix4::new(
        r[0], u[0], f[0], 0.0,
        r[1], u[1], f[1], 0.0,
        r[2], u[2], f[2], 0.0,
        -vec3_dot(r, p), -vec3_dot(u, p), -vec3_dot(f, p), 1.0,
    )
}

fn main() {
    let mut window: PistonWindow = PistonWindow::new(
        OpenGL::V3_3,
        0,
        WindowSettings::new("terra preview", [1920, 1080])
            .exit_on_esc(true)
            .opengl(OpenGL::V3_3)
            .vsync(false)
            // .srgb(false)
            .fullscreen(true)
            .build()
            .unwrap(),
    );
    window.set_capture_cursor(true);
    window.set_max_fps(240);
    window.set_ups(240);

    let mut smaa_target =
        gfx_smaa::SmaaTarget::new(&mut window.factory, window.output_color.clone(), 1920, 1080)
            .unwrap();

    let mut terrain = QuadTreeBuilder::new(window.factory.clone(), &mut window.encoder)
        .latitude(42)
        .longitude(-73)
        .vertex_quality(VertexQuality::High)
        .texture_quality(TextureQuality::High)
        .build(&smaa_target.output_color(), &smaa_target.output_stencil())
        .unwrap();

    let mut first_person =
        FirstPerson::new([0.0, 1000.0, 0.0], FirstPersonSettings::keyboard_wasd());
    first_person.settings.speed_vertical = 5000.0;
    first_person.settings.speed_horizontal = 5000.0;

    let mut projection_matrix = compute_projection_matrix(&window);
    let mut detached_camera = false;
    let mut camera_position = Point3::new(0.0, 0.0, 0.0);
    let mut camera_frustum = None;

    let mut text = gfx_text::new(window.factory.clone())
        .with_size(12)
        .build()
        .unwrap();

    let mut fps_counter = FPSCounter::new();
    let mut last_frame = Instant::now();
    while let Some(e) = window.next() {
        if let Some(_) = e.resize_args() {
            projection_matrix = compute_projection_matrix(&window);
        }
        if let Some(Button::Keyboard(key)) = e.press_args() {
            if key == Key::Tab {
                detached_camera = !detached_camera;
            }
        }

        first_person.event(&e);
        e.update(|_args| {
            if !detached_camera {
                let center_distance: f32 = first_person.position[0] * first_person.position[0]
                    + first_person.position[2] * first_person.position[2];
                let center_distance = center_distance.sqrt();

                if center_distance > 3000.0 {
                    first_person.position[0] =
                        first_person.position[0] / (center_distance / 3000.0);
                    first_person.position[2] =
                        first_person.position[2] / (center_distance / 3000.0);
                }
                camera_position = Point3::new(
                    first_person.position[0],
                    first_person.position[1],
                    first_person.position[2],
                );
                camera_frustum = Frustum::from_matrix4(
                    projection_matrix * compute_view_matrix(first_person.camera(0.0)),
                );
                assert!(camera_frustum.is_some());
            }
            first_person.settings.speed_vertical =
                (5.0 * first_person.position[1] as f32).max(100.0f32);
        });

        window.draw_3d(&e, |window| {
            let now = Instant::now();
            let dt = (now - last_frame).as_secs() as f32
                + (now - last_frame).subsec_nanos() as f32 / 1000_000_000.0;
            last_frame = now;

            window
                .encoder
                .clear_depth(&smaa_target.output_stencil(), 1.0);
            window
                .encoder
                .clear(&smaa_target.output_color(), [0.3, 0.3, 0.3, 1.0]);

            let view_matrix = compute_view_matrix(first_person.camera(0.0));
            terrain.update(
                projection_matrix * view_matrix,
                camera_position,
                camera_frustum,
                &mut window.encoder,
                dt,
            );
            terrain.render(&mut window.encoder).unwrap();
            terrain.render_sky(&mut window.encoder);

            let text_color = [0.0, 1.0, 1.0, 1.0];
            let fps = fps_counter.tick();
            text.add(&format!("FPS: {}", fps), [5, 5], text_color);
            text.add(
                &format!("Frame time: {:.1}", 1000.0 / fps as f32),
                [5, 17],
                text_color,
            );
            text.draw(&mut window.encoder, &smaa_target.output_color())
                .unwrap();

            smaa_target.resolve(&mut window.encoder);
        });
    }
}
<commit_msg>Closer near plane<commit_after>extern crate camera_controllers;
extern crate cgmath;
extern crate collision;
extern crate fps_counter;
extern crate gfx;
extern crate gfx_smaa;
extern crate gfx_text;
extern crate piston_window;
extern crate terra;
extern crate vecmath;

use std::time::Instant;

use fps_counter::FPSCounter;
use piston_window::*;
use camera_controllers::{Camera, FirstPerson, FirstPersonSettings};
use collision::Frustum;
use cgmath::*;
use vecmath::vec3_dot;

use terra::{QuadTreeBuilder, TextureQuality, VertexQuality};

fn compute_projection_matrix(w: &PistonWindow) -> Matrix4<f32> {
    let draw_size = w.window.draw_size();
    PerspectiveFov {
        fovy: Rad((90.0f32 * 9.0 / 16.0).to_radians()),
        near: 10.0,
        far: 50000000.0,
        aspect: (draw_size.width as f32) / (draw_size.height as f32),
    }.into()
}

fn compute_view_matrix(c: Camera) -> Matrix4<f32> {
    let p = c.position;
    let r = c.right;
    let u = c.up;
    let f = c.forward;

    #[cfg_attr(rustfmt, rustfmt_skip)]
    Matrix4::new(
        r[0], u[0], f[0], 0.0,
        r[1], u[1], f[1], 0.0,
        r[2], u[2], f[2], 0.0,
        -vec3_dot(r, p), -vec3_dot(u, p), -vec3_dot(f, p), 1.0,
    )
}

fn main() {
    let mut window: PistonWindow = PistonWindow::new(
        OpenGL::V3_3,
        0,
        WindowSettings::new("terra preview", [1920, 1080])
            .exit_on_esc(true)
            .opengl(OpenGL::V3_3)
            .vsync(false)
            // .srgb(false)
            .fullscreen(true)
            .build()
            .unwrap(),
    );
    window.set_capture_cursor(true);
    window.set_max_fps(240);
    window.set_ups(240);

    let mut smaa_target =
        gfx_smaa::SmaaTarget::new(&mut window.factory, window.output_color.clone(), 1920, 1080)
            .unwrap();

    let mut terrain = QuadTreeBuilder::new(window.factory.clone(), &mut window.encoder)
        .latitude(42)
        .longitude(-73)
        .vertex_quality(VertexQuality::High)
        .texture_quality(TextureQuality::High)
        .build(&smaa_target.output_color(), &smaa_target.output_stencil())
        .unwrap();

    let mut first_person =
        FirstPerson::new([0.0, 1000.0, 0.0], FirstPersonSettings::keyboard_wasd());
    first_person.settings.speed_vertical = 5000.0;
    first_person.settings.speed_horizontal = 5000.0;

    let mut projection_matrix = compute_projection_matrix(&window);
    let mut detached_camera = false;
    let mut camera_position = Point3::new(0.0, 0.0, 0.0);
    let mut camera_frustum = None;

    let mut text = gfx_text::new(window.factory.clone())
        .with_size(12)
        .build()
        .unwrap();

    let mut fps_counter = FPSCounter::new();
    let mut last_frame = Instant::now();
    while let Some(e) = window.next() {
        if let Some(_) = e.resize_args() {
            projection_matrix = compute_projection_matrix(&window);
        }
        if let Some(Button::Keyboard(key)) = e.press_args() {
            if key == Key::Tab {
                detached_camera = !detached_camera;
            }
        }

        first_person.event(&e);
        e.update(|_args| {
            if !detached_camera {
                let center_distance: f32 = first_person.position[0] * first_person.position[0]
                    + first_person.position[2] * first_person.position[2];
                let center_distance = center_distance.sqrt();

                if center_distance > 3000.0 {
                    first_person.position[0] =
                        first_person.position[0] / (center_distance / 3000.0);
                    first_person.position[2] =
                        first_person.position[2] / (center_distance / 3000.0);
                }
                camera_position = Point3::new(
                    first_person.position[0],
                    first_person.position[1],
                    first_person.position[2],
                );
                camera_frustum = Frustum::from_matrix4(
                    projection_matrix * compute_view_matrix(first_person.camera(0.0)),
                );
                assert!(camera_frustum.is_some());
            }
            first_person.settings.speed_vertical =
                (5.0 * first_person.position[1] as f32).max(100.0f32);
        });

        window.draw_3d(&e, |window| {
            let now = Instant::now();
            let dt = (now - last_frame).as_secs() as f32
                + (now - last_frame).subsec_nanos() as f32 / 1000_000_000.0;
            last_frame = now;

            window
                .encoder
                .clear_depth(&smaa_target.output_stencil(), 1.0);
            window
                .encoder
                .clear(&smaa_target.output_color(), [0.3, 0.3, 0.3, 1.0]);

            let view_matrix = compute_view_matrix(first_person.camera(0.0));
            terrain.update(
                projection_matrix * view_matrix,
                camera_position,
                camera_frustum,
                &mut window.encoder,
                dt,
            );
            terrain.render(&mut window.encoder).unwrap();
            terrain.render_sky(&mut window.encoder);

            let text_color = [0.0, 1.0, 1.0, 1.0];
            let fps = fps_counter.tick();
            text.add(&format!("FPS: {}", fps), [5, 5], text_color);
            text.add(
                &format!("Frame time: {:.1}", 1000.0 / fps as f32),
                [5, 17],
                text_color,
            );
            text.draw(&mut window.encoder, &smaa_target.output_color())
                .unwrap();

            smaa_target.resolve(&mut window.encoder);
        });
    }
}
<|endoftext|>


<commit_before>extern crate rsrl;

use rsrl::{run, SerialExperiment, Evaluation};
use rsrl::fa::linear::UniformGrid;
use rsrl::agents::control::td::QLearning;
use rsrl::domains::{Domain, CartPole};
use rsrl::policies::{Greedy, EpsilonGreedy};
use rsrl::geometry::Space;

use rsrl::logging::DefaultLogger;

fn main() {
    let domain = CartPole::default();
    let mut agent = {
        let aspace = domain.action_space();
        let n_actions: usize = aspace.span().into();

        let q_func = UniformGrid::new(
            domain.state_space().partitioned(10), n_actions);

        QLearning::new(q_func, Greedy, 0.2, 0.95)
    };

    // Training:
    let training_result = {
        let e = SerialExperiment::new(&mut agent,
                                      Box::new(CartPole::default),
                                      1000);

        run(e, 2000)
    };

    // Testing:
    let testing_result =
        Evaluation::new(&mut agent, Box::new(CartPole::default)).next().unwrap();

    println!("Solution \u{21D2} {} steps | reward {}",
             testing_result.n_steps,
             testing_result.total_reward);
}
<commit_msg>Change example slightly<commit_after>extern crate rsrl;

use rsrl::{run, SerialExperiment, Evaluation};
use rsrl::fa::linear::RBFNetwork;
use rsrl::agents::control::td::QLearning;
use rsrl::domains::{Domain, MountainCar};
use rsrl::policies::{Greedy, EpsilonGreedy};
use rsrl::geometry::Space;

use rsrl::logging::DefaultLogger;

fn main() {
    let domain = MountainCar::default();
    let mut agent = {
        let aspace = domain.action_space();
        let n_actions: usize = aspace.span().into();

        let q_func = RBFNetwork::new(
            domain.state_space().partitioned(8), n_actions);

        QLearning::new(q_func, Greedy, 0.1, 0.95)
    };

    // Training:
    let training_result = {
        let e = SerialExperiment::new(&mut agent,
                                      Box::new(MountainCar::default),
                                      1000);

        run(e, 1000)
    };

    // Testing:
    let testing_result =
        Evaluation::new(&mut agent, Box::new(MountainCar::default)).next().unwrap();

    println!("Solution \u{21D2} {} steps | reward {}",
             testing_result.n_steps,
             testing_result.total_reward);
}
<|endoftext|>


<commit_before>use serialize::json::{Json};
use anymap::AnyMap;

use server::{Request, Response};
use middleware::{HandleResult, Error};
use framework::endpoint::Endpoint;
use framework::media::Media;
use server_backend::status;
use server_backend::mime;
use server_backend::header::Header;
use server_backend::header::common::{ContentType, Location};

pub struct Client<'a> {
    pub endpoint: &'a Endpoint,
    pub request: &'a mut Request,
    pub media: Option<&'a Media>,
    pub ext: AnyMap,
    pub response: Response
}

impl<'a> Client<'a> {

    pub fn new(endpoint: &'a Endpoint, request: &'a mut Request, media: Option<&'a Media>) -> Client<'a> {
        Client {
            endpoint: endpoint,
            request: request,
            media: media,
            ext: AnyMap::new(),
            response: Response::new(status::Ok)
        }
    }

    pub fn status(&mut self) -> status::StatusCode {
        self.response.status
    }

    pub fn set_status(&mut self, status: status::StatusCode) {
        self.response.status = status;
    }

    pub fn set_header<H: Header>(&mut self, header: H) {
        self.response.headers.set(header);
    }

    pub fn set_json_content_type(&mut self) {
        let application_json: mime::Mime = from_str("application/json").unwrap();
        self.set_header(ContentType(application_json));
    }

    pub fn error<T: Error>(self, error: T) -> HandleResult<Client<'a>> {
        Err(error.abstract())
    }

    pub fn json(mut self, result: &Json) -> HandleResult<Client<'a>> {
        self.set_json_content_type();
        self.response.push_string(result.to_string());

        Ok(self)
    }

    pub fn text(mut self, result: String) -> HandleResult<Client<'a>> {
        self.response.push_string(result);

        Ok(self)
    }

    pub fn redirect(mut self, to: &str) -> HandleResult<Client<'a>> {
        self.set_status(status::Found);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn permanent_redirect(mut self, to: &str) -> HandleResult<Client<'a>> {
        self.set_status(status::MovedPermanently);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn move_response(self) -> Response {
        self.response
    }

    pub fn ext(&self) -> &AnyMap {
        &self.ext
    }

    pub fn ext_mut(&mut self) -> &mut AnyMap {
        &mut self.ext
    }

}<commit_msg>feature: add ability to set `Content-Type`<commit_after>use serialize::json::{Json};
use anymap::AnyMap;

use server::{Request, Response};
use middleware::{HandleResult, Error};
use framework::endpoint::Endpoint;
use framework::media::Media;
use server_backend::status;
use server_backend::mime;
use server_backend::header::Header;
use server_backend::header::common::{ContentType, Location};

pub struct Client<'a> {
    pub endpoint: &'a Endpoint,
    pub request: &'a mut Request,
    pub media: Option<&'a Media>,
    pub ext: AnyMap,
    pub response: Response
}

impl<'a> Client<'a> {

    pub fn new(endpoint: &'a Endpoint, request: &'a mut Request, media: Option<&'a Media>) -> Client<'a> {
        Client {
            endpoint: endpoint,
            request: request,
            media: media,
            ext: AnyMap::new(),
            response: Response::new(status::Ok)
        }
    }

    pub fn status(&mut self) -> status::StatusCode {
        self.response.status
    }

    pub fn set_status(&mut self, status: status::StatusCode) {
        self.response.status = status;
    }

    pub fn set_header<H: Header>(&mut self, header: H) {
        self.response.headers.set(header);
    }

    pub fn set_json_content_type(&mut self) {
        self.set_header(ContentType(mime::Mime(mime::Application, mime::Json, vec![])));
    }

    pub fn set_content_type(&mut self, mime: mime::Mime) {
        self.set_header(ContentType(mime));
    }

    pub fn error<T: Error>(self, error: T) -> HandleResult<Client<'a>> {
        Err(error.abstract())
    }

    pub fn json(mut self, result: &Json) -> HandleResult<Client<'a>> {
        self.set_json_content_type();
        self.response.push_string(result.to_string());

        Ok(self)
    }

    pub fn text(mut self, result: String) -> HandleResult<Client<'a>> {
        self.response.push_string(result);

        Ok(self)
    }

    pub fn redirect(mut self, to: &str) -> HandleResult<Client<'a>> {
        self.set_status(status::Found);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn permanent_redirect(mut self, to: &str) -> HandleResult<Client<'a>> {
        self.set_status(status::MovedPermanently);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn move_response(self) -> Response {
        self.response
    }

    pub fn ext(&self) -> &AnyMap {
        &self.ext
    }

    pub fn ext_mut(&mut self) -> &mut AnyMap {
        &mut self.ext
    }

}<|endoftext|>


<commit_before>use bounded_spsc_queue::{Consumer};
use kissfft::KissFFT;
use kissfft::binding::kiss_fft_cpx;
use osc::osc_sender::*;
use osc::osc_data::OscPacket::*;
use osc::osc_data::OscArg::*;
use std::thread;
use std::thread::{JoinHandle};
use std::sync::{Arc, Mutex};
use itertools::Itertools;

const OSC_PER_SEC : usize = 30usize;

#[derive(Clone, Debug)]
struct IndexedMagnitude {
    index : usize,
    magnitude : f32
}

use std::cmp::Ordering;
impl PartialOrd for IndexedMagnitude {
     fn partial_cmp(&self, other: &IndexedMagnitude) -> Option<Ordering> {
        return self.magnitude.partial_cmp(&other.magnitude);
     }
}
impl PartialEq for IndexedMagnitude {
    fn eq(&self, other: &IndexedMagnitude) -> bool {
        return self.magnitude.eq(&other.magnitude);
    }
}

fn index_magnitudes(mags : &Vec<f32>) -> Vec<IndexedMagnitude> {
    let mut indexed = vec!();
    let mut i = 0usize;
    for mag in mags {
        indexed.push(IndexedMagnitude{index : i, magnitude : *mag});
        i += 1usize;
    }
    indexed
}
use std::f32;
const PEAK_THRESHOLD : f32 = 9./10.;
fn pitch_detect_ac(buckets : &Vec<f32>, fs : usize) -> Option<(f32, usize)> {
    //  1 indexed
    //  filter to peaks
    let buckets = &mut buckets.clone()[0..buckets.len()/4].to_vec();
    for i in 0..buckets.len() {
        buckets[i] = f32::max(0., buckets[i]);
    }
    let mut first_zero_idx = 0usize;
    for i in 0..buckets.len() {
        if buckets[i] <= 0. {
            first_zero_idx = i;
            break;
        }
    }
    let peaks = find_peaks(&index_magnitudes(buckets)[first_zero_idx..buckets.len()].to_vec(), PEAK_THRESHOLD).0;
    for peak in peaks.iter() {
        if peak.index > first_zero_idx {
            return Some((fs as f32 / 2. / peak.index as f32, peak.index));
        }
    }
    None
}

fn idx_to_freq(idx : usize, n : usize, fs : usize) -> f32 {
    (idx * fs) as f32 / n as f32
}

fn bkt_to_freq(bkt : &IndexedMagnitude, buckets : usize, fs : usize) -> f32 {
    idx_to_freq(bkt.index, buckets, fs)
}

fn compute_dissonance(buckets : &Vec<f32>, fs : usize) -> f32{
    let (mut peaks, _) = find_peaks(&find_peaks(&index_magnitudes(buckets), 1./12.).0, 1./12.);
    peaks.sort_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
    if peaks.len() < 3 {
        return 0.;
    }
    let f1 = bkt_to_freq(&peaks[0], buckets.len() * 2, fs);
    let f2 = bkt_to_freq(&peaks[1], buckets.len() * 2, fs);
    let f3 = bkt_to_freq(&peaks[2], buckets.len() * 2, fs);
    let d1 = f2 / f1;
    let d2 = f3 / f1;

    let fd1 = (d1 - d1.floor() - 0.5).abs() * 2.;
    let fd2 = (d2 - d2.floor() - 0.5).abs() * 2.;
    return (fd1 - fd2).abs();
}

/// Return peaks of the signal considering values above threshold * the maximum
/// Expects a vector of magnitudes
/// Also returns the valleys
fn find_peaks(buckets : &Vec<IndexedMagnitude>,
              threshold_coef : f32) -> (Vec<IndexedMagnitude>,
                                        Vec<Option<IndexedMagnitude>>) {
    let mut threshold = 0.0;
    for bucket in buckets.iter() {
        threshold = f32::max(threshold, bucket.magnitude);
    }
    threshold *= threshold_coef;
    let mut peaks = vec!();
    let mut valleys = vec!();
    let buckets = buckets.iter();
    let mut high : Option<IndexedMagnitude> = None;
    let mut low : Option<IndexedMagnitude> = None;
    let mut pre_peak_low : Option<IndexedMagnitude> = None;
    for bucket in buckets {
        if let Some(low_val) = low.clone() {
           if bucket.magnitude < low_val.magnitude {
               low = Some(bucket.clone());
           }
        } else {
            low = Some(bucket.clone());
        }
        if let Some(high_val) = high.clone() {
           if bucket.magnitude > high_val.magnitude {
               high = Some(bucket.clone());
               pre_peak_low = low.clone();
           }
        } else {
            high = Some(bucket.clone());
            pre_peak_low = low.clone();
        }
        if let Some(high_val) = high.clone() {
            if high_val.magnitude - bucket.magnitude > threshold / 2.
                && bucket.magnitude - low.clone().unwrap().magnitude > threshold / 2. {
                    peaks.push(high_val.clone());
                    valleys.push(pre_peak_low.clone());
                    high = None;
                    low = None;
                    pre_peak_low = None;
            }
        }
    }
    (peaks, valleys)
}

fn zero_padded_fft_norm(buf : &Vec<kiss_fft_cpx>, zeros : usize) -> Vec<f32>{
    let mut zero_vec = vec!();
    for _ in 0..zeros {
        zero_vec.push(kiss_fft_cpx{r : 0f32, i : 0f32});
    }
    let mut fft_buf = vec!();
    fft_buf.push_all(&zero_vec[..]);
    fft_buf.push_all(&buf[..]);
    let mut fft = KissFFT::new(buf.len() + zeros, false);
    let mut fft_out = fft.transform_norm_to_vec(&fft_buf[..]);
    let n = fft_out.len();
    fft_out.split_off(n / 2usize);
    Vec::from_iter(fft_out.iter().map(|c| (c.r * c.r + c.i * c.i).sqrt()))
}

fn fft_inv_real(buf : &Vec<kiss_fft_cpx>) -> Vec<f32>{
    let mut fft = KissFFT::new(buf.len(), true);
    let fft_out = fft.transform_norm_to_vec(&buf[..]);
    fft_out.into_iter().map(|r| r.r).collect()
}

use std::f32::consts;
fn hann_window(v : Vec<kiss_fft_cpx>) -> Vec<kiss_fft_cpx> {
    let mut v = v;
    for i in 0..v.len() {
        v[i] = kiss_fft_cpx{
            r : v[i].r * ((consts::PI * i as f32) / (v.len() as f32 - 1.)).sin().powi(2),
            i : v[i].i * ((consts::PI * i as f32) / (v.len() as f32 - 1.)).sin().powi(2)
        };
    }
    v
}

fn autocorrelate(buf : &Vec<kiss_fft_cpx>) -> Vec<f32> {
    let buf = hann_window(buf.clone());
    let mut fft_norm : Vec<f32> = zero_padded_fft_norm(&buf, buf.len()).into_iter().map(|r| r*r).collect();
    fft_norm[0] = 0f32;
    let ac = fft_inv_real(&fft_norm.into_iter().map(|r| kiss_fft_cpx{r:r, i:0f32}).collect());
    let first = ac[0];
    let ac = ac.into_iter().map(|e| e/first).collect();
    ac
}

use std::iter::FromIterator;
pub fn meter_fft(
    sampling_frequency : usize,
    active_channels : Vec<String>,
    c : Consumer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String,
    display_buckets : Arc<Mutex<Vec<f32>>>,
    display_lines : Arc<Mutex<Vec<([f32; 4], usize)>>>,
    display_chan_index : Option<i32>,
    ) -> JoinHandle<()> {
        let mut chan_index = 0;
        let fft_buckets = 2048;
        let mut samples = 0usize;
        let mut last_sent_time = 0usize;
        let mut bufs_by_channel = Vec::new();
        let mut pitch_by_chan : Vec<f32> = Vec::new();
        let mut last_pitch_by_chan : Vec<(f32, usize)> = Vec::new();
        let mut dissonance_by_chan : Vec<f32> = Vec::new();
        let mut num_peaks_by_chan : Vec<usize> = Vec::new();
        for _ in 0..active_channels.len() {
            bufs_by_channel.push(vec!());
            pitch_by_chan.push(0.);
            last_pitch_by_chan.push((0., 0));
            dissonance_by_chan.push(0.);
            num_peaks_by_chan.push(0);
        }
        thread::spawn(move || {
            loop {
                if let Some(s) = c.try_pop() {
                    let buf = &mut bufs_by_channel[chan_index];
                    buf.push(kiss_fft_cpx{r : s, i : 0f32});
                    if buf.len() == fft_buckets {
                        let fft_norm = autocorrelate(buf);
                        //let fft_norm = zero_padded_cepstrum(&hann_window(buf.clone()), n - fft_buckets);

                        let (peaks, valleys) = find_peaks(&index_magnitudes(&fft_norm), PEAK_THRESHOLD);
                        let (mtns, _) = find_peaks(&peaks, 1./5.);
                        num_peaks_by_chan[chan_index] = mtns.len();
                        if let Some((detected_pitch, index)) = pitch_detect_ac(&fft_norm, sampling_frequency) {
                            let black = [0./255., 0./255., 0./255., 0.5];
                            pitch_by_chan[chan_index] = detected_pitch;
                            let mut display_lines = display_lines.lock().unwrap();
                            display_lines.push((black.clone(), index));
                        }
                        let dissonance = compute_dissonance(&fft_norm, sampling_frequency);
                        dissonance_by_chan[chan_index] = dissonance;
                        if let Some(display_chan_index) = display_chan_index {
                            if display_chan_index == chan_index as i32 {
                                let mut display_buckets = display_buckets.lock().unwrap();
                                display_buckets.clear();
                                display_buckets.push_all(&fft_norm[..]);
                                let yellow = [243./255., 232./255., 51./255., 0.5];
                                let red = [239./255., 101./255., 68./255., 1.];
                                let mut display_lines = display_lines.lock().unwrap();
                                display_lines.clear();
                                for mtn in peaks.iter() {
                                    display_lines.push((red.clone(), mtn.index.clone()));
                                }
                                for valley in valleys.iter() {
                                    if let &Some(ref valley) = valley {
                                        display_lines.push((yellow.clone(), valley.index.clone()));
                                    }
                                }
                                display_buckets.push_all(&fft_norm[..]);
                            }
                        }
                        if samples > last_sent_time + sampling_frequency * active_channels.len() / OSC_PER_SEC {
                            last_sent_time = samples;
                            let mut sender = osc_sender.lock().unwrap();
                            for i in 0..active_channels.len() {
                                let track_title = &active_channels[i];
                                let detected_pitch = pitch_by_chan[i];
                                let pitch_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/detectedPitch", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(detected_pitch))
                                    };
                                if let Err(e) = sender.send(pitch_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let num_peaks = num_peaks_by_chan[i];
                                let peaks_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/numPeaks", track_title, osc_prefix).to_string(),
                                        args : vec!(OscInt(num_peaks as i32))
                                    };
                                if let Err(e) = sender.send(peaks_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let dissonance = dissonance_by_chan[i];
                                let diss_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/dissonance", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(dissonance))
                                    };
                                if let Err(e) = sender.send(diss_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }

                            }
                        }
                        let drain = buf.len() * 3 / 4;
                        for _ in 0..drain {
                            buf.remove(0);
                        }
                        //buf.clear();
                    }
                    samples += 1usize;
                    chan_index = (chan_index + 1) % active_channels.len();
                } else {
                    thread::sleep_ms(12u32);
                }
            }
        })

    }
<commit_msg>.95 peak threshold<commit_after>use bounded_spsc_queue::{Consumer};
use kissfft::KissFFT;
use kissfft::binding::kiss_fft_cpx;
use osc::osc_sender::*;
use osc::osc_data::OscPacket::*;
use osc::osc_data::OscArg::*;
use std::thread;
use std::thread::{JoinHandle};
use std::sync::{Arc, Mutex};
use itertools::Itertools;

const OSC_PER_SEC : usize = 30usize;

#[derive(Clone, Debug)]
struct IndexedMagnitude {
    index : usize,
    magnitude : f32
}

use std::cmp::Ordering;
impl PartialOrd for IndexedMagnitude {
     fn partial_cmp(&self, other: &IndexedMagnitude) -> Option<Ordering> {
        return self.magnitude.partial_cmp(&other.magnitude);
     }
}
impl PartialEq for IndexedMagnitude {
    fn eq(&self, other: &IndexedMagnitude) -> bool {
        return self.magnitude.eq(&other.magnitude);
    }
}

fn index_magnitudes(mags : &Vec<f32>) -> Vec<IndexedMagnitude> {
    let mut indexed = vec!();
    let mut i = 0usize;
    for mag in mags {
        indexed.push(IndexedMagnitude{index : i, magnitude : *mag});
        i += 1usize;
    }
    indexed
}
use std::f32;
const PEAK_THRESHOLD : f32 = 9.5/10.;
fn pitch_detect_ac(buckets : &Vec<f32>, fs : usize) -> Option<(f32, usize)> {
    //  1 indexed
    //  filter to peaks
    let buckets = &mut buckets.clone()[0..buckets.len()/4].to_vec();
    for i in 0..buckets.len() {
        buckets[i] = f32::max(0., buckets[i]);
    }
    let mut first_zero_idx = 0usize;
    for i in 0..buckets.len() {
        if buckets[i] <= 0. {
            first_zero_idx = i;
            break;
        }
    }
    let peaks = find_peaks(&index_magnitudes(buckets)[first_zero_idx..buckets.len()].to_vec(), PEAK_THRESHOLD).0;
    for peak in peaks.iter() {
        if peak.index > first_zero_idx {
            return Some((fs as f32 / 2. / peak.index as f32, peak.index));
        }
    }
    None
}

fn idx_to_freq(idx : usize, n : usize, fs : usize) -> f32 {
    (idx * fs) as f32 / n as f32
}

fn bkt_to_freq(bkt : &IndexedMagnitude, buckets : usize, fs : usize) -> f32 {
    idx_to_freq(bkt.index, buckets, fs)
}

fn compute_dissonance(buckets : &Vec<f32>, fs : usize) -> f32{
    let (mut peaks, _) = find_peaks(&find_peaks(&index_magnitudes(buckets), 1./12.).0, 1./12.);
    peaks.sort_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
    if peaks.len() < 3 {
        return 0.;
    }
    let f1 = bkt_to_freq(&peaks[0], buckets.len() * 2, fs);
    let f2 = bkt_to_freq(&peaks[1], buckets.len() * 2, fs);
    let f3 = bkt_to_freq(&peaks[2], buckets.len() * 2, fs);
    let d1 = f2 / f1;
    let d2 = f3 / f1;

    let fd1 = (d1 - d1.floor() - 0.5).abs() * 2.;
    let fd2 = (d2 - d2.floor() - 0.5).abs() * 2.;
    return (fd1 - fd2).abs();
}

/// Return peaks of the signal considering values above threshold * the maximum
/// Expects a vector of magnitudes
/// Also returns the valleys
fn find_peaks(buckets : &Vec<IndexedMagnitude>,
              threshold_coef : f32) -> (Vec<IndexedMagnitude>,
                                        Vec<Option<IndexedMagnitude>>) {
    let mut threshold = 0.0;
    for bucket in buckets.iter() {
        threshold = f32::max(threshold, bucket.magnitude);
    }
    threshold *= threshold_coef;
    let mut peaks = vec!();
    let mut valleys = vec!();
    let buckets = buckets.iter();
    let mut high : Option<IndexedMagnitude> = None;
    let mut low : Option<IndexedMagnitude> = None;
    let mut pre_peak_low : Option<IndexedMagnitude> = None;
    for bucket in buckets {
        if let Some(low_val) = low.clone() {
           if bucket.magnitude < low_val.magnitude {
               low = Some(bucket.clone());
           }
        } else {
            low = Some(bucket.clone());
        }
        if let Some(high_val) = high.clone() {
           if bucket.magnitude > high_val.magnitude {
               high = Some(bucket.clone());
               pre_peak_low = low.clone();
           }
        } else {
            high = Some(bucket.clone());
            pre_peak_low = low.clone();
        }
        if let Some(high_val) = high.clone() {
            if high_val.magnitude - bucket.magnitude > threshold / 2.
                && bucket.magnitude - low.clone().unwrap().magnitude > threshold / 2. {
                    peaks.push(high_val.clone());
                    valleys.push(pre_peak_low.clone());
                    high = None;
                    low = None;
                    pre_peak_low = None;
            }
        }
    }
    (peaks, valleys)
}

fn zero_padded_fft_norm(buf : &Vec<kiss_fft_cpx>, zeros : usize) -> Vec<f32>{
    let mut zero_vec = vec!();
    for _ in 0..zeros {
        zero_vec.push(kiss_fft_cpx{r : 0f32, i : 0f32});
    }
    let mut fft_buf = vec!();
    fft_buf.push_all(&zero_vec[..]);
    fft_buf.push_all(&buf[..]);
    let mut fft = KissFFT::new(buf.len() + zeros, false);
    let mut fft_out = fft.transform_norm_to_vec(&fft_buf[..]);
    let n = fft_out.len();
    fft_out.split_off(n / 2usize);
    Vec::from_iter(fft_out.iter().map(|c| (c.r * c.r + c.i * c.i).sqrt()))
}

fn fft_inv_real(buf : &Vec<kiss_fft_cpx>) -> Vec<f32>{
    let mut fft = KissFFT::new(buf.len(), true);
    let fft_out = fft.transform_norm_to_vec(&buf[..]);
    fft_out.into_iter().map(|r| r.r).collect()
}

use std::f32::consts;
fn hann_window(v : Vec<kiss_fft_cpx>) -> Vec<kiss_fft_cpx> {
    let mut v = v;
    for i in 0..v.len() {
        v[i] = kiss_fft_cpx{
            r : v[i].r * ((consts::PI * i as f32) / (v.len() as f32 - 1.)).sin().powi(2),
            i : v[i].i * ((consts::PI * i as f32) / (v.len() as f32 - 1.)).sin().powi(2)
        };
    }
    v
}

fn autocorrelate(buf : &Vec<kiss_fft_cpx>) -> Vec<f32> {
    let buf = hann_window(buf.clone());
    let mut fft_norm : Vec<f32> = zero_padded_fft_norm(&buf, buf.len()).into_iter().map(|r| r*r).collect();
    fft_norm[0] = 0f32;
    let ac = fft_inv_real(&fft_norm.into_iter().map(|r| kiss_fft_cpx{r:r, i:0f32}).collect());
    let first = ac[0];
    let ac = ac.into_iter().map(|e| e/first).collect();
    ac
}

use std::iter::FromIterator;
pub fn meter_fft(
    sampling_frequency : usize,
    active_channels : Vec<String>,
    c : Consumer<f32>,
    osc_sender : Arc<Mutex<OscSender>>,
    osc_prefix : String,
    display_buckets : Arc<Mutex<Vec<f32>>>,
    display_lines : Arc<Mutex<Vec<([f32; 4], usize)>>>,
    display_chan_index : Option<i32>,
    ) -> JoinHandle<()> {
        let mut chan_index = 0;
        let fft_buckets = 2048;
        let mut samples = 0usize;
        let mut last_sent_time = 0usize;
        let mut bufs_by_channel = Vec::new();
        let mut pitch_by_chan : Vec<f32> = Vec::new();
        let mut last_pitch_by_chan : Vec<(f32, usize)> = Vec::new();
        let mut dissonance_by_chan : Vec<f32> = Vec::new();
        let mut num_peaks_by_chan : Vec<usize> = Vec::new();
        for _ in 0..active_channels.len() {
            bufs_by_channel.push(vec!());
            pitch_by_chan.push(0.);
            last_pitch_by_chan.push((0., 0));
            dissonance_by_chan.push(0.);
            num_peaks_by_chan.push(0);
        }
        thread::spawn(move || {
            loop {
                if let Some(s) = c.try_pop() {
                    let buf = &mut bufs_by_channel[chan_index];
                    buf.push(kiss_fft_cpx{r : s, i : 0f32});
                    if buf.len() == fft_buckets {
                        let fft_norm = autocorrelate(buf);
                        //let fft_norm = zero_padded_cepstrum(&hann_window(buf.clone()), n - fft_buckets);

                        let (peaks, valleys) = find_peaks(&index_magnitudes(&fft_norm), PEAK_THRESHOLD);
                        let (mtns, _) = find_peaks(&peaks, 1./5.);
                        num_peaks_by_chan[chan_index] = mtns.len();
                        if let Some((detected_pitch, index)) = pitch_detect_ac(&fft_norm, sampling_frequency) {
                            let black = [0./255., 0./255., 0./255., 0.5];
                            pitch_by_chan[chan_index] = detected_pitch;
                            let mut display_lines = display_lines.lock().unwrap();
                            display_lines.push((black.clone(), index));
                        }
                        let dissonance = compute_dissonance(&fft_norm, sampling_frequency);
                        dissonance_by_chan[chan_index] = dissonance;
                        if let Some(display_chan_index) = display_chan_index {
                            if display_chan_index == chan_index as i32 {
                                let mut display_buckets = display_buckets.lock().unwrap();
                                display_buckets.clear();
                                display_buckets.push_all(&fft_norm[..]);
                                let yellow = [243./255., 232./255., 51./255., 0.5];
                                let red = [239./255., 101./255., 68./255., 1.];
                                let mut display_lines = display_lines.lock().unwrap();
                                display_lines.clear();
                                for mtn in peaks.iter() {
                                    display_lines.push((red.clone(), mtn.index.clone()));
                                }
                                for valley in valleys.iter() {
                                    if let &Some(ref valley) = valley {
                                        display_lines.push((yellow.clone(), valley.index.clone()));
                                    }
                                }
                                display_buckets.push_all(&fft_norm[..]);
                            }
                        }
                        if samples > last_sent_time + sampling_frequency * active_channels.len() / OSC_PER_SEC {
                            last_sent_time = samples;
                            let mut sender = osc_sender.lock().unwrap();
                            for i in 0..active_channels.len() {
                                let track_title = &active_channels[i];
                                let detected_pitch = pitch_by_chan[i];
                                let pitch_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/detectedPitch", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(detected_pitch))
                                    };
                                if let Err(e) = sender.send(pitch_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let num_peaks = num_peaks_by_chan[i];
                                let peaks_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/numPeaks", track_title, osc_prefix).to_string(),
                                        args : vec!(OscInt(num_peaks as i32))
                                    };
                                if let Err(e) = sender.send(peaks_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }
                                let dissonance = dissonance_by_chan[i];
                                let diss_msg =
                                    OscMessage{
                                        addr : format!("/{}/{}/dissonance", track_title, osc_prefix).to_string(),
                                        args : vec!(OscFloat(dissonance))
                                    };
                                if let Err(e) = sender.send(diss_msg) {
                                    println!("Error sending OSC: {:?}", e);
                                }

                            }
                        }
                        let drain = buf.len() * 3 / 4;
                        for _ in 0..drain {
                            buf.remove(0);
                        }
                        //buf.clear();
                    }
                    samples += 1usize;
                    chan_index = (chan_index + 1) % active_channels.len();
                } else {
                    thread::sleep_ms(12u32);
                }
            }
        })

    }
<|endoftext|>


<commit_before>//! A window implemented by SDL2 back-end.

// External crates.
use sdl2;

// Local crate.
use game_window::{
    GameWindow,
};
use event;
use game_window_settings::GameWindowSettings;
use keyboard;
use mouse;
use gl;

/// A widow implemented by SDL2 back-end.
pub struct GameWindowSDL2 {
    window: sdl2::video::Window,
    context: sdl2::video::GLContext,

    settings: GameWindowSettings,
    should_close: bool,
}

impl GameWindow for GameWindowSDL2 {
    fn new(settings: GameWindowSettings) -> GameWindowSDL2 {
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMajorVersion, 3);
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMinorVersion, 3);
        sdl2::video::gl_set_attribute(sdl2::video::GLContextProfileMask, sdl2::video::ll::SDL_GL_CONTEXT_PROFILE_CORE as int);

        let window = sdl2::video::Window::new(
            settings.title,
            sdl2::video::PosCentered,
            sdl2::video::PosCentered,
            settings.size[0] as int,
            settings.size[1] as int,
            sdl2::video::OpenGL
        ).unwrap();

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers
        gl::load_with(|s| sdl2::video::gl_get_proc_address(s));

        GameWindowSDL2 {
            window: window,
            context: context,

            settings: settings,
            should_close: false,
        }
    }

    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn swap_buffers(&self) {
        self.window.gl_swap_window();
    }

    fn poll_event(&mut self) -> event::Event {
        match sdl2::event::poll_event() {
            sdl2::event::QuitEvent(_) => { self.should_close = true; },
            sdl2::event::KeyDownEvent(_, _, key, _, _) => {
                if self.settings.exit_on_esc && key == sdl2::keycode::EscapeKey {
                    self.should_close = true;
                } else {
                    return event::KeyPressed(sdl2_map_key(key));
                }
            },
            sdl2::event::KeyUpEvent(_, _, key, _, _) => {
                return event::KeyReleased(sdl2_map_key(key));
            },
            sdl2::event::MouseButtonDownEvent(_, _, _, button, _, _) => {
                return event::MouseButtonPressed(sdl2_map_mouse(button));
            },
            sdl2::event::MouseButtonUpEvent(_, _, _, button, _, _) => {
                return event::MouseButtonReleased(sdl2_map_mouse(button));
            },
            sdl2::event::MouseMotionEvent(_, _, _, _, x, y, dx, dy) => {
                return event::MouseMoved(
                    x as f64,
                    y as f64,
                    Some((dx as f64, dy as f64))
                );
            },
            _ => {},
        }
        event::NoEvent
    }
}

fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use std::num::FromPrimitive;
    FromPrimitive::from_u64(keycode.code() as u64).unwrap()
}

fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> mouse::Button {
    match button {
        sdl2::mouse::LeftMouse => mouse::Left,
        sdl2::mouse::RightMouse => mouse::Right,
        sdl2::mouse::MiddleMouse => mouse::Middle,
        sdl2::mouse::X1Mouse => mouse::X1,
        sdl2::mouse::X2Mouse => mouse::X2,
        sdl2::mouse::UnknownMouse(_) => mouse::Unknown,
    }
}

<commit_msg>Fixed SDL2 key down bug<commit_after>//! A window implemented by SDL2 back-end.

// External crates.
use sdl2;

// Local crate.
use game_window::{
    GameWindow,
};
use event;
use game_window_settings::GameWindowSettings;
use keyboard;
use mouse;
use gl;

/// A widow implemented by SDL2 back-end.
pub struct GameWindowSDL2 {
    window: sdl2::video::Window,
    context: sdl2::video::GLContext,
    settings: GameWindowSettings,
    should_close: bool,
    last_pressed_key: Option<sdl2::keycode::KeyCode>,
}

impl GameWindow for GameWindowSDL2 {
    fn new(settings: GameWindowSettings) -> GameWindowSDL2 {
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMajorVersion, 3);
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMinorVersion, 3);
        sdl2::video::gl_set_attribute(sdl2::video::GLContextProfileMask, sdl2::video::ll::SDL_GL_CONTEXT_PROFILE_CORE as int);

        let window = sdl2::video::Window::new(
            settings.title,
            sdl2::video::PosCentered,
            sdl2::video::PosCentered,
            settings.size[0] as int,
            settings.size[1] as int,
            sdl2::video::OpenGL
        ).unwrap();

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers
        gl::load_with(|s| sdl2::video::gl_get_proc_address(s));

        GameWindowSDL2 {
            window: window,
            context: context,
            settings: settings,
            should_close: false,
            last_pressed_key: None,
        }
    }

    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn swap_buffers(&self) {
        self.window.gl_swap_window();
    }

    fn poll_event(&mut self) -> event::Event {
        match sdl2::event::poll_event() {
            sdl2::event::QuitEvent(_) => { self.should_close = true; },
            sdl2::event::KeyDownEvent(_, _, key, _, _) => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                match self.last_pressed_key {
                    Some(x) if x == key => return event::NoEvent,
                    _ => {},
                };
                self.last_pressed_key = Some(key);

                if self.settings.exit_on_esc
                && key == sdl2::keycode::EscapeKey {
                    self.should_close = true;
                } else {
                    return event::KeyPressed(sdl2_map_key(key));
                }
            },
            sdl2::event::KeyUpEvent(_, _, key, _, _) => {
                // Reset the last pressed key.
                self.last_pressed_key = match self.last_pressed_key {
                    Some(x) if x == key => None,
                    x => x,
                };

                return event::KeyReleased(sdl2_map_key(key));
            },
            sdl2::event::MouseButtonDownEvent(_, _, _, button, _, _) => {
                return event::MouseButtonPressed(sdl2_map_mouse(button));
            },
            sdl2::event::MouseButtonUpEvent(_, _, _, button, _, _) => {
                return event::MouseButtonReleased(sdl2_map_mouse(button));
            },
            sdl2::event::MouseMotionEvent(_, _, _, _, x, y, dx, dy) => {
                return event::MouseMoved(
                    x as f64,
                    y as f64,
                    Some((dx as f64, dy as f64))
                );
            },
            _ => {},
        }
        event::NoEvent
    }
}

fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use std::num::FromPrimitive;
    FromPrimitive::from_u64(keycode.code() as u64).unwrap()
}

fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> mouse::Button {
    match button {
        sdl2::mouse::LeftMouse => mouse::Left,
        sdl2::mouse::RightMouse => mouse::Right,
        sdl2::mouse::MiddleMouse => mouse::Middle,
        sdl2::mouse::X1Mouse => mouse::X1,
        sdl2::mouse::X2Mouse => mouse::X2,
        sdl2::mouse::UnknownMouse(_) => mouse::Unknown,
    }
}

<|endoftext|>