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}