|
|
@ -11,7 +11,6 @@ use citro3d_sys::C3D_Mtx; |
|
|
|
use ctru::prelude::*; |
|
|
|
use ctru::prelude::*; |
|
|
|
use ctru::services::gfx::{RawFrameBuffer, Screen, TopScreen3D}; |
|
|
|
use ctru::services::gfx::{RawFrameBuffer, Screen, TopScreen3D}; |
|
|
|
|
|
|
|
|
|
|
|
use std::f32::consts::PI; |
|
|
|
|
|
|
|
use std::ffi::CStr; |
|
|
|
use std::ffi::CStr; |
|
|
|
use std::mem::MaybeUninit; |
|
|
|
use std::mem::MaybeUninit; |
|
|
|
|
|
|
|
|
|
|
@ -38,15 +37,15 @@ struct Vertex { |
|
|
|
|
|
|
|
|
|
|
|
static VERTICES: &[Vertex] = &[ |
|
|
|
static VERTICES: &[Vertex] = &[ |
|
|
|
Vertex { |
|
|
|
Vertex { |
|
|
|
pos: Vec3::new(0.0, 0.5, 0.5), |
|
|
|
pos: Vec3::new(0.0, 0.5, 3.0), |
|
|
|
color: Vec3::new(1.0, 0.0, 0.0), |
|
|
|
color: Vec3::new(1.0, 0.0, 0.0), |
|
|
|
}, |
|
|
|
}, |
|
|
|
Vertex { |
|
|
|
Vertex { |
|
|
|
pos: Vec3::new(-0.5, -0.5, 0.5), |
|
|
|
pos: Vec3::new(-0.5, -0.5, 3.0), |
|
|
|
color: Vec3::new(0.0, 1.0, 0.0), |
|
|
|
color: Vec3::new(0.0, 1.0, 0.0), |
|
|
|
}, |
|
|
|
}, |
|
|
|
Vertex { |
|
|
|
Vertex { |
|
|
|
pos: Vec3::new(0.5, -0.5, 0.5), |
|
|
|
pos: Vec3::new(0.5, -0.5, 3.0), |
|
|
|
color: Vec3::new(0.0, 0.0, 1.0), |
|
|
|
color: Vec3::new(0.0, 0.0, 1.0), |
|
|
|
}, |
|
|
|
}, |
|
|
|
]; |
|
|
|
]; |
|
|
@ -95,13 +94,7 @@ fn main() { |
|
|
|
let mut buf_info = buffer::Info::new(); |
|
|
|
let mut buf_info = buffer::Info::new(); |
|
|
|
let (attr_info, vbo_idx) = prepare_vbos(&mut buf_info, &vbo_data); |
|
|
|
let (attr_info, vbo_idx) = prepare_vbos(&mut buf_info, &vbo_data); |
|
|
|
|
|
|
|
|
|
|
|
let (projection_uniform_idx, mut projection) = scene_init(&mut program); |
|
|
|
let projection_uniform_idx = scene_init(&mut program); |
|
|
|
|
|
|
|
|
|
|
|
unsafe { citro3d_sys::Mtx_RotateY(&mut projection, -PI / 12.0, true) }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut right_eye_projection = projection; |
|
|
|
|
|
|
|
unsafe { citro3d_sys::Mtx_RotateY(&mut right_eye_projection, 2.0 * PI / 12.0, true) }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while apt.main_loop() { |
|
|
|
while apt.main_loop() { |
|
|
|
hid.scan_input(); |
|
|
|
hid.scan_input(); |
|
|
|
|
|
|
|
|
|
|
@ -132,9 +125,15 @@ fn main() { |
|
|
|
instance.draw_arrays(buffer::Primitive::Triangles, vbo_idx); |
|
|
|
instance.draw_arrays(buffer::Primitive::Triangles, vbo_idx); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
render_to(&mut top_left_target, &projection); |
|
|
|
let Projections { |
|
|
|
render_to(&mut top_right_target, &right_eye_projection); |
|
|
|
left, |
|
|
|
render_to(&mut bottom_target, &projection); |
|
|
|
right, |
|
|
|
|
|
|
|
center, |
|
|
|
|
|
|
|
} = calculate_projections(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
render_to(&mut top_left_target, &left); |
|
|
|
|
|
|
|
render_to(&mut top_right_target, &right); |
|
|
|
|
|
|
|
render_to(&mut bottom_target, ¢er); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -159,7 +158,7 @@ where |
|
|
|
.unwrap(); |
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
attr_info |
|
|
|
attr_info |
|
|
|
.add_loader(reg1, attrib::Format::Float, 5) |
|
|
|
.add_loader(reg1, attrib::Format::Float, 3) |
|
|
|
.unwrap(); |
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
let buf_idx = buf_info.add(vbo_data, &attr_info).unwrap(); |
|
|
|
let buf_idx = buf_info.add(vbo_data, &attr_info).unwrap(); |
|
|
@ -167,34 +166,71 @@ where |
|
|
|
(attr_info, buf_idx) |
|
|
|
(attr_info, buf_idx) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx) { |
|
|
|
struct Projections { |
|
|
|
// Load the vertex shader, create a shader program and bind it
|
|
|
|
left: C3D_Mtx, |
|
|
|
|
|
|
|
right: C3D_Mtx, |
|
|
|
|
|
|
|
center: C3D_Mtx, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn calculate_projections() -> Projections { |
|
|
|
|
|
|
|
let mut left_eye = MaybeUninit::uninit(); |
|
|
|
|
|
|
|
let mut right_eye = MaybeUninit::uninit(); |
|
|
|
|
|
|
|
let mut center = MaybeUninit::uninit(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: it would be cool to allow playing around with these parameters on
|
|
|
|
|
|
|
|
// the fly with D-pad, etc.
|
|
|
|
|
|
|
|
let slider_val = unsafe { citro3d_sys::osGet3DSliderState() }; |
|
|
|
|
|
|
|
let iod = slider_val / 4.0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let near = 0.01; |
|
|
|
|
|
|
|
let far = 100.0; |
|
|
|
|
|
|
|
let fovy = 40.0_f32.to_radians(); |
|
|
|
|
|
|
|
let screen = 2.0; |
|
|
|
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
citro3d_sys::C3D_BindProgram(program.as_raw()); |
|
|
|
citro3d_sys::Mtx_PerspStereoTilt( |
|
|
|
|
|
|
|
left_eye.as_mut_ptr(), |
|
|
|
|
|
|
|
fovy, |
|
|
|
|
|
|
|
citro3d_sys::C3D_AspectRatioTop as f32, |
|
|
|
|
|
|
|
near, |
|
|
|
|
|
|
|
far, |
|
|
|
|
|
|
|
-iod, |
|
|
|
|
|
|
|
screen, |
|
|
|
|
|
|
|
true, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Get the location of the uniforms
|
|
|
|
citro3d_sys::Mtx_PerspStereoTilt( |
|
|
|
let projection_name = CStr::from_bytes_with_nul(b"projection\0").unwrap(); |
|
|
|
right_eye.as_mut_ptr(), |
|
|
|
let projection_uniform_idx = ctru_sys::shaderInstanceGetUniformLocation( |
|
|
|
fovy, |
|
|
|
(*program.as_raw()).vertexShader, |
|
|
|
citro3d_sys::C3D_AspectRatioTop as f32, |
|
|
|
projection_name.as_ptr(), |
|
|
|
near, |
|
|
|
|
|
|
|
far, |
|
|
|
|
|
|
|
iod, |
|
|
|
|
|
|
|
screen, |
|
|
|
|
|
|
|
true, |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Compute the projection matrix
|
|
|
|
citro3d_sys::Mtx_PerspTilt( |
|
|
|
let projection = { |
|
|
|
center.as_mut_ptr(), |
|
|
|
let mut projection = MaybeUninit::uninit(); |
|
|
|
fovy, |
|
|
|
citro3d_sys::Mtx_OrthoTilt( |
|
|
|
citro3d_sys::C3D_AspectRatioBot as f32, |
|
|
|
projection.as_mut_ptr(), |
|
|
|
near, |
|
|
|
// The 3ds top screen is a 5:3 ratio
|
|
|
|
far, |
|
|
|
-1.66, |
|
|
|
|
|
|
|
1.66, |
|
|
|
|
|
|
|
-1.0, |
|
|
|
|
|
|
|
1.0, |
|
|
|
|
|
|
|
0.0, |
|
|
|
|
|
|
|
1.0, |
|
|
|
|
|
|
|
true, |
|
|
|
true, |
|
|
|
); |
|
|
|
); |
|
|
|
projection.assume_init() |
|
|
|
|
|
|
|
}; |
|
|
|
Projections { |
|
|
|
|
|
|
|
left: left_eye.assume_init(), |
|
|
|
|
|
|
|
right: right_eye.assume_init(), |
|
|
|
|
|
|
|
center: center.assume_init(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn scene_init(program: &mut shader::Program) -> i8 { |
|
|
|
|
|
|
|
// Load the vertex shader, create a shader program and bind it
|
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
citro3d_sys::C3D_BindProgram(program.as_raw()); |
|
|
|
|
|
|
|
|
|
|
|
// Configure the first fragment shading substage to just pass through the vertex color
|
|
|
|
// Configure the first fragment shading substage to just pass through the vertex color
|
|
|
|
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
|
|
|
|
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
|
|
|
@ -209,6 +245,13 @@ fn scene_init(program: &mut shader::Program) -> (i8, C3D_Mtx) { |
|
|
|
); |
|
|
|
); |
|
|
|
citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, ctru_sys::GPU_REPLACE); |
|
|
|
citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, ctru_sys::GPU_REPLACE); |
|
|
|
|
|
|
|
|
|
|
|
(projection_uniform_idx, projection) |
|
|
|
// Get the location of the uniforms
|
|
|
|
|
|
|
|
let projection_name = CStr::from_bytes_with_nul(b"projection\0").unwrap(); |
|
|
|
|
|
|
|
let projection_uniform_idx = ctru_sys::shaderInstanceGetUniformLocation( |
|
|
|
|
|
|
|
(*program.as_raw()).vertexShader, |
|
|
|
|
|
|
|
projection_name.as_ptr(), |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
projection_uniform_idx |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|