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#[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#[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#[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#[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
118pub unsafe fn swap_interval(interval: i32) -> bool {
124 ffi::wglSwapIntervalEXT(interval)
125}
126
127pub 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
152pub 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}