#![cfg(feature = "glutin")]
pub use glutin;
use glutin::surface::Surface;
use takeable_option::Takeable;
use crate::SwapBuffersError;
use crate::backend;
use crate::backend::Backend;
use crate::backend::Context;
use crate::context;
use crate::debug;
use crate::glutin::prelude::*;
use crate::glutin::context::PossiblyCurrentContext;
use crate::glutin::display::GetGlDisplay;
use crate::glutin::surface::{SurfaceTypeTrait, ResizeableSurface};
use std::cell::RefCell;
use std::error::Error;
use std::ffi::CString;
use std::fmt;
use std::num::NonZeroU32;
use std::ops::Deref;
use std::os::raw::c_void;
use std::rc::Rc;
use crate::{Frame, IncompatibleOpenGl};
pub struct ContextSurfacePair<T: SurfaceTypeTrait + ResizeableSurface> {
context: PossiblyCurrentContext,
surface: glutin::surface::Surface<T>,
}
impl<T: SurfaceTypeTrait + ResizeableSurface> ContextSurfacePair<T> {
fn new(context: PossiblyCurrentContext, surface: glutin::surface::Surface<T>) -> Self {
Self { context, surface }
}
#[inline]
pub fn get_framebuffer_dimensions(&self) -> (u32, u32) {
(self.surface.width().unwrap(), self.surface.height().unwrap())
}
#[inline]
pub fn swap_buffers(&self) -> Result<(), glutin::error::Error> {
self.surface.swap_buffers(&self.context)
}
#[inline]
pub fn resize(&self, new_size:(u32, u32)) {
let width = NonZeroU32::new(new_size.0).unwrap_or(NonZeroU32::new(1).unwrap());
let height = NonZeroU32::new(new_size.1).unwrap_or(NonZeroU32::new(1).unwrap());
self.surface.resize(&self.context, width, height);
}
}
impl<T: SurfaceTypeTrait + ResizeableSurface> Deref for ContextSurfacePair<T> {
type Target = PossiblyCurrentContext;
#[inline]
fn deref(&self) -> &PossiblyCurrentContext {
&self.context
}
}
#[derive(Clone)]
pub struct Display<T: SurfaceTypeTrait + ResizeableSurface + 'static> {
context: Rc<context::Context>,
gl_context: Rc<RefCell<Takeable<ContextSurfacePair<T>>>>,
}
#[derive(Clone)]
pub struct GlutinBackend<T: SurfaceTypeTrait + ResizeableSurface>(Rc<RefCell<Takeable<ContextSurfacePair<T>>>>);
#[derive(Debug)]
pub enum DisplayCreationError {
GlutinError(glutin::error::Error),
IncompatibleOpenGl(IncompatibleOpenGl),
}
impl<T: SurfaceTypeTrait + ResizeableSurface> std::fmt::Debug for Display<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[glium::backend::glutin::Display]")
}
}
impl<T: SurfaceTypeTrait + ResizeableSurface> Display<T> {
pub fn new(
context: PossiblyCurrentContext,
surface: Surface<T>,
) -> Result<Self, DisplayCreationError> {
Self::from_context_surface(context, surface).map_err(From::from)
}
pub fn from_context_surface(
context: PossiblyCurrentContext,
surface: Surface<T>,
) -> Result<Self, IncompatibleOpenGl> {
Self::with_debug(context, surface, Default::default())
}
pub unsafe fn unchecked(
context: PossiblyCurrentContext,
surface: Surface<T>,
) -> Result<Self, IncompatibleOpenGl> {
Self::unchecked_with_debug(context, surface, Default::default())
}
pub fn with_debug(
context: PossiblyCurrentContext,
surface: Surface<T>,
debug: debug::DebugCallbackBehavior,
) -> Result<Self, IncompatibleOpenGl> {
Self::new_inner(context, surface, debug, true)
}
pub unsafe fn unchecked_with_debug(
context: PossiblyCurrentContext,
surface: Surface<T>,
debug: debug::DebugCallbackBehavior,
) -> Result<Self, IncompatibleOpenGl> {
Self::new_inner(context, surface, debug, false)
}
fn new_inner(
context: PossiblyCurrentContext,
surface: Surface<T>,
debug: debug::DebugCallbackBehavior,
checked: bool,
) -> Result<Self, IncompatibleOpenGl> {
let context_surface_pair = ContextSurfacePair::new(context, surface);
let gl_window = Rc::new(RefCell::new(Takeable::new(context_surface_pair)));
let glutin_backend = GlutinBackend(gl_window.clone());
let context = unsafe { context::Context::new(glutin_backend, checked, debug) }?;
Ok(Display {
gl_context: gl_window,
context,
})
}
#[inline]
pub fn resize(&self, new_size:(u32, u32)) {
self.gl_context.borrow().resize(new_size)
}
#[inline]
pub fn draw(&self) -> Frame {
let dimensions = self.get_framebuffer_dimensions();
Frame::new(self.context.clone(), dimensions)
}
}
impl fmt::Display for DisplayCreationError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
DisplayCreationError::GlutinError(err) => write!(fmt, "{}", err),
DisplayCreationError::IncompatibleOpenGl(err) => write!(fmt, "{}", err),
}
}
}
impl Error for DisplayCreationError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
DisplayCreationError::GlutinError(ref err) => Some(err),
DisplayCreationError::IncompatibleOpenGl(ref err) => Some(err),
}
}
}
impl From<glutin::error::Error> for DisplayCreationError {
#[inline]
fn from(err: glutin::error::Error) -> DisplayCreationError {
DisplayCreationError::GlutinError(err)
}
}
impl From<IncompatibleOpenGl> for DisplayCreationError {
#[inline]
fn from(err: IncompatibleOpenGl) -> DisplayCreationError {
DisplayCreationError::IncompatibleOpenGl(err)
}
}
impl<T: SurfaceTypeTrait + ResizeableSurface> Deref for Display<T> {
type Target = Context;
#[inline]
fn deref(&self) -> &Context {
&self.context
}
}
impl<T: SurfaceTypeTrait + ResizeableSurface> backend::Facade for Display<T> {
#[inline]
fn get_context(&self) -> &Rc<Context> {
&self.context
}
}
impl<T: SurfaceTypeTrait + ResizeableSurface> Deref for GlutinBackend<T> {
type Target = Rc<RefCell<Takeable<ContextSurfacePair<T>>>>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
unsafe impl<T: SurfaceTypeTrait + ResizeableSurface> Backend for GlutinBackend<T> {
#[inline]
fn swap_buffers(&self) -> Result<(), SwapBuffersError> {
match self.borrow().swap_buffers() {
Ok(()) => Ok(()),
_ => Err(SwapBuffersError::ContextLost),
}
}
#[inline]
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
let symbol = CString::new(symbol).unwrap();
self.borrow().display().get_proc_address(&symbol) as *const _
}
#[inline]
fn get_framebuffer_dimensions(&self) -> (u32, u32) {
self.0.borrow().get_framebuffer_dimensions()
}
#[inline]
fn resize(&self, new_size:(u32, u32)) {
self.borrow().resize(new_size)
}
#[inline]
fn is_current(&self) -> bool {
self.borrow().is_current()
}
#[inline]
unsafe fn make_current(&self) {
let pair = self.borrow();
pair.context.make_current(&pair.surface).unwrap();
}
}
#[cfg(feature = "simple_window_builder")]
pub struct SimpleWindowBuilder {
builder: winit::window::WindowBuilder
}
#[cfg(feature = "simple_window_builder")]
impl SimpleWindowBuilder {
pub fn new() -> Self {
Self {
builder: winit::window::WindowBuilder::new()
.with_title("Simple Glium Window")
.with_inner_size(winit::dpi::PhysicalSize::new(800, 480))
}
}
pub fn with_inner_size(mut self, width: u32, height: u32) -> Self {
self.builder = self.builder.with_inner_size(winit::dpi::PhysicalSize::new(width, height));
self
}
pub fn with_title(mut self, title: &str) -> Self {
self.builder = self.builder.with_title(title);
self
}
pub fn set_window_builder(mut self, window_builder: winit::window::WindowBuilder) -> Self {
self.builder = window_builder;
self
}
pub fn into_window_builder(self) -> winit::window::WindowBuilder {
self.builder
}
pub fn build<T>(self, event_loop: &winit::event_loop::EventLoop<T>) -> (winit::window::Window, Display<glutin::surface::WindowSurface>) {
use glutin::prelude::*;
use raw_window_handle::HasRawWindowHandle;
let display_builder = glutin_winit::DisplayBuilder::new().with_window_builder(Some(self.builder));
let config_template_builder = glutin::config::ConfigTemplateBuilder::new();
let (window, gl_config) = display_builder
.build(&event_loop, config_template_builder, |mut configs| {
configs.next().unwrap()
})
.unwrap();
let window = window.unwrap();
let (width, height): (u32, u32) = window.inner_size().into();
let attrs = glutin::surface::SurfaceAttributesBuilder::<glutin::surface::WindowSurface>::new().build(
window.raw_window_handle(),
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
);
let surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() };
let context_attributes = glutin::context::ContextAttributesBuilder::new().build(Some(window.raw_window_handle()));
let current_context = Some(unsafe {
gl_config.display().create_context(&gl_config, &context_attributes).expect("failed to create context")
}).unwrap().make_current(&surface).unwrap();
let display = Display::from_context_surface(current_context, surface).unwrap();
(window, display)
}
}