Browse Source

3D images without stereo calibration

pull/137/head
Andrea Ciliberti 1 year ago
parent
commit
0ec4c92fbc
  1. 45
      ctru-rs/examples/camera-image.rs
  2. 174
      ctru-rs/src/services/cam.rs

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

@ -6,7 +6,7 @@ use ctru::prelude::*; @@ -6,7 +6,7 @@ use ctru::prelude::*;
use ctru::services::cam::{
Cam, Camera, OutputFormat, ShutterSound, Trimming, ViewSize, WhiteBalance,
};
use ctru::services::gfx::{Flush, Screen, Swap};
use ctru::services::gfx::{Flush, Screen, Swap, TopScreen3D};
use ctru::services::gspgpu::FramebufferFormat;
use std::time::Duration;
@ -20,9 +20,12 @@ fn main() { @@ -20,9 +20,12 @@ fn main() {
let mut hid = Hid::new().expect("Failed to initialize Hid service.");
let gfx = Gfx::new().expect("Failed to initialize GFX service.");
let mut top_screen = gfx.top_screen.borrow_mut();
top_screen.set_double_buffering(true);
top_screen.set_framebuffer_format(FramebufferFormat::Rgb565);
gfx.top_screen.borrow_mut().set_double_buffering(true);
gfx.top_screen
.borrow_mut()
.set_framebuffer_format(FramebufferFormat::Rgb565);
let mut top_screen_3d = TopScreen3D::from(&gfx.top_screen);
let _console = Console::new(gfx.bottom_screen.borrow_mut());
@ -31,7 +34,7 @@ fn main() { @@ -31,7 +34,7 @@ fn main() {
let mut cam = Cam::new().expect("Failed to initialize CAM service.");
// Camera setup.
let camera = &mut cam.outer_right_cam;
let camera = &mut cam.both_outer_cams;
{
camera
.set_view_size(ViewSize::TopLCD)
@ -73,7 +76,7 @@ fn main() { @@ -73,7 +76,7 @@ fn main() {
if keys_down.contains(KeyPad::R) {
println!("Capturing new image");
let camera = &mut cam.outer_right_cam;
let mut camera = &mut cam.both_outer_cams;
// Take a picture and write it to the buffer.
camera
@ -86,17 +89,29 @@ fn main() { @@ -86,17 +89,29 @@ fn main() {
cam.play_shutter_sound(ShutterSound::Normal)
.expect("Failed to play shutter sound");
// Rotate the image and correctly display it on the screen.
rotate_image_to_screen(
&buf,
top_screen.raw_framebuffer().ptr,
image_size.0 as usize,
image_size.1 as usize,
);
{
let (mut left_side, mut right_side) = top_screen_3d.split_mut();
// Rotate the left image and correctly display it on the screen.
rotate_image_to_screen(
&buf,
left_side.raw_framebuffer().ptr,
image_size.0 as usize,
image_size.1 as usize,
);
// Rotate the right image and correctly display it on the screen.
rotate_image_to_screen(
&buf[len / 2..],
right_side.raw_framebuffer().ptr,
image_size.0 as usize,
image_size.1 as usize,
);
}
// We will only flush and swap the "camera" screen, since the other screen is handled by the `Console`.
top_screen.flush_buffers();
top_screen.swap_buffers();
top_screen_3d.flush_buffers();
top_screen_3d.swap_buffers();
gfx.wait_for_vblank();
}

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

@ -241,15 +241,16 @@ pub enum Trimming { @@ -241,15 +241,16 @@ pub enum Trimming {
}
/// Data used by the camera to calibrate image quality for a single camera.
// TODO: Implement Image quality calibration.
#[doc(alias = "CAMU_ImageQualityCalibrationData")]
#[derive(Default, Clone, Copy, Debug)]
pub struct ImageQualityCalibrationData(pub ctru_sys::CAMU_ImageQualityCalibrationData);
pub struct ImageQualityCalibration(pub ctru_sys::CAMU_ImageQualityCalibrationData);
/// Data used by the camera to calibrate image quality when using both outward cameras.
// TODO: Implement Stereo camera calibration.
#[doc(alias = "CAMU_StereoCameraCalibrationData")]
#[derive(Default, Clone, Copy, Debug)]
pub struct StereoCameraCalibrationData(pub ctru_sys::CAMU_StereoCameraCalibrationData);
pub struct StereoCameraCalibration(ctru_sys::CAMU_StereoCameraCalibrationData);
/// Inward camera representation (facing the user of the 3DS).
///
@ -358,8 +359,44 @@ impl BothOutwardCam { @@ -358,8 +359,44 @@ impl BothOutwardCam {
ResultCode(ctru_sys::CAMU_SetBrightnessSynchronization(
brightness_synchronization,
))?;
Ok(())
}
Ok(())
}
#[doc(alias = "CAMU_GetStereoCameraCalibrationData")]
/// Returns the currently set [`StereoCameraCalibration`].
pub fn stereo_calibration(&self) -> crate::Result<StereoCameraCalibration> {
let mut calibration = StereoCameraCalibration::default();
unsafe {
ResultCode(ctru_sys::CAMU_GetStereoCameraCalibrationData(
&mut calibration.0,
))?;
}
Ok(calibration)
}
#[doc(alias = "CAMU_SetStereoCameraCalibrationData")]
/// Set the [`StereoCameraCalibration`].
// TODO: This seems to have no effect.
pub fn set_stereo_calibration(
&mut self,
mut stereo_calibration: StereoCameraCalibration,
) -> crate::Result<()> {
let view_size = self.final_view_size();
stereo_calibration.0.imageWidth = view_size.0;
stereo_calibration.0.imageHeight = view_size.1;
unsafe {
ResultCode(ctru_sys::CAMU_SetStereoCameraCalibrationData(
stereo_calibration.0,
))?;
}
Ok(())
}
}
@ -389,6 +426,114 @@ impl Camera for BothOutwardCam { @@ -389,6 +426,114 @@ impl Camera for BothOutwardCam {
fn port_as_raw(&self) -> ctru_sys::u32_ {
ctru_sys::PORT_BOTH
}
fn take_picture(&mut self, buffer: &mut [u8], timeout: Duration) -> crate::Result<()> {
// Check whether the provided buffer is big enough to store the image.
let max_size = self.final_byte_length();
if buffer.len() < max_size {
return Err(Error::BufferTooShort {
provided: buffer.len(),
wanted: max_size,
});
}
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...
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,
))?;
};
unsafe {
ResultCode(ctru_sys::CAMU_Activate(self.camera_as_raw()))?;
ResultCode(ctru_sys::CAMU_ClearBuffer(self.port_as_raw()))?;
};
// Synchronize the two cameras.
unsafe {
ResultCode(ctru_sys::CAMU_SynchronizeVsyncTiming(
ctru_sys::SELECT_OUT1,
ctru_sys::SELECT_OUT2,
))?;
}
// Start capturing with the camera.
unsafe {
ResultCode(ctru_sys::CAMU_StartCapture(self.port_as_raw()))?;
};
let receive_event_1 = unsafe {
let mut completion_handle: Handle = 0;
ResultCode(ctru_sys::CAMU_SetReceiving(
&mut completion_handle,
buffer.as_mut_ptr().cast(),
ctru_sys::PORT_CAM1,
(max_size / 2) as u32,
transfer_unit.try_into().unwrap(),
))?;
completion_handle
};
let receive_event_2 = unsafe {
let mut completion_handle: Handle = 0;
ResultCode(ctru_sys::CAMU_SetReceiving(
&mut completion_handle,
buffer[max_size / 2..].as_mut_ptr().cast(),
ctru_sys::PORT_CAM2,
(max_size / 2) as u32,
transfer_unit.try_into().unwrap(),
))?;
completion_handle
};
unsafe {
// Panicking without closing an SVC handle causes an ARM exception, we have to handle it carefully.
let wait_result_1 = ResultCode(ctru_sys::svcWaitSynchronization(
receive_event_1,
timeout.as_nanos().try_into().unwrap(),
));
let wait_result_2 = ResultCode(ctru_sys::svcWaitSynchronization(
receive_event_2,
timeout.as_nanos().try_into().unwrap(),
));
// We close everything first, then we check for possible errors
let _ = ctru_sys::svcCloseHandle(receive_event_1); // We wouldn't return the error even if there was one, so no use of ResultCode is needed.
let _ = ctru_sys::svcCloseHandle(receive_event_2);
// Camera state cleanup
ResultCode(ctru_sys::CAMU_StopCapture(self.port_as_raw()))?;
ResultCode(ctru_sys::CAMU_ClearBuffer(self.port_as_raw()))?;
ResultCode(ctru_sys::CAMU_Activate(ctru_sys::SELECT_NONE))?;
wait_result_1?;
wait_result_2?;
};
Ok(())
}
}
/// Generic functionality common to all cameras.
@ -445,6 +590,7 @@ pub trait Camera: private::ConfigurableCamera { @@ -445,6 +590,7 @@ pub trait Camera: private::ConfigurableCamera {
///
/// # Notes
///
/// The value returned will be double the image size if requested by [`BothOutwardCam`].
/// Remember to query this information again if *any* changes are applied to the [`Camera`] configuration!
///
/// # Example
@ -799,11 +945,11 @@ pub trait Camera: private::ConfigurableCamera { @@ -799,11 +945,11 @@ pub trait Camera: private::ConfigurableCamera {
}
}
/// Set the [`ImageQualityCalibrationData`] for the camera.
/// Set the [`ImageQualityCalibration`] for the camera.
#[doc(alias = "CAMU_SetImageQualityCalibrationData")]
fn set_image_quality_calibration_data(
fn set_image_quality_calibration(
&mut self,
data: ImageQualityCalibrationData,
data: ImageQualityCalibration,
) -> crate::Result<()> {
unsafe {
ResultCode(ctru_sys::CAMU_SetImageQualityCalibrationData(data.0))?;
@ -811,11 +957,11 @@ pub trait Camera: private::ConfigurableCamera { @@ -811,11 +957,11 @@ pub trait Camera: private::ConfigurableCamera {
}
}
/// Returns the current [`ImageQualityCalibrationData`] for the camera.
/// Returns the current [`ImageQualityCalibration`] for the camera.
#[doc(alias = "CAMU_GetImageQualityCalibrationData")]
fn image_quality_calibration_data(&self) -> crate::Result<ImageQualityCalibrationData> {
fn image_quality_calibration(&self) -> crate::Result<ImageQualityCalibration> {
unsafe {
let mut data = ImageQualityCalibrationData::default();
let mut data = ImageQualityCalibration::default();
ResultCode(ctru_sys::CAMU_GetImageQualityCalibrationData(&mut data.0))?;
Ok(data)
}
@ -826,6 +972,13 @@ pub trait Camera: private::ConfigurableCamera { @@ -826,6 +972,13 @@ pub trait Camera: private::ConfigurableCamera {
/// # Errors
///
/// This function will return an error if the camera is already busy or if the timeout duration is reached.
///
/// # Notes
///
/// If the picture is taken using [`BothOutwardCam`], the buffer will have to be able to hold both images
/// (from each camera), which will be written into it sequentially.
/// Use [`Camera::final_byte_length()`] to know how big the buffer needs to be to hold your next image.
///
/// # Example
///
/// ```no_run
@ -858,13 +1011,12 @@ pub trait Camera: private::ConfigurableCamera { @@ -858,13 +1011,12 @@ pub trait Camera: private::ConfigurableCamera {
// Check whether the provided buffer is big enough to store the image.
let max_size = self.final_byte_length();
if buffer.len() < max_size {
return Err(Error::BufferTooShort {
provided: buffer.len(),
wanted: max_size,
});
}
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...

Loading…
Cancel
Save