#[cfg(target_os = "windows")]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate shared_library;
extern crate libc;
extern crate winit;
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate shell32;
#[cfg(target_os = "windows")]
extern crate gdi32;
#[cfg(target_os = "windows")]
extern crate user32;
#[cfg(target_os = "windows")]
extern crate dwmapi;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_use]
extern crate objc;
#[cfg(target_os = "macos")]
extern crate cgl;
#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
extern crate x11_dl;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
extern crate wayland_client;
pub use headless::{HeadlessRendererBuilder, HeadlessContext};
pub use winit::{AvailableMonitorsIter, AxisId, ButtonId, ControlFlow,
CreationError as WindowCreationError, CursorState, DeviceEvent, DeviceId,
ElementState, Event, EventsLoop, EventsLoopClosed, EventsLoopProxy,
get_available_monitors, get_primary_monitor, KeyboardInput, ModifiersState,
MonitorId, MouseButton, MouseCursor, MouseScrollDelta, NativeMonitorId, ScanCode,
Touch, TouchPhase, VirtualKeyCode, Window, WindowAttributes, WindowBuilder,
WindowEvent, WindowId};
use std::io;
mod api;
mod platform;
mod headless;
pub mod os;
pub trait GlContext {
unsafe fn make_current(&self) -> Result<(), ContextError>;
fn is_current(&self) -> bool;
fn get_proc_address(&self, addr: &str) -> *const ();
fn swap_buffers(&self) -> Result<(), ContextError>;
fn get_api(&self) -> Api;
fn get_pixel_format(&self) -> PixelFormat;
fn resize(&self, width: u32, height: u32);
}
pub struct Context {
context: platform::Context,
}
pub struct ContextBuilder<'a> {
pub gl_attr: GlAttributes<&'a Context>,
pf_reqs: PixelFormatRequirements,
}
pub struct GlWindow {
context: Context,
window: Window,
}
impl<'a> ContextBuilder<'a> {
pub fn new() -> Self {
ContextBuilder {
pf_reqs: std::default::Default::default(),
gl_attr: std::default::Default::default(),
}
}
#[inline]
pub fn with_gl(mut self, request: GlRequest) -> Self {
self.gl_attr.version = request;
self
}
#[inline]
pub fn with_gl_profile(mut self, profile: GlProfile) -> Self {
self.gl_attr.profile = Some(profile);
self
}
#[inline]
pub fn with_gl_debug_flag(mut self, flag: bool) -> Self {
self.gl_attr.debug = flag;
self
}
#[inline]
pub fn with_gl_robustness(mut self, robustness: Robustness) -> Self {
self.gl_attr.robustness = robustness;
self
}
#[inline]
pub fn with_vsync(mut self, vsync: bool) -> Self {
self.gl_attr.vsync = vsync;
self
}
#[inline]
pub fn with_shared_lists(mut self, other: &'a Context) -> Self {
self.gl_attr.sharing = Some(other);
self
}
#[inline]
pub fn with_multisampling(mut self, samples: u16) -> Self {
self.pf_reqs.multisampling = match samples {
0 => None,
_ => {
assert!(samples.is_power_of_two());
Some(samples)
}
};
self
}
#[inline]
pub fn with_depth_buffer(mut self, bits: u8) -> Self {
self.pf_reqs.depth_bits = Some(bits);
self
}
#[inline]
pub fn with_stencil_buffer(mut self, bits: u8) -> Self {
self.pf_reqs.stencil_bits = Some(bits);
self
}
#[inline]
pub fn with_pixel_format(mut self, color_bits: u8, alpha_bits: u8) -> Self {
self.pf_reqs.color_bits = Some(color_bits);
self.pf_reqs.alpha_bits = Some(alpha_bits);
self
}
#[inline]
pub fn with_stereoscopy(mut self) -> Self {
self.pf_reqs.stereoscopy = true;
self
}
#[inline]
pub fn with_srgb(mut self, srgb_enabled: bool) -> Self {
self.pf_reqs.srgb = srgb_enabled;
self
}
}
impl GlWindow {
pub fn new(
window_builder: WindowBuilder,
context_builder: ContextBuilder,
events_loop: &EventsLoop,
) -> Result<Self, CreationError>
{
let ContextBuilder { pf_reqs, gl_attr } = context_builder;
let gl_attr = gl_attr.map_sharing(|ctxt| &ctxt.context);
platform::Context::new(window_builder, events_loop, &pf_reqs, &gl_attr)
.map(|(window, context)| GlWindow {
window: window,
context: Context { context: context },
})
}
pub fn window(&self) -> &Window {
&self.window
}
pub fn context(&self) -> &Context {
&self.context
}
}
impl GlContext for Context {
unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current()
}
fn is_current(&self) -> bool {
self.context.is_current()
}
fn get_proc_address(&self, addr: &str) -> *const () {
self.context.get_proc_address(addr)
}
fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers()
}
fn get_api(&self) -> Api {
self.context.get_api()
}
fn get_pixel_format(&self) -> PixelFormat {
self.context.get_pixel_format()
}
fn resize(&self, width: u32, height: u32) {
self.context.resize(width, height);
}
}
impl GlContext for GlWindow {
unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current()
}
fn is_current(&self) -> bool {
self.context.is_current()
}
fn get_proc_address(&self, addr: &str) -> *const () {
self.context.get_proc_address(addr)
}
fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers()
}
fn get_api(&self) -> Api {
self.context.get_api()
}
fn get_pixel_format(&self) -> PixelFormat {
self.context.get_pixel_format()
}
fn resize(&self, width: u32, height: u32) {
self.context.resize(width, height);
}
}
impl std::ops::Deref for GlWindow {
type Target = Window;
fn deref(&self) -> &Self::Target {
&self.window
}
}
#[derive(Debug)]
pub enum CreationError {
OsError(String),
NotSupported,
NoBackendAvailable(Box<std::error::Error + Send>),
RobustnessNotSupported,
OpenGlVersionNotSupported,
NoAvailablePixelFormat,
PlatformSpecific(String),
Window(WindowCreationError),
}
impl CreationError {
fn to_string(&self) -> &str {
match *self {
CreationError::OsError(ref text) => &text,
CreationError::NotSupported => "Some of the requested attributes are not supported",
CreationError::NoBackendAvailable(_) => "No backend is available",
CreationError::RobustnessNotSupported => "You requested robustness, but it is \
not supported.",
CreationError::OpenGlVersionNotSupported => "The requested OpenGL version is not \
supported.",
CreationError::NoAvailablePixelFormat => "Couldn't find any pixel format that matches \
the criterias.",
CreationError::PlatformSpecific(ref text) => &text,
CreationError::Window(ref err) => std::error::Error::description(err),
}
}
}
impl std::fmt::Display for CreationError {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
formatter.write_str(self.to_string())?;
if let Some(err) = std::error::Error::cause(self) {
write!(formatter, ": {}", err)?;
}
Ok(())
}
}
impl std::error::Error for CreationError {
fn description(&self) -> &str {
self.to_string()
}
fn cause(&self) -> Option<&std::error::Error> {
match *self {
CreationError::NoBackendAvailable(ref err) => Some(&**err),
CreationError::Window(ref err) => Some(err),
_ => None
}
}
}
impl From<WindowCreationError> for CreationError {
fn from(err: WindowCreationError) -> Self {
CreationError::Window(err)
}
}
#[derive(Debug)]
pub enum ContextError {
IoError(io::Error),
ContextLost,
}
impl ContextError {
fn to_string(&self) -> &str {
use std::error::Error;
match *self {
ContextError::IoError(ref err) => err.description(),
ContextError::ContextLost => "Context lost"
}
}
}
impl std::fmt::Display for ContextError {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
formatter.write_str(self.to_string())
}
}
impl std::error::Error for ContextError {
fn description(&self) -> &str {
self.to_string()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Api {
OpenGl,
OpenGlEs,
WebGl,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GlProfile {
Compatibility,
Core,
}
#[derive(Debug, Copy, Clone)]
pub enum GlRequest {
Latest,
Specific(Api, (u8, u8)),
GlThenGles {
opengl_version: (u8, u8),
opengles_version: (u8, u8),
},
}
impl GlRequest {
pub fn to_gl_version(&self) -> Option<(u8, u8)> {
match self {
&GlRequest::Specific(Api::OpenGl, version) => Some(version),
&GlRequest::GlThenGles { opengl_version: version, .. } => Some(version),
_ => None,
}
}
}
pub static GL_CORE: GlRequest = GlRequest::Specific(Api::OpenGl, (3, 2));
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Robustness {
NotRobust,
NoError,
RobustNoResetNotification,
TryRobustNoResetNotification,
RobustLoseContextOnReset,
TryRobustLoseContextOnReset,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ReleaseBehavior {
None,
Flush,
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct PixelFormat {
pub hardware_accelerated: bool,
pub color_bits: u8,
pub alpha_bits: u8,
pub depth_bits: u8,
pub stencil_bits: u8,
pub stereoscopy: bool,
pub double_buffer: bool,
pub multisampling: Option<u16>,
pub srgb: bool,
}
#[derive(Clone, Debug)]
pub struct PixelFormatRequirements {
pub hardware_accelerated: Option<bool>,
pub color_bits: Option<u8>,
pub float_color_buffer: bool,
pub alpha_bits: Option<u8>,
pub depth_bits: Option<u8>,
pub stencil_bits: Option<u8>,
pub double_buffer: Option<bool>,
pub multisampling: Option<u16>,
pub stereoscopy: bool,
pub srgb: bool,
pub release_behavior: ReleaseBehavior,
}
impl Default for PixelFormatRequirements {
#[inline]
fn default() -> PixelFormatRequirements {
PixelFormatRequirements {
hardware_accelerated: Some(true),
color_bits: Some(24),
float_color_buffer: false,
alpha_bits: Some(8),
depth_bits: Some(24),
stencil_bits: Some(8),
double_buffer: None,
multisampling: None,
stereoscopy: false,
srgb: false,
release_behavior: ReleaseBehavior::Flush,
}
}
}
#[derive(Clone)]
pub struct GlAttributes<S> {
pub sharing: Option<S>,
pub version: GlRequest,
pub profile: Option<GlProfile>,
pub debug: bool,
pub robustness: Robustness,
pub vsync: bool,
}
impl<S> GlAttributes<S> {
#[inline]
pub fn map_sharing<F, T>(self, f: F) -> GlAttributes<T> where F: FnOnce(S) -> T {
GlAttributes {
sharing: self.sharing.map(f),
version: self.version,
profile: self.profile,
debug: self.debug,
robustness: self.robustness,
vsync: self.vsync,
}
}
}
impl<S> Default for GlAttributes<S> {
#[inline]
fn default() -> GlAttributes<S> {
GlAttributes {
sharing: None,
version: GlRequest::Latest,
profile: None,
debug: cfg!(debug_assertions),
robustness: Robustness::NotRobust,
vsync: false,
}
}
}