Merge pull request #173 from tomaka/change-builder-attribs

Finalize window building API
This commit is contained in:
tomaka 2014-12-31 07:49:44 +01:00
commit 4d5e39f436
8 changed files with 131 additions and 61 deletions

View file

@ -7,8 +7,7 @@ use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton::LeftMouseButton;
#[cfg(feature = "headless")]
use HeadlessRendererBuilder;
use BuilderAttribs;
pub struct Window {
display: ffi::egl::types::EGLDisplay,
@ -45,7 +44,7 @@ pub struct HeadlessContext(int);
#[cfg(feature = "headless")]
impl HeadlessContext {
/// See the docs in the crate root file.
pub fn new(_builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> {
pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
unimplemented!()
}
@ -66,7 +65,7 @@ unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}
impl Window {
pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> {
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
use std::{mem, ptr};
if builder.sharing.is_some() {

View file

@ -70,12 +70,14 @@ pub struct MonitorID(winimpl::MonitorID);
#[deriving(Clone, Show, PartialEq, Eq)]
pub enum CreationError {
OsError(String),
NotSupported,
}
impl std::error::Error for CreationError {
fn description(&self) -> &str {
match self {
&CreationError::OsError(ref text) => text.as_slice(),
&CreationError::NotSupported => "Some of the requested attributes are not supported",
}
}
}
@ -92,7 +94,14 @@ pub enum Api {
/// Object that allows you to build windows.
#[cfg(feature = "window")]
pub struct WindowBuilder<'a> {
sharing: Option<&'a Window>,
attribs: BuilderAttribs<'a>
}
/// Attributes
struct BuilderAttribs<'a> {
headless: bool,
strict: bool,
sharing: Option<&'a winimpl::Window>,
dimensions: Option<(uint, uint)>,
title: String,
monitor: Option<winimpl::MonitorID>,
@ -101,13 +110,18 @@ pub struct WindowBuilder<'a> {
vsync: bool,
visible: bool,
multisampling: Option<u16>,
depth_bits: Option<u8>,
stencil_bits: Option<u8>,
color_bits: Option<u8>,
alpha_bits: Option<u8>,
stereoscopy: bool,
}
#[cfg(feature = "window")]
impl<'a> WindowBuilder<'a> {
/// Initializes a new `WindowBuilder` with default values.
pub fn new() -> WindowBuilder<'a> {
WindowBuilder {
impl BuilderAttribs<'static> {
fn new() -> BuilderAttribs<'static> {
BuilderAttribs {
headless: false,
strict: false,
sharing: None,
dimensions: None,
title: "glutin window".to_string(),
@ -117,6 +131,21 @@ impl<'a> WindowBuilder<'a> {
vsync: false,
visible: true,
multisampling: None,
depth_bits: None,
stencil_bits: None,
color_bits: None,
alpha_bits: None,
stereoscopy: false,
}
}
}
#[cfg(feature = "window")]
impl<'a> WindowBuilder<'a> {
/// Initializes a new `WindowBuilder` with default values.
pub fn new() -> WindowBuilder<'a> {
WindowBuilder {
attribs: BuilderAttribs::new(),
}
}
@ -124,13 +153,13 @@ impl<'a> WindowBuilder<'a> {
///
/// Width and height are in pixels.
pub fn with_dimensions(mut self, width: uint, height: uint) -> WindowBuilder<'a> {
self.dimensions = Some((width, height));
self.attribs.dimensions = Some((width, height));
self
}
/// Requests a specific title for the window.
pub fn with_title(mut self, title: String) -> WindowBuilder<'a> {
self.title = title;
self.attribs.title = title;
self
}
@ -139,7 +168,7 @@ impl<'a> WindowBuilder<'a> {
/// If you don't specify dimensions for the window, it will match the monitor's.
pub fn with_fullscreen(mut self, monitor: MonitorID) -> WindowBuilder<'a> {
let MonitorID(monitor) = monitor;
self.monitor = Some(monitor);
self.attribs.monitor = Some(monitor);
self
}
@ -147,7 +176,7 @@ impl<'a> WindowBuilder<'a> {
///
/// There are some exceptions, like FBOs or VAOs. See the OpenGL documentation.
pub fn with_shared_lists(mut self, other: &'a Window) -> WindowBuilder<'a> {
self.sharing = Some(other);
self.attribs.sharing = Some(&other.window);
self
}
@ -156,7 +185,7 @@ impl<'a> WindowBuilder<'a> {
/// Version is a (major, minor) pair. For example to request OpenGL 3.3
/// you would pass `(3, 3)`.
pub fn with_gl_version(mut self, version: (uint, uint)) -> WindowBuilder<'a> {
self.gl_version = Some(version);
self.attribs.gl_version = Some(version);
self
}
@ -165,19 +194,19 @@ impl<'a> WindowBuilder<'a> {
/// The default value for this flag is `cfg!(ndebug)`, which means that it's enabled
/// when you run `cargo build` and disabled when you run `cargo build --release`.
pub fn with_gl_debug_flag(mut self, flag: bool) -> WindowBuilder<'a> {
self.gl_debug = flag;
self.attribs.gl_debug = flag;
self
}
/// Requests that the window has vsync enabled.
pub fn with_vsync(mut self) -> WindowBuilder<'a> {
self.vsync = true;
self.attribs.vsync = true;
self
}
/// Sets whether the window will be initially hidden or visible.
pub fn with_visibility(mut self, visible: bool) -> WindowBuilder<'a> {
self.visible = visible;
self.attribs.visible = visible;
self
}
@ -189,7 +218,32 @@ impl<'a> WindowBuilder<'a> {
pub fn with_multisampling(mut self, samples: u16) -> WindowBuilder<'a> {
use std::num::UnsignedInt;
assert!(samples.is_power_of_two());
self.multisampling = Some(samples);
self.attribs.multisampling = Some(samples);
self
}
/// Sets the number of bits in the depth buffer.
pub fn with_depth_buffer(mut self, bits: u8) -> WindowBuilder<'a> {
self.attribs.depth_bits = Some(bits);
self
}
/// Sets the number of bits in the stencil buffer.
pub fn with_stencil_buffer(mut self, bits: u8) -> WindowBuilder<'a> {
self.attribs.stencil_bits = Some(bits);
self
}
/// Sets the number of bits in the color buffer.
pub fn with_pixel_format(mut self, color_bits: u8, alpha_bits: u8) -> WindowBuilder<'a> {
self.attribs.color_bits = Some(color_bits);
self.attribs.alpha_bits = Some(alpha_bits);
self
}
/// Request the backend to be stereoscopic.
pub fn with_stereoscopy(mut self) -> WindowBuilder<'a> {
self.attribs.stereoscopy = true;
self
}
@ -199,26 +253,33 @@ impl<'a> WindowBuilder<'a> {
/// out of memory, etc.
pub fn build(mut self) -> Result<Window, CreationError> {
// resizing the window to the dimensions of the monitor when fullscreen
if self.dimensions.is_none() && self.monitor.is_some() {
self.dimensions = Some(self.monitor.as_ref().unwrap().get_dimensions())
if self.attribs.dimensions.is_none() && self.attribs.monitor.is_some() {
self.attribs.dimensions = Some(self.attribs.monitor.as_ref().unwrap().get_dimensions())
}
// default dimensions
if self.dimensions.is_none() {
self.dimensions = Some((1024, 768));
if self.attribs.dimensions.is_none() {
self.attribs.dimensions = Some((1024, 768));
}
// building
winimpl::Window::new(self).map(|w| Window { window: w })
winimpl::Window::new(self.attribs).map(|w| Window { window: w })
}
/// Builds the window.
///
/// The context is build in a *strict* way. That means that if the backend couldn't give
/// you what you requested, an `Err` will be returned.
pub fn build_strict(mut self) -> Result<Window, CreationError> {
self.attribs.strict = true;
self.build()
}
}
/// Object that allows you to build headless contexts.
#[cfg(feature = "headless")]
pub struct HeadlessRendererBuilder {
dimensions: (uint, uint),
gl_version: Option<(uint, uint)>,
gl_debug: bool,
attribs: BuilderAttribs<'static>,
}
#[cfg(feature = "headless")]
@ -226,9 +287,11 @@ impl HeadlessRendererBuilder {
/// Initializes a new `HeadlessRendererBuilder` with default values.
pub fn new(width: uint, height: uint) -> HeadlessRendererBuilder {
HeadlessRendererBuilder {
dimensions: (width, height),
gl_version: None,
gl_debug: cfg!(ndebug),
attribs: BuilderAttribs {
headless: true,
dimensions: Some((width, height)),
.. BuilderAttribs::new()
},
}
}
@ -237,7 +300,7 @@ impl HeadlessRendererBuilder {
/// Version is a (major, minor) pair. For example to request OpenGL 3.3
/// you would pass `(3, 3)`.
pub fn with_gl_version(mut self, version: (uint, uint)) -> HeadlessRendererBuilder {
self.gl_version = Some(version);
self.attribs.gl_version = Some(version);
self
}
@ -246,7 +309,7 @@ impl HeadlessRendererBuilder {
/// The default value for this flag is `cfg!(ndebug)`, which means that it's enabled
/// when you run `cargo build` and disabled when you run `cargo build --release`.
pub fn with_gl_debug_flag(mut self, flag: bool) -> HeadlessRendererBuilder {
self.gl_debug = flag;
self.attribs.gl_debug = flag;
self
}
@ -255,7 +318,16 @@ impl HeadlessRendererBuilder {
/// Error should be very rare and only occur in case of permission denied, incompatible system,
/// out of memory, etc.
pub fn build(self) -> Result<HeadlessContext, CreationError> {
winimpl::HeadlessContext::new(self).map(|w| HeadlessContext { context: w })
winimpl::HeadlessContext::new(self.attribs).map(|w| HeadlessContext { context: w })
}
/// Builds the headless context.
///
/// The context is build in a *strict* way. That means that if the backend couldn't give
/// you what you requested, an `Err` will be returned.
pub fn build_strict(mut self) -> Result<HeadlessContext, CreationError> {
self.attribs.strict = true;
self.build()
}
}

View file

@ -1,6 +1,6 @@
use CreationError;
use CreationError::OsError;
use HeadlessRendererBuilder;
use BuilderAttribs;
use libc;
use std::ptr;
@ -30,7 +30,7 @@ pub struct HeadlessContext {
}
impl HeadlessContext {
pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> {
pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
let (width, height) = builder.dimensions;
let context = unsafe {
let attributes = [

View file

@ -5,8 +5,7 @@ use {CreationError, Event};
use CreationError::OsError;
use libc;
#[cfg(feature = "window")]
use WindowBuilder;
use BuilderAttribs;
use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair};
use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar};
@ -63,7 +62,7 @@ pub struct Window {
#[cfg(feature = "window")]
impl Window {
pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> {
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
if builder.sharing.is_some() {
unimplemented!()
}

View file

@ -3,11 +3,7 @@ use std::ptr;
use libc;
use {CreationError, Event};
#[cfg(feature = "window")]
use WindowBuilder;
#[cfg(feature = "headless")]
use HeadlessRendererBuilder;
use BuilderAttribs;
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
@ -19,15 +15,13 @@ mod init;
mod monitor;
///
#[cfg(feature = "headless")]
pub struct HeadlessContext(Window);
#[cfg(feature = "headless")]
impl HeadlessContext {
/// See the docs in the crate root file.
pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> {
let HeadlessRendererBuilder { dimensions, gl_version, gl_debug } = builder;
init::new_window(Some(dimensions), "".to_string(), None, gl_version, gl_debug, false, true,
pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
let BuilderAttribs { dimensions, gl_version, gl_debug, .. } = builder;
init::new_window(dimensions, "".to_string(), None, gl_version, gl_debug, false, true,
None, None)
.map(|w| HeadlessContext(w))
}
@ -83,14 +77,13 @@ pub struct Window {
unsafe impl Send for Window {}
unsafe impl Sync for Window {}
#[cfg(feature = "window")]
impl Window {
/// See the docs in the crate root file.
pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> {
let WindowBuilder { dimensions, title, monitor, gl_version,
gl_debug, vsync, visible, sharing, multisampling } = builder;
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
let BuilderAttribs { dimensions, title, monitor, gl_version,
gl_debug, vsync, visible, sharing, multisampling, .. } = builder;
init::new_window(dimensions, title, monitor, gl_version, gl_debug, vsync,
!visible, sharing.map(|w| init::ContextHack(w.window.context)),
!visible, sharing.map(|w| init::ContextHack(w.context)),
multisampling)
}
}

View file

@ -1,4 +1,4 @@
use HeadlessRendererBuilder;
use BuilderAttribs;
use CreationError;
use CreationError::OsError;
use libc;
@ -13,11 +13,13 @@ pub struct HeadlessContext {
}
impl HeadlessContext {
pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> {
pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
let dimensions = builder.dimensions.unwrap();
Ok(HeadlessContext {
width: builder.dimensions.0,
height: builder.dimensions.1,
buffer: Vec::from_elem(builder.dimensions.0 * builder.dimensions.1, unsafe { mem::uninitialized() }),
width: dimensions.0,
height: dimensions.1,
buffer: Vec::from_elem(dimensions.0 * dimensions.1, unsafe { mem::uninitialized() }),
context: unsafe {
let ctxt = ffi::OSMesaCreateContext(0x1908, ptr::null());
if ctxt.is_null() {

View file

@ -11,3 +11,8 @@ mod headless;
#[cfg(feature = "window")]
mod window;
#[cfg(not(feature = "window"))]
pub type Window = (); // TODO: hack to make things work
#[cfg(not(feature = "window"))]
pub type MonitorID = (); // TODO: hack to make things work

View file

@ -1,4 +1,4 @@
use {Event, WindowBuilder};
use {Event, BuilderAttribs};
use CreationError;
use CreationError::OsError;
use libc;
@ -89,7 +89,7 @@ pub struct Window {
}
impl Window {
pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> {
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
ensure_thread_init();
let dimensions = builder.dimensions.unwrap_or((800, 600));
@ -308,7 +308,7 @@ impl Window {
});
let share = if let Some(win) = builder.sharing {
win.window.x.context
win.x.context
} else {
ptr::null()
};