gltf/accessor/mod.rs
1//! # Basic usage
2//!
3//! Visiting the accessors of a glTF asset.
4//!
5//! ```
6//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
7//! # let gltf = gltf::Gltf::open("examples/Box.gltf")?;
8//! for accessor in gltf.accessors() {
9//! println!("Accessor #{}", accessor.index());
10//! println!("offset: {:?}", accessor.offset());
11//! println!("count: {}", accessor.count());
12//! println!("data_type: {:?}", accessor.data_type());
13//! println!("dimensions: {:?}", accessor.dimensions());
14//! }
15//! # Ok(())
16//! # }
17//! # fn main() {
18//! # let _ = run().expect("runtime error");
19//! # }
20//! ```
21//!
22//! # Utility functions
23//!
24//! Reading the values from the `vec3` accessors of a glTF asset.
25//!
26//! ## Note
27//!
28//! The [`Iter`] utility is a low-level iterator intended for use in special
29//! cases. The average user is expected to use reader abstractions such as
30//! [`mesh::Reader`].
31//!
32//! [`Iter`]: struct.Iter.html
33//! [`mesh::Reader`]: ../mesh/struct.Reader.html
34//!
35//! ```
36//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
37//! # use gltf::accessor::{DataType, Dimensions, Iter};
38//! let (gltf, buffers, _) = gltf::import("examples/Box.gltf")?;
39//! let get_buffer_data = |buffer: gltf::Buffer| buffers.get(buffer.index()).map(|x| &*x.0);
40//! for accessor in gltf.accessors() {
41//! match (accessor.data_type(), accessor.dimensions()) {
42//! (DataType::F32, Dimensions::Vec3) => {
43//! if let Some(iter) = Iter::<[f32; 3]>::new(accessor, get_buffer_data) {
44//! for item in iter {
45//! println!("{:?}", item);
46//! }
47//! }
48//! }
49//! _ => {},
50//! }
51//! }
52//! # Ok(())
53//! # }
54//! # fn main() {
55//! # let _ = run().expect("runtime error");
56//! # }
57//! ```
58
59use crate::{buffer, Document};
60
61pub use json::accessor::ComponentType as DataType;
62pub use json::accessor::Type as Dimensions;
63#[cfg(feature = "extensions")]
64use serde_json::{Map, Value};
65
66/// Utility functions.
67#[cfg(feature = "utils")]
68#[cfg_attr(docsrs, doc(cfg(feature = "utils")))]
69pub mod util;
70
71/// Contains data structures for sparse storage.
72pub mod sparse;
73
74#[cfg(feature = "utils")]
75#[doc(inline)]
76pub use self::util::{Item, Iter};
77
78/// A typed view into a buffer view.
79#[derive(Clone, Debug)]
80pub struct Accessor<'a> {
81 /// The parent `Document` struct.
82 document: &'a Document,
83
84 /// The corresponding JSON index.
85 index: usize,
86
87 /// The corresponding JSON struct.
88 json: &'a json::accessor::Accessor,
89}
90
91impl<'a> Accessor<'a> {
92 /// Constructs an `Accessor`.
93 pub(crate) fn new(
94 document: &'a Document,
95 index: usize,
96 json: &'a json::accessor::Accessor,
97 ) -> Self {
98 Self {
99 document,
100 index,
101 json,
102 }
103 }
104
105 /// Returns the internal JSON index.
106 pub fn index(&self) -> usize {
107 self.index
108 }
109
110 /// Returns the size of each component that this accessor describes.
111 pub fn size(&self) -> usize {
112 self.data_type().size() * self.dimensions().multiplicity()
113 }
114
115 /// Returns the buffer view this accessor reads from.
116 ///
117 /// This may be `None` if the corresponding accessor is sparse.
118 pub fn view(&self) -> Option<buffer::View<'a>> {
119 self.json
120 .buffer_view
121 .map(|view| self.document.views().nth(view.value()).unwrap())
122 }
123
124 /// Returns the offset relative to the start of the parent buffer view in bytes.
125 ///
126 /// This will be 0 if the corresponding accessor is sparse.
127 pub fn offset(&self) -> usize {
128 // TODO: Change this function to return Option<usize> in the next
129 // version and return None for sparse accessors.
130 self.json.byte_offset.unwrap_or_default().0 as usize
131 }
132
133 /// Returns the number of components within the buffer view - not to be confused
134 /// with the number of bytes in the buffer view.
135 pub fn count(&self) -> usize {
136 self.json.count.0 as usize
137 }
138
139 /// Returns the data type of components in the attribute.
140 pub fn data_type(&self) -> DataType {
141 self.json.component_type.unwrap().0
142 }
143
144 /// Returns extension data unknown to this crate version.
145 #[cfg(feature = "extensions")]
146 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
147 pub fn extensions(&self) -> Option<&Map<String, Value>> {
148 let ext = self.json.extensions.as_ref()?;
149 Some(&ext.others)
150 }
151
152 /// Queries extension data unknown to this crate version.
153 #[cfg(feature = "extensions")]
154 #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
155 pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
156 let ext = self.json.extensions.as_ref()?;
157 ext.others.get(ext_name)
158 }
159
160 /// Optional application specific data.
161 pub fn extras(&self) -> &'a json::Extras {
162 &self.json.extras
163 }
164
165 /// Specifies if the attribute is a scalar, vector, or matrix.
166 pub fn dimensions(&self) -> Dimensions {
167 self.json.type_.unwrap()
168 }
169
170 /// Returns the minimum value of each component in this attribute.
171 pub fn min(&self) -> Option<json::Value> {
172 self.json.min.clone()
173 }
174
175 /// Returns the maximum value of each component in this attribute.
176 pub fn max(&self) -> Option<json::Value> {
177 self.json.max.clone()
178 }
179
180 /// Optional user-defined name for this object.
181 #[cfg(feature = "names")]
182 #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
183 pub fn name(&self) -> Option<&'a str> {
184 self.json.name.as_deref()
185 }
186
187 /// Specifies whether integer data values should be normalized.
188 pub fn normalized(&self) -> bool {
189 self.json.normalized
190 }
191
192 /// Returns sparse storage of attributes that deviate from their initialization
193 /// value.
194 pub fn sparse(&self) -> Option<sparse::Sparse<'a>> {
195 self.json
196 .sparse
197 .as_ref()
198 .map(|json| sparse::Sparse::new(self.document, json))
199 }
200}