macroquad_ply/window.rs
1//! Window and associated to window rendering context related functions.
2
3use crate::{get_context, get_quad_context};
4
5use crate::color::Color;
6
7// miniquad is re-exported for the use in combination with `get_internal_gl`
8pub use miniquad;
9
10pub use miniquad::conf::Conf;
11
12/// Block execution until the next frame.
13#[must_use = "use `next_frame().await` to advance to the next frame"]
14pub fn next_frame() -> crate::exec::FrameFuture {
15 crate::thread_assert::same_thread();
16 crate::exec::FrameFuture::default()
17}
18
19/// Fill window background with solid color.
20/// Note: even when "clear_background" is not called explicitly,
21/// the screen will be cleared at the beginning of the frame.
22pub fn clear_background(color: Color) {
23 let context = get_context();
24
25 context.gl.clear(get_quad_context(), color);
26}
27
28#[doc(hidden)]
29pub fn gl_set_drawcall_buffer_capacity(max_vertices: usize, max_indices: usize) {
30 let context = get_context();
31 context
32 .gl
33 .update_drawcall_capacity(get_quad_context(), max_vertices, max_indices);
34}
35
36pub struct InternalGlContext<'a> {
37 pub quad_context: &'a mut dyn miniquad::RenderingBackend,
38 pub quad_gl: &'a mut crate::quad_gl::QuadGl,
39}
40
41impl<'a> InternalGlContext<'a> {
42 /// Draw all the batched stuff and reset the internal state cache.
43 /// May be helpful for combining macroquad's drawing with raw miniquad/opengl calls.
44 pub fn flush(&mut self) {
45 get_context().perform_render_passes();
46 }
47}
48
49pub unsafe fn get_internal_gl<'a>() -> InternalGlContext<'a> {
50 let context = get_context();
51
52 InternalGlContext {
53 quad_context: get_quad_context(),
54 quad_gl: &mut context.gl,
55 }
56}
57
58pub fn screen_width() -> f32 {
59 let context = get_context();
60 context.screen_width / miniquad::window::dpi_scale()
61}
62
63pub fn screen_height() -> f32 {
64 let context = get_context();
65
66 context.screen_height / miniquad::window::dpi_scale()
67}
68
69pub fn screen_dpi_scale() -> f32 {
70 miniquad::window::dpi_scale()
71}
72
73/// Request the window size to be the given value. This takes DPI into account.
74///
75/// Note that the OS might decide to give a different size. Additionally, the size in macroquad won't be updated until the next `next_frame().await`.
76pub fn request_new_screen_size(width: f32, height: f32) {
77 miniquad::window::set_window_size(
78 (width * miniquad::window::dpi_scale()) as u32,
79 (height * miniquad::window::dpi_scale()) as u32,
80 );
81 // We do not set the context.screen_width and context.screen_height here.
82 // After `set_window_size` is called, EventHandlerFree::resize will be invoked, setting the size correctly.
83 // Because the OS might decide to give a different screen dimension, setting the context.screen_* here would be confusing.
84}
85
86/// Toggle whether the window is fullscreen.
87pub fn set_fullscreen(fullscreen: bool) {
88 miniquad::window::set_fullscreen(fullscreen);
89}
90
91/// With `set_panic_handler` set to a handler code, macroquad will use
92/// `std::panic::catch_unwind` on user code to catch some panics.
93///
94/// Sometimes it is nice to let player send a bug report with a screenshot of an
95/// error. It is way easier to ask for a screenshot than ask to connect to a phone
96/// with adb and post a log.
97///
98/// For this very case "set_panic_handler" exists.
99/// ```ignore
100/// set_panic_handler(|msg, backtrace| async move {
101/// loop {
102/// clear_background(RED);
103/// ui::root_ui().label(None, &msg);
104/// for line in backtrace.split('\n') {
105/// root_ui().label(None, line);
106/// }
107/// next_frame().await;
108/// }
109/// });
110/// ```
111///
112/// `set_panic_handler` acts as a second app entry-point, that will be used
113/// after a panic in user code will happen. Macroquad will also try to catch some OS
114/// panics, but not all of them - some compatibility bugs may end up crashing the app.
115///
116/// Without `set_panic_handler` macroquad will not use `catch_unwind` at all,
117/// therefore `panic_handler` is completely optional.
118/// NOTE: only with "backtrace" macroquad feature `backtrace` string will contain an
119/// actual backtrace. Otherwise only panic location and message will be available.
120/// NOTE: on android, even with "backtrace" nice backtrace is available only if the game is compiled with sdk >= 21.
121/// To use sdk >= 21 add "min_sdk_version = 21" to Cargo.toml
122pub fn set_panic_handler<T, F>(future: F)
123where
124 T: std::future::Future<Output = ()> + 'static,
125 F: Fn(String, String) -> T + Send + Sync + 'static,
126{
127 std::panic::set_hook(Box::new(move |info| {
128 let message = format!("{info:?}");
129 #[cfg(feature = "backtrace")]
130 let backtrace_string = format!("{:?}", backtrace::Backtrace::new());
131 #[cfg(not(feature = "backtrace"))]
132 let backtrace_string = format!("Macroquad compiled without \"backtrace\" feature");
133 crate::logging::error!("{}", message);
134 crate::logging::error!("{}", backtrace_string);
135
136 crate::get_context().recovery_future = Some(Box::pin(future(message, backtrace_string)));
137 }));
138
139 crate::get_context().unwind = true;
140}