softbuffer/src/lib.rs

121 lines
4.6 KiB
Rust
Raw Normal View History

2022-01-16 08:43:00 -06:00
#![doc = include_str!("../README.md")]
2022-01-19 11:59:43 +09:00
#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;
#[cfg(target_os = "windows")]
mod win32;
2022-01-19 11:59:43 +09:00
#[cfg(target_os = "macos")]
mod cg;
2022-01-16 08:59:29 -06:00
#[cfg(target_os = "linux")]
mod x11;
mod error;
pub use error::SoftBufferError;
2022-01-15 08:17:17 -06:00
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
2022-01-16 08:17:53 -06:00
/// An instance of this struct contains the platform-specific data that must be managed in order to
/// write to a window on that platform. This struct owns the window that this data corresponds to
/// to ensure safety, as that data must be destroyed before the window itself is destroyed. You may
/// access the underlying window via [`window`](Self::window) and [`window_mut`](Self::window_mut).
2022-01-16 08:59:29 -06:00
pub struct GraphicsContext<W: HasRawWindowHandle> {
2022-01-15 08:17:17 -06:00
window: W,
2022-01-16 08:59:29 -06:00
graphics_context_impl: Box<dyn GraphicsContextImpl>,
2022-01-15 08:17:17 -06:00
}
impl<W: HasRawWindowHandle> GraphicsContext<W> {
2022-01-16 08:17:53 -06:00
/// Creates a new instance of this struct, consuming the given window.
///
/// # Safety
///
/// - Ensure that the passed object is valid to draw a 2D buffer to
2022-01-16 08:59:29 -06:00
pub unsafe fn new(window: W) -> Result<Self, SoftBufferError<W>> {
2022-01-15 08:17:17 -06:00
let raw_handle = window.raw_window_handle();
2022-01-16 08:59:29 -06:00
let imple = match raw_handle {
#[cfg(target_os = "linux")]
2022-01-16 08:59:29 -06:00
RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11Impl::new(xlib_handle)?),
#[cfg(target_os = "windows")]
2022-01-16 08:59:29 -06:00
RawWindowHandle::Win32(win32_handle) => Box::new(win32::Win32Impl::new(&win32_handle)?),
2022-01-19 11:59:43 +09:00
#[cfg(target_os = "macos")]
RawWindowHandle::AppKit(appkit_handle) => Box::new(cg::CGImpl::new(appkit_handle)?),
2022-01-16 08:59:29 -06:00
unimplemented_handle_type => return Err(SoftBufferError::UnsupportedPlatform {
window,
human_readable_platform_name: window_handle_type_name(&unimplemented_handle_type),
handle: unimplemented_handle_type,
}),
2022-01-15 08:17:17 -06:00
};
2022-01-16 08:59:29 -06:00
Ok(Self {
2022-01-15 08:17:17 -06:00
window,
2022-01-16 08:59:29 -06:00
graphics_context_impl: imple,
})
2022-01-15 08:17:17 -06:00
}
2022-01-16 08:17:53 -06:00
/// Gets shared access to the underlying window
2022-01-15 08:17:17 -06:00
#[inline]
2022-01-16 08:59:29 -06:00
pub fn window(&self) -> &W {
2022-01-15 08:17:17 -06:00
&self.window
}
2022-01-16 08:17:53 -06:00
/// Gets mut/exclusive access to the underlying window
2022-01-15 08:17:17 -06:00
#[inline]
2022-01-16 08:59:29 -06:00
pub fn window_mut(&mut self) -> &mut W {
2022-01-15 08:17:17 -06:00
&mut self.window
}
2022-01-16 08:17:53 -06:00
/// Shows the given buffer with the given width and height on the window corresponding to this
/// graphics context. Panics if buffer.len() ≠ width*height. If the size of the buffer does
/// not match the size of the window, the buffer is drawn in the upper-left corner of the window.
/// It is recommended in most production use cases to have the buffer fill the entire window.
/// Use your windowing library to find the size of the window.
///
/// The format of the buffer is as follows. There is one u32 in the buffer for each pixel in
/// the area to draw. The first entry is the upper-left most pixel. The second is one to the right
/// etc. (Row-major top to bottom left to right one u32 per pixel). Within each u32 the highest
/// order 8 bits are to be set to 0. The next highest order 8 bits are the red channel, then the
/// green channel, and then the blue channel in the lowest-order 8 bits. See the examples for
/// one way to build this format using bitwise operations.
///
/// --------
///
/// Pixel format (u32):
///
/// 00000000RRRRRRRRGGGGGGGGBBBBBBBB
///
/// 0: Bit is 0
/// R: Red channel
/// G: Green channel
/// B: Blue channel
2022-01-15 08:17:17 -06:00
#[inline]
2022-01-16 08:59:29 -06:00
pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
if (width as usize) * (height as usize) != buffer.len() {
panic!("The size of the passed buffer is not the correct size. Its length must be exactly width*height.");
}
2022-01-15 08:17:17 -06:00
unsafe {
self.graphics_context_impl.set_buffer(buffer, width, height);
}
}
}
2022-01-16 08:59:29 -06:00
trait GraphicsContextImpl {
2022-01-15 08:17:17 -06:00
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16);
}
2022-01-16 08:59:29 -06:00
fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str {
match handle {
2022-01-15 08:17:17 -06:00
RawWindowHandle::Xlib(_) => "Xlib",
RawWindowHandle::Win32(_) => "Win32",
RawWindowHandle::WinRt(_) => "WinRt",
RawWindowHandle::Web(_) => "Web",
RawWindowHandle::Wayland(_) => "Wayland",
RawWindowHandle::AndroidNdk(_) => "AndroidNdk",
RawWindowHandle::AppKit(_) => "AppKit",
RawWindowHandle::Orbital(_) => "Orbital",
RawWindowHandle::UiKit(_) => "UiKit",
2022-01-16 08:59:29 -06:00
_ => "Unknown Name", //don't completely fail to compile if there is a new raw window handle type that's added at some point
2022-01-15 08:17:17 -06:00
}
2022-01-16 08:59:29 -06:00
}