Skip to main content

cotis_modules_debug/
render_module_debugger.rs

1//! Renderer replay wrapper for re-drawing saved render command streams.
2//!
3//! Use [`RenderModuleReplay`] when you have precomputed render commands **and** need the
4//! renderer's `init` hook to run against a live layout manager (for example, to load fonts
5//! or textures registered during layout init).
6//!
7//! For stage 3 when layout output JSON plus a pipe is sufficient and no renderer init from
8//! a layout module is needed, prefer calling [`CotisRenderer::draw_frame`]
9//! directly (see `gradients_example_solid_render_only`).
10
11use cotis::renders::{CotisRenderer, CotisRendererAsync, RenderCompatibleWith};
12
13/// Thin wrapper around a renderer for debug replay.
14pub struct RenderModuleReplay<Renderer> {
15    internal: Renderer,
16}
17
18impl<Renderer> RenderModuleReplay<Renderer> {
19    /// Creates a replay wrapper around an existing renderer.
20    pub fn new(renderer: Renderer) -> Self {
21        Self { internal: renderer }
22    }
23}
24
25/// Synchronous renderer replay: `init(layout)` followed by `draw_frame(commands)`.
26pub trait RenderModuleReplayTrait<'frame, ConfigType, RenderCommandType, LayoutModule> {
27    /// Initializes the renderer against `layout`, then draws `render_commands`.
28    fn replay(
29        &mut self,
30        render_commands: impl Iterator<Item = RenderCommandType>,
31        layout: &mut LayoutModule,
32    );
33}
34
35impl<'frame, ConfigType, RenderCommandType, LayoutModule, Renderer>
36    RenderModuleReplayTrait<'frame, ConfigType, RenderCommandType, LayoutModule>
37    for RenderModuleReplay<Renderer>
38where
39    Renderer: RenderCompatibleWith<LayoutModule> + CotisRenderer<RenderCommandType>,
40{
41    fn replay(
42        &mut self,
43        render_commands: impl Iterator<Item = RenderCommandType>,
44        layout: &mut LayoutModule,
45    ) {
46        self.internal.init(layout);
47        self.internal.draw_frame(render_commands);
48    }
49}
50
51/// Async renderer replay: `init(layout)` followed by `draw_frame(commands).await`.
52#[allow(async_fn_in_trait)]
53pub trait RenderModuleReplayAsyncTrait<'frame, ConfigType, RenderCommandType, LayoutModule> {
54    /// Initializes the renderer against `layout`, then draws `render_commands` asynchronously.
55    async fn replay(
56        &mut self,
57        render_commands: impl Iterator<Item = RenderCommandType>,
58        layout: &mut LayoutModule,
59    );
60}
61
62impl<'frame, ConfigType, RenderCommandType, LayoutModule, Renderer>
63    RenderModuleReplayAsyncTrait<'frame, ConfigType, RenderCommandType, LayoutModule>
64    for RenderModuleReplay<Renderer>
65where
66    Renderer: RenderCompatibleWith<LayoutModule> + CotisRendererAsync<RenderCommandType>,
67{
68    async fn replay(
69        &mut self,
70        render_commands: impl Iterator<Item = RenderCommandType>,
71        layout: &mut LayoutModule,
72    ) {
73        self.internal.init(layout);
74        self.internal.draw_frame(render_commands).await;
75    }
76}