From 1c2eaae4d1e37d7942c8dbe5e298f07c8f765b2e Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Fri, 25 Feb 2022 06:01:43 +0100 Subject: [PATCH] macOS fixes --- build.rs | 8 +- src/framework/backend_sdl2.rs | 181 +++++++++++++++++++++++---------- src/framework/render_opengl.rs | 2 +- src/lib.rs | 14 ++- 4 files changed, 146 insertions(+), 59 deletions(-) diff --git a/build.rs b/build.rs index e09e446..824d2e2 100644 --- a/build.rs +++ b/build.rs @@ -19,8 +19,12 @@ fn main() { // .unwrap(); // } - if target.contains("macos") { - println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.12") + if target.contains("darwin") { + println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.12"); + println!("cargo:rustc-link-arg=-weak_framework"); + println!("cargo:rustc-link-arg=GameController"); + println!("cargo:rustc-link-arg=-weak_framework"); + println!("cargo:rustc-link-arg=CoreHaptics"); } if is_android { diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs index de7301d..40fcfe7 100644 --- a/src/framework/backend_sdl2.rs +++ b/src/framework/backend_sdl2.rs @@ -16,6 +16,7 @@ use sdl2::pixels::PixelFormatEnum; use sdl2::render::{Texture, TextureCreator, TextureQuery, WindowCanvas}; use sdl2::video::GLProfile; use sdl2::video::WindowContext; +use sdl2::video::Window; use sdl2::{keyboard, pixels, EventPump, Sdl, VideoSubsystem}; use crate::common::{Color, Rect}; @@ -53,6 +54,71 @@ impl Backend for SDL2Backend { } } +enum WindowOrCanvas { + None, + Win(Window), + Canvas(WindowCanvas, TextureCreator<WindowContext>), +} + +impl Default for WindowOrCanvas { + fn default() -> Self { + WindowOrCanvas::None + } +} + +impl WindowOrCanvas { + #[inline] + pub fn window(&self) -> &Window { + match self { + WindowOrCanvas::Win(ref window) => window, + WindowOrCanvas::Canvas(ref canvas, _) => canvas.window(), + _ => unsafe { std::hint::unreachable_unchecked(); }, + } + } + + #[inline] + pub fn window_mut(&mut self) -> &mut Window { + match self { + WindowOrCanvas::Win(ref mut window) => window, + WindowOrCanvas::Canvas(ref mut canvas, _) => canvas.window_mut(), + _ => unsafe { std::hint::unreachable_unchecked(); }, + } + } + + #[inline] + pub fn canvas(&mut self) -> &mut WindowCanvas { + match self { + WindowOrCanvas::Canvas(ref mut canvas, _) => canvas, + _ => unsafe { std::hint::unreachable_unchecked(); }, + } + } + + #[inline] + pub fn texture_creator(&mut self) -> &mut TextureCreator<WindowContext> { + match self { + WindowOrCanvas::Canvas(_, ref mut texture_creator) => texture_creator, + _ => unsafe { std::hint::unreachable_unchecked(); }, + } + } + + pub fn make_canvas(self) -> GameResult<WindowOrCanvas> { + if let WindowOrCanvas::Win(window) = self { + let canvas = window + .into_canvas() + .accelerated() + .present_vsync() + .build() + .map_err(|e| GameError::RenderError(e.to_string()))?; + + let texture_creator = canvas.texture_creator(); + + Ok(WindowOrCanvas::Canvas(canvas, texture_creator)) + } else { + Ok(self) + } + } +} + struct SDL2EventLoop { event_pump: EventPump, refs: Rc<RefCell<SDL2Context>>, @@ -61,8 +127,7 @@ struct SDL2EventLoop { struct SDL2Context { video: VideoSubsystem, - canvas: WindowCanvas, - texture_creator: TextureCreator<WindowContext>, + window: WindowOrCanvas, gl_context: Option<sdl2::video::GLContext>, blend_mode: sdl2::render::BlendMode, } @@ -73,8 +138,8 @@ impl SDL2EventLoop { let video = sdl.video().map_err(GameError::WindowError)?; let gl_attr = video.gl_attr(); - gl_attr.set_context_profile(GLProfile::Core); - gl_attr.set_context_version(3, 0); + gl_attr.set_context_profile(GLProfile::Compatibility); + gl_attr.set_context_version(2, 1); let mut window = video.window("Cave Story (doukutsu-rs)", size_hint.0 as _, size_hint.1 as _); window.position_centered(); @@ -85,22 +150,12 @@ impl SDL2EventLoop { let window = window.build().map_err(|e| GameError::WindowError(e.to_string()))?; - let canvas = window - .into_canvas() - .accelerated() - .present_vsync() - .build() - .map_err(|e| GameError::RenderError(e.to_string()))?; - - let texture_creator = canvas.texture_creator(); - let opengl_available = if let Ok(v) = std::env::var("CAVESTORY_NO_OPENGL") { v != "1" } else { true }; let event_loop = SDL2EventLoop { event_pump, refs: Rc::new(RefCell::new(SDL2Context { video, - canvas, - texture_creator, + window: WindowOrCanvas::Win(window), gl_context: None, blend_mode: sdl2::render::BlendMode::Blend, })), @@ -122,7 +177,7 @@ impl BackendEventLoop for SDL2EventLoop { }; { - let (width, height) = self.refs.deref().borrow().canvas.window().size(); + let (width, height) = self.refs.deref().borrow().window.window().size(); ctx.screen_size = (width.max(1) as f32, height.max(1) as f32); imgui.io_mut().display_size = [ctx.screen_size.0, ctx.screen_size.1]; @@ -140,7 +195,7 @@ impl BackendEventLoop for SDL2EventLoop { winfo.version.minor = sdl2_sys::SDL_MINOR_VERSION as _; winfo.version.patch = sdl2_sys::SDL_PATCHLEVEL as _; - let mut whandle = self.refs.deref().borrow().canvas.window().raw(); + let mut whandle = self.refs.deref().borrow().window.window().raw(); if sdl2_sys::SDL_GetWindowWMInfo(whandle, &mut winfo as *mut _) != sdl2_sys::SDL_bool::SDL_FALSE { let window = winfo.info.x11.display as *mut objc::runtime::Object; @@ -230,7 +285,7 @@ impl BackendEventLoop for SDL2EventLoop { imgui_sdl2.prepare_frame( imgui.io_mut(), - self.refs.deref().borrow().canvas.window(), + self.refs.deref().borrow().window.window(), &self.event_pump.mouse_state(), ); @@ -242,9 +297,9 @@ impl BackendEventLoop for SDL2EventLoop { #[cfg(feature = "render-opengl")] { let mut refs = self.refs.borrow_mut(); - match refs.canvas.window().gl_create_context() { + match refs.window.window().gl_create_context() { Ok(gl_ctx) => { - refs.canvas.window().gl_make_current(&gl_ctx).map_err(|e| GameError::RenderError(e.to_string()))?; + refs.window.window().gl_make_current(&gl_ctx).map_err(|e| GameError::RenderError(e.to_string()))?; refs.gl_context = Some(gl_ctx); } Err(err) => { @@ -281,7 +336,7 @@ impl BackendEventLoop for SDL2EventLoop { { let refs = &mut *refs.as_ptr(); - refs.canvas.window().gl_swap_window(); + refs.window.window().gl_swap_window(); } *user_data = Rc::into_raw(refs) as *mut c_void; @@ -290,6 +345,10 @@ impl BackendEventLoop for SDL2EventLoop { let gl_context = GLContext { gles2_mode: false, get_proc_address, swap_buffers, user_data }; return Ok(Box::new(OpenGLRenderer::new(gl_context, UnsafeCell::new(imgui)))); + } else { + let mut refs = self.refs.borrow_mut(); + let window = std::mem::take(&mut refs.window); + refs.window = window.make_canvas()?; } SDL2Renderer::new(self.refs.clone()) @@ -317,7 +376,8 @@ impl SDL2Renderer { let mut texture = refs .borrow_mut() - .texture_creator + .window + .texture_creator() .create_texture_streaming(PixelFormatEnum::RGBA32, font_tex.width, font_tex.height) .map_err(|e| GameError::RenderError(e.to_string()))?; @@ -350,7 +410,7 @@ impl SDL2Renderer { let imgui_sdl2 = unsafe { let refs = &mut *refs.as_ptr(); - ImguiSdl2::new(&mut imgui, refs.canvas.window()) + ImguiSdl2::new(&mut imgui, refs.window.window()) }; Ok(Box::new(SDL2Renderer { @@ -405,33 +465,37 @@ impl BackendRenderer for SDL2Renderer { fn clear(&mut self, color: Color) { let mut refs = self.refs.borrow_mut(); + let canvas = refs.window.canvas(); - refs.canvas.set_draw_color(to_sdl(color)); - refs.canvas.set_blend_mode(sdl2::render::BlendMode::Blend); - refs.canvas.clear(); + canvas.set_draw_color(to_sdl(color)); + canvas.set_blend_mode(sdl2::render::BlendMode::Blend); + canvas.clear(); } fn present(&mut self) -> GameResult { let mut refs = self.refs.borrow_mut(); + let canvas = refs.window.canvas(); - refs.canvas.present(); + canvas.present(); Ok(()) } fn prepare_draw(&mut self, width: f32, height: f32) -> GameResult { let mut refs = self.refs.borrow_mut(); + let canvas = refs.window.canvas(); - refs.canvas.set_clip_rect(Some(sdl2::rect::Rect::new(0, 0, width as u32, height as u32))); + canvas.set_clip_rect(Some(sdl2::rect::Rect::new(0, 0, width as u32, height as u32))); Ok(()) } fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> { - let refs = self.refs.borrow_mut(); + let mut refs = self.refs.borrow_mut(); let texture = refs - .texture_creator + .window + .texture_creator() .create_texture_target(PixelFormatEnum::RGBA32, width as u32, height as u32) .map_err(|e| GameError::RenderError(e.to_string()))?; @@ -439,10 +503,11 @@ impl BackendRenderer for SDL2Renderer { } fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> { - let refs = self.refs.borrow_mut(); + let mut refs = self.refs.borrow_mut(); let mut texture = refs - .texture_creator + .window + .texture_creator() .create_texture_streaming(PixelFormatEnum::RGBA32, width as u32, height as u32) .map_err(|e| GameError::RenderError(e.to_string()))?; @@ -479,7 +544,7 @@ impl BackendRenderer for SDL2Renderer { } fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> GameResult { - let renderer = self.refs.deref().borrow().canvas.raw(); + let renderer = self.refs.borrow_mut().window.canvas().raw(); match texture { Some(texture) => { @@ -506,13 +571,14 @@ impl BackendRenderer for SDL2Renderer { fn draw_rect(&mut self, rect: Rect<isize>, color: Color) -> GameResult<()> { let mut refs = self.refs.borrow_mut(); + let blend = refs.blend_mode; + let canvas = refs.window.canvas(); let (r, g, b, a) = color.to_rgba(); - let blend = refs.blend_mode; - refs.canvas.set_draw_color(pixels::Color::RGBA(r, g, b, a)); - refs.canvas.set_blend_mode(blend); - refs.canvas + canvas.set_draw_color(pixels::Color::RGBA(r, g, b, a)); + canvas.set_blend_mode(blend); + canvas .fill_rect(sdl2::rect::Rect::new( rect.left as i32, rect.top as i32, @@ -526,17 +592,18 @@ impl BackendRenderer for SDL2Renderer { fn draw_outline_rect(&mut self, rect: Rect<isize>, line_width: usize, color: Color) -> GameResult<()> { let mut refs = self.refs.borrow_mut(); + let blend = refs.blend_mode; + let canvas = refs.window.canvas(); let (r, g, b, a) = color.to_rgba(); - let blend = refs.blend_mode; - refs.canvas.set_draw_color(pixels::Color::RGBA(r, g, b, a)); - refs.canvas.set_blend_mode(blend); + canvas.set_draw_color(pixels::Color::RGBA(r, g, b, a)); + canvas.set_blend_mode(blend); match line_width { 0 => {} // no-op 1 => { - refs.canvas + canvas .draw_rect(sdl2::rect::Rect::new( rect.left as i32, rect.top as i32, @@ -563,7 +630,7 @@ impl BackendRenderer for SDL2Renderer { ), ]; - refs.canvas.fill_rects(&rects).map_err(|e| GameError::RenderError(e.to_string()))?; + canvas.fill_rects(&rects).map_err(|e| GameError::RenderError(e.to_string()))?; } } @@ -572,16 +639,17 @@ impl BackendRenderer for SDL2Renderer { fn set_clip_rect(&mut self, rect: Option<Rect>) -> GameResult { let mut refs = self.refs.borrow_mut(); + let canvas = refs.window.canvas(); if let Some(rect) = &rect { - refs.canvas.set_clip_rect(Some(sdl2::rect::Rect::new( + canvas.set_clip_rect(Some(sdl2::rect::Rect::new( rect.left as i32, rect.top as i32, rect.width() as u32, rect.height() as u32, ))); } else { - refs.canvas.set_clip_rect(None); + canvas.set_clip_rect(None); } Ok(()) @@ -602,19 +670,20 @@ impl BackendRenderer for SDL2Renderer { fn prepare_imgui(&mut self, ui: &Ui) -> GameResult { let refs = self.refs.borrow_mut(); - self.imgui_event.borrow_mut().prepare_render(ui, refs.canvas.window()); + self.imgui_event.borrow_mut().prepare_render(ui, refs.window.window()); Ok(()) } fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult { let mut refs = self.refs.borrow_mut(); + let canvas = refs.window.canvas(); for draw_list in draw_data.draw_lists() { for cmd in draw_list.commands() { match cmd { DrawCmd::Elements { count, cmd_params } => { - refs.canvas.set_clip_rect(Some(sdl2::rect::Rect::new( + canvas.set_clip_rect(Some(sdl2::rect::Rect::new( cmd_params.clip_rect[0] as i32, cmd_params.clip_rect[1] as i32, (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as u32, @@ -630,7 +699,7 @@ impl BackendRenderer for SDL2Renderer { let v0 = vtx_buffer.get_unchecked(cmd_params.vtx_offset); sdl2_sys::SDL_RenderGeometryRaw( - refs.canvas.raw(), + canvas.raw(), tex_ptr, v0.pos.as_ptr(), mem::size_of::<DrawVert>() as _, @@ -645,7 +714,7 @@ impl BackendRenderer for SDL2Renderer { ); } - refs.canvas.set_clip_rect(None); + canvas.set_clip_rect(None); } DrawCmd::ResetRenderState => {} DrawCmd::RawCallback { callback, raw_cmd } => unsafe { callback(draw_list.raw(), raw_cmd) }, @@ -686,7 +755,7 @@ impl BackendRenderer for SDL2Renderer { unsafe { // potential danger: we assume that the layout of VertexData is the same as SDL_Vertex sdl2_sys::SDL_RenderGeometry( - refs.canvas.raw(), + refs.window.canvas().raw(), texture_ptr, vertices.as_ptr() as *const sdl2_sys::SDL_Vertex, vertices.len() as i32, @@ -725,14 +794,16 @@ impl BackendTexture for SDL2Texture { None => Ok(()), Some(texture) => { let mut refs = self.refs.borrow_mut(); + let blend = refs.blend_mode; + let canvas = refs.window.canvas(); for command in &self.commands { match command { SpriteBatchCommand::DrawRect(src, dest) => { texture.set_color_mod(255, 255, 255); texture.set_alpha_mod(255); - texture.set_blend_mode(refs.blend_mode); + texture.set_blend_mode(blend); - refs.canvas + canvas .copy( texture, Some(sdl2::rect::Rect::new( @@ -754,9 +825,9 @@ impl BackendTexture for SDL2Texture { let (r, g, b, a) = color.to_rgba(); texture.set_color_mod(r, g, b); texture.set_alpha_mod(a); - texture.set_blend_mode(refs.blend_mode); + texture.set_blend_mode(blend); - refs.canvas + canvas .copy( texture, Some(sdl2::rect::Rect::new( @@ -777,9 +848,9 @@ impl BackendTexture for SDL2Texture { SpriteBatchCommand::DrawRectFlip(src, dest, flip_x, flip_y) => { texture.set_color_mod(255, 255, 255); texture.set_alpha_mod(255); - texture.set_blend_mode(refs.blend_mode); + texture.set_blend_mode(blend); - refs.canvas + canvas .copy_ex( texture, Some(sdl2::rect::Rect::new( diff --git a/src/framework/render_opengl.rs b/src/framework/render_opengl.rs index 03e4e5e..24e41df 100644 --- a/src/framework/render_opengl.rs +++ b/src/framework/render_opengl.rs @@ -628,7 +628,7 @@ impl BackendRenderer for OpenGLRenderer { if self.refs.gles2_mode { "OpenGL ES 2.0".to_string() } else { - "OpenGL 3".to_string() + "OpenGL 2.1".to_string() } } diff --git a/src/lib.rs b/src/lib.rs index e6313ed..ec7bc8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,13 +228,25 @@ pub fn init(options: LaunchOptions) -> GameResult { let mut bundle_dir = resource_dir.clone(); let _ = bundle_dir.pop(); let mut bundle_exec_dir = bundle_dir.clone(); + let mut csplus_data_dir = bundle_dir.clone(); + let _ = csplus_data_dir.pop(); + let _ = csplus_data_dir.pop(); + let mut csplus_data_base_dir = csplus_data_dir.clone(); + csplus_data_base_dir.push("data"); + csplus_data_base_dir.push("base"); bundle_exec_dir.push("MacOS"); bundle_dir.push("Resources"); if bundle_exec_dir.is_dir() && bundle_dir.is_dir() { log::info!("Running in macOS bundle mode"); - resource_dir = bundle_dir + + if csplus_data_base_dir.is_dir() { + log::info!("Cave Story+ Steam detected"); + resource_dir = csplus_data_dir; + } else { + resource_dir = bundle_dir; + } } }