From 7e3ec23dbddeeffb594f46fdefb4bdc908ad9f5b Mon Sep 17 00:00:00 2001 From: gram Date: Tue, 15 Oct 2024 17:35:40 +0200 Subject: [PATCH 1/8] move Image into graphics --- src/fs.rs | 42 +----------------------------------------- src/graphics/funcs.rs | 2 +- src/graphics/image.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/graphics/mod.rs | 2 ++ 4 files changed, 46 insertions(+), 42 deletions(-) create mode 100644 src/graphics/image.rs diff --git a/src/fs.rs b/src/fs.rs index f7f7350..210d463 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,6 +1,6 @@ //! Access file system: the game ROM files and the data dir. -use crate::graphics::{Point, Size}; +use crate::graphics::*; #[cfg(feature = "alloc")] use alloc::vec; #[cfg(feature = "alloc")] @@ -155,46 +155,6 @@ impl<'a> From<&'a FileBuf> for Font<'a> { } } -/// A loaded image file. -/// -/// Can be loaded as [`FileBuf`] from ROM with [`rom::load_buf`] -/// and then cast using [Into]. -pub struct Image<'a> { - pub(crate) raw: &'a [u8], -} - -impl<'a> From> for Image<'a> { - fn from(value: File<'a>) -> Self { - Self { raw: value.raw } - } -} - -#[cfg(feature = "alloc")] -impl<'a> From<&'a FileBuf> for Image<'a> { - fn from(value: &'a FileBuf) -> Self { - Self { raw: &value.raw } - } -} - -impl<'a> Image<'a> { - /// Get a rectangle subregion of the image. - #[must_use] - pub fn sub(&self, p: Point, s: Size) -> SubImage<'a> { - SubImage { - point: p, - size: s, - raw: self.raw, - } - } -} - -/// A subregion of an image. Constructed using [`Image::sub`]. -pub struct SubImage<'a> { - pub(crate) point: Point, - pub(crate) size: Size, - pub(crate) raw: &'a [u8], -} - mod bindings { #[link(wasm_import_module = "fs")] extern { diff --git a/src/graphics/funcs.rs b/src/graphics/funcs.rs index 5d04c08..053bac7 100644 --- a/src/graphics/funcs.rs +++ b/src/graphics/funcs.rs @@ -1,5 +1,5 @@ use super::{bindings as b, *}; -use crate::fs::{Font, Image, SubImage}; +use crate::*; /// Fill the whole frame with the given color. pub fn clear_screen(c: Color) { diff --git a/src/graphics/image.rs b/src/graphics/image.rs new file mode 100644 index 0000000..80fe312 --- /dev/null +++ b/src/graphics/image.rs @@ -0,0 +1,42 @@ +use crate::*; + +/// A loaded image file. +/// +/// Can be loaded as [`FileBuf`] from ROM with [`load_file_buf`] +/// and then cast using [Into]. +pub struct Image<'a> { + pub(crate) raw: &'a [u8], +} + +impl<'a> From> for Image<'a> { + fn from(value: File<'a>) -> Self { + Self { raw: value.raw } + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a FileBuf> for Image<'a> { + fn from(value: &'a FileBuf) -> Self { + Self { raw: &value.raw } + } +} + +impl<'a> Image<'a> { + /// Get a rectangle subregion of the image. + #[must_use] + pub fn sub(&self, p: Point, s: Size) -> SubImage<'a> { + SubImage { + point: p, + size: s, + raw: self.raw, + } + } +} + +/// A subregion of an image. Constructed using [`Image::sub`]. +#[expect(clippy::module_name_repetitions)] +pub struct SubImage<'a> { + pub(crate) point: Point, + pub(crate) size: Size, + pub(crate) raw: &'a [u8], +} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index ec5a970..c75fe29 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -3,12 +3,14 @@ mod angle; mod bindings; mod funcs; +mod image; mod point; mod size; mod types; pub use angle::*; pub use funcs::*; +pub use image::*; pub use point::*; pub use size::*; pub use types::*; From 70a6cea6079917b49d89eab1d8fb5cc64e4d3b36 Mon Sep 17 00:00:00 2001 From: gram Date: Tue, 15 Oct 2024 18:15:17 +0200 Subject: [PATCH 2/8] add getters for Image --- src/graphics/image.rs | 77 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/src/graphics/image.rs b/src/graphics/image.rs index 80fe312..23d5f1b 100644 --- a/src/graphics/image.rs +++ b/src/graphics/image.rs @@ -3,7 +3,7 @@ use crate::*; /// A loaded image file. /// /// Can be loaded as [`FileBuf`] from ROM with [`load_file_buf`] -/// and then cast using [Into]. +/// and then cast using [`Into`]. pub struct Image<'a> { pub(crate) raw: &'a [u8], } @@ -24,13 +24,86 @@ impl<'a> From<&'a FileBuf> for Image<'a> { impl<'a> Image<'a> { /// Get a rectangle subregion of the image. #[must_use] - pub fn sub(&self, p: Point, s: Size) -> SubImage<'a> { + pub const fn sub(&self, p: Point, s: Size) -> SubImage<'a> { SubImage { point: p, size: s, raw: self.raw, } } + + /// Bits per pixel. One of: 1, 2, or 4. + #[must_use] + pub const fn bpp(&self) -> u8 { + self.raw[1] + } + + /// The color used for transparency. If no transparency, returns [`Color::None`]. + #[must_use] + pub fn transparency(&self) -> Color { + let c = usize::from(self.raw[4]) + 1; + c.try_into().unwrap_or(Color::None) + } + + // pub fn set_transparency(&mut self, c: Color) { + // let c: i32 = c.into(); + // if c == 0 { + // self.raw[4] = 16; + // } else { + // self.raw[4] = c as u8; + // } + // } + + /// The number of pixels the image has. + #[must_use] + pub const fn pixels(&self) -> usize { + self.raw.len() * 8 / self.bpp() as usize + } + + /// The image width in pixels. + #[must_use] + pub fn width(&self) -> u16 { + let big = u16::from(self.raw[2]); + let little = u16::from(self.raw[3]); + big | (little << 8) + } + + /// The image height in pixels. + #[must_use] + pub fn height(&self) -> u16 { + let p = self.pixels(); + let w = self.width() as usize; + p.checked_div(w).unwrap_or(0) as u16 + } + + /// The image size in pixels. + #[must_use] + pub fn size(&self) -> Size { + Size { + width: i32::from(self.width()), + height: i32::from(self.height()), + } + } + + /// Get the color used to represent the given pixel value. + #[must_use] + pub fn get_color(&self, p: u8) -> Color { + if p > 15 { + return Color::None; + } + let byte_idx = usize::from(5 + p / 2); + let mut byte_val = self.raw[byte_idx]; + if p % 2 == 0 { + byte_val >>= 4; + } + byte_val &= 0b1111; + let transp = self.raw[4]; + if byte_val == transp { + return Color::None; + } + let color_val = usize::from(byte_val + 1); + color_val.try_into().unwrap_or(Color::None) + } } /// A subregion of an image. Constructed using [`Image::sub`]. From a64ce514b1ce169b6c8197c55764da4c52f06f25 Mon Sep 17 00:00:00 2001 From: gram Date: Tue, 15 Oct 2024 18:17:50 +0200 Subject: [PATCH 3/8] make all possible methods const --- src/fs.rs | 6 +++--- src/graphics/angle.rs | 4 ++-- src/graphics/point.rs | 2 +- src/graphics/size.rs | 2 +- src/graphics/types.rs | 2 +- src/sudo.rs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index 210d463..4fa761a 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -49,17 +49,17 @@ pub struct File<'a> { impl<'a> File<'a> { #[must_use] - pub fn data(&self) -> &[u8] { + pub const fn data(&self) -> &[u8] { self.raw } #[must_use] - pub fn as_font(&self) -> Font { + pub const fn as_font(&self) -> Font { Font { raw: self.raw } } #[must_use] - pub fn as_image(&self) -> Image { + pub const fn as_image(&self) -> Image { Image { raw: self.raw } } } diff --git a/src/graphics/angle.rs b/src/graphics/angle.rs index 973fbd5..ea2e702 100644 --- a/src/graphics/angle.rs +++ b/src/graphics/angle.rs @@ -26,7 +26,7 @@ impl Angle { /// An angle in radians where [TAU] (doubled [PI]) is the full circle. #[must_use] - pub fn from_radians(r: f32) -> Self { + pub const fn from_radians(r: f32) -> Self { Self(r) } @@ -50,7 +50,7 @@ impl Angle { /// Get the angle value in radians where [TAU] (doubled [PI]) is the full circle. #[must_use] - pub fn to_radians(self) -> f32 { + pub const fn to_radians(self) -> f32 { self.0 } diff --git a/src/graphics/point.rs b/src/graphics/point.rs index 0e62e04..765516a 100644 --- a/src/graphics/point.rs +++ b/src/graphics/point.rs @@ -32,7 +32,7 @@ impl Point { /// Set x and y to their absolute (non-negative) value. #[must_use] - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { Self { x: self.x.abs(), y: self.y.abs(), diff --git a/src/graphics/size.rs b/src/graphics/size.rs index bb1a11e..dbb9a41 100644 --- a/src/graphics/size.rs +++ b/src/graphics/size.rs @@ -35,7 +35,7 @@ impl Size { /// Set both width and height to their absolute (non-negative) value. #[must_use] - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { Self { width: self.width.abs(), height: self.height.abs(), diff --git a/src/graphics/types.rs b/src/graphics/types.rs index c88f4a0..c8871b2 100644 --- a/src/graphics/types.rs +++ b/src/graphics/types.rs @@ -36,7 +36,7 @@ impl Style { /// /// [`LineStyle`] is the same as [Style] except it doesn't have a fill color. #[must_use] - pub fn as_line_style(&self) -> LineStyle { + pub const fn as_line_style(&self) -> LineStyle { LineStyle { color: self.stroke_color, width: self.stroke_width, diff --git a/src/sudo.rs b/src/sudo.rs index 30109a1..5fd5d7c 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -57,7 +57,7 @@ impl<'a> Dir<'a> { /// Iterate over all loaded entries in the directory. #[must_use] - pub fn iter(&self) -> DirIter<'a> { + pub const fn iter(&self) -> DirIter<'a> { DirIter { raw: self.raw } } } From 0412e33170c10d5844005216fed1a1071a963d75 Mon Sep 17 00:00:00 2001 From: gram Date: Tue, 15 Oct 2024 18:30:17 +0200 Subject: [PATCH 4/8] add missing graphics docs --- src/graphics/mod.rs | 2 ++ src/graphics/point.rs | 3 +++ src/graphics/size.rs | 3 +++ src/graphics/types.rs | 22 ++++++++++++++++++++++ src/lib.rs | 5 ++++- 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index c75fe29..4af26d0 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,5 +1,7 @@ //! Draw shapes, images, and text on the screen. +#![deny(missing_docs)] + mod angle; mod bindings; mod funcs; diff --git a/src/graphics/point.rs b/src/graphics/point.rs index 765516a..bb8501e 100644 --- a/src/graphics/point.rs +++ b/src/graphics/point.rs @@ -9,7 +9,9 @@ use nalgebra::{base::Scalar, Vector2}; /// Typically, the upper-left corner of a bounding box of a shape. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct Point { + /// Pixel distance from left. pub x: i32, + /// Pixel distance from the top. pub y: i32, } @@ -22,6 +24,7 @@ impl Point { /// The coordinate of the top-left corner on the screen. pub const MIN: Point = Point { x: 0, y: 0 }; + /// Create a new point casting the argument types. #[must_use] pub fn new>(x: I, y: I) -> Self { Self { diff --git a/src/graphics/size.rs b/src/graphics/size.rs index dbb9a41..8c2fb9a 100644 --- a/src/graphics/size.rs +++ b/src/graphics/size.rs @@ -14,7 +14,9 @@ pub const HEIGHT: i32 = 160; /// The width and height must be positive. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct Size { + /// Horizontal size in pixels. pub width: i32, + /// Vertical size in pixels. pub height: i32, } @@ -25,6 +27,7 @@ impl Size { height: HEIGHT, }; + /// Create a new size casting the argument types. #[must_use] pub fn new>(width: I, height: I) -> Self { Self { diff --git a/src/graphics/types.rs b/src/graphics/types.rs index c8871b2..1a9b8ce 100644 --- a/src/graphics/types.rs +++ b/src/graphics/types.rs @@ -1,8 +1,11 @@ /// The RGB value of a color in the palette. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct RGB { + /// Red component. pub r: u8, + /// Green component. pub g: u8, + /// Blue component. pub b: u8, } @@ -47,7 +50,9 @@ impl Style { /// The same as [Style] but without a fill color (only stroke color and width). #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] pub struct LineStyle { + /// The line stroke color. pub color: Color, + /// The line stroke width. pub width: i32, } @@ -63,22 +68,39 @@ impl From