use winit::dpi::PhysicalSize;
use glutin::{
GlProfile, GlRequest, Api,
ContextBuilder,
Context, RawContext,
NotCurrent
};
use crate::geometry::Size;
use crate::draw::context::get_or_create_context;
use crate::draw::{gl, Options};
use crate::application::get_or_create_event_loop;
enum UnderlyingContext {
NoWindow(Context<NotCurrent>),
WithWindow(RawContext<NotCurrent>)
}
pub struct Surface {
context: Option<UnderlyingContext>, render_buffer: u32, frame_buffer: u32, size: Size
}
impl Surface {
pub fn new(size: Size, options: Options) -> Surface {
let event_loop = get_or_create_event_loop();
let shared_context = get_or_create_context();
let context_builder = ContextBuilder::new()
.with_gl(GlRequest::Specific(Api::OpenGlEs, (3, 2)))
.with_gl_profile(GlProfile::Core)
.with_shared_lists(shared_context);
let size_one = PhysicalSize::new(1, 1);
let context = context_builder.build_headless(&event_loop, size_one).unwrap();
let mut render_buffer = 0;
let mut frame_buffer = 0;
unsafe {
gl::GenRenderbuffers(1, &mut render_buffer);
gl::BindRenderbuffer(gl::RENDERBUFFER, render_buffer);
gl::RenderbufferStorage(
gl::RENDERBUFFER,
gl::RGB8,
size.width as _,
size.height as _,
);
gl::GenFramebuffers(1, &mut frame_buffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, frame_buffer);
gl::FramebufferRenderbuffer(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::RENDERBUFFER,
render_buffer,
);
gl::Viewport(0, 0, size.width as _, size.height as _);
}
Surface {
context: Some(UnderlyingContext::NoWindow(context)),
render_buffer: render_buffer,
frame_buffer: frame_buffer,
size: size
}
}
pub fn from_window(context: RawContext<NotCurrent>, size: Size) -> Surface {
Surface {
context: Some(UnderlyingContext::WithWindow(context)),
render_buffer: 0, frame_buffer: 0, size: size
}
}
pub fn resize(&mut self, size: Size) {
let mut context = self.context.take().unwrap();
context = match context {
UnderlyingContext::NoWindow(mut underlying_context) => {
underlying_context = unsafe {
let current_context = underlying_context.make_current().unwrap();
current_context.treat_as_not_current()
};
UnderlyingContext::NoWindow(underlying_context)
},
UnderlyingContext::WithWindow(mut underlying_context) => {
underlying_context = unsafe {
let current_context = underlying_context.make_current().unwrap();
current_context.resize(winit::dpi::PhysicalSize::new(size.width as _, size.height as _));
current_context.treat_as_not_current()
};
UnderlyingContext::WithWindow(underlying_context)
}
};
self.context = Some(context);
}
pub fn erase(&mut self) {
let color: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
unsafe {
gl::ClearColor(color[0], color[1], color[2], color[3]);
gl::Clear(gl::COLOR_BUFFER_BIT);
}
}
pub fn swap(&mut self) {
let mut context = self.context.take().unwrap();
context = match context {
UnderlyingContext::NoWindow(underlying_context) =>
UnderlyingContext::NoWindow(underlying_context),
UnderlyingContext::WithWindow(mut underlying_context) => {
underlying_context = unsafe {
let current_context = underlying_context.make_current().unwrap();
current_context.swap_buffers().unwrap();
current_context.treat_as_not_current()
};
UnderlyingContext::WithWindow(underlying_context)
}
};
self.context = Some(context);
}
pub fn activate(&mut self) {
let mut context = self.context.take().unwrap();
context = match context {
UnderlyingContext::NoWindow(mut underlying_context) => {
underlying_context = unsafe {
underlying_context.make_current().unwrap().treat_as_not_current()
};
UnderlyingContext::NoWindow(underlying_context)
},
UnderlyingContext::WithWindow(mut underlying_context) => {
underlying_context = unsafe {
underlying_context.make_current().unwrap().treat_as_not_current()
};
UnderlyingContext::WithWindow(underlying_context)
}
};
self.context = Some(context);
}
}