<commit_before>//! Backend (rendering/input) helpers
//!
//! This module provides helpers for interaction with the operating system.
//!
//! ## Module structure
//!
//! The module is largely structured around three main aspects of interaction with the OS:
//! session management, input handling, and graphics.
//!
//! ### Session management
//!
//! Session management relates to mechanisms allowing the compositor to access the resources
//! it needs to function. It contains interaction with the login manager if any ((e)logind or
//! seatd), as well as releasing those resources when TTY-switching. It is handled by the
//! [`session`] module, gated by the `backend_session` cargo feature. You will generally need
//! it to run your compositor directly on a TTY.
//!
//! This module is tightly coupled with the [`udev`] module (gated by the `backend_udev` cargo
//! feature), which allows the discovery of usable graphics and input devices on the system, using
//! the udev system daemon.
//!
//! ### Input handling
//!
//! Input handling consists in discovering the various available input devices, and receiving
//! all inputs events from it. Smithay is build to support different possible sources for
//! that input data, with a generic API provided by the traits and types defined in the
//! [`input`] module. An input provider following this API based on `libinput` is given in the
//! [`libinput`] module, gated by the `backend_libinput` cargo feature. The winit backend
//! (see below) also provides an input provider.
//!
//! ### Graphics
//!
//! Combining content from the clients and displaying it on the screen is the central role of
//! a wayland compositor, and also one of its most complex tasks; several backend modules are
//! dedicated to this task.
//!
//! Smithay provides a rendering infrastructure built around graphics buffers: you retrieve buffers
//! for your client, you composite them into a new buffer holding the contents of your desktop,
//! that you will then submit to the hardware for display. The backbone of this infrastructure is
//! structured around the [`allocator`] and [`renderer`] modules. The first one contains generic
//! traits representing the capability to allocate and convert graphical buffers, as well as an
//! implementation of this capability using GBM (see its module-level docs for details). The second
//! provides traits representing the capability of graphics rendering using those buffers, as well
//! as an implementation of this capability using GLes2 (see its module-level docs for details).
//!
//! Alongside this backbone capability, Smithay also provides the [`drm`] module, which handles
//! direct interaction with the graphical physical devices to setup the display pipeline and
//! submit rendered buffers to the monitors for display. This module is gated by the
//! `backend_drm` cargo feature.
//!
//! The [`egl`] module provides the logic to setup an OpenGL context. It is used by the Gles2
//! renderer (which is based on OpenGL), and also provides the capability for clients to use
//! the `wl_drm`-based hardware-acceleration provided by Mesa, a precursor to the
//! [`linux_dmabuf`](crate::wayland::dmabuf) Wayland protocol extension. Note that, at the
//! moment, even clients using dma-buf still require that the `wl_drm` infrastructure is
//! initialized to have hardware-acceleration.
//!
//! ## X11 backend
//!
//! Alongside this infrastructure, Smithay also provides an alternative backend based on
//! [x11rb](https://crates.io/crates/x11rb), which makes it possible to run your compositor as
//! an X11 client. This is generally quite helpful for development and debugging.
//!
//! The X11 backend does not concern itself with what renderer is in use, allowing presentation to
//! the window assuming you can provide it with a [`Dmabuf`](crate::backend::allocator::dmabuf::Dmabuf).
//! The X11 backend is also an input provider, and is accessible in the [`x11`] module, gated by
//! the `backend_x11` cargo feature.
//!
//! ## Winit backend
//!
//! Alongside this infrastructure, Smithay also provides an alternative backend based on
//! [winit](https://crates.io/crates/winit), which makes it possible to run your compositor as
//! a Wayland or X11 client. You are encouraged to use the X11 backend where possible since winit
//! does not integrate into calloop too well. This backend is generally quite helpful for
//! development and debugging. That backend is both a renderer and an input provider, and is
//! accessible in the [`winit`] module, gated by the `backend_winit` cargo feature.
//!

pub mod allocator;
pub mod input;
pub mod renderer;

#[cfg(feature = "backend_drm")]
pub mod drm;
#[cfg(feature = "backend_egl")]
pub mod egl;
#[cfg(feature = "backend_libinput")]
pub mod libinput;
#[cfg(feature = "backend_session")]
pub mod session;
#[cfg(feature = "backend_udev")]
pub mod udev;

#[cfg(feature = "backend_winit")]
pub mod winit;

#[cfg(feature = "backend_x11")]
pub mod x11;

/// Error that can happen when swapping buffers.
#[derive(Debug, thiserror::Error)]
pub enum SwapBuffersError {
    /// The buffers have already been swapped.
    ///
    /// This error can be returned when `swap_buffers` has been called multiple times
    /// without any modification in between.
    #[error("Buffers are already swapped, swap_buffers was called too many times")]
    AlreadySwapped,
    /// The corresponding context has been lost and needs to be recreated.
    ///
    /// All the objects associated to it (textures, buffers, programs, etc.)
    /// need to be recreated from scratch. Underlying resources like native surfaces
    /// might also need to be recreated.
    ///
    /// Operations will have no effect. Functions that read textures, buffers, etc.
    /// will return uninitialized data instead.
    #[error("The context has been lost, it needs to be recreated: {0}")]
    ContextLost(Box<dyn std::error::Error>),
    /// A temporary condition caused to rendering to fail.
    ///
    /// Depending on the underlying error this *might* require fixing internal state of the rendering backend,
    /// but failures mapped to `TemporaryFailure` are always recoverable without re-creating the entire stack,
    /// as is represented by `ContextLost`.
    ///
    /// Proceed after investigating the source to reschedule another full rendering step or just this page_flip at a later time.
    /// If the root cause cannot be discovered and subsequent renderings also fail, it is advised to fallback to
    /// recreation.
    #[error("A temporary condition caused the page flip to fail: {0}")]
    TemporaryFailure(Box<dyn std::error::Error>),
}
<commit_msg>backend: Make SwapBuffersError Send+Sync<commit_after>//! Backend (rendering/input) helpers
//!
//! This module provides helpers for interaction with the operating system.
//!
//! ## Module structure
//!
//! The module is largely structured around three main aspects of interaction with the OS:
//! session management, input handling, and graphics.
//!
//! ### Session management
//!
//! Session management relates to mechanisms allowing the compositor to access the resources
//! it needs to function. It contains interaction with the login manager if any ((e)logind or
//! seatd), as well as releasing those resources when TTY-switching. It is handled by the
//! [`session`] module, gated by the `backend_session` cargo feature. You will generally need
//! it to run your compositor directly on a TTY.
//!
//! This module is tightly coupled with the [`udev`] module (gated by the `backend_udev` cargo
//! feature), which allows the discovery of usable graphics and input devices on the system, using
//! the udev system daemon.
//!
//! ### Input handling
//!
//! Input handling consists in discovering the various available input devices, and receiving
//! all inputs events from it. Smithay is build to support different possible sources for
//! that input data, with a generic API provided by the traits and types defined in the
//! [`input`] module. An input provider following this API based on `libinput` is given in the
//! [`libinput`] module, gated by the `backend_libinput` cargo feature. The winit backend
//! (see below) also provides an input provider.
//!
//! ### Graphics
//!
//! Combining content from the clients and displaying it on the screen is the central role of
//! a wayland compositor, and also one of its most complex tasks; several backend modules are
//! dedicated to this task.
//!
//! Smithay provides a rendering infrastructure built around graphics buffers: you retrieve buffers
//! for your client, you composite them into a new buffer holding the contents of your desktop,
//! that you will then submit to the hardware for display. The backbone of this infrastructure is
//! structured around the [`allocator`] and [`renderer`] modules. The first one contains generic
//! traits representing the capability to allocate and convert graphical buffers, as well as an
//! implementation of this capability using GBM (see its module-level docs for details). The second
//! provides traits representing the capability of graphics rendering using those buffers, as well
//! as an implementation of this capability using GLes2 (see its module-level docs for details).
//!
//! Alongside this backbone capability, Smithay also provides the [`drm`] module, which handles
//! direct interaction with the graphical physical devices to setup the display pipeline and
//! submit rendered buffers to the monitors for display. This module is gated by the
//! `backend_drm` cargo feature.
//!
//! The [`egl`] module provides the logic to setup an OpenGL context. It is used by the Gles2
//! renderer (which is based on OpenGL), and also provides the capability for clients to use
//! the `wl_drm`-based hardware-acceleration provided by Mesa, a precursor to the
//! [`linux_dmabuf`](crate::wayland::dmabuf) Wayland protocol extension. Note that, at the
//! moment, even clients using dma-buf still require that the `wl_drm` infrastructure is
//! initialized to have hardware-acceleration.
//!
//! ## X11 backend
//!
//! Alongside this infrastructure, Smithay also provides an alternative backend based on
//! [x11rb](https://crates.io/crates/x11rb), which makes it possible to run your compositor as
//! an X11 client. This is generally quite helpful for development and debugging.
//!
//! The X11 backend does not concern itself with what renderer is in use, allowing presentation to
//! the window assuming you can provide it with a [`Dmabuf`](crate::backend::allocator::dmabuf::Dmabuf).
//! The X11 backend is also an input provider, and is accessible in the [`x11`] module, gated by
//! the `backend_x11` cargo feature.
//!
//! ## Winit backend
//!
//! Alongside this infrastructure, Smithay also provides an alternative backend based on
//! [winit](https://crates.io/crates/winit), which makes it possible to run your compositor as
//! a Wayland or X11 client. You are encouraged to use the X11 backend where possible since winit
//! does not integrate into calloop too well. This backend is generally quite helpful for
//! development and debugging. That backend is both a renderer and an input provider, and is
//! accessible in the [`winit`] module, gated by the `backend_winit` cargo feature.
//!

pub mod allocator;
pub mod input;
pub mod renderer;

#[cfg(feature = "backend_drm")]
pub mod drm;
#[cfg(feature = "backend_egl")]
pub mod egl;
#[cfg(feature = "backend_libinput")]
pub mod libinput;
#[cfg(feature = "backend_session")]
pub mod session;
#[cfg(feature = "backend_udev")]
pub mod udev;

#[cfg(feature = "backend_winit")]
pub mod winit;

#[cfg(feature = "backend_x11")]
pub mod x11;

/// Error that can happen when swapping buffers.
#[derive(Debug, thiserror::Error)]
pub enum SwapBuffersError {
    /// The buffers have already been swapped.
    ///
    /// This error can be returned when `swap_buffers` has been called multiple times
    /// without any modification in between.
    #[error("Buffers are already swapped, swap_buffers was called too many times")]
    AlreadySwapped,
    /// The corresponding context has been lost and needs to be recreated.
    ///
    /// All the objects associated to it (textures, buffers, programs, etc.)
    /// need to be recreated from scratch. Underlying resources like native surfaces
    /// might also need to be recreated.
    ///
    /// Operations will have no effect. Functions that read textures, buffers, etc.
    /// will return uninitialized data instead.
    #[error("The context has been lost, it needs to be recreated: {0}")]
    ContextLost(Box<dyn std::error::Error + Send + Sync>),
    /// A temporary condition caused to rendering to fail.
    ///
    /// Depending on the underlying error this *might* require fixing internal state of the rendering backend,
    /// but failures mapped to `TemporaryFailure` are always recoverable without re-creating the entire stack,
    /// as is represented by `ContextLost`.
    ///
    /// Proceed after investigating the source to reschedule another full rendering step or just this page_flip at a later time.
    /// If the root cause cannot be discovered and subsequent renderings also fail, it is advised to fallback to
    /// recreation.
    #[error("A temporary condition caused the page flip to fail: {0}")]
    TemporaryFailure(Box<dyn std::error::Error + Send + Sync>),
}
<|endoftext|>


<commit_before>use context::{mod, GlVersion};
use gl;
use libc;
use std::c_vec::CVec;
use std::{fmt, mem, ptr};
use std::sync::Arc;
use GlObject;

/// A buffer in the graphics card's memory.
pub struct Buffer {
    display: Arc<super::DisplayImpl>,
    id: gl::types::GLuint,
    elements_size: uint,
    elements_count: uint,
}

/// Type of a buffer.
pub trait BufferType {
    /// Should return `&mut ctxt.state.something`.
    fn get_storage_point(Option<Self>, &mut context::GLState)
        -> &mut gl::types::GLuint;
    /// Should return `gl::SOMETHING_BUFFER`.
    fn get_bind_point(Option<Self>) -> gl::types::GLenum;
}

/// Used for vertex buffers.
pub struct ArrayBuffer;

impl BufferType for ArrayBuffer {
    fn get_storage_point(_: Option<ArrayBuffer>, state: &mut context::GLState)
        -> &mut gl::types::GLuint
    {
        &mut state.array_buffer_binding
    }

    fn get_bind_point(_: Option<ArrayBuffer>) -> gl::types::GLenum {
        gl::ARRAY_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelPackBuffer;

impl BufferType for PixelPackBuffer {
    fn get_storage_point(_: Option<PixelPackBuffer>, state: &mut context::GLState)
        -> &mut gl::types::GLuint
    {
        &mut state.pixel_pack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelPackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_PACK_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelUnpackBuffer;

impl BufferType for PixelUnpackBuffer {
    fn get_storage_point(_: Option<PixelUnpackBuffer>, state: &mut context::GLState)
        -> &mut gl::types::GLuint
    {
        &mut state.pixel_unpack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelUnpackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_UNPACK_BUFFER
    }
}

impl Buffer {
    pub fn new<T, D>(display: &super::Display, data: Vec<D>, usage: gl::types::GLenum)
        -> Buffer where T: BufferType, D: Send + Copy
    {
        use std::mem;

        let elements_size = {
            let d0: *const D = &data[0];
            let d1: *const D = &data[1];
            (d1 as uint) - (d0 as uint)
        };

        let elements_count = data.len();
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();

        display.context.context.exec(move |: ctxt| {
            let data = data;

            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                ctxt.gl.GenBuffers(1, &mut id);
                tx.send(id);

                let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                let bind = BufferType::get_bind_point(None::<T>);

                ctxt.gl.BindBuffer(bind, id);
                *storage = id;
                ctxt.gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr,
                                   data.as_ptr() as *const libc::c_void, usage);

                let mut obtained_size: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetBufferParameteriv(bind, gl::BUFFER_SIZE, &mut obtained_size);
                if buffer_size != obtained_size as uint {
                    ctxt.gl.DeleteBuffers(1, [id].as_ptr());
                    panic!("Not enough available memory for buffer");
                }
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn new_empty<T>(display: &super::Display, elements_size: uint, elements_count: uint,
                        usage: gl::types::GLenum) -> Buffer where T: BufferType
    {
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();
        display.context.context.exec(move |: ctxt| {
            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                ctxt.gl.GenBuffers(1, &mut id);

                let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                let bind = BufferType::get_bind_point(None::<T>);

                ctxt.gl.BindBuffer(bind, id);
                *storage = id;
                ctxt.gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr, ptr::null(), usage);

                let mut obtained_size: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetBufferParameteriv(bind, gl::BUFFER_SIZE, &mut obtained_size);
                if buffer_size != obtained_size as uint {
                    ctxt.gl.DeleteBuffers(1, [id].as_ptr());
                    panic!("Not enough available memory for buffer");
                }

                tx.send(id);
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn get_display(&self) -> &Arc<super::DisplayImpl> {
        &self.display
    }

    pub fn get_elements_size(&self) -> uint {
        self.elements_size
    }

    pub fn get_elements_count(&self) -> uint {
        self.elements_count
    }

    pub fn get_total_size(&self) -> uint {
        self.elements_count * self.elements_size
    }

    #[cfg(feature = "gl_extensions")]
    pub fn map<'a, T, D>(&'a mut self) -> Mapping<'a, T, D> where T: BufferType, D: Send {
        let (tx, rx) = channel();
        let id = self.id.clone();
        let elements_count = self.elements_count.clone();

        self.display.context.exec(move |: ctxt| {
            if ctxt.opengl_es {
                tx.send(Err("OpenGL ES doesn't support glMapBuffer"));
                return;
            }

            let ptr = unsafe {
                if ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.MapNamedBuffer(id, gl::READ_WRITE)

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    ctxt.gl.BindBuffer(bind, id);
                    *storage = id;
                    ctxt.gl.MapBuffer(bind, gl::READ_WRITE)
                }
            };

            if ptr.is_null() {
                tx.send(Err("glMapBuffer returned null"));
            } else {
                tx.send(Ok(ptr as *mut D));
            }
        });

        Mapping {
            buffer: self,
            data: unsafe { CVec::new(rx.recv().unwrap(), elements_count) },
        }
    }

    #[cfg(feature = "gl_extensions")]
    pub fn read<T, D>(&self) -> Vec<D> where T: BufferType, D: Send {
        self.read_slice::<T, D>(0, self.elements_count)
    }

    #[cfg(feature = "gl_extensions")]
    pub fn read_slice<T, D>(&self, offset: uint, size: uint)
                            -> Vec<D> where T: BufferType, D: Send
    {
        assert!(offset + size <= self.elements_count);

        let id = self.id.clone();
        let elements_size = self.elements_size.clone();
        let (tx, rx) = channel();

        self.display.context.exec(move |: ctxt| {
            if ctxt.opengl_es {
                panic!("OpenGL ES doesn't support glGetBufferSubData");
            }

            unsafe {
                let mut data = Vec::with_capacity(size);
                data.set_len(size);

                if !ctxt.opengl_es && ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.GetNamedBufferSubData(id, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizei,
                        data.as_mut_ptr() as *mut libc::c_void);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    ctxt.gl.BindBuffer(bind, id);
                    *storage = id;
                    ctxt.gl.GetBufferSubData(bind, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizeiptr,
                        data.as_mut_ptr() as *mut libc::c_void);
                }

                tx.send_opt(data).ok();
            }
        });

        rx.recv()
    }
}

impl fmt::Show for Buffer {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        (format!("Buffer #{}", self.id)).fmt(formatter)
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        let id = self.id.clone();
        self.display.context.exec(move |: ctxt| {
            if ctxt.state.array_buffer_binding == id {
                ctxt.state.array_buffer_binding = 0;
            }

            if ctxt.state.pixel_pack_buffer_binding == id {
                ctxt.state.pixel_pack_buffer_binding = 0;
            }

            if ctxt.state.pixel_unpack_buffer_binding == id {
                ctxt.state.pixel_unpack_buffer_binding = 0;
            }

            unsafe { ctxt.gl.DeleteBuffers(1, [ id ].as_ptr()); }
        });
    }
}

impl GlObject for Buffer {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

/// Describes the attribute of a vertex.
///
/// When you create a vertex buffer, you need to pass some sort of array of data. In order for
/// OpenGL to use this data, we must tell it some informations about each field of each
/// element. This structure describes one such field.
#[deriving(Show, Clone)]
pub struct VertexAttrib {
    /// The offset, in bytes, between the start of each vertex and the attribute.
    pub offset: uint,

    /// Type of the field.
    pub data_type: gl::types::GLenum,

    /// Number of invidual elements in the attribute.
    ///
    /// For example if `data_type` is a f32 and `elements_count` is 2, then you have a `vec2`.
    pub elements_count: u32,
}

/// Describes the layout of each vertex in a vertex buffer.
pub type VertexBindings = Vec<(String, VertexAttrib)>;

/// Trait for structures that represent a vertex.
pub trait VertexFormat: Copy {
    /// Builds the `VertexBindings` representing the layout of this element.
    fn build_bindings(Option<Self>) -> VertexBindings;
}

/// A mapping of a buffer.
#[cfg(feature = "gl_extensions")]
pub struct Mapping<'b, T, D> {
    buffer: &'b mut Buffer,
    data: CVec<D>,
}

#[cfg(feature = "gl_extensions")]
#[unsafe_destructor]
impl<'a, T, D> Drop for Mapping<'a, T, D> where T: BufferType {
    fn drop(&mut self) {
        let id = self.buffer.id.clone();
        self.buffer.display.context.exec(move |: ctxt| {
            unsafe {
                if ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.UnmapNamedBuffer(id);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    if *storage != id {
                        ctxt.gl.BindBuffer(bind, id);
                        *storage = id;
                    }

                    ctxt.gl.UnmapBuffer(bind);
                }
            }
        });
    }
}

#[cfg(feature = "gl_extensions")]
impl<'a, T, D> Deref<[D]> for Mapping<'a, T, D> {
    fn deref<'b>(&'b self) -> &'b [D] {
        self.data.as_slice()
    }
}

#[cfg(feature = "gl_extensions")]
impl<'a, T, D> DerefMut<[D]> for Mapping<'a, T, D> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut [D] {
        self.data.as_mut_slice()
    }
}
<commit_msg>Fix buffer not tolerant enough<commit_after>use context::{mod, GlVersion};
use gl;
use libc;
use std::c_vec::CVec;
use std::{fmt, mem, ptr};
use std::sync::Arc;
use GlObject;

/// A buffer in the graphics card's memory.
pub struct Buffer {
    display: Arc<super::DisplayImpl>,
    id: gl::types::GLuint,
    elements_size: uint,
    elements_count: uint,
}

/// Type of a buffer.
pub trait BufferType {
    /// Should return `&mut ctxt.state.something`.
    fn get_storage_point(Option<Self>, &mut context::GLState)
        -> &mut gl::types::GLuint;
    /// Should return `gl::SOMETHING_BUFFER`.
    fn get_bind_point(Option<Self>) -> gl::types::GLenum;
}

/// Used for vertex buffers.
pub struct ArrayBuffer;

impl BufferType for ArrayBuffer {
    fn get_storage_point(_: Option<ArrayBuffer>, state: &mut context::GLState)
        -> &mut gl::types::GLuint
    {
        &mut state.array_buffer_binding
    }

    fn get_bind_point(_: Option<ArrayBuffer>) -> gl::types::GLenum {
        gl::ARRAY_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelPackBuffer;

impl BufferType for PixelPackBuffer {
    fn get_storage_point(_: Option<PixelPackBuffer>, state: &mut context::GLState)
        -> &mut gl::types::GLuint
    {
        &mut state.pixel_pack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelPackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_PACK_BUFFER
    }
}

/// Used for pixel buffers.
pub struct PixelUnpackBuffer;

impl BufferType for PixelUnpackBuffer {
    fn get_storage_point(_: Option<PixelUnpackBuffer>, state: &mut context::GLState)
        -> &mut gl::types::GLuint
    {
        &mut state.pixel_unpack_buffer_binding
    }

    fn get_bind_point(_: Option<PixelUnpackBuffer>) -> gl::types::GLenum {
        gl::PIXEL_UNPACK_BUFFER
    }
}

impl Buffer {
    pub fn new<T, D>(display: &super::Display, data: Vec<D>, usage: gl::types::GLenum)
        -> Buffer where T: BufferType, D: Send + Copy
    {
        use std::mem;

        let elements_size = if data.len() <= 1 {
            mem::size_of::<D>()
        } else {
            let d0: *const D = &data[0];
            let d1: *const D = &data[1];
            (d1 as uint) - (d0 as uint)
        };

        let elements_count = data.len();
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();

        display.context.context.exec(move |: ctxt| {
            let data = data;

            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                ctxt.gl.GenBuffers(1, &mut id);
                tx.send(id);

                let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                let bind = BufferType::get_bind_point(None::<T>);

                ctxt.gl.BindBuffer(bind, id);
                *storage = id;
                ctxt.gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr,
                                   data.as_ptr() as *const libc::c_void, usage);

                let mut obtained_size: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetBufferParameteriv(bind, gl::BUFFER_SIZE, &mut obtained_size);
                if buffer_size != obtained_size as uint {
                    ctxt.gl.DeleteBuffers(1, [id].as_ptr());
                    panic!("Not enough available memory for buffer");
                }
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn new_empty<T>(display: &super::Display, elements_size: uint, elements_count: uint,
                        usage: gl::types::GLenum) -> Buffer where T: BufferType
    {
        let buffer_size = elements_count * elements_size as uint;

        let (tx, rx) = channel();
        display.context.context.exec(move |: ctxt| {
            unsafe {
                let mut id: gl::types::GLuint = mem::uninitialized();
                ctxt.gl.GenBuffers(1, &mut id);

                let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                let bind = BufferType::get_bind_point(None::<T>);

                ctxt.gl.BindBuffer(bind, id);
                *storage = id;
                ctxt.gl.BufferData(bind, buffer_size as gl::types::GLsizeiptr, ptr::null(), usage);

                let mut obtained_size: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetBufferParameteriv(bind, gl::BUFFER_SIZE, &mut obtained_size);
                if buffer_size != obtained_size as uint {
                    ctxt.gl.DeleteBuffers(1, [id].as_ptr());
                    panic!("Not enough available memory for buffer");
                }

                tx.send(id);
            }
        });

        Buffer {
            display: display.context.clone(),
            id: rx.recv(),
            elements_size: elements_size,
            elements_count: elements_count,
        }
    }

    pub fn get_display(&self) -> &Arc<super::DisplayImpl> {
        &self.display
    }

    pub fn get_elements_size(&self) -> uint {
        self.elements_size
    }

    pub fn get_elements_count(&self) -> uint {
        self.elements_count
    }

    pub fn get_total_size(&self) -> uint {
        self.elements_count * self.elements_size
    }

    #[cfg(feature = "gl_extensions")]
    pub fn map<'a, T, D>(&'a mut self) -> Mapping<'a, T, D> where T: BufferType, D: Send {
        let (tx, rx) = channel();
        let id = self.id.clone();
        let elements_count = self.elements_count.clone();

        self.display.context.exec(move |: ctxt| {
            if ctxt.opengl_es {
                tx.send(Err("OpenGL ES doesn't support glMapBuffer"));
                return;
            }

            let ptr = unsafe {
                if ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.MapNamedBuffer(id, gl::READ_WRITE)

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    ctxt.gl.BindBuffer(bind, id);
                    *storage = id;
                    ctxt.gl.MapBuffer(bind, gl::READ_WRITE)
                }
            };

            if ptr.is_null() {
                tx.send(Err("glMapBuffer returned null"));
            } else {
                tx.send(Ok(ptr as *mut D));
            }
        });

        Mapping {
            buffer: self,
            data: unsafe { CVec::new(rx.recv().unwrap(), elements_count) },
        }
    }

    #[cfg(feature = "gl_extensions")]
    pub fn read<T, D>(&self) -> Vec<D> where T: BufferType, D: Send {
        self.read_slice::<T, D>(0, self.elements_count)
    }

    #[cfg(feature = "gl_extensions")]
    pub fn read_slice<T, D>(&self, offset: uint, size: uint)
                            -> Vec<D> where T: BufferType, D: Send
    {
        assert!(offset + size <= self.elements_count);

        let id = self.id.clone();
        let elements_size = self.elements_size.clone();
        let (tx, rx) = channel();

        self.display.context.exec(move |: ctxt| {
            if ctxt.opengl_es {
                panic!("OpenGL ES doesn't support glGetBufferSubData");
            }

            unsafe {
                let mut data = Vec::with_capacity(size);
                data.set_len(size);

                if !ctxt.opengl_es && ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.GetNamedBufferSubData(id, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizei,
                        data.as_mut_ptr() as *mut libc::c_void);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    ctxt.gl.BindBuffer(bind, id);
                    *storage = id;
                    ctxt.gl.GetBufferSubData(bind, (offset * elements_size) as gl::types::GLintptr,
                        (size * elements_size) as gl::types::GLsizeiptr,
                        data.as_mut_ptr() as *mut libc::c_void);
                }

                tx.send_opt(data).ok();
            }
        });

        rx.recv()
    }
}

impl fmt::Show for Buffer {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        (format!("Buffer #{}", self.id)).fmt(formatter)
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        let id = self.id.clone();
        self.display.context.exec(move |: ctxt| {
            if ctxt.state.array_buffer_binding == id {
                ctxt.state.array_buffer_binding = 0;
            }

            if ctxt.state.pixel_pack_buffer_binding == id {
                ctxt.state.pixel_pack_buffer_binding = 0;
            }

            if ctxt.state.pixel_unpack_buffer_binding == id {
                ctxt.state.pixel_unpack_buffer_binding = 0;
            }

            unsafe { ctxt.gl.DeleteBuffers(1, [ id ].as_ptr()); }
        });
    }
}

impl GlObject for Buffer {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

/// Describes the attribute of a vertex.
///
/// When you create a vertex buffer, you need to pass some sort of array of data. In order for
/// OpenGL to use this data, we must tell it some informations about each field of each
/// element. This structure describes one such field.
#[deriving(Show, Clone)]
pub struct VertexAttrib {
    /// The offset, in bytes, between the start of each vertex and the attribute.
    pub offset: uint,

    /// Type of the field.
    pub data_type: gl::types::GLenum,

    /// Number of invidual elements in the attribute.
    ///
    /// For example if `data_type` is a f32 and `elements_count` is 2, then you have a `vec2`.
    pub elements_count: u32,
}

/// Describes the layout of each vertex in a vertex buffer.
pub type VertexBindings = Vec<(String, VertexAttrib)>;

/// Trait for structures that represent a vertex.
pub trait VertexFormat: Copy {
    /// Builds the `VertexBindings` representing the layout of this element.
    fn build_bindings(Option<Self>) -> VertexBindings;
}

/// A mapping of a buffer.
#[cfg(feature = "gl_extensions")]
pub struct Mapping<'b, T, D> {
    buffer: &'b mut Buffer,
    data: CVec<D>,
}

#[cfg(feature = "gl_extensions")]
#[unsafe_destructor]
impl<'a, T, D> Drop for Mapping<'a, T, D> where T: BufferType {
    fn drop(&mut self) {
        let id = self.buffer.id.clone();
        self.buffer.display.context.exec(move |: ctxt| {
            unsafe {
                if ctxt.version >= &GlVersion(4, 5) {
                    ctxt.gl.UnmapNamedBuffer(id);

                } else {
                    let storage = BufferType::get_storage_point(None::<T>, ctxt.state);
                    let bind = BufferType::get_bind_point(None::<T>);

                    if *storage != id {
                        ctxt.gl.BindBuffer(bind, id);
                        *storage = id;
                    }

                    ctxt.gl.UnmapBuffer(bind);
                }
            }
        });
    }
}

#[cfg(feature = "gl_extensions")]
impl<'a, T, D> Deref<[D]> for Mapping<'a, T, D> {
    fn deref<'b>(&'b self) -> &'b [D] {
        self.data.as_slice()
    }
}

#[cfg(feature = "gl_extensions")]
impl<'a, T, D> DerefMut<[D]> for Mapping<'a, T, D> {
    fn deref_mut<'b>(&'b mut self) -> &'b mut [D] {
        self.data.as_mut_slice()
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use ref_into::{RefInto, MutInto};
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn split_array_buffer(self)
        -> (BA, ContextOf<BufferBinderOf<(), BE>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (ba_binder, rest_buffers) = buffers.split_array();

        (ba_binder, gl.join_buffers(rest_buffers))
    }

    pub fn split_element_array_buffer(self)
        -> (BE, ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (be_binder, rest_buffers) = buffers.split_element_array();
        (be_binder, gl.join_buffers(rest_buffers))
    }

    pub fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ArrayBufferBinding<'a>,
            ContextOf<BufferBinderOf<(), BE>, F, P, R, T>
        )
        where BA: BorrowMut<ArrayBufferBinder>
    {
        let (mut ba_binder, gl) = self.split_array_buffer();
        (ba_binder.borrow_mut().bind(buffer), gl)
    }

    pub fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ElementArrayBufferBinding<'a>,
            ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>
        )
        where BE: BorrowMut<ElementArrayBufferBinder>
    {
        let (mut be_binder, gl) = self.split_element_array_buffer();
        (be_binder.borrow_mut().bind(buffer), gl)
    }
}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }

    pub fn split_array(self) -> (A, BufferBinderOf<(), E>) {
        (
            self.array,
            BufferBinderOf {
                array: (),
                element_array: self.element_array
            }
        )
    }

    pub fn split_element_array(self) -> (E, BufferBinderOf<A, ()>) {
        (
            self.element_array,
            BufferBinderOf {
                array: self.array,
                element_array: ()
            }
        )
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a mut BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<commit_msg>Move `bind_*_buffer()` methods into `*BufferContext` traits<commit_after>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use ref_into::{RefInto, MutInto};
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<B, F, P, R, T> ContextOf<B, F, P, R, T> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

impl<BA, BE, F, P, R, T> ContextOf<BufferBinderOf<BA, BE>, F, P, R, T> {
    pub fn split_array_buffer(self)
        -> (BA, ContextOf<BufferBinderOf<(), BE>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (ba_binder, rest_buffers) = buffers.split_array();

        (ba_binder, gl.join_buffers(rest_buffers))
    }

    pub fn split_element_array_buffer(self)
        -> (BE, ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>)
    {
        let (buffers, gl) = self.split_buffers();
        let (be_binder, rest_buffers) = buffers.split_element_array();
        (be_binder, gl.join_buffers(rest_buffers))
    }
}

pub trait ArrayBufferContext {
    type Rest;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest);
}

pub trait ElementArrayBufferContext {
    type Rest;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest);
}

impl<BA, BE, F, P, R, T> ArrayBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BA: BorrowMut<ArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<(), BE>, F, P, R, T>;

    fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ArrayBufferBinding<'a>, Self::Rest)
    {
        let (mut ba_binder, rest) = self.split_array_buffer();
        (ba_binder.borrow_mut().bind(buffer), rest)
    }
}

impl<BA, BE, F, P, R, T> ElementArrayBufferContext
    for ContextOf<BufferBinderOf<BA, BE>, F, P, R, T>
    where BE: BorrowMut<ElementArrayBufferBinder>
{
    type Rest = ContextOf<BufferBinderOf<BA, ()>, F, P, R, T>;

    fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (ElementArrayBufferBinding<'a>, Self::Rest)
    {
        let (mut be_binder, rest) = self.split_element_array_buffer();
        (be_binder.borrow_mut().bind(buffer), rest)
    }
}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }

    pub fn split_array(self) -> (A, BufferBinderOf<(), E>) {
        (
            self.array,
            BufferBinderOf {
                array: (),
                element_array: self.element_array
            }
        )
    }

    pub fn split_element_array(self) -> (E, BufferBinderOf<A, ()>) {
        (
            self.element_array,
            BufferBinderOf {
                array: self.array,
                element_array: ()
            }
        )
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> RefInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn ref_into(&'a self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a BufferBinderOf<A, E>
    where A: RefInto<'a, AI>,
          E: RefInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.ref_into(),
            element_array: self.element_array.ref_into()
        }
    }
}

impl<'a, A, E, AI, EI> MutInto<'a, BufferBinderOf<AI, EI>>
    for &'a mut BufferBinderOf<A, E>
    where A: MutInto<'a, AI>,
          E: MutInto<'a, EI>,
          AI: 'a, EI: 'a
{
    fn mut_into(&'a mut self) -> BufferBinderOf<AI, EI> {
        BufferBinderOf {
            array: self.array.mut_into(),
            element_array: self.element_array.mut_into()
        }
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg};

fn main() {
    // If you have arguments of specific values you want to test for, you can use the
    // .possible_values() method of Arg
    //
    // This allows you specify the valid values for that argument. If the user does not use one of
    // those specific values, they will receive a graceful exit with error message informing them
    // of the mistake, and what the possible valid values are
    //
    // For this example, assume you want one positional argument of either "fast" or "slow"
    // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
    let matches = App::new("myapp")
        .about("does awesome things")
        .arg(
            Arg::new("MODE")
                .about("What mode to run the program in")
                .index(1)
                .possible_values(["fast", "slow"])
                .required(true),
        )
        .get_matches();

    // Note, it's safe to call unwrap() because the arg is required
    match matches.value_of("MODE").unwrap() {
        "fast" => {
            // Do fast things...
        }
        "slow" => {
            // Do slow things...
        }
        _ => unreachable!(),
    }
}
<commit_msg>docs(examples): Provide visual indication of user choice<commit_after>use clap::{App, Arg};

fn main() {
    // If you have arguments of specific values you want to test for, you can use the
    // .possible_values() method of Arg
    //
    // This allows you specify the valid values for that argument. If the user does not use one of
    // those specific values, they will receive a graceful exit with error message informing them
    // of the mistake, and what the possible valid values are
    //
    // For this example, assume you want one positional argument of either "fast" or "slow"
    // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
    let matches = App::new("myapp")
        .about("does awesome things")
        .arg(
            Arg::new("MODE")
                .about("What mode to run the program in")
                .index(1)
                .possible_values(["fast", "slow"])
                .required(true),
        )
        .get_matches();

    // Note, it's safe to call unwrap() because the arg is required
    match matches.value_of("MODE").unwrap() {
        "fast" => {
            println!("Hare");
        }
        "slow" => {
            println!("Tortoise");
        }
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;
use std::str;
use std::ffi::CString;

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [
     0.0,  0.5,
     0.5, -0.5,
    -0.5, -0.5
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 position;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::from_slice(src.as_bytes());
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::new();
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
            panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint { unsafe {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf = Vec::new();
        buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
        gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ProgramInfoLog not valid utf8"));
    }
    program
} }

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // Choose a GL profile that is compatible with OS X 10.7+
    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(WindowHint::OpenglProfile(OpenGlProfileHint::Core));

    let (mut window, _) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // It is essential to make the context current before calling `gl::load_with`.
    window.make_current();

    // Load the OpenGL function pointers
    gl::load_with(|s| window.get_proc_address(s));

    // Create GLSL shaders
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                       mem::transmute(&VERTEX_DATA[0]),
                       gl::STATIC_DRAW);

        // Use shader program
        gl::UseProgram(program);
        gl::BindFragDataLocation(program, 0,
                                 CString::from_slice(b"out_color").as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program,
                                             CString::from_slice(b"position").as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    while !window.should_close() {
        // Poll events
        glfw.poll_events();

        unsafe {
            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        // Swap buffers
        window.swap_buffers();
    }

    unsafe {
    // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}
<commit_msg>More fixes to static_triangle example<commit_after>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;
use std::str;
use std::ffi::CString;

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [
     0.0,  0.5,
     0.5, -0.5,
    -0.5, -0.5
];

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
    in vec2 position;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
    }";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::from_slice(src.as_bytes());
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
            panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint { unsafe {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf = Vec::new();
        buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
        gl::GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ProgramInfoLog not valid utf8"));
    }
    program
} }

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // Choose a GL profile that is compatible with OS X 10.7+
    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(WindowHint::OpenglProfile(OpenGlProfileHint::Core));

    let (mut window, _) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // It is essential to make the context current before calling `gl::load_with`.
    window.make_current();

    // Load the OpenGL function pointers
    gl::load_with(|s| window.get_proc_address(s));

    // Create GLSL shaders
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create Vertex Array Object
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTEX_DATA.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                       mem::transmute(&VERTEX_DATA[0]),
                       gl::STATIC_DRAW);

        // Use shader program
        gl::UseProgram(program);
        gl::BindFragDataLocation(program, 0,
                                 CString::from_slice(b"out_color").as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program,
                                             CString::from_slice(b"position").as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint, 2, gl::FLOAT,
                                gl::FALSE as GLboolean, 0, ptr::null());
    }

    while !window.should_close() {
        // Poll events
        glfw.poll_events();

        unsafe {
            // Clear the screen to black
            gl::ClearColor(0.3, 0.3, 0.3, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        // Swap buffers
        window.swap_buffers();
    }

    unsafe {
    // Cleanup
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}
<|endoftext|>


<commit_before>use bls::Keypair;
use clap::{App, Arg, SubCommand};
use slog::{debug, info, o, Drain};
use std::path::PathBuf;
use types::test_utils::generate_deterministic_keypair;
use validator_client::Config as ValidatorClientConfig;

fn main() {
    // Logging
    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::CompactFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();
    let log = slog::Logger::root(drain, o!());

    // CLI
    let matches = App::new("Lighthouse Accounts Manager")
        .version("0.0.1")
        .author("Sigma Prime <contact@sigmaprime.io>")
        .about("Eth 2.0 Accounts Manager")
        .arg(
            Arg::with_name("datadir")
                .long("datadir")
                .value_name("DIR")
                .help("Data directory for keys and databases.")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("generate")
                .about("Generates a new validator private key")
                .version("0.0.1")
                .author("Sigma Prime <contact@sigmaprime.io>"),
        )
        .subcommand(
            SubCommand::with_name("generate_deterministic")
                .about("Generates a deterministic validator private key FOR TESTING")
                .version("0.0.1")
                .author("Sigma Prime <contact@sigmaprime.io>")
                .arg(
                    Arg::with_name("validator index")
                        .long("index")
                        .short("i")
                        .value_name("index")
                        .help("The index of the validator, for which the test key is generated")
                        .takes_value(true)
                        .required(true),
                ),
        )
        .get_matches();

    let config = ValidatorClientConfig::parse_args(&matches, &log)
        .expect("Unable to build a configuration for the account manager.");

    // Log configuration
    info!(log, "";
          "data_dir" => &config.data_dir.to_str());

    match matches.subcommand() {
        ("generate", Some(_gen_m)) => {
            let keypair = Keypair::random();
            let key_path: PathBuf = config
                .save_key(&keypair)
                .expect("Unable to save newly generated private key.");
            debug!(
                log,
                "Keypair generated {:?}, saved to: {:?}",
                keypair.identifier(),
                key_path.to_string_lossy()
            );
        }
        ("generate_deterministic", Some(gen_d_matches)) => {
            let validator_index = gen_d_matches
                .value_of("validator index")
                .expect("Validator index required.")
                .parse::<u64>()
                .expect("Invalid validator index.") as usize;
            let keypair = generate_deterministic_keypair(validator_index);
            let key_path: PathBuf = config
                .save_key(&keypair)
                .expect("Unable to save newly generated deterministic private key.");
            debug!(
                log,
                "Deterministic Keypair generated {:?}, saved to: {:?}",
                keypair.identifier(),
                key_path.to_string_lossy()
            );
        }
        _ => panic!(
            "The account manager must be run with a subcommand. See help for more information."
        ),
    }
}
<commit_msg>Add feat for `account_manager` to gen key range<commit_after>use bls::Keypair;
use clap::{App, Arg, SubCommand};
use slog::{debug, info, o, Drain};
use std::path::PathBuf;
use types::test_utils::generate_deterministic_keypair;
use validator_client::Config as ValidatorClientConfig;

fn main() {
    // Logging
    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::CompactFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();
    let log = slog::Logger::root(drain, o!());

    // CLI
    let matches = App::new("Lighthouse Accounts Manager")
        .version("0.0.1")
        .author("Sigma Prime <contact@sigmaprime.io>")
        .about("Eth 2.0 Accounts Manager")
        .arg(
            Arg::with_name("datadir")
                .long("datadir")
                .value_name("DIR")
                .help("Data directory for keys and databases.")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("generate")
                .about("Generates a new validator private key")
                .version("0.0.1")
                .author("Sigma Prime <contact@sigmaprime.io>"),
        )
        .subcommand(
            SubCommand::with_name("generate_deterministic")
                .about("Generates a deterministic validator private key FOR TESTING")
                .version("0.0.1")
                .author("Sigma Prime <contact@sigmaprime.io>")
                .arg(
                    Arg::with_name("validator index")
                        .long("index")
                        .short("i")
                        .value_name("index")
                        .help("The index of the validator, for which the test key is generated")
                        .takes_value(true)
                        .required(true),
                )
                .arg(
                    Arg::with_name("end validator index")
                        .long("end_index")
                        .short("j")
                        .value_name("end_index")
                        .help("If supplied along with `index`, generates a range of keys.")
                        .takes_value(true),
                ),
        )
        .get_matches();

    let config = ValidatorClientConfig::parse_args(&matches, &log)
        .expect("Unable to build a configuration for the account manager.");

    // Log configuration
    info!(log, "";
          "data_dir" => &config.data_dir.to_str());

    match matches.subcommand() {
        ("generate", Some(_)) => generate_random(&config, &log),
        ("generate_deterministic", Some(m)) => {
            if let Some(string) = m.value_of("validator index") {
                let i: usize = string.parse().expect("Invalid validator index");
                if let Some(string) = m.value_of("end validator index") {
                    let j: usize = string.parse().expect("Invalid end validator index");

                    let indices: Vec<usize> = (i..j).collect();
                    generate_deterministic_multiple(&indices, &config, &log)
                } else {
                    generate_deterministic(i, &config, &log)
                }
            }
        }
        _ => panic!(
            "The account manager must be run with a subcommand. See help for more information."
        ),
    }
}

fn generate_random(config: &ValidatorClientConfig, log: &slog::Logger) {
    save_key(&Keypair::random(), config, log)
}

fn generate_deterministic_multiple(
    validator_indices: &[usize],
    config: &ValidatorClientConfig,
    log: &slog::Logger,
) {
    for validator_index in validator_indices {
        generate_deterministic(*validator_index, config, log)
    }
}

fn generate_deterministic(
    validator_index: usize,
    config: &ValidatorClientConfig,
    log: &slog::Logger,
) {
    save_key(
        &generate_deterministic_keypair(validator_index),
        config,
        log,
    )
}

fn save_key(keypair: &Keypair, config: &ValidatorClientConfig, log: &slog::Logger) {
    let key_path: PathBuf = config
        .save_key(&keypair)
        .expect("Unable to save newly generated private key.");
    debug!(
        log,
        "Keypair generated {:?}, saved to: {:?}",
        keypair.identifier(),
        key_path.to_string_lossy()
    );
}
<|endoftext|>


<commit_before>use rand::{thread_rng, Rng};
use graphics::{Context, Transformed};
use opengl_graphics::{GlGraphics, Texture};

pub struct Player {
    x: u32,
    y: u32,
    animation_state: u32, // there is 6 animation frames.
    life: u32,
    texture: Texture,
}

impl Player {
    /// Spawn the player in a random location
    pub fn spawn() -> Player {
        let mut rng = thread_rng();
        let x: u32 = rng.gen_range(1, 9);
        let y: u32 = rng.gen_range(1, 9);

        // todo moves that in a drawing class
        // Textures
        let resources = find_folder::Search::ParentsThenKids(3, 3)
            .for_folder("resources").unwrap();

        let sprite = resources.join("Scavengers_SpriteSheet.png");
        // A texture to use with the image
        let texture = Texture::from_path(sprite).unwrap();

        Player {
            x: x,
            y: y,
            animation_state: 1,
            life: 100,
            texture: texture,
        }
    }

    /// Draw the player
    pub fn draw(&self, c: &Context, gl: &mut GlGraphics) {
        use graphics::*;
        let position_x = self.x as f64 * 64.0;
        let position_y = self.y as f64 * 64.0;
        let transform = c.transform.trans(position_x, position_y);
        Image::new()
            .src_rect([0, 0, 64, 64])
            .draw(&self.texture, default_draw_state(), transform, gl);
    }

    /// When the player get something to eat on the ground
    pub fn eat(&mut self) {
        self.life += 50
    }

    /// When the player takes some damage
    pub fn take_damage(&mut self, damage: u32) {
        self.life -= damage;
    }
}
<commit_msg>basic player model, naive sprite handling<commit_after>use rand::{thread_rng, Rng};
use find_folder;
use graphics::{Context, Transformed};
use opengl_graphics::{GlGraphics, Texture};

pub struct Player {
    x: u32,
    y: u32,
    animation_state: u32, // there is 6 animation frames.
    life: u32,
    texture: Texture,
}

impl Player {
    /// Spawn the player in a random location
    pub fn spawn() -> Player {
        let mut rng = thread_rng();
        let x: u32 = rng.gen_range(1, 9);
        let y: u32 = rng.gen_range(1, 9);

        // todo moves that in a drawing class
        // Textures
        let resources = find_folder::Search::ParentsThenKids(3, 3)
            .for_folder("resources").unwrap();

        let sprite = resources.join("Scavengers_SpriteSheet.png");
        // A texture to use with the image
        let texture = Texture::from_path(sprite).unwrap();

        Player {
            x: x,
            y: y,
            animation_state: 1,
            life: 100,
            texture: texture,
        }
    }

    /// Draw the player
    pub fn draw(&self, c: &Context, gl: &mut GlGraphics) {
        use graphics::*;
        let position_x = self.x as f64 * 64.0;
        let position_y = self.y as f64 * 64.0;
        let transform = c.transform.trans(position_x, position_y);
        Image::new()
            .src_rect([0, 0, 64, 64])
            .draw(&self.texture, default_draw_state(), transform, gl);
    }

    /// When the player get something to eat on the ground
    pub fn eat(&mut self) {
        self.life += 50
    }

    /// When the player takes some damage
    pub fn take_damage(&mut self, damage: u32) {
        self.life -= damage;
    }
}
<|endoftext|>