use crate::windows::{
Window,
WinCore,
WinError,
core::device_context::{
PixelType,
PixelFormat,
PixelBufferProperty,
PixelBufferProperties,
DeviceContextHandle,
},
core::window::WindowHandle,
core::render_context::RenderContextHandle,
};
use winapi::{
um::{
wingdi::{
wglGetProcAddress,
},
}
};
pub struct OpenGLRenderContext{
window:WindowHandle,
window_context:DeviceContextHandle,
render_context:RenderContextHandle,
wglSwapIntervalEXT:wglSwapIntervalEXT_t,
}
impl OpenGLRenderContext{
pub fn new(
window:&Window,
attributes:OpenGLRenderContextAttributes
)->Result<OpenGLRenderContext,WinError>{
let pixel_format=PixelFormat::new()
.set_color_bits(32)
.set_flags(
PixelBufferProperties::new()
.set(PixelBufferProperty::DrawToWindow)
.set(PixelBufferProperty::SupportOpenGL)
.set(PixelBufferProperty::DoubleBuffer)
)
.set_pixel_type(PixelType::RGBA);
unsafe{
let window_context=window.get_context_unchecked();
let pixel_format_index=WinCore.device_context.choose_pixel_format(window_context,&pixel_format);
if pixel_format_index==0{
return Err(WinError::get_last_error())
}
if !WinCore.device_context.set_pixel_format(window_context,pixel_format_index,&pixel_format){
return Err(WinError::get_last_error())
}
let render_context=if let Some(render_context)=WinCore.render_context.wgl_create_context(window_context){
render_context
}
else{
return Err(WinError::get_last_error())
};
if !WinCore.render_context.wgl_make_current(Some(window_context),Some(render_context)){
return Err(WinError::get_last_error())
}
let wglSwapIntervalEXT:wglSwapIntervalEXT_t=core::mem::transmute(
wglGetProcAddress("wglSwapIntervalEXT\0".as_ptr() as *const i8)
);
wglSwapIntervalEXT.expect("wglSwapIntervalEXT is not loaded")(attributes.vsync as i32);
Ok(Self{
window:window.handle,
window_context,
render_context,
wglSwapIntervalEXT,
})
}
}
pub fn render_context(&self)->RenderContextHandle{
self.render_context
}
pub fn make_current(&self,current:bool)->Result<(),WinError>{
unsafe{
let result=if current{
WinCore.render_context.wgl_make_current(Some(self.window_context),Some(self.render_context))
}
else{
WinCore.render_context.wgl_make_current(None,None)
};
if result{
Ok(())
}
else{
Err(WinError::get_last_error())
}
}
}
pub fn swap_buffers(&self)->Result<(),WinError>{
unsafe{
if WinCore.device_context.swap_buffers(self.window_context){
Ok(())
}
else{
Err(WinError::get_last_error())
}
}
}
pub fn set_vsync(&self,enabled:bool)->Result<(),WinError>{
unsafe{
if self.wglSwapIntervalEXT.expect("wglSwapIntervalEXT is not loaded")(enabled as i32)==1{
Ok(())
}
else{
Err(WinError::get_last_error())
}
}
}
}
impl Drop for OpenGLRenderContext{
fn drop(&mut self){
unsafe{
WinCore.render_context.wgl_make_current(None,None);
WinCore.render_context.wgl_delete_context(self.render_context);
WinCore.device_context.release(self.window,self.window_context);
}
}
}
#[derive(Clone)]
pub struct OpenGLRenderContextAttributes{
pub vsync:bool,
}
impl OpenGLRenderContextAttributes{
pub fn new()->OpenGLRenderContextAttributes{
Self{
vsync:true,
}
}
}
pub type wglSwapIntervalEXT_t=Option<unsafe extern "system" fn(interval:i32)->i32>;