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_point,
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 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::{
71 matrix4::Matrix4,
72 vector3::Vector3,
73 vector4::Vector4
74 },
75 rotation::quaternion::Quaternion,
76 utils::space::Space
77 },
78 winit::event::Event,
79 std::{
80 sync::{
81 Arc,
82 RwLock
83 },
84 any::Any,
85 mem
86 },
87 super::{
88 super::{
89 GameObject,
90 camera::Camera,
91 },
92 Light
93 }
94};
95
96#[derive(GameObject, Drawable, Parent, Child, Named, Scriptable)]
98#[light]
99pub struct PointLight {
100 name: String,
101 id: ID,
102
103 pub subspace: Space,
104
105 intensity: f32,
106 color: RGB,
107
108 parent: ParentWrapper,
109 children: Vec<Arc<RwLock<dyn GameObject>>>,
110
111 script: Option<Box<Script<Self>>>,
112}
113
114impl std::fmt::Debug for PointLight {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("PointLight")
117 .field("name", &self.name)
118 .field("id", &self.id)
119 .field("subspace", &self.subspace)
120 .field("intensity", &self.intensity)
121 .field("color", &self.color)
122 .field("parent", &self.parent)
123 .field("children", &self.children)
124 .field("script", &self.script).finish()
125 }
126}
127
128impl Clone for PointLight {
129 fn clone(&self) -> Self {
130 let id = self.id.get_system().take();
131 PointLight{
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 PointLight {
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<PointLight>> {
163 let id = engine_globals.id_system.take();
164 Arc::new( RwLock::new( PointLight {
165 name: match name {
166 Some(name) => name.to_string(),
167 None => String::from("point_light_") + id.to_string().as_str()
168 },
169 id, 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 #[allow(clippy::too_many_arguments)]
186 pub fn draw<N, C, S, D>(
187 &self,
188 graphics_system: GraphicsSystem,
189 viewport_dimensions: [u32; 2],
190 normals_input: N,
191 diffuse_input: C,
192 specular_input: S,
193 depth_input: D,
194 screen_to_camera: Matrix4<f32>,
195 to_camera_space: Space
196 ) -> AutoCommandBuffer
197 where
198 N: ImageViewAbstract + Send + Sync + 'static,
199 C: ImageViewAbstract + Send + Sync + 'static,
200 S: ImageViewAbstract + Send + Sync + 'static,
201 D: ImageViewAbstract + Send + Sync + 'static,
202 {
203 let position_camera_space = Vector4::from_vector3(
204 (to_camera_space.build() * Vector4::from_vector3(self.get_subspace().center, 1.0)).into(), 0.0
206 ).into();
207
208 let push_constants = fs_lighting_point::ty::PushConstants {
209 screen_to_camera: screen_to_camera.transpose().into(),
210 color: [self.color.r, self.color.g, self.color.b, 1.0],
211 position_camera_space, };
213
214 let layout = graphics_system.pipeline.descriptor_set_layout(0).unwrap();
215
216 let descriptor_set = PersistentDescriptorSet::start(layout.clone())
217 .add_image(diffuse_input).unwrap()
218 .add_image(specular_input).unwrap()
219 .add_image(normals_input).unwrap()
220 .add_image(depth_input).unwrap()
221 .build().unwrap();
222
223 let dynamic_state = DynamicState {
224 viewports: Some(vec![Viewport {
225 origin: [0.0, 0.0],
226 dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
227 depth_range: 0.0..1.0,
228 }]),
229 ..DynamicState::none()
230 };
231
232 let mut builder = AutoCommandBufferBuilder::secondary_graphics(
233 graphics_system.gfx_queue.device().clone(),
234 graphics_system.gfx_queue.family(),
235 graphics_system.pipeline.clone().subpass().clone(),
236 ).unwrap();
237
238 builder.draw(
239 graphics_system.pipeline.clone(),
240 &dynamic_state,
241 vec![graphics_system.vertex_buffer.clone()],
242 descriptor_set,
243 push_constants,
244 vec![],
245 ).unwrap();
246
247 builder.build().unwrap()
248 }
249}
250
251impl Light for PointLight {
252 fn as_any(&self) -> &dyn Any { self }
253
254 fn as_gameobject(&self) -> &dyn GameObject { self }
255
256 fn cast_gameobject_arc_rwlock(&self, this: Arc<RwLock<dyn Light>>) -> Arc<RwLock<dyn GameObject>> {
257 let this= Arc::into_raw(this).cast::<RwLock<Self>>();
258 let this = unsafe { Arc::from_raw(this) };
259 this as Arc<RwLock<dyn GameObject>>
260 }
261
262}
263
264impl GraphicsSystemTrait for PointLight {
265
266 fn new_system<L>(gfx_queue: Arc<Queue>, subpass: Subpass<L>) -> crate::graphics::graphics_system::GraphicsSystem
267 where L: RenderPassAbstract + Sync + Send + 'static {
268 let vertex_buffer = {
269 CpuAccessibleBuffer::from_iter(
270 gfx_queue.device().clone(),
271 BufferUsage::all(),
272 false,
273 [
274 ScreenPos {
275 position: [-1.0, -1.0],
276 },
277 ScreenPos {
278 position: [-1.0, 3.0],
279 },
280 ScreenPos {
281 position: [3.0, -1.0],
282 },
283 ].iter().cloned(),
284 ).expect("failed to create buffer")
285 };
286
287 let pipeline = {
288 let vs = vs_lighting::Shader::load(gfx_queue.device().clone())
289 .expect("failed to create shader");
290 let fs = fs_lighting_point::Shader::load(gfx_queue.device().clone())
291 .expect("failed to create shader");
292
293 Arc::new(
294 GraphicsPipeline::start()
295 .vertex_input_single_buffer::<ScreenPos>()
296 .vertex_shader(vs.main_entry_point(), ())
297 .triangle_list()
298 .viewports_dynamic_scissors_irrelevant(1)
299 .fragment_shader(fs.main_entry_point(), ())
300 .blend_collective(AttachmentBlend {
301 enabled: true,
302 color_op: BlendOp::Add,
303 color_source: BlendFactor::One,
304 color_destination: BlendFactor::One,
305 alpha_op: BlendOp::Max,
306 alpha_source: BlendFactor::One,
307 alpha_destination: BlendFactor::One,
308 mask_red: true,
309 mask_green: true,
310 mask_blue: true,
311 mask_alpha: true,
312 })
313 .render_pass(subpass)
314 .build(gfx_queue.device().clone()).unwrap(),
315 ) as Arc<_>
316 };
317
318 GraphicsSystem {
319 gfx_queue,
320 vertex_buffer,
321 pipeline,
322 }
323 }
324
325 fn get_system_num(&self) -> usize { 2 }
326
327 fn pass<'b, 'p : 'b>(&self, pass_builder: &'b mut PassBuilder<'p>, gfx_system: GraphicsSystem){
328 let dims = pass_builder.framebuffer.dimensions();
329
330 let command_buffer = self.draw(
331 gfx_system,
332 [dims[0], dims[1]],
333 pass_builder.system.normals_buffer.clone(),
334 pass_builder.system.diffuse_buffer.clone(),
335 pass_builder.system.specular_buffer.clone(),
336 pass_builder.system.specular_buffer.clone(),
337 pass_builder.screen_to_camera,
338 pass_builder.to_camera_space
339 );
340
341 pass_builder.command_buffer_builder
342 .as_mut().unwrap()
343 .execute_commands(command_buffer).unwrap();
344 }
345}