feo_oop_engine/scene/game_object/light/
ambient_light.rs

1//! A light that lights up everything
2//! 
3//! TODO
4//! 
5use {
6    crate::{
7        registration::{
8            relation::{
9                ParentWrapper, 
10                Parent, Child
11            }, 
12            named::Named,
13            id::ID
14        },
15        scripting::{
16            Script,
17            executor::Spawner,
18            globals::{Global, EngineGlobals}, 
19            Scriptable
20        }, // TODO: in proc-macro
21        graphics::{ 
22            Drawable, 
23            draw_pass_manager::DrawPassManager,
24            lighting_pass_manager::LightingPassManager,
25            graphics_system::{GraphicsSystem, GraphicsSystemTrait}, 
26            pass_builder::PassBuilder
27        },
28        components::{
29            triangle_mesh::TriangleMesh,
30            RGB, 
31            ScreenPos
32        },
33        shaders::{
34            fs_lighting_ambient,
35            vs_lighting
36        },
37        event::UserEvent
38    },
39    vulkano::{
40        buffer::{
41            BufferUsage,
42            CpuAccessibleBuffer
43        }, 
44        command_buffer::{
45            AutoCommandBuffer, 
46            AutoCommandBufferBuilder,
47            DynamicState
48        }, 
49        device::Queue,
50        descriptor::{
51            descriptor_set::PersistentDescriptorSet,
52        },
53        framebuffer::{
54            RenderPassAbstract,
55            Subpass
56        },
57        image::ImageViewAbstract,
58        pipeline::{
59            GraphicsPipeline, 
60            GraphicsPipelineAbstract, 
61            blend::{
62                AttachmentBlend, 
63                BlendFactor, 
64                BlendOp
65            }, 
66            viewport::Viewport
67        },
68    },
69    feo_math::{
70        linear_algebra::vector3::Vector3, 
71        rotation::quaternion::Quaternion, 
72        utils::space::Space
73    },
74    winit::event::Event,
75    std::{
76        sync::{
77            Arc, 
78            RwLock
79        },
80        any::Any,
81        mem
82    },
83    super::{
84        super::{
85            GameObject,
86            camera::Camera,
87        },
88        Light
89    }
90};
91
92/// Allows applying a directional light source to a scene.
93/// You should only use one of these but you can use as many as you want
94#[derive(GameObject, Drawable, Parent, Child, Named, Scriptable)]
95#[light] // TODO: I can do better ):
96pub struct AmbientLight {
97    name: String,
98    id: ID,
99
100    pub subspace: Space,
101
102    intensity: f32,
103    color: RGB,
104
105    parent: ParentWrapper,
106    children: Vec<Arc<RwLock<dyn GameObject>>>,
107
108    script: Option<Box<Script<Self>>>,
109}
110
111impl std::fmt::Debug for AmbientLight {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        f.debug_struct("AmbientLight")
114            .field("name", &self.name)
115            .field("id", &self.id)
116            .field("subspace", &self.subspace)
117            .field("intensity", &self.intensity)
118            .field("color", &self.color)
119            .field("parent", &self.parent)
120            .field("children", &self.children)
121            .field("script", &self.script).finish()
122    }
123}
124
125impl Clone for AmbientLight {
126    fn clone(&self) -> Self {
127        let id = self.id.get_system().take();
128        AmbientLight {
129            id,
130            name: self.name.clone(),
131            parent: self.parent.clone(),
132            subspace: self.subspace,
133            script: self.script.clone(),
134            children: self.children.clone().into_iter().map(|_child| {
135                // Dangerous
136                todo!();
137            }).collect::<Vec<Arc<RwLock<dyn GameObject>>>>(),
138            intensity: self.intensity,
139            color: self.color,
140        }
141    }
142}
143
144impl AmbientLight {
145    /// Initializes the directional lighting system.
146    #[allow(clippy::too_many_arguments)]
147    pub fn new(
148        name: Option<&str>,
149        parent: Option<Arc<RwLock<dyn GameObject>>>,
150        intensity: f32,
151        color: RGB,
152        
153        position: Option<Vector3<f32>>, // no effect on actual lighting
154        rotation: Option<Quaternion<f32>>,
155        scale_factor: Option<Vector3<f32>>, // no effect on actual lighting
156        
157        script: Option<Box<Script<Self>>>,
158
159        engine_globals: EngineGlobals) -> Arc<RwLock<AmbientLight>> {
160        let id = engine_globals.id_system.take();
161        Arc::new(RwLock::new(AmbientLight {
162            name: match name {
163                Some(name) => name.to_string(),
164                None => String::from("ambient_light_") + id.to_string().as_str()
165            },
166            id,
167
168            intensity,
169            color,
170            subspace: Space::new(position, rotation, scale_factor),
171
172            parent: match parent{
173                Some(game_object) => ParentWrapper::GameObject(game_object), 
174                None => ParentWrapper::Scene(engine_globals.scene),
175            },
176            children: Vec::new(),
177
178            script
179        }))
180    }
181
182    fn draw<C, A, D> (
183        &self, 
184        graphics_system: GraphicsSystem, 
185        viewport_dimensions: [u32; 2],
186        diffuse_input: C,
187        ambient_input: A,
188        depth_input: D) -> AutoCommandBuffer
189    where 
190        C: ImageViewAbstract + Send + Sync + 'static,
191        A: ImageViewAbstract + Send + Sync + 'static,
192        D: ImageViewAbstract + Send + Sync + 'static,
193    {
194        let push_constants = fs_lighting_ambient::ty::PushConstants {
195            color: [self.color.r, self.color.g, self.color.b, 1.0],
196        };
197
198        let layout = graphics_system.pipeline.descriptor_set_layout(0).unwrap();
199
200        let descriptor_set = PersistentDescriptorSet::start(layout.clone())
201            .add_image(diffuse_input).unwrap()
202            .add_image(ambient_input).unwrap()
203            .add_image(depth_input).unwrap()
204            .build().unwrap();
205
206        let dynamic_state = DynamicState {
207            viewports: Some(vec![Viewport {
208                origin: [0.0, 0.0],
209                dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
210                depth_range: 0.0..1.0,
211            }]),
212            ..DynamicState::none()
213        };
214
215        let mut builder = AutoCommandBufferBuilder::secondary_graphics(
216            graphics_system.gfx_queue.device().clone(),
217            graphics_system.gfx_queue.family(),
218            graphics_system.pipeline.clone().subpass().clone(),
219        ).unwrap();
220
221        builder.draw(
222            graphics_system.pipeline.clone(),
223            &dynamic_state,
224            vec![graphics_system.vertex_buffer.clone()],
225            descriptor_set,
226            push_constants,
227            vec![],
228        ).unwrap();
229        
230        builder.build().unwrap()
231    }
232}
233
234impl Light for AmbientLight {
235    fn as_any(&self) -> &dyn Any { self }
236    fn as_gameobject(&self) -> &dyn GameObject { self }
237    fn cast_gameobject_arc_rwlock(&self, this: Arc<RwLock<dyn Light>>) -> Arc<RwLock<dyn GameObject>> {
238        let this= Arc::into_raw(this).cast::<RwLock<Self>>();
239        let this = unsafe { Arc::from_raw(this) };
240        this as Arc<RwLock<dyn GameObject>>
241    }
242}
243
244impl GraphicsSystemTrait for AmbientLight{
245    fn new_system<L>(gfx_queue: Arc<Queue>, subpass: Subpass<L>) -> crate::graphics::graphics_system::GraphicsSystem
246    where L: RenderPassAbstract + Sync + Send + 'static {
247        let vertex_buffer = CpuAccessibleBuffer::from_iter(
248                gfx_queue.device().clone(),
249                BufferUsage::all(),
250                false,
251                [
252                    ScreenPos { position: [-1.0, -1.0] },
253                    ScreenPos { position: [-1.0,  3.0] },
254                    ScreenPos { position: [ 3.0, -1.0] },
255                ].iter().cloned(),
256            ).expect("failed to create buffer");
257
258        let pipeline = {
259            let vs = vs_lighting::Shader::load(gfx_queue.device().clone())
260                .expect("failed to create shader");
261            let fs = fs_lighting_ambient::Shader::load(gfx_queue.device().clone())
262                .expect("failed to create shader");
263
264            Arc::new(
265                GraphicsPipeline::start()
266                    .vertex_input_single_buffer::<ScreenPos>()
267                    .vertex_shader(vs.main_entry_point(), ())
268                    .triangle_list()
269                    .viewports_dynamic_scissors_irrelevant(1)
270                    .fragment_shader(fs.main_entry_point(), ())
271                    .blend_collective(AttachmentBlend {
272                        enabled: true,
273                        color_op: BlendOp::Add,
274                        color_source: BlendFactor::One,
275                        color_destination: BlendFactor::One,
276                        alpha_op: BlendOp::Max,
277                        alpha_source: BlendFactor::One,
278                        alpha_destination: BlendFactor::One,
279                        mask_red: true,
280                        mask_green: true,
281                        mask_blue: true,
282                        mask_alpha: true,
283                    })
284                    .render_pass(subpass)
285                    .build(gfx_queue.device().clone()).unwrap()
286            ) as Arc<_>
287        };
288
289        GraphicsSystem {
290            gfx_queue,
291            vertex_buffer,
292            pipeline,
293        }
294    }
295
296    fn get_system_num(&self) -> usize { 0 }
297
298    fn pass<'b, 'p : 'b>(&self, pass_builder: &'b mut PassBuilder<'p>, gfx_system: GraphicsSystem){
299        let dims = pass_builder.framebuffer.dimensions();
300
301        let command_buffer = self.draw(
302            gfx_system,
303            [dims[0], dims[1]],
304            pass_builder.system.diffuse_buffer.clone(),
305            pass_builder.system.ambient_buffer.clone(),
306            pass_builder.system.depth_buffer.clone(),
307        );
308
309        pass_builder.command_buffer_builder
310            .as_mut().unwrap()
311            .execute_commands(command_buffer).unwrap();
312    }
313}