aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/android/ffi.rs23
-rw-r--r--src/api/android/mod.rs226
-rw-r--r--src/api/caca/mod.rs83
-rw-r--r--src/api/cocoa/headless.rs21
-rw-r--r--src/api/cocoa/mod.rs251
-rw-r--r--src/api/egl/ffi.rs4
-rw-r--r--src/api/egl/mod.rs316
-rw-r--r--src/api/emscripten/ffi.rs82
-rw-r--r--src/api/emscripten/mod.rs251
-rw-r--r--src/api/glx/mod.rs36
-rw-r--r--src/api/mod.rs1
-rw-r--r--src/api/osmesa/mod.rs48
-rw-r--r--src/api/win32/init.rs35
-rw-r--r--src/api/win32/mod.rs81
-rw-r--r--src/api/x11/mod.rs97
-rw-r--r--src/headless.rs28
-rw-r--r--src/lib.rs64
-rw-r--r--src/platform/android/mod.rs31
-rw-r--r--src/platform/emscripten/mod.rs44
-rw-r--r--src/platform/linux/mod.rs56
-rw-r--r--src/platform/windows/mod.rs22
-rw-r--r--src/window.rs35
22 files changed, 1284 insertions, 551 deletions
diff --git a/src/api/android/ffi.rs b/src/api/android/ffi.rs
index 111f670..1398b77 100644
--- a/src/api/android/ffi.rs
+++ b/src/api/android/ffi.rs
@@ -5,29 +5,6 @@
use libc;
-pub mod egl {
- pub type khronos_utime_nanoseconds_t = super::khronos_utime_nanoseconds_t;
- pub type khronos_uint64_t = super::khronos_uint64_t;
- pub type khronos_ssize_t = super::khronos_ssize_t;
- pub type EGLNativeDisplayType = super::EGLNativeDisplayType;
- pub type EGLNativePixmapType = super::EGLNativePixmapType;
- pub type EGLNativeWindowType = super::EGLNativeWindowType;
- pub type EGLint = super::EGLint;
- pub type NativeDisplayType = super::EGLNativeDisplayType;
- pub type NativePixmapType = super::EGLNativePixmapType;
- pub type NativeWindowType = super::EGLNativeWindowType;
-
- include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));
-}
-
-pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
-pub type khronos_uint64_t = libc::uint64_t;
-pub type khronos_ssize_t = libc::c_long;
-pub type EGLint = libc::int32_t;
-pub type EGLNativeDisplayType = *const libc::c_void;
-pub type EGLNativePixmapType = *const libc::c_void; // FIXME: egl_native_pixmap_t instead
-pub type EGLNativeWindowType = *const ANativeWindow;
-
#[link(name = "android")]
#[link(name = "EGL")]
#[link(name = "GLESv2")]
diff --git a/src/api/android/mod.rs b/src/api/android/mod.rs
index c769fc8..9a98322 100644
--- a/src/api/android/mod.rs
+++ b/src/api/android/mod.rs
@@ -16,14 +16,16 @@ use std::collections::VecDeque;
use Api;
use BuilderAttribs;
use CursorState;
+use GlContext;
use GlRequest;
use PixelFormat;
use native_monitor::NativeMonitorId;
+use api::egl;
+use api::egl::Context as EglContext;
+
pub struct Window {
- display: ffi::egl::types::EGLDisplay,
- context: ffi::egl::types::EGLContext,
- surface: ffi::egl::types::EGLSurface,
+ context: EglContext,
event_rx: Receiver<android_glue::Event>,
}
@@ -31,7 +33,7 @@ pub struct MonitorID;
mod ffi;
-pub fn get_available_monitors() -> VecDeque <MonitorID> {
+pub fn get_available_monitors() -> VecDeque<MonitorID> {
let mut rb = VecDeque::new();
rb.push_back(MonitorID);
rb
@@ -55,41 +57,6 @@ impl MonitorID {
}
}
-#[cfg(feature = "headless")]
-pub struct HeadlessContext(i32);
-
-#[cfg(feature = "headless")]
-impl HeadlessContext {
- /// See the docs in the crate root file.
- pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
- unimplemented!()
- }
-
- /// See the docs in the crate root file.
- pub unsafe fn make_current(&self) {
- unimplemented!()
- }
-
- /// See the docs in the crate root file.
- pub fn is_current(&self) -> bool {
- unimplemented!()
- }
-
- /// See the docs in the crate root file.
- pub fn get_proc_address(&self, _addr: &str) -> *const () {
- unimplemented!()
- }
-
- pub fn get_api(&self) -> ::Api {
- ::Api::OpenGlEs
- }
-}
-
-#[cfg(feature = "headless")]
-unsafe impl Send for HeadlessContext {}
-#[cfg(feature = "headless")]
-unsafe impl Sync for HeadlessContext {}
-
pub struct PollEventsIterator<'a> {
window: &'a Window,
}
@@ -138,125 +105,19 @@ impl Window {
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
use std::{mem, ptr};
- if builder.sharing.is_some() {
- unimplemented!()
- }
-
let native_window = unsafe { android_glue::get_native_window() };
if native_window.is_null() {
return Err(OsError(format!("Android's native window is null")));
}
- let display = unsafe {
- let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
- if display.is_null() {
- return Err(OsError("No EGL display connection available".to_string()));
- }
- display
- };
-
- android_glue::write_log("eglGetDisplay succeeded");
-
- let (_major, _minor) = unsafe {
- let mut major: ffi::egl::types::EGLint = mem::uninitialized();
- let mut minor: ffi::egl::types::EGLint = mem::uninitialized();
-
- if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
- return Err(OsError(format!("eglInitialize failed")))
- }
-
- (major, minor)
- };
-
- android_glue::write_log("eglInitialize succeeded");
-
- let use_gles2 = match builder.gl_version {
- GlRequest::Specific(Api::OpenGlEs, (2, _)) => true,
- GlRequest::Specific(Api::OpenGlEs, _) => false,
- GlRequest::Specific(_, _) => panic!("Only OpenGL ES is supported"), // FIXME: return a result
- GlRequest::GlThenGles { opengles_version: (2, _), .. } => true,
- _ => false,
- };
-
- let mut attribute_list = vec!();
-
- if use_gles2 {
- attribute_list.push(ffi::egl::RENDERABLE_TYPE as i32);
- attribute_list.push(ffi::egl::OPENGL_ES2_BIT as i32);
- }
-
- {
- let (red, green, blue) = match builder.color_bits.unwrap_or(24) {
- 24 => (8, 8, 8),
- 16 => (6, 5, 6),
- _ => panic!("Bad color_bits"),
- };
- attribute_list.push(ffi::egl::RED_SIZE as i32);
- attribute_list.push(red);
- attribute_list.push(ffi::egl::GREEN_SIZE as i32);
- attribute_list.push(green);
- attribute_list.push(ffi::egl::BLUE_SIZE as i32);
- attribute_list.push(blue);
- }
-
- attribute_list.push(ffi::egl::DEPTH_SIZE as i32);
- attribute_list.push(builder.depth_bits.unwrap_or(8) as i32);
-
- attribute_list.push(ffi::egl::NONE as i32);
-
- let config = unsafe {
- let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
- let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
- if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
- &mut num_config) == 0
- {
- return Err(OsError(format!("eglChooseConfig failed")))
- }
-
- if num_config <= 0 {
- return Err(OsError(format!("eglChooseConfig returned no available config")))
- }
-
- config
- };
-
- android_glue::write_log("eglChooseConfig succeeded");
-
- let context = unsafe {
- let mut context_attributes = vec!();
- if use_gles2 {
- context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
- context_attributes.push(2);
- }
- context_attributes.push(ffi::egl::NONE as i32);
-
- let context = ffi::egl::CreateContext(display, config, ptr::null(),
- context_attributes.as_ptr());
- if context.is_null() {
- return Err(OsError(format!("eglCreateContext failed")))
- }
- context
- };
-
- android_glue::write_log("eglCreateContext succeeded");
-
- let surface = unsafe {
- let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
- if surface.is_null() {
- return Err(OsError(format!("eglCreateWindowSurface failed")))
- }
- surface
- };
-
- android_glue::write_log("eglCreateWindowSurface succeeded");
+ let context = try!(EglContext::new(egl::ffi::egl::Egl, builder, None,
+ native_window as *const _));
let (tx, rx) = channel();
android_glue::add_sender(tx);
Ok(Window {
- display: display,
context: context,
- surface: surface,
event_rx: rx,
})
}
@@ -317,42 +178,14 @@ impl Window {
}
}
- pub fn make_current(&self) {
- unsafe {
- ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
- }
- }
-
- pub fn is_current(&self) -> bool {
- unsafe { ffi::egl::GetCurrentContext() == self.context }
- }
-
- pub fn get_proc_address(&self, addr: &str) -> *const () {
- let addr = CString::new(addr.as_bytes()).unwrap();
- let addr = addr.as_ptr();
- unsafe {
- ffi::egl::GetProcAddress(addr) as *const ()
- }
- }
-
- pub fn swap_buffers(&self) {
- unsafe {
- ffi::egl::SwapBuffers(self.display, self.surface);
- }
- }
-
pub fn platform_display(&self) -> *mut libc::c_void {
- self.display as *mut libc::c_void
+ unimplemented!();
}
pub fn platform_window(&self) -> *mut libc::c_void {
unimplemented!()
}
- pub fn get_api(&self) -> ::Api {
- ::Api::OpenGlEs
- }
-
pub fn get_pixel_format(&self) -> PixelFormat {
unimplemented!();
}
@@ -379,6 +212,32 @@ impl Window {
unsafe impl Send for Window {}
unsafe impl Sync for Window {}
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ self.context.make_current()
+ }
+
+ fn is_current(&self) -> bool {
+ self.context.is_current()
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ self.context.get_proc_address(addr)
+ }
+
+ fn swap_buffers(&self) {
+ self.context.swap_buffers()
+ }
+
+ fn get_api(&self) -> Api {
+ self.context.get_api()
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.context.get_pixel_format()
+ }
+}
+
#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;
@@ -388,18 +247,3 @@ impl WindowProxy {
unimplemented!()
}
}
-
-impl Drop for Window {
- fn drop(&mut self) {
- use std::ptr;
-
- unsafe {
- // we don't call MakeCurrent(0, 0) because we are not sure that the context
- // is still the current one
- android_glue::write_log("Destroying gl-init window");
- ffi::egl::DestroySurface(self.display, self.surface);
- ffi::egl::DestroyContext(self.display, self.context);
- ffi::egl::Terminate(self.display);
- }
- }
-}
diff --git a/src/api/caca/mod.rs b/src/api/caca/mod.rs
index d8199dd..1e3840c 100644
--- a/src/api/caca/mod.rs
+++ b/src/api/caca/mod.rs
@@ -1,11 +1,13 @@
-#![cfg(all(any(target_os = "linux", target_os = "freebsd"), feature="headless"))]
+#![cfg(any(target_os = "linux", target_os = "freebsd"))]
use libc;
-use api::osmesa::OsMesaContext;
+use api::osmesa::{OsMesaContext, OsMesaCreationError};
+use Api;
use BuilderAttribs;
use CreationError;
use Event;
+use GlContext;
use PixelFormat;
use CursorState;
use MouseCursor;
@@ -81,7 +83,12 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
impl Window {
pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
- let opengl = try!(OsMesaContext::new(builder));
+ let opengl = match OsMesaContext::new(builder) {
+ Err(OsMesaCreationError::NotSupported) => return Err(CreationError::NotSupported),
+ Err(OsMesaCreationError::CreationError(e)) => return Err(e),
+ Ok(c) => c
+ };
+
let opengl_dimensions = opengl.get_dimensions();
let libcaca = match ffi::LibCaca::open(&Path::new("libcaca.so.0")) {
@@ -169,34 +176,6 @@ impl Window {
}
}
- pub unsafe fn make_current(&self) {
- self.opengl.make_current()
- }
-
- pub fn is_current(&self) -> bool {
- self.opengl.is_current()
- }
-
- pub fn get_proc_address(&self, addr: &str) -> *const () {
- self.opengl.get_proc_address(addr) as *const _
- }
-
- pub fn swap_buffers(&self) {
- unsafe {
- let canvas = (self.libcaca.caca_get_canvas)(self.display);
- let width = (self.libcaca.caca_get_canvas_width)(canvas);
- let height = (self.libcaca.caca_get_canvas_height)(canvas);
-
- let buffer = self.opengl.get_framebuffer().chunks(self.opengl.get_dimensions().0 as usize)
- .flat_map(|i| i.iter().cloned()).rev().collect::<Vec<u32>>();
-
- (self.libcaca.caca_dither_bitmap)(canvas, 0, 0, width as libc::c_int,
- height as libc::c_int, self.dither,
- buffer.as_ptr() as *const _);
- (self.libcaca.caca_refresh_display)(self.display);
- };
- }
-
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!()
}
@@ -205,10 +184,6 @@ impl Window {
unimplemented!()
}
- pub fn get_api(&self) -> ::Api {
- self.opengl.get_api()
- }
-
pub fn get_pixel_format(&self) -> PixelFormat {
unimplemented!();
}
@@ -232,6 +207,44 @@ impl Window {
}
}
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ self.opengl.make_current()
+ }
+
+ fn is_current(&self) -> bool {
+ self.opengl.is_current()
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ self.opengl.get_proc_address(addr)
+ }
+
+ fn swap_buffers(&self) {
+ unsafe {
+ let canvas = (self.libcaca.caca_get_canvas)(self.display);
+ let width = (self.libcaca.caca_get_canvas_width)(canvas);
+ let height = (self.libcaca.caca_get_canvas_height)(canvas);
+
+ let buffer = self.opengl.get_framebuffer().chunks(self.opengl.get_dimensions().0 as usize)
+ .flat_map(|i| i.iter().cloned()).rev().collect::<Vec<u32>>();
+
+ (self.libcaca.caca_dither_bitmap)(canvas, 0, 0, width as libc::c_int,
+ height as libc::c_int, self.dither,
+ buffer.as_ptr() as *const _);
+ (self.libcaca.caca_refresh_display)(self.display);
+ };
+ }
+
+ fn get_api(&self) -> Api {
+ self.opengl.get_api()
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.opengl.get_pixel_format()
+ }
+}
+
impl Drop for Window {
fn drop(&mut self) {
unsafe {
diff --git a/src/api/cocoa/headless.rs b/src/api/cocoa/headless.rs
index 298027f..75cca8d 100644
--- a/src/api/cocoa/headless.rs
+++ b/src/api/cocoa/headless.rs
@@ -1,6 +1,7 @@
use CreationError;
use CreationError::OsError;
use BuilderAttribs;
+use GlContext;
use libc;
use std::ptr;
@@ -9,6 +10,7 @@ use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
use cocoa::base::{id, nil};
use cocoa::appkit::*;
+use PixelFormat;
mod gl {
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
@@ -56,8 +58,10 @@ impl HeadlessContext {
Ok(headless)
}
+}
- pub unsafe fn make_current(&self) {
+impl GlContext for HeadlessContext {
+ unsafe fn make_current(&self) {
self.context.makeCurrentContext();
gl::GenFramebuffersEXT(1, &mut framebuffer);
@@ -76,11 +80,11 @@ impl HeadlessContext {
}
}
- pub fn is_current(&self) -> bool {
+ fn is_current(&self) -> bool {
unimplemented!()
}
- pub fn get_proc_address(&self, _addr: &str) -> *const () {
+ fn get_proc_address(&self, _addr: &str) -> *const libc::c_void {
let symbol_name: CFString = _addr.parse().unwrap();
let framework_name: CFString = "com.apple.opengl".parse().unwrap();
let framework = unsafe {
@@ -89,12 +93,19 @@ impl HeadlessContext {
let symbol = unsafe {
CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
};
- symbol as *const ()
+ symbol as *const libc::c_void
+ }
+
+ fn swap_buffers(&self) {
}
- pub fn get_api(&self) -> ::Api {
+ fn get_api(&self) -> ::Api {
::Api::OpenGl
}
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ unimplemented!();
+ }
}
unsafe impl Send for HeadlessContext {}
diff --git a/src/api/cocoa/mod.rs b/src/api/cocoa/mod.rs
index 3254ee6..55ae617 100644
--- a/src/api/cocoa/mod.rs
+++ b/src/api/cocoa/mod.rs
@@ -1,6 +1,5 @@
#![cfg(target_os = "macos")]
-#[cfg(feature = "headless")]
pub use self::headless::HeadlessContext;
use {CreationError, Event, MouseCursor, CursorState};
@@ -9,6 +8,8 @@ use libc;
use Api;
use BuilderAttribs;
+use GlContext;
+use GlProfile;
use GlRequest;
use PixelFormat;
use native_monitor::NativeMonitorId;
@@ -27,7 +28,7 @@ use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
-use core_graphics::display::{CGMainDisplayID, CGDisplayPixelsHigh};
+use core_graphics::display::{CGAssociateMouseAndMouseCursorPosition, CGMainDisplayID, CGDisplayPixelsHigh};
use std::ffi::CStr;
use std::collections::VecDeque;
@@ -46,8 +47,6 @@ pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
mod monitor;
mod event;
-
-#[cfg(feature = "headless")]
mod headless;
static mut shift_pressed: bool = false;
@@ -156,6 +155,7 @@ pub struct Window {
view: IdRef,
window: IdRef,
context: IdRef,
+ pixel_format: PixelFormat,
delegate: WindowDelegate,
}
@@ -326,9 +326,8 @@ impl Window {
Some(app) => app,
None => { return Err(OsError(format!("Couldn't create NSApplication"))); },
};
- let window = match Window::create_window(builder.dimensions.unwrap_or((800, 600)),
- &*builder.title,
- &builder.monitor)
+
+ let window = match Window::create_window(&builder)
{
Some(window) => window,
None => { return Err(OsError(format!("Couldn't create NSWindow"))); },
@@ -338,9 +337,11 @@ impl Window {
None => { return Err(OsError(format!("Couldn't create NSView"))); },
};
- let context = match Window::create_context(*view, &builder) {
- Some(context) => context,
- None => { return Err(OsError(format!("Couldn't create OpenGL context"))); },
+ // TODO: perhaps we should return error from create_context so we can
+ // determine the cause of failure and possibly recover?
+ let (context, pf) = match Window::create_context(*view, &builder) {
+ Ok((Some(context), Some(pf))) => (context, pf),
+ _ => { return Err(OsError(format!("Couldn't create OpenGL context"))); },
};
unsafe {
@@ -365,6 +366,7 @@ impl Window {
view: view,
window: window,
context: context,
+ pixel_format: pf,
delegate: WindowDelegate::new(ds),
};
@@ -384,9 +386,9 @@ impl Window {
}
}
- fn create_window(dimensions: (u32, u32), title: &str, monitor: &Option<MonitorID>) -> Option<IdRef> {
+ fn create_window(builder: &BuilderAttribs) -> Option<IdRef> {
unsafe {
- let screen = match *monitor {
+ let screen = match builder.monitor {
Some(ref monitor_id) => {
let native_id = match monitor_id.get_native_identifier() {
NativeMonitorId::Numeric(num) => num,
@@ -418,7 +420,7 @@ impl Window {
let frame = match screen {
Some(screen) => NSScreen::frame(screen),
None => {
- let (width, height) = dimensions;
+ let (width, height) = builder.dimensions.unwrap_or((800, 600));
NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64))
}
};
@@ -439,7 +441,7 @@ impl Window {
NO,
));
window.non_nil().map(|window| {
- let title = IdRef::new(NSString::alloc(nil).init_str(title));
+ let title = IdRef::new(NSString::alloc(nil).init_str(&builder.title));
window.setTitle_(*title);
window.setAcceptsMouseMovedEvents_(YES);
if screen.is_some() {
@@ -464,53 +466,106 @@ impl Window {
}
}
- fn create_context(view: id, builder: &BuilderAttribs) -> Option<IdRef> {
- let profile = match builder.gl_version {
- GlRequest::Latest => NSOpenGLProfileVersion4_1Core as u32,
- GlRequest::Specific(Api::OpenGl, (1 ... 2, _)) => NSOpenGLProfileVersionLegacy as u32,
- GlRequest::Specific(Api::OpenGl, (3, 0)) => NSOpenGLProfileVersionLegacy as u32,
- GlRequest::Specific(Api::OpenGl, (3, 1 ... 2)) => NSOpenGLProfileVersion3_2Core as u32,
- GlRequest::Specific(Api::OpenGl, _) => NSOpenGLProfileVersion4_1Core as u32,
- GlRequest::Specific(_, _) => panic!("Only the OpenGL API is supported"), // FIXME: return Result
- GlRequest::GlThenGles { opengl_version: (1 ... 2, _), .. } => NSOpenGLProfileVersionLegacy as u32,
- GlRequest::GlThenGles { opengl_version: (3, 0), .. } => NSOpenGLProfileVersionLegacy as u32,
- GlRequest::GlThenGles { opengl_version: (3, 1 ... 2), .. } => NSOpenGLProfileVersion3_2Core as u32,
- GlRequest::GlThenGles { .. } => NSOpenGLProfileVersion4_1Core as u32,
+ fn create_context(view: id, builder: &BuilderAttribs) -> Result<(Option<IdRef>, Option<PixelFormat>), CreationError> {
+ let profile = match (builder.gl_version, builder.gl_version.to_gl_version(), builder.gl_profile) {
+ (GlRequest::Latest, _, Some(GlProfile::Compatibility)) => NSOpenGLProfileVersionLegacy as u32,
+ (GlRequest::Latest, _, _) => NSOpenGLProfileVersion4_1Core as u32,
+ (_, Some((1 ... 2, _)), Some(GlProfile::Core)) |
+ (_, Some((3 ... 4, _)), Some(GlProfile::Compatibility)) =>
+ return Err(CreationError::NotSupported),
+ (_, Some((1 ... 2, _)), _) => NSOpenGLProfileVersionLegacy as u32,
+ (_, Some((3, 0 ... 2)), _) => NSOpenGLProfileVersion3_2Core as u32,
+ (_, Some((3 ... 4, _)), _) => NSOpenGLProfileVersion4_1Core as u32,
+ _ => return Err(CreationError::NotSupported),
};
- unsafe {
- let mut attributes = vec![
- NSOpenGLPFADoubleBuffer as u32,
- NSOpenGLPFAClosestPolicy as u32,
- NSOpenGLPFAColorSize as u32, 24,
- NSOpenGLPFAAlphaSize as u32, 8,
- NSOpenGLPFADepthSize as u32, 24,
- NSOpenGLPFAStencilSize as u32, 8,
- NSOpenGLPFAOpenGLProfile as u32, profile,
- ];
-
- if let Some(samples) = builder.multisampling {
- attributes = attributes + &[
- NSOpenGLPFAMultisample as u32,
- NSOpenGLPFASampleBuffers as u32, 1,
- NSOpenGLPFASamples as u32, samples as u32,
- ];
- }
- attributes.push(0);
+ // NOTE: OS X no longer has the concept of setting individual
+ // color component's bit size. Instead we can only specify the
+ // full color size and hope for the best. Another hiccup is that
+ // `NSOpenGLPFAColorSize` also includes `NSOpenGLPFAAlphaSize`,
+ // so we have to account for that as well.
+ let alpha_depth = builder.alpha_bits.unwrap_or(8);
+ let color_depth = builder.color_bits.unwrap_or(24) + alpha_depth;
+
+ let mut attributes = vec![
+ NSOpenGLPFADoubleBuffer as u32,
+ NSOpenGLPFAClosestPolicy as u32,
+ NSOpenGLPFAColorSize as u32, color_depth as u32,
+ NSOpenGLPFAAlphaSize as u32, alpha_depth as u32,
+ NSOpenGLPFADepthSize as u32, builder.depth_bits.unwrap_or(24) as u32,
+ NSOpenGLPFAStencilSize as u32, builder.stencil_bits.unwrap_or(8) as u32,
+ NSOpenGLPFAOpenGLProfile as u32, profile,
+ ];
+
+ // A color depth higher than 64 implies we're using either 16-bit
+ // floats or 32-bit floats and OS X requires a flag to be set
+ // accordingly.
+ if color_depth >= 64 {
+ attributes.push(NSOpenGLPFAColorFloat as u32);
+ }
+ builder.multisampling.map(|samples| {
+ attributes.push(NSOpenGLPFAMultisample as u32);
+ attributes.push(NSOpenGLPFASampleBuffers as u32); attributes.push(1);
+ attributes.push(NSOpenGLPFASamples as u32); attributes.push(samples as u32);
+ });
+
+ // attribute list must be null terminated.
+ attributes.push(0);
+
+ Ok(unsafe {
let pixelformat = IdRef::new(NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes));
- pixelformat.non_nil().map(|pixelformat| {
+
+ if let Some(pixelformat) = pixelformat.non_nil() {
+
+ // TODO: Add context sharing
let context = IdRef::new(NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(*pixelformat, nil));
- context.non_nil().map(|context| {
- context.setView_(view);
+
+ if let Some(cxt) = context.non_nil() {
+ let pf = {
+ let get_attr = |attrib: NSOpenGLPixelFormatAttribute| -> i32 {
+ let mut value = 0;
+
+ NSOpenGLPixelFormat::getValues_forAttribute_forVirtualScreen_(
+ *pixelformat,
+ &mut value,
+ attrib,
+ NSOpenGLContext::currentVirtualScreen(*cxt));
+
+ value
+ };
+
+ PixelFormat {
+ hardware_accelerated: get_attr(NSOpenGLPFAAccelerated) != 0,
+ color_bits: (get_attr(NSOpenGLPFAColorSize) - get_attr(NSOpenGLPFAAlphaSize)) as u8,
+ alpha_bits: get_attr(NSOpenGLPFAAlphaSize) as u8,
+ depth_bits: get_attr(NSOpenGLPFADepthSize) as u8,
+ stencil_bits: get_attr(NSOpenGLPFAStencilSize) as u8,
+ stereoscopy: get_attr(NSOpenGLPFAStereo) != 0,
+ double_buffer: get_attr(NSOpenGLPFADoubleBuffer) != 0,
+ multisampling: if get_attr(NSOpenGLPFAMultisample) > 0 {
+ Some(get_attr(NSOpenGLPFASamples) as u16)
+ } else {
+ None
+ },
+ srgb: true,
+ }
+ };
+
+ cxt.setView_(view);
if builder.vsync {
let value = 1;
- context.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval);
+ cxt.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval);
}
- context
- })
- }).unwrap_or(None)
- }
+
+ (Some(cxt), Some(pf))
+ } else {
+ (None, None)
+ }
+ } else {
+ (None, None)
+ }
+ })
}
pub fn is_closed(&self) -> bool {
@@ -608,39 +663,6 @@ impl Window {
return None;
}
- pub unsafe fn make_current(&self) {
- let _: () = msg_send![*self.context, update];
- self.context.makeCurrentContext();
- }
-
- pub fn is_current(&self) -> bool {
- unsafe {
- let current = NSOpenGLContext::currentContext(nil);
- if current != nil {
- let is_equal: BOOL = msg_send![current, isEqual:*self.context];
- is_equal != NO
- } else {
- false
- }
- }
- }
-
- pub fn get_proc_address(&self, _addr: &str) -> *const () {
- let symbol_name: CFString = FromStr::from_str(_addr).unwrap();
- let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap();
- let framework = unsafe {
- CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
- };
- let symbol = unsafe {
- CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
- };
- symbol as *const ()
- }
-
- pub fn swap_buffers(&self) {
- unsafe { self.context.flushBuffer(); }
- }
-
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!()
}
@@ -649,14 +671,6 @@ impl Window {
unimplemented!()
}
- pub fn get_api(&self) -> ::Api {
- ::Api::OpenGl
- }
-
- pub fn get_pixel_format(&self) -> PixelFormat {
- unimplemented!();
- }
-
pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
self.delegate.state.resize_handler = callback;
}
@@ -701,9 +715,12 @@ impl Window {
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
let cls = Class::get("NSCursor").unwrap();
+
+ // TODO: Check for errors.
match state {
CursorState::Normal => {
let _: () = unsafe { msg_send![cls, unhide] };
+ let _: i32 = unsafe { CGAssociateMouseAndMouseCursorPosition(true) };
Ok(())
},
CursorState::Hide => {
@@ -711,7 +728,8 @@ impl Window {
Ok(())
},
CursorState::Grab => {
- Err("Mouse grabbing is unimplemented".to_string())
+ let _: i32 = unsafe { CGAssociateMouseAndMouseCursorPosition(false) };
+ Ok(())
}
}
}
@@ -727,6 +745,49 @@ impl Window {
}
}
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ let _: () = msg_send![*self.context, update];
+ self.context.makeCurrentContext();
+ }
+
+ fn is_current(&self) -> bool {
+ unsafe {
+ let current = NSOpenGLContext::currentContext(nil);
+ if current != nil {
+ let is_equal: BOOL = msg_send![current, isEqual:*self.context];
+ is_equal != NO
+ } else {
+ false
+ }
+ }
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ let symbol_name: CFString = FromStr::from_str(addr).unwrap();
+ let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap();
+ let framework = unsafe {
+ CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
+ };
+ let symbol = unsafe {
+ CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
+ };
+ symbol as *const _
+ }
+
+ fn swap_buffers(&self) {
+ unsafe { self.context.flushBuffer(); }
+ }
+
+ fn get_api(&self) -> ::Api {
+ ::Api::OpenGl
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.pixel_format.clone()
+ }
+}
+
struct IdRef(id);
impl IdRef {
diff --git a/src/api/egl/ffi.rs b/src/api/egl/ffi.rs
index 8e2528d..5fa6384 100644
--- a/src/api/egl/ffi.rs
+++ b/src/api/egl/ffi.rs
@@ -2,8 +2,6 @@ use libc;
#[cfg(target_os = "windows")]
extern crate winapi;
-#[cfg(target_os = "android")]
-use api::android::ffi;
pub mod egl {
pub type khronos_utime_nanoseconds_t = super::khronos_utime_nanoseconds_t;
@@ -32,4 +30,4 @@ pub type EGLNativeWindowType = winapi::HWND;
#[cfg(target_os = "linux")]
pub type EGLNativeWindowType = *const libc::c_void;
#[cfg(target_os = "android")]
-pub type EGLNativeWindowType = *const ffi::ANativeWindow;
+pub type EGLNativeWindowType = *const libc::c_void;
diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs
index fdea2cd..b2fe2c6 100644
--- a/src/api/egl/mod.rs
+++ b/src/api/egl/mod.rs
@@ -1,8 +1,10 @@
-#![cfg(target_os = "linux")]
+#![cfg(any(target_os = "linux", target_os = "android"))]
use BuilderAttribs;
use CreationError;
+use GlContext;
use GlRequest;
+use PixelFormat;
use Api;
use libc;
@@ -16,6 +18,8 @@ pub struct Context {
display: ffi::egl::types::EGLDisplay,
context: ffi::egl::types::EGLContext,
surface: ffi::egl::types::EGLSurface,
+ api: Api,
+ pixel_format: PixelFormat,
}
impl Context {
@@ -35,7 +39,7 @@ impl Context {
display
};
- let (_major, _minor) = unsafe {
+ let egl_version = unsafe {
let mut major: ffi::egl::types::EGLint = mem::uninitialized();
let mut minor: ffi::egl::types::EGLint = mem::uninitialized();
@@ -46,62 +50,61 @@ impl Context {
(major, minor)
};
- let use_gles2 = match builder.gl_version {
- GlRequest::Specific(Api::OpenGlEs, (2, _)) => true,
- GlRequest::Specific(Api::OpenGlEs, _) => false,
- GlRequest::Specific(_, _) => return Err(CreationError::NotSupported),
- GlRequest::GlThenGles { opengles_version: (2, _), .. } => true,
- _ => false,
- };
-
- let mut attribute_list = vec!();
- attribute_list.push(ffi::egl::RENDERABLE_TYPE as i32);
- attribute_list.push(ffi::egl::OPENGL_ES2_BIT as i32);
-
- attribute_list.push(ffi::egl::CONFORMANT as i32);
- attribute_list.push(ffi::egl::OPENGL_ES2_BIT as i32);
-
- attribute_list.push(ffi::egl::SURFACE_TYPE as i32);
- attribute_list.push(ffi::egl::WINDOW_BIT as i32);
-
- {
- let (red, green, blue) = match builder.color_bits.unwrap_or(24) {
- 24 => (8, 8, 8),
- 16 => (6, 5, 6),
- _ => panic!("Bad color_bits"),
- };
-
- attribute_list.push(ffi::egl::RED_SIZE as i32);
- attribute_list.push(red);
- attribute_list.push(ffi::egl::GREEN_SIZE as i32);
- attribute_list.push(green);
- attribute_list.push(ffi::egl::BLUE_SIZE as i32);
- attribute_list.push(blue);
- }
-
- attribute_list.push(ffi::egl::DEPTH_SIZE as i32);
- attribute_list.push(builder.depth_bits.unwrap_or(8) as i32);
-
- attribute_list.push(ffi::egl::NONE as i32);
-
- let config = unsafe {
- let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
- let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
- if egl.ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
- &mut num_config) == 0
- {
- return Err(CreationError::OsError(format!("eglChooseConfig failed")))
+ // binding the right API and choosing the version
+ let (version, api) = unsafe {
+ match builder.gl_version {
+ GlRequest::Latest => {
+ if egl_version >= (1, 4) {
+ if egl.BindAPI(ffi::egl::OPENGL_API) != 0 {
+ (None, Api::OpenGl)
+ } else if egl.BindAPI(ffi::egl::OPENGL_ES_API) != 0 {
+ (None, Api::OpenGlEs)
+ } else {
+ return Err(CreationError::NotSupported);
+ }
+ } else {
+ (None, Api::OpenGlEs)
+ }
+ },
+ GlRequest::Specific(Api::OpenGlEs, version) => {
+ if egl_version >= (1, 2) {
+ if egl.BindAPI(ffi::egl::OPENGL_ES_API) == 0 {
+ return Err(CreationError::NotSupported);
+ }
+ }
+ (Some(version), Api::OpenGlEs)
+ },
+ GlRequest::Specific(Api::OpenGl, version) => {
+ if egl_version < (1, 4) {
+ return Err(CreationError::NotSupported);
+ }
+ if egl.BindAPI(ffi::egl::OPENGL_API) == 0 {
+ return Err(CreationError::NotSupported);
+ }
+ (Some(version), Api::OpenGl)
+ },
+ GlRequest::Specific(_, _) => return Err(CreationError::NotSupported),
+ GlRequest::GlThenGles { opengles_version, opengl_version } => {
+ if egl_version >= (1, 4) {
+ if egl.BindAPI(ffi::egl::OPENGL_API) != 0 {
+ (Some(opengl_version), Api::OpenGl)
+ } else if egl.BindAPI(ffi::egl::OPENGL_ES_API) != 0 {
+ (Some(opengles_version), Api::OpenGlEs)
+ } else {
+ return Err(CreationError::NotSupported);
+ }
+ } else {
+ (Some(opengles_version), Api::OpenGlEs)
+ }
+ },
}
-
- if num_config <= 0 {
- return Err(CreationError::OsError(format!("eglChooseConfig returned no available config")))
- }
-
- config
};
+ let configs = unsafe { try!(enumerate_configs(&egl, display, &egl_version, api, version)) };
+ let (config_id, pixel_format) = try!(builder.choose_pixel_format(configs.into_iter()));
+
let surface = unsafe {
- let surface = egl.CreateWindowSurface(display, config, native_window, ptr::null());
+ let surface = egl.CreateWindowSurface(display, config_id, native_window, ptr::null());
if surface.is_null() {
return Err(CreationError::OsError(format!("eglCreateWindowSurface failed")))
}
@@ -109,17 +112,40 @@ impl Context {
};
let context = unsafe {
- let mut context_attributes = vec!();
- context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
- context_attributes.push(2);
- context_attributes.push(ffi::egl::NONE as i32);
-
- let context = egl.CreateContext(display, config, ptr::null(),
- context_attributes.as_ptr());
- if context.is_null() {
- return Err(CreationError::OsError(format!("eglCreateContext failed")))
+ if let Some(version) = version {
+ try!(create_context(&egl, display, &egl_version, api, version, config_id,
+ builder.gl_debug).map_err(|_| CreationError::NotSupported))
+
+ } else if api == Api::OpenGlEs {
+ if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (2, 0),
+ config_id, builder.gl_debug)
+ {
+ ctxt
+ } else if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (1, 0),
+ config_id, builder.gl_debug)
+ {
+ ctxt
+ } else {
+ return Err(CreationError::NotSupported);
+ }
+
+ } else {
+ if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (3, 2),
+ config_id, builder.gl_debug)
+ {
+ ctxt
+ } else if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (3, 1),
+ config_id, builder.gl_debug)
+ {
+ ctxt
+ } else if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (1, 0),
+ config_id, builder.gl_debug)
+ {
+ ctxt
+ } else {
+ return Err(CreationError::NotSupported);
+ }
}
- context
};
Ok(Context {
@@ -127,10 +153,14 @@ impl Context {
display: display,
context: context,
surface: surface,
+ api: api,
+ pixel_format: pixel_format,
})
}
+}
- pub fn make_current(&self) {
+impl GlContext for Context {
+ unsafe fn make_current(&self) {
let ret = unsafe {
self.egl.MakeCurrent(self.display, self.surface, self.surface, self.context)
};
@@ -140,19 +170,19 @@ impl Context {
}
}
- pub fn is_current(&self) -> bool {
+ fn is_current(&self) -> bool {
unsafe { self.egl.GetCurrentContext() == self.context }
}
- pub fn get_proc_address(&self, addr: &str) -> *const () {
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
let addr = CString::new(addr.as_bytes()).unwrap();
let addr = addr.as_ptr();
unsafe {
- self.egl.GetProcAddress(addr) as *const ()
+ self.egl.GetProcAddress(addr) as *const _
}
}
- pub fn swap_buffers(&self) {
+ fn swap_buffers(&self) {
let ret = unsafe {
self.egl.SwapBuffers(self.display, self.surface)
};
@@ -162,8 +192,12 @@ impl Context {
}
}
- pub fn get_api(&self) -> ::Api {
- ::Api::OpenGlEs
+ fn get_api(&self) -> Api {
+ self.api
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.pixel_format.clone()
}
}
@@ -183,3 +217,143 @@ impl Drop for Context {
}
}
}
+
+unsafe fn enumerate_configs(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay,
+ egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint),
+ api: Api, version: Option<(u8, u8)>)
+ -> Result<Vec<(ffi::egl::types::EGLConfig, PixelFormat)>, CreationError>
+{
+ let mut num_configs = mem::uninitialized();
+ if egl.GetConfigs(display, ptr::null_mut(), 0, &mut num_configs) == 0 {
+ return Err(CreationError::OsError(format!("eglGetConfigs failed")));
+ }
+
+ let mut configs_ids = Vec::with_capacity(num_configs as usize);
+ if egl.GetConfigs(display, configs_ids.as_mut_ptr(),
+ configs_ids.capacity() as ffi::egl::types::EGLint,
+ &mut num_configs) == 0
+ {
+ return Err(CreationError::OsError(format!("eglGetConfigs failed")));
+ }
+ configs_ids.set_len(num_configs as usize);
+
+ // analyzing each config
+ let mut result = Vec::with_capacity(num_configs as usize);
+ for config_id in configs_ids {
+ macro_rules! attrib {
+ ($egl:expr, $display:expr, $config:expr, $attr:expr) => (
+ {
+ let mut value = mem::uninitialized();
+ let res = $egl.GetConfigAttrib($display, $config,
+ $attr as ffi::egl::types::EGLint, &mut value);
+ if res == 0 {
+ return Err(CreationError::OsError(format!("eglGetConfigAttrib failed")));
+ }
+ value
+ }
+ )
+ };
+
+ let renderable = attrib!(egl, display, config_id, ffi::egl::RENDERABLE_TYPE) as u32;
+ let conformant = attrib!(egl, display, config_id, ffi::egl::CONFORMANT) as u32;
+
+ if api == Api::OpenGlEs {
+ if let Some(version) = version {
+ if version.0 == 3 && (renderable & ffi::egl::OPENGL_ES3_BIT == 0 ||
+ conformant & ffi::egl::OPENGL_ES3_BIT == 0)
+ {
+ continue;
+ }
+
+ if version.0 == 2 && (renderable & ffi::egl::OPENGL_ES2_BIT == 0 ||
+ conformant & ffi::egl::OPENGL_ES2_BIT == 0)
+ {
+ continue;
+ }
+
+ if version.0 == 1 && (renderable & ffi::egl::OPENGL_ES_BIT == 0 ||
+ conformant & ffi::egl::OPENGL_ES_BIT == 0)
+ {
+ continue;
+ }
+ }
+
+ } else if api == Api::OpenGl {
+ if renderable & ffi::egl::OPENGL_BIT == 0 ||
+ conformant & ffi::egl::OPENGL_BIT == 0
+ {
+ continue;
+ }
+ }
+
+ if attrib!(egl, display, config_id, ffi::egl::SURFACE_TYPE) & ffi::egl::WINDOW_BIT as i32 == 0 {
+ continue;
+ }
+
+ if attrib!(egl, display, config_id, ffi::egl::TRANSPARENT_TYPE) != ffi::egl::NONE as i32 {
+ continue;
+ }
+
+ if attrib!(egl, display, config_id, ffi::egl::COLOR_BUFFER_TYPE) != ffi::egl::RGB_BUFFER as i32 {
+ continue;
+ }
+
+ result.push((config_id, PixelFormat {
+ hardware_accelerated: attrib!(egl, display, config_id, ffi::egl::CONFIG_CAVEAT)
+ != ffi::egl::SLOW_CONFIG as i32,
+ color_bits: attrib!(egl, display, config_id, ffi::egl::RED_SIZE) as u8 +
+ attrib!(egl, display, config_id, ffi::egl::BLUE_SIZE) as u8 +
+ attrib!(egl, display, config_id, ffi::egl::GREEN_SIZE) as u8,
+ alpha_bits: attrib!(egl, display, config_id, ffi::egl::ALPHA_SIZE) as u8,
+ depth_bits: attrib!(egl, display, config_id, ffi::egl::DEPTH_SIZE) as u8,
+ stencil_bits: attrib!(egl, display, config_id, ffi::egl::STENCIL_SIZE) as u8,
+ stereoscopy: false,
+ double_buffer: true,
+ multisampling: match attrib!(egl, display, config_id, ffi::egl::SAMPLES) {
+ 0 | 1 => None,
+ a => Some(a as u16),
+ },
+ srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that
+ }));
+ }
+
+ Ok(result)
+}
+
+unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay,
+ egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint),
+ api: Api, version: (u8, u8), config_id: ffi::egl::types::EGLConfig,
+ gl_debug: bool)
+ -> Result<ffi::egl::types::EGLContext, ()>
+{
+ let mut context_attributes = vec![];
+
+ if egl_version >= &(1, 5) {
+ context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
+ context_attributes.push(version.0 as i32);
+ context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32);
+ context_attributes.push(version.1 as i32);
+
+ if gl_debug {
+ context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32);
+ context_attributes.push(ffi::egl::TRUE as i32);
+ }
+
+ } else {
+ if api == Api::OpenGlEs {
+ context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
+ context_attributes.push(version.0 as i32);
+ }
+ }
+
+ context_attributes.push(ffi::egl::NONE as i32);
+
+ let context = egl.CreateContext(display, config_id, ptr::null(),
+ context_attributes.as_ptr());
+
+ if context.is_null() {
+ return Err(());
+ }
+
+ Ok(context)
+}
diff --git a/src/api/emscripten/ffi.rs b/src/api/emscripten/ffi.rs
new file mode 100644
index 0000000..34b6c17
--- /dev/null
+++ b/src/api/emscripten/ffi.rs
@@ -0,0 +1,82 @@
+#![allow(dead_code)]
+#![allow(non_snake_case)]
+#![allow(non_camel_case_types)]
+
+use libc;
+
+pub type EM_BOOL = libc::c_int;
+pub type EM_UTF8 = libc::c_char;
+pub type EMSCRIPTEN_WEBGL_CONTEXT_HANDLE = libc::c_int;
+pub type EMSCRIPTEN_RESULT = libc::c_int;
+
+pub type em_webgl_context_callback = extern fn(libc::c_int, *const libc::c_void, *mut libc::c_void)
+ -> EM_BOOL;
+
+#[repr(C)]
+pub struct EmscriptenWebGLContextAttributes {
+ pub alpha: EM_BOOL,
+ pub depth: EM_BOOL,
+ pub stencil: EM_BOOL,
+ pub antialias: EM_BOOL,
+ pub premultipliedAlpha: EM_BOOL,
+ pub preserveDrawingBuffer: EM_BOOL,
+ pub preferLowPowerToHighPerformance: EM_BOOL,
+ pub failIfMajorPerformanceCaveat: EM_BOOL,
+ pub majorVersion: libc::c_int,
+ pub minorVersion: libc::c_int,
+ pub enableExtensionsByDefault: EM_BOOL,
+}
+
+// values for EMSCRIPTEN_RESULT
+pub const EMSCRIPTEN_RESULT_SUCCESS: libc::c_int = 0;
+pub const EMSCRIPTEN_RESULT_DEFERRED: libc::c_int = 1;
+pub const EMSCRIPTEN_RESULT_NOT_SUPPORTED: libc::c_int = -1;
+pub const EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED: libc::c_int = -2;
+pub const EMSCRIPTEN_RESULT_INVALID_TARGET: libc::c_int = -3;
+pub const EMSCRIPTEN_RESULT_UNKNOWN_TARGET: libc::c_int = -4;
+pub const EMSCRIPTEN_RESULT_INVALID_PARAM: libc::c_int = -5;
+pub const EMSCRIPTEN_RESULT_FAILED: libc::c_int = -6;
+pub const EMSCRIPTEN_RESULT_NO_DATA: libc::c_int = -7;
+
+extern {
+ pub fn emscripten_webgl_init_context_attributes(attributes: *mut EmscriptenWebGLContextAttributes);
+ pub fn emscripten_webgl_create_context(target: *const libc::c_char,
+ attributes: *const EmscriptenWebGLContextAttributes) -> EMSCRIPTEN_WEBGL_CONTEXT_HANDLE;
+
+ pub fn emscripten_webgl_make_context_current(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)
+ -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_webgl_get_current_context() -> EMSCRIPTEN_WEBGL_CONTEXT_HANDLE;
+
+ pub fn emscripten_webgl_destroy_context(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)
+ -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_webgl_enable_extension(context: EMSCRIPTEN_WEBGL_CONTEXT_HANDLE,
+ extension: *const libc::c_char) -> EM_BOOL;
+
+ pub fn emscripten_set_webglcontextlost_callback(target: *const libc::c_char,
+ userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_webgl_context_callback)
+ -> EMSCRIPTEN_RESULT;
+ pub fn emscripten_set_webglcontextrestored_callback(target: *const libc::c_char,
+ userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_webgl_context_callback)
+ -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_is_webgl_context_lost(target: *const libc::c_char) -> EM_BOOL;
+
+ // note: this function is not documented but is used by the ports of glfw, SDL and EGL
+ pub fn emscripten_GetProcAddress(name: *const libc::c_char) -> *const libc::c_void;
+
+
+ pub fn emscripten_request_fullscreen(target: *const libc::c_char,
+ deferUntilInEventHandler: EM_BOOL) -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_set_element_css_size(target: *const libc::c_char, width: libc::c_double,
+ height: libc::c_double) -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_get_element_css_size(target: *const libc::c_char, width: *mut libc::c_double,
+ height: *mut libc::c_double) -> EMSCRIPTEN_RESULT;
+
+ pub fn emscripten_sleep(delay: libc::c_uint);
+}
diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs
new file mode 100644
index 0000000..48b31a9
--- /dev/null
+++ b/src/api/emscripten/mod.rs
@@ -0,0 +1,251 @@
+#![cfg(target_os = "emscripten")]
+
+use std::ffi::CString;
+use libc;
+use {Event, BuilderAttribs, CreationError, MouseCursor};
+use Api;
+use PixelFormat;
+use GlContext;
+
+use std::collections::VecDeque;
+
+mod ffi;
+
+pub struct Window {
+ context: ffi::EMSCRIPTEN_WEBGL_CONTEXT_HANDLE,
+}
+
+pub struct PollEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for PollEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ None
+ }
+}
+
+pub struct WaitEventsIterator<'a> {
+ window: &'a Window,
+}
+
+impl<'a> Iterator for WaitEventsIterator<'a> {
+ type Item = Event;
+
+ fn next(&mut self) -> Option<Event> {
+ None
+ }
+}
+
+#[derive(Clone)]
+pub struct WindowProxy;
+
+impl WindowProxy {
+ pub fn wakeup_event_loop(&self) {
+ unimplemented!()
+ }
+}
+
+pub struct MonitorID;
+
+pub fn get_available_monitors() -> VecDeque<MonitorID> {
+ let mut list = VecDeque::new();
+ list.push_back(MonitorID);
+ list
+}
+
+pub fn get_primary_monitor() -> MonitorID {
+ MonitorID
+}
+
+impl MonitorID {
+ pub fn get_name(&self) -> Option<String> {
+ Some("Canvas".to_string())
+ }
+
+ pub fn get_dimensions(&self) -> (u32, u32) {
+ unimplemented!()
+ }
+}
+
+impl Window {
+ pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
+ // getting the default values of attributes
+ let mut attributes = unsafe {
+ use std::mem;
+ let mut attributes: ffi::EmscriptenWebGLContextAttributes = mem::uninitialized();
+ ffi::emscripten_webgl_init_context_attributes(&mut attributes);
+ attributes
+ };
+
+ // setting the attributes
+ // FIXME:
+ /*match builder.gl_version {
+ Some((major, minor)) => {
+ attributes.majorVersion = major as libc::c_int;
+ attributes.minorVersion = minor as libc::c_int;
+ },
+ None => ()
+ };*/
+
+ // creating the context
+ let context = unsafe {
+ use std::{mem, ptr};
+ let context = ffi::emscripten_webgl_create_context(ptr::null(), &attributes);
+ if context <= 0 {
+ return Err(CreationError::OsError(format!("Error while calling emscripten_webgl_create_context: {}",
+ error_to_str(mem::transmute(context)))));
+ }
+ context
+ };
+
+ // TODO: emscripten_set_webglcontextrestored_callback
+
+ Ok(Window {
+ context: context
+ })
+ }
+
+ pub fn is_closed(&self) -> bool {
+ use std::ptr;
+ unsafe { ffi::emscripten_is_webgl_context_lost(ptr::null()) != 0 }
+ }
+
+ pub fn set_title(&self, _title: &str) {
+ }
+
+ pub fn get_position(&self) -> Option<(i32, i32)> {
+ Some((0, 0))
+ }
+
+ pub fn set_position(&self, _: i32, _: i32) {
+ }
+
+ pub fn get_inner_size(&self) -> Option<(u32, u32)> {
+ unsafe {
+ use std::{mem, ptr};
+ let mut width = mem::uninitialized();
+ let mut height = mem::uninitialized();
+
+ if ffi::emscripten_get_element_css_size(ptr::null(), &mut width, &mut height)
+ != ffi::EMSCRIPTEN_RESULT_SUCCESS
+ {
+ None
+ } else {
+ Some((width as u32, height as u32))
+ }
+ }
+ }
+
+ pub fn get_outer_size(&self) -> Option<(u32, u32)> {
+ self.get_inner_size()
+ }
+
+ pub fn set_inner_size(&self, width: u32, height: u32) {
+ unsafe {
+ use std::ptr;
+ ffi::emscripten_set_element_css_size(ptr::null(), width as libc::c_double, height
+ as libc::c_double);
+ }
+ }
+
+ pub fn poll_events(&self) -> PollEventsIterator {
+ PollEventsIterator {
+ window: self,
+ }
+ }
+
+ pub fn wait_events(&self) -> WaitEventsIterator {
+ WaitEventsIterator {
+ window: self,
+ }
+ }
+
+ pub fn create_window_proxy(&self) -> WindowProxy {
+ WindowProxy
+ }
+
+ pub fn show(&self) {}
+ pub fn hide(&self) {}
+
+ pub fn platform_display(&self) -> *mut libc::c_void {
+ unimplemented!()
+ }
+
+ pub fn platform_window(&self) -> *mut libc::c_void {
+ unimplemented!()
+ }
+
+ pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
+ }
+
+ pub fn set_cursor(&self, _cursor: MouseCursor) {
+ unimplemented!()
+ }
+
+ pub fn hidpi_factor(&self) -> f32 {
+ 1.0
+ }
+}
+
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ // TOOD: check if == EMSCRIPTEN_RESULT
+ ffi::emscripten_webgl_make_context_current(self.context);
+ }
+
+ fn is_current(&self) -> bool {
+ true // FIXME:
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ let addr = CString::new(addr.as_bytes()).unwrap();
+ let addr = addr.as_ptr();
+
+ unsafe {
+ ffi::emscripten_GetProcAddress(addr) as *const _
+ }
+ }
+
+ fn swap_buffers(&self) {
+ unsafe {
+ ffi::emscripten_sleep(1); // FIXME:
+ }
+ }
+
+ fn get_api(&self) -> Api {
+ Api::WebGl
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ unimplemented!();
+ }
+}
+
+impl Drop for Window {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::emscripten_exit_fullscreen();
+ ffi::emscripten_webgl_destroy_context(self.context);
+ }
+ }
+}
+
+fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str {
+ match code {
+ ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED
+ => "Internal error in the library (success detected as failure)",
+
+ ffi::EMSCRIPTEN_RESULT_NOT_SUPPORTED => "Not supported",
+ ffi::EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED => "Failed not deferred",
+ ffi::EMSCRIPTEN_RESULT_INVALID_TARGET => "Invalid target",
+ ffi::EMSCRIPTEN_RESULT_UNKNOWN_TARGET => "Unknown target",
+ ffi::EMSCRIPTEN_RESULT_INVALID_PARAM => "Invalid parameter",
+ ffi::EMSCRIPTEN_RESULT_FAILED => "Failed",
+ ffi::EMSCRIPTEN_RESULT_NO_DATA => "No data",
+
+ _ => "Undocumented error"
+ }
+}
diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs
index fb86dfd..cb61dfa 100644
--- a/src/api/glx/mod.rs
+++ b/src/api/glx/mod.rs
@@ -2,8 +2,11 @@
use BuilderAttribs;
use CreationError;
+use GlContext;
+use GlProfile;
use GlRequest;
use Api;
+use PixelFormat;
use libc;
use std::ffi::CString;
@@ -50,6 +53,17 @@ impl Context {
},
}
+ if let Some(profile) = builder.gl_profile {
+ let flag = match profile {
+ GlProfile::Compatibility =>
+ ffi::glx_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+ GlProfile::Core =>
+ ffi::glx_extra::CONTEXT_CORE_PROFILE_BIT_ARB,
+ };
+ attributes.push(ffi::glx_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
+ attributes.push(flag as libc::c_int);
+ }
+
if builder.gl_debug {
attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as libc::c_int);
attributes.push(ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
@@ -140,35 +154,41 @@ impl Context {
context: context,
})
}
+}
- pub fn make_current(&self) {
- let res = unsafe { ffi::glx::MakeCurrent(self.display as *mut _, self.window, self.context) };
+impl GlContext for Context {
+ unsafe fn make_current(&self) {
+ let res = ffi::glx::MakeCurrent(self.display as *mut _, self.window, self.context);
if res == 0 {
panic!("glx::MakeCurrent failed");
}
}
- pub fn is_current(&self) -> bool {
+ fn is_current(&self) -> bool {
unsafe { ffi::glx::GetCurrentContext() == self.context }
}
- pub fn get_proc_address(&self, addr: &str) -> *const () {
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
let addr = CString::new(addr.as_bytes()).unwrap();
let addr = addr.as_ptr();
unsafe {
- ffi::glx::GetProcAddress(addr as *const _) as *const ()
+ ffi::glx::GetProcAddress(addr as *const _) as *const _
}
}
- pub fn swap_buffers(&self) {
+ fn swap_buffers(&self) {
unsafe {
ffi::glx::SwapBuffers(self.display as *mut _, self.window)
}
}
- pub fn get_api(&self) -> ::Api {
+ fn get_api(&self) -> ::Api {
::Api::OpenGl
}
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ unimplemented!();
+ }
}
unsafe impl Send for Context {}
@@ -176,8 +196,6 @@ unsafe impl Sync for Context {}
impl Drop for Context {
fn drop(&mut self) {
- use std::ptr;
-
unsafe {
// we don't call MakeCurrent(0, 0) because we are not sure that the context
// is still the current one
diff --git a/src/api/mod.rs b/src/api/mod.rs
index b8cf9de..b1a7249 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -3,6 +3,7 @@ pub mod caca;
pub mod cocoa;
pub mod dlopen;
pub mod egl;
+pub mod emscripten;
pub mod glx;
pub mod osmesa;
pub mod win32;
diff --git a/src/api/osmesa/mod.rs b/src/api/osmesa/mod.rs
index ea90583..22df72a 100644
--- a/src/api/osmesa/mod.rs
+++ b/src/api/osmesa/mod.rs
@@ -1,10 +1,12 @@
-#![cfg(all(any(target_os = "linux", target_os = "freebsd"), feature="headless"))]
+#![cfg(any(target_os = "linux", target_os = "freebsd"))]
extern crate osmesa_sys;
+use Api;
use BuilderAttribs;
use CreationError;
-use CreationError::OsError;
+use GlContext;
+use PixelFormat;
use libc;
use std::{mem, ptr};
use std::ffi::CString;
@@ -16,8 +18,23 @@ pub struct OsMesaContext {
height: u32,
}
+pub enum OsMesaCreationError {
+ CreationError(CreationError),
+ NotSupported,
+}
+
+impl From<CreationError> for OsMesaCreationError {
+ fn from(e: CreationError) -> OsMesaCreationError {
+ OsMesaCreationError::CreationError(e)
+ }
+}
+
impl OsMesaContext {
- pub fn new(builder: BuilderAttribs) -> Result<OsMesaContext, CreationError> {
+ pub fn new(builder: BuilderAttribs) -> Result<OsMesaContext, OsMesaCreationError> {
+ if let Err(_) = osmesa_sys::OsMesa::try_loading() {
+ return Err(OsMesaCreationError::NotSupported);
+ }
+
let dimensions = builder.dimensions.unwrap();
Ok(OsMesaContext {
@@ -28,7 +45,7 @@ impl OsMesaContext {
context: unsafe {
let ctxt = osmesa_sys::OSMesaCreateContext(0x1908, ptr::null_mut());
if ctxt.is_null() {
- return Err(OsError("OSMesaCreateContext failed".to_string()));
+ return Err(CreationError::OsError("OSMesaCreateContext failed".to_string()).into());
}
ctxt
}
@@ -43,7 +60,13 @@ impl OsMesaContext {
(self.width, self.height)
}
- pub unsafe fn make_current(&self) {
+ // TODO: can we remove this without causing havoc?
+ pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
+ }
+}
+
+impl GlContext for OsMesaContext {
+ unsafe fn make_current(&self) {
let ret = osmesa_sys::OSMesaMakeCurrent(self.context,
self.buffer.as_ptr() as *mut libc::c_void,
0x1401, self.width as libc::c_int, self.height as libc::c_int);
@@ -53,23 +76,26 @@ impl OsMesaContext {
}
}
- pub fn is_current(&self) -> bool {
+ fn is_current(&self) -> bool {
unsafe { osmesa_sys::OSMesaGetCurrentContext() == self.context }
}
- pub fn get_proc_address(&self, addr: &str) -> *const () {
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
unsafe {
let c_str = CString::new(addr.as_bytes().to_vec()).unwrap();
mem::transmute(osmesa_sys::OSMesaGetProcAddress(mem::transmute(c_str.as_ptr())))
}
}
- /// See the docs in the crate root file.
- pub fn get_api(&self) -> ::Api {
- ::Api::OpenGl
+ fn swap_buffers(&self) {
}
- pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
+ fn get_api(&self) -> Api {
+ Api::OpenGl
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ unimplemented!();
}
}
diff --git a/src/api/win32/init.rs b/src/api/win32/init.rs
index 5cdd6b8..e5b0b3a 100644
--- a/src/api/win32/init.rs
+++ b/src/api/win32/init.rs
@@ -17,6 +17,7 @@ use BuilderAttribs;
use CreationError;
use CreationError::OsError;
use CursorState;
+use GlProfile;
use GlRequest;
use PixelFormat;
@@ -205,7 +206,12 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
// calling SetPixelFormat
let pixel_format = {
let formats = if extra_functions.GetPixelFormatAttribivARB.is_loaded() {
- enumerate_arb_pixel_formats(&extra_functions, &real_window)
+ let f = enumerate_arb_pixel_formats(&extra_functions, &real_window);
+ if f.is_empty() {
+ enumerate_native_pixel_formats(&real_window)
+ } else {
+ f
+ }
} else {
enumerate_native_pixel_formats(&real_window)
};
@@ -369,6 +375,23 @@ unsafe fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &BuilderAttribs<'st
},
}
+ if let Some(profile) = builder.gl_profile {
+ if is_extension_supported(extra_functions, hdc,
+ "WGL_ARB_create_context_profile")
+ {
+ let flag = match profile {
+ GlProfile::Compatibility =>
+ gl::wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+ GlProfile::Core =>
+ gl::wgl_extra::CONTEXT_CORE_PROFILE_BIT_ARB,
+ };
+ attributes.push(gl::wgl_extra::CONTEXT_PROFILE_MASK_ARB as libc::c_int);
+ attributes.push(flag as libc::c_int);
+ } else {
+ return Err(CreationError::NotSupported);
+ }
+ }
+
if builder.gl_debug {
attributes.push(gl::wgl_extra::CONTEXT_FLAGS_ARB as libc::c_int);
attributes.push(gl::wgl_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
@@ -433,9 +456,7 @@ unsafe fn enumerate_native_pixel_formats(hdc: &WindowWrapper) -> Vec<(PixelForma
result.push((PixelFormat {
hardware_accelerated: (output.dwFlags & winapi::PFD_GENERIC_FORMAT) == 0,
- red_bits: output.cRedBits,
- green_bits: output.cGreenBits,
- blue_bits: output.cBlueBits,
+ color_bits: output.cRedBits + output.cGreenBits + output.cBlueBits,
alpha_bits: output.cAlphaBits,
depth_bits: output.cDepthBits,
stencil_bits: output.cStencilBits,
@@ -484,9 +505,9 @@ unsafe fn enumerate_arb_pixel_formats(extra: &gl::wgl_extra::Wgl, hdc: &WindowWr
result.push((PixelFormat {
hardware_accelerated: true,
- red_bits: get_info(index, gl::wgl_extra::RED_BITS_ARB) as u8,
- green_bits: get_info(index, gl::wgl_extra::GREEN_BITS_ARB) as u8,
- blue_bits: get_info(index, gl::wgl_extra::BLUE_BITS_ARB) as u8,
+ color_bits: get_info(index, gl::wgl_extra::RED_BITS_ARB) as u8 +
+ get_info(index, gl::wgl_extra::GREEN_BITS_ARB) as u8 +
+ get_info(index, gl::wgl_extra::BLUE_BITS_ARB) as u8,
alpha_bits: get_info(index, gl::wgl_extra::ALPHA_BITS_ARB) as u8,
depth_bits: get_info(index, gl::wgl_extra::DEPTH_BITS_ARB) as u8,
stencil_bits: get_info(index, gl::wgl_extra::STENCIL_BITS_ARB) as u8,
diff --git a/src/api/win32/mod.rs b/src/api/win32/mod.rs
index dd3e685..d0caea7 100644
--- a/src/api/win32/mod.rs
+++ b/src/api/win32/mod.rs
@@ -14,7 +14,9 @@ use std::sync::mpsc::Receiver;
use libc;
use {CreationError, Event, MouseCursor};
use CursorState;
+use GlContext;
+use Api;
use PixelFormat;
use BuilderAttribs;
@@ -195,7 +197,7 @@ impl Window {
unsafe {
user32::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, x as libc::c_int,
- y as libc::c_int, winapi::SWP_NOZORDER | winapi::SWP_NOREPOSITION);
+ y as libc::c_int, winapi::SWP_NOZORDER | winapi::SWP_NOREPOSITION | winapi::SWP_NOMOVE);
user32::UpdateWindow(self.window.0);
}
}
@@ -218,37 +220,6 @@ impl Window {
}
}
- /// See the docs in the crate root file.
- pub unsafe fn make_current(&self) {
- // TODO: check return value
- gl::wgl::MakeCurrent(self.window.1 as *const libc::c_void,
- self.context.0 as *const libc::c_void);
- }
-
- /// See the docs in the crate root file.
- pub fn is_current(&self) -> bool {
- unsafe { gl::wgl::GetCurrentContext() == self.context.0 as *const libc::c_void }
- }
-
- /// See the docs in the crate root file.
- pub fn get_proc_address(&self, addr: &str) -> *const () {
- let addr = CString::new(addr.as_bytes()).unwrap();
- let addr = addr.as_ptr();
-
- unsafe {
- let p = gl::wgl::GetProcAddress(addr) as *const ();
- if !p.is_null() { return p; }
- kernel32::GetProcAddress(self.gl_library, addr) as *const ()
- }
- }
-
- /// See the docs in the crate root file.
- pub fn swap_buffers(&self) {
- unsafe {
- gdi32::SwapBuffers(self.window.1);
- }
- }
-
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!()
}
@@ -257,15 +228,6 @@ impl Window {
self.window.0 as *mut libc::c_void
}
- /// See the docs in the crate root file.
- pub fn get_api(&self) -> ::Api {
- ::Api::OpenGl
- }
-
- pub fn get_pixel_format(&self) -> PixelFormat {
- self.pixel_format.clone()
- }
-
pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
}
@@ -362,6 +324,43 @@ impl Window {
}
}
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ // TODO: check return value
+ gl::wgl::MakeCurrent(self.window.1 as *const libc::c_void,
+ self.context.0 as *const libc::c_void);
+ }
+
+ fn is_current(&self) -> bool {
+ unsafe { gl::wgl::GetCurrentContext() == self.context.0 as *const libc::c_void }
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ let addr = CString::new(addr.as_bytes()).unwrap();
+ let addr = addr.as_ptr();
+
+ unsafe {
+ let p = gl::wgl::GetProcAddress(addr) as *const _;
+ if !p.is_null() { return p; }
+ kernel32::GetProcAddress(self.gl_library, addr) as *const _
+ }
+ }
+
+ fn swap_buffers(&self) {
+ unsafe {
+ gdi32::SwapBuffers(self.window.1);
+ }
+ }
+
+ fn get_api(&self) -> Api {
+ Api::OpenGl
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.pixel_format.clone()
+ }
+}
+
pub struct PollEventsIterator<'a> {
window: &'a Window,
}
diff --git a/src/api/x11/mod.rs b/src/api/x11/mod.rs
index 252b22e..7d7c048 100644
--- a/src/api/x11/mod.rs
+++ b/src/api/x11/mod.rs
@@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex, Once, ONCE_INIT};
use Api;
use CursorState;
+use GlContext;
use GlRequest;
use PixelFormat;
@@ -411,9 +412,9 @@ impl Window {
PixelFormat {
hardware_accelerated: true,
- red_bits: get_attrib(ffi::glx::RED_SIZE as libc::c_int) as u8,
- green_bits: get_attrib(ffi::glx::GREEN_SIZE as libc::c_int) as u8,
- blue_bits: get_attrib(ffi::glx::BLUE_SIZE as libc::c_int) as u8,
+ color_bits: get_attrib(ffi::glx::RED_SIZE as libc::c_int) as u8 +
+ get_attrib(ffi::glx::GREEN_SIZE as libc::c_int) as u8 +
+ get_attrib(ffi::glx::BLUE_SIZE as libc::c_int) as u8,
alpha_bits: get_attrib(ffi::glx::ALPHA_SIZE as libc::c_int) as u8,
depth_bits: get_attrib(ffi::glx::DEPTH_SIZE as libc::c_int) as u8,
stencil_bits: get_attrib(ffi::glx::STENCIL_SIZE as libc::c_int) as u8,
@@ -674,38 +675,6 @@ impl Window {
}
}
- pub unsafe fn make_current(&self) {
- match self.x.context {
- Context::Glx(ref ctxt) => ctxt.make_current(),
- Context::Egl(ref ctxt) => ctxt.make_current(),
- Context::None => {}
- }
- }
-
- pub fn is_current(&self) -> bool {
- match self.x.context {
- Context::Glx(ref ctxt) => ctxt.is_current(),
- Context::Egl(ref ctxt) => ctxt.is_current(),
- Context::None => panic!()
- }
- }
-
- pub fn get_proc_address(&self, addr: &str) -> *const () {
- match self.x.context {
- Context::Glx(ref ctxt) => ctxt.get_proc_address(addr),
- Context::Egl(ref ctxt) => ctxt.get_proc_address(addr),
- Context::None => ptr::null()
- }
- }
-
- pub fn swap_buffers(&self) {
- match self.x.context {
- Context::Glx(ref ctxt) => ctxt.swap_buffers(),
- Context::Egl(ref ctxt) => ctxt.swap_buffers(),
- Context::None => {}
- }
- }
-
pub fn platform_display(&self) -> *mut libc::c_void {
self.x.display as *mut libc::c_void
}
@@ -714,18 +683,6 @@ impl Window {
unimplemented!()
}
- /// See the docs in the crate root file.
- pub fn get_api(&self) -> ::Api {
- match self.x.context {
- Context::Glx(ref ctxt) => ctxt.get_api(),
- Context::Egl(ref ctxt) => ctxt.get_api(),
- Context::None => panic!()
- }
- }
-
- pub fn get_pixel_format(&self) -> PixelFormat {
- self.pixel_format.clone()
- }
pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
}
@@ -828,3 +785,49 @@ impl Window {
Ok(())
}
}
+
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ match self.x.context {
+ Context::Glx(ref ctxt) => ctxt.make_current(),
+ Context::Egl(ref ctxt) => ctxt.make_current(),
+ Context::None => {}
+ }
+ }
+
+ fn is_current(&self) -> bool {
+ match self.x.context {
+ Context::Glx(ref ctxt) => ctxt.is_current(),
+ Context::Egl(ref ctxt) => ctxt.is_current(),
+ Context::None => panic!()
+ }
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ match self.x.context {
+ Context::Glx(ref ctxt) => ctxt.get_proc_address(addr),
+ Context::Egl(ref ctxt) => ctxt.get_proc_address(addr),
+ Context::None => ptr::null()
+ }
+ }
+
+ fn swap_buffers(&self) {
+ match self.x.context {
+ Context::Glx(ref ctxt) => ctxt.swap_buffers(),
+ Context::Egl(ref ctxt) => ctxt.swap_buffers(),
+ Context::None => {}
+ }
+ }
+
+ fn get_api(&self) -> Api {
+ match self.x.context {
+ Context::Glx(ref ctxt) => ctxt.get_api(),
+ Context::Egl(ref ctxt) => ctxt.get_api(),
+ Context::None => panic!()
+ }
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.pixel_format.clone()
+ }
+}
diff --git a/src/headless.rs b/src/headless.rs
index dc42108..566cbee 100644
--- a/src/headless.rs
+++ b/src/headless.rs
@@ -2,6 +2,8 @@ use Api;
use BuilderAttribs;
use CreationError;
use GlRequest;
+use GlContext;
+use PixelFormat;
use gl_common;
use libc;
@@ -101,3 +103,29 @@ impl gl_common::GlFunctionsSource for HeadlessContext {
self.get_proc_address(addr)
}
}
+
+impl GlContext for HeadlessContext {
+ unsafe fn make_current(&self) {
+ self.make_current()
+ }
+
+ fn is_current(&self) -> bool {
+ self.is_current()
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ self.get_proc_address(addr)
+ }
+
+ fn swap_buffers(&self) {
+ self.swap_buffers()
+ }
+
+ fn get_api(&self) -> Api {
+ self.get_api()
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.get_pixel_format()
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index b12b894..974ef0b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -53,7 +53,6 @@ extern crate glutin_core_graphics as core_graphics;
extern crate x11;
pub use events::*;
-#[cfg(feature = "headless")]
pub use headless::{HeadlessRendererBuilder, HeadlessContext};
#[cfg(feature = "window")]
pub use window::{WindowBuilder, Window, WindowProxy, PollEventsIterator, WaitEventsIterator};
@@ -65,11 +64,38 @@ pub use native_monitor::NativeMonitorId;
mod api;
mod platform;
mod events;
-#[cfg(feature = "headless")]
mod headless;
#[cfg(feature = "window")]
mod window;
+/// Trait that describes objects that have access to an OpenGL context.
+pub trait GlContext {
+ /// Sets the context as the current context.
+ unsafe fn make_current(&self);
+
+ /// Returns true if this context is the current one in this thread.
+ fn is_current(&self) -> bool;
+
+ /// Returns the address of an OpenGL function.
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void;
+
+ /// Swaps the buffers in case of double or triple buffering.
+ ///
+ /// You should call this function every time you have finished rendering, or the image
+ /// may not be displayed on the screen.
+ ///
+ /// **Warning**: if you enabled vsync, this function will block until the next time the screen
+ /// is refreshed. However drivers can choose to override your vsync settings, which means that
+ /// you can't know in advance whether `swap_buffers` will block or not.
+ fn swap_buffers(&self);
+
+ /// Returns the OpenGL API being used.
+ fn get_api(&self) -> Api;
+
+ /// Returns the pixel format of the main framebuffer of the context.
+ fn get_pixel_format(&self) -> PixelFormat;
+}
+
/// Error that can happen while creating a window or a headless renderer.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CreationError {
@@ -109,6 +135,15 @@ pub enum Api {
WebGl,
}
+/// Describes the requested OpenGL context profiles.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum GlProfile {
+ /// Include all the immediate more functions and definitions.
+ Compatibility,
+ /// Include all the future-compatible functions and definitions.
+ Core,
+}
+
/// Describes the OpenGL API and version that are being requested when a context is created.
#[derive(Debug, Copy, Clone)]
pub enum GlRequest {
@@ -133,6 +168,22 @@ pub enum GlRequest {
},
}
+impl GlRequest {
+ /// Extract the desktop GL version, if any.
+ 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,
+ }
+ }
+}
+
+/// The minimum core profile GL context. Useful for getting the minimum
+/// required GL version while still running on OSX, which often forbids
+/// the compatibility profile features.
+pub static GL_CORE: GlRequest = GlRequest::Specific(Api::OpenGl, (3, 2));
+
#[derive(Debug, Copy, Clone)]
pub enum MouseCursor {
/// The platform-dependent default cursor.
@@ -211,9 +262,7 @@ pub enum CursorState {
#[derive(Debug, Clone)]
pub struct PixelFormat {
pub hardware_accelerated: bool,
- pub red_bits: u8,
- pub green_bits: u8,
- pub blue_bits: u8,
+ pub color_bits: u8,
pub alpha_bits: u8,
pub depth_bits: u8,
pub stencil_bits: u8,
@@ -235,6 +284,7 @@ pub struct BuilderAttribs<'a> {
title: String,
monitor: Option<platform::MonitorID>,
gl_version: GlRequest,
+ gl_profile: Option<GlProfile>,
gl_debug: bool,
vsync: bool,
visible: bool,
@@ -257,6 +307,7 @@ impl BuilderAttribs<'static> {
title: "glutin window".to_string(),
monitor: None,
gl_version: GlRequest::Latest,
+ gl_profile: None,
gl_debug: cfg!(debug_assertions),
vsync: false,
visible: true,
@@ -283,6 +334,7 @@ impl<'a> BuilderAttribs<'a> {
title: self.title,
monitor: self.monitor,
gl_version: self.gl_version,
+ gl_profile: self.gl_profile,
gl_debug: self.gl_debug,
vsync: self.vsync,
visible: self.visible,
@@ -306,7 +358,7 @@ impl<'a> BuilderAttribs<'a> {
// TODO: do this more properly
for (id, format) in iter {
- if format.red_bits + format.green_bits + format.blue_bits < self.color_bits.unwrap_or(0) {
+ if format.color_bits < self.color_bits.unwrap_or(0) {
continue;
}
diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs
index c90d8ce..a1b9416 100644
--- a/src/platform/android/mod.rs
+++ b/src/platform/android/mod.rs
@@ -1,3 +1,34 @@
#![cfg(target_os = "android")]
pub use api::android::*;
+
+pub struct HeadlessContext(i32);
+
+impl HeadlessContext {
+ /// See the docs in the crate root file.
+ pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
+ unimplemented!()
+ }
+
+ /// See the docs in the crate root file.
+ pub unsafe fn make_current(&self) {
+ unimplemented!()
+ }
+
+ /// See the docs in the crate root file.
+ pub fn is_current(&self) -> bool {
+ unimplemented!()
+ }
+
+ /// See the docs in the crate root file.
+ pub fn get_proc_address(&self, _addr: &str) -> *const () {
+ unimplemented!()
+ }
+
+ pub fn get_api(&self) -> ::Api {
+ ::Api::OpenGlEs
+ }
+}
+
+unsafe impl Send for HeadlessContext {}
+unsafe impl Sync for HeadlessContext {}
diff --git a/src/platform/emscripten/mod.rs b/src/platform/emscripten/mod.rs
new file mode 100644
index 0000000..56a7e9f
--- /dev/null
+++ b/src/platform/emscripten/mod.rs
@@ -0,0 +1,44 @@
+#![cfg(target_os = "emscripten")]
+
+use GlContext;
+
+pub use api::emscripten::{Window, WindowProxy, MonitorID, get_available_monitors};
+pub use api::emscripten::{get_primary_monitor, WaitEventsIterator, PollEventsIterator};
+
+pub struct HeadlessContext(Window);
+
+impl HeadlessContext {
+ /// See the docs in the crate root file.
+ pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
+ Window::new(builder).map(|w| HeadlessContext(w))
+ }
+}
+
+impl GlContext for HeadlessContext {
+ unsafe fn make_current(&self) {
+ self.0.make_current()
+ }
+
+ fn is_current(&self) -> bool {
+ self.0.is_current()
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ self.0.get_proc_address(addr)
+ }
+
+ fn swap_buffers(&self) {
+ self.0.swap_buffers()
+ }
+
+ fn get_api(&self) -> Api {
+ self.0.get_api()
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.0.get_pixel_format()
+ }
+}
+
+unsafe impl Send for HeadlessContext {}
+unsafe impl Sync for HeadlessContext {}
diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 63a0118..1e12a80 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -1,7 +1,13 @@
#![cfg(target_os = "linux")]
-#[cfg(feature = "headless")]
-pub use api::osmesa::OsMesaContext as HeadlessContext;
+use Api;
+use BuilderAttribs;
+use CreationError;
+use GlContext;
+use PixelFormat;
+use libc;
+
+use api::osmesa::{self, OsMesaContext};
#[cfg(feature = "window")]
pub use api::x11::{Window, WindowProxy, MonitorID, get_available_monitors, get_primary_monitor};
@@ -12,3 +18,49 @@ pub use api::x11::{WaitEventsIterator, PollEventsIterator};
pub type Window = (); // TODO: hack to make things work
#[cfg(not(feature = "window"))]
pub type MonitorID = (); // TODO: hack to make things work
+
+pub struct HeadlessContext(OsMesaContext);
+
+impl HeadlessContext {
+ pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
+ match OsMesaContext::new(builder) {
+ Ok(c) => return Ok(HeadlessContext(c)),
+ Err(osmesa::OsMesaCreationError::NotSupported) => (),
+ Err(osmesa::OsMesaCreationError::CreationError(e)) => return Err(e),
+ };
+
+ Err(CreationError::NotSupported)
+ }
+}
+
+impl GlContext for HeadlessContext {
+ #[inline]
+ unsafe fn make_current(&self) {
+ self.0.make_current()
+ }
+
+ #[inline]
+ fn is_current(&self) -> bool {
+ self.0.is_current()
+ }
+
+ #[inline]
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ self.0.get_proc_address(addr)
+ }
+
+ #[inline]
+ fn swap_buffers(&self) {
+ self.0.swap_buffers()
+ }
+
+ #[inline]
+ fn get_api(&self) -> Api {
+ self.0.get_api()
+ }
+
+ #[inline]
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.0.get_pixel_format()
+ }
+}
diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs
index 78cbefc..260ab94 100644
--- a/src/platform/windows/mod.rs
+++ b/src/platform/windows/mod.rs
@@ -2,9 +2,13 @@
pub use api::win32::*;
+use libc;
+
use Api;
use BuilderAttribs;
use CreationError;
+use PixelFormat;
+use GlContext;
///
pub struct HeadlessContext(Window);
@@ -14,20 +18,30 @@ impl HeadlessContext {
builder.visible = false;
Window::new(builder).map(|w| HeadlessContext(w))
}
+}
- pub unsafe fn make_current(&self) {
+impl GlContext for HeadlessContext {
+ unsafe fn make_current(&self) {
self.0.make_current()
}
- pub fn is_current(&self) -> bool {
+ fn is_current(&self) -> bool {
self.0.is_current()
}
- pub fn get_proc_address(&self, addr: &str) -> *const () {
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
self.0.get_proc_address(addr)
}
- pub fn get_api(&self) -> Api {
+ fn swap_buffers(&self) {
+ self.0.swap_buffers()
+ }
+
+ fn get_api(&self) -> Api {
self.0.get_api()
}
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.0.get_pixel_format()
+ }
}
diff --git a/src/window.rs b/src/window.rs
index 0dd9905..c21b82d 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -6,6 +6,8 @@ use BuilderAttribs;
use CreationError;
use CursorState;
use Event;
+use GlContext;
+use GlProfile;
use GlRequest;
use MouseCursor;
use PixelFormat;
@@ -66,6 +68,12 @@ impl<'a> WindowBuilder<'a> {
self
}
+ /// Sets the desired OpenGL context profile.
+ pub fn with_gl_profile(mut self, profile: GlProfile) -> WindowBuilder<'a> {
+ self.attribs.gl_profile = Some(profile);
+ self
+ }
+
/// Sets the *debug* flag for the OpenGL context.
///
/// The default value for this flag is `cfg!(debug_assertions)`, which means that it's enabled
@@ -428,6 +436,32 @@ impl gl_common::GlFunctionsSource for Window {
}
}
+impl GlContext for Window {
+ unsafe fn make_current(&self) {
+ self.make_current()
+ }
+
+ fn is_current(&self) -> bool {
+ self.is_current()
+ }
+
+ fn get_proc_address(&self, addr: &str) -> *const libc::c_void {
+ self.get_proc_address(addr)
+ }
+
+ fn swap_buffers(&self) {
+ self.swap_buffers()
+ }
+
+ fn get_api(&self) -> Api {
+ self.get_api()
+ }
+
+ fn get_pixel_format(&self) -> PixelFormat {
+ self.get_pixel_format()
+ }
+}
+
/// Represents a thread safe subset of operations that can be called
/// on a window. This structure can be safely cloned and sent between
/// threads.
@@ -437,7 +471,6 @@ pub struct WindowProxy {
}
impl WindowProxy {
-
/// Triggers a blocked event loop to wake up. This is
/// typically called when another thread wants to wake
/// up the blocked rendering thread to cause a refresh.