Skip to content

Commit

Permalink
Use a Box<Fn(&[PixelFormat]) -> PixelFormat in the builder attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaka committed Sep 20, 2015
1 parent 80a15ab commit 9b7e578
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 122 deletions.
1 change: 0 additions & 1 deletion src/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ impl HeadlessRendererBuilder {
/// 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()
}
}
Expand Down
207 changes: 103 additions & 104 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ pub enum CursorState {

/// Describes a possible format. Unused.
#[allow(missing_docs)]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PixelFormat {
pub hardware_accelerated: bool,
pub color_bits: u8,
Expand All @@ -356,23 +356,21 @@ pub struct PixelFormat {

/// Attributes
// FIXME: remove `pub` (https://github.com/rust-lang/rust/issues/23585)
#[derive(Clone)]
#[doc(hidden)]
pub struct BuilderAttribs<'a> {
#[allow(dead_code)]
headless: bool,
strict: bool,
dimensions: Option<(u32, u32)>,
title: String,
monitor: Option<platform::MonitorID>,
visible: bool,
multisampling: Option<u16>,
depth_bits: Option<u8>,
stencil_bits: Option<u8>,
color_bits: Option<u8>,
alpha_bits: Option<u8>,
stereoscopy: bool,
srgb: Option<bool>,

/// Given a list of pixel formats, returns the one that should be used.
///
/// If the function returns `None`, a `NoAvailablePixelFormat` error will be returned.
///
/// If the function returns a pixel format that is not in the list, a panic will occur.
pixel_format_chooser: Box<Fn(&[PixelFormat]) -> Option<PixelFormat> + Send + Sync>,
transparent: bool,
decorations: bool,
multitouch: bool,
Expand All @@ -383,18 +381,11 @@ impl BuilderAttribs<'static> {
fn new() -> BuilderAttribs<'static> {
BuilderAttribs {
headless: false,
strict: false,
dimensions: None,
title: "glutin window".to_string(),
monitor: None,
visible: true,
multisampling: None,
depth_bits: None,
stencil_bits: None,
color_bits: None,
alpha_bits: None,
stereoscopy: false,
srgb: None,
pixel_format_chooser: Box::new(|l| l.get(0).map(|p| p.clone())),
transparent: false,
decorations: true,
multitouch: false,
Expand All @@ -410,18 +401,11 @@ impl<'a> BuilderAttribs<'a> {

let new_attribs = BuilderAttribs {
headless: self.headless,
strict: self.strict,
dimensions: self.dimensions,
title: self.title,
monitor: self.monitor,
visible: self.visible,
multisampling: self.multisampling,
depth_bits: self.depth_bits,
stencil_bits: self.stencil_bits,
color_bits: self.color_bits,
alpha_bits: self.alpha_bits,
stereoscopy: self.stereoscopy,
srgb: self.srgb,
pixel_format_chooser: self.pixel_format_chooser,
transparent: self.transparent,
decorations: self.decorations,
multitouch: self.multitouch,
Expand All @@ -441,101 +425,116 @@ impl<'a> BuilderAttribs<'a> {
fn choose_pixel_format<T, I>(&self, iter: I) -> Result<(T, PixelFormat), CreationError>
where I: IntoIterator<Item=(T, PixelFormat)>, T: Clone
{
// filtering formats that don't match the requirements
let iter = iter.into_iter().filter(|&(_, ref format)| {
if format.color_bits < self.color_bits.unwrap_or(0) {
return false;
}
let formats_and_id = iter.into_iter().collect::<Vec<_>>();
let formats = formats_and_id.iter().map(|&(_, ref f)| f.clone()).collect::<Vec<_>>();

if format.alpha_bits < self.alpha_bits.unwrap_or(0) {
return false;
}
if let Some(chosen_format) = (self.pixel_format_chooser)(&formats) {
Ok(formats_and_id.into_iter().find(|&(_, ref f)| f == &chosen_format).unwrap())
} else {
Err(CreationError::NoAvailablePixelFormat)
}
}
}

if format.depth_bits < self.depth_bits.unwrap_or(0) {
return false;
}
fn choose_pixel_format<I>(iter: I, multisampling: Option<u16>, depth_bits: Option<u8>,
stencil_bits: Option<u8>, color_bits: Option<u8>, alpha_bits: Option<u8>,
stereoscopy: bool, srgb: Option<bool>) -> Option<PixelFormat>
where I: IntoIterator<Item=PixelFormat>
{
// filtering formats that don't match the requirements
let iter = iter.into_iter().filter(|format| {
if format.color_bits < color_bits.unwrap_or(0) {
return false;
}

if format.stencil_bits < self.stencil_bits.unwrap_or(0) {
return false;
}
if format.alpha_bits < alpha_bits.unwrap_or(0) {
return false;
}

if !format.stereoscopy && self.stereoscopy {
return false;
}
if format.depth_bits < depth_bits.unwrap_or(0) {
return false;
}

if let Some(req_ms) = self.multisampling {
match format.multisampling {
Some(val) if val >= req_ms => (),
_ => return false
}
} else {
if format.multisampling.is_some() {
return false;
}
}
if format.stencil_bits < stencil_bits.unwrap_or(0) {
return false;
}

if let Some(srgb) = self.srgb {
if srgb != format.srgb {
return false;
}
}
if !format.stereoscopy && stereoscopy {
return false;
}

true
});

// sorting so that the preferred format comes first
let mut formats = iter.collect::<Vec<_>>();
formats.sort_by(|&(_, ref left), &(_, ref right)| {
// prefer hardware-accelerated formats
if left.hardware_accelerated && !right.hardware_accelerated {
return Ordering::Less;
} else if right.hardware_accelerated && !left.hardware_accelerated {
return Ordering::Greater;
if let Some(req_ms) = multisampling {
match format.multisampling {
Some(val) if val >= req_ms => (),
_ => return false
}

// prefer sRGB formats
if left.srgb && !right.srgb {
return Ordering::Less;
} else if right.srgb && !left.srgb {
return Ordering::Greater;
} else {
if format.multisampling.is_some() {
return false;
}
}

// prefer formats with the highest color+alpha bits
if left.color_bits + left.alpha_bits != right.color_bits + right.alpha_bits {
return (right.color_bits + right.alpha_bits)
.cmp(&(left.color_bits + left.alpha_bits));
if let Some(srgb) = srgb {
if srgb != format.srgb {
return false;
}
}

// prefer double-buffering formats
if left.double_buffer && !right.double_buffer {
return Ordering::Less;
} else if right.double_buffer && !left.double_buffer {
return Ordering::Greater;
}
true
});

// sorting so that the preferred format comes first
let mut formats = iter.collect::<Vec<_>>();
formats.sort_by(|left, right| {
// prefer hardware-accelerated formats
if left.hardware_accelerated && !right.hardware_accelerated {
return Ordering::Less;
} else if right.hardware_accelerated && !left.hardware_accelerated {
return Ordering::Greater;
}

// prefer formats with the highest depth bits
if left.depth_bits != right.depth_bits {
return (right.depth_bits).cmp(&left.depth_bits);
}
// prefer sRGB formats
if left.srgb && !right.srgb {
return Ordering::Less;
} else if right.srgb && !left.srgb {
return Ordering::Greater;
}

// prefer formats with the highest stencil bits
if left.stencil_bits != right.stencil_bits {
return (right.stencil_bits).cmp(&left.stencil_bits);
}
// prefer formats with the highest color+alpha bits
if left.color_bits + left.alpha_bits != right.color_bits + right.alpha_bits {
return (right.color_bits + right.alpha_bits)
.cmp(&(left.color_bits + left.alpha_bits));
}

// prefer formats with multisampling
if left.multisampling.is_some() && right.multisampling.is_none() {
return Ordering::Less;
} else if right.multisampling.is_some() && left.multisampling.is_none() {
return Ordering::Greater;
}
// prefer double-buffering formats
if left.double_buffer && !right.double_buffer {
return Ordering::Less;
} else if right.double_buffer && !left.double_buffer {
return Ordering::Greater;
}

// default
return Ordering::Equal;
});
// prefer formats with the highest depth bits
if left.depth_bits != right.depth_bits {
return (right.depth_bits).cmp(&left.depth_bits);
}

formats.into_iter().next().ok_or(CreationError::NoAvailablePixelFormat)
}
// prefer formats with the highest stencil bits
if left.stencil_bits != right.stencil_bits {
return (right.stencil_bits).cmp(&left.stencil_bits);
}

// prefer formats with multisampling
if left.multisampling.is_some() && right.multisampling.is_none() {
return Ordering::Less;
} else if right.multisampling.is_some() && left.multisampling.is_none() {
return Ordering::Greater;
}

// default
return Ordering::Equal;
});

formats.into_iter().next()
}

/// Attributes to use when creating an OpenGL context.
Expand Down
Loading

0 comments on commit 9b7e578

Please sign in to comment.