use std::num::NonZeroU32;
use glow::HasContext;
#[cfg(not(target_arch = "wasm32"))]
use glutin::surface::{Surface, WindowSurface, GlSurface, SwapInterval};
#[cfg(not(target_arch = "wasm32"))]
use glutin::{config::{ConfigTemplateBuilder, GlConfig}, context::{ContextApi, ContextAttributesBuilder, PossiblyCurrentContext}, display::GetGlDisplay, prelude::{GlDisplay, NotCurrentGlContext}};
#[cfg(not(target_arch = "wasm32"))]
use glutin_winit::{DisplayBuilder, GlWindow};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::{prelude::Closure, JsCast};
#[cfg(target_arch = "wasm32")]
use web_sys::{Event, HtmlCanvasElement};
#[cfg(target_arch = "wasm32")]
use winit::platform::web::{WindowAttributesExtWebSys, WindowExtWebSys};
use winit::{application::ApplicationHandler, dpi::LogicalSize, event::WindowEvent, event_loop::ActiveEventLoop, raw_window_handle::HasWindowHandle, window::{Window, WindowAttributes}};
pub mod init;
#[derive(Default)]
pub struct App {
window: Option<Window>,
program: Option<glow::Program>,
vertex_array: Option<glow::VertexArray>,
vertex_buffer: Option<glow::Buffer>,
element_buffer: Option<glow::Buffer>,
#[cfg(not(target_arch = "wasm32"))]
gl_surface: Option<Surface<WindowSurface>>,
#[cfg(not(target_arch = "wasm32"))]
gl_context: Option<PossiblyCurrentContext>,
gl: Option<glow::Context>,
}
const VERTICES: [f32; 8] = [
-1.0, -1.0,
1.0, -1.0,
1.0, 1.0,
-1.0, 1.0,
];
const INDICES: [u32; 6] = [
0, 1, 2,
2, 3, 0,
];
impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
#[cfg(target_arch = "wasm32")]
let attributes = {
let document = web_sys::window().unwrap().document().unwrap();
let canvas = document.get_element_by_id("canvas").unwrap();
let canvas = canvas.dyn_into::<web_sys::HtmlCanvasElement>()
.map_err(|_| ()).unwrap();
canvas.set_width(web_sys::window().unwrap().inner_width().unwrap().as_f64().unwrap() as u32);
canvas.set_height(web_sys::window().unwrap().inner_height().unwrap().as_f64().unwrap() as u32);
Window::default_attributes()
.with_title("StarKingdoms.TK")
.with_canvas(Some(canvas))
};
#[cfg(not(target_arch = "wasm32"))]
let attributes = {
Window::default_attributes().with_transparent(true).with_title("StarKingdoms.TK")
.with_inner_size(LogicalSize::new(400, 300))
};
self.window = Some(event_loop.create_window(attributes.clone()).unwrap());
let window = self.window.as_ref().unwrap();
#[cfg(target_arch = "wasm32")]
let context = window.canvas().unwrap().get_context("webgl2")
.unwrap().unwrap()
.dyn_into::<web_sys::WebGl2RenderingContext>()
.unwrap();
#[cfg(target_arch = "wasm32")]
let (gl, shader_version) = (glow::Context::from_webgl2_context(context), "#version 300 es");
#[cfg(not(target_arch = "wasm32"))]
let (gl, shader_version) = unsafe {
let template = ConfigTemplateBuilder::new().with_transparency(true);
let display_builder = DisplayBuilder::new().with_window_attributes(Some(attributes));
let (window, gl_config) = display_builder.build(event_loop, template, |configs| {
configs.reduce(|accum, config| {
if config.num_samples() > accum.num_samples() {
config
} else {
accum
}
}).unwrap()
}).unwrap();
let raw_handle = window.as_ref().map(|window| window.window_handle().unwrap().window_handle().unwrap().as_raw());
let gl_display = gl_config.display();
let context_attributes = ContextAttributesBuilder::new()
.with_context_api(ContextApi::OpenGl(Some(glutin::context::Version {
major: 3,
minor: 0,
}))).build(raw_handle);
let not_current_gl_context = gl_display.create_context(&gl_config, &context_attributes).unwrap();
let window = window.unwrap();
let surface_attributes = window.build_surface_attributes(Default::default()).unwrap();
let gl_surface = gl_display.create_window_surface(&gl_config, &surface_attributes).unwrap();
let gl_context = not_current_gl_context.make_current(&gl_surface).unwrap();
let gl = glow::Context::from_loader_function_cstr(|s| gl_display.get_proc_address(s));
gl_surface.set_swap_interval(&gl_context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())).unwrap();
self.gl_surface = Some(gl_surface);
self.gl_context = Some(gl_context);
(gl, "#version 300 es")
};
unsafe {
let shaders = [
("vertex", include_str!("../shaders/vertex.glsl"), glow::VERTEX_SHADER),
("fragment", include_str!("../shaders/fragment.glsl"), glow::FRAGMENT_SHADER),
];
let program = gl.create_program().expect("Failed to create program");
for (name, source, shader_type) in shaders {
let shader = gl.create_shader(shader_type).expect("Failed to create vertex shader");
gl.shader_source(shader, &format!("{}\n{}", shader_version, source));
gl.compile_shader(shader);
if !gl.get_shader_compile_status(shader) {
tracing::error!("error in {} shader: {}", name, gl.get_shader_info_log(shader));
}
gl.attach_shader(program, shader);
gl.delete_shader(shader);
}
gl.link_program(program);
gl.use_program(Some(program));
let vertex_array = gl.create_vertex_array().expect("Failed to create vertex array");
gl.bind_vertex_array(Some(vertex_array));
let vertex_buffer = gl.create_buffer().expect("Failed to create vertex buffer");
gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer));
let element_buffer = gl.create_buffer().expect("Failed to create element buffer");
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(element_buffer));
gl.buffer_data_u8_slice(glow::ARRAY_BUFFER,
std::slice::from_raw_parts(VERTICES.as_ptr() as *const u8, 8*4),
glow::STATIC_DRAW);
gl.buffer_data_u8_slice(glow::ELEMENT_ARRAY_BUFFER,
std::slice::from_raw_parts(INDICES.as_ptr() as *const u8, 6*4),
glow::STATIC_DRAW);
gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 2*std::mem::size_of::<f32>() as i32, 0);
gl.enable_vertex_attrib_array(0);
gl.clear_color(1.0, 1.0, 1.0, 1.0);
gl.viewport(0, 0, window.inner_size().width as i32, window.inner_size().height as i32);
self.program = Some(program);
self.vertex_array = Some(vertex_array);
self.vertex_buffer = Some(vertex_buffer);
self.element_buffer = Some(element_buffer);
}
#[cfg(target_arch = "wasm32")]
web_sys::window().unwrap().set_onresize(Some(Closure::<dyn Fn(Event)>::new(move |_| {
let document = web_sys::window().unwrap().document().unwrap();
let canvas = document.get_element_by_id("canvas").unwrap();
let canvas = canvas.dyn_into::<web_sys::HtmlCanvasElement>()
.map_err(|_| ()).unwrap();
canvas.set_width(web_sys::window().unwrap().inner_width().unwrap().as_f64().unwrap() as u32);
canvas.set_height(web_sys::window().unwrap().inner_height().unwrap().as_f64().unwrap() as u32);
}).into_js_value().as_ref().unchecked_ref()));
self.gl = Some(gl);
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
match event {
WindowEvent::CloseRequested => {
event_loop.exit();
}
WindowEvent::Resized(size) => {
#[cfg(not(target_arch = "wasm32"))]
self.gl_surface.as_ref().unwrap().resize(self.gl_context.as_ref().unwrap(),
NonZeroU32::new(size.width).unwrap(), NonZeroU32::new(size.height).unwrap());
unsafe {
self.gl.as_ref().unwrap().viewport(0, 0, size.width as i32, size.height as i32);
}
}
WindowEvent::RedrawRequested => {
let window = self.window.as_ref().unwrap();
let gl = self.gl.as_ref().unwrap();
unsafe {
gl.clear(glow::COLOR_BUFFER_BIT);
gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0);
#[cfg(not(target_arch = "wasm32"))]
self.gl_surface.as_ref().unwrap().swap_buffers(self.gl_context.as_ref().unwrap()).unwrap();
}
window.request_redraw();
}
_ => {}
}
}
}