swamp_advanced_game/
render.rs

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
/*
 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 */

use crate::logic::GameLogic;
use crate::{ApplicationLogic, ApplicationRender};
use limnus_app::prelude::{App, Plugin};
use limnus_local_resource::prelude::LocalResource;
use limnus_resource::ResourceStorage;
use limnus_system_params::{LoRe, LoReM, Re, ReM};
use limnus_system_runner::UpdatePhase;
use limnus_wgpu_window::WgpuWindow;
use monotonic_time_rs::{InstantMonotonicClock, Millis, MonotonicClock};
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use swamp_font::Font;
use swamp_game_assets::GameAssets;
use swamp_render_wgpu::{Material, Render};
use tracing::trace;

#[derive(LocalResource)]
pub struct GameRenderer<R: ApplicationRender<L>, L: ApplicationLogic> {
    renderer: R,
    clock: InstantMonotonicClock,
    _phantom: PhantomData<L>,
}

impl<R: ApplicationRender<L>, L: ApplicationLogic> Debug for GameRenderer<R, L> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "GameAudioRender")
    }
}

impl<R: ApplicationRender<L>, L: ApplicationLogic> GameRenderer<R, L> {
    #[must_use]
    pub fn new(all_resources: &mut ResourceStorage) -> Self {
        let clock = InstantMonotonicClock::new();
        let mut assets = GameAssets::new(all_resources, clock.now());
        let renderer = R::new(&mut assets);

        Self {
            renderer,
            clock,
            _phantom: PhantomData,
        }
    }

    pub fn render(
        &mut self,
        logic: &L,
        wgpu: &WgpuWindow,
        wgpu_render: &mut Render,
        materials: &limnus_assets::Assets<Material>,
        fonts: &limnus_assets::Assets<Font>,
        now: Millis,
    ) {
        wgpu_render.set_now(now);
        self.renderer.render(wgpu_render, logic);

        wgpu.render(wgpu_render.clear_color(), |render_pass| {
            wgpu_render.render(render_pass, materials, fonts, now)
        })
        .unwrap();
    }
}

pub fn advanced_game_render_tick<R: ApplicationRender<L>, L: ApplicationLogic>(
    mut game_render: LoReM<GameRenderer<R, L>>,
    logic: LoRe<GameLogic<L>>,
    materials: Re<limnus_assets::Assets<Material>>,
    fonts: Re<limnus_assets::Assets<Font>>,
    window: Re<WgpuWindow>,
    mut wgpu_render: ReM<Render>,
) {
    let now = game_render.clock.now();
    game_render.render(
        &logic.logic,
        &window,
        &mut wgpu_render,
        &materials,
        &fonts,
        now,
    );
}

#[derive(Default)]
pub struct GameRendererPlugin<R: ApplicationRender<L>, L: ApplicationLogic> {
    _phantom: PhantomData<(R, L)>,
}

impl<A: ApplicationRender<L>, L: ApplicationLogic> GameRendererPlugin<A, L> {
    pub fn new() -> Self {
        Self {
            _phantom: PhantomData,
        }
    }
}

impl<R: ApplicationRender<L>, L: ApplicationLogic> Plugin for GameRendererPlugin<R, L> {
    fn post_initialization(&self, app: &mut App) {
        trace!("GameRendererPlugin startup");
        let all_resources = app.resources_mut();

        let game_renderer = GameRenderer::<R, L>::new(all_resources);
        app.insert_local_resource(game_renderer);

        app.add_system(UpdatePhase::Update, advanced_game_render_tick::<R, L>);
    }
}