Browse Source

Rotate RGB565 image rather than convert

pull/94/head
Andrea Ciliberti 2 years ago
parent
commit
4ecb1e4077
  1. 66
      ctru-rs/examples/camera-image.rs

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

@ -1,16 +1,15 @@
use ctru::console::Console; use ctru::gfx::Screen;
use ctru::gfx::{Gfx, Screen}; use ctru::prelude::*;
use ctru::services::cam::{Cam, CamOutputFormat, CamShutterSoundType, CamSize, Camera}; use ctru::services::cam::{Cam, CamOutputFormat, CamShutterSoundType, CamSize, Camera};
use ctru::services::hid::KeyPad; use ctru::services::gspgpu::FramebufferFormat;
use ctru::services::{Apt, Hid};
use std::time::Duration; use std::time::Duration;
const WIDTH: usize = 400; const WIDTH: usize = 400;
const HEIGHT: usize = 240; const HEIGHT: usize = 240;
// The screen size is the width and height multiplied by 2 and // The screen size is the width and height multiplied by 2 (RGB565 store pixels in 2 bytes)
// then multiplied by 2 again for 3D images const BUF_SIZE: usize = WIDTH * HEIGHT * 2;
const BUF_SIZE: usize = WIDTH * HEIGHT * 2 * 2;
const WAIT_TIMEOUT: Duration = Duration::from_micros(300); const WAIT_TIMEOUT: Duration = Duration::from_micros(300);
@ -22,8 +21,10 @@ fn main() {
let gfx = Gfx::init().expect("Failed to initialize GFX service."); let gfx = Gfx::init().expect("Failed to initialize GFX service.");
gfx.top_screen.borrow_mut().set_double_buffering(true); gfx.top_screen.borrow_mut().set_double_buffering(true);
gfx.top_screen
.borrow_mut()
.set_framebuffer_format(FramebufferFormat::Rgb565);
gfx.bottom_screen.borrow_mut().set_double_buffering(false); gfx.bottom_screen.borrow_mut().set_double_buffering(false);
let _console = Console::init(gfx.bottom_screen.borrow_mut()); let _console = Console::init(gfx.bottom_screen.borrow_mut());
let mut keys_down; let mut keys_down;
@ -54,7 +55,9 @@ fn main() {
.set_trimming(false) .set_trimming(false)
.expect("Failed to disable trimming"); .expect("Failed to disable trimming");
} }
let mut buf = vec![0u8; BUF_SIZE]; let mut buf = vec![128u8; BUF_SIZE / 2];
let mut lol = vec![255u8; BUF_SIZE / 2];
buf.append(&mut lol);
println!("\nPress R to take a new picture"); println!("\nPress R to take a new picture");
println!("Press Start to exit to Homebrew Launcher"); println!("Press Start to exit to Homebrew Launcher");
@ -83,7 +86,7 @@ fn main() {
.expect("Failed to take picture"); .expect("Failed to take picture");
} }
let img = convert_image_to_rgb8(&buf, 0, 0, WIDTH, HEIGHT); let img = rotate_image(&buf, WIDTH, HEIGHT);
unsafe { unsafe {
gfx.top_screen gfx.top_screen
@ -99,39 +102,28 @@ fn main() {
} }
} }
// The available camera output formats are both using u16 values. // The 3DS' screens are 2 vertical LCD panels rotated by 90 degrees.
// To write to the frame buffer with the default RGB8 format, // As such, we'll need to write a "vertical" image to the framebuffer to have it displayed properly.
// the values must be converted. // This functions handles the rotation of an horizontal image to a vertical one.
// fn rotate_image(img: &[u8], width: usize, height: usize) -> Vec<u8> {
// Alternatively, the frame buffer format could be set to RGB565 as well let mut res = vec![0u8; img.len()];
// but the image would need to be rotated 90 degrees.
fn convert_image_to_rgb8(img: &[u8], x: usize, y: usize, width: usize, height: usize) -> Vec<u8> {
let mut rgb8 = vec![0u8; img.len()];
for j in 0..height { for j in 0..height {
for i in 0..width { for i in 0..width {
// Y-coordinate of where to draw in the frame buffer // Y-coordinate of where to draw in the frame buffer
let draw_y = y + height - j; // Height must be esclusive of the upper end (otherwise, we'd be writing to the pixel one column to the right when having j=0)
let draw_y = (height - 1) - j;
// X-coordinate of where to draw in the frame buffer // X-coordinate of where to draw in the frame buffer
let draw_x = x + i; let draw_x = i;
// Initial index of where to draw in the frame buffer based on y and x coordinates
let draw_index = (draw_y + draw_x * height) * 3;
// Index of the pixel to draw within the image buffer // Index of the pixel to draw within the image buffer
let index = (j * width + i) * 2; let read_index = (j * width + i) * 2;
// Pixels in the image are 2 bytes because of the RGB565 format.
let pixel = u16::from_ne_bytes(img[index..index + 2].try_into().unwrap()); // Initial index of where to draw in the frame buffer based on y and x coordinates
// b value from the pixel let draw_index = (draw_x * height + draw_y) * 2; // This 2 stands for the number of bytes per pixel (16 bits)
let b = (((pixel >> 11) & 0x1F) << 3) as u8;
// g value from the pixel res[draw_index] = img[read_index];
let g = (((pixel >> 5) & 0x3F) << 2) as u8; res[draw_index + 1] = img[read_index + 1];
// r value from the pixel
let r = ((pixel & 0x1F) << 3) as u8;
// set the r, g, and b values to the calculated index within the frame buffer
rgb8[draw_index] = r;
rgb8[draw_index + 1] = g;
rgb8[draw_index + 2] = b;
} }
} }
rgb8 res
} }

Loading…
Cancel
Save