radar-g/gi/src/ui/operation.rs
2024-09-13 09:53:17 +08:00

146 lines
3.6 KiB
Rust

use super::typ::CameraOP;
use crate::{
camera::Camera,
components::Program,
graphics::{AttaWithProgram, AttachWithIO},
pg::layout_type::ViewPort,
};
pub struct Operation<T: AttachWithIO> {
camera: Camera,
projection: Projection,
operation: T,
need_update: bool,
}
impl<T: AttachWithIO + AttaWithProgram> Operation<T> {
pub fn new(operation: T, aspect: f32, fov: f32, z_near: f32, z_far: f32) -> Self {
let projection = Projection::new(aspect, fov, z_near, z_far);
Self {
projection,
camera: operation.init_camera(),
operation,
need_update: true,
}
}
pub fn deal_io(&mut self, viewport: &ViewPort, io: &super::io::IO) {
self.need_update = self.operation.attach_with_mouse(
&T::State::from_context(io),
&mut self.camera,
&mut self.projection,
viewport,
);
}
pub fn set_camera(&mut self, f: impl Fn(&mut Camera)) {
f(&mut self.camera);
self.need_update = true;
}
pub fn camera(&self) -> &Camera {
&self.camera
}
pub fn projection(&self) -> &Projection {
&self.projection
}
pub fn set_projection(&mut self, f: impl Fn(&mut Projection)) {
f(&mut self.projection);
self.need_update = true;
}
pub fn attach_with_program(&self, gl: &glow::Context, program: &mut Program) {
use glow::HasContext;
unsafe {
let projection = program.get_uniform_location(gl, "trackball_projection");
gl.uniform_matrix_4_f32_slice(projection.as_ref(), false, self.projection.as_slice());
let view = program.get_uniform_location(gl, "trackball_view");
gl.uniform_matrix_4_f32_slice(
view.as_ref(),
false,
self.camera.get_view_matrix().as_slice(),
);
}
self.operation.attach_with_program(gl, program);
}
pub fn is_need_update(&self) -> bool {
self.need_update
}
pub fn reset(&mut self) {
self.operation.reset();
self.need_update = true;
}
pub fn clean(&mut self) {
self.need_update = false;
}
}
pub struct Projection {
fov: f32,
z_near: f32,
z_far: f32,
aspect: f32,
projection: nalgebra_glm::Mat4,
}
impl Projection {
fn new(aspect: f32, fov: f32, z_near: f32, z_far: f32) -> Self {
let projection = nalgebra_glm::perspective(aspect, fov.to_radians(), z_near, z_far);
Self {
aspect,
fov,
z_far,
z_near,
projection,
}
}
fn new_perspective(&self) -> nalgebra_glm::Mat4 {
nalgebra_glm::perspective(self.aspect, self.fov.to_radians(), self.z_near, self.z_far)
}
pub fn set_aspect(&mut self, aspect: f32) {
self.aspect = aspect;
self.projection = self.new_perspective();
}
pub fn set_fov(&mut self, fov: f32) {
self.fov = fov;
self.projection = self.new_perspective();
}
pub fn set_z_near(&mut self, z_near: f32) {
self.z_near = z_near;
self.projection = self.new_perspective();
}
pub fn set_z_far(&mut self, z_far: f32) {
self.z_far = z_far;
self.projection = self.new_perspective();
}
pub fn fov(&self) -> f32 {
self.fov
}
pub fn z_far(&self) -> f32 {
self.z_far
}
pub fn z_near(&self) -> f32 {
self.z_near
}
pub fn aspect(&self) -> f32 {
self.aspect
}
fn as_slice(&self) -> &[f32] {
self.projection.as_slice()
}
}