miniquad/
conf.rs

1//! Context creation configuration
2//!
3//! A [`Conf`] struct is used to describe a hardware and platform specific setup,
4//! mostly video display settings.
5//!
6//! ## High DPI rendering
7//!
8//! You can set the [`Conf::high_dpi`] flag during initialization to request
9//! a full-resolution framebuffer on HighDPI displays. The default behaviour
10//! is `high_dpi = false`, this means that the application will
11//! render to a lower-resolution framebuffer on HighDPI displays and the
12//! rendered content will be upscaled by the window system composer.
13//! In a HighDPI scenario, you still request the same window size during
14//! [`miniquad::start`][super::start], but the framebuffer sizes returned by
15//! [`screen_size`] will be scaled up according to the DPI scaling ratio.
16//! You can also get a DPI scaling factor with the function [`dpi_scale`].
17//!
18//! Here's an example on a Mac with Retina display:
19//! ```ignore
20//! Conf {
21//!   width = 640,
22//!   height = 480,
23//!   high_dpi = true,
24//!   .. Default::default()
25//! };
26//! ```
27//!
28//! The functions [`screen_size`] and [`dpi_scale`] will return the following values:
29//! ```bash
30//! screen_size -> (1280, 960)
31//! dpi_scale   -> 2.0
32//! ```
33//!
34//! If the `high_dpi` flag is false, or you're not running on a Retina display,
35//! the values would be:
36//! ```bash
37//! screen_size -> (640, 480)
38//! dpi_scale   -> 1.0
39//! ```
40//!
41//! [`dpi_scale`]: super::window::dpi_scale
42//! [`screen_size`]: super::window::screen_size
43
44/// Specifies how to load an OpenGL context on X11 in Linux.
45#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
46pub enum LinuxX11Gl {
47    /// Use `libGLX.so` (or `libGLX.so.0`) exclusively. Panics if unavailable.
48    GLXOnly,
49    /// Use `libEGL.so` (or `libEGL.so.0`) exclusively. Panics if unavailable.
50    EGLOnly,
51    /// Prefer `libGLX`; fall back to `libEGL` if `libGLX` is unavailable.
52    /// This is the default choice.
53    #[default]
54    GLXWithEGLFallback,
55    /// Prefer `libEGL`; fall back to `libGLX` if `libEGL` is unavailable.
56    EGLWithGLXFallback,
57}
58
59/// On Linux, the backend used for windowing and event handling.
60///
61/// Defaults to `X11Only`. The Wayland implementation is currently unstable
62#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
63pub enum LinuxBackend {
64    /// Use only the X11 backend. Panics if unavailable. This is the default choice.
65    #[default]
66    X11Only,
67    /// Use only the Wayland backend. Panics if unavailable.
68    WaylandOnly,
69    /// Prefer X11, fall back to Wayland if X11 is unavailable.
70    X11WithWaylandFallback,
71    /// Prefer Wayland, fall back to X11 if Wayland is unavailable.
72    WaylandWithX11Fallback,
73}
74
75/// On Apple platforms, choose the rendering API for creating contexts.
76///
77/// Miniquad always links to Metal.framework (assuming it's present),
78/// and links to OpenGL dynamically only if required.
79///
80/// Defaults to AppleGfxApi::GL for legacy reasons.
81#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
82pub enum AppleGfxApi {
83    /// Use OpenGL for Apple platforms. This is the default choice.
84    #[default]
85    OpenGl,
86    /// Use Metal for Apple platforms.
87    Metal,
88}
89
90/// On the Web, specify which WebGL version to use.
91///
92/// While miniquad itself only uses WebGL 1 features, a WebGL 2 context allows to:
93/// - Use GLES3 shaders.
94/// - Do raw WebGL2 OpenGL calls.
95#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
96pub enum WebGLVersion {
97    /// Use WebGL 1.0. This is the default choice.
98    #[default]
99    WebGL1,
100    /// Use WebGL 2.0.
101    WebGL2,
102}
103
104/// On Wayland, specify how to draw client-side decoration (CSD) if server-side decoration (SSD) is
105/// not supported (e.g., on GNOME).
106///
107/// Defaults to ServerWithLibDecorFallback
108#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
109pub enum WaylandDecorations {
110    /// If SSD is not supported, will try to load `libdecor` to draw CSD. This is the default
111    /// choice.
112    #[default]
113    ServerWithLibDecorFallback,
114    /// If SSD is not supported, draw a light gray border.
115    ServerWithMiniquadFallback,
116    /// If SSD is not supported, no CSD will be drawn.
117    ServerOnly,
118}
119
120/// Platform-specific settings.
121#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
122pub struct Platform {
123    /// Determines how to load an OpenGL context on X11 (via GLX or EGL).
124    pub linux_x11_gl: LinuxX11Gl,
125
126    /// Specifies which Linux window system (X11 or Wayland) is preferred or used.
127    pub linux_backend: LinuxBackend,
128
129    /// Specifies which WebGL version to use on the Web (1.0. or 2.0).
130    pub webgl_version: WebGLVersion,
131
132    /// Defines which rendering API to use on Apple platforms (Metal or OpenGL).
133    pub apple_gfx_api: AppleGfxApi,
134
135    /// Optional swap interval (vertical sync).
136    ///
137    /// Note that this is highly platform- and driver-dependent.
138    /// There is no guarantee the FPS will match the specified `swap_interval`.
139    /// In other words, `swap_interval` is only a hint to the GPU driver and
140    /// not a reliable way to limit the game's FPS.
141    pub swap_interval: Option<i32>,
142
143    /// If `true`, the event loop will block until [`schedule_update`] is called.
144    ///
145    /// This can reduce CPU usage to nearly zero while waiting for events.
146    ///
147    /// It is recommended to call `schedule_update` at the end of `resize_event`
148    /// or any relevant mouse/keyboard input.
149    ///
150    /// `schedule_update` may be used from other threads to "wake up" the window.
151    ///
152    /// [`schedule_update`]: super::window::schedule_update
153    pub blocking_event_loop: bool,
154
155    /// If `true`, the framebuffer includes an alpha channel.
156    /// Currently supported only on Android.
157    ///
158    /// - TODO: Make it works on web, on web it should make a transparent HTML5 canvas
159    /// - TODO: Document(and check) what does it actually mean on android. Transparent window?
160    pub framebuffer_alpha: bool,
161
162    /// On Wayland, specifies how to draw client-side decoration (CSD) if server-side decoration (SSD) is
163    /// not supported (e.g., on GNOME).
164    pub wayland_decorations: WaylandDecorations,
165
166    /// Set the `WM_CLASS` window property on X11 and the `app_id` on Wayland. This is used
167    /// by gnome to determine the window icon (together with an external `.desktop` file).
168    // in fact `WM_CLASS` contains two strings "instance name" and "class name"
169    // for most purposes they are the same so we just use class name for simplicity
170    // https://unix.stackexchange.com/questions/494169/
171    pub linux_wm_class: &'static str,
172}
173
174impl Default for Platform {
175    fn default() -> Platform {
176        Platform {
177            linux_x11_gl: LinuxX11Gl::default(),
178            linux_backend: LinuxBackend::default(),
179            apple_gfx_api: AppleGfxApi::default(),
180            webgl_version: WebGLVersion::default(),
181            blocking_event_loop: false,
182            swap_interval: None,
183            framebuffer_alpha: false,
184            wayland_decorations: WaylandDecorations::default(),
185            linux_wm_class: "miniquad-application",
186        }
187    }
188}
189
190/// Describes a hardware and platform-specific setup.
191#[derive(Debug)]
192pub struct Conf {
193    /// Window title. Defaults to an empty string.
194    pub window_title: String,
195
196    /// Preferred window width (ignored on WASM/Android).
197    /// Defaults to `800`.
198    pub window_width: i32,
199
200    /// Preferred window height (ignored on WASM/Android).
201    /// Defaults to `600`.
202    pub window_height: i32,
203
204    /// If `true`, the rendering canvas is scaled for HighDPI displays.
205    /// Defaults to `false`.
206    pub high_dpi: bool,
207
208    /// If `true`, create the window in fullscreen mode (ignored on WASM/Android).
209    /// Defaults to `false`.
210    pub fullscreen: bool,
211
212    /// MSAA sample count.
213    /// Defaults to `1`.
214    pub sample_count: i32,
215
216    /// If `true`, the user can resize the window.
217    pub window_resizable: bool,
218
219    /// Optional icon data used by the OS where applicable:
220    /// - On Windows, taskbar/title bar icon
221    /// - On macOS, Dock/title bar icon
222    /// - TODO: Favicon on HTML5
223    /// - TODO: Taskbar/title bar icon on Linux (depends on WM)
224    /// - Note: on gnome, icon is determined using `WM_CLASS` (can be set under [`Platform`]) and
225    ///   an external `.desktop` file
226    pub icon: Option<Icon>,
227
228    /// Platform-specific hints (e.g., context creation, driver settings).
229    pub platform: Platform,
230}
231
232/// Icon image in three levels of detail.
233#[derive(Clone)]
234pub struct Icon {
235    /// 16 * 16 image of RGBA pixels (each 4 * u8) in row-major order.
236    pub small: [u8; 16 * 16 * 4],
237    /// 32 x 32 image of RGBA pixels (each 4 * u8) in row-major order.
238    pub medium: [u8; 32 * 32 * 4],
239    /// 64 x 64 image of RGBA pixels (each 4 * u8) in row-major order.
240    pub big: [u8; 64 * 64 * 4],
241}
242
243impl Icon {
244    pub fn miniquad_logo() -> Icon {
245        Icon {
246            small: crate::default_icon::SMALL,
247            medium: crate::default_icon::MEDIUM,
248            big: crate::default_icon::BIG,
249        }
250    }
251}
252// Printing 64x64 array with a default formatter is not meaningfull,
253// so debug will skip the data fields of an Icon
254impl std::fmt::Debug for Icon {
255    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256        f.debug_struct("Icon").finish()
257    }
258}
259
260// reasonable defaults for PC and mobiles are slightly different
261#[cfg(not(target_os = "android"))]
262impl Default for Conf {
263    fn default() -> Conf {
264        Conf {
265            window_title: "".to_owned(),
266            window_width: 800,
267            window_height: 600,
268            high_dpi: false,
269            fullscreen: false,
270            sample_count: 1,
271            window_resizable: true,
272            icon: Some(Icon::miniquad_logo()),
273            platform: Default::default(),
274        }
275    }
276}
277
278#[cfg(target_os = "android")]
279impl Default for Conf {
280    fn default() -> Conf {
281        Conf {
282            window_title: "".to_owned(),
283            window_width: 800,
284            window_height: 600,
285            high_dpi: true,
286            fullscreen: true, //
287            sample_count: 1,
288            window_resizable: false, //
289            icon: Some(Icon::miniquad_logo()),
290            platform: Default::default(),
291        }
292    }
293}