forte_engine/
component_app.rs

1use crate::render::render_engine::RenderEngine;
2
3/// A trait defining the standard functions for a component to be used by the engine.
4/// 
5/// T - The other components needed from the engine to use this component.
6pub trait EngineComponent<T> {
7    /// Creates a new instance of this component using a mutable reference to a `RenderEngine`.
8    fn create(engine: &mut RenderEngine) -> Self;
9
10    /// Called when the engine starts all the components after they are all created.
11    fn start(&mut self, other: T);
12
13    /// Called when the engine updates.
14    fn update(&mut self, other: T);
15
16    /// Called when this component is called to render during its render pass defined in the created `App`.
17    fn render<'rpass>(&'rpass mut self, render_engine: &'rpass RenderEngine, pass: &mut wgpu::RenderPass<'rpass>);
18
19    /// Called when the engine exits.
20    fn exit(&mut self, other: T);
21}
22
23/// This macro creates a `App` objects using a given set of components and some render pass descriptions.
24/// 
25/// Example:
26/// ```rust
27/// create_app! {
28///     CLEAR_COLOR = wgpu::Color { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
29/// 
30///     APP {
31///         ui_engine: UIEngine[render_engine],
32///         test: TestComponent[render_engine, ui_engine, egui],
33///         egui: EguiEngine[render_engine, inputs]
34///     },
35/// 
36///     PASSES {
37///         0: {
38///             PARTS: [
39///                 {
40///                     PIPELINE: "forte.test",
41///                     PREPARE: [],
42///                     RENDER: test,
43///                 }
44///             ],
45///             DEPTH: true
46///         },
47///         1: {
48///             PARTS: [
49///                 {
50///                     PIPELINE: "forte.ui",
51///                     PREPARE: [],
52///                     RENDER: ui_engine,
53///                 },
54///                 {
55///                     PIPELINE: "forte.ui",
56///                     PREPARE: [],
57///                     RENDER: egui,
58///                 }
59///             ],
60///             DEPTH: false
61///         }
62///     }
63/// }
64/// ```
65#[macro_export]
66macro_rules! create_app {
67    {
68        CLEAR_COLOR = $color:expr,
69        APP {$(
70            $component:ident: $type:ty[$($param:ident),*]
71        ),*},
72        PASSES {$(
73            $pass_idx:literal: {
74                PARTS: [$(
75                    {
76                        PIPELINE: $pipeline:expr,
77                        PREPARE: [$($prepare:ident),*],
78                        RENDER: $to_render:ident,
79                    }
80                ),*],
81                DEPTH: $depth:literal
82            }
83        ),*}
84    } => {
85        use forte_engine::{EngineApp, start_render, end_render, pass, inputs::{Inputs, winit_input::EngineInput}, render::{render_engine::RenderEngine, render_utils}};
86
87        pub struct App {
88            render_engine: RenderEngine,
89            inputs: Inputs,
90            $($component: $type,)*
91        }
92
93        impl EngineApp for App {
94            // Takes in a render engine and creates each component individually in the order listed, then saves them into a new instance of App.
95            fn create(mut render_engine: RenderEngine) -> Self {
96                let inputs = Inputs::new();
97                $(let $component = <$type>::create(&mut render_engine);)*
98                Self {
99                    render_engine,
100                    inputs,
101                    $($component,)*
102                }
103            }
104
105            // Starts app components of the App.
106            fn start(&mut self) {
107                $(
108                    <$type>::start(&mut self.$component, ($(&mut self.$param),*));
109                )*
110            }
111
112            // Updates App components, then performs the render steps in the order given.
113            fn update(&mut self) {
114                // Run update
115                $(
116                    <$type>::update(&mut self.$component, ($(&mut self.$param),*));
117                )*
118
119                // start the render
120                let resources = render_utils::prepare_render(&self.render_engine);
121                let mut resources = if resources.is_ok() { resources.unwrap() } else { return };
122
123                // run each render pass in the order given
124                $(
125                    {
126                        // create color attachment for this pass
127                        let pass_id = $pass_idx;
128                        let color_attachment = wgpu::RenderPassColorAttachment {
129                            view: &resources.view,
130                            resolve_target: None,
131                            ops: if pass_id == 0 {
132                                wgpu::Operations {
133                                    load: wgpu::LoadOp::Clear($color),
134                                    store: wgpu::StoreOp::Store,
135                                }
136                            } else {
137                                wgpu::Operations {
138                                    load: wgpu::LoadOp::Load,
139                                    store: wgpu::StoreOp::Store,
140                                }
141                            },
142                        };
143
144                        // create the render pass
145                        let mut pass = resources.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
146                            label: Some("Render Pass"),
147                            color_attachments: &[Some(color_attachment)],
148                            depth_stencil_attachment: 
149                                if !$depth { None } 
150                                else { 
151                                    Some(wgpu::RenderPassDepthStencilAttachment {
152                                        view: &self.render_engine.depth_texture.view,
153                                        depth_ops: Some(wgpu::Operations {
154                                            load: wgpu::LoadOp::Clear(1.0),
155                                            store: wgpu::StoreOp::Store
156                                        }),
157                                        stencil_ops: None
158                                    })
159                                },
160                            occlusion_query_set: None,
161                            timestamp_writes: None,
162                        });
163
164                        $(
165                            // call all members of this pass' render functions
166                            self.render_engine.pipeline_path($pipeline).unwrap().bind(&mut pass);
167                            $(
168                                self.$prepare.render(&self.render_engine, &mut pass);
169                            )*
170                            self.$to_render.render(&self.render_engine, &mut pass);
171                        )*
172                    }
173                )*
174
175                // end the render
176                render_utils::finalize_render(&mut self.render_engine, resources);
177
178                // call next frame, will be replaced later
179                self.render_engine.next_frame();
180
181                // reset inputs
182                self.inputs.reset();
183            }
184
185            // takes all input from the event loop, will be processed later
186            fn input(&mut self, input: EngineInput) {
187                self.inputs.handle_input(input);
188            }
189            
190            // passes all resize from the event loop to the render engine
191            fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { self.render_engine.resize(new_size); }
192
193            // calls all the exit functions of the components in the order given
194            fn exit(&mut self) {
195                $(
196                    <$type>::exit(&mut self.$component, ($(&mut self.$param),*));
197                )*
198            }
199        }
200    };
201}