Browse Source

First pass of safe buffer info API

pull/16/head
Ian Chamberlain 2 years ago
parent
commit
704f6e58b7
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 1
      Cargo.toml
  2. 287
      citro3d-sys/src/bindings.rs
  3. 53
      citro3d/examples/triangle.rs
  4. 117
      citro3d/src/attrib.rs
  5. 55
      citro3d/src/buffers.rs
  6. 17
      citro3d/src/error.rs
  7. 5
      citro3d/src/lib.rs
  8. 1
      citro3d/src/vbo.rs

1
Cargo.toml

@ -1,5 +1,6 @@
[workspace] [workspace]
members = ["citro3d-sys", "citro3d", "bindgen-citro3d"] members = ["citro3d-sys", "citro3d", "bindgen-citro3d"]
default-members = ["citro3d-sys", "citro3d"]
[patch."https://github.com/rust3ds/citro3d-rs.git"] [patch."https://github.com/rust3ds/citro3d-rs.git"]
citro3d-sys = { path = "citro3d-sys" } citro3d-sys = { path = "citro3d-sys" }

287
citro3d-sys/src/bindings.rs

@ -1,4 +1,4 @@
/* automatically generated by rust-bindgen 0.62.0 */ /* automatically generated by rust-bindgen 0.64.0 */
use ctru_sys::*; use ctru_sys::*;
@ -96,10 +96,7 @@ pub type _off_t = __int64_t;
pub type _fpos_t = __int64_t; pub type _fpos_t = __int64_t;
pub type wint_t = ::libc::c_int; pub type wint_t = ::libc::c_int;
pub type C3D_IVec = u32_; pub type C3D_IVec = u32_;
#[doc = " @struct C3D_FVec"] #[doc = " @struct C3D_FVec\n @brief Float vector\n\n Matches PICA layout"]
#[doc = " @brief Float vector"]
#[doc = ""]
#[doc = " Matches PICA layout"]
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub union C3D_FVec { pub union C3D_FVec {
@ -134,13 +131,9 @@ pub struct C3D_FVec__bindgen_ty_2 {
#[doc = "< I-component"] #[doc = "< I-component"]
pub i: f32, pub i: f32,
} }
#[doc = " @struct C3D_FVec"] #[doc = " @struct C3D_FVec\n @brief Float vector\n\n Matches PICA layout"]
#[doc = " @brief Float vector"]
#[doc = ""]
#[doc = " Matches PICA layout"]
pub type C3D_FQuat = C3D_FVec; pub type C3D_FQuat = C3D_FVec;
#[doc = " @struct C3D_Mtx"] #[doc = " @struct C3D_Mtx\n @brief Row-major 4x4 matrix"]
#[doc = " @brief Row-major 4x4 matrix"]
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub union C3D_Mtx { pub union C3D_Mtx {
@ -150,101 +143,55 @@ pub union C3D_Mtx {
pub m: [f32; 16usize], pub m: [f32; 16usize],
} }
extern "C" { extern "C" {
#[doc = "@brief Transposes the matrix. Row => Column, and vice versa."] #[doc = "@brief Transposes the matrix. Row => Column, and vice versa.\n@param[in,out] out Output matrix."]
#[doc = "@param[in,out] out Output matrix."]
pub fn Mtx_Transpose(out: *mut C3D_Mtx); pub fn Mtx_Transpose(out: *mut C3D_Mtx);
} }
extern "C" { extern "C" {
#[doc = " @brief Multiply two matrices"] #[doc = " @brief Multiply two matrices\n @param[out] out Output matrix\n @param[in] a Multiplicand\n @param[in] b Multiplier"]
#[doc = " @param[out] out Output matrix"]
#[doc = " @param[in] a Multiplicand"]
#[doc = " @param[in] b Multiplier"]
pub fn Mtx_Multiply(out: *mut C3D_Mtx, a: *const C3D_Mtx, b: *const C3D_Mtx); pub fn Mtx_Multiply(out: *mut C3D_Mtx, a: *const C3D_Mtx, b: *const C3D_Mtx);
} }
extern "C" { extern "C" {
#[doc = " @brief Inverse a matrix"] #[doc = " @brief Inverse a matrix\n @param[in,out] out Matrix to inverse\n @retval 0.0f Degenerate matrix (no inverse)\n @return determinant"]
#[doc = " @param[in,out] out Matrix to inverse"]
#[doc = " @retval 0.0f Degenerate matrix (no inverse)"]
#[doc = " @return determinant"]
pub fn Mtx_Inverse(out: *mut C3D_Mtx) -> f32; pub fn Mtx_Inverse(out: *mut C3D_Mtx) -> f32;
} }
extern "C" { extern "C" {
#[doc = " @brief Multiply 3x3 matrix by a FVec3"] #[doc = " @brief Multiply 3x3 matrix by a FVec3\n @param[in] mtx Matrix\n @param[in] v Vector\n @return mtx*v (product)"]
#[doc = " @param[in] mtx Matrix"]
#[doc = " @param[in] v Vector"]
#[doc = " @return mtx*v (product)"]
pub fn Mtx_MultiplyFVec3(mtx: *const C3D_Mtx, v: C3D_FVec) -> C3D_FVec; pub fn Mtx_MultiplyFVec3(mtx: *const C3D_Mtx, v: C3D_FVec) -> C3D_FVec;
} }
extern "C" { extern "C" {
#[doc = " @brief Multiply 4x4 matrix by a FVec4"] #[doc = " @brief Multiply 4x4 matrix by a FVec4\n @param[in] mtx Matrix\n @param[in] v Vector\n @return mtx*v (product)"]
#[doc = " @param[in] mtx Matrix"]
#[doc = " @param[in] v Vector"]
#[doc = " @return mtx*v (product)"]
pub fn Mtx_MultiplyFVec4(mtx: *const C3D_Mtx, v: C3D_FVec) -> C3D_FVec; pub fn Mtx_MultiplyFVec4(mtx: *const C3D_Mtx, v: C3D_FVec) -> C3D_FVec;
} }
extern "C" { extern "C" {
#[doc = " @brief Get 4x4 matrix equivalent to Quaternion"] #[doc = " @brief Get 4x4 matrix equivalent to Quaternion\n @param[out] m Output matrix\n @param[in] q Input Quaternion"]
#[doc = " @param[out] m Output matrix"]
#[doc = " @param[in] q Input Quaternion"]
pub fn Mtx_FromQuat(m: *mut C3D_Mtx, q: C3D_FQuat); pub fn Mtx_FromQuat(m: *mut C3D_Mtx, q: C3D_FQuat);
} }
extern "C" { extern "C" {
#[doc = " @brief 3D translation"] #[doc = " @brief 3D translation\n @param[in,out] mtx Matrix to translate\n @param[in] x X component to translate\n @param[in] y Y component to translate\n @param[in] z Z component to translate\n @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @param[in,out] mtx Matrix to translate"]
#[doc = " @param[in] x X component to translate"]
#[doc = " @param[in] y Y component to translate"]
#[doc = " @param[in] z Z component to translate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
pub fn Mtx_Translate(mtx: *mut C3D_Mtx, x: f32, y: f32, z: f32, bRightSide: bool); pub fn Mtx_Translate(mtx: *mut C3D_Mtx, x: f32, y: f32, z: f32, bRightSide: bool);
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Scale"] #[doc = " @brief 3D Scale\n @param[in,out] mtx Matrix to scale\n @param[in] x X component to scale\n @param[in] y Y component to scale\n @param[in] z Z component to scale"]
#[doc = " @param[in,out] mtx Matrix to scale"]
#[doc = " @param[in] x X component to scale"]
#[doc = " @param[in] y Y component to scale"]
#[doc = " @param[in] z Z component to scale"]
pub fn Mtx_Scale(mtx: *mut C3D_Mtx, x: f32, y: f32, z: f32); pub fn Mtx_Scale(mtx: *mut C3D_Mtx, x: f32, y: f32, z: f32);
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation"] #[doc = " @brief 3D Rotation\n @param[in,out] mtx Matrix to rotate\n @param[in] axis Axis about which to rotate\n @param[in] angle Radians to rotate\n @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @param[in,out] mtx Matrix to rotate"]
#[doc = " @param[in] axis Axis about which to rotate"]
#[doc = " @param[in] angle Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
pub fn Mtx_Rotate(mtx: *mut C3D_Mtx, axis: C3D_FVec, angle: f32, bRightSide: bool); pub fn Mtx_Rotate(mtx: *mut C3D_Mtx, axis: C3D_FVec, angle: f32, bRightSide: bool);
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation about the X axis"] #[doc = " @brief 3D Rotation about the X axis\n @param[in,out] mtx Matrix to rotate\n @param[in] angle Radians to rotate\n @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @param[in,out] mtx Matrix to rotate"]
#[doc = " @param[in] angle Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
pub fn Mtx_RotateX(mtx: *mut C3D_Mtx, angle: f32, bRightSide: bool); pub fn Mtx_RotateX(mtx: *mut C3D_Mtx, angle: f32, bRightSide: bool);
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation about the Y axis"] #[doc = " @brief 3D Rotation about the Y axis\n @param[in,out] mtx Matrix to rotate\n @param[in] angle Radians to rotate\n @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @param[in,out] mtx Matrix to rotate"]
#[doc = " @param[in] angle Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
pub fn Mtx_RotateY(mtx: *mut C3D_Mtx, angle: f32, bRightSide: bool); pub fn Mtx_RotateY(mtx: *mut C3D_Mtx, angle: f32, bRightSide: bool);
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation about the Z axis"] #[doc = " @brief 3D Rotation about the Z axis\n @param[in,out] mtx Matrix to rotate\n @param[in] angle Radians to rotate\n @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @param[in,out] mtx Matrix to rotate"]
#[doc = " @param[in] angle Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
pub fn Mtx_RotateZ(mtx: *mut C3D_Mtx, angle: f32, bRightSide: bool); pub fn Mtx_RotateZ(mtx: *mut C3D_Mtx, angle: f32, bRightSide: bool);
} }
extern "C" { extern "C" {
#[doc = " @brief Orthogonal projection"] #[doc = " @brief Orthogonal projection\n @param[out] mtx Output matrix\n @param[in] left Left clip plane (X=left)\n @param[in] right Right clip plane (X=right)\n @param[in] bottom Bottom clip plane (Y=bottom)\n @param[in] top Top clip plane (Y=top)\n @param[in] near Near clip plane (Z=near)\n @param[in] far Far clip plane (Z=far)\n @param[in] isLeftHanded Whether to build a LH projection\n @sa Mtx_OrthoTilt"]
#[doc = " @param[out] mtx Output matrix"]
#[doc = " @param[in] left Left clip plane (X=left)"]
#[doc = " @param[in] right Right clip plane (X=right)"]
#[doc = " @param[in] bottom Bottom clip plane (Y=bottom)"]
#[doc = " @param[in] top Top clip plane (Y=top)"]
#[doc = " @param[in] near Near clip plane (Z=near)"]
#[doc = " @param[in] far Far clip plane (Z=far)"]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @sa Mtx_OrthoTilt"]
pub fn Mtx_Ortho( pub fn Mtx_Ortho(
mtx: *mut C3D_Mtx, mtx: *mut C3D_Mtx,
left: f32, left: f32,
@ -257,16 +204,7 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Perspective projection"] #[doc = " @brief Perspective projection\n @param[out] mtx Output matrix\n @param[in] fovy Vertical field of view in radians\n @param[in] aspect Aspect ration of projection plane (width/height)\n @param[in] near Near clip plane (Z=near)\n @param[in] far Far clip plane (Z=far)\n @param[in] isLeftHanded Whether to build a LH projection\n @sa Mtx_PerspTilt\n @sa Mtx_PerspStereo\n @sa Mtx_PerspStereoTilt"]
#[doc = " @param[out] mtx Output matrix"]
#[doc = " @param[in] fovy Vertical field of view in radians"]
#[doc = " @param[in] aspect Aspect ration of projection plane (width/height)"]
#[doc = " @param[in] near Near clip plane (Z=near)"]
#[doc = " @param[in] far Far clip plane (Z=far)"]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @sa Mtx_PerspTilt"]
#[doc = " @sa Mtx_PerspStereo"]
#[doc = " @sa Mtx_PerspStereoTilt"]
pub fn Mtx_Persp( pub fn Mtx_Persp(
mtx: *mut C3D_Mtx, mtx: *mut C3D_Mtx,
fovy: f32, fovy: f32,
@ -277,24 +215,7 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Stereo perspective projection"] #[doc = " @brief Stereo perspective projection\n @note Typically you will use iod to mean the distance between the eyes. Plug\n in -iod for the left eye and iod for the right eye.\n @note The focal length is defined by screen. If objects are further than this,\n they will appear to be inside the screen. If objects are closer than this,\n they will appear to pop out of the screen. Objects at this distance appear\n to be at the screen.\n @param[out] mtx Output matrix\n @param[in] fovy Vertical field of view in radians\n @param[in] aspect Aspect ration of projection plane (width/height)\n @param[in] near Near clip plane (Z=near)\n @param[in] far Far clip plane (Z=far)\n @param[in] iod Interocular distance\n @param[in] screen Focal length\n @param[in] isLeftHanded Whether to build a LH projection\n @sa Mtx_Persp\n @sa Mtx_PerspTilt\n @sa Mtx_PerspStereoTilt"]
#[doc = " @note Typically you will use iod to mean the distance between the eyes. Plug"]
#[doc = " in -iod for the left eye and iod for the right eye."]
#[doc = " @note The focal length is defined by screen. If objects are further than this,"]
#[doc = " they will appear to be inside the screen. If objects are closer than this,"]
#[doc = " they will appear to pop out of the screen. Objects at this distance appear"]
#[doc = " to be at the screen."]
#[doc = " @param[out] mtx Output matrix"]
#[doc = " @param[in] fovy Vertical field of view in radians"]
#[doc = " @param[in] aspect Aspect ration of projection plane (width/height)"]
#[doc = " @param[in] near Near clip plane (Z=near)"]
#[doc = " @param[in] far Far clip plane (Z=far)"]
#[doc = " @param[in] iod Interocular distance"]
#[doc = " @param[in] screen Focal length"]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @sa Mtx_Persp"]
#[doc = " @sa Mtx_PerspTilt"]
#[doc = " @sa Mtx_PerspStereoTilt"]
pub fn Mtx_PerspStereo( pub fn Mtx_PerspStereo(
mtx: *mut C3D_Mtx, mtx: *mut C3D_Mtx,
fovy: f32, fovy: f32,
@ -307,16 +228,7 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Orthogonal projection, tilted to account for the 3DS screen rotation"] #[doc = " @brief Orthogonal projection, tilted to account for the 3DS screen rotation\n @param[out] mtx Output matrix\n @param[in] left Left clip plane (X=left)\n @param[in] right Right clip plane (X=right)\n @param[in] bottom Bottom clip plane (Y=bottom)\n @param[in] top Top clip plane (Y=top)\n @param[in] near Near clip plane (Z=near)\n @param[in] far Far clip plane (Z=far)\n @param[in] isLeftHanded Whether to build a LH projection\n @sa Mtx_Ortho"]
#[doc = " @param[out] mtx Output matrix"]
#[doc = " @param[in] left Left clip plane (X=left)"]
#[doc = " @param[in] right Right clip plane (X=right)"]
#[doc = " @param[in] bottom Bottom clip plane (Y=bottom)"]
#[doc = " @param[in] top Top clip plane (Y=top)"]
#[doc = " @param[in] near Near clip plane (Z=near)"]
#[doc = " @param[in] far Far clip plane (Z=far)"]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @sa Mtx_Ortho"]
pub fn Mtx_OrthoTilt( pub fn Mtx_OrthoTilt(
mtx: *mut C3D_Mtx, mtx: *mut C3D_Mtx,
left: f32, left: f32,
@ -329,16 +241,7 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Perspective projection, tilted to account for the 3DS screen rotation"] #[doc = " @brief Perspective projection, tilted to account for the 3DS screen rotation\n @param[out] mtx Output matrix\n @param[in] fovy Vertical field of view in radians\n @param[in] aspect Aspect ration of projection plane (width/height)\n @param[in] near Near clip plane (Z=near)\n @param[in] far Far clip plane (Z=far)\n @param[in] isLeftHanded Whether to build a LH projection\n @sa Mtx_Persp\n @sa Mtx_PerspStereo\n @sa Mtx_PerspStereoTilt"]
#[doc = " @param[out] mtx Output matrix"]
#[doc = " @param[in] fovy Vertical field of view in radians"]
#[doc = " @param[in] aspect Aspect ration of projection plane (width/height)"]
#[doc = " @param[in] near Near clip plane (Z=near)"]
#[doc = " @param[in] far Far clip plane (Z=far)"]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @sa Mtx_Persp"]
#[doc = " @sa Mtx_PerspStereo"]
#[doc = " @sa Mtx_PerspStereoTilt"]
pub fn Mtx_PerspTilt( pub fn Mtx_PerspTilt(
mtx: *mut C3D_Mtx, mtx: *mut C3D_Mtx,
fovy: f32, fovy: f32,
@ -349,19 +252,7 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Stereo perspective projection, tilted to account for the 3DS screen rotation"] #[doc = " @brief Stereo perspective projection, tilted to account for the 3DS screen rotation\n @note See the notes for @ref Mtx_PerspStereo\n @param[out] mtx Output matrix\n @param[in] fovy Vertical field of view in radians\n @param[in] aspect Aspect ration of projection plane (width/height)\n @param[in] near Near clip plane (Z=near)\n @param[in] far Far clip plane (Z=far)\n @param[in] iod Interocular distance\n @param[in] screen Focal length\n @param[in] isLeftHanded Whether to build a LH projection\n @sa Mtx_Persp\n @sa Mtx_PerspTilt\n @sa Mtx_PerspStereo"]
#[doc = " @note See the notes for @ref Mtx_PerspStereo"]
#[doc = " @param[out] mtx Output matrix"]
#[doc = " @param[in] fovy Vertical field of view in radians"]
#[doc = " @param[in] aspect Aspect ration of projection plane (width/height)"]
#[doc = " @param[in] near Near clip plane (Z=near)"]
#[doc = " @param[in] far Far clip plane (Z=far)"]
#[doc = " @param[in] iod Interocular distance"]
#[doc = " @param[in] screen Focal length"]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @sa Mtx_Persp"]
#[doc = " @sa Mtx_PerspTilt"]
#[doc = " @sa Mtx_PerspStereo"]
pub fn Mtx_PerspStereoTilt( pub fn Mtx_PerspStereoTilt(
mtx: *mut C3D_Mtx, mtx: *mut C3D_Mtx,
fovy: f32, fovy: f32,
@ -374,13 +265,7 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Look-At matrix, based on DirectX implementation"] #[doc = " @brief Look-At matrix, based on DirectX implementation\n @note See https://msdn.microsoft.com/en-us/library/windows/desktop/bb205342\n @param[out] out Output matrix.\n @param[in] cameraPosition Position of the intended camera in 3D space.\n @param[in] cameraTarget Position of the intended target the camera is supposed to face in 3D space.\n @param[in] cameraUpVector The vector that points straight up depending on the camera's \"Up\" direction.\n @param[in] isLeftHanded Whether to build a LH projection"]
#[doc = " @note See https://msdn.microsoft.com/en-us/library/windows/desktop/bb205342"]
#[doc = " @param[out] out Output matrix."]
#[doc = " @param[in] cameraPosition Position of the intended camera in 3D space."]
#[doc = " @param[in] cameraTarget Position of the intended target the camera is supposed to face in 3D space."]
#[doc = " @param[in] cameraUpVector The vector that points straight up depending on the camera's \"Up\" direction."]
#[doc = " @param[in] isLeftHanded Whether to build a LH projection"]
pub fn Mtx_LookAt( pub fn Mtx_LookAt(
out: *mut C3D_Mtx, out: *mut C3D_Mtx,
cameraPosition: C3D_FVec, cameraPosition: C3D_FVec,
@ -390,84 +275,43 @@ extern "C" {
); );
} }
extern "C" { extern "C" {
#[doc = " @brief Multiply two Quaternions"] #[doc = " @brief Multiply two Quaternions\n @param[in] lhs Multiplicand\n @param[in] rhs Multiplier\n @return lhs*rhs"]
#[doc = " @param[in] lhs Multiplicand"]
#[doc = " @param[in] rhs Multiplier"]
#[doc = " @return lhs*rhs"]
pub fn Quat_Multiply(lhs: C3D_FQuat, rhs: C3D_FQuat) -> C3D_FQuat; pub fn Quat_Multiply(lhs: C3D_FQuat, rhs: C3D_FQuat) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief Raise Quaternion to a power"] #[doc = " @brief Raise Quaternion to a power\n @note If p is 0, this returns the identity Quaternion.\n If p is 1, this returns q.\n @param[in] q Base Quaternion\n @param[in] p Power\n @return q<sup>p</sup>"]
#[doc = " @note If p is 0, this returns the identity Quaternion."]
#[doc = " If p is 1, this returns q."]
#[doc = " @param[in] q Base Quaternion"]
#[doc = " @param[in] p Power"]
#[doc = " @return q<sup>p</sup>"]
pub fn Quat_Pow(q: C3D_FQuat, p: f32) -> C3D_FQuat; pub fn Quat_Pow(q: C3D_FQuat, p: f32) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief Cross product of Quaternion and FVec3"] #[doc = " @brief Cross product of Quaternion and FVec3\n @param[in] q Base Quaternion\n @param[in] v Vector to cross\n @return q×v"]
#[doc = " @param[in] q Base Quaternion"]
#[doc = " @param[in] v Vector to cross"]
#[doc = " @return q×v"]
pub fn Quat_CrossFVec3(q: C3D_FQuat, v: C3D_FVec) -> C3D_FVec; pub fn Quat_CrossFVec3(q: C3D_FQuat, v: C3D_FVec) -> C3D_FVec;
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation"] #[doc = " @brief 3D Rotation\n @param[in] q Quaternion to rotate\n @param[in] axis Axis about which to rotate\n @param[in] r Radians to rotate\n @param[in] bRightSide Whether to transform from the right side\n @return Rotated Quaternion"]
#[doc = " @param[in] q Quaternion to rotate"]
#[doc = " @param[in] axis Axis about which to rotate"]
#[doc = " @param[in] r Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @return Rotated Quaternion"]
pub fn Quat_Rotate(q: C3D_FQuat, axis: C3D_FVec, r: f32, bRightSide: bool) -> C3D_FQuat; pub fn Quat_Rotate(q: C3D_FQuat, axis: C3D_FVec, r: f32, bRightSide: bool) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation about the X axis"] #[doc = " @brief 3D Rotation about the X axis\n @param[in] q Quaternion to rotate\n @param[in] r Radians to rotate\n @param[in] bRightSide Whether to transform from the right side\n @return Rotated Quaternion"]
#[doc = " @param[in] q Quaternion to rotate"]
#[doc = " @param[in] r Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @return Rotated Quaternion"]
pub fn Quat_RotateX(q: C3D_FQuat, r: f32, bRightSide: bool) -> C3D_FQuat; pub fn Quat_RotateX(q: C3D_FQuat, r: f32, bRightSide: bool) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation about the Y axis"] #[doc = " @brief 3D Rotation about the Y axis\n @param[in] q Quaternion to rotate\n @param[in] r Radians to rotate\n @param[in] bRightSide Whether to transform from the right side\n @return Rotated Quaternion"]
#[doc = " @param[in] q Quaternion to rotate"]
#[doc = " @param[in] r Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @return Rotated Quaternion"]
pub fn Quat_RotateY(q: C3D_FQuat, r: f32, bRightSide: bool) -> C3D_FQuat; pub fn Quat_RotateY(q: C3D_FQuat, r: f32, bRightSide: bool) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief 3D Rotation about the Z axis"] #[doc = " @brief 3D Rotation about the Z axis\n @param[in] q Quaternion to rotate\n @param[in] r Radians to rotate\n @param[in] bRightSide Whether to transform from the right side\n @return Rotated Quaternion"]
#[doc = " @param[in] q Quaternion to rotate"]
#[doc = " @param[in] r Radians to rotate"]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @return Rotated Quaternion"]
pub fn Quat_RotateZ(q: C3D_FQuat, r: f32, bRightSide: bool) -> C3D_FQuat; pub fn Quat_RotateZ(q: C3D_FQuat, r: f32, bRightSide: bool) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief Get Quaternion equivalent to 4x4 matrix"] #[doc = " @brief Get Quaternion equivalent to 4x4 matrix\n @note If the matrix is orthogonal or special orthogonal, where determinant(matrix) = +1.0f, then the matrix can be converted.\n @param[in] m Input Matrix\n @return Generated Quaternion"]
#[doc = " @note If the matrix is orthogonal or special orthogonal, where determinant(matrix) = +1.0f, then the matrix can be converted."]
#[doc = " @param[in] m Input Matrix"]
#[doc = " @return Generated Quaternion"]
pub fn Quat_FromMtx(m: *const C3D_Mtx) -> C3D_FQuat; pub fn Quat_FromMtx(m: *const C3D_Mtx) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief Converting Pitch, Yaw, and Roll to Quaternion equivalent"] #[doc = " @brief Converting Pitch, Yaw, and Roll to Quaternion equivalent\n @param[in] pitch The pitch angle in radians.\n @param[in] yaw The yaw angle in radians.\n @param[in] roll The roll angle in radians.\n @param[in] bRightSide Whether to transform from the right side\n @return C3D_FQuat The Quaternion equivalent with the pitch, yaw, and roll (in that order) orientations applied."]
#[doc = " @param[in] pitch The pitch angle in radians."]
#[doc = " @param[in] yaw The yaw angle in radians."]
#[doc = " @param[in] roll The roll angle in radians."]
#[doc = " @param[in] bRightSide Whether to transform from the right side"]
#[doc = " @return C3D_FQuat The Quaternion equivalent with the pitch, yaw, and roll (in that order) orientations applied."]
pub fn Quat_FromPitchYawRoll(pitch: f32, yaw: f32, roll: f32, bRightSide: bool) -> C3D_FQuat; pub fn Quat_FromPitchYawRoll(pitch: f32, yaw: f32, roll: f32, bRightSide: bool) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief Quaternion Look-At"] #[doc = " @brief Quaternion Look-At\n @param[in] source C3D_FVec Starting position. Origin of rotation.\n @param[in] target C3D_FVec Target position to orient towards.\n @param[in] forwardVector C3D_FVec The Up vector.\n @param[in] upVector C3D_FVec The Up vector.\n @return Quaternion rotation."]
#[doc = " @param[in] source C3D_FVec Starting position. Origin of rotation."]
#[doc = " @param[in] target C3D_FVec Target position to orient towards."]
#[doc = " @param[in] forwardVector C3D_FVec The Up vector."]
#[doc = " @param[in] upVector C3D_FVec The Up vector."]
#[doc = " @return Quaternion rotation."]
pub fn Quat_LookAt( pub fn Quat_LookAt(
source: C3D_FVec, source: C3D_FVec,
target: C3D_FVec, target: C3D_FVec,
@ -476,10 +320,7 @@ extern "C" {
) -> C3D_FQuat; ) -> C3D_FQuat;
} }
extern "C" { extern "C" {
#[doc = " @brief Quaternion, created from a given axis and angle in radians."] #[doc = " @brief Quaternion, created from a given axis and angle in radians.\n @param[in] axis C3D_FVec The axis to rotate around at.\n @param[in] angle float The angle to rotate. Unit: Radians\n @return Quaternion rotation based on the axis and angle. Axis doesn't have to be orthogonal."]
#[doc = " @param[in] axis C3D_FVec The axis to rotate around at."]
#[doc = " @param[in] angle float The angle to rotate. Unit: Radians"]
#[doc = " @return Quaternion rotation based on the axis and angle. Axis doesn't have to be orthogonal."]
pub fn Quat_FromAxisAngle(axis: C3D_FVec, angle: f32) -> C3D_FQuat; pub fn Quat_FromAxisAngle(axis: C3D_FVec, angle: f32) -> C3D_FQuat;
} }
#[repr(C)] #[repr(C)]
@ -1823,8 +1664,7 @@ extern "C" {
); );
} }
pub type FILE = __FILE; pub type FILE = __FILE;
#[doc = " @brief Subtexture"] #[doc = " @brief Subtexture\n @note If top > bottom, the subtexture is rotated 1/4 revolution counter-clockwise"]
#[doc = " @note If top > bottom, the subtexture is rotated 1/4 revolution counter-clockwise"]
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Tex3DS_SubTexture { pub struct Tex3DS_SubTexture {
@ -1849,13 +1689,7 @@ pub struct Tex3DS_Texture_s {
#[doc = " @brief Texture"] #[doc = " @brief Texture"]
pub type Tex3DS_Texture = *mut Tex3DS_Texture_s; pub type Tex3DS_Texture = *mut Tex3DS_Texture_s;
extern "C" { extern "C" {
#[doc = " @brief Import Tex3DS texture"] #[doc = " @brief Import Tex3DS texture\n @param[in] input Input data\n @param[in] insize Size of the input data\n @param[out] tex citro3d texture\n @param[out] texcube citro3d texcube\n @param[in] vram Whether to store textures in VRAM\n @returns Tex3DS texture"]
#[doc = " @param[in] input Input data"]
#[doc = " @param[in] insize Size of the input data"]
#[doc = " @param[out] tex citro3d texture"]
#[doc = " @param[out] texcube citro3d texcube"]
#[doc = " @param[in] vram Whether to store textures in VRAM"]
#[doc = " @returns Tex3DS texture"]
pub fn Tex3DS_TextureImport( pub fn Tex3DS_TextureImport(
input: *const ::libc::c_void, input: *const ::libc::c_void,
insize: usize, insize: usize,
@ -1865,18 +1699,7 @@ extern "C" {
) -> Tex3DS_Texture; ) -> Tex3DS_Texture;
} }
extern "C" { extern "C" {
#[doc = " @brief Import Tex3DS texture"] #[doc = " @brief Import Tex3DS texture\n\n @description\n For example, use this if you want to import from a large file without\n pulling the entire file into memory.\n\n @param[out] tex citro3d texture\n @param[out] texcube citro3d texcube\n @param[in] vram Whether to store textures in VRAM\n @param[in] callback Data callback\n @param[in] userdata User data passed to callback\n @returns Tex3DS texture"]
#[doc = ""]
#[doc = " @description"]
#[doc = " For example, use this if you want to import from a large file without"]
#[doc = " pulling the entire file into memory."]
#[doc = ""]
#[doc = " @param[out] tex citro3d texture"]
#[doc = " @param[out] texcube citro3d texcube"]
#[doc = " @param[in] vram Whether to store textures in VRAM"]
#[doc = " @param[in] callback Data callback"]
#[doc = " @param[in] userdata User data passed to callback"]
#[doc = " @returns Tex3DS texture"]
pub fn Tex3DS_TextureImportCallback( pub fn Tex3DS_TextureImportCallback(
tex: *mut C3D_Tex, tex: *mut C3D_Tex,
texcube: *mut C3D_TexCube, texcube: *mut C3D_TexCube,
@ -1886,17 +1709,7 @@ extern "C" {
) -> Tex3DS_Texture; ) -> Tex3DS_Texture;
} }
extern "C" { extern "C" {
#[doc = " @brief Import Tex3DS texture"] #[doc = " @brief Import Tex3DS texture\n\n Starts reading at the current file descriptor's offset. The file\n descriptor's position is left at the end of the decoded data. On error, the\n file descriptor's position is indeterminate.\n\n @param[in] fd Open file descriptor\n @param[out] tex citro3d texture\n @param[out] texcube citro3d texcube\n @param[in] vram Whether to store textures in VRAM\n @returns Tex3DS texture"]
#[doc = ""]
#[doc = " Starts reading at the current file descriptor's offset. The file"]
#[doc = " descriptor's position is left at the end of the decoded data. On error, the"]
#[doc = " file descriptor's position is indeterminate."]
#[doc = ""]
#[doc = " @param[in] fd Open file descriptor"]
#[doc = " @param[out] tex citro3d texture"]
#[doc = " @param[out] texcube citro3d texcube"]
#[doc = " @param[in] vram Whether to store textures in VRAM"]
#[doc = " @returns Tex3DS texture"]
pub fn Tex3DS_TextureImportFD( pub fn Tex3DS_TextureImportFD(
fd: ::libc::c_int, fd: ::libc::c_int,
tex: *mut C3D_Tex, tex: *mut C3D_Tex,
@ -1905,17 +1718,7 @@ extern "C" {
) -> Tex3DS_Texture; ) -> Tex3DS_Texture;
} }
extern "C" { extern "C" {
#[doc = " @brief Import Tex3DS texture"] #[doc = " @brief Import Tex3DS texture\n\n Starts reading at the current file stream's offset. The file stream's\n position is left at the end of the decoded data. On error, the file\n stream's position is indeterminate.\n\n @param[in] fp Open file stream\n @param[out] tex citro3d texture\n @param[out] texcube citro3d texcube\n @param[in] vram Whether to store textures in VRAM\n @returns Tex3DS texture"]
#[doc = ""]
#[doc = " Starts reading at the current file stream's offset. The file stream's"]
#[doc = " position is left at the end of the decoded data. On error, the file"]
#[doc = " stream's position is indeterminate."]
#[doc = ""]
#[doc = " @param[in] fp Open file stream"]
#[doc = " @param[out] tex citro3d texture"]
#[doc = " @param[out] texcube citro3d texcube"]
#[doc = " @param[in] vram Whether to store textures in VRAM"]
#[doc = " @returns Tex3DS texture"]
pub fn Tex3DS_TextureImportStdio( pub fn Tex3DS_TextureImportStdio(
fp: *mut FILE, fp: *mut FILE,
tex: *mut C3D_Tex, tex: *mut C3D_Tex,
@ -1924,20 +1727,14 @@ extern "C" {
) -> Tex3DS_Texture; ) -> Tex3DS_Texture;
} }
extern "C" { extern "C" {
#[doc = " @brief Get number of subtextures"] #[doc = " @brief Get number of subtextures\n @param[in] texture Tex3DS texture\n @returns Number of subtextures"]
#[doc = " @param[in] texture Tex3DS texture"]
#[doc = " @returns Number of subtextures"]
pub fn Tex3DS_GetNumSubTextures(texture: Tex3DS_Texture) -> usize; pub fn Tex3DS_GetNumSubTextures(texture: Tex3DS_Texture) -> usize;
} }
extern "C" { extern "C" {
#[doc = " @brief Get subtexture"] #[doc = " @brief Get subtexture\n @param[in] texture Tex3DS texture\n @param[in] index Subtexture index\n @returns Subtexture info"]
#[doc = " @param[in] texture Tex3DS texture"]
#[doc = " @param[in] index Subtexture index"]
#[doc = " @returns Subtexture info"]
pub fn Tex3DS_GetSubTexture(texture: Tex3DS_Texture, index: usize) -> *const Tex3DS_SubTexture; pub fn Tex3DS_GetSubTexture(texture: Tex3DS_Texture, index: usize) -> *const Tex3DS_SubTexture;
} }
extern "C" { extern "C" {
#[doc = " @brief Free Tex3DS texture"] #[doc = " @brief Free Tex3DS texture\n @param[in] texture Tex3DS texture to free"]
#[doc = " @param[in] texture Tex3DS texture to free"]
pub fn Tex3DS_TextureFree(texture: Tex3DS_Texture); pub fn Tex3DS_TextureFree(texture: Tex3DS_Texture);
} }

53
citro3d/examples/triangle.rs

@ -1,5 +1,7 @@
#![feature(allocator_api)] #![feature(allocator_api)]
use citro3d::attrib::{self, AttrInfo};
use citro3d::buffers::BufInfo;
use citro3d::render::{ClearFlags, Target}; use citro3d::render::{ClearFlags, Target};
use citro3d::{include_aligned_bytes, shader}; use citro3d::{include_aligned_bytes, shader};
use citro3d_sys::C3D_Mtx; use citro3d_sys::C3D_Mtx;
@ -51,8 +53,6 @@ static SHADER_BYTES: &[u8] =
include_aligned_bytes!(concat!(env!("OUT_DIR"), "/examples/assets/vshader.shbin")); include_aligned_bytes!(concat!(env!("OUT_DIR"), "/examples/assets/vshader.shbin"));
fn main() { fn main() {
ctru::init();
let mut soc = Soc::init().expect("failed to get SOC"); let mut soc = Soc::init().expect("failed to get SOC");
drop(soc.redirect_to_3dslink(true, true)); drop(soc.redirect_to_3dslink(true, true));
@ -121,10 +121,38 @@ fn scene_init(program: &mut shader::Program, vbo_data: &[Vertex]) -> (i8, C3D_Mt
); );
// Configure attributes for use with the vertex shader // Configure attributes for use with the vertex shader
let attr_info = citro3d_sys::C3D_GetAttrInfo(); let mut attr_info = AttrInfo::get_mut().expect("failed to get global attr info");
citro3d_sys::AttrInfo_Init(attr_info);
citro3d_sys::AttrInfo_AddLoader(attr_info, 0, ctru_sys::GPU_FLOAT, 3); // v0=position let reg0 = attrib::Register::new(0).unwrap();
citro3d_sys::AttrInfo_AddLoader(attr_info, 1, ctru_sys::GPU_FLOAT, 3); // v1=color let reg1 = attrib::Register::new(1).unwrap();
// The default permutation would actually already be what we want if we
// inserted position, then color, but just show that it's customizable
// by swapping the order then using `set_permutation`.
let color_attr = attr_info
.add_loader(reg0, attrib::Format::Float, 3)
.unwrap();
let position_attr = attr_info
.add_loader(reg1, attrib::Format::Float, 3)
.unwrap();
eprintln!(
"count {} permutation {:#x}",
attr_info.count(),
attr_info.permutation()
);
attr_info
.set_permutation(&[position_attr, color_attr])
.unwrap();
eprintln!(
"count {} permutation {:#x}",
attr_info.count(),
attr_info.permutation()
);
// Compute the projection matrix // Compute the projection matrix
let projection = { let projection = {
@ -144,17 +172,8 @@ fn scene_init(program: &mut shader::Program, vbo_data: &[Vertex]) -> (i8, C3D_Mt
}; };
// Configure buffers // Configure buffers
let buf_info = citro3d_sys::C3D_GetBufInfo(); let mut buf_info = BufInfo::get_mut().unwrap();
citro3d_sys::BufInfo_Init(buf_info); buf_info.add(vbo_data, &attr_info).unwrap();
citro3d_sys::BufInfo_Add(
buf_info,
vbo_data.as_ptr().cast(),
std::mem::size_of::<Vertex>()
.try_into()
.expect("size of vec3 fits in u32"),
2, // Each vertex has two attributes
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
// 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

117
citro3d/src/attrib.rs

@ -0,0 +1,117 @@
use std::ops::{Deref, DerefMut};
use std::sync::{LazyLock, RwLock};
static ATTR_INFO: LazyLock<RwLock<AttrInfo>> = LazyLock::new(|| {
let raw = unsafe {
// TODO: should we check is_null() here?
let info = citro3d_sys::C3D_GetAttrInfo();
citro3d_sys::AttrInfo_Init(info);
info
};
RwLock::new(AttrInfo { raw })
});
pub struct AttrInfo {
raw: *mut citro3d_sys::C3D_AttrInfo,
}
pub struct Register(libc::c_int);
impl Register {
pub fn new(n: u16) -> crate::Result<Self> {
// TODO proper validation for attributes? Or maybe just a next() function
// that gets atomically increasing indices or something? Or look at
// <https://3dbrew.org/wiki/GPU/Internal_Registers> and define some consts
// or lookup functions
Ok(Self(n as _))
}
}
#[must_use]
pub struct Index(libc::c_int);
#[repr(u32)]
pub enum Format {
Byte = ctru_sys::GPU_BYTE,
UnsignedByte = ctru_sys::GPU_UNSIGNED_BYTE,
Float = ctru_sys::GPU_FLOAT,
Short = ctru_sys::GPU_SHORT,
}
// SAFETY: the RWLock ensures unique access when mutating the global struct, and
// we trust citro3d to Do The Right Thing™ and not mutate it otherwise.
unsafe impl Sync for AttrInfo {}
unsafe impl Send for AttrInfo {}
impl AttrInfo {
/// Get a reference to the global attribute info.
pub fn get() -> crate::Result<impl Deref<Target = Self>> {
Ok(ATTR_INFO.try_read()?)
}
/// Get a mutable reference to the global attribute info.
pub fn get_mut() -> crate::Result<impl DerefMut<Target = Self>> {
Ok(ATTR_INFO.try_write()?)
}
/// Add an attribute loader to the attribute info. By default, the resulting
/// attribute index will be appended to the permutation
pub fn add_loader(
&mut self,
register: Register,
format: Format,
count: usize,
) -> crate::Result<Index> {
let count = count.try_into()?;
let idx =
unsafe { citro3d_sys::AttrInfo_AddLoader(self.raw, register.0, format as u32, count) };
Ok(Index(idx))
}
pub fn set_permutation(&mut self, indices: &[Index]) -> crate::Result<()> {
if indices.len() > 16 {
return Err(crate::Error::TooManyAttributes);
}
let mut bytes: Vec<u8> = indices
.windows(2)
.map(|window| {
let [lo, hi] = match *window {
[Index(lo), Index(hi)] => [lo, hi],
[Index(lo)] => [lo, 0], // high nibble is just padding
_ => unreachable!(), // window size of 2 == always 1 or 2 elements
};
// each value is a nibble, combine them into a byte
lo as u8 | (hi as u8) << 4
})
.collect();
// pad the remainder with zeros
bytes.extend(std::iter::repeat(0).take(8 - bytes.len()));
let permutation = bytemuck::cast(<[u8; 8]>::try_from(bytes).unwrap());
unsafe {
(*self.raw).permutation = permutation;
(*self.raw).attrCount = indices.len() as _;
}
Ok(())
}
/// Get the current permutation of input register to vertex attributes mapping.
/// See [GPU/Internal Registers] for an explanation of how the bits are laid out
/// in the resulting value.
///
/// [GPU/Internal Registers]: https://3dbrew.org/wiki/GPU/Internal_Registers#GPUREG_SH_ATTRIBUTES_PERMUTATION_LOW
pub fn permutation(&self) -> u64 {
unsafe { (*self.raw).permutation }
}
/// Get the number of attributes in the current permutation.
pub fn count(&self) -> libc::c_int {
unsafe { (*self.raw).attrCount }
}
}

55
citro3d/src/buffers.rs

@ -0,0 +1,55 @@
use std::ops::{Deref, DerefMut};
use std::sync::{LazyLock, RwLock};
use crate::attrib;
static BUF_INFO: LazyLock<RwLock<BufInfo>> = LazyLock::new(|| {
let raw = unsafe {
let info = citro3d_sys::C3D_GetBufInfo();
citro3d_sys::BufInfo_Init(info);
info
};
RwLock::new(BufInfo { raw })
});
pub struct BufInfo {
raw: *mut citro3d_sys::C3D_BufInfo,
}
// SAFETY: the RWLock ensures unique access when mutating the global struct, and
// we trust citro3d to Do The Right Thing™ and not mutate it otherwise.
unsafe impl Sync for BufInfo {}
unsafe impl Send for BufInfo {}
impl BufInfo {
/// Get a reference to the global buffer info.
pub fn get() -> crate::Result<impl Deref<Target = Self>> {
Ok(BUF_INFO.try_read()?)
}
/// Get a mutable reference to the global buffer info.
pub fn get_mut() -> crate::Result<impl DerefMut<Target = Self>> {
Ok(BUF_INFO.try_write()?)
}
pub fn add<T>(&mut self, vbo_data: &[T], attrib_info: &attrib::AttrInfo) -> crate::Result<()> {
let stride = std::mem::size_of::<T>().try_into()?;
let attrib_count = attrib_info.count();
let permutation = attrib_info.permutation();
unsafe {
citro3d_sys::BufInfo_Add(
self.raw,
// TODO: figure out how the hell to encode the lifetime of this
// data so that we don't try to use it after it's destroyed...
vbo_data.as_ptr().cast(),
stride,
attrib_count,
permutation,
);
}
Ok(())
}
}

17
citro3d/src/error.rs

@ -1,20 +1,31 @@
//! General-purpose error and result types returned by public APIs of this crate. //! General-purpose error and result types returned by public APIs of this crate.
use std::num::TryFromIntError; use std::num::TryFromIntError;
use std::sync::TryLockError;
/// The common result type returned by `citro3d` functions. /// The common result type returned by `citro3d` functions.
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
// TODO probably want a similar type to ctru::Result to make it easier to convert
// nonzero result codes to errors.
/// The common error type that may be returned by `citro3d` functions. /// The common error type that may be returned by `citro3d` functions.
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// C3D error code.
System(libc::c_int),
/// A C3D object or context could not be initialized. /// A C3D object or context could not be initialized.
FailedToInitialize, FailedToInitialize,
/// A size parameter was specified that cannot be converted to the proper type. /// A size parameter was specified that cannot be converted to the proper type.
InvalidSize, InvalidSize,
/// Failed to select the given render target for drawing to. /// Failed to select the given render target for drawing to.
InvalidRenderTarget, InvalidRenderTarget,
/// Indicates that a reference could not be obtained because a lock is already
/// held on the requested object.
LockHeld,
/// Indicates that too many vertex attributes were specified (max 16 supported).
TooManyAttributes,
} }
impl From<TryFromIntError> for Error { impl From<TryFromIntError> for Error {
@ -22,3 +33,9 @@ impl From<TryFromIntError> for Error {
Self::InvalidSize Self::InvalidSize
} }
} }
impl<T> From<TryLockError<T>> for Error {
fn from(_: TryLockError<T>) -> Self {
Self::LockHeld
}
}

5
citro3d/src/lib.rs

@ -1,10 +1,13 @@
#![feature(once_cell)]
//! Safe Rust bindings to `citro3d`. //! Safe Rust bindings to `citro3d`.
pub mod attrib;
pub mod buffers;
pub mod error; pub mod error;
pub mod render; pub mod render;
pub mod shader; pub mod shader;
pub mod texture; pub mod texture;
pub mod vbo;
use citro3d_sys::C3D_FrameDrawOn; use citro3d_sys::C3D_FrameDrawOn;
pub use error::{Error, Result}; pub use error::{Error, Result};

1
citro3d/src/vbo.rs

@ -1 +0,0 @@
Loading…
Cancel
Save