use crate::base::ControlFlow; use crate::prelude::*; use std::ffi::CStr; use std::os::raw::c_uint; use sdl2::{Sdl, VideoSubsystem}; use sdl2::video::{GLContext, Window}; pub struct SimpleSdl2OpenglComponent { window: Window, window_fbo: c_uint, gl_context: GLContext, pixel_format: sdl2::pixels::PixelFormatEnum, hw_context_reset_fn: Option, hw_context_destroy_fn: Option, } impl SimpleSdl2OpenglComponent { pub fn new(sdl_context: &mut Sdl, retro: &LibretroWrapper) -> Result> { let sys_info = retro.get_system_info(); let title = format!( "{} - ferretro SDL GL", unsafe { CStr::from_ptr(sys_info.library_name) }.to_string_lossy() ); let geometry = retro.get_system_av_info().geometry; let pixel_format = sdl2::pixels::PixelFormatEnum::ARGB1555; let video = sdl_context.video()?; let window = video .window(title.as_str(), geometry.base_width, geometry.base_height) .opengl() .build()?; // http://forums.libsdl.org/viewtopic.php?p=43353 // likely to remain `0` on any platform that isn't iOS, but we'll do it anyhow let gl_context = window.gl_create_context()?; let window_fbo = Self::current_framebuffer_binding(&video); Ok(SimpleSdl2OpenglComponent { window, window_fbo, gl_context, pixel_format, hw_context_reset_fn: None, hw_context_destroy_fn: None, }) } fn current_framebuffer_binding(video: &VideoSubsystem) -> c_uint { let mut fbo: c_uint = 0; unsafe { const GL_FRAMEBUFFER_BINDING: c_uint = 0x8CA6; #[allow(non_snake_case)] let glGetIntegerv: unsafe extern "C" fn(c_uint, *mut c_uint) = std::mem::transmute( video.gl_get_proc_address("glGetIntegerv") ); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mut fbo); } eprintln!("get_framebuffer_binding: {}", fbo); fbo } fn call_context_reset(&self) -> Option<()> { self.hw_context_reset_fn.map(|f| unsafe { f(); }) } fn call_context_destroy(&self) -> Option<()> { self.hw_context_destroy_fn.map(|f| unsafe { f(); }) } } impl RetroCallbacks for SimpleSdl2OpenglComponent { fn set_pixel_format(&mut self, pix_fmt: PixelFormat) -> Option { self.pixel_format = match pix_fmt { PixelFormat::ARGB1555 => sdl2::pixels::PixelFormatEnum::RGB555, PixelFormat::ARGB8888 => sdl2::pixels::PixelFormatEnum::ARGB8888, PixelFormat::RGB565 => sdl2::pixels::PixelFormatEnum::RGB565, }; Some(true) } fn set_hw_render(&mut self, hw_render_callback: &HwRenderCallback) -> Option { self.hw_context_reset_fn.replace(hw_render_callback.context_reset); self.hw_context_destroy_fn.replace(hw_render_callback.context_destroy); self.call_context_reset(); Some(true) } fn get_variable(&mut self, key: &str) -> Option { match key { "parallel-n64-gfxplugin" => Some("glide64".to_string()), _ => None, } } fn set_system_av_info(&mut self, av_info: &SystemAvInfo) -> Option { self.set_geometry(&av_info.geometry)?; Some(true) } fn set_geometry(&mut self, geom: &GameGeometry) -> Option { self.window.set_size(geom.base_width, geom.base_height).ok()?; self.call_context_destroy()?; self.gl_context = self.window.gl_create_context().ok()?; self.window_fbo = Self::current_framebuffer_binding(self.window.subsystem()); self.call_context_reset()?; Some(true) } fn hw_get_current_framebuffer(&mut self) -> Option { Some(self.window_fbo as usize) } fn hw_get_proc_address(&mut self, sym: &str) -> Option<*const ()> { Some(self.window.subsystem().gl_get_proc_address(sym)) } } impl RetroComponent for SimpleSdl2OpenglComponent { fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow { self.window.gl_swap_window(); ControlFlow::Continue } }