1use crate::{
2 component::{
3 CompositeCamera, CompositeCameraAlignment, CompositeEffect, CompositeRenderAlpha,
4 CompositeRenderDepth, CompositeRenderLayer, CompositeRenderable, CompositeRenderableStroke,
5 CompositeTransform, CompositeVisibility,
6 },
7 composite_renderer::{Command, CompositeRenderer, Renderable, Stats},
8 math::{Mat2d, Vec2},
9 resource::CompositeTransformCache,
10};
11use core::{
12 app::AppLifeCycle,
13 assets::database::AssetsDatabase,
14 ecs::{components::Tag, Comp, Universe, UnsafeRef, UnsafeScope, WorldRef},
15};
16
17pub type CompositeRendererSystemResources<'a, CR> = (
18 WorldRef,
19 &'a mut CR,
20 &'a AppLifeCycle,
21 &'a AssetsDatabase,
22 &'a CompositeTransformCache,
23 (
24 Comp<&'a CompositeCamera>,
25 Comp<&'a CompositeVisibility>,
26 Comp<&'a CompositeRenderable>,
27 Comp<&'a CompositeTransform>,
28 Comp<&'a CompositeRenderLayer>,
29 Comp<&'a CompositeRenderDepth>,
30 Comp<&'a CompositeRenderAlpha>,
31 Comp<&'a CompositeCameraAlignment>,
32 Comp<&'a CompositeRenderableStroke>,
33 Comp<&'a CompositeEffect>,
34 Comp<&'a Tag>,
35 ),
36);
37
38#[allow(clippy::many_single_char_names)]
39pub fn composite_renderer_system<CR>(universe: &mut Universe)
40where
41 CR: CompositeRenderer + 'static,
42{
43 let (world, mut renderer, lifecycle, assets, cache, ..) =
44 universe.query_resources::<CompositeRendererSystemResources<CR>>();
45
46 renderer.update_cache(&assets);
47 renderer.update_state();
48 let (width, height) = {
49 let r = renderer.view_size();
50 (r.x, r.y)
51 };
52 let mut stats = Stats {
53 view_size: renderer.view_size(),
54 images_count: renderer.images_count(),
55 fontfaces_count: renderer.fontfaces_count(),
56 surfaces_count: renderer.surfaces_count(),
57 ..Default::default()
58 };
59
60 if let Some(color) = renderer.state().clear_color {
61 let result = renderer.execute(vec![Command::Draw(Renderable::FullscreenRectangle(color))]);
62 if let Ok((render_ops, renderables)) = result {
63 stats.render_ops += render_ops;
64 stats.renderables += renderables;
65 }
66 }
67
68 let unsafe_scope = UnsafeScope;
69 let mut sorted_cameras = world
70 .query::<(
71 &CompositeCamera,
72 &CompositeTransform,
73 Option<&CompositeVisibility>,
74 Option<&CompositeRenderAlpha>,
75 Option<&CompositeRenderLayer>,
76 Option<&CompositeRenderDepth>,
77 )>()
78 .iter()
79 .filter_map(
80 |(_, (camera, transform, visibility, alpha, layer, depth))| {
81 let visible = visibility.map(|v| v.0).unwrap_or(true);
82 let alpha = alpha.map(|v| v.0);
83 let alpha_visible = alpha.map(|v| v > 0.0).unwrap_or(true);
84 if visible && alpha_visible {
85 let layer = layer.map(|v| v.0).unwrap_or(0);
86 let depth = depth.map(|v| v.0).unwrap_or(0.0);
87 unsafe {
88 Some((
89 layer,
90 depth,
91 alpha,
92 UnsafeRef::upgrade(&unsafe_scope, camera),
93 UnsafeRef::upgrade(&unsafe_scope, transform),
94 ))
95 }
96 } else {
97 None
98 }
99 },
100 )
101 .collect::<Vec<_>>();
102 sorted_cameras.sort_by(|a, b| {
103 a.0.partial_cmp(&b.0)
104 .unwrap()
105 .then_with(|| a.1.partial_cmp(&b.1).unwrap())
106 });
107
108 for (_, _, camera_alpha, camera, camera_transform) in sorted_cameras {
109 let unsafe_scope = UnsafeScope;
110 let mut sorted = world
111 .query::<(
112 &CompositeRenderable,
113 Option<&Tag>,
114 Option<&CompositeVisibility>,
115 Option<&CompositeRenderAlpha>,
116 Option<&CompositeRenderLayer>,
117 Option<&CompositeRenderDepth>,
118 Option<&CompositeCameraAlignment>,
119 Option<&CompositeEffect>,
120 Option<&CompositeRenderableStroke>,
121 )>()
122 .with::<&CompositeTransform>()
123 .iter()
124 .filter(|(_, (_, tag, ..))| unsafe {
125 camera.read().tags.is_empty()
126 || tag
127 .map(|tag| camera.read().tags.contains(&tag.0))
128 .unwrap_or(false)
129 })
130 .filter_map(
131 |(
132 entity,
133 (renderable, _, visibility, alpha, layer, depth, alignment, effect, stroke),
134 )| {
135 let visible = visibility.map(|v| v.0).unwrap_or(true);
136 let alpha_visible = alpha.map(|v| v.0 > 0.0).unwrap_or(true);
137 if visible && alpha_visible {
138 let layer = layer.map(|v| v.0).unwrap_or(0);
139 let depth = depth.map(|v| v.0).unwrap_or(0.0);
140 unsafe {
141 Some((
142 layer,
143 depth,
144 cache.matrix(entity).unwrap_or_default(),
145 UnsafeRef::upgrade(&unsafe_scope, renderable),
146 alignment
147 .map(|alignment| UnsafeRef::upgrade(&unsafe_scope, alignment)),
148 effect.map(|effect| UnsafeRef::upgrade(&unsafe_scope, effect)),
149 alpha.map(|alpha| UnsafeRef::upgrade(&unsafe_scope, alpha)),
150 stroke.map(|stroke| UnsafeRef::upgrade(&unsafe_scope, stroke)),
151 ))
152 }
153 } else {
154 None
155 }
156 },
157 )
158 .collect::<Vec<_>>();
159 sorted.sort_by(|a, b| {
160 a.0.partial_cmp(&b.0)
161 .unwrap()
162 .then_with(|| a.1.partial_cmp(&b.1).unwrap())
163 });
164
165 let camera_matrix = unsafe {
166 camera
167 .read()
168 .view_matrix(camera_transform.read(), [width, height].into())
169 };
170 let commands = std::iter::once(Command::Store)
171 .chain(std::iter::once({
172 let [a, b, c, d, e, f] = camera_matrix.0;
173 Command::Transform(a, b, c, d, e, f)
174 }))
175 .chain(std::iter::once(
176 camera_alpha.map(Command::Alpha).unwrap_or(Command::None),
177 ))
178 .chain(sorted.iter().flat_map(
179 |(_, _, matrix, renderable, alignment, effect, alpha, stroke)| {
180 let [a, b, c, d, e, f] = matrix.0;
181 vec![
182 Command::Store,
183 alignment
184 .as_ref()
185 .map(|alignment| unsafe {
186 let alignment = alignment.read();
187 let p = Vec2::new(alignment.0.x * width, alignment.0.y * height);
188 let [a, b, c, d, e, f] =
189 ((!camera_matrix).unwrap() * Mat2d::translation(p)).0;
190 Command::Transform(a, b, c, d, e, f)
191 })
192 .unwrap_or(Command::None),
193 Command::Transform(a, b, c, d, e, f),
194 effect
195 .as_ref()
196 .map(|effect| unsafe { Command::Effect(effect.read().0) })
197 .unwrap_or(Command::None),
198 alpha
199 .as_ref()
200 .map(|alpha| unsafe { Command::Alpha(alpha.read().0) })
201 .unwrap_or(Command::None),
202 stroke
203 .as_ref()
204 .map(|stroke| unsafe {
205 Command::Stroke(stroke.read().0, renderable.read().0.clone())
206 })
207 .unwrap_or_else(|| unsafe {
208 Command::Draw(renderable.read().0.clone())
209 }),
210 Command::Restore,
211 ]
212 },
213 ))
214 .chain(std::iter::once(Command::Restore));
215
216 if let Ok((render_ops, renderables)) = renderer.execute(commands) {
217 stats.render_ops += render_ops;
218 stats.renderables += renderables;
219 }
220 }
221 stats.delta_time = lifecycle.delta_time_seconds();
222 stats.fps = if stats.delta_time > 0.0 {
223 1.0 / stats.delta_time
224 } else {
225 0.0
226 };
227 renderer.state_mut().set_stats(stats);
228}