use std::ffi::{c_void, CStr};
use std::num::NonZeroI32;
use std::rc::Rc;
use windows_core::{s, PCSTR};
use windows_sys::Win32::Graphics::OpenGL::wglGetProcAddress;
use crate::gl::*;
use crate::warn;
use crate::wrappers::win32::window::{
with_dummy_window, HWnd, OwnDeviceContext, PixelFormat, PixelFormatAttribs, WglContext,
WglExtra,
};
use crate::wrappers::win32::LibraryModule;
pub type GlContext = Rc<GlContextInner>;
pub struct GlContextInner {
hdc: OwnDeviceContext,
wgl_ctx: WglContext,
gl_library: LibraryModule,
}
impl GlContextInner {
pub fn create(window: HWnd, config: GlConfig) -> Result<Self, windows_core::Error> {
let gl_library = unsafe { LibraryModule::load(s!("opengl32.dll"))? };
let extra = with_dummy_window(|hwnd_tmp| {
let hdc = hwnd_tmp.get_own_dc()?;
hdc.set_pixel_format(&PixelFormat::default())?;
let wgl_ctx = hdc.create_wgl_context()?;
wgl_ctx.with_current(&hdc, WglExtra::load)
})?;
let hdc = window.get_own_dc()?;
match find_wgl_pixel_format(&extra, &hdc, &config) {
Some(format) => hdc.set_pixel_format_from_index(format)?,
None => hdc.set_pixel_format(&PixelFormat::from_config(&config))?,
}
let wgl_ctx = match extra.create_context_for_config(&hdc, &config) {
Ok(wgl_ctx) => wgl_ctx,
Err(e) => {
warn!("Could not create OpenGL context from OpenGL config attributes: {}. Attempting fallback.", e);
hdc.create_wgl_context()?
}
};
if let Err(e) | Ok(Err(e)) = wgl_ctx.with_current(&hdc, || extra.set_vsync(config.vsync)) {
warn!("Could not set vsync: {}", e);
}
Ok(Self { hdc, wgl_ctx, gl_library })
}
pub unsafe fn make_current(&self) -> Result<(), super::Error> {
self.wgl_ctx.make_current(&self.hdc)?;
Ok(())
}
pub unsafe fn make_not_current(&self) -> Result<(), super::Error> {
self.wgl_ctx.make_not_current()?;
Ok(())
}
pub fn get_proc_address(&self, symbol: &CStr) -> *const c_void {
let symbol_ptr = symbol.as_ptr().cast();
if let Some(addr) = unsafe { wglGetProcAddress(symbol_ptr) } {
return addr as *const c_void;
}
let symbol_ptr = PCSTR::from_raw(symbol_ptr);
if let Some(addr) = unsafe { self.gl_library.get_proc_address(symbol_ptr) } {
return addr;
}
core::ptr::null()
}
pub fn swap_buffers(&self) -> Result<(), super::Error> {
self.hdc.swap_buffers()?;
Ok(())
}
}
fn find_wgl_pixel_format(
extra: &WglExtra, dc: &OwnDeviceContext, config: &GlConfig,
) -> Option<NonZeroI32> {
let mut format_attribs = PixelFormatAttribs::from_config(config);
match extra.choose_pixel_format_from_attribs(&format_attribs, dc) {
Ok(Some(format)) => return Some(format),
Err(e) => {
warn!("Could not choose optimal pixel format from GL configuration: {}", e);
return None;
}
Ok(None) => {}
};
crate::warn!("Warning: sRGB framebuffer not supported, falling back to non-sRGB");
format_attribs.set_without_srgb_ext();
match extra.choose_pixel_format_from_attribs(&format_attribs, dc) {
Ok(Some(format)) => return Some(format),
Err(e) => {
warn!("Could not choose optimal pixel format from GL configuration: {}", e);
return None;
}
Ok(None) => {}
};
None
}