nsi_core/output/pixel_format.rs
1use core::ops::Deref;
2use std::ffi::CStr;
3
4/// Description of an [`OutputLayer`](crate::OUTPUT_LAYER) node
5/// inside a flat, raw pixel.
6#[derive(Debug, Clone, Default)]
7pub struct Layer {
8 name: String,
9 depth: LayerDepth,
10 offset: usize,
11}
12
13impl Layer {
14 /// The name of the layer.
15 #[inline]
16 pub fn name(&self) -> &str {
17 self.name.as_str()
18 }
19
20 /// The [depth](LayerDepth) of this layer.
21 #[inline]
22 pub fn depth(&self) -> LayerDepth {
23 self.depth
24 }
25
26 /// The channel offset of the layer inside the [`PixelFormat`].
27 #[inline]
28 pub fn offset(&self) -> usize {
29 self.offset
30 }
31
32 /// The number of channels in this layer. This is a shortcut for calling
33 /// `depth().channels()`.
34 #[inline]
35 pub fn channels(&self) -> usize {
36 self.depth.channels()
37 }
38
39 /// Returns true if the [depth](LayerDepth) of this layer contains an alpha
40 /// channel. This is a shortcut for calling `depth().has_alpha()`.
41 #[inline]
42 pub fn has_alpha(&self) -> bool {
43 self.depth.has_alpha()
44 }
45}
46
47/// The depth (number and type of channels) a pixel in a [`Layer`] is
48/// composed of.
49#[derive(Debug, Default, Clone, Copy, PartialEq)]
50pub enum LayerDepth {
51 /// A single channel. Obtained when setting `"layertype"` `"scalar"` on an
52 /// [`OutputLayer`](crate::OUTPUT_LAYER).
53 #[default]
54 OneChannel,
55 /// A single channel with alpha. Obtained when setting `"layertype"`
56 /// `"scalar"` and `"withalpha"` `1` on an
57 /// [`OutputLayer`](crate::OUTPUT_LAYER).
58 OneChannelAndAlpha,
59 /// An `rgb` color triplet. Obtained when setting `"layertype"` `"color"`
60 /// on an [`OutputLayer`](crate::OUTPUT_LAYER).
61 Color,
62 /// An `rgb` color triplet with alpha. Obtained when setting `"layertype"`
63 /// `"color"` and `"withalpha"` `1` on an
64 /// [`OutputLayer`](crate::OUTPUT_LAYER).
65 ColorAndAlpha,
66 /// An `xyz` triplet. Obtained when setting `"layertype"` `"vector"` on an
67 /// [`OutputLayer`](crate::OUTPUT_LAYER).
68 Vector,
69 /// An `xyz` triplet with alpha. Obtained when setting `"layertype"`
70 /// `"vector"` and `"withalpha"` `1` on an
71 /// [`OutputLayer`](crate::OUTPUT_LAYER).
72 VectorAndAlpha,
73 /// An quadruple of values. Obtained when setting `"layertype"` `"quad"` on
74 /// an [`OutputLayer`](crate::OUTPUT_LAYER).
75 FourChannels,
76 /// An quadruple of values with alpha. Obtained when setting `"layertype"`
77 /// `"quad"` and `"withalpha"` `1` on an
78 /// [`OutputLayer`](crate::OUTPUT_LAYER).
79 FourChannelsAndAlpha,
80}
81
82impl LayerDepth {
83 /// Returns the number of channels this layer type consists of.
84 pub fn channels(&self) -> usize {
85 match self {
86 LayerDepth::OneChannel => 1,
87 LayerDepth::OneChannelAndAlpha => 2,
88 LayerDepth::Color => 3,
89 LayerDepth::Vector => 3,
90 LayerDepth::ColorAndAlpha => 4,
91 LayerDepth::VectorAndAlpha => 4,
92 LayerDepth::FourChannels => 4,
93 LayerDepth::FourChannelsAndAlpha => 5,
94 }
95 }
96
97 /// Returns `true`` if this layer contains an alpha channel.
98 pub fn has_alpha(&self) -> bool {
99 [
100 LayerDepth::OneChannelAndAlpha,
101 LayerDepth::ColorAndAlpha,
102 LayerDepth::VectorAndAlpha,
103 LayerDepth::FourChannelsAndAlpha,
104 ]
105 .contains(self)
106 }
107}
108
109/// Accessor for the pixel format the renderer sends in
110/// [`FnOpen`](crate::output::FnOpen), [`FnWrite`](crate::output::FnWrite) and
111/// [`FnFinish`](crate::output::FnFinish)
112///
113/// This is a stack of [`Layer`]s. Where each layer describes an
114/// [`OutputLayer`](crate::OUTPUT_LAYER).
115///
116/// # Example
117///
118/// A typical format for a pixel containing two such layers, an *RGBA* **color**
119/// & **alpha** output layer and a world space **normal**, will look like this:
120///
121/// | [`name`](Layer::name()) | [`depth`](Layer::depth()) | [`offset`](Layer::offset())
122/// |-------------------------|-----------------------------------------------------|----------------------------
123/// | `Ci` |[`ColorAndAlpha`](LayerDepth::ColorAndAlpha)(`rgba`) | `0`
124/// | `N_world` | [`Vector`](LayerDepth::Vector)(`xyz`) | `4`
125///
126/// ## RAW Layout
127///
128/// The resp. callbacks deliver pixels as a flat [`f32`] buffer.
129/// For the above example the actual layout of a single pixel in the
130/// buffer is:
131///
132/// | Value | `r`ed | `g`reen | `b`lue | `a`lpha | `x` | `y` | `z`
133/// |--------|---------|---------|---------|---------|-----|-----|----
134/// | Offset | `0` | `1` | `2` | `3` | `4` | `5` | `6`
135///
136/// The `offset` is the offset into the pixel buffer to obtain the 1st element.
137/// For example, the **y** coordinate of the the normal will be stored in
138/// channel at offset `5` (`4` + `1`).
139///
140/// The pixel format is in the order in which
141/// [`OutputLayer`](crate::OUTPUT_LAYER)s were defined in the
142/// [ɴsɪ scene](https://nsi.readthedocs.io/en/latest/guidelines.html#basic-scene-anatomy).
143///
144/// # Accessing Layers
145///
146/// To access the [`Layer`]s inside a `PixelFormat` use the [`Deref`] operator
147/// to obtain the underlying [`Vec`]<`Layer`>.
148///
149/// # Examples
150///
151/// Dump all layers to `stdout` after a frame has finished rendering:
152///
153/// ```
154/// # #[cfg(feature = "output")]
155/// # {
156/// # use nsi_core as nsi;
157/// let finish = nsi::output::FinishCallback::new(
158/// |_: String,
159/// _: usize,
160/// _: usize,
161/// pixel_format: nsi::output::PixelFormat,
162/// _: Vec<f32>| {
163/// // Dump all layer descriptions to stdout.
164/// for layer in &*pixel_format {
165/// println!("{:?}", layer);
166/// }
167///
168/// nsi::output::Error::None
169/// },
170/// );
171/// # }
172/// ```
173#[derive(Debug, Default)]
174pub struct PixelFormat(Vec<Layer>);
175
176impl PixelFormat {
177 #[inline]
178 pub(crate) fn new(format: &[ndspy_sys::PtDspyDevFormat]) -> Self {
179 let (mut previous_layer_name, mut previous_channel_id) =
180 Self::split_into_layer_name_and_channel_id(
181 unsafe { CStr::from_ptr(format[0].name) }.to_str().unwrap(),
182 );
183
184 let mut depth = LayerDepth::OneChannel;
185 let mut offset = 0;
186
187 PixelFormat(
188 // This loops through each format (channel), r, g, b, a etc.
189 format
190 .iter()
191 .enumerate()
192 .cycle()
193 .take(format.len() + 1)
194 .filter_map(|format| {
195 // FIXME: add support for specifying AOV and detect type
196 // for indexing (.r vs .x)
197 let name = unsafe { CStr::from_ptr(format.1.name) }
198 .to_str()
199 .unwrap();
200
201 let (layer_name, channel_id) =
202 Self::split_into_layer_name_and_channel_id(name);
203
204 // A boundary between two layers will be when the postfix
205 // is a combination of those above.
206 if ["b", "z", "s", "a"].contains(&previous_channel_id)
207 && ["r", "x", "s"].contains(&channel_id)
208 {
209 let tmp_layer_name = if previous_layer_name.is_empty() {
210 "Ci"
211 } else {
212 previous_layer_name
213 };
214 previous_layer_name = layer_name;
215
216 previous_channel_id = channel_id;
217
218 let tmp_depth = depth;
219 depth = LayerDepth::OneChannel;
220
221 let tmp_offset = offset;
222 offset = format.0;
223
224 Some(Layer {
225 name: tmp_layer_name.to_string(),
226 depth: tmp_depth,
227 offset: tmp_offset,
228 })
229 } else {
230 // Do we we have a lonely alpha -> it belongs to the
231 // current layer.
232 if layer_name.is_empty() && "a" == channel_id {
233 depth = match &depth {
234 LayerDepth::OneChannel => {
235 LayerDepth::OneChannelAndAlpha
236 }
237 LayerDepth::Color => LayerDepth::ColorAndAlpha,
238 LayerDepth::Vector => {
239 LayerDepth::VectorAndAlpha
240 }
241 LayerDepth::FourChannels => {
242 LayerDepth::FourChannelsAndAlpha
243 }
244 _ => unreachable!(),
245 };
246 }
247 // Are we still on the same layer?
248 else if layer_name == previous_layer_name {
249 // We only check for first channel.
250 match channel_id {
251 "r" | "g" | "b" => depth = LayerDepth::Color,
252 "x" | "y" | "z" => depth = LayerDepth::Vector,
253 "a" => {
254 if layer_name.is_empty() {
255 depth = match &depth {
256 LayerDepth::OneChannel => {
257 LayerDepth::OneChannelAndAlpha
258 }
259 LayerDepth::Color => {
260 LayerDepth::ColorAndAlpha
261 }
262 LayerDepth::Vector => {
263 LayerDepth::VectorAndAlpha
264 }
265 _ => unreachable!(),
266 };
267 } else {
268 depth = LayerDepth::FourChannels;
269 }
270 }
271 _ => (),
272 }
273 previous_layer_name = layer_name;
274 // We have a new layer.
275 } else {
276 previous_layer_name = layer_name;
277 }
278 previous_channel_id = channel_id;
279 None
280 }
281 })
282 .collect::<Vec<_>>(),
283 )
284 }
285
286 fn split_into_layer_name_and_channel_id(name: &str) -> (&str, &str) {
287 let mut split = name.rsplitn(3, '.');
288 // We know we never get an empty string so we can safely unwrap
289 // here.
290 let mut postfix = split.next().unwrap();
291 if "000" == postfix {
292 postfix = "s";
293 // Reset iterator.
294 split = name.rsplitn(2, '.');
295 }
296 // Skip the middle part.
297 if split.next().is_some() {
298 // We know that if there is middle part we always have a prefix
299 // so we can safely unwrap here.
300 (split.next().unwrap(), postfix)
301 } else {
302 ("", postfix)
303 }
304 }
305
306 /// Returns the total number of channels in a pixel.
307 /// This is the sum of the number of channels in all [`Layer`]s.
308 #[inline]
309 pub fn channels(&self) -> usize {
310 self.0
311 .iter()
312 .fold(0, |total, layer| total + layer.channels())
313 }
314}
315
316impl Deref for PixelFormat {
317 type Target = Vec<Layer>;
318
319 fn deref(&self) -> &Self::Target {
320 &self.0
321 }
322}
323
324impl AsRef<Vec<Layer>> for PixelFormat {
325 fn as_ref(&self) -> &Vec<Layer> {
326 &self.0
327 }
328}