diff --git a/ggdt/src/graphics/basicimage.rs b/ggdt/src/graphics/basicimage.rs index 010847b..6c9ecb9 100644 --- a/ggdt/src/graphics/basicimage.rs +++ b/ggdt/src/graphics/basicimage.rs @@ -5,22 +5,31 @@ //! //! Only a subset of the most common Bitmap drawing operations will be provided here. +use std::error::Error; + use num_traits::{PrimInt, Unsigned}; use crate::graphics::indexed; use crate::math::Rect; -pub enum BasicBlitMethod -where PixelType: PrimInt + Unsigned { +// HACK: enum variant color arguments are sized to the max possible pixel type used across all supported bitmap variants +// right now. for some reason, making this enum generic (e.g. `BasicBlitMethod`) +// resulted in some E0308 compile errors when trying to create enum variant values that contained args of the +// generic type. i could not find a solution to this. so i'll just do this hack approach for now. ugh. +pub enum BasicBlitMethod { Solid, - Transparent(PixelType), + Transparent(u32), } /// Trait that provides "bit-depth-agnostic" access to bitmap drawing operations. This is useful for implementing /// drawing functionality that is to be made generic across all supported bitmap types and is not specific to /// any one pixel-depth. Note that this does not provide cross-bit-depth drawing support. -pub trait BasicImage { +pub trait BasicImage: Sized { type PixelType: PrimInt + Unsigned; + type ErrorType: Error; + + /// Creates a new bitmap with the specified dimensions, in pixels. + fn new(width: u32, height: u32) -> Result; /// Returns the width of the bitmap in pixels. fn width(&self) -> u32; @@ -73,14 +82,14 @@ pub trait BasicImage { fn blit_region( &mut self, - method: BasicBlitMethod, + method: BasicBlitMethod, src: &Self, src_region: &Rect, dest_x: i32, dest_y: i32 ); - fn blit(&mut self, method: BasicBlitMethod, src: &Self, x: i32, y: i32) { + fn blit(&mut self, method: BasicBlitMethod, src: &Self, x: i32, y: i32) { let src_region = Rect::new(0, 0, src.width(), src.height()); self.blit_region(method, src, &src_region, x, y); } @@ -88,6 +97,11 @@ pub trait BasicImage { impl BasicImage for indexed::Bitmap { type PixelType = u8; + type ErrorType = indexed::BitmapError; + + fn new(width: u32, height: u32) -> Result { + Self::new(width, height) + } #[inline] fn width(&self) -> u32 { @@ -156,15 +170,16 @@ impl BasicImage for indexed::Bitmap { fn blit_region( &mut self, - method: BasicBlitMethod, + method: BasicBlitMethod, src: &Self, src_region: &Rect, dest_x: i32, dest_y: i32 ) { + // HACK: pixel/color value downcasting. see "HACK" comment above BasicBlitMethod type def let blit_method = match method { BasicBlitMethod::Solid => indexed::BlitMethod::Solid, - BasicBlitMethod::Transparent(color) => indexed::BlitMethod::Transparent(color), + BasicBlitMethod::Transparent(color) => indexed::BlitMethod::Transparent(color as u8), }; self.blit_region(blit_method, src, src_region, dest_x, dest_y) } diff --git a/ggdt/src/system/input_devices/mouse/cursor.rs b/ggdt/src/system/input_devices/mouse/cursor.rs index 3039d36..20717f6 100644 --- a/ggdt/src/system/input_devices/mouse/cursor.rs +++ b/ggdt/src/system/input_devices/mouse/cursor.rs @@ -2,6 +2,7 @@ // that are not specific to just our 256 colour Bitmap functionality. whether this takes the form // of a generified CustomMouseCursor struct, or multiple versions ... well, i'm not quite sure yet! +use crate::graphics::*; use crate::graphics::indexed::*; use crate::math::*; @@ -12,40 +13,34 @@ const DEFAULT_MOUSE_CURSOR_HOTSPOT_Y: u32 = 0; const DEFAULT_MOUSE_CURSOR_WIDTH: usize = 16; const DEFAULT_MOUSE_CURSOR_HEIGHT: usize = 16; -#[rustfmt::skip] -const DEFAULT_MOUSE_CURSOR: [u8; DEFAULT_MOUSE_CURSOR_WIDTH * DEFAULT_MOUSE_CURSOR_HEIGHT] = [ - 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -]; +pub trait DefaultMouseCursorBitmaps +where + BitmapType: BasicImage +{ + fn get_default() -> BitmapType; +} /// Provides custom mouse cursor rendering functionality via application provided [`Bitmap`]s (or falling back /// to a default cursor if none is set by the application). Custom cursor rendering is disabled by default. #[derive(Debug)] -pub struct CustomMouseCursor { +pub struct CustomMouseCursor +where + BitmapType: BasicImage +{ last_x: i32, last_y: i32, - cursor: Bitmap, - cursor_background: Bitmap, + cursor: BitmapType, + cursor_background: BitmapType, cursor_hotspot_x: u32, cursor_hotspot_y: u32, cursor_enabled: bool, } -impl CustomMouseCursor { +impl CustomMouseCursor +where + Self: DefaultMouseCursorBitmaps, + BitmapType: BasicImage +{ pub fn new() -> Self { let (cursor, cursor_background, cursor_hotspot_x, cursor_hotspot_y) = Self::get_default_mouse_cursor(); @@ -62,7 +57,7 @@ impl CustomMouseCursor { /// Returns a reference to the current mouse cursor bitmap. #[inline] - pub fn cursor_bitmap(&self) -> &Bitmap { + pub fn cursor_bitmap(&self) -> &BitmapType { &self.cursor } @@ -98,9 +93,9 @@ impl CustomMouseCursor { /// * `cursor`: the bitmap to be used to display the mouse cursor on screen /// * `hotspot_x`: the "hotspot" x coordinate /// * `hotspot_y`: the "hotspot" y coordinate. - pub fn set_mouse_cursor(&mut self, cursor: Bitmap, hotspot_x: u32, hotspot_y: u32) { + pub fn set_mouse_cursor(&mut self, cursor: BitmapType, hotspot_x: u32, hotspot_y: u32) { self.cursor = cursor; - self.cursor_background = Bitmap::new(self.cursor.width(), self.cursor.height()).unwrap(); + self.cursor_background = BitmapType::new(self.cursor.width(), self.cursor.height()).unwrap(); self.cursor_hotspot_x = hotspot_x; self.cursor_hotspot_y = hotspot_y; } @@ -134,7 +129,7 @@ impl CustomMouseCursor { /// /// [`SystemResources`]: crate::system::SystemResources /// [`SystemResources::display`]: crate::system::SystemResources::display - pub fn render(&mut self, dest: &mut Bitmap) { + pub fn render(&mut self, dest: &mut BitmapType) { if !self.cursor_enabled { return; } @@ -143,14 +138,15 @@ impl CustomMouseCursor { // preserve existing background first self.cursor_background.blit_region( - BlitMethod::Solid, + BasicBlitMethod::Solid, &dest, &Rect::new(x, y, self.cursor.width(), self.cursor.height()), 0, 0, ); - dest.blit(BlitMethod::Transparent(255), &self.cursor, x, y); + let color = 255; + dest.blit(BasicBlitMethod::Transparent(color), &self.cursor, x, y); } /// Restores the original destination bitmap contents where the mouse cursor bitmap was @@ -164,13 +160,13 @@ impl CustomMouseCursor { /// /// [`SystemResources`]: crate::system::SystemResources /// [`SystemResources::display`]: crate::system::SystemResources::display - pub fn hide(&mut self, dest: &mut Bitmap) { + pub fn hide(&mut self, dest: &mut BitmapType) { if !self.cursor_enabled { return; } let (x, y) = self.get_cursor_render_position(); - dest.blit(BlitMethod::Solid, &self.cursor_background, x, y); + dest.blit(BasicBlitMethod::Solid, &self.cursor_background, x, y); } /// Updates current state from the given [`Mouse`] device's state, ensuring that subsequent calls to render @@ -183,15 +179,9 @@ impl CustomMouseCursor { self.last_y = mouse.y; } - fn get_default_mouse_cursor() -> (Bitmap, Bitmap, u32, u32) { - let mut cursor = Bitmap::new( - DEFAULT_MOUSE_CURSOR_WIDTH as u32, - DEFAULT_MOUSE_CURSOR_HEIGHT as u32, - ) - .unwrap(); - cursor.pixels_mut().copy_from_slice(&DEFAULT_MOUSE_CURSOR); - - let cursor_background = Bitmap::new(cursor.width(), cursor.height()).unwrap(); + fn get_default_mouse_cursor() -> (BitmapType, BitmapType, u32, u32) { + let cursor = Self::get_default(); + let cursor_background = BitmapType::new(cursor.width(), cursor.height()).unwrap(); ( cursor, @@ -200,4 +190,37 @@ impl CustomMouseCursor { DEFAULT_MOUSE_CURSOR_HOTSPOT_Y, ) } -} \ No newline at end of file +} + +impl DefaultMouseCursorBitmaps for CustomMouseCursor { + fn get_default() -> Bitmap { + #[rustfmt::skip] + const CURSOR_PIXELS: [u8; DEFAULT_MOUSE_CURSOR_WIDTH * DEFAULT_MOUSE_CURSOR_HEIGHT] = [ + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ]; + + let mut cursor = Bitmap::new( + DEFAULT_MOUSE_CURSOR_WIDTH as u32, + DEFAULT_MOUSE_CURSOR_HEIGHT as u32, + ).unwrap(); + cursor.pixels_mut().copy_from_slice(&CURSOR_PIXELS); + cursor + } +} + +// TODO: other DefaultMouseCursorBitmaps impl's here ... when the other bitmap types are added diff --git a/ggdt/src/system/res/dos_like.rs b/ggdt/src/system/res/dos_like.rs index c4b42d8..0c6dcf6 100644 --- a/ggdt/src/system/res/dos_like.rs +++ b/ggdt/src/system/res/dos_like.rs @@ -224,7 +224,7 @@ pub struct DosLike { /// Manages custom mouse cursor graphics and state. Use this to set/unset a custom mouse cursor bitmap. /// When set, rendering should occur automatically during calls to [`SystemResources::display`]. - pub cursor: CustomMouseCursor, + pub cursor: CustomMouseCursor, } impl std::fmt::Debug for DosLike {