diff options
-rw-r--r-- | src/osx/headless.rs | 109 | ||||
-rw-r--r-- | src/osx/mod.rs | 25 |
2 files changed, 115 insertions, 19 deletions
diff --git a/src/osx/headless.rs b/src/osx/headless.rs new file mode 100644 index 0000000..bbe3d9f --- /dev/null +++ b/src/osx/headless.rs @@ -0,0 +1,109 @@ +use CreationError; +use CreationError::OsError; +use HeadlessRendererBuilder; +use libc; +use std::ptr; + +use core_foundation::base::TCFType; +use core_foundation::string::CFString; +use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; +use cocoa::base::{id, nil}; +use cocoa::appkit::*; + +mod gl { + generate_gl_bindings! { + api: "gl", + profile: "core", + version: "3.2", + generator: "global", + extensions: ["GL_EXT_framebuffer_object"], + } +} + +static mut framebuffer: u32 = 0; +static mut texture: u32 = 0; + +pub struct HeadlessContext { + width: uint, + height: uint, + context: id, +} + +impl HeadlessContext { + pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> { + let (width, height) = builder.dimensions; + let context = unsafe { + let attributes = [ + NSOpenGLPFADoubleBuffer as uint, + NSOpenGLPFAClosestPolicy as uint, + NSOpenGLPFAColorSize as uint, 24, + NSOpenGLPFAAlphaSize as uint, 8, + NSOpenGLPFADepthSize as uint, 24, + NSOpenGLPFAStencilSize as uint, 8, + NSOpenGLPFAOffScreen as uint, + 0 + ]; + + let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes); + if pixelformat == nil { + return Err(OsError(format!("Could not create the pixel format"))); + } + let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil); + if context == nil { + return Err(OsError(format!("Could not create the rendering context"))); + } + context + }; + + let headless = HeadlessContext { + width: width, + height: height, + context: context, + }; + + // Load the function pointers as we need them to create the FBO + gl::load_with(|s| headless.get_proc_address(s) as *const libc::c_void); + + Ok(headless) + } + + pub unsafe fn make_current(&self) { + self.context.makeCurrentContext(); + + gl::GenFramebuffersEXT(1, &mut framebuffer); + gl::BindFramebufferEXT(gl::FRAMEBUFFER_EXT, framebuffer); + gl::GenTextures(1, &mut texture); + gl::BindTexture(gl::TEXTURE_2D, texture); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); + gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); + gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA8 as i32, self.width as i32, self.height as i32, + 0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null()); + gl::FramebufferTexture2DEXT(gl::FRAMEBUFFER_EXT, gl::COLOR_ATTACHMENT0_EXT, + gl::TEXTURE_2D, texture, 0); + let status = gl::CheckFramebufferStatusEXT(gl::FRAMEBUFFER_EXT); + if status != gl::FRAMEBUFFER_COMPLETE_EXT { + panic!("Error while creating the framebuffer"); + } + } + + pub fn get_proc_address(&self, _addr: &str) -> *const () { + let symbol_name: CFString = from_str(_addr).unwrap(); + let framework_name: CFString = 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 () + } +} + +impl Drop for HeadlessContext { + fn drop(&mut self) { + unsafe { + gl::DeleteTextures(1, &texture); + gl::DeleteFramebuffersEXT(1, &framebuffer); + } + } +} diff --git a/src/osx/mod.rs b/src/osx/mod.rs index 8ab3efd..0cb4553 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "headless")] +pub use self::headless::HeadlessContext; + use {CreationError, Event}; use CreationError::OsError; use libc; @@ -5,9 +8,6 @@ use libc; #[cfg(feature = "window")] use WindowBuilder; -#[cfg(feature = "headless")] -use HeadlessRendererBuilder; - use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable}; @@ -33,6 +33,9 @@ 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; static mut ctrl_pressed: bool = false; static mut win_pressed: bool = false; @@ -60,14 +63,6 @@ pub struct Window { state: Box<InternalState>, } -pub struct HeadlessContext(Window); - -impl Deref<Window> for HeadlessContext { - fn deref(&self) -> &Window { - &self.0 - } -} - #[cfg(feature = "window")] impl Window { pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { @@ -79,14 +74,6 @@ impl Window { } } -#[cfg(feature = "headless")] -impl HeadlessContext { - pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> { - Window::new_impl(Some(builder.dimensions), "", None, false) - .map(|w| HeadlessContext(w)) - } -} - extern fn window_should_close(this: id, _: id) -> id { unsafe { let mut stored_value = ptr::null_mut(); |