Browse Source

Varios cleanup + simplify example

pull/18/head
Ian Chamberlain 3 years ago
parent
commit
5a3fd9d21b
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 1
      .gitignore
  2. 48
      citro3d-sys/src/texenv.rs
  3. 163
      citro3d/examples/triangle.rs

1
.gitignore vendored

@ -16,3 +16,4 @@ Cargo.lock
# Can be used for local development to set a custom toolchain # Can be used for local development to set a custom toolchain
rust-toolchain rust-toolchain
rust-toolchain.toml rust-toolchain.toml
.cargo/

48
citro3d-sys/src/texenv.rs

@ -1,5 +1,8 @@
//! Definitions for `<c3d/texenv.h>`. //! Definitions for `<c3d/texenv.h>`.
//! Most of these functions are `static inline` so they don't get generated by `bindgen`. //! Most of these functions are `static inline` so they don't get generated by `bindgen`.
//! See <https://github.com/rust-lang/rust-bindgen/issues/1090>.
// TODO: probably should mark these all as #[inline] for parity with the C code
use core::ops::{BitOr, Shl}; use core::ops::{BitOr, Shl};
@ -10,7 +13,7 @@ use super::*;
// TODO: why are these two different macros in C? // TODO: why are these two different macros in C?
/// Creates a texture combiner source parameter from three sources. /// Creates a texture combiner source parameter from three sources.
fn gpu_tevsources<T>(a: T, b: T, c: T) -> T fn GPU_TEVSOURCES<T>(a: T, b: T, c: T) -> T
where where
T: BitOr<Output = T> + Shl<u8, Output = T>, T: BitOr<Output = T> + Shl<u8, Output = T>,
{ {
@ -18,7 +21,7 @@ where
} }
/// Creates a texture combiner operand parameter from three operands. /// Creates a texture combiner operand parameter from three operands.
fn gpu_tevoperands<T>(a: T, b: T, c: T) -> T fn GPU_TEVOPERANDS<T>(a: T, b: T, c: T) -> T
where where
T: BitOr<Output = T> + Shl<u8, Output = T>, T: BitOr<Output = T> + Shl<u8, Output = T>,
{ {
@ -26,7 +29,7 @@ where
} }
pub unsafe fn C3D_TexEnvInit(env: *mut C3D_TexEnv) { pub unsafe fn C3D_TexEnvInit(env: *mut C3D_TexEnv) {
(*env).srcRgb = gpu_tevsources(GPU_PREVIOUS, 0, 0) as u16; (*env).srcRgb = GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0) as u16;
(*env).srcAlpha = (*env).srcRgb; (*env).srcAlpha = (*env).srcRgb;
(*env).__bindgen_anon_1.opAll = 0; (*env).__bindgen_anon_1.opAll = 0;
(*env).funcRgb = GPU_REPLACE as u16; (*env).funcRgb = GPU_REPLACE as u16;
@ -36,24 +39,35 @@ pub unsafe fn C3D_TexEnvInit(env: *mut C3D_TexEnv) {
(*env).scaleAlpha = GPU_TEVSCALE_1 as u16; (*env).scaleAlpha = GPU_TEVSCALE_1 as u16;
} }
// TODO: maybe pub unsafe fn C3D_TexEnvSrc(
env: *mut C3D_TexEnv,
pub unsafe fn C3D_TexEnvSrc(env: *mut C3D_TexEnv, mode: c_int, s1: c_int, s2: c_int, s3: c_int) { mode: C3D_TexEnvMode,
let param = gpu_tevsources(s1, s2, s3); s1: GPU_TEVSRC,
s2: GPU_TEVSRC, // default GPU_PRIMARY_COLOR
s3: GPU_TEVSRC, // default GPU_PRIMARY_COLOR
) {
let param = GPU_TEVSOURCES(s1, s2, s3);
if mode & C3D_RGB as i32 != 0 { if mode & C3D_RGB != 0 {
(*env).srcRgb = param as u16; (*env).srcRgb = param as u16;
} }
if mode & C3D_Alpha as i32 != 0 { if mode & C3D_Alpha != 0 {
(*env).srcAlpha = param as u16; (*env).srcAlpha = param as u16;
} }
} }
pub unsafe fn C3D_TexEnvOp(env: *mut C3D_TexEnv, mode: c_int, o1: c_int, o2: c_int, o3: c_int) { // TODO: match API of texenv.h
let param = gpu_tevoperands(o1, o2, o3); pub unsafe fn C3D_TexEnvOp(
env: *mut C3D_TexEnv,
if mode & C3D_RGB as i32 != 0 { mode: C3D_TexEnvMode,
o1: c_int,
o2: c_int,
o3: c_int,
) {
let param = GPU_TEVOPERANDS(o1, o2, o3);
if mode & C3D_RGB != 0 {
// (*env).opRgb = param as u16; // (*env).opRgb = param as u16;
(*env) (*env)
.__bindgen_anon_1 .__bindgen_anon_1
@ -61,7 +75,7 @@ pub unsafe fn C3D_TexEnvOp(env: *mut C3D_TexEnv, mode: c_int, o1: c_int, o2: c_i
.set_opRgb(param as u32); .set_opRgb(param as u32);
} }
if mode & C3D_Alpha as i32 != 0 { if mode & C3D_Alpha != 0 {
(*env) (*env)
.__bindgen_anon_1 .__bindgen_anon_1
.__bindgen_anon_1 .__bindgen_anon_1
@ -69,12 +83,12 @@ pub unsafe fn C3D_TexEnvOp(env: *mut C3D_TexEnv, mode: c_int, o1: c_int, o2: c_i
} }
} }
pub unsafe fn C3D_TexEnvFunc(env: *mut C3D_TexEnv, mode: c_int, param: c_int) { pub unsafe fn C3D_TexEnvFunc(env: *mut C3D_TexEnv, mode: C3D_TexEnvMode, param: GPU_COMBINEFUNC) {
if mode & C3D_RGB as i32 != 0 { if mode & C3D_RGB != 0 {
(*env).funcRgb = param as u16; (*env).funcRgb = param as u16;
} }
if mode & C3D_Alpha as i32 != 0 { if mode & C3D_Alpha != 0 {
(*env).funcAlpha = param as u16; (*env).funcAlpha = param as u16;
} }
} }

163
citro3d/examples/triangle.rs

@ -3,14 +3,43 @@ use citro3d_sys::{shaderProgram_s, DVLB_s};
use ctru::gfx::{Gfx, Screen, Side}; use ctru::gfx::{Gfx, Screen, Side};
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad}; use ctru::services::hid::{Hid, KeyPad};
use ctru::services::soc::Soc;
use std::ffi::CString; use std::ffi::CStr;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
#[repr(C)]
struct Vec3 {
x: f32,
y: f32,
z: f32,
}
impl Vec3 {
const fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
}
#[repr(C)]
struct Vertex {
pos: Vec3,
color: Vec3,
}
const VERTICES: [Vertex; 3] = [ const VERTICES: [Vertex; 3] = [
Vertex::new(200.0, 200.0, 0.5), Vertex {
Vertex::new(100.0, 40.0, 0.5), pos: Vec3::new(0.0, 0.5, 0.5),
Vertex::new(300.0, 40.0, 0.5), color: Vec3::new(1.0, 0.0, 0.0),
},
Vertex {
pos: Vec3::new(-0.5, -0.5, 0.5),
color: Vec3::new(0.0, 1.0, 0.0),
},
Vertex {
pos: Vec3::new(0.5, -0.5, 0.5),
color: Vec3::new(0.0, 0.0, 1.0),
},
]; ];
fn main() { fn main() {
@ -19,6 +48,8 @@ fn main() {
let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let mut soc = Soc::init().expect("failed to get SOC");
drop(soc.redirect_to_3dslink(true, true));
let top_screen = gfx.top_screen.borrow_mut(); let top_screen = gfx.top_screen.borrow_mut();
@ -48,21 +79,23 @@ fn main() {
let (program, uloc_projection, projection, vbo_data, vshader_dvlb) = scene_init(); let (program, uloc_projection, projection, vbo_data, vshader_dvlb) = scene_init();
// Main loop
while apt.main_loop() { while apt.main_loop() {
//Scan all the inputs. This should be done once for each frame
hid.scan_input(); hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::KEY_START) {
break; break;
} }
const CLEAR_COLOR: u32 = 0x68_B0_D8_FF; let clear_color: u32 = 0x7F_7F_7F_FF;
unsafe { unsafe {
citro3d_sys::C3D_FrameBegin(citro3d_sys::C3D_FRAME_SYNCDRAW as u8); citro3d_sys::C3D_FrameBegin(
citro3d_sys::C3D_FRAME_SYNCDRAW
.try_into()
.expect("const is valid u8"),
);
citro3d_sys::C3D_RenderTargetClear(target, citro3d_sys::C3D_CLEAR_ALL, CLEAR_COLOR, 0); citro3d_sys::C3D_RenderTargetClear(target, citro3d_sys::C3D_CLEAR_ALL, clear_color, 0);
citro3d_sys::C3D_FrameDrawOn(target); citro3d_sys::C3D_FrameDrawOn(target);
} }
scene_render(uloc_projection.into(), &projection); scene_render(uloc_projection.into(), &projection);
@ -78,19 +111,6 @@ fn main() {
} }
} }
#[repr(C)]
struct Vertex {
x: f32,
y: f32,
z: f32,
}
impl Vertex {
const fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
}
static SHBIN_BYTES: &[u8] = static SHBIN_BYTES: &[u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/examples/assets/vshader.shbin")); include_bytes!(concat!(env!("OUT_DIR"), "/examples/assets/vshader.shbin"));
@ -101,22 +121,22 @@ fn scene_init() -> (shaderProgram_s, i8, C3D_Mtx, *mut libc::c_void, *mut DVLB_s
// Assume the data is aligned properly... // Assume the data is aligned properly...
let vshader_dvlb = citro3d_sys::DVLB_ParseFile( let vshader_dvlb = citro3d_sys::DVLB_ParseFile(
shader_bytes.as_mut_ptr() as _, shader_bytes.as_mut_ptr().cast(),
(shader_bytes.len() / 4) (shader_bytes.len() / 4)
.try_into() .try_into()
.expect("shader len fits in a u32"), .expect("shader len fits in a u32"),
); );
let mut program = MaybeUninit::<citro3d_sys::shaderProgram_s>::uninit(); let mut program = {
let mut program = MaybeUninit::uninit();
citro3d_sys::shaderProgramInit(program.as_mut_ptr()); citro3d_sys::shaderProgramInit(program.as_mut_ptr());
citro3d_sys::shaderProgramSetVsh(program.as_mut_ptr(), (*vshader_dvlb).DVLE); program.assume_init()
};
let mut program = program.assume_init();
citro3d_sys::shaderProgramSetVsh(&mut program, (*vshader_dvlb).DVLE);
citro3d_sys::C3D_BindProgram(&mut program); citro3d_sys::C3D_BindProgram(&mut program);
// Get the location of the uniforms // Get the location of the uniforms
let projection_name = CString::new("projection").unwrap(); let projection_name = CStr::from_bytes_with_nul(b"projection\0").unwrap();
let uloc_projection = citro3d_sys::shaderInstanceGetUniformLocation( let uloc_projection = citro3d_sys::shaderInstanceGetUniformLocation(
program.vertexShader, program.vertexShader,
projection_name.as_ptr(), projection_name.as_ptr(),
@ -126,44 +146,46 @@ fn scene_init() -> (shaderProgram_s, i8, C3D_Mtx, *mut libc::c_void, *mut DVLB_s
let attr_info = citro3d_sys::C3D_GetAttrInfo(); let attr_info = citro3d_sys::C3D_GetAttrInfo();
citro3d_sys::AttrInfo_Init(attr_info); citro3d_sys::AttrInfo_Init(attr_info);
citro3d_sys::AttrInfo_AddLoader(attr_info, 0, citro3d_sys::GPU_FLOAT, 3); // v0=position citro3d_sys::AttrInfo_AddLoader(attr_info, 0, citro3d_sys::GPU_FLOAT, 3); // v0=position
citro3d_sys::AttrInfo_AddFixed(attr_info, 1); // v1=color citro3d_sys::AttrInfo_AddLoader(attr_info, 1, citro3d_sys::GPU_FLOAT, 3); // v1=color
// Set the fixed attribute (color) to solid white
citro3d_sys::C3D_FixedAttribSet(1, 1.0, 1.0, 1.0, 1.0);
let mut projection = MaybeUninit::<citro3d_sys::C3D_Mtx>::uninit();
// Compute the projection matrix // Compute the projection matrix
citro3d_sys::Mtx_OrthoTilt( let projection = {
projection.as_mut_ptr(), let mut projection = MaybeUninit::uninit();
0.0, citro3d_sys::Mtx_OrthoTilt(
400.0, projection.as_mut_ptr(),
0.0, // The 3ds top screen is a 5:3 ratio
240.0, -1.66,
0.0, 1.66,
1.0, -1.0,
true, 1.0,
); 0.0,
let projection = projection.assume_init(); 1.0,
true,
let vertices_len = std::mem::size_of_val(&VERTICES); );
projection.assume_init()
};
// Create the VBO (vertex buffer object) // Create the vertex buffer object
let vbo_data = let vbo_data: *mut Vertex = citro3d_sys::linearAlloc(
citro3d_sys::linearAlloc(vertices_len.try_into().expect("size does not fit in u32")); std::mem::size_of_val(&VERTICES)
.try_into()
.expect("size fits in u32"),
)
.cast();
vbo_data.copy_from(VERTICES.as_ptr().cast(), vertices_len); vbo_data.copy_from(VERTICES.as_ptr(), VERTICES.len());
// Configure buffers // Configure buffers
let buf_info = citro3d_sys::C3D_GetBufInfo(); let buf_info = citro3d_sys::C3D_GetBufInfo();
citro3d_sys::BufInfo_Init(buf_info); citro3d_sys::BufInfo_Init(buf_info);
citro3d_sys::BufInfo_Add( citro3d_sys::BufInfo_Add(
buf_info, buf_info,
vbo_data, vbo_data.cast(),
std::mem::size_of::<Vertex>() std::mem::size_of::<Vertex>()
.try_into() .try_into()
.expect("size of vertex fits in u32"), .expect("size of vec3 fits in u32"),
1, 2, // Each vertex has two attributes
0x0, 0x10, // v0 = position, v1 = color, in LSB->MSB nibble order
); );
// 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
@ -172,18 +194,20 @@ fn scene_init() -> (shaderProgram_s, i8, C3D_Mtx, *mut libc::c_void, *mut DVLB_s
citro3d_sys::C3D_TexEnvInit(env); citro3d_sys::C3D_TexEnvInit(env);
citro3d_sys::C3D_TexEnvSrc( citro3d_sys::C3D_TexEnvSrc(
env, env,
citro3d_sys::C3D_Both as i32, citro3d_sys::C3D_Both,
citro3d_sys::GPU_PRIMARY_COLOR as i32, citro3d_sys::GPU_PRIMARY_COLOR,
0, 0,
0, 0,
); );
citro3d_sys::C3D_TexEnvFunc( citro3d_sys::C3D_TexEnvFunc(env, citro3d_sys::C3D_Both, citro3d_sys::GPU_REPLACE);
env,
citro3d_sys::C3D_Both as i32, (
citro3d_sys::GPU_REPLACE as i32, program,
); uloc_projection,
projection,
(program, uloc_projection, projection, vbo_data, vshader_dvlb) vbo_data.cast(),
vshader_dvlb,
)
} }
} }
@ -193,7 +217,14 @@ fn scene_render(uloc_projection: i32, projection: &C3D_Mtx) {
citro3d_sys::C3D_FVUnifMtx4x4(citro3d_sys::GPU_VERTEX_SHADER, uloc_projection, projection); citro3d_sys::C3D_FVUnifMtx4x4(citro3d_sys::GPU_VERTEX_SHADER, uloc_projection, projection);
// Draw the VBO // Draw the VBO
citro3d_sys::C3D_DrawArrays(citro3d_sys::GPU_TRIANGLES, 0, VERTICES.len() as i32); citro3d_sys::C3D_DrawArrays(
citro3d_sys::GPU_TRIANGLES,
0,
VERTICES
.len()
.try_into()
.expect("VERTICES.len() fits in i32"),
);
} }
} }

Loading…
Cancel
Save