1extern crate glium;
54extern crate sdl2;
55
56use std::mem;
57use std::cell::UnsafeCell;
58use std::ops::Deref;
59use std::rc::Rc;
60use std::os::raw::c_void;
61
62use glium::SwapBuffersError;
63use glium::debug;
64use glium::backend::{Backend, Context, Facade};
65use glium::IncompatibleOpenGl;
66use sdl2::VideoSubsystem;
67use sdl2::video::{Window, WindowBuildError};
68
69pub type Display = SDL2Facade;
70
71
72#[derive(Debug)]
73pub enum GliumSdl2Error {
74 WindowBuildError(WindowBuildError),
75 ContextCreationError(String)
76}
77
78impl From<String> for GliumSdl2Error {
79 fn from(s : String) -> GliumSdl2Error {
80 return GliumSdl2Error::ContextCreationError(s);
81 }
82}
83
84impl From<WindowBuildError> for GliumSdl2Error {
85 fn from(err : WindowBuildError) -> GliumSdl2Error {
86 return GliumSdl2Error::WindowBuildError(err);
87 }
88}
89
90impl From<IncompatibleOpenGl> for GliumSdl2Error {
91 fn from(err : IncompatibleOpenGl) -> GliumSdl2Error {
92 GliumSdl2Error::ContextCreationError(err.to_string())
93 }
94}
95
96impl std::error::Error for GliumSdl2Error {
97 fn description(&self) -> &str {
98 return match *self {
99 GliumSdl2Error::WindowBuildError(ref err) => err.description(),
100 GliumSdl2Error::ContextCreationError(ref s) => s
101 }
102 }
103
104 fn cause(&self) -> Option<&std::error::Error> {
105 match *self {
106 GliumSdl2Error::WindowBuildError(ref err) => err.cause(),
107 GliumSdl2Error::ContextCreationError(_) => None
108 }
109 }
110}
111
112impl std::fmt::Display for GliumSdl2Error {
113 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
114 match *self {
115 GliumSdl2Error::WindowBuildError(ref err) => err.fmt(formatter),
116 GliumSdl2Error::ContextCreationError(ref err) => err.fmt(formatter),
117 }
118 }
119}
120
121
122#[derive(Clone)]
124pub struct SDL2Facade {
125 context: Rc<Context>,
127
128 backend: Rc<SDL2WindowBackend>,
129}
130
131impl Facade for SDL2Facade {
132 fn get_context(&self) -> &Rc<Context> { &self.context }
133}
134
135impl Deref for SDL2Facade {
136 type Target = Context;
137
138 fn deref(&self) -> &Context { &self.context }
139}
140
141impl SDL2Facade {
142 pub fn window(&self) -> &Window {
143 self.backend.window()
144 }
145
146 pub fn window_mut(&mut self) -> &mut Window {
147 self.backend.window_mut()
148 }
149
150 pub fn draw(&self) -> glium::Frame {
157 glium::Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions())
158 }
159}
160
161pub trait DisplayBuild {
168 type Facade: glium::backend::Facade;
170
171 type Err;
173
174 fn build_glium(self) -> Result<Self::Facade, Self::Err> where Self: Sized {
179 self.build_glium_debug(Default::default())
180 }
181
182 fn build_glium_debug(self, debug::DebugCallbackBehavior) -> Result<Self::Facade, Self::Err>;
187
188 unsafe fn build_glium_unchecked(self) -> Result<Self::Facade, Self::Err> where Self: Sized {
193 self.build_glium_unchecked_debug(Default::default())
194 }
195
196 unsafe fn build_glium_unchecked_debug(self, debug::DebugCallbackBehavior)
201 -> Result<Self::Facade, Self::Err>;
202
203 }
207
208impl<'a> DisplayBuild for &'a mut sdl2::video::WindowBuilder {
209 type Facade = SDL2Facade;
210 type Err = GliumSdl2Error;
211
212 fn build_glium_debug(self, debug: debug::DebugCallbackBehavior) -> Result<SDL2Facade, GliumSdl2Error> {
213 let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
214 let context = try!(unsafe { Context::new(backend.clone(), true, debug) });
215
216 let display = SDL2Facade {
217 context: context,
218 backend: backend
219 };
220
221 Ok(display)
222 }
223
224 unsafe fn build_glium_unchecked_debug(self, debug: debug::DebugCallbackBehavior) -> Result<SDL2Facade, GliumSdl2Error> {
225 let backend = Rc::new(try!(SDL2WindowBackend::new(self)));
226 let context = try!(Context::new(backend.clone(), false, debug));
227
228 let display = SDL2Facade {
229 context: context,
230 backend: backend
231 };
232
233 Ok(display)
234 }
235}
236
237pub struct SDL2WindowBackend {
238 window: UnsafeCell<sdl2::video::Window>,
239 context: sdl2::video::GLContext
240}
241
242impl SDL2WindowBackend {
243 fn subsystem(&self) -> &VideoSubsystem {
244 let ptr = self.window.get();
245 let window: &Window = unsafe { mem::transmute(ptr) };
246 window.subsystem()
247 }
248
249 fn window(&self) -> &Window {
250 let ptr = self.window.get();
251 let window: &Window = unsafe { mem::transmute(ptr) };
252 window
253 }
254
255 fn window_mut(&self) -> &mut Window {
256 let ptr = self.window.get();
257 let window: &mut Window = unsafe { mem::transmute(ptr) };
258 window
259 }
260
261 pub fn new(window_builder: &mut sdl2::video::WindowBuilder) -> Result<SDL2WindowBackend, GliumSdl2Error> {
262 let window = try!(window_builder.opengl().build());
263 let context = try!(window.gl_create_context());
264
265 Ok(SDL2WindowBackend {
266 window: UnsafeCell::new(window),
267 context: context
268 })
269 }
270}
271
272unsafe impl Backend for SDL2WindowBackend {
273 fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
274 self.window().gl_swap_window();
275
276 Ok(())
280 }
281
282 unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
283 self.subsystem().gl_get_proc_address(symbol) as *const c_void
286 }
287
288 fn get_framebuffer_dimensions(&self) -> (u32, u32) {
289 let (width, height) = self.window().drawable_size();
290 (width as u32, height as u32)
291 }
292
293 fn is_current(&self) -> bool {
294 self.context.is_current()
295 }
296
297 unsafe fn make_current(&self) {
298 self.window().gl_make_current(&self.context).unwrap()
299 }
300}