#![deny(clippy::all, clippy::pedantic)] use std::ffi::CString; use std::process::abort; use glutin::context::{NotCurrentContext, PossiblyCurrentContext}; use glutin::display::GetGlDisplay; use glutin::prelude::{GlDisplay, NotCurrentGlContext, PossiblyCurrentGlContext}; use glutin::surface::{GlSurface, Surface, SurfaceTypeTrait}; pub mod blending; pub mod buffer; pub mod data_types; pub mod debug; pub mod misc; pub mod shader; pub mod texture; pub mod vertex_array; pub struct MaybeCurrentContextWithFns { context: PossiblyCurrentContext, fns: Box, } impl MaybeCurrentContextWithFns { /// Returns a new `ContextWithFns`. /// /// # Errors /// Returns `Err` if making this context current fails. pub fn new( context: NotCurrentContext, surface: &Surface, ) -> Result { let context = context .make_current(surface) .map_err(MakeContextCurrentError)?; let display = context.display(); let gl = sys::Gl::load_with(|symbol| { let Ok(symbol) = CString::new(symbol) else { eprintln!("GL symbol contains nul byte"); abort(); }; display.get_proc_address(&symbol) }); Ok(Self { context, fns: Box::new(gl) }) } /// Attempts to make this context & the specified surface current in the calling /// thread. /// /// # Errors /// Returns `Err` if making this context current fails. pub fn make_current( &self, surface: &Surface, ) -> Result<(), MakeContextCurrentError> { if !self.context.is_current() || !surface.is_current(&self.context) { self.context .make_current(surface) .map_err(MakeContextCurrentError)?; } Ok(()) } /// Attempts to make this context current on the calling thread. /// /// # Errors /// Returns `Err` if making this context current fails. pub fn make_current_surfaceless(&self) -> Result<(), MakeContextCurrentError> { if !self.context.is_current() { make_glutin_context_current_surfaceless(&self.context) .map_err(MakeContextCurrentError)?; } Ok(()) } #[must_use] pub fn context(&self) -> &PossiblyCurrentContext { &self.context } #[inline] pub(crate) fn fns(&self) -> &sys::Gl { debug_assert!(self.context.is_current()); &self.fns } } #[derive(Debug, thiserror::Error)] #[error("Failed to make context current")] pub struct MakeContextCurrentError(#[source] glutin::error::Error); fn make_glutin_context_current_surfaceless( context: &PossiblyCurrentContext, ) -> Result<(), glutin::error::Error> { #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))] compile_error!("Unsupported target OS"); match context { #[cfg(any(target_os = "windows", target_os = "linux"))] PossiblyCurrentContext::Egl(context) => context.make_current_surfaceless(), #[cfg(target_os = "linux")] PossiblyCurrentContext::Glx(context) => context.make_current_surfaceless(), #[cfg(target_os = "windows")] PossiblyCurrentContext::Wgl(context) => context.make_current_surfaceless(), #[cfg(target_os = "macos")] PossiblyCurrentContext::Cgl(context) => context.make_current_surfaceless(), } } mod sys { #![allow( clippy::missing_safety_doc, clippy::missing_transmute_annotations, clippy::too_many_arguments, clippy::unused_unit, clippy::upper_case_acronyms, clippy::doc_markdown, clippy::unreadable_literal, unsafe_op_in_unsafe_fn )] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); }