1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
//! Context creation configuration
//!
//! A [`Conf`](struct.Conf.html) struct is used to describe a hardware and platform specific setup,
//! mostly video display settings.
//!
//! ## High DPI rendering
//!
//! You can set the [`Conf::high_dpi`](struct.Conf.html#structfield.high_dpi) flag during initialization to request
//! a full-resolution framebuffer on HighDPI displays. The default behaviour
//! is `high_dpi = false`, this means that the application will
//! render to a lower-resolution framebuffer on HighDPI displays and the
//! rendered content will be upscaled by the window system composer.
//! In a HighDPI scenario, you still request the same window size during
//! [`miniquad::start`](../fn.start.html), but the framebuffer sizes returned by [`Context::screen_size`](../graphics/struct.Context.html#method.screen_size)
//! will be scaled up according to the DPI scaling ratio.
//! You can also get a DPI scaling factor with the function
//! [`Context::dpi_scale`](../graphics/struct.Context.html#method.dpi_scale).
//! Here's an example on a Mac with Retina display:
//! ```ignore
//! Conf {
//!   width = 640,
//!   height = 480,
//!   high_dpi = true,
//!   .. Default::default()
//! };
//! ```
//!
//! The functions [`screen_size`](../graphics/struct.Context.html#method.screen_size) and [`dpi_scale`](../graphics/struct.Context.html#method.dpi_scale) will
//! return the following values:
//! ```bash
//! screen_size -> (1280, 960)
//! dpi_scale   -> 2.0
//! ```
//!
//! If the high_dpi flag is false, or you're not running on a Retina display,
//! the values would be:
//! ```bash
//! screen_size -> (640, 480)
//! dpi_scale   -> 1.0
//! ```

#[derive(Debug)]
pub enum LinuxX11Gl {
    /// Use libGLX.so/libGLX.so.0 and its funciton for creating OpenGL context
    /// If there is no libGLX - just panic right away
    GLXOnly,
    /// Use libEGL.so/libEGL.so.0 and its funciton for creating OpenGL context
    /// If there is no libEGL - just panic right away
    EGLOnly,
    /// Use libGLX and if there is not libGLX - try libEGL.
    /// The default option.
    GLXWithEGLFallback,
    /// Use libEGL and if there is not libEGL - try libGLX.
    EGLWithGLXFallback,
}

#[derive(Debug)]
pub enum LinuxBackend {
    X11Only,
    WaylandOnly,
    X11WithWaylandFallback,
    WaylandWithX11Fallback,
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum AppleGfxApi {
    OpenGl,
    Metal,
}

/// Platform specific settings.
#[derive(Debug)]
pub struct Platform {
    /// On X11 there are two ways to get OpenGl context: libglx.so and libegl.so
    /// Default is GLXWithEGLFallback - will try to create glx context and if fails -
    /// try EGL. If EGL also fails - panic.
    pub linux_x11_gl: LinuxX11Gl,

    /// Wayland or X11. Defaults to X11WithWaylandFallback - miniquad will try
    /// to load "libX11.so", but if there is no - will try to initialize
    /// through wayland natively. If both  fails (no graphics server at
    /// all, like KMS) - will panic.
    ///
    /// Defaults to X11Only. Wayland implementation is way too unstable right now.
    pub linux_backend: LinuxBackend,

    /// Which rendering context to create, Metal or OpenGL.
    /// Miniquad always links with Metal.framework (assuming it is always present)
    /// but it links with OpenGL dynamically and only if required.
    ///
    /// Defaults to AppleGfxApi::GL for legacy reasons.
    pub apple_gfx_api: AppleGfxApi,

    /// On some platform it is possible to ask the OS for a specific swap interval.
    /// Note that this is highly platform and implementation dependent,
    /// there is no guarantee that FPS will be equal to swap_interval.
    /// In other words - "swap_interval" is a hint for a GPU driver, this is not
    /// the way to limit FPS in the game!
    pub swap_interval: Option<i32>,

    /// Whether the framebuffer should have an alpha channel.
    /// Currently supported only on Android
    /// TODO: Make it works on web, on web it should make a transparent HTML5 canvas
    /// TODO: Document(and check) what does it actually mean on android. Transparent window?
    pub framebuffer_alpha: bool,
}

impl Default for Platform {
    fn default() -> Platform {
        Platform {
            linux_x11_gl: LinuxX11Gl::GLXWithEGLFallback,
            swap_interval: None,
            linux_backend: LinuxBackend::X11Only,
            apple_gfx_api: AppleGfxApi::OpenGl,
            framebuffer_alpha: false,
        }
    }
}

#[derive(Debug)]
pub struct Conf {
    /// Title of the window, defaults to an empty string.
    pub window_title: String,
    /// The preferred width of the window, ignored on wasm/android.
    ///
    /// Default: 800
    pub window_width: i32,
    /// The preferred height of the window, ignored on wasm/android.
    ///
    /// Default: 600
    pub window_height: i32,
    /// Whether the rendering canvas is full-resolution on HighDPI displays.
    ///
    /// Default: false
    pub high_dpi: bool,
    /// Whether the window should be created in fullscreen mode, ignored on wasm/android.
    ///
    /// Default: false
    pub fullscreen: bool,
    /// MSAA sample count
    ///
    /// Default: 1
    pub sample_count: i32,

    /// Determines if the application user can resize the window
    pub window_resizable: bool,

    /// Miniquad allows to change the window icon programmatically.
    /// The icon will be used as
    /// - taskbar and titlebar icons on Windows.
    /// - TODO: favicon on HTML5
    /// - TODO: taskbar and titlebar(highly dependent on the WM) icons on Linux
    /// - TODO: dock and titlebar icon on  MacOs
    pub icon: Option<Icon>,

    /// Platform specific settings. Hints to OS for context creation, driver-specific
    /// settings etc.
    pub platform: Platform,
}

/// Icon image in three levels of detail.
#[derive(Clone)]
pub struct Icon {
    /// 16 * 16 image of RGBA pixels (each 4 * u8) in row-major order.
    pub small: [u8; 16 * 16 * 4],
    /// 32 x 32 image of RGBA pixels (each 4 * u8) in row-major order.
    pub medium: [u8; 32 * 32 * 4],
    /// 64 x 64 image of RGBA pixels (each 4 * u8) in row-major order.
    pub big: [u8; 64 * 64 * 4],
}

impl Icon {
    pub fn miniquad_logo() -> Icon {
        Icon {
            small: crate::default_icon::SMALL,
            medium: crate::default_icon::MEDIUM,
            big: crate::default_icon::BIG,
        }
    }
}
// Printing 64x64 array with a default formatter is not meaningfull,
// so debug will skip the data fields of an Icon
impl std::fmt::Debug for Icon {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Icon").finish()
    }
}

// reasonable defaults for PC and mobiles are slightly different
#[cfg(not(target_os = "android"))]
impl Default for Conf {
    fn default() -> Conf {
        Conf {
            window_title: "".to_owned(),
            window_width: 800,
            window_height: 600,
            high_dpi: false,
            fullscreen: false,
            sample_count: 1,
            window_resizable: true,
            icon: Some(Icon::miniquad_logo()),
            platform: Default::default(),
        }
    }
}

#[cfg(target_os = "android")]
impl Default for Conf {
    fn default() -> Conf {
        Conf {
            window_title: "".to_owned(),
            window_width: 800,
            window_height: 600,
            high_dpi: true,
            fullscreen: true,
            sample_count: 1,
            window_resizable: false,
            icon: Some(Icon::miniquad_logo()),
            platform: Default::default(),
        }
    }
}