oxygengine_composite_renderer/system/
renderer.rs

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}