summaryrefslogtreecommitdiff
path: root/opengl-bindings/src/lib.rs
blob: 7fd9933c324263306c164bab93f559fa378dab2c (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
#![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::{Surface, SurfaceTypeTrait};

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 ContextWithFns
{
    context: PossiblyCurrentContext,
    fns: Box<sys::Gl>,
}

impl ContextWithFns
{
    /// Returns a new `ContextWithFns`.
    ///
    /// # Errors
    /// Returns `Err` if making this context current fails.
    pub fn new<SurfaceType: SurfaceTypeTrait>(
        context: NotCurrentContext,
        surface: &Surface<SurfaceType>,
    ) -> Result<Self, Error>
    {
        let context = context
            .make_current(surface)
            .map_err(Error::MakeContextCurrentFailed)?;

        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 current.
    ///
    /// # Errors
    /// Returns `Err` if making this context current fails.
    pub fn make_current<SurfaceType: SurfaceTypeTrait>(
        &self,
        surface: &Surface<SurfaceType>,
    ) -> Result<CurrentContextWithFns<'_>, Error>
    {
        if !self.context.is_current() {
            self.context
                .make_current(surface)
                .map_err(Error::MakeContextCurrentFailed)?;
        }

        Ok(CurrentContextWithFns { ctx: self })
    }

    #[must_use]
    pub fn context(&self) -> &PossiblyCurrentContext
    {
        &self.context
    }

    #[must_use]
    pub fn context_mut(&mut self) -> &mut PossiblyCurrentContext
    {
        &mut self.context
    }
}

pub struct CurrentContextWithFns<'ctx>
{
    ctx: &'ctx ContextWithFns,
}

impl CurrentContextWithFns<'_>
{
    #[inline]
    pub(crate) fn fns(&self) -> &sys::Gl
    {
        &self.ctx.fns
    }
}

#[derive(Debug, thiserror::Error)]
pub enum Error
{
    #[error("Failed to make context current")]
    MakeContextCurrentFailed(#[source] glutin::error::Error),
}

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"));
}