elikar 0.1.9

A rust asynchronous ECS game engine
use crate::common::{from_sdl_string, Result, SdlError};
use sdl2_sys::*;
use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use std::os::raw::{c_char, c_int};
use std::ptr::null_mut;

#[derive(Debug, Default, Copy, Clone, PartialOrd, PartialEq)]
pub struct DPI {
    pub ddpi: f32,
    pub hdpi: f32,
    pub vdpi: f32,
}

#[derive(Debug, Default, Copy, Clone, PartialOrd, PartialEq)]
pub struct DisplayMode {
    pub size: (i32, i32),
    pub refresh_rate: u32,
}

#[derive(Debug, Default, Clone)]
pub struct Screen {
    pub dpi: DPI,
    pub bound: (i32, i32, i32, i32),
    pub modes: Vec<DisplayMode>,
    pub name: String,
}

impl Display for DPI {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "(ddpi:{},hdpi:{},vdpi:{})",
            self.ddpi, self.hdpi, self.vdpi
        )
    }
}

impl Display for DisplayMode {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{} x {} @ {}Hz",
            self.size.0, self.size.1, self.refresh_rate
        )
    }
}

impl Display for Screen {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Screen:\n\tname:{}\n\tbound:({},{},{},{})\n\tdpi:{}\n\tdisplay modes:\n",
            self.name, self.bound.0, self.bound.1, self.bound.2, self.bound.3, self.dpi
        )?;
        for mode in &self.modes {
            write!(f, "\t\t{}\n", mode)?;
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct VideoInfo {
    _marker : PhantomData<()>
}

impl VideoInfo {
    pub(in crate::sysinfo) fn new() -> VideoInfo {
        VideoInfo {
            _marker : Default::default()
        }
    }

    pub fn all_drivers_name(&self) -> Result<Vec<String>> {
        let num = unsafe { SDL_GetNumVideoDrivers() };
        if num < 0 {
            return Err(SdlError::get());
        }
        let mut names: Vec<String> = Vec::with_capacity(num as usize);
        for i in 0..num {
            let cname: *const c_char = unsafe { SDL_GetVideoDriver(i as c_int) };
            names.push(unsafe { from_sdl_string(cname) })
        }
        Ok(names)
    }

    pub fn current_drivers_name(&self) -> String {
        let cname: *const c_char = unsafe { SDL_GetCurrentVideoDriver() };
        unsafe { from_sdl_string(cname) }
    }

    pub fn screens(&self) -> Result<Vec<Screen>> {
        let screen_num = unsafe { SDL_GetNumVideoDisplays() };
        if screen_num < 0 {
            return Err(SdlError::get());
        }
        let mut screens: Vec<Screen> = Vec::with_capacity(screen_num as usize);
        for i in 0..screen_num {
            let mut screen: Screen = Screen::default();
            screen.name = unsafe { from_sdl_string(SDL_GetDisplayName(i)) };

            let mut bound: SDL_Rect = SDL_Rect {
                x: 0,
                y: 0,
                w: 0,
                h: 0,
            };
            if unsafe { SDL_GetDisplayBounds(i, &mut bound) } < 0 {
                return Err(SdlError::get());
            }
            screen.bound.0 = bound.x;
            screen.bound.1 = bound.y;
            screen.bound.2 = bound.w;
            screen.bound.3 = bound.h;

            if unsafe {
                SDL_GetDisplayDPI(
                    i,
                    &mut screen.dpi.ddpi,
                    &mut screen.dpi.hdpi,
                    &mut screen.dpi.vdpi,
                )
            } < 0
            {
                return Err(SdlError::get());
            }

            let mode_num = unsafe { SDL_GetNumDisplayModes(i) };
            for j in 0..mode_num {
                let mut sdlmode: SDL_DisplayMode = SDL_DisplayMode {
                    format: 0,
                    w: 0,
                    h: 0,
                    refresh_rate: 0,
                    driverdata: null_mut(),
                };
                if unsafe { SDL_GetDisplayMode(i, j, &mut sdlmode) } < 0 {
                    return Err(SdlError::get());
                }
                screen.modes.push(DisplayMode {
                    size: (sdlmode.w, sdlmode.h),
                    refresh_rate: sdlmode.refresh_rate as u32,
                })
            }
            screens.push(screen);
        }
        Ok(screens)
    }
}