feo_oop_engine/scene/game_object/camera/
fpv_camera.rs

1//! First Person View Camera GameObject that can capture a scene
2//! 
3//! TODO
4//! 
5use {
6    super::{
7        Camera,
8        super::{
9            GameObject,
10            light::Light,
11        }
12    },
13    crate::{
14        registration::{
15            relation::{
16                Child, Parent,
17                ParentWrapper
18            },
19            named::Named,
20            id::ID
21        },
22        scripting::{
23            Script,
24            executor::Spawner,
25            Scriptable, 
26            globals::{
27                EngineGlobals, 
28                Global
29            }
30        },
31        components::{
32            triangle_mesh::TriangleMesh,
33        },
34        graphics::{
35            Drawable,
36            draw_pass_manager::DrawPassManager,
37            lighting_pass_manager::LightingPassManager,
38        },
39        event::UserEvent,
40        shaders::vs_draw,
41    },
42    feo_math::{
43        linear_algebra::{
44            vector3::Vector3,
45            matrix4::Matrix4
46        },
47        utils::space::Space,
48        rotation::quaternion::Quaternion
49    },
50    std::{
51        any::Any,
52        sync::{
53            Arc, 
54            RwLock
55        },
56        mem
57    },
58    winit::event::Event,
59};
60
61#[derive(Scriptable, GameObject, Parent, Child, Named, Drawable)]
62#[camera]
63pub struct FpvCamera{
64    id: ID,
65    name: String,
66    parent: ParentWrapper,
67
68    main: bool,
69
70    offset: Option<Vector3<f32>>, // offset should be defined by subspace itself
71
72    fov: i32,
73    near_plane: f32,
74    far_plane: f32,
75    aspect_ratio: f32,
76
77    pub subspace: Space,
78
79    script: Option<Box<Script<Self>>>,
80
81    children: Vec<Arc<RwLock<dyn GameObject>>>,
82}
83
84impl std::fmt::Debug for FpvCamera {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        f.debug_struct("FpvCamera")
87            .field("id", &self.id)
88            .field("name", &self.name)
89            .field("parent", &self.parent)
90            .field("main", &self.main)
91            .field("offset", &self.offset)
92            .field("fov", &self.fov)
93            .field("near_plane", &self.near_plane)
94            .field("far_plane", &self.far_plane)
95            .field("aspect_ratio", &self.aspect_ratio)
96            .field("subspace", &self.subspace)
97            .field("script", &self.script)
98            .field("children", &self.children).finish()
99    }
100}
101
102impl Clone for FpvCamera {
103    fn clone(&self) -> Self {
104        let id = self.id.get_system().take();
105        FpvCamera{
106            id,
107            name: self.name.clone(),
108            parent: self.parent.clone(),
109            subspace: self.subspace,
110            script: self.script.clone(),
111            children: self.children.clone().into_iter().map(|_child| {
112                // Dangerous
113                todo!();
114            }).collect::<Vec<Arc<RwLock<dyn GameObject>>>>(),
115            main: self.main,
116            offset: self.offset,
117            fov: self.fov,
118            near_plane: self.near_plane,
119            far_plane: self.far_plane,
120            aspect_ratio: self.aspect_ratio,
121        }
122    }
123}
124
125impl PartialEq for FpvCamera{
126    fn eq(&self, other: &Self) -> bool {
127        self.get_id() == other.get_id()
128    }
129}
130
131impl FpvCamera {
132    #[allow(clippy::too_many_arguments)]
133    pub fn new( 
134            name: Option<&str>,
135
136            main: bool,
137
138            parent: Option<Arc<RwLock<dyn GameObject>>>, // TODO: automatic not great use parent wrapper
139
140            position: Option<Vector3<f32>>,
141            rotation: Option<Quaternion<f32>>,
142            scale_factor: Option<Vector3<f32>>,
143
144            offset: Option<Vector3<f32>>, 
145            
146            fov: i32, 
147            near_plane: f32, 
148            far_plane: f32,
149            aspect_ratio: f32,
150            
151            script: Option<Box<Script<Self>>>,
152            
153            engine_globals: EngineGlobals//&VulkanoEngine
154            ) -> Result<Arc<RwLock<Self>>, &'static str> { // TODO: pass surface
155        let id = engine_globals.id_system.take();
156        let subspace = Space::new(position, rotation, scale_factor);
157        
158        Ok(Arc::new(RwLock::new( FpvCamera {
159            name: match name {
160                Some(name) => name.to_string(),
161                None => String::from("fpv_camera_") + id.to_string().as_str()
162            },
163            id,
164            parent: match parent {
165                Some(game_object) => {
166                    ParentWrapper::GameObject(game_object)
167                },
168                None => {
169                    ParentWrapper::Scene(engine_globals.scene)
170                }
171            },
172
173            main,
174            offset,
175            fov,
176            near_plane,
177            far_plane,
178            aspect_ratio,
179            subspace,
180
181            script,
182
183            children: Vec::new()
184        })))
185    }
186}
187
188impl Camera for FpvCamera {
189    fn as_any(&self) -> &dyn Any { self }
190    fn as_gameobject(&self) -> &dyn GameObject { self }
191    
192    fn cast_gameobject_arc_rwlock(&self, this: Arc<RwLock<dyn Camera>>) -> Arc<RwLock<dyn GameObject>> { 
193        let this= Arc::into_raw(this).cast::<RwLock<Self>>();
194        let this = unsafe { Arc::from_raw(this) };
195        this as Arc<RwLock<dyn GameObject>>
196    }
197
198    fn is_main(&self) -> bool {
199        self.main
200    }
201    
202    fn get_z_step (&self, z_buffer_size: usize) -> f32 {
203        ((self.far_plane / self.near_plane) * 0.5).powi(z_buffer_size as i32)
204    }
205
206    fn build_projection(&self) -> Matrix4<f32> {
207        let half_h = self.near_plane * (self.fov as f32 * 0.5).tan();
208        let half_w = half_h * self.aspect_ratio;
209
210        Matrix4::new(
211            [ self.near_plane / half_w,                       0.0,                                                                      0.0,                                                                            0.0],
212            [                      0.0, self.near_plane / -half_h, /* <- flipped y to account for vulkano axes */                       0.0,                                                                            0.0],
213            [                      0.0,                       0.0, -(self.near_plane + self.far_plane) / (self.far_plane - self.near_plane), (-2.0 * self.far_plane * self.near_plane) / (self.far_plane - self.near_plane)],
214            [                      0.0,                       0.0,                                                                     -1.0,                                                                           0.0] 
215        )
216    }
217  
218    fn build_viewspace(&self) -> Matrix4<f32> {
219        self.get_inversed_subspace().build()
220    }
221
222    fn create_uniforms(&self) -> vs_draw::ty::Camera {
223        vs_draw::ty::Camera {
224            to_view: self.build_viewspace().transpose().into(),
225            view_to_screen: self.build_projection().transpose().into()
226        }
227    }
228}