use std::ffi::{c_float, c_void, CString}; use std::mem::size_of; use std::process::abort; use std::ptr::null; use glfw::WindowSize; use crate::renderer::vertex_array::{PrimitiveKind, VertexArray}; use crate::renderer::vertex_buffers::{BufferUsage, VertexBuffers}; use crate::vector::Vec2; mod vertex_array; mod vertex_buffers; 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(); } } }); let window_size = window.size().map_err(Error::GetWindowSizeFailed)?; set_viewport(&Vec2 { x: 0, y: 0 }, &window_size); Ok(()) } pub fn render<'renderable>(renderables: impl IntoIterator) { unsafe { gl::Clear(gl::COLOR_BUFFER_BIT); } for renderable in renderables { renderable.shader_program.activate(); renderable.vertex_arr.draw(PrimitiveKind::Triangles, 0, 3); } } pub struct Renderable { shader_program: crate::shader::Program, vertex_arr: VertexArray, } impl Renderable { pub fn new(shader_program: crate::shader::Program, vertices: &[f32]) -> Self { let vertex_arr = VertexArray::new(); vertex_arr.bind(); let vertex_buffer = VertexBuffers::<1>::new(); vertex_buffer .store(0, vertices, BufferUsage::Static) .unwrap(); vertex_attrib_ptr(0); enable_vertex_attrib_array(0); unsafe { gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindVertexArray(0); } Self { shader_program, vertex_arr, } } } pub fn set_viewport(position: &Vec2, size: &WindowSize) { unsafe { #[allow(clippy::cast_possible_wrap)] gl::Viewport( position.x as i32, position.y as i32, size.width as i32, size.height as i32, ); } } /// Renderer error. #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Failed to get window size")] GetWindowSizeFailed(#[source] glfw::Error), } fn vertex_attrib_ptr(index: usize) { let stride = 3 * size_of::(); unsafe { #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)] gl::VertexAttribPointer( index as gl::types::GLuint, 3, gl::FLOAT, gl::FALSE, stride as gl::types::GLsizei, null(), ); } } fn enable_vertex_attrib_array(index: usize) { unsafe { #[allow(clippy::cast_possible_truncation)] gl::EnableVertexAttribArray(index as gl::types::GLuint); } }