ux-dx 0.2.1

3D Graphics Primitives for Angular Rust
Documentation
use super::{OnscreenTemplate, Renderer};
use std::fmt;

// @short_description: Common aspects of a display pipeline
//
// The basic intention for this object is to let the application
// configure common display preferences before creating a context, and
// there are a few different aspects to this...
//
// Firstly there are options directly relating to the physical display
// pipeline that is currently being used including the digital to
// analogue conversion hardware and the screens the user sees.
//
// Another aspect is that display options may constrain or affect how
// onscreen framebuffers should later be configured. The original
// rationale for the display object in fact was to let us handle GLX
// and EGLs requirements that framebuffers must be "compatible" with
// the config associated with the current context meaning we have to
// force the user to describe how they would like to create their
// onscreen windows before we can choose a suitable fbconfig and
// create a GLContext.

#[derive(Debug, Clone)]
pub struct Display {
    setup: bool,
    renderer: Option<Renderer>,
    // Seems should be Rc
    onscreen_template: Option<OnscreenTemplate>,
    //   #ifdef HAS_WAYLAND_EGL_SERVER_SUPPORT
    //     struct wl_display *wayland_compositor_display;
    //   #endif

    //   #ifdef HAS_EGL_PLATFORM_GDL_SUPPORT
    //     gdl_plane_id_t gdl_plane;
    //   #endif

    //     void *winsys;
}

impl Display {
    /// Explicitly allocates a new `Display` object to encapsulate the
    /// common state of the display pipeline that applies to the whole
    /// application.
    ///
    /// Many applications don't need to explicitly use
    /// `Display::new` and can just jump straight to `Context::new`
    /// and pass a `None` display argument so  will automatically
    /// connect and setup a renderer and display.
    ///
    /// A `display` can only be made for a specific choice of renderer which
    /// is why this takes the `renderer` argument.
    ///
    /// A common use for explicitly allocating a display object is to
    /// define a template for allocating onscreen framebuffers which is
    /// what the `onscreen_template` argument is for, or alternatively
    /// you can use `Display::set_onscreen_template`.
    ///
    /// When a display is first allocated via `Display::new` it is in a
    /// mutable configuration mode. It's designed this way so we can
    /// extend the apis available for configuring a display without
    /// requiring huge numbers of constructor arguments.
    ///
    /// When you have finished configuring a display object you can
    /// optionally call `Display::setup` to explicitly apply the
    /// configuration and check for errors. Alternaitvely you can pass the
    /// display to `Context::new` and  will implicitly apply your
    /// configuration but if there are errors then the application will
    /// abort with a message. For simple applications with no fallback
    /// options then relying on the implicit setup can be fine.
    /// ## `renderer`
    /// A `Renderer`
    /// ## `onscreen_template`
    /// A `OnscreenTemplate`
    ///
    /// # Returns
    ///
    /// A newly allocated `Display`
    ///  object in a mutable configuration mode.
    pub fn new(renderer: Option<Renderer>, onscreen_template: Option<OnscreenTemplate>) -> Self {
        // dx_init ();

        let renderer = match renderer {
            Some(renderer) => renderer,
            None => Renderer::new(),
        };

        if !renderer.connect() {
            panic!("Failed to connect to renderer");
        }

        // #ifdef HAS_EGL_PLATFORM_GDL_SUPPORT
        // display->gdl_plane = GDL_PLANE_ID_UPP_C;
        // #endif

        let mut display = Self {
            setup: false,
            renderer: Some(renderer),
            onscreen_template: None,
        };

        display.set_onscreen_template(onscreen_template);

        display
    }

    /// Queries the `Renderer` associated with the given `self`.
    ///
    /// # Returns
    ///
    /// The associated `Renderer`
    pub fn renderer(&self) -> Option<Renderer> {
        self.renderer.as_ref().cloned()
    }

    /// Specifies a template for creating `Onscreen` framebuffers.
    ///
    /// Depending on the system, the constraints for creating `Onscreen`
    /// framebuffers need to be known before setting up a `Display` because the
    /// final setup of the display may constrain how onscreen framebuffers may be
    /// allocated. If  knows how an application wants to allocate onscreen
    /// framebuffers then it can try to make sure to setup the display accordingly.
    /// ## `onscreen_template`
    /// A template for creating `Onscreen` framebuffers
    pub fn set_onscreen_template(&mut self, onscreen_template: Option<OnscreenTemplate>) {
        // NB: we want to maintain the invariable that there is always an
        // onscreen template associated with a Display...
        let template = match onscreen_template {
            Some(template) => template,
            None => OnscreenTemplate::new(None),
        };
        self.onscreen_template = Some(template)
    }

    /// Explicitly sets up the given `self` object:: Use of this api is
    /// optional since  will internally setup the display if not done
    /// explicitly.
    ///
    /// When a display is first allocated via `Display::new` it is in a
    /// mutable configuration mode. This allows us to extend the apis
    /// available for configuring a display without requiring huge numbers
    /// of constructor arguments.
    ///
    /// Its possible to request a configuration that might not be
    /// supportable on the current system and so this api provides a means
    /// to apply the configuration explicitly but if it fails then an
    /// exception will be returned so you can handle the error gracefully
    /// and perhaps fall back to an alternative configuration.
    ///
    /// If you instead rely on  implicitly calling `Display::setup`
    /// for you then if there is an error with the configuration you won't
    /// get an opportunity to handle that and the application may abort
    /// with a message. For simple applications that don't have any
    /// fallback options this behaviour may be fine.
    ///
    /// # Returns
    ///
    /// Returns `true` if there was no error, else it returns
    ///  `false` and returns an exception via `error`.
    pub fn setup(&mut self) -> bool {
        // const WinsysVtable *winsys;

        if self.setup {
            return true;
        }

        // winsys = _display_get_winsys (display);
        // if (!winsys->display_setup (display, error)) {
        //     return false;
        // }

        self.setup = true;

        true
    }
}

impl fmt::Display for Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Display")
    }
}