aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/cocoa/headless.rs
blob: 49b8bc3c8ad6cd384b48d4ecc459a11f420e04a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use ContextError;
use CreationError;
use CreationError::OsError;
use GlAttributes;
use GlContext;
use PixelFormatRequirements;
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::*;
use PixelFormat;

mod gl {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

static mut framebuffer: u32 = 0;
static mut texture: u32 = 0;

pub struct HeadlessContext {
    width: u32,
    height: u32,
    context: id,
}

impl HeadlessContext {
    pub fn new((width, height): (u32, u32), _pf_reqs: &PixelFormatRequirements,
               _opengl: &GlAttributes<&HeadlessContext>) -> Result<HeadlessContext, CreationError>
    {
        let context = unsafe {
            let attributes = [
                NSOpenGLPFAAccelerated as u32,
                NSOpenGLPFAAllowOfflineRenderers as u32,
                NSOpenGLPFADoubleBuffer as u32,
                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)
    }
}

impl GlContext for HeadlessContext {
    unsafe fn make_current(&self) -> Result<(), ContextError> {
        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");
        }

        Ok(())
    }

    #[inline]
    fn is_current(&self) -> bool {
        unimplemented!()
    }

    #[inline]
    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 {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const libc::c_void
    }

    #[inline]
    fn swap_buffers(&self) -> Result<(), ContextError> {
        Ok(())
    }

    #[inline]
    fn get_api(&self) -> ::Api {
        ::Api::OpenGl
    }

    #[inline]
    fn get_pixel_format(&self) -> PixelFormat {
        unimplemented!();
    }
}

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl Drop for HeadlessContext {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &texture);
            gl::DeleteFramebuffersEXT(1, &framebuffer);
        }
    }
}