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}