gl_headless/
lib.rs

1//! Easiest way to create a headless OpenGL context.
2//!
3//! Simply add <code>#[[gl_headless]]</code> to any function (even `main`),
4//! then call that function as you otherwise would. Within the
5//! scope of the function, an OpenGL context will be available.
6//!
7//! See all available options in the documentation for
8//! <code>#[[gl_headless]]</code>.
9//!
10//! ## Simple Example
11//!
12//! ```toml
13//! [dependencies]
14//! gl = "0.14"
15//! gl-headless = "0.2"
16//! ```
17//!
18//! ```rust
19//! use gl_headless::gl_headless;
20//!
21//! #[gl_headless]
22//! unsafe fn main() {
23//!     let (mut major, mut minor) = (0, 0);
24//!     gl::GetIntegerv(gl::MAJOR_VERSION, &mut major);
25//!     gl::GetIntegerv(gl::MINOR_VERSION, &mut minor);
26//!     println!("OpenGL {major}.{minor}");
27//! }
28//! ```
29//!
30//! ## Specify OpenGL Version
31//!
32//! By default <code>#[[gl_headless]]</code> attempts to create an OpenGL 4.6 context.
33//! To use a specific version add, e.g. `version = "3.3"`:
34//!
35//! ```rust
36//! use gl_headless::gl_headless;
37//!
38//! #[gl_headless(version = "3.3")]
39//! unsafe fn main() {
40//!     let (mut major, mut minor) = (0, 0);
41//!     gl::GetIntegerv(gl::MAJOR_VERSION, &mut major);
42//!     gl::GetIntegerv(gl::MINOR_VERSION, &mut minor);
43//!     println!("OpenGL {major}.{minor}");
44//! }
45//! ```
46//!
47//! ## Parameters & Return Type
48//!
49//! Specify function parameters and return type as you otherwise would:
50//!
51//! ```rust
52//! use gl_headless::gl_headless;
53//!
54//! fn main() {
55//!     let version = get_version("OpenGL");
56//!     println!("{version}");
57//! }
58//!
59//! #[gl_headless]
60//! fn get_version(prefix: &str) -> String {
61//!     let (mut major, mut minor) = (0, 0);
62//!     unsafe {
63//!         gl::GetIntegerv(gl::MAJOR_VERSION, &mut major);
64//!         gl::GetIntegerv(gl::MINOR_VERSION, &mut minor);
65//!     }
66//!     format!("{prefix} {major}.{minor}")
67//! }
68//! ```
69//!
70//! ## Multiple Functions
71//!
72//! Multiple functions can use <code>#[[gl_headless]]</code>.
73//! Simply call the function as you otherwise would:
74//!
75//! ```rust
76//! use gl_headless::gl_headless;
77//!
78//! fn main() {
79//!     unsafe {
80//!         example1();
81//!         example2();
82//!     }
83//! }
84//!
85//! #[gl_headless(version = "3.3")]
86//! unsafe fn example1() {
87//!     let (mut major, mut minor) = (0, 0);
88//!     gl::GetIntegerv(gl::MAJOR_VERSION, &mut major);
89//!     gl::GetIntegerv(gl::MINOR_VERSION, &mut minor);
90//!     println!("OpenGL {major}.{minor}");
91//! }
92//!
93//! #[gl_headless]
94//! unsafe fn example2() {
95//!     let mut handle = 0;
96//!     gl::CreateBuffers(1, &mut handle);
97//!
98//!     let data: [f32; 5] = [1.0, 2.0, 3.0, 4.0, 5.0];
99//!     gl::NamedBufferData(
100//!         handle,
101//!         std::mem::size_of_val(&data) as _,
102//!         data.as_ptr() as *const _,
103//!         gl::STATIC_DRAW,
104//!     );
105//!
106//!     let mut byte_size = 0;
107//!     gl::GetNamedBufferParameteriv(handle, gl::BUFFER_SIZE, &mut byte_size);
108//!     let float_count = (byte_size as usize) / std::mem::size_of::<f32>() as usize;
109//!
110//!     let mut floats = vec![0.0_f32; float_count];
111//!     gl::GetNamedBufferSubData(
112//!         handle,
113//!         0,
114//!         std::mem::size_of_val(floats.as_slice()) as _,
115//!         floats.as_mut_ptr() as *mut _,
116//!     );
117//!
118//!     println!("Write: {:?}", data);
119//!     println!("Read:  {:?}", floats);
120//!
121//!     assert_eq!(data, floats.as_slice());
122//! }
123//! ```
124//!
125//! [gl_headless]: https://docs.rs/gl-headless/*/gl_headless/attr.gl_headless.html
126
127#![forbid(unsafe_code)]
128#![forbid(elided_lifetimes_in_paths)]
129
130#[doc(hidden)]
131#[path = "internals.rs"]
132pub mod _internals;
133
134pub use gl_headless_macros::gl_headless;
135
136use std::error;
137use std::fmt;
138use std::num::ParseIntError;
139
140use glfw::InitError;
141
142#[doc(hidden)]
143#[derive(Debug)]
144pub enum HeadlessError {
145    Uninitialized(InitError),
146    InvalidVersionFormat(GLVersionError),
147    NoWindow,
148}
149
150impl error::Error for HeadlessError {
151    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
152        match self {
153            Self::Uninitialized(err) => Some(err),
154            Self::InvalidVersionFormat(err) => Some(err),
155            Self::NoWindow => None,
156        }
157    }
158}
159
160impl fmt::Display for HeadlessError {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        match self {
163            Self::Uninitialized(err) => write!(f, "unable to initialize glfw: {err}"),
164            Self::InvalidVersionFormat(err) => err.fmt(f),
165            Self::NoWindow => write!(f, "no window"),
166        }
167    }
168}
169
170impl From<GLVersionError> for HeadlessError {
171    #[inline]
172    fn from(err: GLVersionError) -> Self {
173        Self::InvalidVersionFormat(err)
174    }
175}
176
177#[doc(hidden)]
178#[derive(Debug)]
179pub enum GLVersionError {
180    InvalidVersion(String),
181    InvalidMajor(String, ParseIntError),
182    InvalidMinor(String, ParseIntError),
183}
184
185impl error::Error for GLVersionError {
186    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
187        match self {
188            Self::InvalidVersion(_) => None,
189            Self::InvalidMajor(_, err) => Some(err),
190            Self::InvalidMinor(_, err) => Some(err),
191        }
192    }
193}
194
195impl fmt::Display for GLVersionError {
196    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197        match self {
198            Self::InvalidVersion(version) => {
199                write!(f, "invalid version format: {version:?}")
200            }
201            Self::InvalidMajor(major, err) => write!(f, "invalid major format {major:?}: {err}"),
202            Self::InvalidMinor(minor, err) => write!(f, "invalid minor format {minor:?}: {err}"),
203        }
204    }
205}