use super::events::*;
use super::window_properties::*;
use flo_stream::*;
use flo_render::*;
use flo_binding::*;
use glutin::{WindowedContext, NotCurrent};
use glutin::dpi::{LogicalSize};
use glutin::window::{Fullscreen};
use futures::prelude::*;
use futures::task::{Poll, Context};
use gl;
use std::pin::*;
pub struct GlutinWindow {
context: Option<WindowedContext<NotCurrent>>,
renderer: Option<GlRenderer>
}
impl GlutinWindow {
pub fn new(context: WindowedContext<NotCurrent>) -> GlutinWindow {
GlutinWindow {
context: Some(context),
renderer: None
}
}
}
pub (super) async fn send_actions_to_window<RenderStream: Unpin+Stream<Item=Vec<RenderAction>>, EventPublisher: MessagePublisher<Message=DrawEvent>>(window: GlutinWindow, render_actions: RenderStream, events: EventPublisher, window_properties: WindowProperties) {
let mut window = window;
let mut events = events;
let mut window_actions = WindowUpdateStream {
render_stream: render_actions,
title_stream: follow(window_properties.title),
size: follow(window_properties.size),
fullscreen: follow(window_properties.fullscreen),
has_decorations: follow(window_properties.has_decorations),
mouse_pointer: follow(window_properties.mouse_pointer)
};
while let Some(next_action) = window_actions.next().await {
match next_action {
WindowUpdate::Render(next_action) => {
if next_action.len() == 0 {
continue;
}
let show_frame_buffer = if next_action[next_action.len() - 1] == RenderAction::ShowFrameBuffer {
true
} else {
next_action.iter().any(|item| item == &RenderAction::ShowFrameBuffer)
};
unsafe {
let current_context = window.context.take().expect("Window context");
let current_context = current_context.make_current();
let current_context = if let Ok(context) = current_context { context } else { break; };
let size = current_context.window().inner_size();
let width = size.width as usize;
let height = size.height as usize;
if window.renderer.is_none() {
gl::load_with(|symbol_name| {
current_context.get_proc_address(symbol_name)
});
window.renderer = Some(GlRenderer::new());
}
window.renderer.as_mut().map(move |renderer| {
renderer.prepare_to_render_to_active_framebuffer(width, height);
renderer.render(next_action);
});
if show_frame_buffer {
current_context.swap_buffers().ok();
}
let context = current_context.make_not_current();
let context = if let Ok(context) = context { context } else { break; };
window.context = Some(context);
events.publish(DrawEvent::NewFrame).await;
}
}
WindowUpdate::SetTitle(new_title) => {
window.context.as_ref().map(|ctxt| ctxt.window().set_title(&new_title));
}
WindowUpdate::SetSize((size_x, size_y)) => {
window.context.as_ref().map(|ctxt| ctxt.window().set_inner_size(LogicalSize::new(size_x as f64, size_y as _)));
}
WindowUpdate::SetFullscreen(is_fullscreen) => {
let fullscreen = if is_fullscreen { Some(Fullscreen::Borderless(None)) } else { None };
window.context.as_ref().map(|ctxt| ctxt.window().set_fullscreen(fullscreen));
}
WindowUpdate::SetHasDecorations(decorations) => {
window.context.as_ref().map(|ctxt| ctxt.window().set_decorations(decorations));
}
WindowUpdate::SetMousePointer(MousePointer::None) => {
window.context.as_ref().map(|ctxt| ctxt.window().set_cursor_visible(false));
}
WindowUpdate::SetMousePointer(MousePointer::SystemDefault) => {
window.context.as_ref().map(|ctxt| ctxt.window().set_cursor_visible(true));
}
}
}
}
enum WindowUpdate {
Render(Vec<RenderAction>),
SetTitle(String),
SetSize((u64, u64)),
SetFullscreen(bool),
SetHasDecorations(bool),
SetMousePointer(MousePointer)
}
struct WindowUpdateStream<TRenderStream, TTitleStream, TSizeStream, TFullscreenStream, TDecorationStream, TMousePointerStream> {
render_stream: TRenderStream,
title_stream: TTitleStream,
size: TSizeStream,
fullscreen: TFullscreenStream,
has_decorations: TDecorationStream,
mouse_pointer: TMousePointerStream
}
impl<TRenderStream, TTitleStream, TSizeStream, TFullscreenStream, TDecorationStream, TMousePointerStream> Stream for WindowUpdateStream<TRenderStream, TTitleStream, TSizeStream, TFullscreenStream, TDecorationStream, TMousePointerStream>
where
TRenderStream: Unpin+Stream<Item=Vec<RenderAction>>,
TTitleStream: Unpin+Stream<Item=String>,
TSizeStream: Unpin+Stream<Item=(u64, u64)>,
TFullscreenStream: Unpin+Stream<Item=bool>,
TDecorationStream: Unpin+Stream<Item=bool>,
TMousePointerStream: Unpin+Stream<Item=MousePointer> {
type Item = WindowUpdate;
fn poll_next(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.render_stream.poll_next_unpin(context) {
Poll::Ready(Some(item)) => { return Poll::Ready(Some(WindowUpdate::Render(item))); }
Poll::Ready(None) => { return Poll::Ready(None); }
Poll::Pending => { }
}
match self.title_stream.poll_next_unpin(context) {
Poll::Ready(Some(item)) => { return Poll::Ready(Some(WindowUpdate::SetTitle(item))); }
Poll::Ready(None) => { return Poll::Ready(None); }
Poll::Pending => { }
}
match self.size.poll_next_unpin(context) {
Poll::Ready(Some(item)) => { return Poll::Ready(Some(WindowUpdate::SetSize(item))); }
Poll::Ready(None) => { return Poll::Ready(None); }
Poll::Pending => { }
}
match self.fullscreen.poll_next_unpin(context) {
Poll::Ready(Some(item)) => { return Poll::Ready(Some(WindowUpdate::SetFullscreen(item))); }
Poll::Ready(None) => { return Poll::Ready(None); }
Poll::Pending => { }
}
match self.has_decorations.poll_next_unpin(context) {
Poll::Ready(Some(item)) => { return Poll::Ready(Some(WindowUpdate::SetHasDecorations(item))); }
Poll::Ready(None) => { return Poll::Ready(None); }
Poll::Pending => { }
}
match self.mouse_pointer.poll_next_unpin(context) {
Poll::Ready(Some(item)) => { return Poll::Ready(Some(WindowUpdate::SetMousePointer(item))); }
Poll::Ready(None) => { return Poll::Ready(None); }
Poll::Pending => { }
}
Poll::Pending
}
}