tiny_gl/wgl/
mod.rs

1use bitflags::bitflags;
2use core::{ffi::c_void, ptr::NonNull};
3
4pub mod ffi;
5
6pub type HDC = NonNull<c_void>;
7pub type HGLRC = NonNull<c_void>;
8
9/// Represents the acceleration level of the graphics hardware.
10/// You almost certainly want to use `Acceleration::Full`.
11#[derive(Copy, Clone, PartialEq, Eq)]
12#[repr(i32)]
13pub enum Acceleration {
14    None = ffi::WGL_NO_ACCELERATION_ARB,
15    Generic = ffi::WGL_GENERIC_ACCELERATION_ARB,
16    Full = ffi::WGL_FULL_ACCELERATION_ARB,
17}
18
19/// A boolean value that can be used in integer attributes.
20#[derive(Copy, Clone, PartialEq, Eq)]
21#[repr(i32)]
22pub enum IntegerBool {
23    True = 1,
24    False = 0,
25}
26
27impl From<bool> for IntegerBool {
28    fn from(value: bool) -> Self {
29        if value {
30            IntegerBool::True
31        } else {
32            IntegerBool::False
33        }
34    }
35}
36
37#[derive(Copy, Clone, PartialEq, Eq)]
38#[repr(i32)]
39pub enum PixelType {
40    Rgba = ffi::WGL_TYPE_RGBA_ARB,
41}
42
43bitflags! {
44    #[derive(Copy, Clone, PartialEq, Eq)]
45    pub struct ProfileMask: i32 {
46        const Core = ffi::WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
47        const Compatibility = ffi::WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
48    }
49}
50
51bitflags! {
52    #[derive(Copy, Clone, PartialEq, Eq)]
53    pub struct ContextFlags: i32 {
54        const Debug = ffi::WGL_CONTEXT_DEBUG_BIT_ARB;
55        const ForwardCompatible = ffi::WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
56    }
57}
58
59/// Various attributes that can be used in choosing a pixel format.
60#[derive(Copy, Clone, PartialEq, Eq)]
61#[repr(C, i32)]
62pub enum PixelFormatAttribute {
63    End = 0,
64
65    DrawToWindow(IntegerBool) = ffi::WGL_DRAW_TO_WINDOW_ARB,
66    SupportOpenGL(IntegerBool) = ffi::WGL_SUPPORT_OPENGL_ARB,
67    DoubleBuffer(IntegerBool) = ffi::WGL_DOUBLE_BUFFER_ARB,
68    Acceleration(Acceleration) = ffi::WGL_ACCELERATION_ARB,
69    PixelType(PixelType) = ffi::WGL_PIXEL_TYPE_ARB,
70    ColorBits(i32) = ffi::WGL_COLOR_BITS_ARB,
71    DepthBits(i32) = ffi::WGL_DEPTH_BITS_ARB,
72    AlphaBits(i32) = ffi::WGL_ALPHA_BITS_ARB,
73    StencilBits(i32) = ffi::WGL_STENCIL_BITS_ARB,
74    SampleBuffers(IntegerBool) = ffi::WGL_SAMPLE_BUFFERS_ARB,
75    Samples(i32) = ffi::WGL_SAMPLES_ARB,
76}
77
78impl PixelFormatAttribute {
79    fn validate(attributes: &[Self]) {
80        if attributes.is_empty() {
81            panic!("IntegerAttributes list is empty")
82        }
83
84        let last = unsafe { *attributes.last().unwrap_unchecked() };
85
86        if last != Self::End {
87            panic!("IntegerAttributes list does not end with IntegerAttribute::End")
88        }
89    }
90}
91
92/// Various attributes that can be used in creating a context.
93#[derive(Copy, Clone, PartialEq, Eq)]
94#[repr(C, i32)]
95pub enum ContextAttribute {
96    End = 0,
97
98    MajorVersion(i32) = ffi::WGL_CONTEXT_MAJOR_VERSION_ARB,
99    MinorVersion(i32) = ffi::WGL_CONTEXT_MINOR_VERSION_ARB,
100    ProfileMask(ProfileMask) = ffi::WGL_CONTEXT_PROFILE_MASK_ARB,
101    Flags(ContextFlags) = ffi::WGL_CONTEXT_FLAGS_ARB,
102}
103
104impl ContextAttribute {
105    fn validate(attributes: &[Self]) {
106        if attributes.is_empty() {
107            panic!("IntegerAttributes list is empty")
108        }
109
110        let last = unsafe { *attributes.last().unwrap_unchecked() };
111
112        if last != Self::End {
113            panic!("IntegerAttributes list does not end with IntegerAttribute::End")
114        }
115    }
116}
117
118/// Set the swap interval.
119/// See https://raw.githubusercontent.com/KhronosGroup/OpenGL-Registry/refs/heads/main/extensions/EXT/WGL_EXT_swap_control.txt
120///
121/// # Notes
122/// This wraps [`ffi::wglSwapIntervalEXT`].
123pub unsafe fn swap_interval(interval: i32) -> bool {
124    ffi::wglSwapIntervalEXT(interval)
125}
126
127/// Create a new OpenGL context with the given attributes.
128/// See https://raw.githubusercontent.com/KhronosGroup/OpenGL-Registry/refs/heads/main/extensions/ARB/WGL_ARB_create_context.txt
129///
130/// # Notes
131/// This wraps [`ffi::wglCreateContextAttribsARB`].
132/// Make sure that integer_attributes is not empty and ends with IntegerAttribute::End.
133pub unsafe fn create_context_attributes(
134    hdc: HDC,
135    share_context: Option<HGLRC>,
136    integer_attributes: &[ContextAttribute],
137) -> Option<HGLRC> {
138    #[cfg(debug_assertions)]
139    ContextAttribute::validate(integer_attributes);
140
141    let share_context = share_context.map_or(core::ptr::null_mut(), NonNull::as_ptr);
142
143    let context = ffi::wglCreateContextAttribsARB(
144        hdc.as_ptr(),
145        share_context,
146        integer_attributes.as_ptr() as _,
147    );
148
149    NonNull::new(context)
150}
151
152/// Chooses a pixel format with the given attributes.
153/// See https://raw.githubusercontent.com/KhronosGroup/OpenGL-Registry/refs/heads/main/extensions/ARB/WGL_ARB_pixel_format.txt
154///
155/// # Notes
156/// This wraps [`ffi::wglChoosePixelFormatARB`].
157/// Make sure that integer_attributes is not empty and ends with IntegerAttribute::End.
158pub unsafe fn choose_pixel_format(
159    hdc: HDC,
160    integer_attributes: &[PixelFormatAttribute],
161    max_formats: u32,
162    pixel_format: &mut i32,
163    num_formats: &mut u32,
164) -> bool {
165    #[cfg(debug_assertions)]
166    PixelFormatAttribute::validate(integer_attributes);
167
168    ffi::wglChoosePixelFormatARB(
169        hdc.as_ptr(),
170        integer_attributes.as_ptr() as _,
171        core::ptr::null(),
172        max_formats,
173        pixel_format,
174        num_formats,
175    )
176}