#![allow(dead_code)] use glc::{ array_buffer::{ArrayBuffer, Target, Usage}, error::Error, matrix::Matrix4f, vector::Vector2f, }; pub struct Camera { buffer: ArrayBuffer, data: Data, view_invert: Matrix4f, projection_invert: Matrix4f, update_counter: usize, } #[repr(C, packed)] #[derive(Clone)] struct Data { projection: Matrix4f, view: Matrix4f, size: Vector2f, } impl Camera { pub fn new() -> Result { let data = Data { projection: Matrix4f::identity(), view: Matrix4f::identity(), size: Vector2f::default(), }; let mut buffer = ArrayBuffer::new(Target::UniformBuffer)?; buffer.buffer_data(Usage::StaticDraw, &[data.clone()])?; Ok(Self { buffer, data, view_invert: Default::default(), projection_invert: Default::default(), update_counter: 0, }) } pub fn projection(&self) -> &Matrix4f { &self.data.projection } pub fn projection_invert(&self) -> &Matrix4f { &self.projection_invert } pub fn view(&self) -> &Matrix4f { &self.data.view } pub fn view_invert(&self) -> &Matrix4f { &self.view_invert } pub fn update_counter(&self) -> usize { self.update_counter } pub fn size(&self) -> &Vector2f { &self.data.size } pub fn resize(&mut self, w: f32, h: f32) -> Result<(), Error> { self.data.projection = Matrix4f::ortho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -100.0, 100.0); self.data.size = (w, h).into(); let mut data = self.buffer.map_mut::(true)?; data[0].projection = self.data.projection; data[0].size = self.data.size; self.update_counter = self.update_counter.wrapping_add(1); self.projection_invert = self.data.projection.invert(); Ok(()) } pub fn update(&mut self, m: Matrix4f) -> Result<(), Error> { self.update_with(|view| view * m) } pub fn update_with(&mut self, f: F) -> Result<(), Error> where F: FnOnce(&Matrix4f) -> Matrix4f, { self.data.view = f(&self.data.view); let mut data = self.buffer.map_mut::(true)?; data[0].view = self.data.view; self.update_counter = self.update_counter.wrapping_add(1); self.view_invert = self.data.view.invert(); Ok(()) } pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { Error::checked(|| self.buffer.bind_buffer_base(index)) } pub fn world_to_view>(&self, pos: T) -> Vector2f { self.data.view.transform(T::into(pos)).into() } pub fn view_to_world>(&self, pos: T) -> Vector2f { self.view_invert.transform(T::into(pos)).into() } pub fn view_to_window>(&self, pos: T) -> Vector2f { view_to_window(&self.data.size, pos) } pub fn window_to_view>(&self, pos: T) -> Vector2f { window_to_view(&self.data.size, pos) } pub fn world_to_window>(&self, pos: T) -> Vector2f { self.view_to_window(self.world_to_view(pos)) } pub fn window_to_world>(&self, pos: T) -> Vector2f { self.view_to_world(self.window_to_view(pos)) } } pub fn view_to_window>(res: &Vector2f, pos: T) -> Vector2f { let mut pos = T::into(pos); pos.x += res.x / 2.0; pos.y = res.y / 2.0 - pos.y; pos } pub fn window_to_view>(res: &Vector2f, pos: T) -> Vector2f { let mut pos = T::into(pos); pos.x -= res.x / 2.0; pos.y = res.y / 2.0 - pos.y; pos }