enigma_3d/
lib.rs

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 serde::de::Unexpected::Str;
12use uuid::Uuid;
13use winit::event::{Event, WindowEvent};
14use winit::event_loop::{ControlFlow};
15use crate::audio::{AudioClip, AudioEngine};
16use crate::camera::{Camera, CameraSerializer};
17use crate::collision_world::MouseState;
18use crate::data::AppStateData;
19use crate::event::EventModifiers;
20use crate::geometry::BoneTransforms;
21use crate::light::{Light, LightEmissionType};
22use crate::logging::{EnigmaError, EnigmaMessage, EnigmaWarning};
23use crate::material::Material;
24use crate::object::{Object, ObjectInstance};
25use crate::postprocessing::PostProcessingEffect;
26use crate::texture::Texture;
27
28pub mod shader;
29pub mod geometry;
30pub mod debug_geo;
31pub mod texture;
32pub mod material;
33pub mod object;
34pub mod light;
35pub mod camera;
36pub mod event;
37pub mod collision_world;
38pub mod default_events;
39pub mod postprocessing;
40pub mod ui;
41pub mod resources;
42pub mod data;
43pub mod example_resources;
44pub mod animation;
45pub mod logging;
46pub mod audio;
47
48pub fn init_default(app_state: &mut AppState) {
49    app_state.set_renderscale(1);
50    app_state.set_fps(60);
51    app_state.set_max_buffers(3);
52
53    if app_state.get_camera().is_none(){
54        app_state.set_camera(Camera::default());
55    }
56
57    app_state.inject_event(
58        event::EventCharacteristic::MousePress(event::MouseButton::Left),
59        Arc::new(default_events::select_object),
60        None,
61    );
62    app_state.inject_event(
63        event::EventCharacteristic::MousePress(event::MouseButton::Right),
64        Arc::new(default_events::select_object_add),
65        None,
66    );
67
68    //event functions for moving the camera
69    // adding the camera move and rotation speed as a state data entry. this allows us to retrieve it in all camera related functions while having
70    // a unique place to control it. See, that we need to pass the value in with explicit type declaration, this is so enigma can properly use it
71    app_state.add_state_data("camera_move_speed", Box::new(10.0f32));
72    app_state.add_state_data("camera_rotate_speed", Box::new(2.0f32));
73
74    app_state.inject_event(
75        event::EventCharacteristic::KeyPress(event::VirtualKeyCode::W),
76        Arc::new(default_events::camera_fly_forward),
77        Some(EventModifiers::new(false, false, false)),
78    );
79    app_state.inject_event(
80        event::EventCharacteristic::KeyPress(event::VirtualKeyCode::A),
81        Arc::new(default_events::camera_fly_left),
82        Some(EventModifiers::new(false, false, false)),
83    );
84    app_state.inject_event(
85        event::EventCharacteristic::KeyPress(event::VirtualKeyCode::S),
86        Arc::new(default_events::camera_fly_backward),
87        Some(EventModifiers::new(false, false, false)),
88    );
89    app_state.inject_event(
90        event::EventCharacteristic::KeyPress(event::VirtualKeyCode::D),
91        Arc::new(default_events::camera_fly_right),
92        Some(EventModifiers::new(false, false, false)),
93    );
94    app_state.inject_event(
95        event::EventCharacteristic::KeyPress(event::VirtualKeyCode::Space),
96        Arc::new(default_events::camera_up),
97        Some(EventModifiers::new(false, false, false)),
98    );
99    app_state.inject_event(
100        event::EventCharacteristic::KeyPress(event::VirtualKeyCode::Space),
101        Arc::new(default_events::camera_down),
102        Some(EventModifiers::new(true, false, false)),
103    );
104    app_state.inject_event(
105        event::EventCharacteristic::MouseDown(event::MouseButton::Right),
106        Arc::new(default_events::camera_rotate),
107        Some(EventModifiers::new(true, false, false)),
108    );
109}
110
111#[derive(Serialize, Deserialize)]
112pub struct AppStateSerializer {
113    pub camera: Option<CameraSerializer>,
114    pub light: Vec<light::LightSerializer>,
115    pub ambient_light: Option<light::LightSerializer>,
116    pub skybox: Option<object::ObjectSerializer>,
117    pub materials: Vec<material::MaterialSerializer>,
118    pub skybox_texture: Option<texture::TextureSerializer>,
119    pub objects: Vec<object::ObjectSerializer>,
120    pub object_selection: Vec<String>,
121}
122
123pub struct AppState {
124    pub fps: u64,
125    pub camera: Option<camera::Camera>,
126    pub light: Vec<light::Light>,
127    pub ambient_light: Option<light::Light>,
128    pub skybox: Option<object::Object>,
129    pub skybox_texture: Option<texture::Texture>,
130    pub objects: Vec<object::Object>,
131    pub materials: Vec<material::Material>,
132    pub object_selection: Vec<Uuid>,
133    pub event_injections: Vec<(event::EventCharacteristic, event::EventFunction, event::EventModifiers)>,
134    pub update_injections: Vec<event::EventFunction>,
135    pub gui_injections: Vec<ui::GUIDrawFunction>,
136    pub post_processes: Vec<Box<dyn PostProcessingEffect>>,
137    pub display: Option<glium::Display<WindowSurface>>,
138    pub time: f32,
139    pub delta_time: f32,
140    pub render_scale: u32,
141    pub max_buffers: usize,
142    mouse_state: MouseState,
143    last_event_time: Instant,
144    last_frame_time: Instant,
145    is_mouse_down: bool,
146    pub state_data: Vec<AppStateData>,
147    audio_engine: AudioEngine,
148    audio_clips:  HashMap<String, AudioClip>
149}
150
151pub struct EventLoop {
152    pub event_loop: winit::event_loop::EventLoop<()>,
153    pub window: Window,
154    pub display: Display<WindowSurface>,
155    pub modifiers: EventModifiers,
156    gui_renderer: Option<EguiGlium>,
157}
158
159impl AppState {
160    pub fn new() -> Self {
161        AppState {
162            fps: 60,
163            camera: None,
164            skybox: None,
165            skybox_texture: None,
166            objects: Vec::new(),
167            materials: Vec::new(),
168            object_selection: Vec::new(),
169            light: Vec::new(),
170            ambient_light: None,
171            event_injections: Vec::new(),
172            update_injections: Vec::new(),
173            post_processes: Vec::new(),
174            display: None,
175            time: 0.0,
176            delta_time: 0.0,
177            render_scale: 1,
178            max_buffers: 3,
179            mouse_state: MouseState::new(),
180            gui_injections: Vec::new(),
181            state_data: Vec::new(),
182            last_event_time: Instant::now(),
183            last_frame_time: Instant::now(),
184            is_mouse_down: false,
185            audio_engine: AudioEngine::new(),
186            audio_clips: HashMap::new()
187        }
188    }
189
190    pub fn add_audio(&mut self, clip: AudioClip){
191        if self.audio_clips.contains_key(&clip.name){
192            EnigmaError::new(Some("Cannot add audio clip, since it is already added"), true).log();
193            return;
194        }
195        self.audio_clips.insert(clip.name.to_string(), clip);
196    }
197
198    pub fn play_audio_once(&mut self, name: &str){
199        self.audio_engine.play_clip_once(name, &self.audio_clips);
200    }
201
202    pub fn play_audio_loop(&mut self, name: &str) {
203        self.audio_engine.play_clip_loop(name, &self.audio_clips);
204    }
205
206    pub fn stop_audio(&mut self, name: &str) {
207        self.audio_engine.stop_clip(name);
208    }
209
210    pub fn toggle_pause_audio(&mut self, name: &str) {
211        self.audio_engine.toggle_pause_clip(name);
212    }
213
214    fn setup_skybox_instance(&self, display: &Display<WindowSurface>, sky_box_matrix: &Option<[[f32; 4]; 4]>) -> Option<(Uuid, object::ObjectInstance)> {
215        match &self.skybox {
216            Some(skybox) => {
217                let mut instance = ObjectInstance::new(display);
218                let model_matrix = sky_box_matrix.unwrap_or_else(|| {
219                    [[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]]
220                });
221                instance.set_vertex_buffers(skybox.get_vertex_buffers(display));
222                instance.set_index_buffers(skybox.get_index_buffers(display));
223                instance.instance_matrices.push(model_matrix);
224                let data = instance.instance_matrices
225                    .iter()
226                    .map(|i| geometry::InstanceAttribute {
227                        model_matrix: *i,
228                    })
229                    .collect::<Vec<_>>();
230                instance.instance_attributes = glium::vertex::VertexBuffer::dynamic(display, &data).unwrap();
231                Some((skybox.get_unique_id(), instance))
232            }
233            None => None
234        }
235    }
236
237    fn setup_instances(&mut self, display: &Display<WindowSurface>, model_matrices: &HashMap<Uuid, [[f32; 4]; 4]>) -> HashMap<Uuid, object::ObjectInstance> {
238        let mut instances = HashMap::new();
239        // sort objects for transparent rendering
240        self.objects.sort_by(|a, b| {
241            let distance_a = (self.camera.expect("failed to retrieve camera").transform.get_position() - a.transform.get_position()).len();
242            let distance_b = (self.camera.expect("failed to retrieve camera").transform.get_position() - b.transform.get_position()).len();
243            distance_b.partial_cmp(&distance_a).unwrap()
244        });
245
246        // iterating over the objects, making instances
247        for object in self.objects.iter() {
248            let instance_id = object.get_instance_id();
249            let model_matrix = model_matrices.get(&object.get_unique_id()).unwrap_or_else(|| {
250                &[[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]]
251            });
252            if !instances.contains_key(&instance_id) {
253                let mut object_instance = ObjectInstance::new(display);
254                object_instance.set_vertex_buffers(object.get_vertex_buffers(display));
255                object_instance.set_index_buffers(object.get_index_buffers(display));
256                instances.insert(instance_id, object_instance);
257            }
258            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);
259
260
261            //updating instance attributes
262            match instances.get_mut(&instance_id) {
263                Some(instance) => {
264                    let data = instance.instance_matrices
265                        .iter()
266                        .map(|i| geometry::InstanceAttribute {
267                            model_matrix: *i,
268                        })
269                        .collect::<Vec<_>>();
270                    instance.instance_attributes = glium::vertex::VertexBuffer::dynamic(display, &data).unwrap();
271                }
272                None => panic!("Something went wrong, when adding the instance")
273            }
274        }
275        instances
276    }
277
278    pub fn to_serializer(&self) -> AppStateSerializer {
279        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();
280        let camera = match self.camera {
281            Some(camera) => Some(camera.to_serializer()),
282            None => None,
283        };
284        let light = self.light.iter().map(|l| l.to_serializer()).collect();
285        let ambient_light = match &self.ambient_light {
286            Some(light) => Some(light.to_serializer()),
287            None => None,
288        };
289        let skybox = match &self.skybox {
290            Some(skybox) => Some(skybox.to_serializer()),
291            None => None,
292        };
293        let skybox_texture = match &self.skybox_texture {
294            Some(texture) => Some(texture.to_serializer()),
295            None => None,
296        };
297        let objects = self.objects.iter().map(|o| o.to_serializer()).collect();
298        let materials = self.materials.iter().map(|o| o.to_serializer()).collect();
299        let object_selection = self.object_selection.iter().map(|o| o.to_string()).collect();
300        AppStateSerializer {
301            camera,
302            light,
303            ambient_light,
304            skybox,
305            skybox_texture,
306            objects,
307            materials,
308            object_selection,
309        }
310    }
311
312    pub fn inject_serializer(&mut self, serializer: AppStateSerializer, display: Display<WindowSurface>, additive: bool) {
313        self.camera = match serializer.camera {
314            Some(camera) => Some(Camera::from_serializer(camera)),
315            None => None,
316        };
317        match serializer.ambient_light {
318            Some(light) => {
319                self.add_light(Light::from_serializer(light), LightEmissionType::Ambient);
320            }
321            None => {}
322        };
323        self.skybox = match serializer.skybox {
324            Some(skybox) => Some(Object::from_serializer(skybox)),
325            None => None,
326        };
327        self.skybox_texture = match serializer.skybox_texture {
328            Some(texture) => Some(Texture::from_serializer(texture, &display)),
329            None => None,
330        };
331
332        if !additive {
333            self.light.clear();
334            self.objects.clear();
335            self.object_selection.clear();
336        }
337        for l in serializer.light {
338            self.add_light(Light::from_serializer(l), LightEmissionType::Source);
339        }
340        for o in serializer.objects {
341            self.add_object(Object::from_serializer(o));
342        }
343        for m in serializer.materials {
344            self.add_material(Material::from_serializer(m, &display));
345        }
346        for o in serializer.object_selection {
347            self.object_selection.push(Uuid::parse_str(&o).unwrap());
348        }
349    }
350
351    pub fn add_state_data(&mut self, name: &str, data: Box<dyn Any>) {
352        self.state_data.push(AppStateData::new(name, data));
353    }
354
355    pub fn add_material(&mut self, material: Material) {
356        self.materials.push(material);
357    }
358
359    pub fn get_material(&self, uuid: &Uuid) -> Option<&Material> {
360        for material in &self.materials {
361            if &material.uuid == uuid {
362                return Some(&material);
363            }
364        }
365        None
366    }
367
368    pub fn get_material_by_name(&self, name: &str) -> Option<&Material> {
369        for material in &self.materials {
370            if &material.name == name {
371                return Some(&material);
372            }
373        }
374        None
375    }
376
377    pub fn get_state_data_value<T: 'static>(&self, name: &str) -> Option<&T> {
378        for data in self.state_data.iter() {
379            if data.get_name() == name {
380                // Attempt to downcast to the requested type T
381                if let Some(value) = data.get_value().downcast_ref::<T>() {
382                    return Some(value);
383                }
384            }
385        }
386        None
387    }
388
389    pub fn get_state_data_value_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
390        for data in self.state_data.iter_mut() {
391            if data.get_name() == name {
392                // Attempt to downcast to the requested type T
393                if let Some(value) = data.get_value_mut().downcast_mut::<T>() {
394                    return Some(value);
395                }
396            }
397        }
398        None
399    }
400
401    pub fn set_state_data_value(&mut self, name: &str, value: Box<dyn Any>) {
402        for data in &mut self.state_data {
403            if data.get_name() == name {
404                data.set_value(value);
405                return;
406            }
407        }
408        // If no existing data is found with the name, add as new state data
409        self.add_state_data(name, value);
410    }
411
412    pub fn inject_gui(&mut self, function: ui::GUIDrawFunction) {
413        self.gui_injections.push(function);
414    }
415
416    pub fn add_post_process(&mut self, post_process: Box<dyn PostProcessingEffect>) {
417        self.post_processes.push(post_process);
418    }
419
420    pub fn get_post_processes(&self) -> &Vec<Box<dyn PostProcessingEffect>> {
421        &self.post_processes
422    }
423
424    pub fn get_post_processes_mut(&mut self) -> &mut Vec<Box<dyn PostProcessingEffect>> {
425        &mut self.post_processes
426    }
427
428    pub fn get_mouse_state(&self) -> &MouseState {
429        &self.mouse_state
430    }
431
432    pub fn get_mouse_state_mut(&mut self) -> &mut MouseState {
433        &mut self.mouse_state
434    }
435
436    pub fn convert_to_arc_mutex(self) -> Arc<Mutex<Self>> {
437        Arc::new(Mutex::new(self))
438    }
439
440    pub fn add_object(&mut self, object: object::Object) {
441        self.objects.push(object);
442    }
443
444    pub fn get_objects(&self) -> &Vec<object::Object> {
445        &self.objects
446    }
447
448    pub fn get_object(&self, name: &str) -> Option<&object::Object> {
449        for object in self.objects.iter() {
450            if object.name == name {
451                return Some(object);
452            }
453        }
454        None
455    }
456
457    pub fn get_object_mut(&mut self, name: &str) -> Option<&mut object::Object> {
458        for object in self.objects.iter_mut() {
459            if object.name == name {
460                return Some(object);
461            }
462        }
463        None
464    }
465
466    pub fn get_object_by_uuid(&self, uuid: &Uuid) -> Option<&object::Object> {
467        for object in self.objects.iter() {
468            if &object.get_unique_id() == uuid {
469                return Some(object);
470            }
471        }
472        None
473    }
474
475    pub fn get_object_by_uuid_mut(&mut self, uuid: Uuid) -> Option<&mut object::Object> {
476        for object in self.objects.iter_mut() {
477            if object.get_unique_id() == uuid {
478                return Some(object);
479            }
480        }
481        None
482    }
483
484    pub fn get_selected_objects_mut(&mut self) -> Vec<&mut object::Object> {
485        let mut selected = Vec::new();
486        for object in self.objects.iter_mut() {
487            if self.object_selection.contains(&object.get_unique_id()) {
488                selected.push(object);
489            }
490        }
491        selected
492    }
493
494    pub fn add_light(&mut self, light: light::Light, light_type: LightEmissionType) {
495        match light_type {
496            LightEmissionType::Source => self.light.push(light),
497            LightEmissionType::Ambient => self.ambient_light = Some(light),
498        }
499    }
500
501    pub fn remove_light(&mut self, index: usize, light_type: LightEmissionType) {
502        match light_type {
503            LightEmissionType::Source => {
504                if index >= self.light.len() {
505                    panic!("Index out of bounds");
506                }
507                self.light.remove(index);
508            }
509            LightEmissionType::Ambient => {
510                self.ambient_light = None;
511            }
512        };
513    }
514
515    pub fn get_lights(&self) -> &Vec<light::Light> {
516        &self.light
517    }
518
519    pub fn set_fps(&mut self, fps: u64) {
520        self.fps = fps;
521    }
522
523    pub fn get_fps(&self) -> u64 {
524        self.fps
525    }
526
527    pub fn get_objects_mut(&mut self) -> &mut Vec<object::Object> {
528        &mut self.objects
529    }
530
531    pub fn set_camera(&mut self, camera: camera::Camera) {
532        self.camera = Some(camera);
533    }
534
535    pub fn get_camera(&self) -> &Option<camera::Camera> {
536        &self.camera
537    }
538
539    pub fn get_camera_mut(&mut self) -> &mut Option<camera::Camera> {
540        &mut self.camera
541    }
542
543    pub fn set_renderscale(&mut self, scale: u32) {
544        self.render_scale = scale;
545    }
546
547    pub fn get_renderscale(&self) -> u32 {
548        self.render_scale
549    }
550
551    pub fn set_max_buffers(&mut self, max_buffers: usize) {
552        self.max_buffers = max_buffers;
553    }
554
555    pub fn get_max_buffers(&self) -> usize {
556        self.max_buffers
557    }
558
559    pub fn inject_event(&mut self, characteristic: event::EventCharacteristic, function: event::EventFunction, modifiers: Option<event::EventModifiers>) {
560        match modifiers {
561            Some(modifiers) => self.event_injections.push((characteristic, function, modifiers)),
562            None => self.event_injections.push((characteristic, function, event::EventModifiers::default())),
563        }
564    }
565    pub fn inject_update_function(&mut self, function: event::EventFunction) {
566        self.update_injections.push(function);
567    }
568
569    pub fn set_skybox(&mut self, skybox: object::Object) {
570        self.skybox = Some(skybox);
571    }
572
573    pub fn set_skybox_from_texture(&mut self, texture: Texture, event_loop: &EventLoop){
574        let mut material = crate::material::Material::unlit(event_loop.get_display_clone(), false);
575        material.set_name("INTERNAL::SkyBox");
576
577        material.set_texture(texture, crate::material::TextureType::Albedo);
578        // create a default object
579        let mut object = Object::load_from_gltf_resource(resources::skybox(), None);
580        // set the material
581        object.add_material(material.uuid);
582        object.get_shapes_mut()[0].set_material_from_object_list(0);
583        object.name = "Skybox".to_string();
584        object.transform.set_scale([1.0, 1.0, 1.0]);
585        self.add_material(material);
586        self.set_skybox(object);
587    }
588
589    pub fn get_skybox(&self) -> &Option<object::Object> {
590        &self.skybox
591    }
592
593    pub fn get_skybox_mut(&mut self) -> &mut Option<object::Object> {
594        &mut self.skybox
595    }
596}
597
598impl EventLoop {
599    pub fn new(title: &str, width: u32, height: u32) -> Self {
600        let event_loop = winit::event_loop::EventLoopBuilder::new().build();
601        let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new()
602            .with_title(title)
603            .with_inner_size(width, height)
604            .build(&event_loop);
605        EventLoop {
606            event_loop,
607            window,
608            display,
609            modifiers: EventModifiers::default(),
610            gui_renderer: None,
611        }
612    }
613    pub fn get_display_clone(&self) -> Display<WindowSurface> {
614        self.display.clone()
615    }
616
617    pub fn get_display_reference(&self) -> &Display<WindowSurface> {
618        &self.display
619    }
620
621    pub fn spawn_skybox(&mut self, app_state: &mut AppState) -> (crate::object::Object, texture::Texture) {
622        if let Some(current_skybox_object) = app_state.get_skybox().clone() {
623            // If we have an existing skybox, try to get its texture
624            if let Some(texture_uuid) = current_skybox_object.get_materials().first() {
625                if let Some(material) = app_state.get_material(texture_uuid) {
626                    if let Some(texture) = &material.albedo {
627                        // Successfully found texture, clone it and return with the existing object
628                        return (
629                            current_skybox_object,
630                            texture.get_texture_clone(self.get_display_reference())
631                        );
632                    }
633                }
634            }
635
636            // If we reached here, we couldn't get the texture from the existing skybox
637            let mut logger = EnigmaWarning::new(None, true);
638            logger.extent("Failed to get texture from existing skybox. Creating default skybox...");
639            logger.log();
640        }
641
642        let mut material = crate::material::Material::unlit(self.display.clone(), false);
643        material.set_name("INTERNAL::SkyBox");
644
645        material.set_texture_from_resource(resources::skybox_texture(), crate::material::TextureType::Albedo);
646
647        // create a default object
648        let mut object = Object::load_from_gltf_resource(resources::skybox(), None);
649
650        // set the material
651        object.add_material(material.uuid);
652        object.get_shapes_mut()[0].set_material_from_object_list(0);
653
654        object.name = "Skybox".to_string();
655
656        object.transform.set_scale([1.0, 1.0, 1.0]);
657
658        app_state.add_material(material);
659        // skybox texture
660        let skybox_texture = texture::Texture::from_resource(&self.display, resources::skybox_texture());
661        (object, skybox_texture)
662    }
663
664    pub fn set_icon_from_path(&self, path: &str) {
665        let image = image::open(path).expect("failed to load icon").to_rgba8();
666        let image_dimensions = image.dimensions();
667        let data = image.into_raw();
668        let icon = winit::window::Icon::from_rgba(data, image_dimensions.0, image_dimensions.1).expect("failed to load icon");
669        self.window.set_window_icon(Some(icon));
670    }
671
672    pub fn set_icon_from_resource(&self, data: &[u8]) {
673        let image = image::load_from_memory(data).expect("failed to load icon").to_rgba8();
674        let image_dimensions = image.dimensions();
675        let data = image.into_raw();
676        let icon = winit::window::Icon::from_rgba(data, image_dimensions.0, image_dimensions.1).expect("failed to load icon");
677        self.window.set_window_icon(Some(icon));
678    }
679
680    // This is just the render loop . an actual event loop still needs to be set up
681    pub fn run(mut self, app_state: Arc<Mutex<AppState>>) {
682        let mut temp_app_state = app_state.lock().unwrap();
683        temp_app_state.display = Some(self.display.clone());
684
685        //spawning skybox
686        let (skybox, skybox_texture) = self.spawn_skybox(&mut temp_app_state);
687        temp_app_state.set_skybox(skybox);
688
689
690        // managing fps
691        let mut next_frame_time = Instant::now();
692        let nanos = 1_000_000_000 / temp_app_state.fps;
693        let frame_duration = Duration::from_nanos(nanos); // 60 FPS (1,000,000,000 ns / 60)
694
695        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");
696        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");
697
698        let mut buffer_textures: Vec<Texture2d> = Vec::new();
699        for _ in 0..temp_app_state.max_buffers {
700            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"));
701        }
702
703        //dropping modified appstate
704        drop(temp_app_state);
705
706        // prepare post processing
707        let screen_vert_rect = postprocessing::get_screen_vert_rect(&self.display);
708        let screen_indices_rect = postprocessing::get_screen_indices_rect(&self.display);
709        let screen_program = postprocessing::get_screen_program(&self.display);
710
711        //initializing GUI
712        match self.gui_renderer {
713            Some(_) => {}
714            None => {
715                let egui_glium = EguiGlium::new(&self.display, &self.window, &self.event_loop);
716                self.gui_renderer = Some(egui_glium);
717            }
718        }
719        // run loop
720        self.event_loop.run(move |event, _window_target, control_flow| {
721            // unpacking appstate
722            let mut app_state = app_state.lock().unwrap();
723            let light = app_state.light.clone();
724            let ambient_light = app_state.ambient_light.clone();
725            let camera = app_state.camera.clone();
726            let event_injections = app_state.event_injections.clone();
727            let update_injections = app_state.update_injections.clone();
728            let gui_injections = app_state.gui_injections.clone();
729
730            *control_flow = ControlFlow::WaitUntil(next_frame_time);
731            next_frame_time = Instant::now() + frame_duration;
732
733            // passing framebuffer
734            let texture = &mut texture;
735            let depth_texture = &mut depth_texture;
736            let buffer_textures = &mut buffer_textures;
737            let mut framebuffer = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&self.display, &*texture, &*depth_texture).expect("Failed to create framebuffer");
738
739            // passing skybox
740            let skybox_texture = &skybox_texture;
741
742            match event {
743                Event::WindowEvent { event, .. } => match event {
744                    WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; }
745                    WindowEvent::Resized(new_size) => {
746                        let response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
747                        if !response.consumed {
748                            app_state.camera.as_mut().expect("failed to retrieve camera").set_aspect(new_size.width as f32, new_size.height as f32);
749                            self.display.resize(new_size.into());
750                            if let Some(app_state_display) = app_state.display.as_mut() {
751                                app_state_display.resize(new_size.into());
752                            }
753                        }
754                    }
755                    WindowEvent::ModifiersChanged(modifiers) => {
756                        self.modifiers.ctrl = modifiers.ctrl();
757                        self.modifiers.shift = modifiers.shift();
758                        self.modifiers.alt = modifiers.alt();
759                    }
760                    WindowEvent::CursorMoved { position, .. } => {
761                        let response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
762                        if !response.consumed {
763                            app_state.get_mouse_state_mut().update_position((position.x, position.y));
764                        }
765                    }
766                    WindowEvent::MouseInput { state, button, .. } => {
767                        let mut response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
768                        if !response.consumed {
769                            for (characteristic, function, modifiers) in &event_injections {
770                                if let event::EventCharacteristic::MouseDown(mouse_button) = characteristic {
771                                    if button == *mouse_button && modifiers == &self.modifiers {
772                                        if state == winit::event::ElementState::Pressed {
773                                            app_state.is_mouse_down = true;
774                                            app_state.last_event_time = Instant::now();
775                                            function(&mut app_state);
776                                        } else {
777                                            app_state.is_mouse_down = false;
778                                        }
779                                    }
780                                } else if let event::EventCharacteristic::MousePress(_) = characteristic {
781                                    if modifiers == &self.modifiers {
782                                        function(&mut app_state);
783                                        response.consumed = true;
784                                    }
785                                }
786                            }
787                        }
788                    }
789                    WindowEvent::KeyboardInput { input, .. } => {
790                        let response = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
791                        if !response.consumed {
792                            for (characteristic, function, modifiers) in event_injections {
793                                if let event::EventCharacteristic::KeyPress(key_code) = characteristic {
794                                    if input.state == winit::event::ElementState::Pressed && input.virtual_keycode == Some(key_code) && modifiers == self.modifiers {
795                                        function(&mut app_state);
796                                    }
797                                }
798                            };
799                        }
800                    }
801                    _ => {
802                        _ = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer").on_event(&event);
803                    }
804                }
805                Event::RedrawRequested(_) => {
806                    let current_time = Instant::now();
807                    app_state.delta_time = (current_time - app_state.last_frame_time).as_secs_f32();
808                    app_state.last_frame_time = current_time;
809                    app_state.time += app_state.delta_time;
810                    // updating materials
811                    for material in app_state.materials.iter_mut() {
812                        material.update();
813                    }
814                    // updating objects
815                    let deltatime = app_state.delta_time;
816                    for object in app_state.objects.iter_mut() {
817                        object.update(deltatime);
818                    }
819
820                    let render_target = &mut framebuffer;
821                    render_target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
822                    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();
823                    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();
824                    let object_instances = app_state.setup_instances(&self.display, &model_matrices);
825                    // render objects opaque
826                    let opaque_rendering_parameter = glium::DrawParameters {
827                        depth: glium::Depth {
828                            test: glium::draw_parameters::DepthTest::IfLess,
829                            write: true,
830                            ..Default::default()
831                        },
832                        backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
833                        ..Default::default()
834                    };
835
836                    for (instance_id, object_instance) in object_instances.iter() {
837                        let object_option = app_state.get_object_by_uuid(&instance_id);
838                        match object_option {
839                            Some(object) => {
840                                let closest_lights = object.get_closest_lights(&light);
841                                let has_skeleton = object.get_skeleton().is_some();
842                                let bone_transform = bone_uniform_buffers.get(&object.get_unique_id()).expect("Missing Bone Transform Uniforms for Object");
843                                for ((buffer, mat_index), indices) in object_instance.vertex_buffers.iter().zip(object_instance.index_buffers.iter()) {
844                                    let mat_uuid: &Uuid = &object.get_materials()[*mat_index];
845                                    match app_state.get_material(mat_uuid) {
846                                        Some(material) => {
847                                            if material.render_transparent {
848                                                continue;
849                                            }
850                                            let uniforms = &material.get_uniforms(&closest_lights, ambient_light, camera, &bone_transform, has_skeleton, skybox_texture);
851                                            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");
852                                        }
853                                        None => ()
854                                    }
855                                }
856                            }
857                            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()
858                        }
859                    }
860
861                    // render skybox
862                    let skybox_rendering_parameter = glium::DrawParameters {
863                        depth: glium::Depth {
864                            test: glium::draw_parameters::DepthTest::IfLess,
865                            write: false,
866                            ..Default::default()
867                        },
868                        backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
869                        ..Default::default()
870                    };
871
872                    //First get the matrix outside of the closure
873                    let skybox_model_matrix = match app_state.get_skybox_mut() {
874                        Some(obj) => Some(obj.transform.get_matrix().clone()),
875                        None => None
876                    };
877                    let skybox_instance = app_state.setup_skybox_instance(&self.display, &skybox_model_matrix);
878
879                    match skybox_instance {
880                        Some((skybox_id, instance)) => {
881                            let object_option = app_state.get_skybox();
882                            match object_option {
883                                Some(skybox) => {
884                                    let closest_lights = skybox.get_closest_lights(&light);
885                                    let skybox_bone_buffer = skybox.get_bone_transform_buffer(&self.display);
886                                    for ((buffer, mat_index), indices) in instance.vertex_buffers.iter().zip(instance.index_buffers.iter()) {
887                                        let mat_uuid: &Uuid = &skybox.get_materials()[*mat_index];
888                                        match app_state.get_material(mat_uuid) {
889                                            Some(material) => {
890                                                let uniforms = &material.get_uniforms(&closest_lights, ambient_light, camera, &skybox_bone_buffer, false, skybox_texture);
891                                                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");
892                                            }
893                                            None => ()
894                                        }
895                                    }
896                                }
897                                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()
898                            }
899                        }
900                        None => {}
901                    }
902
903                    // render objects transparent
904                    let transparent_rendering_parameter = glium::DrawParameters {
905                        blend: glium::Blend::alpha_blending(),
906                        ..opaque_rendering_parameter
907                    };
908                    for (instance_id, object_instance) in object_instances.iter() {
909                        let object_option = app_state.get_object_by_uuid(&instance_id);
910                        match object_option {
911                            Some(object) => {
912                                let closest_lights = object.get_closest_lights(&light);
913                                let has_skeleton = object.get_skeleton().is_some();
914                                let bone_transform = bone_uniform_buffers.get(&object.get_unique_id()).expect("Missing Bone Transform Uniforms for Object");
915                                for ((buffer, mat_index), indices) in object_instance.vertex_buffers.iter().zip(object_instance.index_buffers.iter()) {
916                                    let mat_uuid: &Uuid = &object.get_materials()[*mat_index];
917                                    match app_state.get_material(mat_uuid) {
918                                        Some(material) => {
919                                            if !material.render_transparent {
920                                                continue;
921                                            }
922                                            let uniforms = &material.get_uniforms(&closest_lights, ambient_light, camera, &bone_transform, has_skeleton, skybox_texture);
923                                            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");
924                                        }
925                                        None => ()
926                                    }
927                                }
928                            }
929                            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()
930                        }
931                    }
932
933                    // execute post processing#
934                    for process in app_state.get_post_processes() {
935                        process.render(&app_state, &screen_vert_rect, &screen_indices_rect, &mut framebuffer, &texture, &depth_texture, &buffer_textures);
936                    }
937
938                    // drawing to screen
939                    let mut screen_target = self.display.draw();
940                    let screen_uniforms = uniform! {
941                        scene: &*texture,
942                    };
943                    screen_target.draw(
944                        &screen_vert_rect,
945                        &screen_indices_rect,
946                        &screen_program,
947                        &screen_uniforms,
948                        &Default::default(),
949                    ).expect("Failed to draw screen");
950
951                    // drawing GUI
952                    let gui_renderer = self.gui_renderer.as_mut().expect("Failed to retrieve gui renderer");
953                    gui_renderer.run(&self.window, |egui_context| {
954                        for function in gui_injections.iter() {
955                            function(egui_context, &mut app_state);
956                        }
957                    });
958                    gui_renderer.paint(&self.display, &mut screen_target);
959                    screen_target.finish().expect("Failed to swap buffers");
960                }
961                Event::MainEventsCleared => {
962
963                    // executing mouse down events
964                    if app_state.is_mouse_down && app_state.last_event_time.elapsed() >= Duration::from_millis(100) {
965                        for (characteristic, function, modifiers) in &event_injections {
966                            if let event::EventCharacteristic::MouseDown(_) = characteristic {
967                                if modifiers == &self.modifiers {
968                                    function(&mut app_state);
969                                    app_state.last_event_time = Instant::now();
970                                }
971                            }
972                        }
973                    }
974
975                    // executing update functions
976                    for function in update_injections {
977                        function(&mut app_state);
978                    }
979                    self.window.request_redraw();
980                }
981                _ => (),
982            }
983        });
984    }
985}