<commit_before>//! Rust bindings for the [http://openexr.com](OpenEXR) C++ library.
//!
//! OpenEXR is a bitmap image file format that can store high dynamic images
//! along with other arbitrary per-pixel data. It is used heavily in the VFX
//! and 3D animation industries.
//!
//! Although this wrapper differs a little in its API compared to the C++
//! library, it tried not to differ wildly.  Therefore the
//! [C++ OpenEXR documentation]
//! (https://github.com/openexr/openexr/tree/develop/OpenEXR/doc) is still
//! useful as an introduction and rough reference.  Moreover, the file format
//! itself is also documented there.
//!
//! # Examples
//!
//! Writing a scanline RGB file.
//!
//! ```no_run
//! use std::path::Path;
//! use openexr::{FrameBuffer, Header, ScanlineOutputFile, PixelType};
//!
//! // Pixel data for a 256x256 floating point RGB image.
//! let mut pixel_data = vec![(0.82f32, 1.78f32, 0.21f32); 256 * 256];
//!
//! // Create a file to write to.  The `Header` determines the properties of the
//! // file, like resolution and what channels it has.
//! let mut output_file = ScanlineOutputFile::new(
//!     Path::new("output_file.exr"),
//!     Header::new()
//!         .set_resolution(256, 256)
//!         .add_channel("R", PixelType::FLOAT)
//!         .add_channel("G", PixelType::FLOAT)
//!         .add_channel("B", PixelType::FLOAT)).unwrap();
//!
//! // The `FrameBuffer` points to and describes pixel data in memory. In this
//! // case, it points to `pixel_data` and says it has three channels: 'R', 'G',
//! // and 'B'.  The data type of the channels is inferred from `pixel_data`'s
//! // type.
//! //
//! // The `0.0`'s are fallback values for each channel in case of missing
//! // pixel data when reading from a file.  In this example they aren't used.
//! let mut fb = FrameBuffer::new(256, 256);
//! fb.insert_pixels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
//!
//! // Write pixel data to the file.  We pass our framebuffer to it so it knows
//! // what pixel data to write.
//! output_file.write_pixels(&mut fb).unwrap();
//! ```
//!
//! Reading an RGB file.
//!
//! ```no_run
//! use std::path::Path;
//! use openexr::{FrameBuffer, InputFile, PixelType};
//!
//! // Open the EXR file.
//! let input_file = InputFile::new(Path::new("input_file.exr")).unwrap();
//!
//! // Get the image dimensions, so we know how large of a buffer to make.
//! let window = input_file.header().data_window();
//! let width = window.max.x - window.min.x + 1;
//! let height = window.max.y - window.min.y + 1;
//!
//! // Make sure the channels we want exist in the file and are of the type we
//! // expect.  If you statically know the properties of the file you're
//! // loading, this isn't necessary.
//! for channel_name in ["R", "G", "B"].iter() {
//!     let channel = input_file
//!         .header()
//!         .get_channel(channel_name)
//!         .expect(&format!("Didn't find channel {}.", channel_name));
//!     assert!(channel.pixel_type == PixelType::FLOAT);
//! }
//!
//! // Space to read pixel data into.
//! let mut pixel_data = vec![(0.0f32, 0.0f32, 0.0f32); (width*height) as usize];
//!
//! // New scope because `FrameBuffer` mutably borrows `pixel_data`, so we need
//! // it to go out of scope before we can access our `pixel_data` again.
//! {
//!     // Create `FrameBuffer`.  Same drill as for output.
//!     let mut fb = FrameBuffer::new(width as usize, height as usize);
//!     fb.insert_pixels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
//!
//!     // Read in pixel data.
//!     input_file.read_pixels(&mut fb).unwrap();
//! }
//!
//! // The image data is now loaded into `pixel_data`.
//! ```

// #![warn(missing_docs)]

extern crate half;
extern crate libc;
extern crate openexr_sys;

mod cexr_type_aliases;
mod error;
mod frame_buffer;
mod input;
mod output;

use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use openexr_sys::*;

pub use cexr_type_aliases::*;
pub use error::*;
pub use frame_buffer::*;
pub use input::*;
pub use output::*;

// TODO: move Header to its own module once we can use
// `pub(crate)` on struct fields (should be in Rust 1.18).

/// File header of an OpenEXR file.
///
/// This represents the header of an OpenEXR file.  It contains attributes, channel
/// descriptions, image resolution information, etc.  It is used both for fetching
/// information about a loaded EXR file and for defining the header of a file to be
/// written.
///
/// # Examples
///
/// Creating a header for a file that will be written:
///
/// ```
/// use openexr::{Header, PixelType};
///
/// Header::new()
///     .set_resolution(1920, 1080)
///     .add_channel("R", PixelType::FLOAT)
///     .add_channel("G", PixelType::FLOAT)
///     .add_channel("B", PixelType::FLOAT);
/// ```
pub struct Header {
    handle: *mut CEXR_Header,
    owned: bool,
    _phantom: PhantomData<CEXR_Header>,
}

impl Header {
    /// Creates a new header.
    pub fn new() -> Self {
        // Create underlying C header
        let header = {
            let display_window = Box2i {
                min: CEXR_V2i { x: 0, y: 0 },
                max: CEXR_V2i { x: 1, y: 1 },
            };
            let data_window = display_window;
            let pixel_aspect_ratio = 1.0;
            let screen_window_center = CEXR_V2f { x: 0.0, y: 0.0 };
            let screen_window_width = 1.0;
            let line_order = LineOrder::INCREASING_Y;
            let compression = Compression::PIZ_COMPRESSION;
            let header = unsafe {
                CEXR_Header_new(&display_window,
                                &data_window,
                                pixel_aspect_ratio,
                                &screen_window_center,
                                screen_window_width,
                                line_order,
                                compression)
            };
            header
        };

        Self {
            handle: header,
            owned: true,
            _phantom: PhantomData,
        }
    }

    /// Sets the resolution.
    ///
    /// This is really just a shortcut for setting both the display window
    /// and data window to `(0, 0), (width-1, height-1)`.
    pub fn set_resolution(&mut self, width: u32, height: u32) -> &mut Self {
        let window = Box2i {
            min: CEXR_V2i { x: 0, y: 0 },
            max: CEXR_V2i {
                x: width as i32 - 1,
                y: height as i32 - 1,
            },
        };
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the display window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_display_window(&mut self, window: Box2i) -> &mut Self {
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        self
    }

    /// Sets the data window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_data_window(&mut self, window: Box2i) -> &mut Self {
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the pixel aspect ratio.
    pub fn set_pixel_aspect_ratio(&mut self, aspect_ratio: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_pixel_aspect_ratio(self.handle, aspect_ratio);
        }
        self
    }

    /// Sets the screen window center.
    pub fn set_screen_window_center(&mut self, center: (f32, f32)) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_center(self.handle,
                                                 CEXR_V2f {
                                                     x: center.0,
                                                     y: center.1,
                                                 });
        }
        self
    }

    /// Sets the screen window width.
    pub fn set_screen_window_width(&mut self, width: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_width(self.handle, width);
        }
        self
    }

    /// Sets the line order.
    pub fn set_line_order(&mut self, line_order: LineOrder) -> &mut Self {
        unsafe {
            CEXR_Header_set_line_order(self.handle, line_order);
        }
        self
    }

    /// Sets the compression mode.
    pub fn set_compression(&mut self, compression: Compression) -> &mut Self {
        unsafe {
            CEXR_Header_set_compression(self.handle, compression);
        }
        self
    }

    /// Adds a channel.
    ///
    /// This is a simplified version of `add_channel_detailed()`, using some reasonable
    /// defaults for the details.  Specifically: sampling is set to (1, 1)
    /// and p_linear is set to true.
    pub fn add_channel(&mut self, name: &str, pixel_type: PixelType) -> &mut Self {
        self.add_channel_detailed(name,
                                  Channel {
                                      pixel_type: pixel_type,
                                      x_sampling: 1,
                                      y_sampling: 1,
                                      p_linear: true,
                                  })
    }

    /// Adds a channel, specifying full details.
    pub fn add_channel_detailed(&mut self, name: &str, channel: Channel) -> &mut Self {
        let cname = CString::new(name.as_bytes()).unwrap();
        unsafe { CEXR_Header_insert_channel(self.handle, cname.as_ptr(), channel) };
        self
    }

    /// Access to the data window.
    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(self.handle) }
    }

    /// Access to the display window.
    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(self.handle) }
    }

    /// Returns an iterator over the channels in the header.
    pub fn channels<'a>(&'a self) -> ChannelIter<'a> {
        ChannelIter {
            iterator: unsafe { CEXR_Header_channel_list_iter(self.handle) },
            _phantom_1: PhantomData,
            _phantom_2: PhantomData,
        }
    }

    /// Access channels by name.
    pub fn get_channel<'a>(&'a self, name: &str) -> Option<&'a Channel> {
        let c_name = CString::new(name.as_bytes()).unwrap();
        let mut error_out = std::ptr::null();
        let mut out = std::ptr::null();
        if unsafe {
               CEXR_Header_get_channel(self.handle, c_name.as_ptr(), &mut out, &mut error_out)
           } == 0 {
            Some(unsafe { &(*out) })
        } else {
            None
        }
    }
}

impl Drop for Header {
    fn drop(&mut self) {
        if self.owned {
            unsafe { CEXR_Header_delete(self.handle) };
        }
    }
}

pub struct ChannelIter<'a> {
    iterator: *mut CEXR_ChannelListIter,
    _phantom_1: PhantomData<CEXR_ChannelListIter>,
    _phantom_2: PhantomData<&'a Header>,
}

impl<'a> Drop for ChannelIter<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_ChannelListIter_delete(self.iterator) };
    }
}

impl<'a> Iterator for ChannelIter<'a> {
    type Item = Result<(&'a str, Channel)>;
    fn next(&mut self) -> Option<Result<(&'a str, Channel)>> {
        let mut name = unsafe { std::mem::uninitialized() };
        let mut channel = unsafe { std::mem::uninitialized() };
        if unsafe { CEXR_ChannelListIter_next(self.iterator, &mut name, &mut channel) } {
            // TODO: use CStr::from_bytes_with_nul() instead to avoid memory unsafety
            // if the string is not nul terminated.
            let cname = unsafe { CStr::from_ptr(name) };
            let str_name = cname.to_str();
            if let Ok(n) = str_name {
                Some(Ok((n, channel)))
            } else {
                Some(Err(Error::Generic(format!("Invalid channel name: {:?}", cname))))
            }
        } else {
            None
        }
    }
}
<commit_msg>Silly mistake in the top-level documentation.<commit_after>//! Rust bindings for the [OpenEXR](http://openexr.com) C++ library.
//!
//! OpenEXR is a bitmap image file format that can store high dynamic images
//! along with other arbitrary per-pixel data. It is used heavily in the VFX
//! and 3D animation industries.
//!
//! Although this wrapper differs a little in its API compared to the C++
//! library, it tried not to differ wildly.  Therefore the
//! [C++ OpenEXR documentation]
//! (https://github.com/openexr/openexr/tree/develop/OpenEXR/doc) is still
//! useful as an introduction and rough reference.  Moreover, the file format
//! itself is also documented there.
//!
//! # Examples
//!
//! Writing a scanline RGB file.
//!
//! ```no_run
//! use std::path::Path;
//! use openexr::{FrameBuffer, Header, ScanlineOutputFile, PixelType};
//!
//! // Pixel data for a 256x256 floating point RGB image.
//! let mut pixel_data = vec![(0.82f32, 1.78f32, 0.21f32); 256 * 256];
//!
//! // Create a file to write to.  The `Header` determines the properties of the
//! // file, like resolution and what channels it has.
//! let mut output_file = ScanlineOutputFile::new(
//!     Path::new("output_file.exr"),
//!     Header::new()
//!         .set_resolution(256, 256)
//!         .add_channel("R", PixelType::FLOAT)
//!         .add_channel("G", PixelType::FLOAT)
//!         .add_channel("B", PixelType::FLOAT)).unwrap();
//!
//! // The `FrameBuffer` points to and describes pixel data in memory. In this
//! // case, it points to `pixel_data` and says it has three channels: 'R', 'G',
//! // and 'B'.  The data type of the channels is inferred from `pixel_data`'s
//! // type.
//! //
//! // The `0.0`'s are fallback values for each channel in case of missing
//! // pixel data when reading from a file.  In this example they aren't used.
//! let mut fb = FrameBuffer::new(256, 256);
//! fb.insert_pixels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
//!
//! // Write pixel data to the file.  We pass our framebuffer to it so it knows
//! // what pixel data to write.
//! output_file.write_pixels(&mut fb).unwrap();
//! ```
//!
//! Reading an RGB file.
//!
//! ```no_run
//! use std::path::Path;
//! use openexr::{FrameBuffer, InputFile, PixelType};
//!
//! // Open the EXR file.
//! let input_file = InputFile::new(Path::new("input_file.exr")).unwrap();
//!
//! // Get the image dimensions, so we know how large of a buffer to make.
//! let window = input_file.header().data_window();
//! let width = window.max.x - window.min.x + 1;
//! let height = window.max.y - window.min.y + 1;
//!
//! // Make sure the channels we want exist in the file and are of the type we
//! // expect.  If you statically know the properties of the file you're
//! // loading, this isn't necessary.
//! for channel_name in ["R", "G", "B"].iter() {
//!     let channel = input_file
//!         .header()
//!         .get_channel(channel_name)
//!         .expect(&format!("Didn't find channel {}.", channel_name));
//!     assert!(channel.pixel_type == PixelType::FLOAT);
//! }
//!
//! // Space to read pixel data into.
//! let mut pixel_data = vec![(0.0f32, 0.0f32, 0.0f32); (width*height) as usize];
//!
//! // New scope because `FrameBuffer` mutably borrows `pixel_data`, so we need
//! // it to go out of scope before we can access our `pixel_data` again.
//! {
//!     // Create `FrameBuffer`.  Same drill as for output.
//!     let mut fb = FrameBuffer::new(width as usize, height as usize);
//!     fb.insert_pixels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
//!
//!     // Read in pixel data.
//!     input_file.read_pixels(&mut fb).unwrap();
//! }
//!
//! // The image data is now loaded into `pixel_data`.
//! ```

// #![warn(missing_docs)]

extern crate half;
extern crate libc;
extern crate openexr_sys;

mod cexr_type_aliases;
mod error;
mod frame_buffer;
mod input;
mod output;

use std::ffi::{CStr, CString};
use std::marker::PhantomData;

use openexr_sys::*;

pub use cexr_type_aliases::*;
pub use error::*;
pub use frame_buffer::*;
pub use input::*;
pub use output::*;

// TODO: move Header to its own module once we can use
// `pub(crate)` on struct fields (should be in Rust 1.18).

/// File header of an OpenEXR file.
///
/// This represents the header of an OpenEXR file.  It contains attributes, channel
/// descriptions, image resolution information, etc.  It is used both for fetching
/// information about a loaded EXR file and for defining the header of a file to be
/// written.
///
/// # Examples
///
/// Creating a header for a file that will be written:
///
/// ```
/// use openexr::{Header, PixelType};
///
/// Header::new()
///     .set_resolution(1920, 1080)
///     .add_channel("R", PixelType::FLOAT)
///     .add_channel("G", PixelType::FLOAT)
///     .add_channel("B", PixelType::FLOAT);
/// ```
pub struct Header {
    handle: *mut CEXR_Header,
    owned: bool,
    _phantom: PhantomData<CEXR_Header>,
}

impl Header {
    /// Creates a new header.
    pub fn new() -> Self {
        // Create underlying C header
        let header = {
            let display_window = Box2i {
                min: CEXR_V2i { x: 0, y: 0 },
                max: CEXR_V2i { x: 1, y: 1 },
            };
            let data_window = display_window;
            let pixel_aspect_ratio = 1.0;
            let screen_window_center = CEXR_V2f { x: 0.0, y: 0.0 };
            let screen_window_width = 1.0;
            let line_order = LineOrder::INCREASING_Y;
            let compression = Compression::PIZ_COMPRESSION;
            let header = unsafe {
                CEXR_Header_new(&display_window,
                                &data_window,
                                pixel_aspect_ratio,
                                &screen_window_center,
                                screen_window_width,
                                line_order,
                                compression)
            };
            header
        };

        Self {
            handle: header,
            owned: true,
            _phantom: PhantomData,
        }
    }

    /// Sets the resolution.
    ///
    /// This is really just a shortcut for setting both the display window
    /// and data window to `(0, 0), (width-1, height-1)`.
    pub fn set_resolution(&mut self, width: u32, height: u32) -> &mut Self {
        let window = Box2i {
            min: CEXR_V2i { x: 0, y: 0 },
            max: CEXR_V2i {
                x: width as i32 - 1,
                y: height as i32 - 1,
            },
        };
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the display window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_display_window(&mut self, window: Box2i) -> &mut Self {
        unsafe {
            CEXR_Header_set_display_window(self.handle, window);
        }
        self
    }

    /// Sets the data window.
    ///
    /// For simple use-cases, it's better to use `set_resolution()` instead.
    pub fn set_data_window(&mut self, window: Box2i) -> &mut Self {
        unsafe {
            CEXR_Header_set_data_window(self.handle, window);
        }
        self
    }

    /// Sets the pixel aspect ratio.
    pub fn set_pixel_aspect_ratio(&mut self, aspect_ratio: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_pixel_aspect_ratio(self.handle, aspect_ratio);
        }
        self
    }

    /// Sets the screen window center.
    pub fn set_screen_window_center(&mut self, center: (f32, f32)) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_center(self.handle,
                                                 CEXR_V2f {
                                                     x: center.0,
                                                     y: center.1,
                                                 });
        }
        self
    }

    /// Sets the screen window width.
    pub fn set_screen_window_width(&mut self, width: f32) -> &mut Self {
        unsafe {
            CEXR_Header_set_screen_window_width(self.handle, width);
        }
        self
    }

    /// Sets the line order.
    pub fn set_line_order(&mut self, line_order: LineOrder) -> &mut Self {
        unsafe {
            CEXR_Header_set_line_order(self.handle, line_order);
        }
        self
    }

    /// Sets the compression mode.
    pub fn set_compression(&mut self, compression: Compression) -> &mut Self {
        unsafe {
            CEXR_Header_set_compression(self.handle, compression);
        }
        self
    }

    /// Adds a channel.
    ///
    /// This is a simplified version of `add_channel_detailed()`, using some reasonable
    /// defaults for the details.  Specifically: sampling is set to (1, 1)
    /// and p_linear is set to true.
    pub fn add_channel(&mut self, name: &str, pixel_type: PixelType) -> &mut Self {
        self.add_channel_detailed(name,
                                  Channel {
                                      pixel_type: pixel_type,
                                      x_sampling: 1,
                                      y_sampling: 1,
                                      p_linear: true,
                                  })
    }

    /// Adds a channel, specifying full details.
    pub fn add_channel_detailed(&mut self, name: &str, channel: Channel) -> &mut Self {
        let cname = CString::new(name.as_bytes()).unwrap();
        unsafe { CEXR_Header_insert_channel(self.handle, cname.as_ptr(), channel) };
        self
    }

    /// Access to the data window.
    pub fn data_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_data_window(self.handle) }
    }

    /// Access to the display window.
    pub fn display_window(&self) -> &Box2i {
        unsafe { &*CEXR_Header_display_window(self.handle) }
    }

    /// Returns an iterator over the channels in the header.
    pub fn channels<'a>(&'a self) -> ChannelIter<'a> {
        ChannelIter {
            iterator: unsafe { CEXR_Header_channel_list_iter(self.handle) },
            _phantom_1: PhantomData,
            _phantom_2: PhantomData,
        }
    }

    /// Access channels by name.
    pub fn get_channel<'a>(&'a self, name: &str) -> Option<&'a Channel> {
        let c_name = CString::new(name.as_bytes()).unwrap();
        let mut error_out = std::ptr::null();
        let mut out = std::ptr::null();
        if unsafe {
               CEXR_Header_get_channel(self.handle, c_name.as_ptr(), &mut out, &mut error_out)
           } == 0 {
            Some(unsafe { &(*out) })
        } else {
            None
        }
    }
}

impl Drop for Header {
    fn drop(&mut self) {
        if self.owned {
            unsafe { CEXR_Header_delete(self.handle) };
        }
    }
}

pub struct ChannelIter<'a> {
    iterator: *mut CEXR_ChannelListIter,
    _phantom_1: PhantomData<CEXR_ChannelListIter>,
    _phantom_2: PhantomData<&'a Header>,
}

impl<'a> Drop for ChannelIter<'a> {
    fn drop(&mut self) {
        unsafe { CEXR_ChannelListIter_delete(self.iterator) };
    }
}

impl<'a> Iterator for ChannelIter<'a> {
    type Item = Result<(&'a str, Channel)>;
    fn next(&mut self) -> Option<Result<(&'a str, Channel)>> {
        let mut name = unsafe { std::mem::uninitialized() };
        let mut channel = unsafe { std::mem::uninitialized() };
        if unsafe { CEXR_ChannelListIter_next(self.iterator, &mut name, &mut channel) } {
            // TODO: use CStr::from_bytes_with_nul() instead to avoid memory unsafety
            // if the string is not nul terminated.
            let cname = unsafe { CStr::from_ptr(name) };
            let str_name = cname.to_str();
            if let Ok(n) = str_name {
                Some(Ok((n, channel)))
            } else {
                Some(Err(Error::Generic(format!("Invalid channel name: {:?}", cname))))
            }
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Provides a way for shaders to access the content of buffers and images, or read arbitrary data.
//!
//! If you except vertex attributes, there are two ways in Vulkan to pass data to a shader:
//!
//! - You can pass a very small amount of data (only a guaranteed 128 bytes) through the *push
//!   constants* mechanism. Push constants are the fastest and easiest way to pass data.
//! - You can make your shader read from a buffer or an image by binding it to a *descriptor*.
//!
//! Here is an example fragment shader in GLSL that uses both:
//!
//! ```ignore
//! #version 450
//!
//! // This is a descriptor that contains a texture.
//! layout(set = 0, binding = 0) uniform sampler2D u_texture;
//!
//! layout(push_constant) uniform PushConstants {
//!     // This is a push constant.
//!     float opacity;
//! } push_constants;
//!
//! layout(location = 0) in vec2 v_tex_coords;
//! layout(location = 0) out vec4 f_output;
//!
//! void main() {
//!     f_output.rgb = texture(u_texture, v_tex_coords).rgb;
//!     f_output.a = push_constants.opacity;
//! }
//! ```
//!
//! # Descriptors
//!
//! In order to read the content of a buffer or an image from a shader, that buffer or image
//! must be put in a *descriptor*. Each descriptor contains one buffer or one image alongside with
//! the way that it can be accessed. A descriptor can also be an array, in which case it contains
//! multiple buffers or images with the same layout.
//!
//! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind
//! individual descriptors one by one, but you create then bind descriptor sets one by one. You are
//! therefore encouraged to put descriptors that are often used together in the same set.
//!
//! The layout of all the descriptors and the push constants used by all the stages of a graphics
//! or compute pipeline is grouped in a *pipeline layout* object.
//!
//! # Pipeline initialization
//!
//! When you build a pipeline object (a `GraphicsPipeline` or a `ComputePipeline`), you have to
//! pass a reference to a struct that implements the `PipelineLayoutRef` trait. This object will
//! describe to the Vulkan implementation the types and layouts of the descriptors and push
//! constants that are going to be accessed by the shaders of the pipeline.
//!
//! The `PipelineLayoutRef` trait is unsafe. You are encouraged not to implemented it yourself, but
//! instead use the `pipeline_layout!` macro, which will generate a struct that implements this
//! trait for you.
//!
//! Here is an example usage:
//!
//! ```ignore       // TODO: make it pass doctests
//! mod pipeline_layout {
//!     pipeline_layout!{
//!         push_constants: {
//!             opacity: f32
//!         },
//!         set0: {
//!             u_texture: CombinedImageSampler
//!         }
//!     }
//! }
//!
//! let _pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();
//! ```
//!
//! # When drawing
//!
//! When you call a function that adds a draw command to a command buffer, one of the parameters
//! corresponds to the list of descriptor sets to use, and another parameter contains the push
//! constants. Vulkano will check that what you passed is compatible with the pipeline layout that
//! you used when creating the pipeline.
//!
//! It is encouraged, but not mandatory, that the descriptor sets you pass when drawing were
//! created from the same pipeline layout as the one you create the graphics or compute pipeline
//! with.
//!
//! Descriptor sets have to be created in advance from a descriptor pool. You can use the same
//! descriptor set multiple time with multiple draw commands, and keep alive descriptor sets
//! between frames. Creating a descriptor set is quite cheap, so it won't kill your performances
//! to create new sets at each frame.
//!
//! TODO: talk about perfs of changing sets

pub use self::descriptor_set::DescriptorSet;
pub use self::pipeline_layout::PipelineLayoutRef;

pub mod descriptor;
pub mod descriptor_set;
pub mod pipeline_layout;
<commit_msg>Minor work on documentation<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Provides a way for shaders to access the content of buffers and images, or read arbitrary data.
//!
//! If you except vertex attributes, there are two ways in Vulkan to pass data to a shader:
//!
//! - You can pass a very small amount of data (only a guaranteed 128 bytes) through the *push
//!   constants* mechanism. Push constants are the fastest and easiest way to pass data.
//! - You can make your shader read from a buffer or an image by binding it to a *descriptor*.
//!
//! Here is an example fragment shader in GLSL that uses both:
//!
//! ```ignore
//! #version 450
//!
//! // This is a descriptor that contains a texture.
//! layout(set = 0, binding = 0) uniform sampler2D u_texture;
//!
//! layout(push_constant) uniform PushConstants {
//!     // This is a push constant.
//!     float opacity;
//! } push_constants;
//!
//! layout(location = 0) in vec2 v_tex_coords;
//! layout(location = 0) out vec4 f_output;
//!
//! void main() {
//!     f_output.rgb = texture(u_texture, v_tex_coords).rgb;
//!     f_output.a = push_constants.opacity;
//! }
//! ```
//!
//! # Descriptors
//!
//! In order to read the content of a buffer or an image from a shader, that buffer or image
//! must be put in a *descriptor*. Each descriptor contains one buffer or one image alongside with
//! the way that it can be accessed. A descriptor can also be an array, in which case it contains
//! multiple buffers or images with the same layout.
//!
//! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind
//! individual descriptors one by one, but you create then bind descriptor sets one by one. You are
//! therefore encouraged to put descriptors that are often used together in the same set.
//!
//! In order to pass descriptors to your shaders, you first have to create descriptor sets. To do
//! so, the easiest way is to use the `simple_descriptor_set!` macro.
//!
//! ```ignore
//! let set0 = simple_descriptor_set!(&graphics_pipeline, 0, {
//!     buffer1: &my_buffer1,
//!     buffer2: &my_buffer2,
//!     image1: &my_image,
//! });
//!
//! let set1 = simple_descriptor_set!(&graphics_pipeline, 1, {
//!     buffer3: &my_buffer3,
//! });
//! ```
//!
//! # When drawing
//!
//! When you call a function that adds a draw command to a command buffer, one of the parameters
//! corresponds to the list of descriptor sets to use, and another parameter contains the push
//! constants. Vulkano will check that what you passed is compatible with the layout of the
//! compute or graphics pipeline.
//!
//! TODO: talk about perfs of changing sets

pub use self::descriptor_set::DescriptorSet;
pub use self::pipeline_layout::PipelineLayoutRef;

pub mod descriptor;
pub mod descriptor_set;
pub mod pipeline_layout;
<|endoftext|>


<commit_before>extern crate libc;
// export it for now

use libc::{c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet};

pub struct TCPsocket {
    opaquePtr: *mut _TCPsocket,
}
pub struct SocketSet {
    opaquePtr: *mut _SDLNet_SocketSet,
}

pub fn init() -> () { unsafe { ffi::SDLNet_Init(); } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port)
    }
    if (result == 0){
        Some(address)
    } else {
        None
    }
}

pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port)
    }
    if (result == 0) {
        Some(address)
    } else {
        None
    }
}

pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn tcp_open(mut ip: IPaddress) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Open(&mut ip) }
    }
}

pub fn tcp_close(sock: TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaquePtr)
    }
}

pub fn tcp_accept(server: TCPsocket) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Accept(server.opaquePtr) }
    }
}

pub fn tcp_get_peer_address(sock: TCPsocket) -> Box<*mut IPaddress> {
    unsafe {
        Box::new(ffi::SDLNet_TCP_GetPeerAddress(sock.opaquePtr))
    }
}

pub fn tcp_send(sock: TCPsocket, data: &[u8]) -> () {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaquePtr, data.as_ptr() as *const c_void, data.len() as i32);
    }
}

pub fn tcp_recv(sock: TCPsocket, maxlen: i32) -> Vec<u8> {
    let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    unsafe {
        let read_ammnt = ffi::SDLNet_TCP_Recv(sock.opaquePtr, data.as_mut_ptr() as *mut c_void, data.len() as i32);
        data.set_len(read_ammnt as usize);
    }
    data
}

pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

pub fn free_socket_set(set: SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

pub fn tcp_add_socket(set: SocketSet, sock: TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_AddSocket(set.opaquePtr, sock.opaquePtr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn tcp_del_socket(set: SocketSet, sock: TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_DelSocket(set.opaquePtr, sock.opaquePtr)
    }
}

pub fn check_sockets(set: SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_SocketReady(sock.opaquePtr)
    }
}
<commit_msg>Changed function header for tcp_open temporarily.<commit_after>extern crate libc;
// export it for now

use libc::{c_int, c_char, c_void};
use std::ffi::CString;
use std::ptr;

pub mod ffi;
pub use ffi::{IPaddress, _TCPsocket, _SDLNet_SocketSet};

pub struct TCPsocket {
    opaquePtr: *mut _TCPsocket,
}
pub struct SocketSet {
    opaquePtr: *mut _SDLNet_SocketSet,
}

pub fn init() -> () { unsafe { ffi::SDLNet_Init(); } }
pub fn quit() -> () { unsafe { ffi::SDLNet_Quit(); } }
pub fn get_error() -> String {
    unsafe {
        let raw = &ffi::SDLNet_GetError();
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn become_host(port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0};
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, ptr::null() , port)
    }
    if (result == 0){
        Some(address)
    } else {
        None
    }
}

pub fn resolve_host(host: &str, port: u16) -> Option<ffi::IPaddress> {
    let mut address = ffi::IPaddress { host: 0, port: 0 };
    let mut result = 0;
    unsafe {
        result = ffi::SDLNet_ResolveHost(&mut address, CString::from_slice(host.as_bytes()).as_ptr(), port)
    }
    if (result == 0) {
        Some(address)
    } else {
        None
    }
}

pub fn resolve_ip(mut address: IPaddress) -> String {
    unsafe {
        let raw = &ffi::SDLNet_ResolveIP(&mut address);
        std::str::from_utf8(std::ffi::c_str_to_bytes(raw)).unwrap().to_string()
    }
}

pub fn tcp_open() -> TCPsocket {
    let mut address = ffi::IPaddress { host: 0, port: 0};

    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Open(&mut address) }
    }
}

pub fn tcp_close(sock: TCPsocket) -> () {
    unsafe {
        ffi::SDLNet_TCP_Close(sock.opaquePtr)
    }
}

pub fn tcp_accept(server: TCPsocket) -> TCPsocket {
    unsafe {
        TCPsocket { opaquePtr: ffi::SDLNet_TCP_Accept(server.opaquePtr) }
    }
}

pub fn tcp_get_peer_address(sock: TCPsocket) -> Box<*mut IPaddress> {
    unsafe {
        Box::new(ffi::SDLNet_TCP_GetPeerAddress(sock.opaquePtr))
    }
}

pub fn tcp_send(sock: TCPsocket, data: &[u8]) -> () {
    unsafe {
        ffi::SDLNet_TCP_Send(sock.opaquePtr, data.as_ptr() as *const c_void, data.len() as i32);
    }
}

pub fn tcp_recv(sock: TCPsocket, maxlen: i32) -> Vec<u8> {
    let mut data: Vec<u8> = Vec::with_capacity(maxlen as usize);
    unsafe {
        let read_ammnt = ffi::SDLNet_TCP_Recv(sock.opaquePtr, data.as_mut_ptr() as *mut c_void, data.len() as i32);
        data.set_len(read_ammnt as usize);
    }
    data
}

pub fn alloc_socket_set(maxsockets: i32) -> SocketSet {
    unsafe {
        SocketSet { opaquePtr: ffi::SDLNet_AllocSocketSet(maxsockets) }
    }
}

pub fn free_socket_set(set: SocketSet) -> () {
    unsafe {
        ffi::SDLNet_FreeSocketSet(set.opaquePtr);
    }
}

pub fn tcp_add_socket(set: SocketSet, sock: TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_AddSocket(set.opaquePtr, sock.opaquePtr)
    }
}

// Maybe should take in the box here as it may get deleted.... not sure
pub fn tcp_del_socket(set: SocketSet, sock: TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_TCP_DelSocket(set.opaquePtr, sock.opaquePtr)
    }
}

pub fn check_sockets(set: SocketSet, timeout: u32) -> i32 {
    unsafe {
        ffi::SDLNet_CheckSockets(set.opaquePtr, timeout)
    }
}

pub fn socket_ready(sock: TCPsocket) -> i32 {
    unsafe {
        ffi::SDLNet_SocketReady(sock.opaquePtr)
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A Glutin window back-end for the Piston game engine.

extern crate glutin;
extern crate gl;
extern crate window;
extern crate shader_version;
extern crate input;
#[macro_use]
extern crate quack;

// External crates.
use input::{
    keyboard,
    MouseButton,
    Button,
    Input,
    Motion,
};
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title,
    ExitOnEsc
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlutinWindow {
    /// The window.
    pub window: glutin::Window,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
    // The back-end does not remember the title.
    title: String,
    exit_on_esc: bool,
}

impl GlutinWindow {
    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlutinWindow {
        let (major, minor) = opengl.get_major_minor();
        let mut builder = glutin::WindowBuilder::new()
            .with_dimensions(settings.size[0], settings.size[1])
            .with_gl_version((major as u32, minor as u32))
            .with_title(settings.title.clone())
            .with_multisampling(settings.samples as u16);
        if settings.fullscreen {
            builder = builder.with_fullscreen(glutin::get_primary_monitor());
        }
        let window = builder
            .build().unwrap();
        unsafe { window.make_current(); }

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

        GlutinWindow {
            window: window,
            last_mouse_pos: None,
            title: settings.title,
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn poll_event(&mut self) -> Option<Input> {
        use glutin::Event as E;
        use input::Input;

        if let Some((x, y)) = self.last_mouse_pos {
            return Some(Input::Move(input::Motion::MouseRelative(x, y)));
        }

        match self.window.poll_events().next() {
            None => None,
            Some(E::Resized(w, h)) =>
                Some(Input::Resize(w, h)),
            Some(E::ReceivedCharacter(ch)) =>
                Some(Input::Text(ch.to_string())),
            Some(E::Focused(focused)) =>
                Some(Input::Focus(focused)),
            Some(E::KeyboardInput(glutin::ElementState::Pressed,
                _, Some(key))) =>
                Some(Input::Press(Button::Keyboard(map_key(key)))),
            Some(E::KeyboardInput(glutin::ElementState::Released,
                _, Some(key))) =>
                Some(Input::Release(Button::Keyboard(map_key(key)))),
            Some(E::MouseMoved((x, y))) => {
                self.last_mouse_pos = Some((x as f64, y as f64));
                Some(Input::Move(
                    Motion::MouseCursor(x as f64, y as f64)))
            }
            Some(E::MouseWheel(y)) =>
                Some(Input::Move(
                    Motion::MouseScroll(0.0, y as f64))),
            Some(E::MouseInput(glutin::ElementState::Pressed, button)) =>
                Some(Input::Press(Button::Mouse(map_mouse(button)))),
            Some(E::MouseInput(glutin::ElementState::Released, button)) =>
                Some(Input::Release(Button::Mouse(map_mouse(button)))),
            _ => None,
        }
    }

    /*
    fn capture_cursor(&mut self, enabled: bool) {

    }
    */
}

quack! {
obj: GlutinWindow[]
get:
    fn () -> Size [] {
        if let Some((w, h)) = obj.window.get_outer_size() {
            Size([w, h])
        } else {
            Size([0, 0])
        }
    }
    fn () -> ShouldClose [] { ShouldClose(obj.window.should_close()) }
    fn () -> DrawSize [] {
        if let Some((w, h)) = obj.window.get_inner_size() {
            DrawSize([w, h])
        } else {
            DrawSize([0, 0])
        }
    }
    fn () -> Title [] { Title(obj.title.clone()) }
    fn () -> ExitOnEsc [] { ExitOnEsc(obj.exit_on_esc) }
set:
    // fn (val: CaptureCursor) [] {}
    // fn (val: ShouldClose) [] {}
    fn (val: Title) [] {
        obj.title = val.0;
        obj.window.set_title(&obj.title[]);
    }
    fn (val: ExitOnEsc) [] { obj.exit_on_esc = val.0; }
action:
    fn (__: PollEvent) -> Option<Input> [] { obj.poll_event() }
    fn (__: SwapBuffers) -> () [] { obj.window.swap_buffers(); }
}

/// Maps Glutin's key to Piston's key.
pub fn map_key(keycode: glutin::VirtualKeyCode) -> keyboard::Key {
    use input::keyboard::Key;
    use glutin::VirtualKeyCode as K;

    match keycode {
        K::Key0 => Key::D0,
        K::Key1 => Key::D1,
        K::Key2 => Key::D2,
        K::Key3 => Key::D3,
        K::Key4 => Key::D4,
        K::Key5 => Key::D5,
        K::Key6 => Key::D6,
        K::Key7 => Key::D7,
        K::Key8 => Key::D8,
        K::Key9 => Key::D9,
        K::A => Key::A,
        K::B => Key::B,
        K::C => Key::C,
        K::D => Key::D,
        K::E => Key::E,
        K::F => Key::F,
        K::G => Key::G,
        K::H => Key::H,
        K::I => Key::I,
        K::J => Key::J,
        K::K => Key::K,
        K::L => Key::L,
        K::M => Key::M,
        K::N => Key::N,
        K::O => Key::O,
        K::P => Key::P,
        K::Q => Key::Q,
        K::R => Key::R,
        K::S => Key::S,
        K::T => Key::T,
        K::U => Key::U,
        K::V => Key::V,
        K::W => Key::W,
        K::X => Key::X,
        K::Y => Key::Y,
        K::Z => Key::Z,
        K::Apostrophe => Key::Unknown,
        K::Backslash => Key::Backslash,
        K::Back => Key::Backspace,
        // K::CapsLock => Key::CapsLock,
        K::Delete => Key::Delete,
        K::Comma => Key::Comma,
        K::Down => Key::Down,
        K::End => Key::End,
        K::Return => Key::Return,
        K::Equals => Key::Equals,
        K::Escape => Key::Escape,
        K::F1 => Key::F1,
        K::F2 => Key::F2,
        K::F3 => Key::F3,
        K::F4 => Key::F4,
        K::F5 => Key::F5,
        K::F6 => Key::F6,
        K::F7 => Key::F7,
        K::F8 => Key::F8,
        K::F9 => Key::F9,
        K::F10 => Key::F10,
        K::F11 => Key::F11,
        K::F12 => Key::F12,
        K::F13 => Key::F13,
        K::F14 => Key::F14,
        K::F15 => Key::F15,
        // K::F16 => Key::F16,
        // K::F17 => Key::F17,
        // K::F18 => Key::F18,
        // K::F19 => Key::F19,
        // K::F20 => Key::F20,
        // K::F21 => Key::F21,
        // K::F22 => Key::F22,
        // K::F23 => Key::F23,
        // K::F24 => Key::F24,
        // Possibly next code.
        // K::F25 => Key::Unknown,
        K::Numpad0 => Key::NumPad0,
        K::Numpad1 => Key::NumPad1,
        K::Numpad2 => Key::NumPad2,
        K::Numpad3 => Key::NumPad3,
        K::Numpad4 => Key::NumPad4,
        K::Numpad5 => Key::NumPad5,
        K::Numpad6 => Key::NumPad6,
        K::Numpad7 => Key::NumPad7,
        K::Numpad8 => Key::NumPad8,
        K::Numpad9 => Key::NumPad9,
        K::NumpadComma => Key::NumPadDecimal,
        K::Divide => Key::NumPadDivide,
        K::Multiply => Key::NumPadMultiply,
        K::Subtract => Key::NumPadMinus,
        K::Add => Key::NumPadPlus,
        K::NumpadEnter => Key::NumPadEnter,
        K::NumpadEquals => Key::NumPadEquals,
        K::LShift => Key::LShift,
        K::LControl => Key::LCtrl,
        K::LAlt => Key::LAlt,
        K::LMenu => Key::LGui,
        K::RShift => Key::RShift,
        K::RControl => Key::RCtrl,
        K::RAlt => Key::RAlt,
        K::RMenu => Key::RGui,
        // Map to backslash?
        // K::GraveAccent => Key::Unknown,
        K::Home => Key::Home,
        K::Insert => Key::Insert,
        K::Left => Key::Left,
        K::LBracket => Key::LeftBracket,
        // K::Menu => Key::Menu,
        K::Minus => Key::Minus,
        K::Numlock => Key::NumLockClear,
        K::PageDown => Key::PageDown,
        K::PageUp => Key::PageUp,
        K::Pause => Key::Pause,
        K::Period => Key::Period,
        // K::PrintScreen => Key::PrintScreen,
        K::Right => Key::Right,
        K::RBracket => Key::RightBracket,
        // K::ScrollLock => Key::ScrollLock,
        K::Semicolon => Key::Semicolon,
        K::Slash => Key::Slash,
        K::Space => Key::Space,
        K::Tab => Key::Tab,
        K::Up => Key::Up,
        // K::World1 => Key::Unknown,
        // K::World2 => Key::Unknown,
        _ => Key::Unknown,
    }
}

/// Maps Glutin's mouse button to Piston's mouse button.
pub fn map_mouse(mouse_button: glutin::MouseButton) -> MouseButton {
    use glutin::MouseButton as M;

    match mouse_button {
        M::Left => MouseButton::Left,
        M::Right => MouseButton::Right,
        M::Middle => MouseButton::Middle,
        M::Other(0) => MouseButton::X1,
        M::Other(1) => MouseButton::X2,
        M::Other(2) => MouseButton::Button6,
        M::Other(3) => MouseButton::Button7,
        M::Other(4) => MouseButton::Button8,
        _ => MouseButton::Unknown
    }
}
<commit_msg>set last_mouse_pos to None before returning MouseRelative event<commit_after>#![deny(missing_docs)]

//! A Glutin window back-end for the Piston game engine.

extern crate glutin;
extern crate gl;
extern crate window;
extern crate shader_version;
extern crate input;
#[macro_use]
extern crate quack;

// External crates.
use input::{
    keyboard,
    MouseButton,
    Button,
    Input,
    Motion,
};
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title,
    ExitOnEsc
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlutinWindow {
    /// The window.
    pub window: glutin::Window,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
    // The back-end does not remember the title.
    title: String,
    exit_on_esc: bool,
}

impl GlutinWindow {
    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlutinWindow {
        let (major, minor) = opengl.get_major_minor();
        let mut builder = glutin::WindowBuilder::new()
            .with_dimensions(settings.size[0], settings.size[1])
            .with_gl_version((major as u32, minor as u32))
            .with_title(settings.title.clone())
            .with_multisampling(settings.samples as u16);
        if settings.fullscreen {
            builder = builder.with_fullscreen(glutin::get_primary_monitor());
        }
        let window = builder
            .build().unwrap();
        unsafe { window.make_current(); }

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

        GlutinWindow {
            window: window,
            last_mouse_pos: None,
            title: settings.title,
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn poll_event(&mut self) -> Option<Input> {
        use glutin::Event as E;
        use input::Input;

        if let Some((x, y)) = self.last_mouse_pos {
            self.last_mouse_pos = None;
            return Some(Input::Move(input::Motion::MouseRelative(x, y)));
        }

        match self.window.poll_events().next() {
            None => None,
            Some(E::Resized(w, h)) =>
                Some(Input::Resize(w, h)),
            Some(E::ReceivedCharacter(ch)) =>
                Some(Input::Text(ch.to_string())),
            Some(E::Focused(focused)) =>
                Some(Input::Focus(focused)),
            Some(E::KeyboardInput(glutin::ElementState::Pressed,
                _, Some(key))) =>
                Some(Input::Press(Button::Keyboard(map_key(key)))),
            Some(E::KeyboardInput(glutin::ElementState::Released,
                _, Some(key))) =>
                Some(Input::Release(Button::Keyboard(map_key(key)))),
            Some(E::MouseMoved((x, y))) => {
                self.last_mouse_pos = Some((x as f64, y as f64));
                Some(Input::Move(
                    Motion::MouseCursor(x as f64, y as f64)))
            }
            Some(E::MouseWheel(y)) =>
                Some(Input::Move(
                    Motion::MouseScroll(0.0, y as f64))),
            Some(E::MouseInput(glutin::ElementState::Pressed, button)) =>
                Some(Input::Press(Button::Mouse(map_mouse(button)))),
            Some(E::MouseInput(glutin::ElementState::Released, button)) =>
                Some(Input::Release(Button::Mouse(map_mouse(button)))),
            _ => None,
        }
    }

    /*
    fn capture_cursor(&mut self, enabled: bool) {

    }
    */
}

quack! {
obj: GlutinWindow[]
get:
    fn () -> Size [] {
        if let Some((w, h)) = obj.window.get_outer_size() {
            Size([w, h])
        } else {
            Size([0, 0])
        }
    }
    fn () -> ShouldClose [] { ShouldClose(obj.window.should_close()) }
    fn () -> DrawSize [] {
        if let Some((w, h)) = obj.window.get_inner_size() {
            DrawSize([w, h])
        } else {
            DrawSize([0, 0])
        }
    }
    fn () -> Title [] { Title(obj.title.clone()) }
    fn () -> ExitOnEsc [] { ExitOnEsc(obj.exit_on_esc) }
set:
    // fn (val: CaptureCursor) [] {}
    // fn (val: ShouldClose) [] {}
    fn (val: Title) [] {
        obj.title = val.0;
        obj.window.set_title(&obj.title[]);
    }
    fn (val: ExitOnEsc) [] { obj.exit_on_esc = val.0; }
action:
    fn (__: PollEvent) -> Option<Input> [] { obj.poll_event() }
    fn (__: SwapBuffers) -> () [] { obj.window.swap_buffers(); }
}

/// Maps Glutin's key to Piston's key.
pub fn map_key(keycode: glutin::VirtualKeyCode) -> keyboard::Key {
    use input::keyboard::Key;
    use glutin::VirtualKeyCode as K;

    match keycode {
        K::Key0 => Key::D0,
        K::Key1 => Key::D1,
        K::Key2 => Key::D2,
        K::Key3 => Key::D3,
        K::Key4 => Key::D4,
        K::Key5 => Key::D5,
        K::Key6 => Key::D6,
        K::Key7 => Key::D7,
        K::Key8 => Key::D8,
        K::Key9 => Key::D9,
        K::A => Key::A,
        K::B => Key::B,
        K::C => Key::C,
        K::D => Key::D,
        K::E => Key::E,
        K::F => Key::F,
        K::G => Key::G,
        K::H => Key::H,
        K::I => Key::I,
        K::J => Key::J,
        K::K => Key::K,
        K::L => Key::L,
        K::M => Key::M,
        K::N => Key::N,
        K::O => Key::O,
        K::P => Key::P,
        K::Q => Key::Q,
        K::R => Key::R,
        K::S => Key::S,
        K::T => Key::T,
        K::U => Key::U,
        K::V => Key::V,
        K::W => Key::W,
        K::X => Key::X,
        K::Y => Key::Y,
        K::Z => Key::Z,
        K::Apostrophe => Key::Unknown,
        K::Backslash => Key::Backslash,
        K::Back => Key::Backspace,
        // K::CapsLock => Key::CapsLock,
        K::Delete => Key::Delete,
        K::Comma => Key::Comma,
        K::Down => Key::Down,
        K::End => Key::End,
        K::Return => Key::Return,
        K::Equals => Key::Equals,
        K::Escape => Key::Escape,
        K::F1 => Key::F1,
        K::F2 => Key::F2,
        K::F3 => Key::F3,
        K::F4 => Key::F4,
        K::F5 => Key::F5,
        K::F6 => Key::F6,
        K::F7 => Key::F7,
        K::F8 => Key::F8,
        K::F9 => Key::F9,
        K::F10 => Key::F10,
        K::F11 => Key::F11,
        K::F12 => Key::F12,
        K::F13 => Key::F13,
        K::F14 => Key::F14,
        K::F15 => Key::F15,
        // K::F16 => Key::F16,
        // K::F17 => Key::F17,
        // K::F18 => Key::F18,
        // K::F19 => Key::F19,
        // K::F20 => Key::F20,
        // K::F21 => Key::F21,
        // K::F22 => Key::F22,
        // K::F23 => Key::F23,
        // K::F24 => Key::F24,
        // Possibly next code.
        // K::F25 => Key::Unknown,
        K::Numpad0 => Key::NumPad0,
        K::Numpad1 => Key::NumPad1,
        K::Numpad2 => Key::NumPad2,
        K::Numpad3 => Key::NumPad3,
        K::Numpad4 => Key::NumPad4,
        K::Numpad5 => Key::NumPad5,
        K::Numpad6 => Key::NumPad6,
        K::Numpad7 => Key::NumPad7,
        K::Numpad8 => Key::NumPad8,
        K::Numpad9 => Key::NumPad9,
        K::NumpadComma => Key::NumPadDecimal,
        K::Divide => Key::NumPadDivide,
        K::Multiply => Key::NumPadMultiply,
        K::Subtract => Key::NumPadMinus,
        K::Add => Key::NumPadPlus,
        K::NumpadEnter => Key::NumPadEnter,
        K::NumpadEquals => Key::NumPadEquals,
        K::LShift => Key::LShift,
        K::LControl => Key::LCtrl,
        K::LAlt => Key::LAlt,
        K::LMenu => Key::LGui,
        K::RShift => Key::RShift,
        K::RControl => Key::RCtrl,
        K::RAlt => Key::RAlt,
        K::RMenu => Key::RGui,
        // Map to backslash?
        // K::GraveAccent => Key::Unknown,
        K::Home => Key::Home,
        K::Insert => Key::Insert,
        K::Left => Key::Left,
        K::LBracket => Key::LeftBracket,
        // K::Menu => Key::Menu,
        K::Minus => Key::Minus,
        K::Numlock => Key::NumLockClear,
        K::PageDown => Key::PageDown,
        K::PageUp => Key::PageUp,
        K::Pause => Key::Pause,
        K::Period => Key::Period,
        // K::PrintScreen => Key::PrintScreen,
        K::Right => Key::Right,
        K::RBracket => Key::RightBracket,
        // K::ScrollLock => Key::ScrollLock,
        K::Semicolon => Key::Semicolon,
        K::Slash => Key::Slash,
        K::Space => Key::Space,
        K::Tab => Key::Tab,
        K::Up => Key::Up,
        // K::World1 => Key::Unknown,
        // K::World2 => Key::Unknown,
        _ => Key::Unknown,
    }
}

/// Maps Glutin's mouse button to Piston's mouse button.
pub fn map_mouse(mouse_button: glutin::MouseButton) -> MouseButton {
    use glutin::MouseButton as M;

    match mouse_button {
        M::Left => MouseButton::Left,
        M::Right => MouseButton::Right,
        M::Middle => MouseButton::Middle,
        M::Other(0) => MouseButton::X1,
        M::Other(1) => MouseButton::X2,
        M::Other(2) => MouseButton::Button6,
        M::Other(3) => MouseButton::Button7,
        M::Other(4) => MouseButton::Button8,
        _ => MouseButton::Unknown
    }
}
<|endoftext|>


<commit_before>extern crate cslice;

#[doc(hidden)]
pub extern crate libc;

#[doc(hidden)]
pub extern crate libcruby_sys as sys;
// pub use rb;

use std::ffi::CString;
use sys::VALUE;

mod macros;
mod class_definition;
mod coercions;

pub use coercions::*;

pub use class_definition::{ClassDefinition, MethodDefinition};

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Class(VALUE);

impl Class {
    pub fn inner(&self) -> VALUE {
        self.0
    }
}

pub trait RubyMethod {
    fn install(self, class: VALUE, name: &str);
}

impl RubyMethod for extern "C" fn(VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &str) {
        unsafe {
            sys::rb_define_method(
                class,
                CString::new(name).unwrap().as_ptr(),
                self as *const libc::c_void,
                0
            );
        }
    }
}

impl RubyMethod for extern "C" fn(VALUE, VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &str) {
        unsafe {
            sys::rb_define_method(
                class,
                CString::new(name).unwrap().as_ptr(),
                self as *const libc::c_void,
                1
            );
        }
    }
}

#[allow(non_snake_case)]
#[inline]
fn ObjectClass() -> Class {
    Class(unsafe { sys::rb_cObject })
}

impl Class {
    pub fn new(name: &str) -> Class {
        ObjectClass().subclass(name)
    }

    pub fn subclass(&self, name: &str) -> Class {
        unsafe {
            Class(sys::rb_define_class(CString::new(name).unwrap().as_ptr(), self.0))
        }
    }

    pub fn define_method<T: RubyMethod>(&self, name: &str, method: T) {
        method.install(self.0, name);
    }
}

pub fn inspect(val: VALUE) -> String {
    unsafe { CheckedValue::<String>::new(sys::rb_inspect(val)).to_rust() }
}

pub type Metadata = ::VALUE;

#[derive(Copy, Clone, Debug)]
pub struct ExceptionInfo {
    pub exception: Class,
    pub message: VALUE
}

impl ExceptionInfo {
    pub fn with_message<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eRuntimeError }),
            message: string.to_ruby(),
        }
    }

    pub fn type_error<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eTypeError }),
            message: string.to_ruby(),
        }
    }

    pub fn from_any(any: Box<std::any::Any>) -> ExceptionInfo {
        match any.downcast_ref::<ExceptionInfo>() {
            Some(e) => *e,
            None => {
                match any.downcast_ref::<&'static str>() {
                    Some(e) => ExceptionInfo::with_message(e.to_string()),
                    None => {
                        match any.downcast_ref::<String>() {
                            Some(e) => ExceptionInfo::with_message(e.as_str()),
                            None => ExceptionInfo::with_message(format!("Unknown Error; err={:?}", any)),
                        }
                    }
                }
            }
        }
    }

    pub fn message(&self) -> VALUE {
        self.message
    }

    pub fn raise(&self) -> ! {
        unsafe {
            sys::rb_raise(self.exception.0,
                          sys::SPRINTF_TO_S,
                          self.message);
        }
    }
}

unsafe impl Send for ExceptionInfo {}
unsafe impl Sync for ExceptionInfo {}
<commit_msg>Fewer allocations by making function signatures take `&CStr`s.<commit_after>extern crate cslice;

#[doc(hidden)]
pub extern crate libc;

#[doc(hidden)]
pub extern crate libcruby_sys as sys;
// pub use rb;

use std::ffi::CStr;
use sys::VALUE;

mod macros;
mod class_definition;
mod coercions;

pub use coercions::*;

pub use class_definition::{ClassDefinition, MethodDefinition};

#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Class(VALUE);

impl Class {
    pub fn inner(&self) -> VALUE {
        self.0
    }
}

pub trait RubyMethod {
    fn install(self, class: VALUE, name: &CStr);
}

impl RubyMethod for extern "C" fn(VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &CStr) {
        unsafe {
            sys::rb_define_method(
                class,
                name.as_ptr(),
                self as *const libc::c_void,
                0
            );
        }
    }
}

impl RubyMethod for extern "C" fn(VALUE, VALUE) -> VALUE {
    fn install(self, class: VALUE, name: &CStr) {
        unsafe {
            sys::rb_define_method(
                class,
                name.as_ptr(),
                self as *const libc::c_void,
                1
            );
        }
    }
}

#[allow(non_snake_case)]
#[inline]
fn ObjectClass() -> Class {
    Class(unsafe { sys::rb_cObject })
}

impl Class {
    pub fn new(name: &CStr) -> Class {
        ObjectClass().subclass(name)
    }

    pub fn subclass(&self, name: &CStr) -> Class {
        unsafe {
            Class(sys::rb_define_class(name.as_ptr(), self.0))
        }
    }

    pub fn define_method<T: RubyMethod>(&self, name: &CStr, method: T) {
        method.install(self.0, name);
    }
}

pub fn inspect(val: VALUE) -> String {
    unsafe { CheckedValue::<String>::new(sys::rb_inspect(val)).to_rust() }
}

pub type Metadata = ::VALUE;

#[derive(Copy, Clone, Debug)]
pub struct ExceptionInfo {
    pub exception: Class,
    pub message: VALUE
}

impl ExceptionInfo {
    pub fn with_message<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eRuntimeError }),
            message: string.to_ruby(),
        }
    }

    pub fn type_error<T: ToRuby>(string: T) -> ExceptionInfo {
        ExceptionInfo {
            exception: Class(unsafe { sys::rb_eTypeError }),
            message: string.to_ruby(),
        }
    }

    pub fn from_any(any: Box<std::any::Any>) -> ExceptionInfo {
        match any.downcast_ref::<ExceptionInfo>() {
            Some(e) => *e,
            None => {
                match any.downcast_ref::<&'static str>() {
                    Some(e) => ExceptionInfo::with_message(e.to_string()),
                    None => {
                        match any.downcast_ref::<String>() {
                            Some(e) => ExceptionInfo::with_message(e.as_str()),
                            None => ExceptionInfo::with_message(format!("Unknown Error; err={:?}", any)),
                        }
                    }
                }
            }
        }
    }

    pub fn message(&self) -> VALUE {
        self.message
    }

    pub fn raise(&self) -> ! {
        unsafe {
            sys::rb_raise(self.exception.0,
                          sys::SPRINTF_TO_S,
                          self.message);
        }
    }
}

unsafe impl Send for ExceptionInfo {}
unsafe impl Sync for ExceptionInfo {}
<|endoftext|>