125 lines
3.3 KiB
Rust
125 lines
3.3 KiB
Rust
use super::typ::CameraOP;
|
|
use crate::{
|
|
camera::Camera,
|
|
components::Program,
|
|
graphics::{AttaWithProgram, AttachWithMouse},
|
|
};
|
|
|
|
pub struct Operation<T: AttachWithMouse> {
|
|
camera: Camera,
|
|
projection: Projection,
|
|
operation: T,
|
|
need_update: bool,
|
|
}
|
|
|
|
impl<T: AttachWithMouse + 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, io: &super::io::IO) {
|
|
self.need_update = self.operation.attach_with_mouse(
|
|
&T::State::from_context(io),
|
|
&mut self.camera,
|
|
&mut self.projection,
|
|
);
|
|
}
|
|
|
|
pub fn set_camera(&mut self, f: impl Fn(&mut Camera)) {
|
|
f(&mut self.camera);
|
|
self.need_update = true;
|
|
}
|
|
|
|
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 attach_with_mouse(&mut self, camera_op: &T::State) -> bool {
|
|
self.operation
|
|
.attach_with_mouse(camera_op, &mut self.camera, &mut self.projection)
|
|
}
|
|
|
|
pub fn is_need_update(&self) -> bool {
|
|
self.need_update
|
|
}
|
|
|
|
pub fn reset(&mut self) {
|
|
self.operation.reset();
|
|
self.need_update = true;
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
fn as_slice(&self) -> &[f32] {
|
|
self.projection.as_slice()
|
|
}
|
|
}
|