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