#![allow(dead_code)]
use glium::{self, Display};
use glium::backend::Facade;
use glium::index::PrimitiveType;
use glutin::config::{Config, ConfigTemplateBuilder};
use glutin::context::ContextAttributesBuilder;
use glutin::display::GetGlDisplay;
use glutin::prelude::*;
use glutin::surface::{SurfaceAttributesBuilder, WindowSurface};
use glutin_winit::DisplayBuilder;
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use winit::event::Event;
use winit::event_loop::{EventLoopBuilder, EventLoopProxy};
use winit::window::{Window, WindowBuilder, WindowId};
use std::collections::HashMap;
use std::env;
use std::num::NonZeroU32;
use std::sync::{mpsc::Receiver, Mutex, Once, RwLock};
use std::thread;
#[cfg(unix)]
use winit::platform::x11::EventLoopBuilderExtX11;
#[cfg(windows)]
use winit::platform::windows::EventLoopBuilderExtWindows;
static mut EVENT_LOOP_PROXY: RwLock<Option<EventLoopProxy<()>>> = RwLock::new(None);
static mut WINDOW_RECEIVER: Mutex<Option<Receiver<(HandleOrWindow, Config)>>> = Mutex::new(None);
static mut INIT_EVENT_LOOP: Once = Once::new();
static mut SEND_PROXY: Once = Once::new();
#[derive(Debug)]
enum HandleOrWindow {
SendHandle(RawWindowHandle),
RefWindow(&'static Window),
}
impl From<&'static Window> for HandleOrWindow {
fn from(window: &'static Window) -> Self {
let raw_window_handle = window.raw_window_handle();
match raw_window_handle {
RawWindowHandle::Xlib(_) |
RawWindowHandle::Xcb(_) |
RawWindowHandle::Web(_) |
RawWindowHandle::Drm(_)
=> HandleOrWindow::SendHandle(raw_window_handle),
RawWindowHandle::UiKit(_) |
RawWindowHandle::AppKit(_) |
RawWindowHandle::Orbital(_) |
RawWindowHandle::Wayland(_) |
RawWindowHandle::Gbm(_) |
RawWindowHandle::Win32(_) |
RawWindowHandle::WinRt(_) |
RawWindowHandle::AndroidNdk(_) |
RawWindowHandle::Haiku(_)
=> HandleOrWindow::RefWindow(window),
_ => panic!("Unsupported"),
}
}
}
impl From<HandleOrWindow> for RawWindowHandle {
fn from(handle: HandleOrWindow) -> Self {
match handle {
HandleOrWindow::SendHandle(handle) => handle,
HandleOrWindow::RefWindow(window) => window.raw_window_handle(),
}
}
}
unsafe impl Send for HandleOrWindow {}
unsafe fn initialize_event_loop() {
INIT_EVENT_LOOP.call_once(|| {
let (ots, otr) = std::sync::mpsc::sync_channel(0);
let (sender, receiver) = std::sync::mpsc::channel();
let builder = thread::Builder::new().name("event_loop".into());
builder
.spawn(|| {
static mut WINDOWS: Option<HashMap<WindowId, Window>> = None;
WINDOWS = Some(HashMap::new());
let event_loop_res = if cfg!(unix) || cfg!(windows) {
EventLoopBuilder::new().with_any_thread(true).build()
} else {
EventLoopBuilder::new().build()
};
let event_loop = event_loop_res.expect("event loop building");
let proxy = event_loop.create_proxy();
event_loop.run(move |event, window_target| {
match event {
Event::UserEvent(_) => {
let window_builder = WindowBuilder::new().with_visible(false);
let config_template_builder = ConfigTemplateBuilder::new();
let display_builder =
DisplayBuilder::new().with_window_builder(Some(window_builder));
let (window, gl_config) = display_builder
.build(&window_target, config_template_builder, |mut configs| {
configs.next().unwrap()
})
.unwrap();
let window = window.unwrap();
let key = window.id();
WINDOWS.as_mut().unwrap().insert(key, window);
let window = &WINDOWS.as_ref().unwrap()[&key];
sender.send((window.into(), gl_config)).unwrap();
}
_ => {
SEND_PROXY.call_once(|| {
ots.send(proxy.clone()).unwrap();
});
}
}
})
.unwrap();
})
.unwrap();
let event_loop_proxy = otr.recv().unwrap();
*EVENT_LOOP_PROXY.write().unwrap() = Some(event_loop_proxy);
*WINDOW_RECEIVER.lock().unwrap() = Some(receiver);
});
}
pub fn build_display() -> Display<WindowSurface> {
unsafe { initialize_event_loop(); }
unsafe {
EVENT_LOOP_PROXY
.read().unwrap()
.as_ref().unwrap()
.send_event(()).unwrap();
}
let (handle_or_window, gl_config) = unsafe {
WINDOW_RECEIVER
.lock().unwrap()
.as_ref().unwrap()
.recv().unwrap()
};
let version = parse_version();
let raw_window_handle = handle_or_window.into();
let context_attributes = ContextAttributesBuilder::new()
.with_context_api(version)
.build(Some(raw_window_handle));
let not_current_gl_context = unsafe {
gl_config.display().create_context(&gl_config, &context_attributes).unwrap()
};
let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
raw_window_handle,
NonZeroU32::new(800).unwrap(),
NonZeroU32::new(600).unwrap(),
);
let surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() };
let current_context = not_current_gl_context.make_current(&surface).unwrap();
Display::from_context_surface(current_context, surface).unwrap()
}
pub fn rebuild_display(_display: &glium::Display<WindowSurface>) {
todo!();
}
fn parse_version() -> glutin::context::ContextApi {
match env::var("GLIUM_GL_VERSION") {
Ok(version) => {
let mut iter = version.rsplitn(2, ' ');
let version = iter.next().unwrap();
let ty = iter.next().unwrap();
let mut iter = version.split('.');
let major = iter.next().unwrap().parse().unwrap();
let minor = iter.next().unwrap().parse().unwrap();
if ty == "OpenGL" {
glutin::context::ContextApi::OpenGl(Some(glutin::context::Version::new(major, minor)))
} else if ty == "OpenGL ES" {
glutin::context::ContextApi::Gles(Some(glutin::context::Version::new(major, minor)))
} else if ty == "WebGL" {
glutin::context::ContextApi::Gles(Some(glutin::context::Version::new(major, minor)))
} else {
panic!();
}
},
Err(_) => glutin::context::ContextApi::OpenGl(None),
}
}
pub fn build_unicolor_texture2d<F: ?Sized>(facade: &F, red: f32, green: f32, blue: f32)
-> glium::Texture2d where F: Facade
{
let color = ((red * 255.0) as u8, (green * 255.0) as u8, (blue * 255.0) as u8);
glium::texture::Texture2d::new(facade, vec![
vec![color, color],
vec![color, color],
]).unwrap()
}
pub fn build_constant_depth_texture<F>(facade: &F, depth: f32) -> glium::texture::DepthTexture2d
where F: Facade + ?Sized
{
glium::texture::DepthTexture2d::new(facade, vec![
vec![depth, depth],
vec![depth, depth],
]).unwrap()
}
pub fn build_fullscreen_red_pipeline<F: ?Sized>(facade: &F) -> (glium::vertex::VertexBufferAny,
glium::index::IndexBufferAny, glium::Program) where F: Facade
{
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 2],
}
implement_vertex!(Vertex, position);
(
glium::VertexBuffer::new(facade, &[
Vertex { position: [-1.0, 1.0] }, Vertex { position: [1.0, 1.0] },
Vertex { position: [-1.0, -1.0] }, Vertex { position: [1.0, -1.0] },
]).unwrap().into(),
glium::IndexBuffer::new(facade, PrimitiveType::TriangleStrip, &[0u8, 1, 2, 3]).unwrap().into(),
program!(facade,
110 => {
vertex: "
#version 110
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
",
fragment: "
#version 110
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
",
},
100 => {
vertex: "
#version 100
attribute lowp vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
",
fragment: "
#version 100
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
",
},
).unwrap()
)
}
pub fn build_rectangle_vb_ib<F: ?Sized>(facade: &F)
-> (glium::vertex::VertexBufferAny, glium::index::IndexBufferAny) where F: Facade
{
#[derive(Copy, Clone)]
struct Vertex {
position: [f32; 2],
}
implement_vertex!(Vertex, position);
(
glium::VertexBuffer::new(facade, &[
Vertex { position: [-1.0, 1.0] }, Vertex { position: [1.0, 1.0] },
Vertex { position: [-1.0, -1.0] }, Vertex { position: [1.0, -1.0] },
]).unwrap().into(),
glium::IndexBuffer::new(facade, PrimitiveType::TriangleStrip, &[0u8, 1, 2, 3]).unwrap().into(),
)
}
pub fn build_renderable_texture<F: ?Sized>(facade: &F) -> glium::Texture2d where F: Facade {
glium::Texture2d::empty(facade, 1024, 1024).unwrap()
}