Browse Source

Trimming works, finally

pull/137/head
Andrea Ciliberti 1 year ago
parent
commit
2453499d58
  1. 10
      ctru-rs/examples/camera-image.rs
  2. 158
      ctru-rs/src/services/cam.rs
  3. 4
      ctru-rs/src/services/hid.rs

10
ctru-rs/examples/camera-image.rs

@ -11,9 +11,6 @@ use ctru::services::gspgpu::FramebufferFormat;
use std::time::Duration; use std::time::Duration;
const WIDTH: i16 = 400;
const HEIGHT: i16 = 240;
const WAIT_TIMEOUT: Duration = Duration::from_millis(300); const WAIT_TIMEOUT: Duration = Duration::from_millis(300);
fn main() { fn main() {
@ -51,10 +48,9 @@ fn main() {
camera camera
.set_white_balance(WhiteBalance::Auto) .set_white_balance(WhiteBalance::Auto)
.expect("Failed to enable auto white balance"); .expect("Failed to enable auto white balance");
camera.set_trimming(Trimming::Centered {
width: WIDTH, // Un-comment this line and see how it changes!
height: HEIGHT, // camera.set_trimming(Trimming::Centered(ViewSize::BottomLCD));
});
// We don't intend on making any other modifications to the camera, so this size should be enough. // We don't intend on making any other modifications to the camera, so this size should be enough.
let len = camera.max_byte_count(); let len = camera.max_byte_count();

158
ctru-rs/src/services/cam.rs

@ -110,7 +110,7 @@ pub enum FrameRate {
/// White balance settings. /// White balance settings.
/// ///
/// See [`Camera::set_white_balance()`] and [`Camera::set_white_balance_without_base_up()`] to learn how to use this. /// See [`Camera::set_white_balance()`] to learn how to use this.
#[doc(alias = "CAMU_WhiteBalance")] #[doc(alias = "CAMU_WhiteBalance")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)] #[repr(u32)]
@ -230,22 +230,11 @@ pub enum ShutterSound {
} }
/// Configuration to handle image trimming. /// Configuration to handle image trimming.
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Trimming { pub enum Trimming {
/// Trimming configuration based on absolute coordinates of the image.
Absolute {
/// Top-left corner coordinates (x,y) of the trimmed area.
top_left: (i16, i16),
/// Bottom-right corner coordinates (x,y) of the trimmed area.
bottom_right: (i16, i16),
},
/// Trimming configuration relatively to the center of the image. /// Trimming configuration relatively to the center of the image.
Centered { Centered(ViewSize),
/// Width of the trimmed area.
width: i16,
/// Height of the trimmed area.
height: i16,
},
/// Trimming disabled. /// Trimming disabled.
Off, Off,
} }
@ -324,36 +313,12 @@ impl BothOutwardCam {
macro_rules! trimming_checks { macro_rules! trimming_checks {
($trimming:ident, $view_size:expr) => { ($trimming:ident, $view_size:expr) => {
match $trimming { match $trimming {
Trimming::Absolute { Trimming::Centered(trim_size) => {
top_left,
bottom_right,
} => {
let view_size: (i16, i16) = $view_size; let view_size: (i16, i16) = $view_size;
let trim_size: (i16, i16) = trim_size.into();
// Top left corner is "before" bottom right corner.
assert!(top_left.0 <= bottom_right.0 && top_left.1 <= bottom_right.1);
// All coordinates are positive.
assert!(
top_left.0 >= 0
&& top_left.1 >= 0
&& bottom_right.0 >= 0
&& bottom_right.1 >= 0
);
// All coordinates are within the view.
assert!(
top_left.0 < view_size.0
&& bottom_right.0 < view_size.0
&& top_left.1 < view_size.1
&& bottom_right.1 < view_size.1
);
}
Trimming::Centered { width, height } => {
let view_size: (i16, i16) = $view_size;
// Trim sizes are positive.
assert!(width >= 0 && height >= 0);
// Trim sizes are within the view. // Trim sizes are within the view.
assert!(width <= view_size.0 && height <= view_size.1); assert!(trim_size.0 <= view_size.0 && trim_size.1 <= view_size.1);
} }
Trimming::Off => (), Trimming::Off => (),
} }
@ -522,7 +487,8 @@ pub trait Camera {
/// # Notes /// # Notes
/// ///
/// This view is the full resolution at which the camera will take the photo. /// This view is the full resolution at which the camera will take the photo.
/// If you are interested in the final image dimension, after all processing and modifications, have a look at [`Camera::final_image_size()`]. /// If you are interested in the final image's size, calculated while taking into account all processing and modifications,
/// have a look at [`Camera::final_view_size()`].
fn view_size(&self) -> ViewSize; fn view_size(&self) -> ViewSize;
/// Returns the raw port of the selected camera. /// Returns the raw port of the selected camera.
@ -558,9 +524,13 @@ pub trait Camera {
} }
} }
/// Returns the maximum amount of bytes the final image will occupy based on the view size, trimming, pixel depth and other /// Returns the maximum amount of bytes the final image will occupy in memory based on the view size, trimming, pixel depth and other
/// modifications set to the camera. /// modifications set to the camera.
/// ///
/// # Notes
///
/// Remember to query this information again if *any* changes are applied to the [`Camera`] configuration!
///
/// # Example /// # Example
/// ///
/// ```no_run /// ```no_run
@ -572,20 +542,19 @@ pub trait Camera {
/// ///
/// let inward = &cam.inner_cam; /// let inward = &cam.inner_cam;
/// ///
/// let transfer_count = inward.max_byte_count(); /// let transfer_count = inward.final_byte_length();
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[doc(alias = "CAMU_GetTransferBytes")] fn final_byte_length(&self) -> usize {
fn max_byte_count(&self) -> usize { let size = self.final_view_size();
let size = self.final_image_size();
let mut res: usize = (size.0 as usize * size.1 as usize) * std::mem::size_of::<i16>(); let mut res: usize = (size.0 as usize * size.1 as usize) * std::mem::size_of::<i16>();
// If we are taking a picture using both outwards cameras, we need to expect 2 images, rather than just 1 // If we are taking a picture using both outwards cameras, we need to expect 2 images, rather than just 1
if self.port_as_raw() == ctru_sys::PORT_BOTH { if self.port_as_raw() == ctru_sys::PORT_BOTH {
res = res * 2; res *= 2;
} }
res res
@ -594,35 +563,33 @@ pub trait Camera {
/// Returns the dimensions of the final image based on the view size, trimming and other /// Returns the dimensions of the final image based on the view size, trimming and other
/// modifications set to the camera. /// modifications set to the camera.
/// ///
/// # Notes
///
/// Remember to query this information again if *any* changes are applied to the [`Camera`] configuration!
///
/// # Example /// # Example
/// ///
/// ```no_run /// ```no_run
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # /// #
/// use ctru::services::cam::{Cam, Camera}; /// use ctru::services::cam::{Cam, Camera, Trimming, ViewSize};
/// let cam = Cam::new()?; /// let mut cam = Cam::new()?;
/// ///
/// let mut inward = &cam.inner_cam; /// let mut inward = &mut cam.inner_cam;
/// ///
/// inward.set_trimming(Trimming::Centered { /// // We trim the image down so that it fits on a DS screen!
/// width: 100, /// inward.set_trimming(Trimming::Centered(ViewSize::DS));
/// height: 100,
/// });
/// ///
/// // This result will take into account the trimming. /// // This result will take into account the trimming.
/// let final_resolution = inward.final_image_size(); /// let final_resolution = inward.final_view_size();
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn final_image_size(&self) -> (i16, i16) { fn final_view_size(&self) -> (i16, i16) {
match self.trimming() { match self.trimming() {
Trimming::Absolute { Trimming::Centered(trim_size) => trim_size.into(),
top_left,
bottom_right,
} => (bottom_right.0 - top_left.0, bottom_right.1 - top_left.1),
Trimming::Centered { width, height } => (width, height),
Trimming::Off => self.view_size().into(), Trimming::Off => self.view_size().into(),
} }
} }
@ -905,74 +872,50 @@ pub trait Camera {
/// # use std::time::Duration; /// # use std::time::Duration;
/// # fn main() -> Result<(), Box<dyn Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # /// #
/// use ctru::services::cam::{Cam, Camera, ViewSize, OutputFormat}; /// use ctru::services::cam::{Cam, Camera, ViewSize, OutputFormat, WhiteBalance};
/// let mut cam = Cam::new()?; /// let mut cam = Cam::new()?;
/// ///
/// // We borrow the inward facing `Camera`. /// // We borrow the inward facing `Camera`.
/// let inward = &mut cam.inner_cam; /// let camera = &mut cam.inner_cam;
/// ///
/// inward.set_view_size(ViewSize::TopLCD)?; /// camera.set_view_size(ViewSize::TopLCD)?;
/// inward.set_output_format(OutputFormat::Rgb565)?; /// camera.set_output_format(OutputFormat::Rgb565)?;
/// inward.set_noise_filter(true)?; /// camera.set_noise_filter(true)?;
/// inward.set_auto_exposure(true)?; /// camera.set_auto_exposure(true)?;
/// inward.set_auto_white_balance(true)?; /// camera.set_white_balance(WhiteBalance::Auto)?;
/// ///
/// // Size of the top screen buffer at 2 bytes per pixel (RGB565). /// // Size of the top screen buffer at 2 bytes per pixel (RGB565).
/// let mut buffer = vec![0; 400*240*2]; /// let mut buffer = vec![0; camera.final_byte_length()];
/// ///
/// // Take picture with 3 seconds of timeout. /// // Take picture with 3 seconds of timeout.
/// inward.take_picture(&mut buffer, 400, 240, Duration::from_secs(3)); /// camera.take_picture(&mut buffer, Duration::from_secs(3));
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn take_picture(&mut self, buffer: &mut [u8], timeout: Duration) -> crate::Result<()> { fn take_picture(&mut self, buffer: &mut [u8], timeout: Duration) -> crate::Result<()> {
let full_view: (i16, i16) = self.view_size().into();
// It seems like doing this as the first step gives the option to use trimming and get correct readings for the transfer bytes.
unsafe {
ResultCode(ctru_sys::CAMU_Activate(self.camera_as_raw()))?;
};
// Obtain the final view size and make the needed modifications to the camera. // Obtain the final view size and make the needed modifications to the camera.
let final_view: (i16, i16) = match self.trimming() { match self.trimming() {
Trimming::Absolute { Trimming::Centered(trim_size) => unsafe {
top_left,
bottom_right,
} => unsafe {
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?; ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?;
ResultCode(ctru_sys::CAMU_SetTrimmingParams( let full_view: (i16, i16) = self.view_size().into();
self.port_as_raw(), let trim_size: (i16, i16) = trim_size.into();
top_left.0,
top_left.1,
bottom_right.0,
bottom_right.1,
))?;
(bottom_right.0 - top_left.0, bottom_right.1 - top_left.1)
},
Trimming::Centered { width, height } => unsafe {
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?;
ResultCode(ctru_sys::CAMU_SetTrimmingParamsCenter( ResultCode(ctru_sys::CAMU_SetTrimmingParamsCenter(
self.port_as_raw(), self.port_as_raw(),
width, trim_size.0,
height, trim_size.1,
full_view.0, full_view.0,
full_view.1, full_view.1,
))?; ))?;
(width, height)
}, },
Trimming::Off => unsafe { Trimming::Off => unsafe {
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), false))?; ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), false))?;
full_view
}, },
}; };
println!("CAMU_GetMaxBytes{:?}", final_view); let final_view = self.final_view_size();
// The transfer unit is NOT the "max number of bytes" or whatever the docs make you think it is... // The transfer unit is NOT the "max number of bytes" or whatever the docs make you think it is...
let transfer_unit = unsafe { let transfer_unit = unsafe {
@ -980,8 +923,8 @@ pub trait Camera {
ResultCode(ctru_sys::CAMU_GetMaxBytes( ResultCode(ctru_sys::CAMU_GetMaxBytes(
&mut transfer_unit, &mut transfer_unit,
full_view.0, final_view.0,
full_view.1, final_view.1,
))?; ))?;
transfer_unit transfer_unit
@ -997,7 +940,7 @@ pub trait Camera {
}; };
// Check whether the input buffer is big enough for the image. // Check whether the input buffer is big enough for the image.
let max_size = (final_view.0 as usize * final_view.1 as usize) * std::mem::size_of::<i16>(); let max_size = self.final_byte_length();
if buffer.len() < max_size { if buffer.len() < max_size {
// We deactivate the camera prematurely. // We deactivate the camera prematurely.
// //
@ -1011,6 +954,11 @@ pub trait Camera {
}); });
} }
unsafe {
ResultCode(ctru_sys::CAMU_Activate(self.camera_as_raw()))?;
ResultCode(ctru_sys::CAMU_ClearBuffer(self.port_as_raw()))?;
};
let receive_event = unsafe { let receive_event = unsafe {
let mut completion_handle: Handle = 0; let mut completion_handle: Handle = 0;

4
ctru-rs/src/services/hid.rs

@ -1,7 +1,7 @@
//! Human Interface Device service. //! Human Interface Device service.
//! //!
//! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position), //! The HID service provides read access to user input such as [button presses](Hid::keys_down), [touch screen presses](Hid::touch_position),
//! and [circle pad information](Hid::circlepad_position). It also provides information from the [volume slider](Hid::slider_volume()), //! and [circle pad information](Hid::circlepad_position). It also provides information from the [volume slider](Hid::volume_slider()),
//! the [accelerometer](Hid::accelerometer_vector()), and the [gyroscope](Hid::gyroscope_rate()). //! the [accelerometer](Hid::accelerometer_vector()), and the [gyroscope](Hid::gyroscope_rate()).
#![doc(alias = "input")] #![doc(alias = "input")]
#![doc(alias = "controller")] #![doc(alias = "controller")]
@ -338,7 +338,7 @@ impl Hid {
/// ///
/// hid.scan_input(); /// hid.scan_input();
/// ///
/// let volume = hid.slider_volume(); /// let volume = hid.volume_slider();
/// # /// #
/// # Ok(()) /// # Ok(())
/// # } /// # }

Loading…
Cancel
Save