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}