Skip to main content

cranpose_render_pixels/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod draw;
4mod pipeline;
5pub mod scene;
6pub mod style;
7
8use cranpose_render_common::{
9    RenderScene, Renderer, SceneUpdates,
10    text_measure::{CachedFontTextMeasurer, SoftwareTextResources},
11};
12use cranpose_ui::LayoutTree;
13use cranpose_ui_graphics::Size;
14pub use draw::draw_scene;
15pub use scene::{HitRegion, Scene};
16
17#[derive(Debug)]
18pub enum PixelsRendererError {
19    Layout(String),
20}
21
22pub struct PixelsRenderer {
23    scene: Scene,
24    text_resources: SoftwareTextResources,
25}
26
27impl Default for PixelsRenderer {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl PixelsRenderer {
34    pub fn new() -> Self {
35        Self {
36            scene: Scene::new(),
37            text_resources: SoftwareTextResources::default(),
38        }
39    }
40
41    pub fn draw(&self, frame: &mut [u8], width: u32, height: u32) {
42        draw::draw_scene_with_text_resources(
43            frame,
44            width,
45            height,
46            &self.scene,
47            &self.text_resources,
48        );
49    }
50
51    /// Rasterizes logical scene coordinates at `scale` device pixels per point.
52    /// Hit regions stay in logical coordinates. Invalid scales use 1.0.
53    pub fn draw_scaled(&self, frame: &mut [u8], width: u32, height: u32, scale: f32) {
54        let scale = if scale.is_finite() && scale > 0.0 {
55            scale
56        } else {
57            1.0
58        };
59        draw::draw_scene_scaled(
60            frame,
61            width,
62            height,
63            &self.scene,
64            &self.text_resources,
65            scale,
66        );
67    }
68}
69
70impl Renderer for PixelsRenderer {
71    type Scene = Scene;
72    type Error = PixelsRendererError;
73
74    fn attach_app_context_services(&mut self, app_context: &cranpose_ui::AppContext) {
75        app_context.set_text_measurer(CachedFontTextMeasurer::with_text_resources(
76            self.text_resources.clone(),
77            64,
78        ));
79    }
80
81    fn scene(&self) -> &Self::Scene {
82        &self.scene
83    }
84
85    fn scene_mut(&mut self) -> &mut Self::Scene {
86        &mut self.scene
87    }
88
89    fn rebuild_scene(
90        &mut self,
91        layout_tree: &LayoutTree,
92        _viewport: Size,
93    ) -> Result<(), Self::Error> {
94        self.scene.clear();
95        pipeline::render_layout_tree(layout_tree.root(), &mut self.scene);
96        Ok(())
97    }
98
99    fn rebuild_scene_from_applier(
100        &mut self,
101        applier: &mut cranpose_core::MemoryApplier,
102        root: cranpose_core::NodeId,
103        _viewport: Size,
104    ) -> Result<(), Self::Error> {
105        self.scene.rebuild_from_applier(applier, root);
106        Ok(())
107    }
108
109    fn update_scene_from_applier(
110        &mut self,
111        applier: &mut cranpose_core::MemoryApplier,
112        root: cranpose_core::NodeId,
113        _viewport: Size,
114        updates: SceneUpdates<'_>,
115    ) -> Result<(), Self::Error> {
116        self.scene.update_from_applier(applier, root, updates, true);
117        Ok(())
118    }
119
120    fn update_visual_scene_from_applier(
121        &mut self,
122        applier: &mut cranpose_core::MemoryApplier,
123        root: cranpose_core::NodeId,
124        _viewport: Size,
125        updates: SceneUpdates<'_>,
126    ) -> Result<(), Self::Error> {
127        self.scene
128            .update_from_applier(applier, root, updates, false);
129        Ok(())
130    }
131}