use bitflags::bitflags;
use core::{ffi::c_void, ptr::NonNull};
pub mod ffi;
pub type HDC = NonNull<c_void>;
pub type HGLRC = NonNull<c_void>;
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(i32)]
pub enum Acceleration {
None = ffi::WGL_NO_ACCELERATION_ARB,
Generic = ffi::WGL_GENERIC_ACCELERATION_ARB,
Full = ffi::WGL_FULL_ACCELERATION_ARB,
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(i32)]
pub enum IntegerBool {
True = 1,
False = 0,
}
impl From<bool> for IntegerBool {
fn from(value: bool) -> Self {
if value {
IntegerBool::True
} else {
IntegerBool::False
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(i32)]
pub enum PixelType {
Rgba = ffi::WGL_TYPE_RGBA_ARB,
}
bitflags! {
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct ProfileMask: i32 {
const Core = ffi::WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
const Compatibility = ffi::WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
}
}
bitflags! {
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct ContextFlags: i32 {
const Debug = ffi::WGL_CONTEXT_DEBUG_BIT_ARB;
const ForwardCompatible = ffi::WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(C, i32)]
pub enum PixelFormatAttribute {
End = 0,
DrawToWindow(IntegerBool) = ffi::WGL_DRAW_TO_WINDOW_ARB,
SupportOpenGL(IntegerBool) = ffi::WGL_SUPPORT_OPENGL_ARB,
DoubleBuffer(IntegerBool) = ffi::WGL_DOUBLE_BUFFER_ARB,
Acceleration(Acceleration) = ffi::WGL_ACCELERATION_ARB,
PixelType(PixelType) = ffi::WGL_PIXEL_TYPE_ARB,
ColorBits(i32) = ffi::WGL_COLOR_BITS_ARB,
DepthBits(i32) = ffi::WGL_DEPTH_BITS_ARB,
AlphaBits(i32) = ffi::WGL_ALPHA_BITS_ARB,
StencilBits(i32) = ffi::WGL_STENCIL_BITS_ARB,
SampleBuffers(IntegerBool) = ffi::WGL_SAMPLE_BUFFERS_ARB,
Samples(i32) = ffi::WGL_SAMPLES_ARB,
}
impl PixelFormatAttribute {
fn validate(attributes: &[Self]) {
if attributes.is_empty() {
panic!("IntegerAttributes list is empty")
}
let last = unsafe { *attributes.last().unwrap_unchecked() };
if last != Self::End {
panic!("IntegerAttributes list does not end with IntegerAttribute::End")
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(C, i32)]
pub enum ContextAttribute {
End = 0,
MajorVersion(i32) = ffi::WGL_CONTEXT_MAJOR_VERSION_ARB,
MinorVersion(i32) = ffi::WGL_CONTEXT_MINOR_VERSION_ARB,
ProfileMask(ProfileMask) = ffi::WGL_CONTEXT_PROFILE_MASK_ARB,
Flags(ContextFlags) = ffi::WGL_CONTEXT_FLAGS_ARB,
}
impl ContextAttribute {
fn validate(attributes: &[Self]) {
if attributes.is_empty() {
panic!("IntegerAttributes list is empty")
}
let last = unsafe { *attributes.last().unwrap_unchecked() };
if last != Self::End {
panic!("IntegerAttributes list does not end with IntegerAttribute::End")
}
}
}
pub unsafe fn swap_interval(interval: i32) -> bool {
ffi::wglSwapIntervalEXT(interval)
}
pub unsafe fn create_context_attributes(
hdc: HDC,
share_context: Option<HGLRC>,
integer_attributes: &[ContextAttribute],
) -> Option<HGLRC> {
#[cfg(debug_assertions)]
ContextAttribute::validate(integer_attributes);
let share_context = share_context.map_or(core::ptr::null_mut(), NonNull::as_ptr);
let context = ffi::wglCreateContextAttribsARB(
hdc.as_ptr(),
share_context,
integer_attributes.as_ptr() as _,
);
NonNull::new(context)
}
pub unsafe fn choose_pixel_format(
hdc: HDC,
integer_attributes: &[PixelFormatAttribute],
max_formats: u32,
pixel_format: &mut i32,
num_formats: &mut u32,
) -> bool {
#[cfg(debug_assertions)]
PixelFormatAttribute::validate(integer_attributes);
ffi::wglChoosePixelFormatARB(
hdc.as_ptr(),
integer_attributes.as_ptr() as _,
core::ptr::null(),
max_formats,
pixel_format,
num_formats,
)
}