Browse Source

Start porting <c3d/maths.h>, vectors and matrices

pull/27/head
Ian Chamberlain 1 year ago
parent
commit
2301e5022c
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 114
      citro3d/examples/triangle.rs
  2. 36
      citro3d/src/lib.rs
  3. 87
      citro3d/src/math.rs
  4. 27
      citro3d/src/shader.rs

114
citro3d/examples/triangle.rs

@ -3,13 +3,10 @@ @@ -3,13 +3,10 @@
#![feature(allocator_api)]
use std::ffi::CStr;
use std::mem::MaybeUninit;
use citro3d::macros::include_shader;
use citro3d::math::{CoordinateSystem, Matrix};
use citro3d::render::{self, ClearFlags};
use citro3d::{attrib, buffer, shader};
use citro3d_sys::C3D_Mtx;
use citro3d::{attrib, buffer, shader, AspectRatio};
use ctru::prelude::*;
use ctru::services::gfx::{RawFrameBuffer, Screen, TopScreen3D};
@ -92,7 +89,10 @@ fn main() { @@ -92,7 +89,10 @@ fn main() {
let mut buf_info = buffer::Info::new();
let (attr_info, vbo_idx) = prepare_vbos(&mut buf_info, &vbo_data);
let projection_uniform_idx = scene_init(&mut program);
scene_init(&mut program);
let projection_uniform_idx = program.get_uniform_location("projection").unwrap();
while apt.main_loop() {
hid.scan_input();
@ -109,14 +109,7 @@ fn main() { @@ -109,14 +109,7 @@ fn main() {
let clear_color: u32 = 0x7F_7F_7F_FF;
target.clear(ClearFlags::ALL, clear_color, 0);
unsafe {
// Update the uniforms
citro3d_sys::C3D_FVUnifMtx4x4(
ctru_sys::GPU_VERTEX_SHADER,
projection_uniform_idx.into(),
projection,
);
}
instance.update_vertex_uniform_mat4x4(projection_uniform_idx, projection);
instance.set_attr_info(&attr_info);
@ -165,16 +158,12 @@ where @@ -165,16 +158,12 @@ where
}
struct Projections {
left: C3D_Mtx,
right: C3D_Mtx,
center: C3D_Mtx,
left: Matrix,
right: Matrix,
center: Matrix,
}
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 { ctru_sys::osGet3DSliderState() };
@ -182,53 +171,48 @@ fn calculate_projections() -> Projections { @@ -182,53 +171,48 @@ fn calculate_projections() -> Projections {
let near = 0.01;
let far = 100.0;
let fovy = 40.0_f32.to_radians();
let fov_y = 40.0_f32.to_radians();
let screen = 2.0;
unsafe {
citro3d_sys::Mtx_PerspStereoTilt(
left_eye.as_mut_ptr(),
fovy,
citro3d_sys::C3D_AspectRatioTop as f32,
near,
far,
-iod,
screen,
true,
);
citro3d_sys::Mtx_PerspStereoTilt(
right_eye.as_mut_ptr(),
fovy,
citro3d_sys::C3D_AspectRatioTop as f32,
near,
far,
iod,
screen,
true,
);
citro3d_sys::Mtx_PerspTilt(
center.as_mut_ptr(),
fovy,
citro3d_sys::C3D_AspectRatioBot as f32,
near,
far,
true,
);
Projections {
left: left_eye.assume_init(),
right: right_eye.assume_init(),
center: center.assume_init(),
}
let left_eye = Matrix::perspective_stereo_tilt(
fov_y,
AspectRatio::TopScreen,
near,
far,
-iod,
screen,
CoordinateSystem::LeftHanded,
);
let right_eye = Matrix::perspective_stereo_tilt(
fov_y,
AspectRatio::TopScreen,
near,
far,
iod,
screen,
CoordinateSystem::LeftHanded,
);
let center = Matrix::perspective_tilt(
fov_y,
AspectRatio::BottomScreen,
near,
far,
CoordinateSystem::LeftHanded,
);
Projections {
left: left_eye,
right: right_eye,
center,
}
}
fn scene_init(program: &mut shader::Program) -> i8 {
fn scene_init(program: &mut shader::Program) {
// Load the vertex shader, create a shader program and bind it
unsafe {
citro3d_sys::C3D_BindProgram(program.as_raw());
citro3d_sys::C3D_BindProgram(program.as_raw_mut());
// 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
@ -242,13 +226,5 @@ fn scene_init(program: &mut shader::Program) -> i8 { @@ -242,13 +226,5 @@ fn scene_init(program: &mut shader::Program) -> i8 {
0,
);
citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, ctru_sys::GPU_REPLACE);
// Get the location of the uniforms
let projection_name = CStr::from_bytes_with_nul(b"projection\0").unwrap();
ctru_sys::shaderInstanceGetUniformLocation(
(*program.as_raw()).vertexShader,
projection_name.as_ptr(),
)
}
}

36
citro3d/src/lib.rs

@ -5,11 +5,12 @@ @@ -5,11 +5,12 @@
pub mod attrib;
pub mod buffer;
pub mod error;
pub mod math;
pub mod render;
pub mod shader;
use citro3d_sys::C3D_FrameDrawOn;
pub use error::{Error, Result};
pub use math::Matrix;
pub mod macros {
//! Helper macros for working with shaders.
@ -53,7 +54,7 @@ impl Instance { @@ -53,7 +54,7 @@ impl Instance {
/// Fails if the given target cannot be used for drawing.
pub fn select_render_target(&mut self, target: &render::Target<'_>) -> Result<()> {
let _ = self;
if unsafe { C3D_FrameDrawOn(target.as_raw()) } {
if unsafe { citro3d_sys::C3D_FrameDrawOn(target.as_raw()) } {
Ok(())
} else {
Err(Error::InvalidRenderTarget)
@ -121,6 +122,19 @@ impl Instance { @@ -121,6 +122,19 @@ impl Instance {
);
}
}
// TODO: need separate versions for vertex/geometry and different dimensions?
// Maybe we could do something nicer with const generics, or something, although
// it will probably be tricker
pub fn update_vertex_uniform_mat4x4(&mut self, index: i8, matrix: &Matrix) {
unsafe {
citro3d_sys::C3D_FVUnifMtx4x4(
ctru_sys::GPU_VERTEX_SHADER,
index.into(),
matrix.as_raw(),
)
}
}
}
impl Drop for Instance {
@ -130,3 +144,21 @@ impl Drop for Instance { @@ -130,3 +144,21 @@ impl Drop for Instance {
}
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum AspectRatio {
TopScreen,
BottomScreen,
Other(f32),
}
impl From<AspectRatio> for f32 {
fn from(ratio: AspectRatio) -> Self {
match ratio {
AspectRatio::TopScreen => citro3d_sys::C3D_AspectRatioTop as f32,
AspectRatio::BottomScreen => citro3d_sys::C3D_AspectRatioBot as f32,
AspectRatio::Other(ratio) => ratio,
}
}
}

87
citro3d/src/math.rs

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
//! Safe wrappers for working with matrix and vector types provided by `citro3d`.
use std::mem::MaybeUninit;
use crate::AspectRatio;
/// A 4-vector of [`u8`]s.
pub struct IntVec(citro3d_sys::C3D_IVec);
/// A 4-vector of [`f32`]s.
pub struct FloatVec(citro3d_sys::C3D_FVec);
/// A quaternion, internally represented the same way as [`FVec`].
pub struct Quaternion(citro3d_sys::C3D_FQuat);
/// A 4x4 row-major matrix of [`f32`]s.
pub struct Matrix(citro3d_sys::C3D_Mtx);
/// Whether to use left-handed or right-handed coordinates for calculations.
#[derive(Clone, Copy, Debug)]
#[non_exhaustive] // This probably is exhaustive, but just in case
pub enum CoordinateSystem {
LeftHanded,
RightHanded,
}
impl Matrix {
// TODO: this could probably be generalized with something like builder or options
// pattern. Should look and see what the different citro3d implementations look like
pub fn perspective_stereo_tilt(
fov_y: f32,
aspect_ratio: AspectRatio,
near: f32,
far: f32,
interocular_distance: f32,
/* better name ?? */ screen_depth: f32,
coordinates: CoordinateSystem,
) -> Self {
let mut result = MaybeUninit::uninit();
let inner = unsafe {
citro3d_sys::Mtx_PerspStereoTilt(
result.as_mut_ptr(),
fov_y,
aspect_ratio.into(),
near,
far,
interocular_distance,
screen_depth,
matches!(coordinates, CoordinateSystem::LeftHanded),
);
result.assume_init()
};
Self(inner)
}
pub fn perspective_tilt(
fov_y: f32,
aspect_ratio: AspectRatio,
near: f32,
far: f32,
coordinates: CoordinateSystem,
) -> Self {
let mut result = MaybeUninit::uninit();
let inner = unsafe {
citro3d_sys::Mtx_PerspTilt(
result.as_mut_ptr(),
fov_y,
aspect_ratio.into(),
near,
far,
matches!(coordinates, CoordinateSystem::LeftHanded),
);
result.assume_init()
};
Self(inner)
}
pub(crate) fn as_raw(&self) -> *const citro3d_sys::C3D_Mtx {
&self.0
}
}

27
citro3d/src/shader.rs

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
//! documentation for <https://github.com/devkitPro/picasso>.
use std::error::Error;
use std::ffi::CString;
use std::mem::MaybeUninit;
/// A PICA200 shader program. It may have one or both of:
@ -66,8 +67,30 @@ impl Program { @@ -66,8 +67,30 @@ impl Program {
}
}
// TODO: newtype for index?
pub fn get_uniform_location(&self, name: &str) -> crate::Result<i8> {
let vertex_instance = unsafe { (*self.as_raw()).vertexShader };
if vertex_instance.is_null() {
return Err(todo!());
}
let name = CString::new(name).map_err(|e| -> crate::Error { todo!() })?;
let idx =
unsafe { ctru_sys::shaderInstanceGetUniformLocation(vertex_instance, name.as_ptr()) };
if idx < 0 {
Err(todo!())
} else {
Ok(idx)
}
}
// TODO: pub(crate)
pub fn as_raw(&mut self) -> *mut ctru_sys::shaderProgram_s {
pub fn as_raw(&self) -> *const ctru_sys::shaderProgram_s {
&self.program
}
pub fn as_raw_mut(&mut self) -> *mut ctru_sys::shaderProgram_s {
&mut self.program
}
}
@ -75,7 +98,7 @@ impl Program { @@ -75,7 +98,7 @@ impl Program {
impl Drop for Program {
fn drop(&mut self) {
unsafe {
let _ = ctru_sys::shaderProgramFree(self.as_raw());
let _ = ctru_sys::shaderProgramFree(self.as_raw_mut());
}
}
}

Loading…
Cancel
Save