Skip to main content

complex_text/
common.rs

1use glfw::*;
2use glow::HasContext;
3use impellers::*;
4
5#[allow(unused)]
6pub struct SdlGlImpellerFrameWork {
7    pub ttx: TypographyContext,
8    pub style: ParagraphStyle,
9    pub itx: impellers::Context,
10    pub glow_ctx: glow::Context,
11    pub receiver: GlfwReceiver<(f64, WindowEvent)>,
12    pub window: PWindow,
13    pub gtx: Glfw,
14    pub events: Vec<WindowEvent>,
15}
16impl Default for SdlGlImpellerFrameWork {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21#[allow(unused)]
22pub const DOG_BYTES: &[u8] = include_bytes!("dog.jpg");
23
24type UserCallback = Box<dyn FnMut(&mut SdlGlImpellerFrameWork) -> Option<DisplayList>>;
25impl SdlGlImpellerFrameWork {
26    pub fn new() -> Self {
27        // initialize window
28        let mut gtx = init(fail_on_errors).expect("failed to init glfw");
29        gtx.window_hint(WindowHint::ContextVersionMajor(4));
30        gtx.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
31        gtx.window_hint(WindowHint::SRgbCapable(true));
32        gtx.window_hint(WindowHint::StencilBits(Some(8)));
33        gtx.window_hint(WindowHint::ScaleToMonitor(true));
34
35        let (mut window, ev_receiver) = gtx
36            .create_window(800, 600, "glfw opengl impeller", WindowMode::Windowed)
37            .unwrap();
38        window.make_current();
39        window.set_all_polling(true);
40
41        // initialize impeller context using opengl fn pointers
42        let itx = unsafe { impellers::Context::new_opengl_es(|s| window.get_proc_address(s) as _) }
43            .unwrap();
44        let glow_ctx =
45            unsafe { glow::Context::from_loader_function(|s| window.get_proc_address(s) as _) };
46        unsafe {
47            let (width, height) = window.get_framebuffer_size();
48            glow_ctx.viewport(0, 0, width, height);
49        }
50        let ttx = TypographyContext::default();
51        let mut style = ParagraphStyle::default();
52        style.set_font_size(24.0);
53        style.set_font_family("Roboto");
54        style.set_font_weight(FontWeight::Bold);
55        let mut paint = Paint::default();
56        paint.set_color(Color::LIGHT_SKY_BLUE);
57        style.set_foreground(&paint);
58        Self {
59            ttx,
60            style,
61            glow_ctx,
62            itx,
63            window,
64            receiver: ev_receiver,
65            gtx,
66            events: vec![],
67        }
68    }
69    /// Enters event loop and continues until window is closed or escape is pressed
70    /// # Arguments
71    /// - dl: If specified, this display list will be drawn on each frame
72    /// - user_callback: If specified, this callback will be called on each frame
73    ///   - If it returns a DisplayList, we will draw that on surface after callback.
74    ///   - The callback has access to everything, so it can draw to surface on its own if it needs to.
75    pub fn enter_event_loop(
76        mut self,
77        dl: Option<DisplayList>,
78        mut user_callback: Option<UserCallback>,
79    ) {
80        let mut previous_instant = std::time::Instant::now();
81        let mut current_frame = 0;
82        let mut fps = 0;
83        let mut vsync = true;
84        // enter event loop
85        while !self.window.should_close() {
86            {
87                // record fps
88                if previous_instant.elapsed().as_secs_f64() >= 1.0 {
89                    fps = current_frame;
90                    current_frame = 0;
91                    previous_instant = std::time::Instant::now();
92                }
93                current_frame += 1;
94            }
95            self.events.clear();
96            // check events
97            self.gtx.poll_events();
98            for (_, event) in flush_messages(&self.receiver) {
99                match &event {
100                    WindowEvent::Close => {
101                        self.window.set_should_close(true);
102                    }
103                    WindowEvent::FramebufferSize(w, h) => {
104                        unsafe {
105                            self.glow_ctx.viewport(0, 0, *w, *h);
106                        }
107                        println!("window resized to {}x{}", w, h);
108                    }
109                    WindowEvent::Key(Key::Space, _, Action::Release, _) => {
110                        vsync = !vsync;
111                        println!("setting vsync to {vsync}");
112
113                        self.gtx.set_swap_interval(if vsync {
114                            SwapInterval::Sync(1)
115                        } else {
116                            SwapInterval::None
117                        });
118                    }
119                    _ => {}
120                }
121                self.events.push(event);
122            }
123
124            let (width, height) = self.window.get_framebuffer_size();
125            // init surface by wrapping default framebuffer (fbo = 0)
126            let mut surface = unsafe {
127                self.itx.wrap_fbo(
128                    0,
129                    PixelFormat::RGBA8888,
130                    ISize::new(width.into(), height.into()),
131                )
132            }
133            .expect("failed to wrap window's framebuffer");
134            let mut dl_builder = DisplayListBuilder::new(Some(&Rect::from_size(
135                [width as f32, height as f32].into(),
136            )));
137
138            if let Some(dl) = dl.as_ref() {
139                dl_builder.draw_display_list(dl, 1.0);
140            }
141            // call user callback
142            if let Some(cb) = user_callback.as_mut() {
143                if let Some(display_list) = cb(&mut self) {
144                    dl_builder.draw_display_list(&display_list, 1.0);
145                }
146            }
147            {
148                let mut para_builder = ParagraphBuilder::new(&self.ttx).unwrap();
149                para_builder.push_style(&self.style);
150                para_builder.add_text(&format!("avg fps: {fps}"));
151                let para = para_builder.build(1000.0).unwrap();
152                dl_builder.draw_paragraph(&para, Point::origin());
153            }
154            surface
155                .draw_display_list(&dl_builder.build().unwrap())
156                .unwrap();
157
158            // submit frame and wait for vsync
159            self.window.swap_buffers();
160        }
161    }
162
163    // drop the window/sdl or whatever
164}
165
166#[allow(unused)]
167pub fn main() {
168    unimplemented!("this is a common module for other examples to use")
169}