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