|
|
@ -261,27 +261,40 @@ pub struct ImageQualityCalibrationData(pub ctru_sys::CAMU_ImageQualityCalibratio |
|
|
|
#[derive(Default, Clone, Copy, Debug)] |
|
|
|
#[derive(Default, Clone, Copy, Debug)] |
|
|
|
pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData); |
|
|
|
pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Basic configuration needed to properly use the built-in cameras.
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)] |
|
|
|
|
|
|
|
struct Configuration { |
|
|
|
|
|
|
|
view_size: ViewSize, |
|
|
|
|
|
|
|
trimming: Trimming, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Configuration { |
|
|
|
|
|
|
|
fn new() -> Self { |
|
|
|
|
|
|
|
Self { |
|
|
|
|
|
|
|
view_size: ViewSize::TopLCD, |
|
|
|
|
|
|
|
trimming: Trimming::Off, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Inward camera representation (facing the user of the 3DS).
|
|
|
|
/// Inward camera representation (facing the user of the 3DS).
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Usually used for selfies.
|
|
|
|
/// Usually used for selfies.
|
|
|
|
#[non_exhaustive] |
|
|
|
#[non_exhaustive] |
|
|
|
pub struct InwardCam { |
|
|
|
pub struct InwardCam { |
|
|
|
view_size: ViewSize, |
|
|
|
configuration: Configuration, |
|
|
|
trimming: Trimming, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Right-side outward camera representation.
|
|
|
|
/// Right-side outward camera representation.
|
|
|
|
#[non_exhaustive] |
|
|
|
#[non_exhaustive] |
|
|
|
pub struct OutwardRightCam { |
|
|
|
pub struct OutwardRightCam { |
|
|
|
view_size: ViewSize, |
|
|
|
configuration: Configuration, |
|
|
|
trimming: Trimming, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Left-side outward camera representation.
|
|
|
|
/// Left-side outward camera representation.
|
|
|
|
#[non_exhaustive] |
|
|
|
#[non_exhaustive] |
|
|
|
pub struct OutwardLeftCam { |
|
|
|
pub struct OutwardLeftCam { |
|
|
|
view_size: ViewSize, |
|
|
|
configuration: Configuration, |
|
|
|
trimming: Trimming, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Both outer cameras combined.
|
|
|
|
/// Both outer cameras combined.
|
|
|
@ -289,8 +302,7 @@ pub struct OutwardLeftCam { |
|
|
|
/// Usually used for 3D photos.
|
|
|
|
/// Usually used for 3D photos.
|
|
|
|
#[non_exhaustive] |
|
|
|
#[non_exhaustive] |
|
|
|
pub struct BothOutwardCam { |
|
|
|
pub struct BothOutwardCam { |
|
|
|
view_size: ViewSize, |
|
|
|
configuration: Configuration, |
|
|
|
trimming: Trimming, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl BothOutwardCam { |
|
|
|
impl BothOutwardCam { |
|
|
@ -309,13 +321,52 @@ impl BothOutwardCam { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! trimming_checks { |
|
|
|
|
|
|
|
($trimming:ident, $view_size:expr) => { |
|
|
|
|
|
|
|
match $trimming { |
|
|
|
|
|
|
|
Trimming::Absolute { |
|
|
|
|
|
|
|
top_left, |
|
|
|
|
|
|
|
bottom_right, |
|
|
|
|
|
|
|
} => { |
|
|
|
|
|
|
|
let view_size: (i16, i16) = $view_size; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
assert!(width <= view_size.0 && height <= view_size.1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Trimming::Off => (), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Camera for InwardCam { |
|
|
|
impl Camera for InwardCam { |
|
|
|
fn camera_as_raw(&self) -> ctru_sys::u32_ { |
|
|
|
fn camera_as_raw(&self) -> ctru_sys::u32_ { |
|
|
|
ctru_sys::SELECT_IN1 |
|
|
|
ctru_sys::SELECT_IN1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
self.view_size |
|
|
|
self.configuration.view_size |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
@ -327,7 +378,7 @@ impl Camera for InwardCam { |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
self.view_size = size; |
|
|
|
self.configuration.view_size = size; |
|
|
|
|
|
|
|
|
|
|
|
self.set_trimming(Trimming::Off); |
|
|
|
self.set_trimming(Trimming::Off); |
|
|
|
|
|
|
|
|
|
|
@ -335,67 +386,14 @@ impl Camera for InwardCam { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn trimming(&self) -> Trimming { |
|
|
|
fn trimming(&self) -> Trimming { |
|
|
|
self.trimming |
|
|
|
self.configuration.trimming |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn set_trimming(&mut self, trimming: Trimming) { |
|
|
|
fn set_trimming(&mut self, trimming: Trimming) { |
|
|
|
match trimming { |
|
|
|
// Run checks for all trimming possibilities.
|
|
|
|
Trimming::Absolute { |
|
|
|
trimming_checks!(trimming, self.view_size().into()); |
|
|
|
top_left, |
|
|
|
|
|
|
|
bottom_right, |
|
|
|
|
|
|
|
} => unsafe { |
|
|
|
|
|
|
|
// 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 |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimmingParams( |
|
|
|
|
|
|
|
self.port_as_raw(), |
|
|
|
|
|
|
|
top_left.0, |
|
|
|
|
|
|
|
top_left.1, |
|
|
|
|
|
|
|
bottom_right.0, |
|
|
|
|
|
|
|
bottom_right.1, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Trimming::Centered { width, height } => unsafe { |
|
|
|
|
|
|
|
let view_size: (i16, i16) = self.view_size().into(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Trim sizes are positive.
|
|
|
|
|
|
|
|
assert!(width >= 0 && height >= 0); |
|
|
|
|
|
|
|
// Trim sizes are within the view.
|
|
|
|
|
|
|
|
assert!(width <= view_size.0 && height <= view_size.1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimmingParamsCenter( |
|
|
|
self.configuration.trimming = trimming; |
|
|
|
self.port_as_raw(), |
|
|
|
|
|
|
|
width, |
|
|
|
|
|
|
|
height, |
|
|
|
|
|
|
|
view_size.0, |
|
|
|
|
|
|
|
view_size.1, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Trimming::Off => unsafe { |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), false))?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -405,7 +403,7 @@ impl Camera for OutwardRightCam { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
self.view_size |
|
|
|
self.configuration.view_size |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
@ -417,12 +415,23 @@ impl Camera for OutwardRightCam { |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
self.view_size = size; |
|
|
|
self.configuration.view_size = size; |
|
|
|
|
|
|
|
|
|
|
|
self.set_trimming(Trimming::Off)?; |
|
|
|
self.set_trimming(Trimming::Off); |
|
|
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn trimming(&self) -> Trimming { |
|
|
|
|
|
|
|
self.configuration.trimming |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn set_trimming(&mut self, trimming: Trimming) { |
|
|
|
|
|
|
|
// Run checks for all trimming possibilities.
|
|
|
|
|
|
|
|
trimming_checks!(trimming, self.view_size().into()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.configuration.trimming = trimming; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Camera for OutwardLeftCam { |
|
|
|
impl Camera for OutwardLeftCam { |
|
|
@ -431,7 +440,7 @@ impl Camera for OutwardLeftCam { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
self.view_size |
|
|
|
self.configuration.view_size |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
@ -443,12 +452,23 @@ impl Camera for OutwardLeftCam { |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
self.view_size = size; |
|
|
|
self.configuration.view_size = size; |
|
|
|
|
|
|
|
|
|
|
|
self.set_trimming(Trimming::Off)?; |
|
|
|
self.set_trimming(Trimming::Off); |
|
|
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn trimming(&self) -> Trimming { |
|
|
|
|
|
|
|
self.configuration.trimming |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn set_trimming(&mut self, trimming: Trimming) { |
|
|
|
|
|
|
|
// Run checks for all trimming possibilities.
|
|
|
|
|
|
|
|
trimming_checks!(trimming, self.view_size().into()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.configuration.trimming = trimming; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Camera for BothOutwardCam { |
|
|
|
impl Camera for BothOutwardCam { |
|
|
@ -461,7 +481,7 @@ impl Camera for BothOutwardCam { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
fn view_size(&self) -> ViewSize { |
|
|
|
self.view_size |
|
|
|
self.configuration.view_size |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
|
fn set_view_size(&mut self, size: ViewSize) -> crate::Result<()> { |
|
|
@ -473,12 +493,23 @@ impl Camera for BothOutwardCam { |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
self.view_size = size; |
|
|
|
self.configuration.view_size = size; |
|
|
|
|
|
|
|
|
|
|
|
self.set_trimming(Trimming::Off)?; |
|
|
|
self.set_trimming(Trimming::Off); |
|
|
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn trimming(&self) -> Trimming { |
|
|
|
|
|
|
|
self.configuration.trimming |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn set_trimming(&mut self, trimming: Trimming) { |
|
|
|
|
|
|
|
// Run checks for all trimming possibilities.
|
|
|
|
|
|
|
|
trimming_checks!(trimming, self.view_size().into()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.configuration.trimming = trimming; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Generic functionality common to all cameras.
|
|
|
|
/// Generic functionality common to all cameras.
|
|
|
@ -547,8 +578,8 @@ pub trait Camera { |
|
|
|
/// # }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
#[doc(alias = "CAMU_GetTransferBytes")] |
|
|
|
#[doc(alias = "CAMU_GetTransferBytes")] |
|
|
|
fn max_byte_count(&self) -> crate::Result<usize> { |
|
|
|
fn max_byte_count(&self) -> usize { |
|
|
|
let size = self.final_image_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>(); |
|
|
|
|
|
|
|
|
|
|
@ -557,7 +588,7 @@ pub trait Camera { |
|
|
|
res = res * 2; |
|
|
|
res = res * 2; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Ok(res) |
|
|
|
res |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 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
|
|
|
@ -585,31 +616,18 @@ pub trait Camera { |
|
|
|
/// # Ok(())
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
fn final_image_size(&self) -> crate::Result<(i16, i16)> { |
|
|
|
fn final_image_size(&self) -> (i16, i16) { |
|
|
|
match self.is_trimming_enabled()? { |
|
|
|
match self.trimming() { |
|
|
|
// Take trimming into account
|
|
|
|
Trimming::Absolute { |
|
|
|
true => { |
|
|
|
top_left, |
|
|
|
// This request should never fail, at least not under safe `ctru-rs` usage.
|
|
|
|
bottom_right, |
|
|
|
let trimming = self.trimming_configuration()?; |
|
|
|
} => (bottom_right.0 - top_left.0, bottom_right.1 - top_left.1), |
|
|
|
|
|
|
|
Trimming::Centered { width, height } => (width, height), |
|
|
|
let Trimming::Absolute { |
|
|
|
Trimming::Off => self.view_size().into(), |
|
|
|
top_left, |
|
|
|
|
|
|
|
bottom_right, |
|
|
|
|
|
|
|
} = trimming |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
unreachable!() |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let width = bottom_right.0 - top_left.0; |
|
|
|
|
|
|
|
let height = bottom_right.1 - top_left.1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok((width, height)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Simply use the full view size.
|
|
|
|
|
|
|
|
false => Ok(self.view_size().into()), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the [`Trimming`] configuration currently set.
|
|
|
|
fn trimming(&self) -> Trimming; |
|
|
|
fn trimming(&self) -> Trimming; |
|
|
|
|
|
|
|
|
|
|
|
/// Set trimming bounds to trim the camera photo.
|
|
|
|
/// Set trimming bounds to trim the camera photo.
|
|
|
@ -618,37 +636,8 @@ pub trait Camera { |
|
|
|
|
|
|
|
|
|
|
|
/// Returns whether or not trimming is currently enabled for the camera.
|
|
|
|
/// Returns whether or not trimming is currently enabled for the camera.
|
|
|
|
#[doc(alias = "CAMU_IsTrimming")] |
|
|
|
#[doc(alias = "CAMU_IsTrimming")] |
|
|
|
fn is_trimming_enabled(&self) -> crate::Result<bool> { |
|
|
|
fn is_trimming(&self) -> bool { |
|
|
|
unsafe { |
|
|
|
matches!(self.trimming(), Trimming::Off) |
|
|
|
let mut trimming = false; |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_IsTrimming(&mut trimming, self.port_as_raw()))?; |
|
|
|
|
|
|
|
Ok(trimming) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the [`Trimming`] configuration currently set.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Notes
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// If successful, this function will always return a [`Trimming::Absolute`].
|
|
|
|
|
|
|
|
#[doc(alias = "CAMU_GetTrimmingParams")] |
|
|
|
|
|
|
|
fn trimming_configuration(&self) -> crate::Result<Trimming> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
let mut top_left = (0, 0); |
|
|
|
|
|
|
|
let mut bottom_right = (0, 0); |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_GetTrimmingParams( |
|
|
|
|
|
|
|
&mut top_left.0, |
|
|
|
|
|
|
|
&mut top_left.1, |
|
|
|
|
|
|
|
&mut bottom_right.0, |
|
|
|
|
|
|
|
&mut bottom_right.1, |
|
|
|
|
|
|
|
self.port_as_raw(), |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Trimming::Absolute { |
|
|
|
|
|
|
|
top_left, |
|
|
|
|
|
|
|
bottom_right, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the exposure level of the camera.
|
|
|
|
/// Set the exposure level of the camera.
|
|
|
@ -672,22 +661,6 @@ pub trait Camera { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the white balance of the camera.
|
|
|
|
|
|
|
|
// TODO: Explain what "without base up" means.
|
|
|
|
|
|
|
|
#[doc(alias = "CAMU_SetWhiteBalanceWithoutBaseUp")] |
|
|
|
|
|
|
|
fn set_white_balance_without_base_up( |
|
|
|
|
|
|
|
&mut self, |
|
|
|
|
|
|
|
white_balance: WhiteBalance, |
|
|
|
|
|
|
|
) -> crate::Result<()> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetWhiteBalanceWithoutBaseUp( |
|
|
|
|
|
|
|
self.camera_as_raw(), |
|
|
|
|
|
|
|
white_balance.into(), |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Set the sharpness of the camera.
|
|
|
|
/// Set the sharpness of the camera.
|
|
|
|
#[doc(alias = "CAMU_SetSharpness")] |
|
|
|
#[doc(alias = "CAMU_SetSharpness")] |
|
|
|
fn set_sharpness(&mut self, sharpness: i8) -> crate::Result<()> { |
|
|
|
fn set_sharpness(&mut self, sharpness: i8) -> crate::Result<()> { |
|
|
@ -913,16 +886,6 @@ pub trait Camera { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Set the camera as the current sleep camera.
|
|
|
|
|
|
|
|
// TODO: Explain sleep camera
|
|
|
|
|
|
|
|
#[doc(alias = "CAMU_SetSleepCamera")] |
|
|
|
|
|
|
|
fn set_sleep_camera(&mut self) -> crate::Result<()> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetSleepCamera(self.camera_as_raw()))?; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Request the camera to take a picture and write it in a buffer.
|
|
|
|
/// Request the camera to take a picture and write it in a buffer.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
/// # Errors
|
|
|
@ -966,21 +929,13 @@ pub trait Camera { |
|
|
|
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(); |
|
|
|
let full_view: (i16, i16) = self.view_size().into(); |
|
|
|
|
|
|
|
|
|
|
|
// Check whether the input buffer is big enough for the image.
|
|
|
|
// It seems like doing this as the first step gives the option to use trimming and get correct readings for the transfer bytes.
|
|
|
|
let max_size = |
|
|
|
|
|
|
|
(final_view.0 as usize * final_view.1 as usize) * std::mem::size_of::<i16>(); |
|
|
|
|
|
|
|
if buffer.len() < max_size { |
|
|
|
|
|
|
|
return Err(Error::BufferTooShort { |
|
|
|
|
|
|
|
provided: buffer.len(), |
|
|
|
|
|
|
|
wanted: max_size, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
ResultCode(ctru_sys::CAMU_Activate(self.camera_as_raw()))?; |
|
|
|
ResultCode(ctru_sys::CAMU_Activate(self.camera_as_raw()))?; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let transfer_unit = match self.trimming() { |
|
|
|
// Obtain the final view size and make the needed modifications to the camera.
|
|
|
|
|
|
|
|
let final_view: (i16, i16) = match self.trimming() { |
|
|
|
Trimming::Absolute { |
|
|
|
Trimming::Absolute { |
|
|
|
top_left, |
|
|
|
top_left, |
|
|
|
bottom_right, |
|
|
|
bottom_right, |
|
|
@ -995,29 +950,7 @@ pub trait Camera { |
|
|
|
bottom_right.1, |
|
|
|
bottom_right.1, |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
// The transfer unit is NOT the "max number of bytes" or whatever the docs make you think it is...
|
|
|
|
(bottom_right.0 - top_left.0, bottom_right.1 - top_left.1) |
|
|
|
let transfer_unit = unsafe { |
|
|
|
|
|
|
|
let mut transfer_unit = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_GetMaxBytes( |
|
|
|
|
|
|
|
&mut transfer_unit, |
|
|
|
|
|
|
|
final_view.0, |
|
|
|
|
|
|
|
final_view.1, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transfer_unit |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTransferBytes( |
|
|
|
|
|
|
|
self.port_as_raw(), |
|
|
|
|
|
|
|
transfer_unit, |
|
|
|
|
|
|
|
final_view.0, |
|
|
|
|
|
|
|
final_view.1, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transfer_unit |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
Trimming::Centered { width, height } => unsafe { |
|
|
|
Trimming::Centered { width, height } => unsafe { |
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?; |
|
|
|
ResultCode(ctru_sys::CAMU_SetTrimming(self.port_as_raw(), true))?; |
|
|
@ -1030,38 +963,57 @@ pub trait Camera { |
|
|
|
full_view.1, |
|
|
|
full_view.1, |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
// The transfer unit is NOT the "max number of bytes" or whatever the docs make you think it is...
|
|
|
|
(width, height) |
|
|
|
let transfer_unit = unsafe { |
|
|
|
|
|
|
|
let mut transfer_unit = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_GetMaxBytes( |
|
|
|
|
|
|
|
&mut transfer_unit, |
|
|
|
|
|
|
|
width, |
|
|
|
|
|
|
|
height, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transfer_unit |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTransferBytes( |
|
|
|
|
|
|
|
self.port_as_raw(), |
|
|
|
|
|
|
|
transfer_unit, |
|
|
|
|
|
|
|
width, |
|
|
|
|
|
|
|
height, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transfer_unit |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The transfer unit is NOT the "max number of bytes" or whatever the docs make you think it is...
|
|
|
|
|
|
|
|
let transfer_unit = unsafe { |
|
|
|
|
|
|
|
let mut transfer_unit = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_GetMaxBytes( |
|
|
|
|
|
|
|
&mut transfer_unit, |
|
|
|
|
|
|
|
final_view.0, |
|
|
|
|
|
|
|
final_view.1, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transfer_unit |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetTransferBytes( |
|
|
|
|
|
|
|
self.port_as_raw(), |
|
|
|
|
|
|
|
transfer_unit, |
|
|
|
|
|
|
|
final_view.0, |
|
|
|
|
|
|
|
final_view.1, |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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>(); |
|
|
|
|
|
|
|
if buffer.len() < max_size { |
|
|
|
|
|
|
|
// We deactivate the camera prematurely.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Note that it shouldn't be too important whether the camera closes or not here,
|
|
|
|
|
|
|
|
// since it only starts capturing later.
|
|
|
|
|
|
|
|
unsafe { ResultCode(ctru_sys::CAMU_Activate(ctru_sys::SELECT_NONE))? }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Err(Error::BufferTooShort { |
|
|
|
|
|
|
|
provided: buffer.len(), |
|
|
|
|
|
|
|
wanted: max_size, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let receive_event = unsafe { |
|
|
|
let receive_event = unsafe { |
|
|
|
let mut completion_handle: Handle = 0; |
|
|
|
let mut completion_handle: Handle = 0; |
|
|
|
|
|
|
|
|
|
|
|
ResultCode(ctru_sys::CAMU_SetReceiving( |
|
|
|
ResultCode(ctru_sys::CAMU_SetReceiving( |
|
|
|
&mut completion_handle, |
|
|
|
&mut completion_handle, |
|
|
|
buffer.as_mut_ptr().cast(), |
|
|
|
buffer.as_mut_ptr().cast(), |
|
|
@ -1073,6 +1025,7 @@ pub trait Camera { |
|
|
|
completion_handle |
|
|
|
completion_handle |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Start capturing with the camera.
|
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
ResultCode(ctru_sys::CAMU_StartCapture(self.port_as_raw()))?; |
|
|
|
ResultCode(ctru_sys::CAMU_StartCapture(self.port_as_raw()))?; |
|
|
|
}; |
|
|
|
}; |
|
|
@ -1140,18 +1093,12 @@ impl Cam { |
|
|
|
}, |
|
|
|
}, |
|
|
|
)?; |
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
|
|
let mut inner_cam = InwardCam { |
|
|
|
let configuration = Configuration::new(); |
|
|
|
view_size: ViewSize::TopLCD, |
|
|
|
|
|
|
|
}; |
|
|
|
let mut inner_cam = InwardCam { configuration }; |
|
|
|
let mut outer_right_cam = OutwardRightCam { |
|
|
|
let mut outer_right_cam = OutwardRightCam { configuration }; |
|
|
|
view_size: ViewSize::TopLCD, |
|
|
|
let mut outer_left_cam = OutwardLeftCam { configuration }; |
|
|
|
}; |
|
|
|
let mut both_outer_cams = BothOutwardCam { configuration }; |
|
|
|
let mut outer_left_cam = OutwardLeftCam { |
|
|
|
|
|
|
|
view_size: ViewSize::TopLCD, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let mut both_outer_cams = BothOutwardCam { |
|
|
|
|
|
|
|
view_size: ViewSize::TopLCD, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inner_cam.set_view_size(ViewSize::TopLCD)?; |
|
|
|
inner_cam.set_view_size(ViewSize::TopLCD)?; |
|
|
|
outer_right_cam.set_view_size(ViewSize::TopLCD)?; |
|
|
|
outer_right_cam.set_view_size(ViewSize::TopLCD)?; |
|
|
|