Skip to content
Snippets Groups Projects
sdl.rs 3.02 KiB
use sdl2::{
    render::Canvas, rwops::RWops, surface::Surface, sys::image, ttf::Sdl2TtfContext, video::Window,
    AudioSubsystem, EventPump, Sdl, TimerSubsystem, VideoSubsystem,
};

/// Structure that provides the complete set of SDL Graphics
/// and Sound syb-system ready to be used by the overall
/// emulator infrastructure.
pub struct SdlSystem {
    pub canvas: Canvas<Window>,
    pub video_subsystem: VideoSubsystem,
    pub timer_subsystem: TimerSubsystem,
    pub audio_subsystem: AudioSubsystem,
    pub event_pump: EventPump,
    pub ttf_context: Sdl2TtfContext,
}

impl SdlSystem {
    /// Start the SDL sub-system and all of its structure and returns
    /// a structure with all the needed stuff to handle SDL graphics
    /// and sound.
    pub fn new(
        sdl: &Sdl,
        title: &str,
        width: u32,
        height: u32,
        scale: f32,
        accelerated: bool,
        vsync: bool,
    ) -> Self {
        // initializes the SDL sub-system, making it ready to be
        // used for display of graphics and audio
        let video_subsystem = sdl.video().unwrap();
        let timer_subsystem = sdl.timer().unwrap();
        let audio_subsystem = sdl.audio().unwrap();
        let event_pump = sdl.event_pump().unwrap();

        // initializes the fonts context to be used
        // in the loading of fonts (supports TTF fonts)
        let ttf_context = sdl2::ttf::init().unwrap();

        // creates the system window that is going to be used to
        // show the emulator and sets it to the central are o screen
        let window = video_subsystem
            .window(
                title,
                (scale * width as f32) as u32,
                (scale * height as f32) as u32,
            )
            .resizable()
            .position_centered()
            .opengl()
            .build()
            .unwrap();

        // creates a canvas (according to spec) to be used in the drawing
        // then clears it so that is can be presented empty initially
        let mut canvas_builder = window.into_canvas();
        if accelerated {
            canvas_builder = canvas_builder.accelerated();
        }
        if vsync {
            canvas_builder = canvas_builder.present_vsync();
        }
        let mut canvas = canvas_builder.build().unwrap();
        canvas.set_logical_size(width, height).unwrap();
        canvas.clear();

        Self {
            canvas,
            video_subsystem,
            timer_subsystem,
            audio_subsystem,
            event_pump,
            ttf_context,
        }
    }

    pub fn window(&self) -> &Window {
        self.canvas.window()
    }

    pub fn window_mut(&mut self) -> &mut Window {
        self.canvas.window_mut()
    }
}

/// Creates an SDL2 Surface structure from the provided
/// bytes that represent an image (eg: an PNG image buffer).
pub fn surface_from_bytes(bytes: &[u8]) -> Surface {
    unsafe {
        let rw_ops = RWops::from_bytes(bytes).unwrap();
        let raw_surface = image::IMG_Load_RW(rw_ops.raw(), 0);
        Surface::from_ll(raw_surface)
    }
}