citro3d/attrib.rs
1//! Configure vertex attributes.
2//!
3//! This module has types and helpers for describing the shape/structure of vertex
4//! data to be sent to the GPU.
5//!
6//! See the [`buffer`](crate::buffer) module to use the vertex data itself.
7
8use std::mem::MaybeUninit;
9
10/// Vertex attribute info. This struct describes how vertex buffers are
11/// layed out and used (i.e. the shape of the vertex data).
12#[derive(Debug)]
13#[doc(alias = "C3D_AttrInfo")]
14pub struct Info(pub(crate) citro3d_sys::C3D_AttrInfo);
15
16/// A shader input register, usually corresponding to a single vertex attribute
17/// (e.g. position or color). These are called `v0`, `v1`, ... `v15` in the
18/// [picasso](https://github.com/devkitPro/picasso/blob/master/Manual.md)
19/// shader language.
20#[derive(Debug, Clone, Copy)]
21pub struct Register(libc::c_int);
22
23impl Register {
24 /// Get a register corresponding to the given index.
25 ///
26 /// # Errors
27 ///
28 /// Returns an error for `n >= 16`.
29 pub fn new(n: u16) -> crate::Result<Self> {
30 if n < 16 {
31 Ok(Self(n.into()))
32 } else {
33 Err(crate::Error::TooManyAttributes)
34 }
35 }
36}
37
38/// An attribute index. This is the attribute's actual index in the input buffer,
39/// and may correspond to any [`Register`] (or multiple) as input in the shader
40/// program.
41#[allow(dead_code)]
42#[derive(Debug, Clone, Copy)]
43pub struct Index(u8);
44
45/// The data format of an attribute.
46#[repr(u8)]
47#[derive(Debug, Clone, Copy)]
48#[doc(alias = "GPU_FORMATS")]
49pub enum Format {
50 /// A signed byte, i.e. [`i8`].
51 Byte = ctru_sys::GPU_BYTE,
52 /// An unsigned byte, i.e. [`u8`].
53 UnsignedByte = ctru_sys::GPU_UNSIGNED_BYTE,
54 /// A float, i.e. [`f32`].
55 Float = ctru_sys::GPU_FLOAT,
56 /// A short integer, i.e. [`i16`].
57 Short = ctru_sys::GPU_SHORT,
58}
59
60impl From<Format> for u8 {
61 fn from(value: Format) -> Self {
62 value as u8
63 }
64}
65
66// SAFETY: the RWLock ensures unique access when mutating the global struct, and
67// we trust citro3d to Do The Right Thing™ and not mutate it otherwise.
68unsafe impl Sync for Info {}
69unsafe impl Send for Info {}
70
71impl Default for Info {
72 #[doc(alias = "AttrInfo_Init")]
73 fn default() -> Self {
74 let mut raw = MaybeUninit::zeroed();
75 let raw = unsafe {
76 citro3d_sys::AttrInfo_Init(raw.as_mut_ptr());
77 raw.assume_init()
78 };
79 Self(raw)
80 }
81}
82
83impl Info {
84 /// Construct a new attribute info structure with no attributes.
85 pub fn new() -> Self {
86 Self::default()
87 }
88
89 pub(crate) fn copy_from(raw: *const citro3d_sys::C3D_AttrInfo) -> Option<Self> {
90 if raw.is_null() {
91 None
92 } else {
93 // This is less efficient than returning a pointer or something, but it's
94 // safer since we don't know the lifetime of the pointee
95 Some(Self(unsafe { *raw }))
96 }
97 }
98
99 /// Add an attribute loader to the attribute info. The resulting attribute index
100 /// indicates the registration order of the attributes.
101 ///
102 /// # Parameters
103 ///
104 /// * `register`: the shader program input register for this attribute.
105 /// * `format`: the data format of this attribute.
106 /// * `count`: the number of elements in each attribute (up to 4, corresponding
107 /// to `xyzw` / `rgba` / `stpq`).
108 ///
109 /// # Errors
110 ///
111 /// * If `count > 4`
112 /// * If this attribute info already has the maximum number of attributes.
113 #[doc(alias = "AttrInfo_AddLoader")]
114 pub fn add_loader(
115 &mut self,
116 register: Register,
117 format: Format,
118 count: u8,
119 ) -> crate::Result<Index> {
120 if count > 4 {
121 return Err(crate::Error::InvalidSize);
122 }
123
124 // SAFETY: the &mut self.0 reference is only used to access fields in
125 // the attribute info, not stored somewhere for later use
126 let ret = unsafe {
127 citro3d_sys::AttrInfo_AddLoader(&mut self.0, register.0, format.into(), count.into())
128 };
129
130 let Ok(idx) = ret.try_into() else {
131 return Err(crate::Error::TooManyAttributes);
132 };
133
134 Ok(Index(idx))
135 }
136
137 pub(crate) fn permutation(&self) -> u64 {
138 self.0.permutation
139 }
140
141 /// Get the number of registered attributes.
142 pub fn attr_count(&self) -> libc::c_int {
143 self.0.attrCount
144 }
145}