cranpose_render_pixels/
lib.rs1#![doc = include_str!("../README.md")]
2
3mod draw;
4mod pipeline;
5pub mod scene;
6pub mod sprites;
7pub mod style;
8
9use cranpose_render_common::{
10 RenderScene, Renderer, SceneUpdates,
11 text_measure::{CachedFontTextMeasurer, SoftwareTextResources},
12};
13use cranpose_ui::LayoutTree;
14use cranpose_ui_graphics::Size;
15pub use draw::draw_scene;
16pub use scene::{HitRegion, Scene};
17
18#[derive(Debug)]
19pub enum PixelsRendererError {
20 Layout(String),
21}
22
23pub struct PixelsRenderer {
24 scene: Scene,
25 text_resources: SoftwareTextResources,
26}
27
28impl Default for PixelsRenderer {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34impl PixelsRenderer {
35 pub fn new() -> Self {
36 Self {
37 scene: Scene::new(),
38 text_resources: SoftwareTextResources::default(),
39 }
40 }
41
42 pub fn draw(&self, frame: &mut [u8], width: u32, height: u32) {
43 draw::draw_scene_with_text_resources(
44 frame,
45 width,
46 height,
47 &self.scene,
48 &self.text_resources,
49 );
50 }
51
52 pub fn draw_scaled(&self, frame: &mut [u8], width: u32, height: u32, scale: f32) {
55 let scale = if scale.is_finite() && scale > 0.0 {
56 scale
57 } else {
58 1.0
59 };
60 draw::draw_scene_scaled(
61 frame,
62 width,
63 height,
64 &self.scene,
65 &self.text_resources,
66 scale,
67 );
68 }
69}
70
71impl PixelsRenderer {
72 pub fn compose_sprites(
76 &self,
77 frame: &mut sprites::SpriteFrame,
78 width: u32,
79 height: u32,
80 scale: f32,
81 ) {
82 let scale = if scale.is_finite() && scale > 0.0 {
83 scale
84 } else {
85 1.0
86 };
87 let scene = match self.scene.graph.as_ref() {
88 Some(graph) => pipeline::build_raster_scene(graph, self.scene.diagnostics(), scale),
89 None => scene::RasterScene::new(),
90 };
91 frame.compose(
92 &scene,
93 width,
94 height,
95 self.scene.diagnostics(),
96 &self.text_resources,
97 );
98 }
99}
100
101impl Renderer for PixelsRenderer {
102 type Scene = Scene;
103 type Error = PixelsRendererError;
104
105 fn attach_app_context_services(&mut self, app_context: &cranpose_ui::AppContext) {
106 app_context.set_text_measurer(CachedFontTextMeasurer::with_text_resources(
107 self.text_resources.clone(),
108 64,
109 ));
110 }
111
112 fn scene(&self) -> &Self::Scene {
113 &self.scene
114 }
115
116 fn scene_mut(&mut self) -> &mut Self::Scene {
117 &mut self.scene
118 }
119
120 fn rebuild_scene(
121 &mut self,
122 layout_tree: &LayoutTree,
123 _viewport: Size,
124 ) -> Result<(), Self::Error> {
125 self.scene.clear();
126 pipeline::render_layout_tree(layout_tree.root(), &mut self.scene);
127 Ok(())
128 }
129
130 fn rebuild_scene_from_applier(
131 &mut self,
132 applier: &mut cranpose_core::MemoryApplier,
133 root: cranpose_core::NodeId,
134 _viewport: Size,
135 ) -> Result<(), Self::Error> {
136 self.scene.rebuild_from_applier(applier, root);
137 Ok(())
138 }
139
140 fn update_scene_from_applier(
141 &mut self,
142 applier: &mut cranpose_core::MemoryApplier,
143 root: cranpose_core::NodeId,
144 _viewport: Size,
145 updates: SceneUpdates<'_>,
146 ) -> Result<(), Self::Error> {
147 self.scene.update_from_applier(applier, root, updates, true);
148 Ok(())
149 }
150
151 fn update_visual_scene_from_applier(
152 &mut self,
153 applier: &mut cranpose_core::MemoryApplier,
154 root: cranpose_core::NodeId,
155 _viewport: Size,
156 updates: SceneUpdates<'_>,
157 ) -> Result<(), Self::Error> {
158 self.scene
159 .update_from_applier(applier, root, updates, false);
160 Ok(())
161 }
162}