1use crate::{interactions::GuiInteractionsEngine, renderer::GuiRenderer};
2#[cfg(target_arch = "wasm32")]
3use instant::Instant;
4use raui_core::{
5 application::Application,
6 layout::{CoordsMapping, CoordsMappingScaling, default_layout_engine::DefaultLayoutEngine},
7 make_widget,
8 widget::{
9 component::containers::content_box::content_box,
10 utils::{Color, Rect},
11 },
12};
13use raui_immediate::*;
14use spitfire_draw::{
15 context::DrawContext,
16 utils::{ShaderRef, Vertex},
17};
18use spitfire_fontdue::*;
19use spitfire_glow::{
20 graphics::{Graphics, Texture},
21 renderer::{GlowTextureFiltering, GlowTextureFormat},
22};
23#[cfg(not(target_arch = "wasm32"))]
24use std::time::Instant;
25
26pub struct GuiContext {
27 pub coords_map_scaling: CoordsMappingScaling,
28 pub texture_filtering: GlowTextureFiltering,
29 pub interactions: GuiInteractionsEngine,
30 application: Application,
31 text_renderer: TextRenderer<Color>,
32 immediate: ImmediateContext,
33 timer: Instant,
34 glyphs_texture: Option<Texture>,
35}
36
37impl Default for GuiContext {
38 fn default() -> Self {
39 Self {
40 coords_map_scaling: Default::default(),
41 texture_filtering: Default::default(),
42 interactions: Default::default(),
43 application: Default::default(),
44 text_renderer: Default::default(),
45 immediate: Default::default(),
46 timer: Instant::now(),
47 glyphs_texture: None,
48 }
49 }
50}
51
52impl GuiContext {
53 pub fn mark_dirty(&mut self) {
54 self.application.mark_dirty();
55 }
56
57 pub fn begin_frame(&self) {
58 ImmediateContext::activate(&self.immediate);
59 begin();
60 }
61
62 pub fn end_frame(
63 &mut self,
64 draw: &mut DrawContext,
65 graphics: &mut Graphics<Vertex>,
66 colored_shader: &ShaderRef,
67 textured_shader: &ShaderRef,
68 text_shader: &ShaderRef,
69 ) {
70 let widgets = end();
71 ImmediateContext::deactivate();
72 self.application
73 .apply(make_widget!(content_box).key("root").listed_slots(widgets));
74 let elapsed = std::mem::replace(&mut self.timer, Instant::now())
75 .elapsed()
76 .as_secs_f32();
77 self.timer = Instant::now();
78 self.application.animations_delta_time = elapsed;
79 let coords_mapping = CoordsMapping::new_scaling(
80 Rect {
81 left: 0.0,
82 right: graphics.state.main_camera.screen_size.x,
83 top: 0.0,
84 bottom: graphics.state.main_camera.screen_size.y,
85 },
86 self.coords_map_scaling,
87 );
88 if self.application.process() {
89 let mut layout_engine = DefaultLayoutEngine::<()>::default();
90 let _ = self.application.layout(&coords_mapping, &mut layout_engine);
91 }
92 self.interactions.maintain(&coords_mapping);
93 let _ = self.application.interact(&mut self.interactions);
94 self.application.consume_signals();
95 let mut renderer = GuiRenderer {
96 texture_filtering: self.texture_filtering,
97 draw,
98 graphics,
99 colored_shader,
100 textured_shader,
101 text_shader,
102 };
103 let _ = self.application.render(&coords_mapping, &mut renderer);
104 let [w, h, d] = self.text_renderer.atlas_size();
105 if let Some(texture) = self.glyphs_texture.as_mut() {
106 texture.upload(
107 w as _,
108 h as _,
109 d as _,
110 GlowTextureFormat::Monochromatic,
111 Some(self.text_renderer.image()),
112 );
113 } else {
114 self.glyphs_texture = graphics
115 .texture(
116 w as _,
117 h as _,
118 d as _,
119 GlowTextureFormat::Monochromatic,
120 Some(self.text_renderer.image()),
121 )
122 .ok();
123 }
124 }
125}