Ian Chamberlain
1 year ago
committed by
GitHub
16 changed files with 163 additions and 2055 deletions
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
[package] |
||||
name = "bindgen-citro3d" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
description = "Helper tool to generate citro3d-sys bindings." |
||||
publish = false |
||||
|
||||
[dependencies] |
||||
bindgen = "0.62.0" |
@ -1,92 +0,0 @@
@@ -1,92 +0,0 @@
|
||||
//! This is meant to be run as a "script" to generate bindings to `citro3d`.
|
||||
//! We use this instead of `bindgen-cli` to enable the use of [`CustomCallbacks`]
|
||||
//! with [`bindgen`] as a library for finer grained control of the bindings.
|
||||
|
||||
use std::iter::FromIterator; |
||||
use std::path::PathBuf; |
||||
|
||||
use bindgen::callbacks::{DeriveTrait, ImplementsTrait, ParseCallbacks}; |
||||
use bindgen::{Builder, RustTarget}; |
||||
|
||||
fn main() { |
||||
let devkitpro = std::env::var("DEVKITPRO").expect("DEVKITPRO not set in environment"); |
||||
let devkitarm = std::env::var("DEVKITARM").expect("DEVKITARM not set in environment"); |
||||
|
||||
let include_path = PathBuf::from_iter([devkitpro.as_str(), "libctru", "include"]); |
||||
let header = include_path.join("tex3ds.h"); |
||||
|
||||
let sysroot = PathBuf::from(devkitarm).join("arm-none-eabi"); |
||||
let system_include = sysroot.join("include"); |
||||
|
||||
let bindings = Builder::default() |
||||
.header(header.to_str().unwrap()) |
||||
.rust_target(RustTarget::Nightly) |
||||
.use_core() |
||||
.trust_clang_mangling(false) |
||||
.layout_tests(false) |
||||
.ctypes_prefix("::libc") |
||||
.prepend_enum_name(false) |
||||
.fit_macro_constants(true) |
||||
.raw_line("use ctru_sys::*;") |
||||
.must_use_type("Result") |
||||
.blocklist_type("u(8|16|32|64)") |
||||
.opaque_type("(GPU|GFX)_.*") |
||||
.opaque_type("float24Uniform_s") |
||||
.allowlist_file(".*/c3d/.*[.]h") |
||||
.allowlist_file(".*/tex3ds[.]h") |
||||
.blocklist_file(".*/3ds/.*[.]h") |
||||
.blocklist_file(".*/sys/.*[.]h") |
||||
.clang_args([ |
||||
"--target=arm-none-eabi", |
||||
"--sysroot", |
||||
sysroot.to_str().unwrap(), |
||||
"-isystem", |
||||
system_include.to_str().unwrap(), |
||||
"-I", |
||||
include_path.to_str().unwrap(), |
||||
"-mfloat-abi=hard", |
||||
"-march=armv6k", |
||||
"-mtune=mpcore", |
||||
"-mfpu=vfp", |
||||
"-DARM11 ", |
||||
"-D_3DS ", |
||||
"-D__3DS__ ", |
||||
]) |
||||
.parse_callbacks(Box::new(CustomCallbacks)) |
||||
.generate() |
||||
.expect("Unable to generate bindings"); |
||||
|
||||
bindings |
||||
.write(Box::new(std::io::stdout())) |
||||
.expect("failed to write bindings"); |
||||
} |
||||
|
||||
/// Custom callback struct to allow us to mark some "known good types" as
|
||||
/// [`Copy`], which in turn allows using Rust `union` instead of bindgen union
|
||||
/// types. See
|
||||
/// <https://rust-lang.github.io/rust-bindgen/using-unions.html#which-union-type-will-bindgen-generate>
|
||||
/// for more info.
|
||||
///
|
||||
/// We do the same for [`Debug`] just for the convenience of derived Debug impls
|
||||
/// on some `citro3d` types.
|
||||
#[derive(Debug)] |
||||
struct CustomCallbacks; |
||||
|
||||
impl ParseCallbacks for CustomCallbacks { |
||||
fn blocklisted_type_implements_trait( |
||||
&self, |
||||
name: &str, |
||||
derive_trait: DeriveTrait, |
||||
) -> Option<ImplementsTrait> { |
||||
if let DeriveTrait::Copy | DeriveTrait::Debug = derive_trait { |
||||
match name { |
||||
"u64_" | "u32_" | "u16_" | "u8_" | "u64" | "u32" | "u16" | "u8" | "gfxScreen_t" |
||||
| "gfx3dSide_t" => Some(ImplementsTrait::Yes), |
||||
_ if name.starts_with("GPU_") => Some(ImplementsTrait::Yes), |
||||
_ => None, |
||||
} |
||||
} else { |
||||
None |
||||
} |
||||
} |
||||
} |
@ -1,10 +1,16 @@
@@ -1,10 +1,16 @@
|
||||
[package] |
||||
name = "citro3d-sys" |
||||
version = "0.1.0" |
||||
authors = [ "Rust3DS Org", "panicbit <panicbit.dev@gmail.com>" ] |
||||
authors = ["Rust3DS Org", "panicbit <panicbit.dev@gmail.com>"] |
||||
edition = "2021" |
||||
license = "Zlib" |
||||
links = "citro3d" |
||||
|
||||
[dependencies] |
||||
libc = "0.2.116" |
||||
ctru-sys = { git = "https://github.com/rust3ds/ctru-rs.git" } |
||||
|
||||
[build-dependencies] |
||||
bindgen = { version = "0.68.1", features = ["experimental"] } |
||||
cc = "1.0.83" |
||||
doxygen-rs = "0.4.2" |
||||
|
@ -1,19 +1,157 @@
@@ -1,19 +1,157 @@
|
||||
//! This build script generates bindings from `citro3d` on the fly at compilation
|
||||
//! time into `OUT_DIR`, from which they can be included into `lib.rs`.
|
||||
|
||||
use std::env; |
||||
use std::iter::FromIterator; |
||||
use std::path::{Path, PathBuf}; |
||||
|
||||
use bindgen::callbacks::{DeriveTrait, ImplementsTrait, ParseCallbacks}; |
||||
use bindgen::{Builder, RustTarget}; |
||||
|
||||
fn main() { |
||||
let dkp_path = env::var("DEVKITPRO").unwrap(); |
||||
let devkitpro = env::var("DEVKITPRO").expect("DEVKITPRO not set in environment"); |
||||
println!("cargo:rerun-if-env-changed=DEVKITPRO"); |
||||
|
||||
let devkitarm = std::env::var("DEVKITARM").expect("DEVKITARM not set in environment"); |
||||
println!("cargo:rerun-if-env-changed=DEVKITARM"); |
||||
|
||||
let debug_symbols = env::var("DEBUG").unwrap(); |
||||
println!("cargo:rerun-if-env-changed=DEBUG"); |
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); |
||||
println!("cargo:rerun-if-env-changed=OUT_DIR"); |
||||
|
||||
println!("cargo:rerun-if-changed=build.rs"); |
||||
println!("cargo:rerun-if-env-changed=DEVKITPRO"); |
||||
println!("cargo:rustc-link-search=native={dkp_path}/libctru/lib"); |
||||
println!("cargo:rustc-link-search=native={devkitpro}/libctru/lib"); |
||||
println!( |
||||
"cargo:rustc-link-lib=static={}", |
||||
match debug_symbols.as_str() { |
||||
// Based on valid values described in
|
||||
// https://doc.rust-lang.org/cargo/reference/profiles.html#debug
|
||||
"0" | "false" => "citro3d", |
||||
"0" | "false" | "none" => "citro3d", |
||||
_ => "citro3dd", |
||||
} |
||||
); |
||||
|
||||
let include_path = PathBuf::from_iter([devkitpro.as_str(), "libctru", "include"]); |
||||
let tex3ds_h = include_path.join("tex3ds.h"); |
||||
let citro3d_h = include_path.join("citro3d.h"); |
||||
let three_ds_h = include_path.join("3ds.h"); |
||||
|
||||
let sysroot = Path::new(devkitarm.as_str()).join("arm-none-eabi"); |
||||
let system_include = sysroot.join("include"); |
||||
let static_fns_path = Path::new("citro3d_statics_wrapper"); |
||||
|
||||
let gcc_dir = PathBuf::from_iter([devkitarm.as_str(), "lib", "gcc", "arm-none-eabi"]); |
||||
|
||||
let gcc_include = gcc_dir |
||||
.read_dir() |
||||
.unwrap() |
||||
// Assuming that there is only one gcc version of libs under the devkitARM dir
|
||||
.next() |
||||
.unwrap() |
||||
.unwrap() |
||||
.path() |
||||
.join("include"); |
||||
|
||||
let bindings = Builder::default() |
||||
.header(three_ds_h.to_str().unwrap()) |
||||
.header(citro3d_h.to_str().unwrap()) |
||||
.header(tex3ds_h.to_str().unwrap()) |
||||
.rust_target(RustTarget::Nightly) |
||||
.use_core() |
||||
.trust_clang_mangling(false) |
||||
.layout_tests(false) |
||||
.ctypes_prefix("::libc") |
||||
.prepend_enum_name(false) |
||||
.fit_macro_constants(true) |
||||
.raw_line("use ctru_sys::*;") |
||||
.must_use_type("Result") |
||||
.blocklist_type("u(8|16|32|64)") |
||||
.opaque_type("(GPU|GFX)_.*") |
||||
.opaque_type("float24Uniform_s") |
||||
.allowlist_file(".*/c3d/.*[.]h") |
||||
.allowlist_file(".*/tex3ds[.]h") |
||||
.blocklist_file(".*/3ds/.*[.]h") |
||||
.blocklist_file(".*/sys/.*[.]h") |
||||
.wrap_static_fns(true) |
||||
.wrap_static_fns_path(out_dir.join(static_fns_path)) |
||||
.clang_args([ |
||||
"--target=arm-none-eabi", |
||||
"--sysroot", |
||||
sysroot.to_str().unwrap(), |
||||
"-isystem", |
||||
system_include.to_str().unwrap(), |
||||
"-isystem", |
||||
gcc_include.to_str().unwrap(), |
||||
"-I", |
||||
include_path.to_str().unwrap(), |
||||
"-mfloat-abi=hard", |
||||
"-march=armv6k", |
||||
"-mtune=mpcore", |
||||
"-mfpu=vfp", |
||||
"-DARM11 ", |
||||
"-D_3DS ", |
||||
"-D__3DS__ ", |
||||
]) |
||||
.parse_callbacks(Box::new(CustomCallbacks)) |
||||
.generate() |
||||
.expect("Unable to generate bindings"); |
||||
|
||||
bindings |
||||
.write_to_file(out_dir.join("bindings.rs")) |
||||
.expect("failed to write bindings"); |
||||
|
||||
// Compile static inline fns wrapper
|
||||
let cc = Path::new(devkitarm.as_str()).join("bin/arm-none-eabi-gcc"); |
||||
let ar = Path::new(devkitarm.as_str()).join("bin/arm-none-eabi-ar"); |
||||
|
||||
cc::Build::new() |
||||
.compiler(cc) |
||||
.archiver(ar) |
||||
.include(&include_path) |
||||
.file(out_dir.join(static_fns_path.with_extension("c"))) |
||||
.flag("-march=armv6k") |
||||
.flag("-mtune=mpcore") |
||||
.flag("-mfloat-abi=hard") |
||||
.flag("-mfpu=vfp") |
||||
.flag("-mtp=soft") |
||||
.flag("-Wno-deprecated-declarations") |
||||
.compile("citro3d_statics_wrapper"); |
||||
} |
||||
|
||||
/// Custom callback struct to allow us to mark some "known good types" as
|
||||
/// [`Copy`], which in turn allows using Rust `union` instead of bindgen union types. See
|
||||
/// <https://rust-lang.github.io/rust-bindgen/using-unions.html#which-union-type-will-bindgen-generate>
|
||||
/// for more info.
|
||||
///
|
||||
/// We do the same for [`Debug`] just for the convenience of derived Debug impls
|
||||
/// on some `citro3d` types.
|
||||
///
|
||||
/// Finally, we use [`doxygen_rs`] to transform the doc comments into something
|
||||
/// easier to read in the generated documentation / hover documentation.
|
||||
#[derive(Debug)] |
||||
struct CustomCallbacks; |
||||
|
||||
impl ParseCallbacks for CustomCallbacks { |
||||
fn process_comment(&self, comment: &str) -> Option<String> { |
||||
Some(doxygen_rs::transform(comment)) |
||||
} |
||||
|
||||
fn blocklisted_type_implements_trait( |
||||
&self, |
||||
name: &str, |
||||
derive_trait: DeriveTrait, |
||||
) -> Option<ImplementsTrait> { |
||||
if let DeriveTrait::Copy | DeriveTrait::Debug = derive_trait { |
||||
match name { |
||||
"u64_" | "u32_" | "u16_" | "u8_" | "u64" | "u32" | "u16" | "u8" | "gfxScreen_t" |
||||
| "gfx3dSide_t" => Some(ImplementsTrait::Yes), |
||||
_ if name.starts_with("GPU_") => Some(ImplementsTrait::Yes), |
||||
_ => None, |
||||
} |
||||
} else { |
||||
None |
||||
} |
||||
} |
||||
} |
||||
|
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
//! Definitions from `<c3d/base.h>`
|
||||
|
||||
use crate::C3D_FixedAttribGetWritePtr; |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_FixedAttribSet(id: libc::c_int, x: f32, y: f32, z: f32, w: f32) { |
||||
let ptr = C3D_FixedAttribGetWritePtr(id); |
||||
(*ptr).c.copy_from_slice(&[x, y, z, w]); |
||||
} |
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
// TODO: move this to ctru-sys, maybe?
|
||||
// would probably be auto-generated via https://github.com/rust3ds/ctru-rs/issues/123
|
||||
|
||||
use ctru_sys::{osSharedConfig_s, OS_SHAREDCFG_VADDR}; |
||||
|
||||
fn OS_SharedConfig() -> *mut osSharedConfig_s { |
||||
OS_SHAREDCFG_VADDR as _ |
||||
} |
||||
|
||||
/// Gets the state of the 3D slider as a value from 0.0 to 1.0
|
||||
pub unsafe fn osGet3DSliderState() -> f32 { |
||||
(*OS_SharedConfig()).slider_3d |
||||
} |
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
//! Definitions from `<c3d/renderqueue.h>`
|
||||
|
||||
use crate::*; |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_RenderTargetDetachOutput(target: *mut C3D_RenderTarget) { |
||||
C3D_RenderTargetSetOutput(core::ptr::null_mut(), (*target).screen, (*target).side, 0); |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_RenderTargetClear( |
||||
target: *mut C3D_RenderTarget, |
||||
clearBits: C3D_ClearBits, |
||||
clearColor: u32, |
||||
clearDepth: u32, |
||||
) { |
||||
C3D_FrameBufClear(&mut (*target).frameBuf, clearBits, clearColor, clearDepth); |
||||
} |
@ -1,100 +0,0 @@
@@ -1,100 +0,0 @@
|
||||
//! Definitions from `<c3d/texenv.h>`.
|
||||
//!
|
||||
//! 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>.
|
||||
|
||||
use core::ops::{BitOr, Shl}; |
||||
|
||||
use ctru_sys::{GPU_COMBINEFUNC, GPU_PREVIOUS, GPU_REPLACE, GPU_TEVSCALE_1, GPU_TEVSRC}; |
||||
use libc::c_int; |
||||
|
||||
use super::*; |
||||
|
||||
// TODO: why are these two different macros in C?
|
||||
|
||||
/// Creates a texture combiner source parameter from three sources.
|
||||
#[inline] |
||||
fn GPU_TEVSOURCES<T>(a: T, b: T, c: T) -> T |
||||
where |
||||
T: BitOr<Output = T> + Shl<u8, Output = T>, |
||||
{ |
||||
a | b << 4 | c << 8 |
||||
} |
||||
|
||||
/// Creates a texture combiner operand parameter from three operands.
|
||||
#[inline] |
||||
fn GPU_TEVOPERANDS<T>(a: T, b: T, c: T) -> T |
||||
where |
||||
T: BitOr<Output = T> + Shl<u8, Output = T>, |
||||
{ |
||||
a | b << 4 | c << 8 |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_TexEnvInit(env: *mut C3D_TexEnv) { |
||||
(*env).srcRgb = GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0) as u16; |
||||
(*env).srcAlpha = (*env).srcRgb; |
||||
(*env).__bindgen_anon_1.opAll = 0; |
||||
(*env).funcRgb = GPU_REPLACE as u16; |
||||
(*env).funcAlpha = (*env).funcRgb; |
||||
(*env).color = 0xFFFFFFFF; |
||||
(*env).scaleRgb = GPU_TEVSCALE_1 as u16; |
||||
(*env).scaleAlpha = GPU_TEVSCALE_1 as u16; |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_TexEnvSrc( |
||||
env: *mut C3D_TexEnv, |
||||
mode: C3D_TexEnvMode, |
||||
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 != 0 { |
||||
(*env).srcRgb = param as u16; |
||||
} |
||||
|
||||
if mode & C3D_Alpha != 0 { |
||||
(*env).srcAlpha = param as u16; |
||||
} |
||||
} |
||||
|
||||
// TODO: match API of texenv.h
|
||||
#[inline] |
||||
pub unsafe fn C3D_TexEnvOp( |
||||
env: *mut C3D_TexEnv, |
||||
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) |
||||
.__bindgen_anon_1 |
||||
.__bindgen_anon_1 |
||||
.set_opRgb(param as u32); |
||||
} |
||||
|
||||
if mode & C3D_Alpha != 0 { |
||||
(*env) |
||||
.__bindgen_anon_1 |
||||
.__bindgen_anon_1 |
||||
.set_opAlpha(param as u32); |
||||
} |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_TexEnvFunc(env: *mut C3D_TexEnv, mode: C3D_TexEnvMode, param: GPU_COMBINEFUNC) { |
||||
if mode & C3D_RGB != 0 { |
||||
(*env).funcRgb = param as u16; |
||||
} |
||||
|
||||
if mode & C3D_Alpha != 0 { |
||||
(*env).funcAlpha = param as u16; |
||||
} |
||||
} |
@ -1,50 +0,0 @@
@@ -1,50 +0,0 @@
|
||||
//! Definitions from`<c3d/uniforms.h>`
|
||||
|
||||
use ctru_sys::GPU_SHADER_TYPE; |
||||
|
||||
use super::{C3D_FVUnif, C3D_FVUnifDirty, C3D_FVec, C3D_Mtx}; |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_FVUnifWritePtr( |
||||
type_: GPU_SHADER_TYPE, |
||||
id: libc::c_int, |
||||
size: libc::c_int, |
||||
) -> *mut C3D_FVec { |
||||
for i in 0..size { |
||||
C3D_FVUnifDirty[type_ as usize][(id + i) as usize] = true; |
||||
} |
||||
|
||||
return &mut C3D_FVUnif[type_ as usize][id as usize]; |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_FVUnifMtxNx4( |
||||
type_: GPU_SHADER_TYPE, |
||||
id: libc::c_int, |
||||
mtx: *const C3D_Mtx, |
||||
num: libc::c_int, |
||||
) { |
||||
let ptr = C3D_FVUnifWritePtr(type_, id, num); |
||||
|
||||
for i in 0..num { |
||||
*ptr.offset(i as isize) = (*mtx).r.as_ref()[i as usize]; |
||||
} |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_FVUnifMtx4x4(type_: GPU_SHADER_TYPE, id: libc::c_int, mtx: *const C3D_Mtx) { |
||||
C3D_FVUnifMtxNx4(type_, id, mtx, 4); |
||||
} |
||||
|
||||
#[inline] |
||||
pub unsafe fn C3D_FVUnifSet( |
||||
type_: GPU_SHADER_TYPE, |
||||
id: libc::c_int, |
||||
x: f32, |
||||
y: f32, |
||||
z: f32, |
||||
w: f32, |
||||
) { |
||||
let ptr = C3D_FVUnifWritePtr(type_, id, 1); |
||||
(*ptr).c.copy_from_slice(&[x, y, z, w]); |
||||
} |
Loading…
Reference in new issue