extern crate glium;
extern crate sdl2;
use std::mem;
use std::cell::UnsafeCell;
use std::ops::Deref;
use std::rc::Rc;
use std::os::raw::c_void;
use glium::SwapBuffersError;
use glium::debug;
use glium::backend::{Backend, Context, Facade};
use glium::IncompatibleOpenGl;
use sdl2::VideoSubsystem;
use sdl2::video::{Window, WindowBuildError};
pub type Display = SDL2Facade;
#[derive(Debug)]
pub enum GliumSdl2Error {
WindowBuildError(WindowBuildError),
ContextCreationError(String)
}
impl From<String> for GliumSdl2Error {
fn from(s : String) -> GliumSdl2Error {
return GliumSdl2Error::ContextCreationError(s);
}
}
impl From<WindowBuildError> for GliumSdl2Error {
fn from(err : WindowBuildError) -> GliumSdl2Error {
return GliumSdl2Error::WindowBuildError(err);
}
}
impl From<IncompatibleOpenGl> for GliumSdl2Error {
fn from(err : IncompatibleOpenGl) -> GliumSdl2Error {
GliumSdl2Error::ContextCreationError(err.to_string())
}
}
impl std::error::Error for GliumSdl2Error {
fn description(&self) -> &str {
return match *self {
GliumSdl2Error::WindowBuildError(ref err) => err.description(),
GliumSdl2Error::ContextCreationError(ref s) => s
}
}
fn cause(&self) -> Option<&std::error::Error> {
match *self {
GliumSdl2Error::WindowBuildError(ref err) => err.cause(),
GliumSdl2Error::ContextCreationError(_) => None
}
}
}
impl std::fmt::Display for GliumSdl2Error {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match *self {
GliumSdl2Error::WindowBuildError(ref err) => err.fmt(formatter),
GliumSdl2Error::ContextCreationError(ref err) => err.fmt(formatter),
}
}
}
#[derive(Clone)]
pub struct SDL2Facade {
context: Rc<Context>,
backend: Rc<SDL2WindowBackend>,
}
impl Facade for SDL2Facade {
fn get_context(&self) -> &Rc<Context> { &self.context }
}
impl Deref for SDL2Facade {
type Target = Context;
fn deref(&self) -> &Context { &self.context }
}
impl SDL2Facade {
pub fn window(&self) -> &Window {
self.backend.window()
}
pub fn window_mut(&mut self) -> &mut Window {
self.backend.window_mut()
}
pub fn draw(&self) -> glium::Frame {
glium::Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions())
}
}
pub trait DisplayBuild {
type Facade: glium::backend::Facade;
type Err;
fn build_glium(self) -> Result<Self::Facade, Self::Err> where Self: Sized {
self.build_glium_debug(Default::default())
}
fn build_glium_debug(self, debug::DebugCallbackBehavior) -> Result<Self::Facade, Self::Err>;
unsafe fn build_glium_unchecked(self) -> Result<Self::Facade, Self::Err> where Self: Sized {
self.build_glium_unchecked_debug(Default::default())
}
unsafe fn build_glium_unchecked_debug(self, debug::DebugCallbackBehavior)
-> Result<Self::Facade, Self::Err>;
}
impl<'a> DisplayBuild for &'a mut sdl2::video::WindowBuilder {
type Facade = SDL2Facade;
type Err = GliumSdl2Error;
fn build_glium_debug(self, debug: debug::DebugCallbackBehavior) -> Result<SDL2Facade, GliumSdl2Error> {
let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
let context = try!(unsafe { Context::new(backend.clone(), true, debug) });
let display = SDL2Facade {
context: context,
backend: backend
};
Ok(display)
}
unsafe fn build_glium_unchecked_debug(self, debug: debug::DebugCallbackBehavior) -> Result<SDL2Facade, GliumSdl2Error> {
let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
let context = try!(Context::new(backend.clone(), false, debug));
let display = SDL2Facade {
context: context,
backend: backend
};
Ok(display)
}
}
pub struct SDL2WindowBackend {
window: UnsafeCell<sdl2::video::Window>,
context: sdl2::video::GLContext
}
impl SDL2WindowBackend {
fn subsystem(&self) -> &VideoSubsystem {
let ptr = self.window.get();
let window: &Window = unsafe { mem::transmute(ptr) };
window.subsystem()
}
fn window(&self) -> &Window {
let ptr = self.window.get();
let window: &Window = unsafe { mem::transmute(ptr) };
window
}
fn window_mut(&self) -> &mut Window {
let ptr = self.window.get();
let window: &mut Window = unsafe { mem::transmute(ptr) };
window
}
pub fn new(window_builder: &mut sdl2::video::WindowBuilder) -> Result<SDL2WindowBackend, GliumSdl2Error> {
let window = try!(window_builder.opengl().build());
let context = try!(window.gl_create_context());
Ok(SDL2WindowBackend {
window: UnsafeCell::new(window),
context: context
})
}
}
unsafe impl Backend for SDL2WindowBackend {
fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
self.window().gl_swap_window();
Ok(())
}
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
self.subsystem().gl_get_proc_address(symbol) as *const c_void
}
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
let (width, height) = self.window().drawable_size();
(width as u32, height as u32)
}
fn is_current(&self) -> bool {
self.context.is_current()
}
unsafe fn make_current(&self) {
self.window().gl_make_current(&self.context).unwrap()
}
}