diff options
Diffstat (limited to 'src/osx/headless.rs')
-rw-r--r-- | src/osx/headless.rs | 109 |
1 files changed, 109 insertions, 0 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); + } + } +} |