1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
use crate::{
    component::{
        CompositeCamera, CompositeCameraAlignment, CompositeEffect, CompositeRenderAlpha,
        CompositeRenderDepth, CompositeRenderLayer, CompositeRenderable, CompositeRenderableStroke,
        CompositeTransform, CompositeVisibility,
    },
    composite_renderer::{Command, CompositeRenderer, Renderable, Stats},
    math::{Mat2d, Vec2},
    resource::CompositeTransformCache,
};
use core::{
    app::AppLifeCycle,
    assets::database::AssetsDatabase,
    ecs::{components::Tag, Comp, Universe, UnsafeRef, UnsafeScope, WorldRef},
};

pub type CompositeRendererSystemResources<'a, CR> = (
    WorldRef,
    &'a mut CR,
    &'a AppLifeCycle,
    &'a AssetsDatabase,
    &'a CompositeTransformCache,
    (
        Comp<&'a CompositeCamera>,
        Comp<&'a CompositeVisibility>,
        Comp<&'a CompositeRenderable>,
        Comp<&'a CompositeTransform>,
        Comp<&'a CompositeRenderLayer>,
        Comp<&'a CompositeRenderDepth>,
        Comp<&'a CompositeRenderAlpha>,
        Comp<&'a CompositeCameraAlignment>,
        Comp<&'a CompositeRenderableStroke>,
        Comp<&'a CompositeEffect>,
        Comp<&'a Tag>,
    ),
);

#[allow(clippy::many_single_char_names)]
pub fn composite_renderer_system<CR>(universe: &mut Universe)
where
    CR: CompositeRenderer + 'static,
{
    let (world, mut renderer, lifecycle, assets, cache, ..) =
        universe.query_resources::<CompositeRendererSystemResources<CR>>();

    renderer.update_cache(&assets);
    renderer.update_state();
    let (width, height) = {
        let r = renderer.view_size();
        (r.x, r.y)
    };
    let mut stats = Stats {
        view_size: renderer.view_size(),
        images_count: renderer.images_count(),
        fontfaces_count: renderer.fontfaces_count(),
        surfaces_count: renderer.surfaces_count(),
        ..Default::default()
    };

    if let Some(color) = renderer.state().clear_color {
        let result = renderer.execute(vec![Command::Draw(Renderable::FullscreenRectangle(color))]);
        if let Ok((render_ops, renderables)) = result {
            stats.render_ops += render_ops;
            stats.renderables += renderables;
        }
    }

    let unsafe_scope = UnsafeScope;
    let mut sorted_cameras = world
        .query::<(
            &CompositeCamera,
            &CompositeTransform,
            Option<&CompositeVisibility>,
            Option<&CompositeRenderAlpha>,
            Option<&CompositeRenderLayer>,
            Option<&CompositeRenderDepth>,
        )>()
        .iter()
        .filter_map(
            |(_, (camera, transform, visibility, alpha, layer, depth))| {
                let visible = visibility.map(|v| v.0).unwrap_or(true);
                let alpha = alpha.map(|v| v.0);
                let alpha_visible = alpha.map(|v| v > 0.0).unwrap_or(true);
                if visible && alpha_visible {
                    let layer = layer.map(|v| v.0).unwrap_or(0);
                    let depth = depth.map(|v| v.0).unwrap_or(0.0);
                    unsafe {
                        Some((
                            layer,
                            depth,
                            alpha,
                            UnsafeRef::upgrade(&unsafe_scope, camera),
                            UnsafeRef::upgrade(&unsafe_scope, transform),
                        ))
                    }
                } else {
                    None
                }
            },
        )
        .collect::<Vec<_>>();
    sorted_cameras.sort_by(|a, b| {
        a.0.partial_cmp(&b.0)
            .unwrap()
            .then_with(|| a.1.partial_cmp(&b.1).unwrap())
    });

    for (_, _, camera_alpha, camera, camera_transform) in sorted_cameras {
        let unsafe_scope = UnsafeScope;
        let mut sorted = world
            .query::<(
                &CompositeRenderable,
                Option<&Tag>,
                Option<&CompositeVisibility>,
                Option<&CompositeRenderAlpha>,
                Option<&CompositeRenderLayer>,
                Option<&CompositeRenderDepth>,
                Option<&CompositeCameraAlignment>,
                Option<&CompositeEffect>,
                Option<&CompositeRenderableStroke>,
            )>()
            .with::<CompositeTransform>()
            .iter()
            .filter(|(_, (_, tag, ..))| unsafe {
                camera.read().tags.is_empty()
                    || tag
                        .map(|tag| camera.read().tags.contains(&tag.0))
                        .unwrap_or(false)
            })
            .filter_map(
                |(
                    entity,
                    (renderable, _, visibility, alpha, layer, depth, alignment, effect, stroke),
                )| {
                    let visible = visibility.map(|v| v.0).unwrap_or(true);
                    let alpha_visible = alpha.map(|v| v.0 > 0.0).unwrap_or(true);
                    if visible && alpha_visible {
                        let layer = layer.map(|v| v.0).unwrap_or(0);
                        let depth = depth.map(|v| v.0).unwrap_or(0.0);
                        unsafe {
                            Some((
                                layer,
                                depth,
                                cache.matrix(entity).unwrap_or_default(),
                                UnsafeRef::upgrade(&unsafe_scope, renderable),
                                alignment
                                    .map(|alignment| UnsafeRef::upgrade(&unsafe_scope, alignment)),
                                effect.map(|effect| UnsafeRef::upgrade(&unsafe_scope, effect)),
                                alpha.map(|alpha| UnsafeRef::upgrade(&unsafe_scope, alpha)),
                                stroke.map(|stroke| UnsafeRef::upgrade(&unsafe_scope, stroke)),
                            ))
                        }
                    } else {
                        None
                    }
                },
            )
            .collect::<Vec<_>>();
        sorted.sort_by(|a, b| {
            a.0.partial_cmp(&b.0)
                .unwrap()
                .then_with(|| a.1.partial_cmp(&b.1).unwrap())
        });

        let camera_matrix = unsafe {
            camera
                .read()
                .view_matrix(camera_transform.read(), [width, height].into())
        };
        let commands = std::iter::once(Command::Store)
            .chain(std::iter::once({
                let [a, b, c, d, e, f] = camera_matrix.0;
                Command::Transform(a, b, c, d, e, f)
            }))
            .chain(std::iter::once(
                camera_alpha.map(Command::Alpha).unwrap_or(Command::None),
            ))
            .chain(sorted.iter().flat_map(
                |(_, _, matrix, renderable, alignment, effect, alpha, stroke)| {
                    let [a, b, c, d, e, f] = matrix.0;
                    vec![
                        Command::Store,
                        alignment
                            .as_ref()
                            .map(|alignment| unsafe {
                                let alignment = alignment.read();
                                let p = Vec2::new(alignment.0.x * width, alignment.0.y * height);
                                let [a, b, c, d, e, f] =
                                    ((!camera_matrix).unwrap() * Mat2d::translation(p)).0;
                                Command::Transform(a, b, c, d, e, f)
                            })
                            .unwrap_or(Command::None),
                        Command::Transform(a, b, c, d, e, f),
                        effect
                            .as_ref()
                            .map(|effect| unsafe { Command::Effect(effect.read().0) })
                            .unwrap_or(Command::None),
                        alpha
                            .as_ref()
                            .map(|alpha| unsafe { Command::Alpha(alpha.read().0) })
                            .unwrap_or(Command::None),
                        stroke
                            .as_ref()
                            .map(|stroke| unsafe {
                                Command::Stroke(stroke.read().0, renderable.read().0.clone())
                            })
                            .unwrap_or_else(|| unsafe {
                                Command::Draw(renderable.read().0.clone())
                            }),
                        Command::Restore,
                    ]
                },
            ))
            .chain(std::iter::once(Command::Restore));

        if let Ok((render_ops, renderables)) = renderer.execute(commands) {
            stats.render_ops += render_ops;
            stats.renderables += renderables;
        }
    }
    stats.delta_time = lifecycle.delta_time_seconds();
    stats.fps = if stats.delta_time > 0.0 {
        1.0 / stats.delta_time
    } else {
        0.0
    };
    renderer.state_mut().set_stats(stats);
}