diff --git a/Cargo.toml b/Cargo.toml index 57892c2..b16ec22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,10 @@ x11-dl = "2.19.1" [target.'cfg(target_os = "windows")'.dependencies] winapi = "0.3.9" +[target.'cfg(target_os = "macos")'.dependencies] +core-graphics = "0.22.3" +objc = "0.2.7" + [dev-dependencies] winit = "0.26.1" image = "0.23.14" \ No newline at end of file diff --git a/src/cg.rs b/src/cg.rs new file mode 100644 index 0000000..4cc1700 --- /dev/null +++ b/src/cg.rs @@ -0,0 +1,55 @@ +use crate::{GraphicsContextImpl, SoftBufferError}; +use raw_window_handle::{HasRawWindowHandle, AppKitHandle}; +use objc::runtime::Object; +use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault}; +use core_graphics::color_space::CGColorSpace; +use core_graphics::context::CGContext; +use core_graphics::data_provider::CGDataProvider; +use core_graphics::geometry::{CGPoint, CGSize, CGRect}; +use core_graphics::image::CGImage; +use core_graphics::sys; + +pub struct CGImpl; + +impl CGImpl { + pub unsafe fn new(handle: AppKitHandle) -> Result> { + let window = handle.ns_window as *mut Object; + let cls = class!(NSGraphicsContext); + let graphics_context: *mut Object = msg_send![cls, graphicsContextWithWindow:window]; + if graphics_context.is_null() { + return Err(SoftBufferError::PlatformError(Some("Graphics context is null".into()), None)); + } + let _: () = msg_send![cls, setCurrentContext:graphics_context]; + Ok(Self) + } +} + +impl GraphicsContextImpl for CGImpl { + unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { + let cls = class!(NSGraphicsContext); + let graphics_context: *mut Object = msg_send![cls, currentContext]; + let context_ptr: *mut sys::CGContext = msg_send![graphics_context, CGContext]; + let context = CGContext::from_existing_context_ptr(context_ptr); + let color_space = CGColorSpace::create_device_rgb(); + let slice = std::slice::from_raw_parts( + buffer.as_ptr() as *const u8, + buffer.len() * 4); + let data_provider = CGDataProvider::from_slice(slice); + let image = CGImage::new( + width as usize, + height as usize, + 8, + 32, + (width * 4) as usize, + &color_space, + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, + &data_provider, + false, + kCGRenderingIntentDefault, + ); + let origin = CGPoint { x: 0f64, y: 0f64 }; + let size = CGSize { width: width as f64, height: height as f64 }; + let rect = CGRect { origin, size }; + context.draw_image(rect, &image); + } +} diff --git a/src/lib.rs b/src/lib.rs index 13afed2..ec97655 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,13 @@ #![doc = include_str!("../README.md")] +#[cfg(target_os = "macos")] +#[macro_use] +extern crate objc; + #[cfg(target_os = "windows")] mod win32; +#[cfg(target_os = "macos")] +mod cg; #[cfg(target_os = "linux")] mod x11; @@ -32,6 +38,8 @@ impl GraphicsContext { RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11Impl::new(xlib_handle)?), #[cfg(target_os = "windows")] RawWindowHandle::Win32(win32_handle) => Box::new(win32::Win32Impl::new(&win32_handle)?), + #[cfg(target_os = "macos")] + RawWindowHandle::AppKit(appkit_handle) => Box::new(cg::CGImpl::new(appkit_handle)?), unimplemented_handle_type => return Err(SoftBufferError::UnsupportedPlatform { window, human_readable_platform_name: window_handle_type_name(&unimplemented_handle_type),