<commit_before>use glutin::{self, PossiblyCurrent};

use std::ffi::CStr;

pub mod gl {
    pub use self::Gles2 as Gl;
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

pub struct Gl {
    pub gl: gl::Gl,
}

extern "system" fn dbg_callback(
    source: gl::types::GLenum,
    etype: gl::types::GLenum,
    _id: gl::types::GLuint,
    severity: gl::types::GLenum,
    _msg_length: gl::types::GLsizei,
    msg: *const gl::types::GLchar,
    _user_data: *mut std::ffi::c_void,
) {
    unsafe {
        println!(
            "dbg_callback {:#X} {:#X} {:#X} {:?}",
            source,
            etype,
            severity,
            std::ffi::CStr::from_ptr(msg),
        );
    }
}

pub fn load(gl_context: &glutin::Context<PossiblyCurrent>) -> Gl {
    let gl =
        gl::Gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _);

    unsafe {
        gl.Enable(gl::DEBUG_OUTPUT);
        gl.DebugMessageCallback(dbg_callback, std::ptr::null());
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl.GetString(gl::VERSION) as *const _)
            .to_bytes()
            .to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);

    unsafe {
        let vs = gl.CreateShader(gl::VERTEX_SHADER);
        gl.ShaderSource(
            vs,
            1,
            [VS_SRC.as_ptr() as *const _].as_ptr(),
            std::ptr::null(),
        );
        gl.CompileShader(vs);

        let fs = gl.CreateShader(gl::FRAGMENT_SHADER);
        gl.ShaderSource(
            fs,
            1,
            [FS_SRC.as_ptr() as *const _].as_ptr(),
            std::ptr::null(),
        );
        gl.CompileShader(fs);

        let program = gl.CreateProgram();
        gl.AttachShader(program, vs);
        gl.AttachShader(program, fs);
        gl.LinkProgram(program);
        gl.UseProgram(program);

        let mut vb = std::mem::uninitialized();
        gl.GenBuffers(1, &mut vb);
        gl.BindBuffer(gl::ARRAY_BUFFER, vb);
        gl.BufferData(
            gl::ARRAY_BUFFER,
            (VERTEX_DATA.len() * std::mem::size_of::<f32>())
                as gl::types::GLsizeiptr,
            VERTEX_DATA.as_ptr() as *const _,
            gl::STATIC_DRAW,
        );

        if gl.BindVertexArray.is_loaded() {
            let mut vao = std::mem::uninitialized();
            gl.GenVertexArrays(1, &mut vao);
            gl.BindVertexArray(vao);
        }

        let pos_attrib =
            gl.GetAttribLocation(program, b"position\0".as_ptr() as *const _);
        let color_attrib =
            gl.GetAttribLocation(program, b"color\0".as_ptr() as *const _);
        gl.VertexAttribPointer(
            pos_attrib as gl::types::GLuint,
            2,
            gl::FLOAT,
            0,
            5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
            std::ptr::null(),
        );
        gl.VertexAttribPointer(
            color_attrib as gl::types::GLuint,
            3,
            gl::FLOAT,
            0,
            5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
            (2 * std::mem::size_of::<f32>()) as *const () as *const _,
        );
        gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
        gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
    }

    Gl { gl: gl }
}

impl Gl {
    pub fn draw_frame(&self, color: [f32; 4]) {
        unsafe {
            self.gl.ClearColor(color[0], color[1], color[2], color[3]);
            self.gl.Clear(gl::COLOR_BUFFER_BIT);
            self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
        }
    }
}

#[rustfmt::skip]
static VERTEX_DATA: [f32; 15] = [
    -0.5, -0.5,  1.0,  0.0,  0.0,
     0.0,  0.5,  0.0,  1.0,  0.0,
     0.5, -0.5,  0.0,  0.0,  1.0,
];

const VS_SRC: &'static [u8] = b"
#version 100
precision mediump float;

attribute vec2 position;
attribute vec3 color;

varying vec3 v_color;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
    v_color = color;
}
\0";

const FS_SRC: &'static [u8] = b"
#version 100
precision mediump float;

varying vec3 v_color;

void main() {
    gl_FragColor = vec4(v_color, 1.0);
}
\0";

pub use self::context_tracker::{
    ContextCurrentWrapper, ContextId, ContextTracker, ContextWrapper,
};

#[allow(dead_code)] // Not used by all examples
mod context_tracker {
    use glutin::{
        self, Context, ContextCurrentState, ContextError, NotCurrent,
        PossiblyCurrent, WindowedContext,
    };
    use takeable_option::Takeable;

    pub enum ContextWrapper<T: ContextCurrentState> {
        Headless(Context<T>),
        Windowed(WindowedContext<T>),
    }

    impl<T: ContextCurrentState> ContextWrapper<T> {
        pub fn headless(&mut self) -> &mut Context<T> {
            match self {
                ContextWrapper::Headless(ref mut ctx) => ctx,
                _ => panic!(),
            }
        }

        pub fn windowed(&mut self) -> &mut WindowedContext<T> {
            match self {
                ContextWrapper::Windowed(ref mut ctx) => ctx,
                _ => panic!(),
            }
        }

        fn map<T2: ContextCurrentState, FH, FW>(
            self,
            fh: FH,
            fw: FW,
        ) -> Result<ContextWrapper<T2>, (Self, ContextError)>
        where
            FH: FnOnce(
                Context<T>,
            )
                -> Result<Context<T2>, (Context<T>, ContextError)>,
            FW: FnOnce(
                WindowedContext<T>,
            ) -> Result<
                WindowedContext<T2>,
                (WindowedContext<T>, ContextError),
            >,
        {
            match self {
                ContextWrapper::Headless(ctx) => match fh(ctx) {
                    Ok(ctx) => Ok(ContextWrapper::Headless(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextWrapper::Headless(ctx), err))
                    }
                },
                ContextWrapper::Windowed(ctx) => match fw(ctx) {
                    Ok(ctx) => Ok(ContextWrapper::Windowed(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextWrapper::Windowed(ctx), err))
                    }
                },
            }
        }
    }

    pub enum ContextCurrentWrapper {
        PossiblyCurrent(ContextWrapper<PossiblyCurrent>),
        NotCurrent(ContextWrapper<NotCurrent>),
    }

    impl ContextCurrentWrapper {
        fn map_possibly<F>(self, f: F) -> Result<Self, (Self, ContextError)>
        where
            F: FnOnce(
                ContextWrapper<PossiblyCurrent>,
            ) -> Result<
                ContextWrapper<NotCurrent>,
                (ContextWrapper<PossiblyCurrent>, ContextError),
            >,
        {
            match self {
                ret @ ContextCurrentWrapper::NotCurrent(_) => Ok(ret),
                ContextCurrentWrapper::PossiblyCurrent(ctx) => match f(ctx) {
                    Ok(ctx) => Ok(ContextCurrentWrapper::NotCurrent(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextCurrentWrapper::PossiblyCurrent(ctx), err))
                    }
                },
            }
        }

        fn map_not<F>(self, f: F) -> Result<Self, (Self, ContextError)>
        where
            F: FnOnce(
                ContextWrapper<NotCurrent>,
            ) -> Result<
                ContextWrapper<PossiblyCurrent>,
                (ContextWrapper<NotCurrent>, ContextError),
            >,
        {
            match self {
                ret @ ContextCurrentWrapper::PossiblyCurrent(_) => Ok(ret),
                ContextCurrentWrapper::NotCurrent(ctx) => match f(ctx) {
                    Ok(ctx) => Ok(ContextCurrentWrapper::PossiblyCurrent(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextCurrentWrapper::NotCurrent(ctx), err))
                    }
                },
            }
        }
    }

    pub type ContextId = usize;
    #[derive(Default)]
    pub struct ContextTracker {
        current: Option<ContextId>,
        others: Vec<(ContextId, Takeable<ContextCurrentWrapper>)>,
        next_id: ContextId,
    }

    impl ContextTracker {
        pub fn insert(&mut self, ctx: ContextCurrentWrapper) -> ContextId {
            let id = self.next_id;
            self.next_id += 1;

            if let ContextCurrentWrapper::PossiblyCurrent(_) = ctx {
                if let Some(old_current) = self.current {
                    unsafe {
                        self.modify(old_current, |ctx| {
                            ctx.map_possibly(|ctx| {
                                ctx.map(
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                )
                            })
                        })
                        .unwrap()
                    }
                }
                self.current = Some(id);
            }

            self.others.push((id, Takeable::new(ctx)));
            id
        }

        pub fn remove(&mut self, id: ContextId) -> ContextCurrentWrapper {
            if Some(id) == self.current {
                self.current.take();
            }

            let this_index = self
                .others
                .binary_search_by(|(sid, _)| sid.cmp(&id))
                .unwrap();
            Takeable::take(&mut self.others.remove(this_index).1)
        }

        fn modify<F>(&mut self, id: ContextId, f: F) -> Result<(), ContextError>
        where
            F: FnOnce(
                ContextCurrentWrapper,
            ) -> Result<
                ContextCurrentWrapper,
                (ContextCurrentWrapper, ContextError),
            >,
        {
            let this_index = self
                .others
                .binary_search_by(|(sid, _)| sid.cmp(&id))
                .unwrap();

            let this_context = Takeable::take(&mut self.others[this_index].1);

            match f(this_context) {
                Err((ctx, err)) => {
                    self.others[this_index].1 = Takeable::new(ctx);
                    Err(err)
                }
                Ok(ctx) => {
                    self.others[this_index].1 = Takeable::new(ctx);
                    Ok(())
                }
            }
        }

        pub fn get_current(
            &mut self,
            id: ContextId,
        ) -> Result<&mut ContextWrapper<PossiblyCurrent>, ContextError>
        {
            unsafe {
                let this_index = self
                    .others
                    .binary_search_by(|(sid, _)| sid.cmp(&id))
                    .unwrap();
                if Some(id) != self.current {
                    let old_current = self.current.take();

                    if let Err(err) = self.modify(id, |ctx| {
                        ctx.map_not(|ctx| {
                            ctx.map(
                                |ctx| ctx.make_current(),
                                |ctx| ctx.make_current(),
                            )
                        })
                    }) {
                        // Oh noes, something went wrong
                        // Let's at least make sure that no context is current.
                        if let Some(old_current) = old_current {
                            if let Err(err2) = self.modify(old_current, |ctx| {
                                ctx.map_possibly(|ctx| {
                                    ctx.map(
                                        |ctx| ctx.make_not_current(),
                                        |ctx| ctx.make_not_current(),
                                    )
                                })
                            }) {
                                panic!("Could not `make_current` nor `make_not_current`, {:?}, {:?}", err, err2);
                            }
                        }

                        if let Err(err2) = self.modify(id, |ctx| {
                            ctx.map_possibly(|ctx| {
                                ctx.map(
                                    |ctx| ctx.make_not_current(),
                                    |ctx| ctx.make_not_current(),
                                )
                            })
                        }) {
                            panic!("Could not `make_current` nor `make_not_current`, {:?}, {:?}", err, err2);
                        }

                        return Err(err);
                    }

                    self.current = Some(id);

                    if let Some(old_current) = old_current {
                        self.modify(old_current, |ctx| {
                            ctx.map_possibly(|ctx| {
                                ctx.map(
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                )
                            })
                        })
                        .unwrap();
                    }
                }

                match *self.others[this_index].1 {
                    ContextCurrentWrapper::PossiblyCurrent(ref mut ctx) => {
                        Ok(ctx)
                    }
                    ContextCurrentWrapper::NotCurrent(_) => panic!(),
                }
            }
        }
    }
}
<commit_msg>Fix examples on macos. (#1201)<commit_after>use glutin::{self, PossiblyCurrent};

use std::ffi::CStr;

pub mod gl {
    pub use self::Gles2 as Gl;
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

pub struct Gl {
    pub gl: gl::Gl,
}

pub fn load(gl_context: &glutin::Context<PossiblyCurrent>) -> Gl {
    let gl =
        gl::Gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _);

    let version = unsafe {
        let data = CStr::from_ptr(gl.GetString(gl::VERSION) as *const _)
            .to_bytes()
            .to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);

    unsafe {
        let vs = gl.CreateShader(gl::VERTEX_SHADER);
        gl.ShaderSource(
            vs,
            1,
            [VS_SRC.as_ptr() as *const _].as_ptr(),
            std::ptr::null(),
        );
        gl.CompileShader(vs);

        let fs = gl.CreateShader(gl::FRAGMENT_SHADER);
        gl.ShaderSource(
            fs,
            1,
            [FS_SRC.as_ptr() as *const _].as_ptr(),
            std::ptr::null(),
        );
        gl.CompileShader(fs);

        let program = gl.CreateProgram();
        gl.AttachShader(program, vs);
        gl.AttachShader(program, fs);
        gl.LinkProgram(program);
        gl.UseProgram(program);

        let mut vb = std::mem::uninitialized();
        gl.GenBuffers(1, &mut vb);
        gl.BindBuffer(gl::ARRAY_BUFFER, vb);
        gl.BufferData(
            gl::ARRAY_BUFFER,
            (VERTEX_DATA.len() * std::mem::size_of::<f32>())
                as gl::types::GLsizeiptr,
            VERTEX_DATA.as_ptr() as *const _,
            gl::STATIC_DRAW,
        );

        if gl.BindVertexArray.is_loaded() {
            let mut vao = std::mem::uninitialized();
            gl.GenVertexArrays(1, &mut vao);
            gl.BindVertexArray(vao);
        }

        let pos_attrib =
            gl.GetAttribLocation(program, b"position\0".as_ptr() as *const _);
        let color_attrib =
            gl.GetAttribLocation(program, b"color\0".as_ptr() as *const _);
        gl.VertexAttribPointer(
            pos_attrib as gl::types::GLuint,
            2,
            gl::FLOAT,
            0,
            5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
            std::ptr::null(),
        );
        gl.VertexAttribPointer(
            color_attrib as gl::types::GLuint,
            3,
            gl::FLOAT,
            0,
            5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
            (2 * std::mem::size_of::<f32>()) as *const () as *const _,
        );
        gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
        gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
    }

    Gl { gl: gl }
}

impl Gl {
    pub fn draw_frame(&self, color: [f32; 4]) {
        unsafe {
            self.gl.ClearColor(color[0], color[1], color[2], color[3]);
            self.gl.Clear(gl::COLOR_BUFFER_BIT);
            self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
        }
    }
}

#[rustfmt::skip]
static VERTEX_DATA: [f32; 15] = [
    -0.5, -0.5,  1.0,  0.0,  0.0,
     0.0,  0.5,  0.0,  1.0,  0.0,
     0.5, -0.5,  0.0,  0.0,  1.0,
];

const VS_SRC: &'static [u8] = b"
#version 100
precision mediump float;

attribute vec2 position;
attribute vec3 color;

varying vec3 v_color;

void main() {
    gl_Position = vec4(position, 0.0, 1.0);
    v_color = color;
}
\0";

const FS_SRC: &'static [u8] = b"
#version 100
precision mediump float;

varying vec3 v_color;

void main() {
    gl_FragColor = vec4(v_color, 1.0);
}
\0";

pub use self::context_tracker::{
    ContextCurrentWrapper, ContextId, ContextTracker, ContextWrapper,
};

#[allow(dead_code)] // Not used by all examples
mod context_tracker {
    use glutin::{
        self, Context, ContextCurrentState, ContextError, NotCurrent,
        PossiblyCurrent, WindowedContext,
    };
    use takeable_option::Takeable;

    pub enum ContextWrapper<T: ContextCurrentState> {
        Headless(Context<T>),
        Windowed(WindowedContext<T>),
    }

    impl<T: ContextCurrentState> ContextWrapper<T> {
        pub fn headless(&mut self) -> &mut Context<T> {
            match self {
                ContextWrapper::Headless(ref mut ctx) => ctx,
                _ => panic!(),
            }
        }

        pub fn windowed(&mut self) -> &mut WindowedContext<T> {
            match self {
                ContextWrapper::Windowed(ref mut ctx) => ctx,
                _ => panic!(),
            }
        }

        fn map<T2: ContextCurrentState, FH, FW>(
            self,
            fh: FH,
            fw: FW,
        ) -> Result<ContextWrapper<T2>, (Self, ContextError)>
        where
            FH: FnOnce(
                Context<T>,
            )
                -> Result<Context<T2>, (Context<T>, ContextError)>,
            FW: FnOnce(
                WindowedContext<T>,
            ) -> Result<
                WindowedContext<T2>,
                (WindowedContext<T>, ContextError),
            >,
        {
            match self {
                ContextWrapper::Headless(ctx) => match fh(ctx) {
                    Ok(ctx) => Ok(ContextWrapper::Headless(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextWrapper::Headless(ctx), err))
                    }
                },
                ContextWrapper::Windowed(ctx) => match fw(ctx) {
                    Ok(ctx) => Ok(ContextWrapper::Windowed(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextWrapper::Windowed(ctx), err))
                    }
                },
            }
        }
    }

    pub enum ContextCurrentWrapper {
        PossiblyCurrent(ContextWrapper<PossiblyCurrent>),
        NotCurrent(ContextWrapper<NotCurrent>),
    }

    impl ContextCurrentWrapper {
        fn map_possibly<F>(self, f: F) -> Result<Self, (Self, ContextError)>
        where
            F: FnOnce(
                ContextWrapper<PossiblyCurrent>,
            ) -> Result<
                ContextWrapper<NotCurrent>,
                (ContextWrapper<PossiblyCurrent>, ContextError),
            >,
        {
            match self {
                ret @ ContextCurrentWrapper::NotCurrent(_) => Ok(ret),
                ContextCurrentWrapper::PossiblyCurrent(ctx) => match f(ctx) {
                    Ok(ctx) => Ok(ContextCurrentWrapper::NotCurrent(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextCurrentWrapper::PossiblyCurrent(ctx), err))
                    }
                },
            }
        }

        fn map_not<F>(self, f: F) -> Result<Self, (Self, ContextError)>
        where
            F: FnOnce(
                ContextWrapper<NotCurrent>,
            ) -> Result<
                ContextWrapper<PossiblyCurrent>,
                (ContextWrapper<NotCurrent>, ContextError),
            >,
        {
            match self {
                ret @ ContextCurrentWrapper::PossiblyCurrent(_) => Ok(ret),
                ContextCurrentWrapper::NotCurrent(ctx) => match f(ctx) {
                    Ok(ctx) => Ok(ContextCurrentWrapper::PossiblyCurrent(ctx)),
                    Err((ctx, err)) => {
                        Err((ContextCurrentWrapper::NotCurrent(ctx), err))
                    }
                },
            }
        }
    }

    pub type ContextId = usize;
    #[derive(Default)]
    pub struct ContextTracker {
        current: Option<ContextId>,
        others: Vec<(ContextId, Takeable<ContextCurrentWrapper>)>,
        next_id: ContextId,
    }

    impl ContextTracker {
        pub fn insert(&mut self, ctx: ContextCurrentWrapper) -> ContextId {
            let id = self.next_id;
            self.next_id += 1;

            if let ContextCurrentWrapper::PossiblyCurrent(_) = ctx {
                if let Some(old_current) = self.current {
                    unsafe {
                        self.modify(old_current, |ctx| {
                            ctx.map_possibly(|ctx| {
                                ctx.map(
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                )
                            })
                        })
                        .unwrap()
                    }
                }
                self.current = Some(id);
            }

            self.others.push((id, Takeable::new(ctx)));
            id
        }

        pub fn remove(&mut self, id: ContextId) -> ContextCurrentWrapper {
            if Some(id) == self.current {
                self.current.take();
            }

            let this_index = self
                .others
                .binary_search_by(|(sid, _)| sid.cmp(&id))
                .unwrap();
            Takeable::take(&mut self.others.remove(this_index).1)
        }

        fn modify<F>(&mut self, id: ContextId, f: F) -> Result<(), ContextError>
        where
            F: FnOnce(
                ContextCurrentWrapper,
            ) -> Result<
                ContextCurrentWrapper,
                (ContextCurrentWrapper, ContextError),
            >,
        {
            let this_index = self
                .others
                .binary_search_by(|(sid, _)| sid.cmp(&id))
                .unwrap();

            let this_context = Takeable::take(&mut self.others[this_index].1);

            match f(this_context) {
                Err((ctx, err)) => {
                    self.others[this_index].1 = Takeable::new(ctx);
                    Err(err)
                }
                Ok(ctx) => {
                    self.others[this_index].1 = Takeable::new(ctx);
                    Ok(())
                }
            }
        }

        pub fn get_current(
            &mut self,
            id: ContextId,
        ) -> Result<&mut ContextWrapper<PossiblyCurrent>, ContextError>
        {
            unsafe {
                let this_index = self
                    .others
                    .binary_search_by(|(sid, _)| sid.cmp(&id))
                    .unwrap();
                if Some(id) != self.current {
                    let old_current = self.current.take();

                    if let Err(err) = self.modify(id, |ctx| {
                        ctx.map_not(|ctx| {
                            ctx.map(
                                |ctx| ctx.make_current(),
                                |ctx| ctx.make_current(),
                            )
                        })
                    }) {
                        // Oh noes, something went wrong
                        // Let's at least make sure that no context is current.
                        if let Some(old_current) = old_current {
                            if let Err(err2) = self.modify(old_current, |ctx| {
                                ctx.map_possibly(|ctx| {
                                    ctx.map(
                                        |ctx| ctx.make_not_current(),
                                        |ctx| ctx.make_not_current(),
                                    )
                                })
                            }) {
                                panic!("Could not `make_current` nor `make_not_current`, {:?}, {:?}", err, err2);
                            }
                        }

                        if let Err(err2) = self.modify(id, |ctx| {
                            ctx.map_possibly(|ctx| {
                                ctx.map(
                                    |ctx| ctx.make_not_current(),
                                    |ctx| ctx.make_not_current(),
                                )
                            })
                        }) {
                            panic!("Could not `make_current` nor `make_not_current`, {:?}, {:?}", err, err2);
                        }

                        return Err(err);
                    }

                    self.current = Some(id);

                    if let Some(old_current) = old_current {
                        self.modify(old_current, |ctx| {
                            ctx.map_possibly(|ctx| {
                                ctx.map(
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                    |ctx| Ok(ctx.treat_as_not_current()),
                                )
                            })
                        })
                        .unwrap();
                    }
                }

                match *self.others[this_index].1 {
                    ContextCurrentWrapper::PossiblyCurrent(ref mut ctx) => {
                        Ok(ctx)
                    }
                    ContextCurrentWrapper::NotCurrent(_) => panic!(),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate turtle;

use turtle::Turtle;

/// This program draws several parallel lines to demonstrate each of the
/// different possible movement speeds
fn main() {
    let mut turtle = Turtle::new();

    turtle.pen_up();
    turtle.set_speed("instant");
    turtle.left(90.0);
    turtle.forward(300.0);
    turtle.right(90.0);
    turtle.pen_down();

    let length = 200.0;

    for i in 1..12 {
        turtle.set_speed(i);
        turtle.forward(length);

        turtle.pen_up();
        turtle.set_speed("instant");
        turtle.backward(length);
        turtle.right(90.0);
        turtle.forward(60.0);
        turtle.left(90.0);
        turtle.pen_down();
    }

    turtle.hide();
}
<commit_msg>Updating speedtest to use all the speed values<commit_after>extern crate turtle;

use turtle::Turtle;

/// This program draws several parallel lines to demonstrate each of the
/// different possible movement speeds
fn main() {
    let mut turtle = Turtle::new();

    turtle.pen_up();
    turtle.set_speed("instant");
    turtle.left(90.0);
    turtle.forward(350.0);
    turtle.right(90.0);
    turtle.pen_down();

    let length = 200.0;

    for i in 1..25 {
        turtle.set_speed(i);
        turtle.forward(length);

        turtle.pen_up();
        turtle.set_speed("instant");
        turtle.backward(length);
        turtle.right(90.0);
        turtle.forward(30.0);
        turtle.left(90.0);
        turtle.pen_down();
    }

    turtle.hide();
}
<|endoftext|>


<commit_before>use std::sync::{Mutex, Arc};
use std::result::Result;
use std::error::Error;

use serde_json::*;
use gossyp_base::*;
use gossyp_base::basic::*;

use super::binding_environment::*;
use super::script_interpreter::*;
use super::bind_statement::*;
use super::evaluate_statement::*;
use super::script::*;
use super::bound_script::*;

///
/// Represents a tool that can be used to evaluate scripts and maintains
/// state (useful for evaluation in a REPL environment)
///
#[derive(Clone)]
pub struct StatefulEvalTool {
    binding:    Arc<Mutex<Box<VariableBindingEnvironment>>>,
    execution:  Arc<Mutex<ScriptExecutionEnvironment>>
}

impl StatefulEvalTool {
    pub fn new() -> StatefulEvalTool {
        StatefulEvalTool {
            binding: Arc::new(Mutex::new(BindingEnvironment::new())),
            execution: Arc::new(Mutex::new(ScriptExecutionEnvironment::new()))
        }
    }

    ///
    /// Evaluates an unbound statement using this tool
    ///
    pub fn evaluate_unbound_statement(&self, script: &Script, environment: &Environment) -> Result<Value, Value> {
        self.evaluate_statement(&self.bind_statement(script, environment)?, environment)
    }

    ///
    /// Binds a statement to this tool
    ///
    pub fn bind_statement(&self, script: &Script, environment: &Environment) -> Result<BoundScript, Value> {
        // Merge the stuff in the external environment with the stored environment
        let our_environment             = &mut **self.binding.lock().unwrap();
        let their_environment           = BindingEnvironment::from_environment(environment);
        let mut combined_environment    = BindingEnvironment::combine(our_environment, &*their_environment);

        // Bind to the combined environments
        bind_statement(script, &mut *combined_environment)
    }

    ///
    /// Evaluates a statement in the environment represented by this tool
    ///
    pub fn evaluate_statement(&self, script: &BoundScript, environment: &Environment) -> Result<Value, Value> {
        evaluate_statement(script, environment, &mut *self.execution.lock().unwrap())
    }
}

impl Tool for StatefulEvalTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let script = from_value::<Script>(input);

        match script {
            Ok(script)          => self.evaluate_unbound_statement(&script, environment),
            Err(script_error)   => Err(json![{
                "error":        "JSON input decode failed",
                "description":  script_error.description(),
            }])
        }
    }
}

///
/// Tool function that creates an eval state in an environment
///
pub fn create_evaluator_with_state_tool(eval_name: String, environment: &Environment) -> Result<(), Value> {
    // Fetch the tool defining tool
    let define_tool = environment.get_json_tool(tool_name::DEFINE_TOOL)
        .map(|tool| TypedTool::<DefineToolInput, ()>::from(tool))
        .map_err(|retrieve_error| json![{
            "error":        "Cannot define tool",
            "description":  retrieve_error.message()
        }])?;

    // Define an environment containing the stateful tool
    let stateful_env = StaticEnvironment::from_tool("new-evaluator", StatefulEvalTool::new(), &EmptyEnvironment::new());

    // Copy the stateful eval tool to the new environment
    define_tool.invoke(DefineToolInput::new("new-evaluator", Some(&eval_name)), &stateful_env)?;

    Ok(())
}

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

    #[test]
    fn can_bind_variable_using_stateful_tool() {
        let eval    = StatefulEvalTool::new();
        let env     = EmptyEnvironment::new();

        // var x = 1
        let assign_x = eval.evaluate_unbound_statement(&Script::Var(ScriptToken::identifier("x"), Expression::Number(ScriptToken::number("1"))), &env);
        assert!(assign_x.is_ok());

        // x
        let val_of_x = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("x"))), &env);
        assert!(val_of_x == Ok(json![ 1 ]));
    }

    #[test]
    fn can_bind_tool_from_passed_in_environment() {
        let eval    = StatefulEvalTool::new();
        let env     = DynamicEnvironment::new();

        env.define("test-tool", Box::new(make_pure_tool(|_: ()| 42)));

        // test-tool
        let val_of_test_tool = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("test-tool"))), &env);
        assert!(val_of_test_tool == Ok(json![ 42 ]));
    }
}
<commit_msg>Need a sequence of statements to pass to the eval tool<commit_after>use std::sync::{Mutex, Arc};
use std::result::Result;
use std::error::Error;

use serde_json::*;
use gossyp_base::*;
use gossyp_base::basic::*;

use super::binding_environment::*;
use super::script_interpreter::*;
use super::bind_statement::*;
use super::evaluate_statement::*;
use super::script::*;
use super::bound_script::*;

///
/// Represents a tool that can be used to evaluate scripts and maintains
/// state (useful for evaluation in a REPL environment)
///
#[derive(Clone)]
pub struct StatefulEvalTool {
    binding:    Arc<Mutex<Box<VariableBindingEnvironment>>>,
    execution:  Arc<Mutex<ScriptExecutionEnvironment>>
}

impl StatefulEvalTool {
    pub fn new() -> StatefulEvalTool {
        StatefulEvalTool {
            binding: Arc::new(Mutex::new(BindingEnvironment::new())),
            execution: Arc::new(Mutex::new(ScriptExecutionEnvironment::new()))
        }
    }

    ///
    /// Evaluates an unbound statement using this tool
    ///
    pub fn evaluate_unbound_statement(&self, script: &Script, environment: &Environment) -> Result<Value, Value> {
        self.evaluate_statement(&self.bind_statement(script, environment)?, environment)
    }

    ///
    /// Binds a statement to this tool
    ///
    pub fn bind_statement(&self, script: &Script, environment: &Environment) -> Result<BoundScript, Value> {
        // Merge the stuff in the external environment with the stored environment
        let our_environment             = &mut **self.binding.lock().unwrap();
        let their_environment           = BindingEnvironment::from_environment(environment);
        let mut combined_environment    = BindingEnvironment::combine(our_environment, &*their_environment);

        // Bind to the combined environments
        bind_statement(script, &mut *combined_environment)
    }

    ///
    /// Evaluates a statement in the environment represented by this tool
    ///
    pub fn evaluate_statement(&self, script: &BoundScript, environment: &Environment) -> Result<Value, Value> {
        evaluate_statement(script, environment, &mut *self.execution.lock().unwrap())
    }
}

impl Tool for StatefulEvalTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let script = from_value::<Vec<Script>>(input)
            .map(|statements| Script::Sequence(statements));

        match script {
            Ok(script)          => self.evaluate_unbound_statement(&script, environment),
            Err(script_error)   => Err(json![{
                "error":        "JSON input decode failed",
                "description":  script_error.description(),
            }])
        }
    }
}

///
/// Tool function that creates an eval state in an environment
///
pub fn create_evaluator_with_state_tool(eval_name: String, environment: &Environment) -> Result<(), Value> {
    // Fetch the tool defining tool
    let define_tool = environment.get_json_tool(tool_name::DEFINE_TOOL)
        .map(|tool| TypedTool::<DefineToolInput, ()>::from(tool))
        .map_err(|retrieve_error| json![{
            "error":        "Cannot define tool",
            "description":  retrieve_error.message()
        }])?;

    // Define an environment containing the stateful tool
    let stateful_env = StaticEnvironment::from_tool("new-evaluator", StatefulEvalTool::new(), &EmptyEnvironment::new());

    // Copy the stateful eval tool to the new environment
    define_tool.invoke(DefineToolInput::new("new-evaluator", Some(&eval_name)), &stateful_env)?;

    Ok(())
}

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

    #[test]
    fn can_bind_variable_using_stateful_tool() {
        let eval    = StatefulEvalTool::new();
        let env     = EmptyEnvironment::new();

        // var x = 1
        let assign_x = eval.evaluate_unbound_statement(&Script::Var(ScriptToken::identifier("x"), Expression::Number(ScriptToken::number("1"))), &env);
        assert!(assign_x.is_ok());

        // x
        let val_of_x = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("x"))), &env);
        assert!(val_of_x == Ok(json![ 1 ]));
    }

    #[test]
    fn can_bind_tool_from_passed_in_environment() {
        let eval    = StatefulEvalTool::new();
        let env     = DynamicEnvironment::new();

        env.define("test-tool", Box::new(make_pure_tool(|_: ()| 42)));

        // test-tool
        let val_of_test_tool = eval.evaluate_unbound_statement(&Script::RunCommand(Expression::Identifier(ScriptToken::identifier("test-tool"))), &env);
        assert!(val_of_test_tool == Ok(json![ 42 ]));
    }
}
<|endoftext|>


<commit_before>use std::process::Command;

use datatype::{Error, Package, UpdateResultCode};
use package_manager::dpkg::parse_package; // XXX: Move somewhere better?

pub fn installed_packages() -> Result<Vec<Package>, Error> {
    Command::new("rpm").arg("-qa").arg("--queryformat").arg("%{NAME} %{SIZE}\n")
        .output()
        .map_err(|e| Error::PackageError(format!("Error fetching packages: {}", e)))
        .and_then(|c| {
            String::from_utf8(c.stdout)
                .map_err(|e| Error::ParseError(format!("Error parsing package: {}", e)))
                .map(|s| s.lines().map(|n| String::from(n)).collect::<Vec<String>>())
        })
        .and_then(|lines| {
            lines.iter()
                .map(|line| parse_package(line))
                .collect::<Result<Vec<Package>, _>>()
        })
}

pub fn install_package(path: &str) -> Result<(UpdateResultCode, String), (UpdateResultCode, String)> {
    let output = try!(Command::new("rpm").arg("-ivh").arg(path)
                      .output()
                      .map_err(|e| {
                          (UpdateResultCode::GENERAL_ERROR, format!("{:?}", e))
                      }));

    let stdout = String::from_utf8_lossy(&output.stdout).into_owned();

    match output.status.code() {
        Some(0) => Ok((UpdateResultCode::OK, stdout)),
        _ => if (&stdout).contains("already installed") {
            Ok((UpdateResultCode::ALREADY_PROCESSED, stdout))
        } else {
            Err((UpdateResultCode::INSTALL_FAILED, stdout))
        }
    }
}
<commit_msg>Fix empty rpm error result_text<commit_after>use std::process::Command;

use datatype::{Error, Package, UpdateResultCode};
use package_manager::dpkg::parse_package; // XXX: Move somewhere better?

pub fn installed_packages() -> Result<Vec<Package>, Error> {
    Command::new("rpm").arg("-qa").arg("--queryformat").arg("%{NAME} %{SIZE}\n")
        .output()
        .map_err(|e| Error::PackageError(format!("Error fetching packages: {}", e)))
        .and_then(|c| {
            String::from_utf8(c.stdout)
                .map_err(|e| Error::ParseError(format!("Error parsing package: {}", e)))
                .map(|s| s.lines().map(|n| String::from(n)).collect::<Vec<String>>())
        })
        .and_then(|lines| {
            lines.iter()
                .map(|line| parse_package(line))
                .collect::<Result<Vec<Package>, _>>()
        })
}

pub fn install_package(path: &str) -> Result<(UpdateResultCode, String), (UpdateResultCode, String)> {
    let output = try!(Command::new("rpm").arg("-ivh").arg(path)
                      .output()
                      .map_err(|e| {
                          (UpdateResultCode::GENERAL_ERROR, format!("{:?}", e))
                      }));

    let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
    let stderr = String::from_utf8_lossy(&output.stderr).into_owned();

    match output.status.code() {
        Some(0) => Ok((UpdateResultCode::OK, stdout)),
        _ => if (&stderr).contains("already installed") {
            Ok((UpdateResultCode::ALREADY_PROCESSED, stderr))
        } else {
            Err((UpdateResultCode::INSTALL_FAILED, stderr))
        }
    }
}
<|endoftext|>


<commit_before>//! # A strongly restrictive color type.

use std::fmt;

/// It is guaranteed that `T` can be and will always be only either `u8` or `f32`.
/// It can also be guaranteed that `Display` is not and will never be implemented
/// for `Color<f32>`.
/// It can also be guaranteed that arithmetics are not and will never be implemented
/// for `Color<u8>`.
///
/// ```rust,ignore
/// assert_fail_to_compile!(Color(0.0, 0.0, 0.0).to_string());
/// assert_fail_to_compile!(println!("{}", Color(0.0, 0.0, 0.0)));
/// assert_fail_to_compile!(Color(0, 0, 0) + Color(1, 1, 1));
/// ```
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Color<T>(pub T, pub T, pub T);

/// `Color888` can only do IO (convert to and from strings), and some simple equality tests.
pub type Color888 = Color<u8>;
/// `Colorf32` can only do arithmetics and convert to/from `Color888`.
pub type Colorf32 = Color<f32>;

impl fmt::Display for Color888 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Color(r, g, b) = *self;
        write!(f, "{:02x}{:02x}{:02x}", r, g, b)
    }
}

impl Eq for Color888 {}

impl From<Color888> for Colorf32 {
    fn from(color: Color888) -> Self {
        let Color(r, g, b) = color;
        let r = r as f32 / 255_f32;
        let g = g as f32 / 255_f32;
        let b = b as f32 / 255_f32;
        Color(r, g, b)
    }
}

impl Colorf32 {
    pub fn clamp_to_888(self) -> Color888 {
        let Color(r, g, b) = self.clamp();
        let r = (r * 255_f32).min(255_f32) as u8;
        let g = (g * 255_f32).min(255_f32) as u8;
        let b = (b * 255_f32).min(255_f32) as u8;
        Color(r, g, b)
    }

    pub fn clamp_with(self, min: f32, max: f32) -> Self {
        let Color(r, g, b) = self;
        let r = r.max(min).min(max);
        let g = g.max(min).min(max);
        let b = b.max(min).min(max);
        Color(r, g, b)
    }

    pub fn clamp(self) -> Self {
        self.clamp_with(0_f32, 1_f32)
    }
}

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

    #[test]
    fn lossless_conversion() {
        for i in 0..256 {
            let a = i as u8;
            let color = Color(a, a, a);
            let color2 = Colorf32::from(color).clamp_to_888();
            assert_eq!(color, color2);
        }
    }

    #[test]
    fn clampped_down_conversion() {
        let max = Color(255, 255, 255);
        for i in 256..512 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, max);
        }
    }

    #[test]
    fn clampped_up_conversion() {
        let min = Color(0, 0, 0);
        for i in -256..0 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, min);
        }
    }

    #[test]
    fn display_color888() {
        assert_eq!(Color(0, 0, 0).to_string(), "000000");
        assert_eq!(Color(255, 255, 255).to_string(), "ffffff");
        assert_eq!(Color(1, 254, 10).to_string(), "01fe0a");
    }
}

<commit_msg>clean up: clearer doc; sRGB and Linear RGB conversion.<commit_after>//! # A strongly restrictive color type.
use std::fmt;
use palette::pixel::Srgb;
use palette::Rgb;

/// It is guaranteed that `T` can be and will always be only either `u8` or `f32`.
/// It can also be guaranteed that `Display` is not and will never be implemented
/// for `Color<f32>`.
/// It can also be guaranteed that arithmetics are not and will never be implemented
/// for `Color<u8>`.
///
/// ```rust,ignore
/// assert_fail_to_compile!(Color(0.0, 0.0, 0.0).to_string());
/// assert_fail_to_compile!(println!("{}", Color(0.0, 0.0, 0.0)));
/// assert_fail_to_compile!(Color(0, 0, 0) + Color(1, 1, 1));
/// ```
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Color<T>(pub T, pub T, pub T);

/// `Color888` can only do IO (convert to and from strings), and some simple equality tests.
/// Color is sRGB encoded.
pub type Color888 = Color<u8>;
/// `Colorf32` can only do arithmetics and convert to/from `Color888`.
/// Color is Linear RGB encoded.
pub type Colorf32 = Color<f32>;

impl fmt::Display for Color888 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Color(r, g, b) = *self;
        write!(f, "{:02x}{:02x}{:02x}", r, g, b)
    }
}

impl Eq for Color888 {}

impl From<Color888> for Colorf32 {
    /// Convert `Color888` (sRGB) to `Colorf32` (Linear RGB).
    fn from(color: Color888) -> Self {
        let Color(r, g, b) = color;
        let rgb: Rgb<f32> = Srgb::new_u8(r, g, b).into();
        let Rgb { red: r, green: g, blue: b } = rgb;
        Color(r, g, b)
    }
}

impl Colorf32 {
    /// Convert `Colorf32` (Linear RGB) to `Color888` (sRGB).
    pub fn clamp_to_888(self) -> Color888 {
        /// This is used to "reduce" conversion error, so that
        /// `lossless_conversion` test can pass.
        const DELTA: f32 = 1e-6;

        let Color(r, g, b) = self;
        let srgb: Srgb = Rgb::new(r + DELTA, g + DELTA, b + DELTA).into();
        let Srgb { red: r, green: g, blue: b, .. } = srgb;
        let Color(r, g, b) = Color(r * 255.0, g * 255.0, b * 255.0).clamp_with(0.0, 255.0);
        Color(r as u8, g as u8, b as u8)
    }

    /// Clamp to [`min`, `max`].
    pub fn clamp_with(self, min: f32, max: f32) -> Self {
        let Color(r, g, b) = self;
        let r = r.max(min).min(max);
        let g = g.max(min).min(max);
        let b = b.max(min).min(max);
        Color(r, g, b)
    }

    /// Clamp to [0, 1].
    pub fn clamp(self) -> Self {
        self.clamp_with(0.0, 1.0)
    }
}

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

    /// When this test fails, you may want to increase the `DELTA` constant
    /// in `Colorf32::clamp_to_888()`.
    #[test]
    fn lossless_conversion() {
        for i in 0..256 {
            let a = i as u8;
            let color = Color(a, a, a);
            let color2 = Colorf32::from(color).clamp_to_888();
            assert_eq!(color, color2);
        }
    }

    #[test]
    fn clampped_down_conversion() {
        let max = Color(255, 255, 255);
        for i in 256..512 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, max);
        }
    }

    #[test]
    fn clampped_up_conversion() {
        let min = Color(0, 0, 0);
        for i in -256..0 {
            let a = i as f32 / 255_f32;
            let color = Color(a, a, a).clamp_to_888();
            assert_eq!(color, min);
        }
    }

    #[test]
    fn display_color888() {
        assert_eq!(Color(0, 0, 0).to_string(), "000000");
        assert_eq!(Color(255, 255, 255).to_string(), "ffffff");
        assert_eq!(Color(1, 254, 10).to_string(), "01fe0a");
    }
}

<|endoftext|>


<commit_before>extern crate glib;

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

extern crate cairo;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, WaveformBuffer};

pub struct AudioController {
    container: gtk::Container,
    drawingarea: gtk::DrawingArea,

    position: u64,
    waveform_buffer_mtx: Arc<Mutex<Option<WaveformBuffer>>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            position: 0,
            waveform_buffer_mtx: Arc::new(Mutex::new(None)),
        }));

        {
            let this_ref = this.borrow();
            let this_weak = Rc::downgrade(&this);
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                match this_weak.upgrade() {
                    Some(this_ref) => {
                        this_ref.borrow_mut()
                            .draw(drawing_area, cairo_ctx).into()
                    },
                    None => Inhibit(false),
                }
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        // force redraw to purge the double buffer
        self.drawingarea.queue_draw();
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context.info.lock()
                .expect("Failed to lock media info while initializing audio controller")
                .audio_best
                .is_some();

        if has_audio {
            self.position = 0;
            self.waveform_buffer_mtx = context.waveform_buffer_mtx.clone();

            self.container.show();
        }
        else {
            self.container.hide();
        }
    }

    pub fn tic(&mut self, position: u64) {
        self.position = position;
        self.drawingarea.queue_draw();
    }

    fn draw(&mut self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if self.position == 0 {
            return Inhibit(false);
        }

        let allocation = drawing_area.get_allocation();
        let width = allocation.width;
        if width.is_negative() {
            return Inhibit(false);
        }

        let requested_duration = 2_000_000_000u64; // 2s TODO: adapt according to zoom

        // TODO: make width and height adapt to zoom
        let width = width as u64;
        cr.scale((width / 2) as f64, (allocation.height / 2) as f64);

        cr.set_line_width(0.0015f64);
        cr.set_source_rgb(0.8f64, 0.8f64, 0.8f64);

        // resolution
        let requested_step_duration =
            if requested_duration > width {
                requested_duration / width
            } else {
                1
            };

        let first_visible_pts = {
            let mut waveform_buffer_opt = self.waveform_buffer_mtx.lock()
                .expect("Couldn't lock waveform buffer in audio controller draw");
            let waveform_buffer =
                match waveform_buffer_opt.as_mut() {
                    Some(waveform_buffer) => waveform_buffer,
                    None => return Inhibit(false),
                };

            waveform_buffer.update_conditions(
                self.position,
                requested_duration,
                requested_step_duration
            );

            if waveform_buffer.samples.is_empty() {
                return Inhibit(false);
            }

            let mut relative_pts = 0f64;
            let step_duration = waveform_buffer.step_duration / 1_000_000_000f64;

            let mut sample_iter = waveform_buffer.iter();
            cr.move_to(relative_pts, *sample_iter.next().unwrap());

            for sample in sample_iter {
                relative_pts += step_duration;
                cr.line_to(relative_pts, *sample);
            }

            waveform_buffer.first_visible_pts
        };

        cr.stroke();

        // draw current pos
        let x = (self.position as f64 - first_visible_pts) / 1_000_000_000f64;
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(0.004f64);
        cr.move_to(x, 0f64);
        cr.line_to(x, 2f64);
        cr.stroke();

        Inhibit(false)
    }
}
<commit_msg>AudioController draw, avoid Weak ref. to this (#25) Reduce checks by using an Rc instead of a Weak in the draw signal<commit_after>extern crate glib;

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

extern crate cairo;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, WaveformBuffer};

pub struct AudioController {
    container: gtk::Container,
    drawingarea: gtk::DrawingArea,

    position: u64,
    waveform_buffer_mtx: Arc<Mutex<Option<WaveformBuffer>>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            position: 0,
            waveform_buffer_mtx: Arc::new(Mutex::new(None)),
        }));

        {
            let this_ref = this.borrow();
            let this_rc = this.clone();
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                this_rc.borrow()
                    .draw(drawing_area, cairo_ctx).into()
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        // force redraw to purge the double buffer
        self.drawingarea.queue_draw();
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context.info.lock()
                .expect("Failed to lock media info while initializing audio controller")
                .audio_best
                .is_some();

        if has_audio {
            self.position = 0;
            self.waveform_buffer_mtx = context.waveform_buffer_mtx.clone();

            self.container.show();
        }
        else {
            self.container.hide();
        }
    }

    pub fn tic(&mut self, position: u64) {
        self.position = position;
        self.drawingarea.queue_draw();
    }

    fn draw(&self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if self.position == 0 {
            return Inhibit(false);
        }

        let allocation = drawing_area.get_allocation();
        let width = allocation.width;
        if width.is_negative() {
            return Inhibit(false);
        }

        let requested_duration = 2_000_000_000u64; // 2s TODO: adapt according to zoom

        // TODO: make width and height adapt to zoom
        let width = width as u64;
        cr.scale((width / 2) as f64, (allocation.height / 2) as f64);

        cr.set_line_width(0.0015f64);
        cr.set_source_rgb(0.8f64, 0.8f64, 0.8f64);

        // resolution
        let requested_step_duration =
            if requested_duration > width {
                requested_duration / width
            } else {
                1
            };

        let first_visible_pts = {
            let mut waveform_buffer_opt = self.waveform_buffer_mtx.lock()
                .expect("Couldn't lock waveform buffer in audio controller draw");
            let waveform_buffer =
                match waveform_buffer_opt.as_mut() {
                    Some(waveform_buffer) => waveform_buffer,
                    None => return Inhibit(false),
                };

            waveform_buffer.update_conditions(
                self.position,
                requested_duration,
                requested_step_duration
            );

            if waveform_buffer.samples.is_empty() {
                return Inhibit(false);
            }

            let mut relative_pts = 0f64;
            let step_duration = waveform_buffer.step_duration / 1_000_000_000f64;

            let mut sample_iter = waveform_buffer.iter();
            cr.move_to(relative_pts, *sample_iter.next().unwrap());

            for sample in sample_iter {
                relative_pts += step_duration;
                cr.line_to(relative_pts, *sample);
            }

            waveform_buffer.first_visible_pts
        };

        cr.stroke();

        // draw current pos
        let x = (self.position as f64 - first_visible_pts) / 1_000_000_000f64;
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(0.004f64);
        cr.move_to(x, 0f64);
        cr.line_to(x, 2f64);
        cr.stroke();

        Inhibit(false)
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;
use core::marker::PhantomData;

// use progress::Graph;
use progress::nested::subgraph::Source::ScopeOutput;
use progress::nested::subgraph::Target::ScopeInput;

use communication::*;
use progress::count_map::CountMap;
use progress::notificator::Notificator;
use progress::{Timestamp, Scope, Antichain};
use communication::channels::{OutputPort, ObserverHelper};

use example_static::stream::ActiveStream;
use example_static::builder::*;

pub struct PullableHelper<T:Eq+Clone, D, P: Pullable<(T, Vec<D>)>> {
    receiver:   P,
    consumed:   CountMap<T>,
    phantom:    PhantomData<D>,
}

impl<T:Eq+Clone, D, P: Pullable<(T, Vec<D>)>> Pullable<(T, Vec<D>)> for PullableHelper<T, D, P> {
    fn pull(&mut self) -> Option<(T, Vec<D>)> {
        if let Some((time, data)) = self.receiver.pull() {
            if data.len() > 0 {
                self.consumed.update(&time, data.len() as i64);
                Some((time, data))
            }
            else { None }
        }
        else { None }
    }
}

impl<T:Eq+Clone, D, P: Pullable<(T, Vec<D>)>> Iterator for PullableHelper<T, D, P> {
    type Item = (T, Vec<D>);
    fn next(&mut self) -> Option<(T, Vec<D>)> { self.pull() }
}

impl<T:Timestamp, D:Data, P: Pullable<(T, Vec<D>)>> PullableHelper<T, D, P> {
    pub fn new(input: P) -> PullableHelper<T, D, P> {
        PullableHelper {
            receiver: input,
            consumed: CountMap::new(),
            phantom:  PhantomData
        }
    }
    pub fn pull_progress(&mut self, consumed: &mut CountMap<T>) {
        while let Some((ref time, value)) = self.consumed.pop() {
            consumed.update(time, value);
        }
    }
}

pub trait UnaryNotifyExt<G: GraphBuilder, D1: Data> {
    fn unary_notify<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (self, pact: P, name: String, init: Vec<G::Timestamp>, logic: L) -> ActiveStream<G, D2>;
}

impl<G: GraphBuilder, D1: Data> UnaryNotifyExt<G, D1> for ActiveStream<G, D1> {
    fn unary_notify<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (mut self, pact: P, name: String, init: Vec<G::Timestamp>, logic: L) -> ActiveStream<G, D2> {
        let (sender, receiver) = pact.connect(self.builder.communicator());
        let targets = OutputPort::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets.clone(), name, logic, init, true);
        let index = self.builder.add_scope(scope);
        self.connect_to(ScopeInput(index, 0), sender);
        self.transfer_borrow_to(ScopeOutput(index, 0), targets)
    }
}

pub trait UnaryExt<G: GraphBuilder, D1: Data> {
    fn unary<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (self, pact: P, name: String, logic: L) -> ActiveStream<G, D2>;
}

impl<G: GraphBuilder, D1: Data> UnaryExt<G, D1> for ActiveStream<G, D1> {
    fn unary<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (mut self, pact: P, name: String, logic: L) -> ActiveStream<G, D2> {
        let (sender, receiver) = pact.connect(self.builder.communicator());
        let targets = OutputPort::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets.clone(), name, logic, vec![], false);
        let index = self.builder.add_scope(scope);
        self.connect_to(ScopeInput(index, 0), sender);
        self.transfer_borrow_to(ScopeOutput(index, 0), targets)
    }
}

pub struct UnaryScopeHandle<T: Timestamp, D1: Data, D2: Data, P: Pullable<(T, Vec<D1>)>> {
    pub input:          PullableHelper<T, D1, P>,
    pub output:         ObserverHelper<OutputPort<T, D2>>,
    pub notificator:    Notificator<T>,
}

pub struct UnaryScope<T: Timestamp, D1: Data, D2: Data, P: Pullable<(T, Vec<D1>)>, L: FnMut(&mut UnaryScopeHandle<T, D1, D2, P>)> {
    name:           String,
    handle:         UnaryScopeHandle<T, D1, D2, P>,
    logic:          L,
    initial:        Vec<T>,  // initial notifications
    notify:         bool,
}

impl<T: Timestamp, D1: Data, D2: Data, P: Pullable<(T, Vec<D1>)>, L: FnMut(&mut UnaryScopeHandle<T, D1, D2, P>)> UnaryScope<T, D1, D2, P, L> {
    pub fn new(receiver: P, targets: OutputPort<T, D2>, name: String, logic: L, init: Vec<T>, notify: bool) -> UnaryScope<T, D1, D2, P, L> {
        UnaryScope {
            name:    name,
            handle:  UnaryScopeHandle {
                input:       PullableHelper::new(receiver),
                output:      ObserverHelper::new(targets, Rc::new(RefCell::new(CountMap::new()))),
                notificator: Default::default(),
            },
            logic:   logic,
            initial: init,
            notify:  notify,
        }
    }
}

impl<T, D1, D2, P, L> Scope<T> for UnaryScope<T, D1, D2, P, L>
where T: Timestamp,
      D1: Data, D2: Data,
      P: Pullable<(T, Vec<D1>)>,
      L: FnMut(&mut UnaryScopeHandle<T, D1, D2, P>) {
    fn inputs(&self) -> u64 { 1 }
    fn outputs(&self) -> u64 { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        let mut internal = vec![CountMap::new()];

        // TODO : this 256 number... it should really be communicator.peers().
        for time in self.initial.drain() { for _ in (0..256) { self.handle.notificator.notify_at(&time); } }
        self.handle.notificator.pull_progress(&mut internal[0]);

        (vec![vec![Antichain::from_elem(Default::default())]], internal)
    }

    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>, frontier: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(frontier);
    }

    fn push_external_progress(&mut self, external: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(external);
    }

    fn pull_internal_progress(&mut self, internal: &mut [CountMap<T>],
                                         consumed: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        (self.logic)(&mut self.handle);

        // extract what we know about progress from the input and output adapters.
        self.handle.input.pull_progress(&mut consumed[0]);
        self.handle.output.pull_progress(&mut produced[0]);
        self.handle.notificator.pull_progress(&mut internal[0]);

        return false;   // no unannounced internal work
    }

    fn name(&self) -> String { format!("{}", self.name) }
    fn notify_me(&self) -> bool { self.notify }
}
<commit_msg>fixed unary initialization to use comm.peers()<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;
use core::marker::PhantomData;

use progress::nested::subgraph::Source::ScopeOutput;
use progress::nested::subgraph::Target::ScopeInput;

use communication::*;
use progress::count_map::CountMap;
use progress::notificator::Notificator;
use progress::{Timestamp, Scope, Antichain};
use communication::channels::{OutputPort, ObserverHelper};

use example_static::stream::ActiveStream;
use example_static::builder::*;

pub struct PullableHelper<T:Eq+Clone, D, P: Pullable<(T, Vec<D>)>> {
    receiver:   P,
    consumed:   CountMap<T>,
    phantom:    PhantomData<D>,
}

impl<T:Eq+Clone, D, P: Pullable<(T, Vec<D>)>> Pullable<(T, Vec<D>)> for PullableHelper<T, D, P> {
    fn pull(&mut self) -> Option<(T, Vec<D>)> {
        if let Some((time, data)) = self.receiver.pull() {
            if data.len() > 0 {
                self.consumed.update(&time, data.len() as i64);
                Some((time, data))
            }
            else { None }
        }
        else { None }
    }
}

impl<T:Eq+Clone, D, P: Pullable<(T, Vec<D>)>> Iterator for PullableHelper<T, D, P> {
    type Item = (T, Vec<D>);
    fn next(&mut self) -> Option<(T, Vec<D>)> { self.pull() }
}

impl<T:Timestamp, D:Data, P: Pullable<(T, Vec<D>)>> PullableHelper<T, D, P> {
    pub fn new(input: P) -> PullableHelper<T, D, P> {
        PullableHelper {
            receiver: input,
            consumed: CountMap::new(),
            phantom:  PhantomData
        }
    }
    pub fn pull_progress(&mut self, consumed: &mut CountMap<T>) {
        while let Some((ref time, value)) = self.consumed.pop() {
            consumed.update(time, value);
        }
    }
}

pub trait UnaryNotifyExt<G: GraphBuilder, D1: Data> {
    fn unary_notify<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (self, pact: P, name: String, init: Vec<G::Timestamp>, logic: L) -> ActiveStream<G, D2>;
}

impl<G: GraphBuilder, D1: Data> UnaryNotifyExt<G, D1> for ActiveStream<G, D1> {
    fn unary_notify<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (mut self, pact: P, name: String, init: Vec<G::Timestamp>, logic: L) -> ActiveStream<G, D2> {
        let (sender, receiver) = pact.connect(self.builder.communicator());
        let targets = OutputPort::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets.clone(), name, logic, init, true, self.builder.communicator().peers());
        let index = self.builder.add_scope(scope);
        self.connect_to(ScopeInput(index, 0), sender);
        self.transfer_borrow_to(ScopeOutput(index, 0), targets)
    }
}

pub trait UnaryExt<G: GraphBuilder, D1: Data> {
    fn unary<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
            (self, pact: P, name: String, logic: L) -> ActiveStream<G, D2>;
}

impl<G: GraphBuilder, D1: Data> UnaryExt<G, D1> for ActiveStream<G, D1> {
    fn unary<D2: Data,
             L: FnMut(&mut UnaryScopeHandle<G::Timestamp, D1, D2, P::Pullable>)+'static,
             P: ParallelizationContract<G::Timestamp, D1>>
             (mut self, pact: P, name: String, logic: L) -> ActiveStream<G, D2> {
        let (sender, receiver) = pact.connect(self.builder.communicator());
        let targets = OutputPort::<G::Timestamp,D2>::new();
        let scope = UnaryScope::new(receiver, targets.clone(), name, logic, vec![], false, self.builder.communicator().peers());
        let index = self.builder.add_scope(scope);
        self.connect_to(ScopeInput(index, 0), sender);
        self.transfer_borrow_to(ScopeOutput(index, 0), targets)
    }
}

pub struct UnaryScopeHandle<T: Timestamp, D1: Data, D2: Data, P: Pullable<(T, Vec<D1>)>> {
    pub input:          PullableHelper<T, D1, P>,
    pub output:         ObserverHelper<OutputPort<T, D2>>,
    pub notificator:    Notificator<T>,
}

pub struct UnaryScope<T: Timestamp, D1: Data, D2: Data, P: Pullable<(T, Vec<D1>)>, L: FnMut(&mut UnaryScopeHandle<T, D1, D2, P>)> {
    name:           String,
    handle:         UnaryScopeHandle<T, D1, D2, P>,
    logic:          L,
    initial:        Vec<T>,  // initial notifications
    notify:         bool,
    peers:          u64,
}

impl<T: Timestamp, D1: Data, D2: Data, P: Pullable<(T, Vec<D1>)>, L: FnMut(&mut UnaryScopeHandle<T, D1, D2, P>)> UnaryScope<T, D1, D2, P, L> {
    pub fn new(receiver: P, targets: OutputPort<T, D2>, name: String, logic: L, init: Vec<T>, notify: bool, peers: u64) -> UnaryScope<T, D1, D2, P, L> {
        UnaryScope {
            name:    name,
            handle:  UnaryScopeHandle {
                input:       PullableHelper::new(receiver),
                output:      ObserverHelper::new(targets, Rc::new(RefCell::new(CountMap::new()))),
                notificator: Default::default(),
            },
            logic:   logic,
            initial: init,
            notify:  notify,
            peers:   peers,
        }
    }
}

impl<T, D1, D2, P, L> Scope<T> for UnaryScope<T, D1, D2, P, L>
where T: Timestamp,
      D1: Data, D2: Data,
      P: Pullable<(T, Vec<D1>)>,
      L: FnMut(&mut UnaryScopeHandle<T, D1, D2, P>) {
    fn inputs(&self) -> u64 { 1 }
    fn outputs(&self) -> u64 { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        let mut internal = vec![CountMap::new()];

        for time in self.initial.drain() { for _ in (0..self.peers) { self.handle.notificator.notify_at(&time); } }
        self.handle.notificator.pull_progress(&mut internal[0]);

        (vec![vec![Antichain::from_elem(Default::default())]], internal)
    }

    fn set_external_summary(&mut self, _summaries: Vec<Vec<Antichain<T::Summary>>>, frontier: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(frontier);
    }

    fn push_external_progress(&mut self, external: &mut [CountMap<T>]) -> () {
        self.handle.notificator.update_frontier_from_cm(external);
    }

    fn pull_internal_progress(&mut self, internal: &mut [CountMap<T>],
                                         consumed: &mut [CountMap<T>],
                                         produced: &mut [CountMap<T>]) -> bool
    {
        (self.logic)(&mut self.handle);

        // extract what we know about progress from the input and output adapters.
        self.handle.input.pull_progress(&mut consumed[0]);
        self.handle.output.pull_progress(&mut produced[0]);
        self.handle.notificator.pull_progress(&mut internal[0]);

        return false;   // no unannounced internal work
    }

    fn name(&self) -> String { format!("{}", self.name) }
    fn notify_me(&self) -> bool { self.notify }
}
<|endoftext|>


<commit_before>extern crate num;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;

mod units;
mod map;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;
const PANEL_HEIGHT: u8 = 5;

const FOV_RADIUS: u8 = 10;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

impl Direction {
    fn to_rel_point(self) -> Point<i16> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(map::MAP_MAX_WIDTH as i32, map::MAP_MAX_HEIGHT as i32);
    root.set_default_foreground(tcod::colors::WHITE);

    let unit_types = units::load_unit_types();
    let (mut map, start_coord) = map::Map::init(&unit_types);

    let player_type = units::UnitType::new("Player", '@', tcod::colors::WHITE);
    let mut player = units::Unit::new(start_coord, &player_type);

    map.update_fov(player.get_position(), FOV_RADIUS);

    while !root.window_closed() {
        buffer_console.clear();
        root.clear();

        // With the scrolling map, we need to try to centre the player on the screen
        // without going past the bounds of the buffer.
        let (map_width, map_height) = map.get_map_size();
        let draw_left = player.get_x() - SCREEN_WIDTH as i16 / 2;
        let draw_top = player.get_y() - SCREEN_HEIGHT as i16 / 2;

        let mut view_port = rectangle::Rectangle::new(Point{x: draw_left, y: draw_top}, (SCREEN_WIDTH, SCREEN_HEIGHT - PANEL_HEIGHT));
        view_port.clamp_to((0,0), (map_width as i16, map_height as i16));

        println!("{:?}", view_port);

        map.render_map(&mut buffer_console);
        map.render_npcs(&mut buffer_console);

        player.render(&mut buffer_console);

        tcod::console::blit(&buffer_console, (view_port.top_left.x as i32, view_port.top_left.y as i32), (SCREEN_WIDTH as i32, (SCREEN_HEIGHT - PANEL_HEIGHT) as i32), &mut root, (0,0), 1.0, 1.0);
        root.flush();

        let key = root.wait_for_keypress(true);

        match key_type(&key) {
            KeyType::Movement(dir)  => {
                let pos = player.get_position();
                let new_pos = pos + dir.to_rel_point();

                if let Ok(tile) = map.get_tile_type(new_pos) {
                    if !tile.blocks_move() {
                        player.move_to(new_pos);
                        map.update_fov(player.get_position(), FOV_RADIUS);
                    }
                }
            },
            KeyType::Exit           => break,
            KeyType::NewGame        => {
                let (new_map, start_coord) = map::Map::init(&unit_types);
                map = new_map;
                player.move_to(start_coord);
                map.update_fov(start_coord, FOV_RADIUS);
            }
            KeyType::Other          => println!("{:?}", key),
        }
    }
}
<commit_msg>Removed viewport printing.<commit_after>extern crate num;
extern crate rand;

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;

mod units;
mod map;

const SCREEN_WIDTH: u8 = 80;
const SCREEN_HEIGHT: u8 = 50;
const PANEL_HEIGHT: u8 = 5;

const FOV_RADIUS: u8 = 10;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

impl Direction {
    fn to_rel_point(self) -> Point<i16> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(map::MAP_MAX_WIDTH as i32, map::MAP_MAX_HEIGHT as i32);
    root.set_default_foreground(tcod::colors::WHITE);

    let unit_types = units::load_unit_types();
    let (mut map, start_coord) = map::Map::init(&unit_types);

    let player_type = units::UnitType::new("Player", '@', tcod::colors::WHITE);
    let mut player = units::Unit::new(start_coord, &player_type);

    map.update_fov(player.get_position(), FOV_RADIUS);

    while !root.window_closed() {
        buffer_console.clear();
        root.clear();

        // With the scrolling map, we need to try to centre the player on the screen
        // without going past the bounds of the buffer.
        let (map_width, map_height) = map.get_map_size();
        let draw_left = player.get_x() - SCREEN_WIDTH as i16 / 2;
        let draw_top = player.get_y() - SCREEN_HEIGHT as i16 / 2;

        let mut view_port = rectangle::Rectangle::new(Point{x: draw_left, y: draw_top}, (SCREEN_WIDTH, SCREEN_HEIGHT - PANEL_HEIGHT));
        view_port.clamp_to((0,0), (map_width as i16, map_height as i16));

        map.render_map(&mut buffer_console);
        map.render_npcs(&mut buffer_console);

        player.render(&mut buffer_console);

        tcod::console::blit(&buffer_console, (view_port.top_left.x as i32, view_port.top_left.y as i32), (SCREEN_WIDTH as i32, (SCREEN_HEIGHT - PANEL_HEIGHT) as i32), &mut root, (0,0), 1.0, 1.0);
        root.flush();

        let key = root.wait_for_keypress(true);

        match key_type(&key) {
            KeyType::Movement(dir)  => {
                let pos = player.get_position();
                let new_pos = pos + dir.to_rel_point();

                if let Ok(tile) = map.get_tile_type(new_pos) {
                    if !tile.blocks_move() {
                        player.move_to(new_pos);
                        map.update_fov(player.get_position(), FOV_RADIUS);
                    }
                }
            },
            KeyType::Exit           => break,
            KeyType::NewGame        => {
                let (new_map, start_coord) = map::Map::init(&unit_types);
                map = new_map;
                player.move_to(start_coord);
                map.update_fov(start_coord, FOV_RADIUS);
            }
            KeyType::Other          => println!("{:?}", key),
        }
    }
}
<|endoftext|>