1use std::any::Any;
2use std::collections::HashMap;
3use std::sync::{Arc, Mutex};
4use std::time::{Duration, Instant};
5use egui_glium::EguiGlium;
6use winit::window::Window;
7use glium::glutin::surface::WindowSurface;
8use glium::{Display, Surface, Texture2d, uniform};
9use glium::uniforms::UniformBuffer;
10use serde::{Deserialize, Serialize};
11use uuid::Uuid;
12use winit::event::{Event, WindowEvent};
13use winit::event_loop::{ControlFlow};
14use crate::audio::{AudioClip, AudioEngine};
15use crate::shadow::ShadowMaps;
16use crate::shadow::{directional_light_space_matrix, view_matrix, perspective_90_matrix, mat4_mul, CUBE_FACE_DIRS, face_viewport};
17use crate::camera::{Camera, CameraSerializer};
18use crate::collision_world::MouseState;
19use crate::data::AppStateData;
20use crate::event::EventModifiers;
21use crate::geometry::BoneTransforms;
22use crate::light::{Light, LightEmissionType};
23use crate::logging::{EnigmaError, EnigmaMessage, EnigmaWarning};
24use crate::material::Material;
25use crate::object::{Object, ObjectInstance};
26use crate::postprocessing::PostProcessingEffect;
27use crate::texture::Texture;
28
29pub mod shader;
30pub mod geometry;
31pub mod debug_geo;
32pub mod texture;
33pub mod material;
34pub mod object;
35pub mod light;
36pub mod camera;
37pub mod event;
38pub mod collision_world;
39pub mod default_events;
40pub mod postprocessing;
41pub mod ui;
42pub mod resources;
43pub mod data;
44pub mod example_resources;
45pub mod animation;
46pub mod logging;
47pub mod audio;
48pub mod shadow;
49
50pub fn init_default(app_state: &mut AppState) {
51 app_state.set_renderscale(1);
52 app_state.set_fps(60);
53 app_state.set_max_buffers(3);
54
55 if app_state.get_camera().is_none(){
56 app_state.set_camera(Camera::default());
57 }
58
59 app_state.inject_event(
60 event::EventCharacteristic::MousePress(event::MouseButton::Left),
61 Arc::new(default_events::select_object),
62 None,
63 );
64 app_state.inject_event(
65 event::EventCharacteristic::MousePress(event::MouseButton::Right),
66 Arc::new(default_events::select_object_add),
67 None,
68 );
69
70 app_state.add_state_data("camera_move_speed", Box::new(10.0f32));
74 app_state.add_state_data("camera_rotate_speed", Box::new(2.0f32));
75
76 app_state.inject_event(
77 event::EventCharacteristic::KeyPress(event::VirtualKeyCode::W),
78 Arc::new(default_events::camera_fly_forward),
79 Some(EventModifiers::new(false, false, false)),
80 );
81 app_state.inject_event(
82 event::EventCharacteristic::KeyPress(event::VirtualKeyCode::A),
83 Arc::new(default_events::camera_fly_left),
84 Some(EventModifiers::new(false, false, false)),
85 );
86 app_state.inject_event(
87 event::EventCharacteristic::KeyPress(event::VirtualKeyCode::S),
88 Arc::new(default_events::camera_fly_backward),
89 Some(EventModifiers::new(false, false, false)),
90 );
91 app_state.inject_event(
92 event::EventCharacteristic::KeyPress(event::VirtualKeyCode::D),
93 Arc::new(default_events::camera_fly_right),
94 Some(EventModifiers::new(false, false, false)),
95 );
96 app_state.inject_event(
97 event::EventCharacteristic::KeyPress(event::VirtualKeyCode::Space),
98 Arc::new(default_events::camera_up),
99 Some(EventModifiers::new(false, false, false)),
100 );
101 app_state.inject_event(
102 event::EventCharacteristic::KeyPress(event::VirtualKeyCode::Space),
103 Arc::new(default_events::camera_down),
104 Some(EventModifiers::new(true, false, false)),
105 );
106 app_state.inject_event(
107 event::EventCharacteristic::MouseDown(event::MouseButton::Right),
108 Arc::new(default_events::camera_rotate),
109 Some(EventModifiers::new(true, false, false)),
110 );
111}
112
113#[derive(Serialize, Deserialize)]
114pub struct AppStateSerializer {
115 pub camera: Option<CameraSerializer>,
116 pub light: Vec<light::LightSerializer>,
117 pub ambient_light: Option<light::LightSerializer>,
118 pub skybox: Option<object::ObjectSerializer>,
119 pub materials: Vec<material::MaterialSerializer>,
120 pub skybox_texture: Option<texture::TextureSerializer>,
121 pub objects: Vec<object::ObjectSerializer>,
122 pub object_selection: Vec<String>,
123}
124
125pub struct AppState {
126 pub fps: u64,
127 pub camera: Option<camera::Camera>,
128 pub light: Vec<light::Light>,
129 pub ambient_light: Option<light::Light>,
130 pub skybox: Option<object::Object>,
131 pub skybox_texture: Option<texture::Texture>,
132 pub objects: Vec<object::Object>,
133 pub materials: Vec<material::Material>,
134 pub object_selection: Vec<Uuid>,
135 pub event_injections: Vec<(event::EventCharacteristic, event::EventFunction, event::EventModifiers)>,
136 pub update_injections: Vec<event::EventFunction>,
137 pub gui_injections: Vec<ui::GUIDrawFunction>,
138 pub post_processes: Vec<Box<dyn PostProcessingEffect>>,
139 pub display: Option<glium::Display<WindowSurface>>,
140 pub time: f32,
141 pub delta_time: f32,
142 pub render_scale: u32,
143 pub max_buffers: usize,
144 mouse_state: MouseState,
145 last_event_time: Instant,
146 last_frame_time: Instant,
147 is_mouse_down: bool,
148 pub state_data: Vec<AppStateData>,
149 audio_engine: AudioEngine,
150 audio_clips: HashMap<String, AudioClip>,
151 pub shadow_resolution: u32,
152 pub shadow_distance: f32,
153}
154
155pub struct EventLoop {
156 pub event_loop: winit::event_loop::EventLoop<()>,
157 pub window: Window,
158 pub display: Display<WindowSurface>,
159 pub modifiers: EventModifiers,
160 gui_renderer: Option<EguiGlium>,
161}
162
163impl AppState {
164 pub fn new() -> Self {
165 AppState {
166 fps: 60,
167 camera: None,
168 skybox: None,
169 skybox_texture: None,
170 objects: Vec::new(),
171 materials: Vec::new(),
172 object_selection: Vec::new(),
173 light: Vec::new(),
174 ambient_light: None,
175 event_injections: Vec::new(),
176 update_injections: Vec::new(),
177 post_processes: Vec::new(),
178 display: None,
179 time: 0.0,
180 delta_time: 0.0,
181 render_scale: 1,
182 max_buffers: 3,
183 mouse_state: MouseState::new(),
184 gui_injections: Vec::new(),
185 state_data: Vec::new(),
186 last_event_time: Instant::now(),
187 last_frame_time: Instant::now(),
188 is_mouse_down: false,
189 audio_engine: AudioEngine::new(),
190 audio_clips: HashMap::new(),
191 shadow_resolution: 1024,
192 shadow_distance: 50.0,
193 }
194 }
195
196 pub fn add_audio(&mut self, clip: AudioClip){
197 if self.audio_clips.contains_key(&clip.name){
198 EnigmaError::new(Some("Cannot add audio clip, since it is already added"), true).log();
199 return;
200 }
201 self.audio_clips.insert(clip.name.to_string(), clip);
202 }
203
204 pub fn play_audio_once(&mut self, name: &str){
205 self.audio_engine.play_clip_once(name, &self.audio_clips);
206 }
207
208 pub fn play_audio_loop(&mut self, name: &str) {
209 self.audio_engine.play_clip_loop(name, &self.audio_clips);
210 }
211
212 pub fn stop_audio(&mut self, name: &str) {
213 self.audio_engine.stop_clip(name);
214 }
215
216 pub fn toggle_pause_audio(&mut self, name: &str) {
217 self.audio_engine.toggle_pause_clip(name);
218 }
219
220 pub fn set_audio_volume(&mut self, name: &str, volume: f32){
221 self.audio_engine.set_clip_volume(name, volume);
222 }
223
224 fn setup_skybox_instance(&self, display: &Display<WindowSurface>, sky_box_matrix: &Option<[[f32; 4]; 4]>) -> Option<(Uuid, object::ObjectInstance)> {
225 match &self.skybox {
226 Some(skybox) => {
227 let mut instance = ObjectInstance::new(display);
228 let model_matrix = sky_box_matrix.unwrap_or_else(|| {
229 [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
230 });
231 instance.set_vertex_buffers(skybox.get_vertex_buffers(display));
232 instance.set_index_buffers(skybox.get_index_buffers(display));
233 instance.instance_matrices.push(model_matrix);
234 let data = instance.instance_matrices
235 .iter()
236 .map(|i| geometry::InstanceAttribute {
237 model_matrix: *i,
238 })
239 .collect::<Vec<_>>();
240 instance.instance_attributes = glium::vertex::VertexBuffer::dynamic(display, &data).unwrap();
241 Some((skybox.get_unique_id(), instance))
242 }
243 None => None
244 }
245 }
246
247 fn setup_instances(&mut self, display: &Display<WindowSurface>, model_matrices: &HashMap<Uuid, [[f32; 4]; 4]>) -> HashMap<Uuid, object::ObjectInstance> {
248 let mut instances = HashMap::new();
249 self.objects.sort_by(|a, b| {
251 let distance_a = (self.camera.expect("failed to retrieve camera").transform.get_position() - a.transform.get_position()).len();
252 let distance_b = (self.camera.expect("failed to retrieve camera").transform.get_position() - b.transform.get_position()).len();
253 distance_b.partial_cmp(&distance_a).unwrap()
254 });
255
256 for object in self.objects.iter() {
258 let instance_id = object.get_instance_id();
259 let model_matrix = model_matrices.get(&object.get_unique_id()).unwrap_or_else(|| {
260 &[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
261 });
262 if !instances.contains_key(&instance_id) {
263 let mut object_instance = ObjectInstance::new(display);
264 object_instance.set_vertex_buffers(object.get_vertex_buffers(display));
265 object_instance.set_index_buffers(object.get_index_buffers(display));
266 instances.insert(instance_id, object_instance);
267 }
268 instances.get_mut(&instance_id).expect("No instance of this uuid found. which is weird, because we just added it above").add_instance(*model_matrix);
269
270
271 match instances.get_mut(&instance_id) {
273 Some(instance) => {
274 let data = instance.instance_matrices
275 .iter()
276 .map(|i| geometry::InstanceAttribute {
277 model_matrix: *i,
278 })
279 .collect::<Vec<_>>();
280 instance.instance_attributes = glium::vertex::VertexBuffer::dynamic(display, &data).unwrap();
281 }
282 None => panic!("Something went wrong, when adding the instance")
283 }
284 }
285 instances
286 }
287
288 pub fn to_serializer(&self) -> AppStateSerializer {
289 EnigmaMessage::new(Some("An AppState Serializer does not completely serialize the AppState but only scene objects like Objects, Camera, Lights. It does NOT serialize any injections like code in form of functions or GUI!"), true).log();
290 let camera = match self.camera {
291 Some(camera) => Some(camera.to_serializer()),
292 None => None,
293 };
294 let light = self.light.iter().map(|l| l.to_serializer()).collect();
295 let ambient_light = match &self.ambient_light {
296 Some(light) => Some(light.to_serializer()),
297 None => None,
298 };
299 let skybox = match &self.skybox {
300 Some(skybox) => Some(skybox.to_serializer()),
301 None => None,
302 };
303 let skybox_texture = match &self.skybox_texture {
304 Some(texture) => Some(texture.to_serializer()),
305 None => None,
306 };
307 let objects = self.objects.iter().map(|o| o.to_serializer()).collect();
308 let materials = self.materials.iter().map(|o| o.to_serializer()).collect();
309 let object_selection = self.object_selection.iter().map(|o| o.to_string()).collect();
310 AppStateSerializer {
311 camera,
312 light,
313 ambient_light,
314 skybox,
315 skybox_texture,
316 objects,
317 materials,
318 object_selection,
319 }
320 }
321
322 pub fn inject_serializer(&mut self, serializer: AppStateSerializer, display: Display<WindowSurface>, additive: bool) {
323 self.camera = match serializer.camera {
324 Some(camera) => Some(Camera::from_serializer(camera)),
325 None => None,
326 };
327 match serializer.ambient_light {
328 Some(light) => {
329 self.add_light(Light::from_serializer(light), LightEmissionType::Ambient);
330 }
331 None => {}
332 };
333 self.skybox = match serializer.skybox {
334 Some(skybox) => Some(Object::from_serializer(skybox)),
335 None => None,
336 };
337 self.skybox_texture = match serializer.skybox_texture {
338 Some(texture) => Some(Texture::from_serializer(texture, &display)),
339 None => None,
340 };
341
342 if !additive {
343 self.light.clear();
344 self.objects.clear();
345 self.object_selection.clear();
346 }
347 for l in serializer.light {
348 self.add_light(Light::from_serializer(l), LightEmissionType::Source);
349 }
350 for o in serializer.objects {
351 self.add_object(Object::from_serializer(o));
352 }
353 for m in serializer.materials {
354 self.add_material(Material::from_serializer(m, &display));
355 }
356 for o in serializer.object_selection {
357 self.object_selection.push(Uuid::parse_str(&o).unwrap());
358 }
359 }
360
361 pub fn add_state_data(&mut self, name: &str, data: Box<dyn Any>) {
362 self.state_data.push(AppStateData::new(name, data));
363 }
364
365 pub fn add_material(&mut self, material: Material) {
366 self.materials.push(material);
367 }
368
369 pub fn get_material(&self, uuid: &Uuid) -> Option<&Material> {
370 for material in &self.materials {
371 if &material.uuid == uuid {
372 return Some(&material);
373 }
374 }
375 None
376 }
377
378 pub fn get_material_by_name(&self, name: &str) -> Option<&Material> {
379 for material in &self.materials {
380 if &material.name == name {
381 return Some(&material);
382 }
383 }
384 None
385 }
386
387 pub fn get_state_data_value<T: 'static>(&self, name: &str) -> Option<&T> {
388 for data in self.state_data.iter() {
389 if data.get_name() == name {
390 if let Some(value) = data.get_value().downcast_ref::<T>() {
392 return Some(value);
393 }
394 }
395 }
396 None
397 }
398
399 pub fn get_state_data_value_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
400 for data in self.state_data.iter_mut() {
401 if data.get_name() == name {
402 if let Some(value) = data.get_value_mut().downcast_mut::<T>() {
404 return Some(value);
405 }
406 }
407 }
408 None
409 }
410
411 pub fn set_state_data_value(&mut self, name: &str, value: Box<dyn Any>) {
412 for data in &mut self.state_data {
413 if data.get_name() == name {
414 data.set_value(value);
415 return;
416 }
417 }
418 self.add_state_data(name, value);
420 }
421
422 pub fn inject_gui(&mut self, function: ui::GUIDrawFunction) {
423 self.gui_injections.push(function);
424 }
425
426 pub fn add_post_process(&mut self, post_process: Box<dyn PostProcessingEffect>) {
427 self.post_processes.push(post_process);
428 }
429
430 pub fn get_post_processes(&self) -> &Vec<Box<dyn PostProcessingEffect>> {
431 &self.post_processes
432 }
433
434 pub fn get_post_processes_mut(&mut self) -> &mut Vec<Box<dyn PostProcessingEffect>> {
435 &mut self.post_processes
436 }
437
438 pub fn get_mouse_state(&self) -> &MouseState {
439 &self.mouse_state
440 }
441
442 pub fn get_mouse_state_mut(&mut self) -> &mut MouseState {
443 &mut self.mouse_state
444 }
445
446 pub fn convert_to_arc_mutex(self) -> Arc<Mutex<Self>> {
447 Arc::new(Mutex::new(self))
448 }
449
450 pub fn add_object(&mut self, object: object::Object) {
451 self.objects.push(object);
452 }
453
454 pub fn get_objects(&self) -> &Vec<object::Object> {
455 &self.objects
456 }
457
458 pub fn get_object(&self, name: &str) -> Option<&object::Object> {
459 for object in self.objects.iter() {
460 if object.name == name {
461 return Some(object);
462 }
463 }
464 None
465 }
466
467 pub fn get_object_mut(&mut self, name: &str) -> Option<&mut object::Object> {
468 for object in self.objects.iter_mut() {
469 if object.name == name {
470 return Some(object);
471 }
472 }
473 None
474 }
475
476 pub fn get_object_by_uuid(&self, uuid: &Uuid) -> Option<&object::Object> {
477 for object in self.objects.iter() {
478 if &object.get_unique_id() == uuid {
479 return Some(object);
480 }
481 }
482 None
483 }
484
485 pub fn get_object_by_uuid_mut(&mut self, uuid: Uuid) -> Option<&mut object::Object> {
486 for object in self.objects.iter_mut() {
487 if object.get_unique_id() == uuid {
488 return Some(object);
489 }
490 }
491 None
492 }
493
494 pub fn get_selected_objects_mut(&mut self) -> Vec<&mut object::Object> {
495 let mut selected = Vec::new();
496 for object in self.objects.iter_mut() {
497 if self.object_selection.contains(&object.get_unique_id()) {
498 selected.push(object);
499 }
500 }
501 selected
502 }
503
504 pub fn add_light(&mut self, light: light::Light, light_type: LightEmissionType) {
505 match light_type {
506 LightEmissionType::Source => self.light.push(light),
507 LightEmissionType::Ambient => self.ambient_light = Some(light),
508 }
509 }
510
511 pub fn remove_light(&mut self, index: usize, light_type: LightEmissionType) {
512 match light_type {
513 LightEmissionType::Source => {
514 if index >= self.light.len() {
515 panic!("Index out of bounds");
516 }
517 self.light.remove(index);
518 }
519 LightEmissionType::Ambient => {
520 self.ambient_light = None;
521 }
522 };
523 }
524
525 pub fn get_lights(&self) -> &Vec<light::Light> {
526 &self.light
527 }
528
529 pub fn set_fps(&mut self, fps: u64) {
530 self.fps = fps;
531 }
532
533 pub fn get_fps(&self) -> u64 {
534 self.fps
535 }
536
537 pub fn get_objects_mut(&mut self) -> &mut Vec<object::Object> {
538 &mut self.objects
539 }
540
541 pub fn set_camera(&mut self, camera: camera::Camera) {
542 self.camera = Some(camera);
543 }
544
545 pub fn get_camera(&self) -> &Option<camera::Camera> {
546 &self.camera
547 }
548
549 pub fn get_camera_mut(&mut self) -> &mut Option<camera::Camera> {
550 &mut self.camera
551 }
552
553 pub fn set_renderscale(&mut self, scale: u32) {
554 self.render_scale = scale;
555 }
556
557 pub fn get_renderscale(&self) -> u32 {
558 self.render_scale
559 }
560
561 pub fn set_max_buffers(&mut self, max_buffers: usize) {
562 self.max_buffers = max_buffers;
563 }
564
565 pub fn get_max_buffers(&self) -> usize {
566 self.max_buffers
567 }
568
569 pub fn inject_event(&mut self, characteristic: event::EventCharacteristic, function: event::EventFunction, modifiers: Option<event::EventModifiers>) {
570 match modifiers {
571 Some(modifiers) => self.event_injections.push((characteristic, function, modifiers)),
572 None => self.event_injections.push((characteristic, function, event::EventModifiers::default())),
573 }
574 }
575 pub fn inject_update_function(&mut self, function: event::EventFunction) {
576 self.update_injections.push(function);
577 }
578
579 pub fn set_skybox(&mut self, skybox: object::Object) {
580 self.skybox = Some(skybox);
581 }
582
583 pub fn set_skybox_from_texture(&mut self, texture: Texture, event_loop: &EventLoop){
584 let mut material = crate::material::Material::unlit(event_loop.get_display_clone(), false);
585 material.set_name("INTERNAL::SkyBox");
586
587 material.set_texture(texture, crate::material::TextureType::Albedo);
588 let mut object = Object::load_from_gltf_resource(resources::skybox(), None);
590 object.add_material(material.uuid);
592 object.get_shapes_mut()[0].set_material_from_object_list(0);
593 object.name = "Skybox".to_string();
594 object.transform.set_scale([1.0, 1.0, 1.0]);
595 self.add_material(material);
596 self.set_skybox(object);
597 }
598
599 pub fn get_skybox(&self) -> &Option<object::Object> {
600 &self.skybox
601 }
602
603 pub fn get_skybox_mut(&mut self) -> &mut Option<object::Object> {
604 &mut self.skybox
605 }
606
607 pub fn set_shadow_resolution(&mut self, resolution: crate::light::ShadowResolution) {
608 self.shadow_resolution = resolution.value();
609 }
610
611 pub fn get_shadow_resolution(&self) -> u32 {
612 self.shadow_resolution
613 }
614
615 pub fn set_shadow_distance(&mut self, distance: f32) {
616 self.shadow_distance = distance;
617 }
618
619 pub fn get_shadow_distance(&self) -> f32 {
620 self.shadow_distance
621 }
622}
623
624impl EventLoop {
625 pub fn new(title: &str, width: u32, height: u32) -> Self {
626 let event_loop = winit::event_loop::EventLoopBuilder::new().build();
627 let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new()
628 .with_title(title)
629 .with_inner_size(width, height)
630 .build(&event_loop);
631 EventLoop {
632 event_loop,
633 window,
634 display,
635 modifiers: EventModifiers::default(),
636 gui_renderer: None,
637 }
638 }
639 pub fn get_display_clone(&self) -> Display<WindowSurface> {
640 self.display.clone()
641 }
642
643 pub fn get_display_reference(&self) -> &Display<WindowSurface> {
644 &self.display
645 }
646
647 pub fn spawn_skybox(&mut self, app_state: &mut AppState) -> (crate::object::Object, texture::Texture) {
648 if let Some(current_skybox_object) = app_state.get_skybox().clone() {
649 if let Some(texture_uuid) = current_skybox_object.get_materials().first() {
651 if let Some(material) = app_state.get_material(texture_uuid) {
652 if let Some(texture) = &material.albedo {
653 return (
655 current_skybox_object,
656 texture.get_texture_clone(self.get_display_reference())
657 );
658 }
659 }
660 }
661
662 let mut logger = EnigmaWarning::new(None, true);
664 logger.extent("Failed to get texture from existing skybox. Creating default skybox...");
665 logger.log();
666 }
667
668 let mut material = crate::material::Material::unlit(self.display.clone(), false);
669 material.set_name("INTERNAL::SkyBox");
670
671 material.set_texture_from_resource(resources::skybox_texture(), crate::material::TextureType::Albedo);
672
673 let mut object = Object::load_from_gltf_resource(resources::skybox(), None);
675
676 object.add_material(material.uuid);
678 object.get_shapes_mut()[0].set_material_from_object_list(0);
679
680 object.name = "Skybox".to_string();
681
682 object.transform.set_scale([1.0, 1.0, 1.0]);
683
684 app_state.add_material(material);
685 let skybox_texture = texture::Texture::from_resource(&self.display, resources::skybox_texture());
687 (object, skybox_texture)
688 }
689
690 pub fn set_icon_from_path(&self, path: &str) {
691 let image = image::open(path).expect("failed to load icon").to_rgba8();
692 let image_dimensions = image.dimensions();
693 let data = image.into_raw();
694 let icon = winit::window::Icon::from_rgba(data, image_dimensions.0, image_dimensions.1).expect("failed to load icon");
695 self.window.set_window_icon(Some(icon));
696 }
697
698 pub fn set_icon_from_resource(&self, data: &[u8]) {
699 let image = image::load_from_memory(data).expect("failed to load icon").to_rgba8();
700 let image_dimensions = image.dimensions();
701 let data = image.into_raw();
702 let icon = winit::window::Icon::from_rgba(data, image_dimensions.0, image_dimensions.1).expect("failed to load icon");
703 self.window.set_window_icon(Some(icon));
704 }
705
706 pub fn run(mut self, app_state: Arc<Mutex<AppState>>) {
708 let mut temp_app_state = app_state.lock().unwrap();
709 temp_app_state.display = Some(self.display.clone());
710
711 let (skybox, skybox_texture) = self.spawn_skybox(&mut temp_app_state);
713 temp_app_state.set_skybox(skybox);
714
715
716 let mut next_frame_time = Instant::now();
718 let nanos = 1_000_000_000 / temp_app_state.fps;
719 let frame_duration = Duration::from_nanos(nanos); let mut texture = Texture2d::empty(&self.display, self.window.inner_size().width * temp_app_state.render_scale, self.window.inner_size().height * temp_app_state.render_scale).expect("Failed to create texture");
722 let mut depth_texture = glium::texture::DepthTexture2d::empty(&self.display, self.window.inner_size().width * temp_app_state.render_scale, self.window.inner_size().height * temp_app_state.render_scale).expect("Failed to create depth texture");
723
724 let mut buffer_textures: Vec<Texture2d> = Vec::new();
725 for _ in 0..temp_app_state.max_buffers {
726 buffer_textures.push(Texture2d::empty(&self.display, self.window.inner_size().width * temp_app_state.render_scale, self.window.inner_size().height * temp_app_state.render_scale).expect("Failed to create texture"));
727 }
728
729 let mut shadow_maps = ShadowMaps::new(&self.display, temp_app_state.shadow_resolution);
730
731 let shadow_dir_program = glium::Program::from_source(
732 &self.display,
733 resources::shadow_depth_vert_shader(),
734 resources::shadow_depth_dir_frag_shader(),
735 None,
736 ).expect("Failed to compile directional shadow shader");
737
738 let shadow_point_program = glium::Program::from_source(
739 &self.display,
740 resources::shadow_depth_vert_shader(),
741 resources::shadow_depth_point_frag_shader(),
742 None,
743 ).expect("Failed to compile point shadow shader");
744
745 drop(temp_app_state);
747
748 let screen_vert_rect = postprocessing::get_screen_vert_rect(&self.display);
750 let screen_indices_rect = postprocessing::get_screen_indices_rect(&self.display);
751 let screen_program = postprocessing::get_screen_program(&self.display);
752
753 match self.gui_renderer {
755 Some(_) => {}
756 None => {
757 let egui_glium = EguiGlium::new(&self.display, &self.window, &self.event_loop);
758 self.gui_renderer = Some(egui_glium);
759 }
760 }
761 self.event_loop.run(move |event, _window_target, control_flow| {
763 let mut app_state = app_state.lock().unwrap();
765 let light = app_state.light.clone();
766 let ambient_light = app_state.ambient_light.clone();
767 let camera = app_state.camera.clone();
768 let event_injections = app_state.event_injections.clone();
769 let update_injections = app_state.update_injections.clone();
770 let gui_injections = app_state.gui_injections.clone();
771
772 *control_flow = ControlFlow::WaitUntil(next_frame_time);
773 next_frame_time = Instant::now() + frame_duration;
774
775 let texture = &mut texture;
777 let depth_texture = &mut depth_texture;
778 let buffer_textures = &mut buffer_textures;
779 let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&self.display, &*texture, &*depth_texture).expect("Failed to create framebuffer");
780
781 let skybox_texture = &skybox_texture;
783
784 match event {
785 Event::WindowEvent { event, .. } => match event {
786 WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; }
787 WindowEvent::Resized(new_size) => {
788 let response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
789 if !response.consumed {
790 app_state.camera.as_mut().expect("failed to retrieve camera").set_aspect(new_size.width as f32, new_size.height as f32);
791 self.display.resize(new_size.into());
792 if let Some(app_state_display) = app_state.display.as_mut() {
793 app_state_display.resize(new_size.into());
794 }
795 }
796 }
797 WindowEvent::ModifiersChanged(modifiers) => {
798 self.modifiers.ctrl = modifiers.ctrl();
799 self.modifiers.shift = modifiers.shift();
800 self.modifiers.alt = modifiers.alt();
801 }
802 WindowEvent::CursorMoved { position, .. } => {
803 let response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
804 if !response.consumed {
805 app_state.get_mouse_state_mut().update_position((position.x, position.y));
806 }
807 }
808 WindowEvent::MouseInput { state, button, .. } => {
809 let mut response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
810 if !response.consumed {
811 for (characteristic, function, modifiers) in &event_injections {
812 if let event::EventCharacteristic::MouseDown(mouse_button) = characteristic {
813 if button == *mouse_button && modifiers == &self.modifiers {
814 if state == winit::event::ElementState::Pressed {
815 app_state.is_mouse_down = true;
816 app_state.last_event_time = Instant::now();
817 function(&mut app_state);
818 } else {
819 app_state.is_mouse_down = false;
820 }
821 }
822 } else if let event::EventCharacteristic::MousePress(_) = characteristic {
823 if modifiers == &self.modifiers {
824 function(&mut app_state);
825 response.consumed = true;
826 }
827 }
828 }
829 }
830 }
831 WindowEvent::KeyboardInput { input, .. } => {
832 let response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
833 if !response.consumed {
834 for (characteristic, function, modifiers) in event_injections {
835 if let event::EventCharacteristic::KeyPress(key_code) = characteristic {
836 if input.state == winit::event::ElementState::Pressed && input.virtual_keycode == Some(key_code) && modifiers == self.modifiers {
837 function(&mut app_state);
838 }
839 }
840 };
841 }
842 }
843 _ => {
844 _ = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
845 }
846 }
847 Event::RedrawRequested(_) => {
848 let current_time = Instant::now();
849 app_state.delta_time = (current_time - app_state.last_frame_time).as_secs_f32();
850 app_state.last_frame_time = current_time;
851 app_state.time += app_state.delta_time;
852 for material in app_state.materials.iter_mut() {
854 material.update();
855 }
856 let deltatime = app_state.delta_time;
858 for object in app_state.objects.iter_mut() {
859 object.update(deltatime);
860 }
861
862 let render_target = &mut framebuffer;
863 render_target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
864 let model_matrices: std::collections::HashMap<Uuid, [[f32; 4]; 4]> = app_state.objects.iter_mut().map(|x| (x.get_unique_id(), x.transform.get_matrix())).collect();
865 let bone_uniform_buffers: std::collections::HashMap<Uuid, UniformBuffer<BoneTransforms>> = app_state.objects.iter_mut().map(|x| (x.get_unique_id(), x.get_bone_transform_buffer(&self.display))).collect();
866 let object_instances = app_state.setup_instances(&self.display, &model_matrices);
867
868 if shadow_maps.resolution != app_state.shadow_resolution {
870 shadow_maps = ShadowMaps::new(&self.display, app_state.shadow_resolution);
871 }
872 shadow_maps.clear();
873
874 let shadow_draw_params = glium::DrawParameters {
875 depth: glium::Depth {
876 test: glium::draw_parameters::DepthTest::IfLess,
877 write: true,
878 ..Default::default()
879 },
880 backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
881 ..Default::default()
882 };
883
884 let cam_pos: [f32; 3] = match camera {
885 Some(ref c) => { let p = c.transform.get_position(); [p.x, p.y, p.z] }
886 None => [0.0, 0.0, 0.0],
887 };
888
889 for (light_index, light_item) in light.iter().enumerate().take(4) {
890 if !light_item.cast_shadow { continue; }
891
892 if light_item.is_directional() {
893 let half = app_state.shadow_distance;
895 let lsm = directional_light_space_matrix(light_item.direction, cam_pos, half);
896 shadow_maps.light_space_matrices[light_index] = lsm;
897
898 let shadow_tex = glium::texture::Texture2d::empty_with_format(
899 &self.display,
900 glium::texture::UncompressedFloatFormat::F32,
901 glium::texture::MipmapsOption::NoMipmap,
902 shadow_maps.resolution,
903 shadow_maps.resolution,
904 ).expect("Failed to create directional shadow texture");
905
906 {
907 let mut fb = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(
908 &self.display,
909 &shadow_tex,
910 &shadow_maps.dir_depth_rb,
911 ).expect("Failed to create directional shadow framebuffer");
912 fb.clear_color_and_depth((1.0, 0.0, 0.0, 1.0), 1.0);
913
914 for (instance_id, object_instance) in object_instances.iter() {
915 if let Some(object) = app_state.get_object_by_uuid(instance_id) {
916 if object.get_materials().is_empty() { continue; }
917 let has_skeleton = object.get_skeleton().is_some();
918 let bone_transform = bone_uniform_buffers.get(&object.get_unique_id())
919 .expect("Missing bone transforms in shadow pass");
920 for ((buffer, _mat_index), indices) in object_instance.vertex_buffers.iter()
921 .zip(object_instance.index_buffers.iter())
922 {
923 let uniforms = glium::uniform! {
924 light_space_matrix: lsm,
925 has_skeleton: has_skeleton,
926 BoneTransforms: bone_transform,
927 };
928 fb.draw(
929 (buffer, object_instance.instance_attributes.per_instance().unwrap()),
930 indices,
931 &shadow_dir_program,
932 &uniforms,
933 &shadow_draw_params,
934 ).expect("Failed to draw shadow pass");
935 }
936 }
937 }
938 }
939 shadow_maps.directional_maps[light_index] = Some(shadow_tex);
940
941 } else {
942 let far_plane = 100.0f32;
944 shadow_maps.point_far_planes[light_index] = far_plane;
945 let res = shadow_maps.resolution;
946
947 let atlas_tex = glium::texture::Texture2d::empty_with_format(
948 &self.display,
949 glium::texture::UncompressedFloatFormat::F32,
950 glium::texture::MipmapsOption::NoMipmap,
951 res * 2,
952 res * 3,
953 ).expect("Failed to create point shadow atlas texture");
954
955 {
957 let mut clear_fb = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(
958 &self.display,
959 &atlas_tex,
960 &shadow_maps.point_depth_rb,
961 ).expect("Failed to create atlas clear framebuffer");
962 clear_fb.clear_color_and_depth((1.0, 0.0, 0.0, 1.0), 1.0);
963 }
964
965 let near = 0.1f32;
966 let proj = perspective_90_matrix(near, far_plane);
967 let lp = light_item.position;
968
969 for face in 0..6usize {
970 let (dir, up) = CUBE_FACE_DIRS[face];
971 let view = view_matrix(&lp, &dir, &up);
972 let lsm = mat4_mul(proj, view);
973 let viewport = face_viewport(face, res);
974
975 let face_draw_params = glium::DrawParameters {
976 depth: glium::Depth {
977 test: glium::draw_parameters::DepthTest::IfLess,
978 write: true,
979 ..Default::default()
980 },
981 backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
982 viewport: Some(viewport),
983 ..Default::default()
984 };
985
986 let mut fb = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(
987 &self.display,
988 &atlas_tex,
989 &shadow_maps.point_depth_rb,
990 ).expect("Failed to create point shadow framebuffer");
991
992 for (instance_id, object_instance) in object_instances.iter() {
993 if let Some(object) = app_state.get_object_by_uuid(instance_id) {
994 if object.get_materials().is_empty() { continue; }
995 let has_skeleton = object.get_skeleton().is_some();
996 let bone_transform = bone_uniform_buffers.get(&object.get_unique_id())
997 .expect("Missing bone transforms in shadow pass");
998 for ((buffer, _mat_index), indices) in object_instance.vertex_buffers.iter()
999 .zip(object_instance.index_buffers.iter())
1000 {
1001 let uniforms = glium::uniform! {
1002 light_space_matrix: lsm,
1003 has_skeleton: has_skeleton,
1004 BoneTransforms: bone_transform,
1005 light_pos: lp,
1006 far_plane: far_plane,
1007 };
1008 fb.draw(
1009 (buffer, object_instance.instance_attributes.per_instance().unwrap()),
1010 indices,
1011 &shadow_point_program,
1012 &uniforms,
1013 &face_draw_params,
1014 ).expect("Failed to draw shadow pass");
1015 }
1016 }
1017 }
1018 }
1019 shadow_maps.point_maps[light_index] = Some(atlas_tex);
1020 }
1021 }
1022 let opaque_rendering_parameter = glium::DrawParameters {
1026 depth: glium::Depth {
1027 test: glium::draw_parameters::DepthTest::IfLess,
1028 write: true,
1029 ..Default::default()
1030 },
1031 backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
1032 ..Default::default()
1033 };
1034
1035 for (instance_id, object_instance) in object_instances.iter() {
1036 let object_option = app_state.get_object_by_uuid(&instance_id);
1037 match object_option {
1038 Some(object) => {
1039 let closest_lights = object.get_closest_lights(&light);
1040 let has_skeleton = object.get_skeleton().is_some();
1041 let bone_transform = bone_uniform_buffers.get(&object.get_unique_id()).expect("Missing Bone Transform Uniforms for Object");
1042 for ((buffer, mat_index), indices) in object_instance.vertex_buffers.iter().zip(object_instance.index_buffers.iter()) {
1043 let mat_uuid: &Uuid = &object.get_materials()[*mat_index];
1044 match app_state.get_material(mat_uuid) {
1045 Some(material) => {
1046 if material.render_transparent {
1047 continue;
1048 }
1049 let uniforms = &material.get_uniforms(&closest_lights, ambient_light, camera, &bone_transform, has_skeleton, skybox_texture, &shadow_maps);
1050 render_target.draw((buffer, object_instance.instance_attributes.per_instance().expect("Error, unwrapping per instance in opaque draw")), indices, &material.program, uniforms, &opaque_rendering_parameter).expect("Failed to draw object");
1051 }
1052 None => ()
1053 }
1054 }
1055 }
1056 None => EnigmaError::new(Some(smart_format!("Error, instancing the Object Instance with the instance id {}, because no Object with that Id could be found", instance_id).as_str()), true).log()
1057 }
1058 }
1059
1060 let skybox_rendering_parameter = glium::DrawParameters {
1062 depth: glium::Depth {
1063 test: glium::draw_parameters::DepthTest::IfLess,
1064 write: false,
1065 ..Default::default()
1066 },
1067 backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
1068 ..Default::default()
1069 };
1070
1071 let skybox_model_matrix = match app_state.get_skybox_mut() {
1073 Some(obj) => Some(obj.transform.get_matrix().clone()),
1074 None => None
1075 };
1076 let skybox_instance = app_state.setup_skybox_instance(&self.display, &skybox_model_matrix);
1077
1078 match skybox_instance {
1079 Some((skybox_id, instance)) => {
1080 let object_option = app_state.get_skybox();
1081 match object_option {
1082 Some(skybox) => {
1083 let closest_lights = skybox.get_closest_lights(&light);
1084 let skybox_bone_buffer = skybox.get_bone_transform_buffer(&self.display);
1085 for ((buffer, mat_index), indices) in instance.vertex_buffers.iter().zip(instance.index_buffers.iter()) {
1086 let mat_uuid: &Uuid = &skybox.get_materials()[*mat_index];
1087 match app_state.get_material(mat_uuid) {
1088 Some(material) => {
1089 let uniforms = &material.get_uniforms(&closest_lights, ambient_light, camera, &skybox_bone_buffer, false, skybox_texture, &shadow_maps);
1090 render_target.draw((buffer, instance.instance_attributes.per_instance().expect("Error, unwrapping per instance in skybox draw")), indices, &material.program, uniforms, &skybox_rendering_parameter).expect("Failed to draw object");
1091 }
1092 None => ()
1093 }
1094 }
1095 }
1096 None => EnigmaError::new(Some(smart_format!("Error, instancing the Skybox Instance with the instance id {}, because no Object with that Id could be found", skybox_id).as_str()), true).log()
1097 }
1098 }
1099 None => {}
1100 }
1101
1102 let transparent_rendering_parameter = glium::DrawParameters {
1104 blend: glium::Blend::alpha_blending(),
1105 ..opaque_rendering_parameter
1106 };
1107 for (instance_id, object_instance) in object_instances.iter() {
1108 let object_option = app_state.get_object_by_uuid(&instance_id);
1109 match object_option {
1110 Some(object) => {
1111 let closest_lights = object.get_closest_lights(&light);
1112 let has_skeleton = object.get_skeleton().is_some();
1113 let bone_transform = bone_uniform_buffers.get(&object.get_unique_id()).expect("Missing Bone Transform Uniforms for Object");
1114 for ((buffer, mat_index), indices) in object_instance.vertex_buffers.iter().zip(object_instance.index_buffers.iter()) {
1115 let mat_uuid: &Uuid = &object.get_materials()[*mat_index];
1116 match app_state.get_material(mat_uuid) {
1117 Some(material) => {
1118 if !material.render_transparent {
1119 continue;
1120 }
1121 let uniforms = &material.get_uniforms(&closest_lights, ambient_light, camera, &bone_transform, has_skeleton, skybox_texture, &shadow_maps);
1122 render_target.draw((buffer, object_instance.instance_attributes.per_instance().expect("Error, unwrapping per instance in transparent draw")), indices, &material.program, uniforms, &transparent_rendering_parameter).expect("Failed to draw object");
1123 }
1124 None => ()
1125 }
1126 }
1127 }
1128 None => EnigmaError::new(Some(smart_format!("Error, instancing the Transparent Object Instance with the instance id {}, because no Object with that Id could be found", instance_id).as_str()), true).log()
1129 }
1130 }
1131
1132 for process in app_state.get_post_processes() {
1134 process.render(&app_state, &screen_vert_rect, &screen_indices_rect, &mut framebuffer, &texture, &depth_texture, &buffer_textures);
1135 }
1136
1137 let mut screen_target = self.display.draw();
1139 let screen_uniforms = uniform! {
1140 scene: &*texture,
1141 };
1142 screen_target.draw(
1143 &screen_vert_rect,
1144 &screen_indices_rect,
1145 &screen_program,
1146 &screen_uniforms,
1147 &Default::default(),
1148 ).expect("Failed to draw screen");
1149
1150 let gui_renderer = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer");
1152 gui_renderer.run(&self.window, |egui_context| {
1153 for function in gui_injections.iter() {
1154 function(egui_context, &mut app_state);
1155 }
1156 });
1157 gui_renderer.paint(&self.display, &mut screen_target);
1158 screen_target.finish().expect("Failed to swap buffers");
1159 }
1160 Event::MainEventsCleared => {
1161
1162 if app_state.is_mouse_down && app_state.last_event_time.elapsed() >= Duration::from_millis(100) {
1164 for (characteristic, function, modifiers) in &event_injections {
1165 if let event::EventCharacteristic::MouseDown(_) = characteristic {
1166 if modifiers == &self.modifiers {
1167 function(&mut app_state);
1168 app_state.last_event_time = Instant::now();
1169 }
1170 }
1171 }
1172 }
1173
1174 for function in update_injections {
1176 function(&mut app_state);
1177 }
1178 self.window.request_redraw();
1179 }
1180 _ => (),
1181 }
1182 });
1183 }
1184}
1185
1186#[cfg(test)]
1187mod tests {
1188 use super::*;
1189 use crate::light::ShadowResolution;
1190
1191 #[test]
1192 fn appstate_shadow_defaults() {
1193 let s = AppState::new();
1194 assert_eq!(s.get_shadow_resolution(), 1024);
1195 assert_eq!(s.get_shadow_distance(), 50.0);
1196 }
1197
1198 #[test]
1199 fn appstate_shadow_setters() {
1200 let mut s = AppState::new();
1201 s.set_shadow_resolution(ShadowResolution::High);
1202 assert_eq!(s.get_shadow_resolution(), 2048);
1203 s.set_shadow_distance(75.0);
1204 assert_eq!(s.get_shadow_distance(), 75.0);
1205 }
1206}