azul_glutin/
lib.rs

1//! The purpose of this library is to provide an OpenGL [`Context`] on as many
2//! platforms as possible.
3//!
4//! # Building a [`WindowedContext<T>`]
5//!
6//! A [`WindowedContext<T>`] is composed of a [`Window`] and an OpenGL
7//! [`Context`].
8//!
9//! Due to some operating-system-specific quirks, glutin prefers control over
10//! the order of creation of the [`Context`] and [`Window`]. Here is an example
11//! of building a [`WindowedContext<T>`]:
12//!
13//! ```no_run
14//! # fn main() {
15//! let el = glutin::event_loop::EventLoop::new();
16//! let wb = glutin::window::WindowBuilder::new()
17//!     .with_title("Hello world!")
18//!     .with_inner_size(glutin::dpi::LogicalSize::new(1024.0, 768.0));
19//! let windowed_context = glutin::ContextBuilder::new()
20//!     .build_windowed(wb, &el)
21//!     .unwrap();
22//! # }
23//! ```
24//!
25//! You can, of course, create a [`RawContext<T>`] separately from an existing
26//! window, however that may result in an suboptimal configuration of the window
27//! on some platforms. In that case use the unsafe platform-specific
28//! [`RawContextExt`] available on unix operating systems and Windows.
29//!
30//! You can also produce headless [`Context`]s via the
31//! [`ContextBuilder::build_headless`] function.
32//!
33//! [`Window`]: window/struct.Window.html
34//! [`Context`]: struct.Context.html
35//! [`WindowedContext<T>`]: type.WindowedContext.html
36//! [`RawContext<T>`]: type.RawContext.html
37#![cfg_attr(
38    target_os = "windows",
39    doc = "\
40[`RawContextExt`]: os/windows/trait.RawContextExt.html
41"
42)]
43#![cfg_attr(
44    not(any(
45        target_os = "linux",
46        target_os = "dragonfly",
47        target_os = "freebsd",
48        target_os = "netbsd",
49        target_os = "windows",
50        target_os = "openbsd",
51    )),
52    doc = "\
53[`RawContextExt`]: os/index.html
54"
55)]
56#![cfg_attr(
57    any(
58        target_os = "linux",
59        target_os = "dragonfly",
60        target_os = "freebsd",
61        target_os = "netbsd",
62        target_os = "openbsd",
63    ),
64    doc = "\
65[`RawContextExt`]: os/unix/trait.RawContextExt.html
66"
67)]
68#![deny(
69    missing_debug_implementations,
70    //missing_docs,
71)]
72
73#[cfg(any(
74    target_os = "windows",
75    target_os = "linux",
76    target_os = "android",
77    target_os = "dragonfly",
78    target_os = "freebsd",
79    target_os = "netbsd",
80    target_os = "openbsd",
81))]
82#[macro_use]
83extern crate lazy_static;
84#[cfg(any(target_os = "macos", target_os = "ios"))]
85#[macro_use]
86extern crate objc;
87#[cfg(any(
88    target_os = "linux",
89    target_os = "dragonfly",
90    target_os = "freebsd",
91    target_os = "netbsd",
92    target_os = "openbsd",
93))]
94#[macro_use]
95extern crate log;
96
97pub mod platform;
98
99mod api;
100mod context;
101mod platform_impl;
102mod windowed;
103
104pub use crate::context::*;
105pub use crate::windowed::*;
106pub use winit::*;
107
108use winit::error::OsError;
109
110use std::io;
111
112/// An object that allows you to build [`Context`]s, [`RawContext<T>`]s and
113/// [`WindowedContext<T>`]s.
114///
115/// One notable limitation of the Wayland backend when it comes to shared
116/// [`Context`]s is that both contexts must use the same events loop.
117///
118/// [`Context`]: struct.Context.html
119/// [`WindowedContext<T>`]: type.WindowedContext.html
120/// [`RawContext<T>`]: type.RawContext.html
121#[derive(Debug, Clone)]
122pub struct ContextBuilder<'a, T: ContextCurrentState> {
123    /// The attributes to use to create the context.
124    pub gl_attr: GlAttributes<&'a Context<T>>,
125    /// The pixel format requirements
126    pub pf_reqs: PixelFormatRequirements,
127}
128
129impl<'a> ContextBuilder<'a, NotCurrent> {
130    /// Initializes a new `ContextBuilder` with default values.
131    pub fn new() -> Self {
132        ContextBuilder {
133            pf_reqs: std::default::Default::default(),
134            gl_attr: std::default::Default::default(),
135        }
136    }
137}
138
139impl<'a, T: ContextCurrentState> ContextBuilder<'a, T> {
140    /// Sets how the backend should choose the OpenGL API and version.
141    #[inline]
142    pub fn with_gl(mut self, request: GlRequest) -> Self {
143        self.gl_attr.version = request;
144        self
145    }
146
147    /// Sets the desired OpenGL [`Context`] profile.
148    ///
149    /// [`Context`]: struct.Context.html
150    #[inline]
151    pub fn with_gl_profile(mut self, profile: GlProfile) -> Self {
152        self.gl_attr.profile = Some(profile);
153        self
154    }
155
156    /// Sets the *debug* flag for the OpenGL [`Context`].
157    ///
158    /// The default value for this flag is `cfg!(debug_assertions)`, which means
159    /// that it's enabled when you run `cargo build` and disabled when you run
160    /// `cargo build --release`.
161    ///
162    /// [`Context`]: struct.Context.html
163    #[inline]
164    pub fn with_gl_debug_flag(mut self, flag: bool) -> Self {
165        self.gl_attr.debug = flag;
166        self
167    }
168
169    /// Sets the robustness of the OpenGL [`Context`]. See the docs of
170    /// [`Robustness`].
171    ///
172    /// [`Context`]: struct.Context.html
173    /// [`Robustness`]: enum.Robustness.html
174    #[inline]
175    pub fn with_gl_robustness(mut self, robustness: Robustness) -> Self {
176        self.gl_attr.robustness = robustness;
177        self
178    }
179
180    /// Requests that the window has vsync enabled.
181    ///
182    /// By default, vsync is not enabled.
183    #[inline]
184    pub fn with_vsync(mut self, vsync: bool) -> Self {
185        self.gl_attr.vsync = vsync;
186        self
187    }
188
189    /// Share the display lists with the given [`Context`].
190    ///
191    /// [`Context`]: struct.Context.html
192    #[inline]
193    pub fn with_shared_lists<T2: ContextCurrentState>(
194        self,
195        other: &'a Context<T2>,
196    ) -> ContextBuilder<'a, T2> {
197        ContextBuilder { gl_attr: self.gl_attr.set_sharing(Some(other)), pf_reqs: self.pf_reqs }
198    }
199
200    /// Sets the multisampling level to request. A value of `0` indicates that
201    /// multisampling must not be enabled.
202    ///
203    /// # Panic
204    ///
205    /// Will panic if `samples` is not a power of two.
206    #[inline]
207    pub fn with_multisampling(mut self, samples: u16) -> Self {
208        self.pf_reqs.multisampling = match samples {
209            0 => None,
210            _ => {
211                assert!(samples.is_power_of_two());
212                Some(samples)
213            }
214        };
215        self
216    }
217
218    /// Sets the number of bits in the depth buffer.
219    #[inline]
220    pub fn with_depth_buffer(mut self, bits: u8) -> Self {
221        self.pf_reqs.depth_bits = Some(bits);
222        self
223    }
224
225    /// Sets the number of bits in the stencil buffer.
226    #[inline]
227    pub fn with_stencil_buffer(mut self, bits: u8) -> Self {
228        self.pf_reqs.stencil_bits = Some(bits);
229        self
230    }
231
232    /// Sets the number of bits in the color buffer.
233    #[inline]
234    pub fn with_pixel_format(mut self, color_bits: u8, alpha_bits: u8) -> Self {
235        self.pf_reqs.color_bits = Some(color_bits);
236        self.pf_reqs.alpha_bits = Some(alpha_bits);
237        self
238    }
239
240    /// Request the backend to be stereoscopic.
241    #[inline]
242    pub fn with_stereoscopy(mut self) -> Self {
243        self.pf_reqs.stereoscopy = true;
244        self
245    }
246
247    /// Sets whether sRGB should be enabled on the window.
248    ///
249    /// The default value is `true`.
250    #[inline]
251    pub fn with_srgb(mut self, srgb_enabled: bool) -> Self {
252        self.pf_reqs.srgb = srgb_enabled;
253        self
254    }
255
256    /// Sets whether double buffering should be enabled.
257    ///
258    /// The default value is `None`.
259    ///
260    /// ## Platform-specific
261    ///
262    /// This option will be taken into account on the following platforms:
263    ///
264    ///   * MacOS
265    ///   * Unix operating systems using GLX with X
266    ///   * Windows using WGL
267    #[inline]
268    pub fn with_double_buffer(mut self, double_buffer: Option<bool>) -> Self {
269        self.pf_reqs.double_buffer = double_buffer;
270        self
271    }
272
273    /// Sets whether hardware acceleration is required.
274    ///
275    /// The default value is `Some(true)`
276    ///
277    /// ## Platform-specific
278    ///
279    /// This option will be taken into account on the following platforms:
280    ///
281    ///   * MacOS
282    ///   * Unix operating systems using EGL with either X or Wayland
283    ///   * Windows using EGL or WGL
284    ///   * Android using EGL
285    #[inline]
286    pub fn with_hardware_acceleration(mut self, acceleration: Option<bool>) -> Self {
287        self.pf_reqs.hardware_accelerated = acceleration;
288        self
289    }
290}
291
292/// Error that can happen while creating a window or a headless renderer.
293#[derive(Debug)]
294pub enum CreationError {
295    OsError(String),
296    NotSupported(String),
297    NoBackendAvailable(Box<dyn std::error::Error + Send + Sync>),
298    RobustnessNotSupported,
299    OpenGlVersionNotSupported,
300    NoAvailablePixelFormat,
301    PlatformSpecific(String),
302    Window(OsError),
303    /// We received multiple errors, instead of one.
304    CreationErrors(Vec<Box<CreationError>>),
305}
306
307impl CreationError {
308    #[cfg(any(
309        target_os = "linux",
310        target_os = "dragonfly",
311        target_os = "freebsd",
312        target_os = "netbsd",
313        target_os = "openbsd",
314    ))]
315    #[cfg(feature = "x11")]
316    pub(crate) fn append(self, err: CreationError) -> Self {
317        match self {
318            CreationError::CreationErrors(mut errs) => {
319                errs.push(Box::new(err));
320                CreationError::CreationErrors(errs)
321            }
322            _ => CreationError::CreationErrors(vec![Box::new(err), Box::new(self)]),
323        }
324    }
325
326    fn to_string(&self) -> &str {
327        match *self {
328            CreationError::OsError(ref text) | CreationError::NotSupported(ref text) => &text,
329            CreationError::NoBackendAvailable(_) => "No backend is available",
330            CreationError::RobustnessNotSupported => {
331                "You requested robustness, but it is not supported."
332            }
333            CreationError::OpenGlVersionNotSupported => {
334                "The requested OpenGL version is not supported."
335            }
336            CreationError::NoAvailablePixelFormat => {
337                "Couldn't find any pixel format that matches the criteria."
338            }
339            CreationError::PlatformSpecific(ref text) => &text,
340            CreationError::Window(ref err) => std::error::Error::description(err),
341            CreationError::CreationErrors(_) => "Received multiple errors.",
342        }
343    }
344}
345
346impl std::fmt::Display for CreationError {
347    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
348        formatter.write_str(self.to_string())?;
349
350        if let CreationError::CreationErrors(ref es) = *self {
351            use std::fmt::Debug;
352            write!(formatter, " Errors: `")?;
353            es.fmt(formatter)?;
354            write!(formatter, "`")?;
355        }
356
357        if let Some(err) = std::error::Error::source(self) {
358            write!(formatter, ": {}", err)?;
359        }
360        Ok(())
361    }
362}
363
364impl std::error::Error for CreationError {
365    fn description(&self) -> &str {
366        self.to_string()
367    }
368
369    fn cause(&self) -> Option<&dyn std::error::Error> {
370        match *self {
371            CreationError::NoBackendAvailable(ref err) => Some(&**err),
372            CreationError::Window(ref err) => Some(err),
373            _ => None,
374        }
375    }
376}
377
378impl From<OsError> for CreationError {
379    fn from(err: OsError) -> Self {
380        CreationError::Window(err)
381    }
382}
383
384/// Error that can happen when manipulating an OpenGL [`Context`].
385///
386/// [`Context`]: struct.Context.html
387#[derive(Debug)]
388pub enum ContextError {
389    /// General platform error.
390    OsError(String),
391    IoError(io::Error),
392    ContextLost,
393    FunctionUnavailable,
394}
395
396impl ContextError {
397    fn to_string(&self) -> &str {
398        use std::error::Error;
399        match *self {
400            ContextError::OsError(ref string) => string,
401            ContextError::IoError(ref err) => err.description(),
402            ContextError::ContextLost => "Context lost",
403            ContextError::FunctionUnavailable => "Function unavailable",
404        }
405    }
406}
407
408impl std::fmt::Display for ContextError {
409    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
410        formatter.write_str(self.to_string())
411    }
412}
413
414impl std::error::Error for ContextError {
415    fn description(&self) -> &str {
416        self.to_string()
417    }
418}
419
420/// All APIs related to OpenGL that you can possibly get while using glutin.
421#[derive(Debug, Clone, Copy, PartialEq, Eq)]
422pub enum Api {
423    /// The classical OpenGL. Available on Windows, Unix operating systems,
424    /// OS/X.
425    OpenGl,
426    /// OpenGL embedded system. Available on Unix operating systems, Android.
427    OpenGlEs,
428    /// OpenGL for the web. Very similar to OpenGL ES.
429    WebGl,
430}
431
432/// Describes the requested OpenGL [`Context`] profiles.
433///
434/// [`Context`]: struct.Context.html
435#[derive(Debug, Clone, Copy, PartialEq, Eq)]
436pub enum GlProfile {
437    /// Include all the immediate more functions and definitions.
438    Compatibility,
439    /// Include all the future-compatible functions and definitions.
440    Core,
441}
442
443/// Describes the OpenGL API and version that are being requested when a context
444/// is created.
445#[derive(Debug, Copy, Clone)]
446pub enum GlRequest {
447    /// Request the latest version of the "best" API of this platform.
448    ///
449    /// On desktop, will try OpenGL.
450    Latest,
451
452    /// Request a specific version of a specific API.
453    ///
454    /// Example: `GlRequest::Specific(Api::OpenGl, (3, 3))`.
455    Specific(Api, (u8, u8)),
456
457    /// If OpenGL is available, create an OpenGL [`Context`] with the specified
458    /// `opengl_version`. Else if OpenGL ES or WebGL is available, create a
459    /// context with the specified `opengles_version`.
460    ///
461    /// [`Context`]: struct.Context.html
462    GlThenGles {
463        /// The version to use for OpenGL.
464        opengl_version: (u8, u8),
465        /// The version to use for OpenGL ES.
466        opengles_version: (u8, u8),
467    },
468}
469
470impl GlRequest {
471    /// Extract the desktop GL version, if any.
472    pub fn to_gl_version(&self) -> Option<(u8, u8)> {
473        match self {
474            &GlRequest::Specific(Api::OpenGl, opengl_version) => Some(opengl_version),
475            &GlRequest::GlThenGles { opengl_version, .. } => Some(opengl_version),
476            _ => None,
477        }
478    }
479}
480
481/// The minimum core profile GL context. Useful for getting the minimum
482/// required GL version while still running on OSX, which often forbids
483/// the compatibility profile features.
484pub static GL_CORE: GlRequest = GlRequest::Specific(Api::OpenGl, (3, 2));
485
486/// Specifies the tolerance of the OpenGL [`Context`] to faults. If you accept
487/// raw OpenGL commands and/or raw shader code from an untrusted source, you
488/// should definitely care about this.
489///
490/// [`Context`]: struct.Context.html
491#[derive(Debug, Copy, Clone, PartialEq, Eq)]
492pub enum Robustness {
493    /// Not everything is checked. Your application can crash if you do
494    /// something wrong with your shaders.
495    NotRobust,
496
497    /// The driver doesn't check anything. This option is very dangerous.
498    /// Please know what you're doing before using it. See the
499    /// `GL_KHR_no_error` extension.
500    ///
501    /// Since this option is purely an optimization, no error will be returned
502    /// if the backend doesn't support it. Instead it will automatically
503    /// fall back to [`NotRobust`].
504    ///
505    /// [`NotRobust`]: enum.Robustness.html#variant.NotRobust
506    NoError,
507
508    /// Everything is checked to avoid any crash. The driver will attempt to
509    /// avoid any problem, but if a problem occurs the behavior is
510    /// implementation-defined. You are just guaranteed not to get a crash.
511    RobustNoResetNotification,
512
513    /// Same as [`RobustNoResetNotification`] but the context creation doesn't
514    /// fail if it's not supported.
515    ///
516    /// [`RobustNoResetNotification`]:
517    /// enum.Robustness.html#variant.RobustNoResetNotification
518    TryRobustNoResetNotification,
519
520    /// Everything is checked to avoid any crash. If a problem occurs, the
521    /// context will enter a "context lost" state. It must then be
522    /// recreated. For the moment, glutin doesn't provide a way to recreate
523    /// a context with the same window :-/
524    RobustLoseContextOnReset,
525
526    /// Same as [`RobustLoseContextOnReset`] but the context creation doesn't
527    /// fail if it's not supported.
528    ///
529    /// [`RobustLoseContextOnReset`]:
530    /// enum.Robustness.html#variant.RobustLoseContextOnReset
531    TryRobustLoseContextOnReset,
532}
533
534/// The behavior of the driver when you change the current context.
535#[derive(Debug, Copy, Clone, PartialEq, Eq)]
536pub enum ReleaseBehavior {
537    /// Doesn't do anything. Most notably doesn't flush.
538    None,
539
540    /// Flushes the context that was previously current as if `glFlush` was
541    /// called.
542    Flush,
543}
544
545/// Describes a possible format.
546#[allow(missing_docs)]
547#[derive(Debug, Clone)]
548pub struct PixelFormat {
549    pub hardware_accelerated: bool,
550    /// The number of color bits. Does not include alpha bits.
551    pub color_bits: u8,
552    pub alpha_bits: u8,
553    pub depth_bits: u8,
554    pub stencil_bits: u8,
555    pub stereoscopy: bool,
556    pub double_buffer: bool,
557    /// `None` if multisampling is disabled, otherwise `Some(N)` where `N` is
558    /// the multisampling level.
559    pub multisampling: Option<u16>,
560    pub srgb: bool,
561}
562
563/// Describes how the backend should choose a pixel format.
564// TODO: swap method? (swap, copy)
565#[derive(Clone, Debug)]
566pub struct PixelFormatRequirements {
567    /// If true, only hardware-accelerated formats will be considered. If
568    /// false, only software renderers. `None` means "don't care". Default
569    /// is `Some(true)`.
570    pub hardware_accelerated: Option<bool>,
571
572    /// Minimum number of bits for the color buffer, excluding alpha. `None`
573    /// means "don't care". The default is `Some(24)`.
574    pub color_bits: Option<u8>,
575
576    /// If true, the color buffer must be in a floating point format. Default
577    /// is `false`.
578    ///
579    /// Using floating points allows you to write values outside of the `[0.0,
580    /// 1.0]` range.
581    pub float_color_buffer: bool,
582
583    /// Minimum number of bits for the alpha in the color buffer. `None` means
584    /// "don't care". The default is `Some(8)`.
585    pub alpha_bits: Option<u8>,
586
587    /// Minimum number of bits for the depth buffer. `None` means "don't care".
588    /// The default value is `Some(24)`.
589    pub depth_bits: Option<u8>,
590
591    /// Minimum number of stencil bits. `None` means "don't care".
592    /// The default value is `Some(8)`.
593    pub stencil_bits: Option<u8>,
594
595    /// If true, only double-buffered formats will be considered. If false,
596    /// only single-buffer formats. `None` means "don't care". The default
597    /// is `Some(true)`.
598    pub double_buffer: Option<bool>,
599
600    /// Contains the minimum number of samples per pixel in the color, depth
601    /// and stencil buffers. `None` means "don't care". Default is `None`.
602    /// A value of `Some(0)` indicates that multisampling must not be enabled.
603    pub multisampling: Option<u16>,
604
605    /// If true, only stereoscopic formats will be considered. If false, only
606    /// non-stereoscopic formats. The default is `false`.
607    pub stereoscopy: bool,
608
609    /// If true, only sRGB-capable formats will be considered. If false, don't
610    /// care. The default is `true`.
611    pub srgb: bool,
612
613    /// The behavior when changing the current context. Default is `Flush`.
614    pub release_behavior: ReleaseBehavior,
615
616    /// X11 only: set internally to insure a certain visual xid is used when
617    /// choosing the fbconfig.
618    pub(crate) x11_visual_xid: Option<std::os::raw::c_ulong>,
619}
620
621impl Default for PixelFormatRequirements {
622    #[inline]
623    fn default() -> PixelFormatRequirements {
624        PixelFormatRequirements {
625            hardware_accelerated: Some(true),
626            color_bits: Some(24),
627            float_color_buffer: false,
628            alpha_bits: Some(8),
629            depth_bits: Some(24),
630            stencil_bits: Some(8),
631            double_buffer: None,
632            multisampling: None,
633            stereoscopy: false,
634            srgb: true,
635            release_behavior: ReleaseBehavior::Flush,
636            x11_visual_xid: None,
637        }
638    }
639}
640
641/// Attributes to use when creating an OpenGL [`Context`].
642///
643/// [`Context`]: struct.Context.html
644#[derive(Clone, Debug)]
645pub struct GlAttributes<S> {
646    /// An existing context with which some OpenGL objects get shared.
647    ///
648    /// The default is `None`.
649    pub sharing: Option<S>,
650
651    /// Version to try create. See [`GlRequest`] for more infos.
652    ///
653    /// The default is [`Latest`].
654    ///
655    /// [`Latest`]: enum.GlRequest.html#variant.Latest
656    /// [`GlRequest`]: enum.GlRequest.html
657    pub version: GlRequest,
658
659    /// OpenGL profile to use.
660    ///
661    /// The default is `None`.
662    pub profile: Option<GlProfile>,
663
664    /// Whether to enable the `debug` flag of the context.
665    ///
666    /// Debug contexts are usually slower but give better error reporting.
667    ///
668    /// The default is `true` in debug mode and `false` in release mode.
669    pub debug: bool,
670
671    /// How the OpenGL [`Context`] should detect errors.
672    ///
673    /// The default is `NotRobust` because this is what is typically expected
674    /// when you create an OpenGL [`Context`]. However for safety you should
675    /// consider [`TryRobustLoseContextOnReset`].
676    ///
677    /// [`Context`]: struct.Context.html
678    /// [`TryRobustLoseContextOnReset`]:
679    /// enum.Robustness.html#variant.TryRobustLoseContextOnReset
680    pub robustness: Robustness,
681
682    /// Whether to use vsync. If vsync is enabled, calling `swap_buffers` will
683    /// block until the screen refreshes. This is typically used to prevent
684    /// screen tearing.
685    ///
686    /// The default is `false`.
687    pub vsync: bool,
688}
689
690impl<S> GlAttributes<S> {
691    /// Turns the `sharing` parameter into another type by calling a closure.
692    #[inline]
693    pub fn map_sharing<F, T>(self, f: F) -> GlAttributes<T>
694    where
695        F: FnOnce(S) -> T,
696    {
697        GlAttributes {
698            sharing: self.sharing.map(f),
699            version: self.version,
700            profile: self.profile,
701            debug: self.debug,
702            robustness: self.robustness,
703            vsync: self.vsync,
704        }
705    }
706
707    /// Turns the `sharing` parameter into another type.
708    #[inline]
709    fn set_sharing<T>(self, sharing: Option<T>) -> GlAttributes<T> {
710        GlAttributes {
711            sharing,
712            version: self.version,
713            profile: self.profile,
714            debug: self.debug,
715            robustness: self.robustness,
716            vsync: self.vsync,
717        }
718    }
719}
720
721impl<S> Default for GlAttributes<S> {
722    #[inline]
723    fn default() -> GlAttributes<S> {
724        GlAttributes {
725            sharing: None,
726            version: GlRequest::Latest,
727            profile: None,
728            debug: cfg!(debug_assertions),
729            robustness: Robustness::NotRobust,
730            vsync: false,
731        }
732    }
733}
734
735// Rectangles to submit as buffer damage.
736#[derive(Debug, Clone, Copy, PartialEq, Eq)]
737pub struct Rect {
738    pub x: u32,
739    pub y: u32,
740    pub width: u32,
741    pub height: u32,
742}