use std::ffi::{c_void, CString}; use std::process::abort; use glfw::WindowSize; #[cfg(feature = "debug")] use crate::opengl::debug::{MessageSeverity, MessageSource, MessageType}; use crate::opengl::shader::Program as ShaderProgram; use crate::opengl::vertex_array::{PrimitiveKind, VertexArray}; use crate::opengl::vertex_buffer::{BufferUsage, VertexBuffer}; use crate::opengl::{clear_buffers, BufferClearMask}; use crate::vector::Vec2; use crate::vertex::Vertex; pub fn initialize(window: &glfw::Window) -> Result<(), Error> { gl::load_with(|symbol| { let proc_name = unsafe { CString::from_vec_unchecked(symbol.into()) }; match window.get_proc_address(proc_name.as_c_str()) { Ok(addr) => addr as *const c_void, Err(err) => { println!( "FATAL ERROR: Failed to get adress of OpenGL function {}. {}", symbol, err ); abort(); } } }); #[cfg(feature = "debug")] { use crate::opengl::debug::{ enable_debug_output, set_debug_message_callback, set_debug_message_control, MessageIdsAction, }; enable_debug_output(); set_debug_message_callback(opengl_debug_message_cb); set_debug_message_control(None, None, None, &[], MessageIdsAction::Disable); } let window_size = window.size().map_err(Error::GetWindowSizeFailed)?; set_viewport(&Vec2 { x: 0, y: 0 }, &window_size); Ok(()) } #[cfg(feature = "debug")] #[tracing::instrument(skip_all)] fn opengl_debug_message_cb( source: MessageSource, ty: MessageType, id: u32, severity: MessageSeverity, message: &str, ) { use tracing::{event, Level}; macro_rules! create_event { ($level: expr) => { event!($level, ?source, ?ty, id, ?severity, message); }; } match ty { MessageType::Error => { create_event!(Level::ERROR); } MessageType::Other => { create_event!(Level::INFO); } _ => { create_event!(Level::WARN); } }; } pub fn render<'renderable>(renderables: impl IntoIterator) { clear_buffers(BufferClearMask::COLOR); for renderable in renderables { renderable.shader_program.activate(); renderable.vertex_arr.bind(|vert_arr_curr_bound| { VertexArray::draw(&vert_arr_curr_bound, PrimitiveKind::Triangles, 0, 3); }); } } pub fn set_viewport(position: &Vec2, size: &WindowSize) { crate::opengl::set_viewport(position, size); } #[derive(Debug)] pub struct Renderable { shader_program: ShaderProgram, vertex_arr: VertexArray, /// Vertex buffer has to live as long as the vertex array _vertex_buffer: VertexBuffer, } impl Renderable { pub fn new(shader_program: ShaderProgram, vertices: &[Vertex]) -> Self { let vertex_arr = VertexArray::new(); let vertex_buffer = VertexBuffer::new(); vertex_arr.bind(|vert_arr_curr_bound| { vertex_buffer.bind(|vert_buf_curr_bound| { VertexBuffer::store(&vert_buf_curr_bound, vertices, BufferUsage::Static); VertexArray::configure_attrs(&vert_arr_curr_bound, &vert_buf_curr_bound); }); }); Self { shader_program, vertex_arr, _vertex_buffer: vertex_buffer, } } } /// Renderer error. #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Failed to get window size")] GetWindowSizeFailed(#[source] glfw::Error), }