rendy_texture/
pixel.rs

1//! Typed pixel formats.
2//! More information on these can be found [here](https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s03.html#VkFormat)
3//!
4
5/// Normalized unsigned integer representation
6#[derive(Clone, Copy, Debug, Default)]
7pub struct Unorm;
8
9/// Normalized signed integer representation
10#[derive(Clone, Copy, Debug, Default)]
11pub struct Inorm;
12
13/// Unsigned integer representation
14#[derive(Clone, Copy, Debug, Default)]
15pub struct Uint;
16
17/// Signed integer representation
18#[derive(Clone, Copy, Debug, Default)]
19pub struct Int;
20
21/// Unsigned scaled integer representation
22#[derive(Clone, Copy, Debug, Default)]
23pub struct Uscaled;
24
25/// Signed scaled integer representation
26#[derive(Clone, Copy, Debug, Default)]
27pub struct Iscaled;
28
29/// `Unorm` but in with srgb gammar correction.
30#[derive(Clone, Copy, Debug, Default)]
31pub struct Srgb;
32
33/// Floating point representation.
34#[derive(Clone, Copy, Debug, Default)]
35pub struct Float;
36
37/// 8 bits marker type
38#[derive(Clone, Copy, Debug, Default)]
39pub struct _8;
40
41/// 16 bits marker type
42#[derive(Clone, Copy, Debug, Default)]
43pub struct _16;
44
45/// 32 bits marker type
46#[derive(Clone, Copy, Debug, Default)]
47pub struct _32;
48
49/// 64 bits marker type
50#[derive(Clone, Copy, Debug, Default)]
51pub struct _64;
52
53/// Byte size of each channel in the image, such as Red, Green,
54/// or other channels depending on the format.
55pub trait ChannelSize {
56    /// Channel representation.
57    const SIZE: u32;
58}
59
60impl ChannelSize for _8 {
61    const SIZE: u32 = 1;
62}
63impl ChannelSize for _16 {
64    const SIZE: u32 = 2;
65}
66impl ChannelSize for _32 {
67    const SIZE: u32 = 4;
68}
69impl ChannelSize for _64 {
70    const SIZE: u32 = 8;
71}
72
73/// Channel representation as a Rust type
74pub trait ChannelRepr<S> {
75    /// Newtype to reduce verbosity of representing a Channel in Rust
76    type Repr: Sized + std::fmt::Debug + Default + Copy + Send + Sync + 'static;
77}
78
79/// Generates an impl for a Channel
80macro_rules! impl_channel_repr {
81    ($($type:ident * $size:ident = $repr:ident;)*) => {
82        $(
83            impl ChannelRepr<$size> for $type { type Repr = $repr; }
84        )*
85    };
86}
87
88// Actually generates the impl for the below types
89impl_channel_repr! {
90    Unorm * _8 = u8;
91    Inorm * _8 = u8;
92    Uint * _8 = u8;
93    Int * _8 = u8;
94    Uscaled * _8 = u8;
95    Iscaled * _8 = u8;
96    Srgb * _8 = u8;
97
98    Unorm * _16 = u16;
99    Inorm * _16 = u16;
100    Uint * _16 = u16;
101    Int * _16 = u16;
102    Uscaled * _16 = u16;
103    Iscaled * _16 = u16;
104    Srgb * _16 = u16;
105
106    Unorm * _32 = u32;
107    Inorm * _32 = u32;
108    Uint * _32 = u32;
109    Int * _32 = u32;
110    Uscaled * _32 = u32;
111    Iscaled * _32 = u32;
112    Srgb * _32 = u32;
113    Float * _32 = f32;
114
115    Unorm * _64 = u64;
116    Inorm * _64 = u64;
117    Uint * _64 = u64;
118    Int * _64 = u64;
119    Uscaled * _64 = u64;
120    Iscaled * _64 = u64;
121    Srgb * _64 = u64;
122    Float * _64 = f64;
123}
124
125/// Red channel.
126#[derive(Clone, Copy, Debug, Default)]
127pub struct R;
128
129/// Red-green channels.
130#[derive(Clone, Copy, Debug, Default)]
131pub struct Rg;
132
133/// Red-green-blue channels.
134#[derive(Clone, Copy, Debug, Default)]
135pub struct Rgb;
136
137/// Red-green-blue-alpha channels.
138#[derive(Clone, Copy, Debug, Default)]
139pub struct Rgba;
140
141/// Blue-green-red channels.
142#[derive(Clone, Copy, Debug, Default)]
143pub struct Bgr;
144
145/// Blue-green-red-alpha channels.
146#[derive(Clone, Copy, Debug, Default)]
147pub struct Bgra;
148
149/// Alpha-blue-green-red channels.
150#[derive(Clone, Copy, Debug, Default)]
151pub struct Abgr;
152
153/// Pixel representation as a Rust type
154pub trait PixelRepr<S, T> {
155    /// Newtype to reduce verbosity of representing a Pixel in Rust
156    type Repr: Sized + std::fmt::Debug + Default + Copy + Send + Sync + 'static;
157}
158
159/// Returns the number of channels for common RGBA combinations
160macro_rules! num_channels {
161    (R) => {
162        1
163    };
164    (Rg) => {
165        2
166    };
167    (Rgb) => {
168        3
169    };
170    (Rgba) => {
171        4
172    };
173    (Bgr) => {
174        3
175    };
176    (Bgra) => {
177        4
178    };
179    (Abgr) => {
180        4
181    };
182}
183
184/// Generates the Pixel impl for various Channels
185macro_rules! impl_pixel_repr {
186    ($($channels:ident;)*) => {
187        $(
188            impl<S, T> PixelRepr<S, T> for $channels
189            where
190                S: ChannelSize,
191                T: ChannelRepr<S>,
192            {
193                type Repr = [<T as ChannelRepr<S>>::Repr; num_channels!($channels)];
194            }
195        )*
196    };
197}
198
199// Actually use the macro to generate the implementations
200impl_pixel_repr! {
201    R;
202    Rg;
203    Rgb;
204    Rgba;
205    Bgr;
206    Bgra;
207    Abgr;
208}
209
210/// One pixel
211#[repr(transparent)]
212pub struct Pixel<C, S, T>
213where
214    C: PixelRepr<S, T>,
215{
216    /// Pixel representation.
217    pub repr: <C as PixelRepr<S, T>>::Repr,
218}
219
220impl<C, S, T> Copy for Pixel<C, S, T> where C: PixelRepr<S, T> {}
221
222impl<C, S, T> Clone for Pixel<C, S, T>
223where
224    C: PixelRepr<S, T>,
225{
226    fn clone(&self) -> Self {
227        Pixel {
228            repr: self.repr.clone(),
229        }
230    }
231}
232
233impl<C, S, T> std::fmt::Debug for Pixel<C, S, T>
234where
235    C: PixelRepr<S, T>,
236{
237    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        fmt.debug_struct("Pixel").field("repr", &self.repr).finish()
239    }
240}
241
242impl<C, S, T> Default for Pixel<C, S, T>
243where
244    C: PixelRepr<S, T>,
245{
246    fn default() -> Self {
247        Pixel {
248            repr: C::Repr::default(),
249        }
250    }
251}
252
253/// AsPixel trait for extracting the underlying data representation information from a Rust data type
254/// # Example
255/// ```rust,no-run
256/// struct Rgba([u8; 4]);
257/// ```
258pub trait AsPixel: Copy + std::fmt::Debug + Default + Send + Sync + 'static {
259    /// Name of the pixel type.
260    const NAME: &'static str;
261
262    /// Size of the pixel.
263    const SIZE: u32;
264
265    /// Pixel format.
266    const FORMAT: rendy_core::hal::format::Format;
267}
268
269macro_rules! impl_pixel {
270    ($($alias:ident = $channels:ident $size:ident $type:ident;)*) => {
271        $(
272            /// Pixel type alias.
273            pub type $alias = Pixel<$channels, $size, $type>;
274
275            impl AsPixel for $alias {
276                const NAME: &'static str = stringify!($alias);
277                const SIZE: u32 = num_channels!($channels) * <$size as ChannelSize>::SIZE;
278                const FORMAT: rendy_core::hal::format::Format = rendy_core::hal::format::Format::$alias;
279            }
280        )*
281    };
282}
283
284// Actually implement AsPixel for all the formats
285// TODO: Implement AsPixel for the Float; they are commented out until then
286impl_pixel! {
287    R8Unorm = R _8 Unorm;
288    R8Snorm = R _8 Inorm;
289    R8Uscaled = R _8 Uscaled;
290    R8Sscaled = R _8 Iscaled;
291    R8Uint = R _8 Uint;
292    R8Sint = R _8 Int;
293    R8Srgb = R _8 Srgb;
294    Rg8Unorm = Rg _8 Unorm;
295    Rg8Snorm = Rg _8 Inorm;
296    Rg8Uscaled = Rg _8 Uscaled;
297    Rg8Sscaled = Rg _8 Iscaled;
298    Rg8Uint = Rg _8 Uint;
299    Rg8Sint = Rg _8 Int;
300    Rg8Srgb = Rg _8 Srgb;
301    Rgb8Unorm = Rgb _8 Unorm;
302    Rgb8Snorm = Rgb _8 Inorm;
303    Rgb8Uscaled = Rgb _8 Uscaled;
304    Rgb8Sscaled = Rgb _8 Iscaled;
305    Rgb8Uint = Rgb _8 Uint;
306    Rgb8Sint = Rgb _8 Int;
307    Rgb8Srgb = Rgb _8 Srgb;
308    Bgr8Unorm = Bgr _8 Unorm;
309    Bgr8Snorm = Bgr _8 Inorm;
310    Bgr8Uscaled = Bgr _8 Uscaled;
311    Bgr8Sscaled = Bgr _8 Iscaled;
312    Bgr8Uint = Bgr _8 Uint;
313    Bgr8Sint = Bgr _8 Int;
314    Bgr8Srgb = Bgr _8 Srgb;
315    Rgba8Unorm = Rgba _8 Unorm;
316    Rgba8Snorm = Rgba _8 Inorm;
317    Rgba8Uscaled = Rgba _8 Uscaled;
318    Rgba8Sscaled = Rgba _8 Iscaled;
319    Rgba8Uint = Rgba _8 Uint;
320    Rgba8Sint = Rgba _8 Int;
321    Rgba8Srgb = Rgba _8 Srgb;
322    Bgra8Unorm = Bgra _8 Unorm;
323    Bgra8Snorm = Bgra _8 Inorm;
324    Bgra8Uscaled = Bgra _8 Uscaled;
325    Bgra8Sscaled = Bgra _8 Iscaled;
326    Bgra8Uint = Bgra _8 Uint;
327    Bgra8Sint = Bgra _8 Int;
328    Bgra8Srgb = Bgra _8 Srgb;
329    Abgr8Unorm = Abgr _8 Unorm;
330    Abgr8Snorm = Abgr _8 Inorm;
331    Abgr8Uscaled = Abgr _8 Uscaled;
332    Abgr8Sscaled = Abgr _8 Iscaled;
333    Abgr8Uint = Abgr _8 Uint;
334    Abgr8Sint = Abgr _8 Int;
335    Abgr8Srgb = Abgr _8 Srgb;
336    R16Unorm = R _16 Unorm;
337    R16Snorm = R _16 Inorm;
338    R16Uscaled = R _16 Uscaled;
339    R16Sscaled = R _16 Iscaled;
340    R16Uint = R _16 Uint;
341    R16Sint = R _16 Int;
342    // R16Sfloat = R _16 Float;
343    Rg16Unorm = Rg _16 Unorm;
344    Rg16Snorm = Rg _16 Inorm;
345    Rg16Uscaled = Rg _16 Uscaled;
346    Rg16Sscaled = Rg _16 Iscaled;
347    Rg16Uint = Rg _16 Uint;
348    Rg16Sint = Rg _16 Int;
349    // Rg16Sfloat = Rg _16 Float;
350    Rgb16Unorm = Rgb _16 Unorm;
351    Rgb16Snorm = Rgb _16 Inorm;
352    Rgb16Uscaled = Rgb _16 Uscaled;
353    Rgb16Sscaled = Rgb _16 Iscaled;
354    Rgb16Uint = Rgb _16 Uint;
355    Rgb16Sint = Rgb _16 Int;
356    // Rgb16Sfloat = Rgb _16 Float;
357    Rgba16Unorm = Rgba _16 Unorm;
358    Rgba16Snorm = Rgba _16 Inorm;
359    Rgba16Uscaled = Rgba _16 Uscaled;
360    Rgba16Sscaled = Rgba _16 Iscaled;
361    Rgba16Uint = Rgba _16 Uint;
362    Rgba16Sint = Rgba _16 Int;
363    // Rgba16Sfloat = Rgba _16 Float;
364    R32Uint = R _32 Uint;
365    R32Sint = R _32 Int;
366    R32Sfloat = R _32 Float;
367    Rg32Uint = Rg _32 Uint;
368    Rg32Sint = Rg _32 Int;
369    Rg32Sfloat = Rg _32 Float;
370    Rgb32Uint = Rgb _32 Uint;
371    Rgb32Sint = Rgb _32 Int;
372    Rgb32Sfloat = Rgb _32 Float;
373    Rgba32Uint = Rgba _32 Uint;
374    Rgba32Sint = Rgba _32 Int;
375    Rgba32Sfloat = Rgba _32 Float;
376    R64Uint = R _64 Uint;
377    R64Sint = R _64 Int;
378    R64Sfloat = R _64 Float;
379    Rg64Uint = Rg _64 Uint;
380    Rg64Sint = Rg _64 Int;
381    Rg64Sfloat = Rg _64 Float;
382    Rgb64Uint = Rgb _64 Uint;
383    Rgb64Sint = Rgb _64 Int;
384    Rgb64Sfloat = Rgb _64 Float;
385    Rgba64Uint = Rgba _64 Uint;
386    Rgba64Sint = Rgba _64 Int;
387    Rgba64Sfloat = Rgba _64 Float;
388}
389
390#[cfg(feature = "palette")]
391mod palette_pixel {
392    //! A palette_pixel represents is a type that represents a single color value
393    //! in a color space.
394    //!
395    use palette::{
396        encoding,
397        luma::{Luma, LumaStandard, Lumaa},
398        rgb::{Rgb, RgbStandard, Rgba},
399        white_point::D65,
400        Component,
401    };
402
403    macro_rules! impl_from_palette {
404        (# $color:ident R as $encoding:path) => {
405            {
406                let f = $color.into_format();
407                let _: (f32,) = f.into_components();
408                let (r,) = f.into_encoding::<$encoding>().into_format().into_components();
409                Self { repr: [r] }
410            }
411        };
412        (# $color:ident Rg as $encoding:path) => {
413            {
414                let f = $color.into_format();
415                let _: (f32,f32) = f.into_components();
416                let (r,g) = f.into_encoding::<$encoding>().into_format().into_components();
417                Self { repr: [r,g] }
418            }
419        };
420        (# $color:ident Rgb as $encoding:path) => {
421            {
422                let f = $color.into_format();
423                let _: (f32,f32,f32) = f.into_components();
424                let (r,g,b) = f.into_encoding::<$encoding>().into_format().into_components();
425                Self { repr: [r,g,b] }
426            }
427        };
428        (# $color:ident Rgba as $encoding:path) => {
429            {
430                let f = $color.into_format();
431                let _: (f32,f32,f32,f32) = f.into_components();
432                let (r,g,b,a) = f.into_encoding::<$encoding>().into_format().into_components();
433                Self { repr: [r,g,b,a] }
434            }
435        };
436
437        ($($container:path as $encoding:path : $standard:path => $channels:ident $($repr:ident)|+),* $(,)*) => {$($(
438            impl<S, T, B> From<$container> for super::Pixel<super::$channels, B, super::$repr>
439            where
440                S: $standard,
441                T: Component,
442                B: super::ChannelSize,
443                super::$repr: super::ChannelRepr<B>,
444                <super::$repr as super::ChannelRepr<B>>::Repr: Component,
445            {
446                fn from(color: $container) -> Self {
447                    impl_from_palette!(# color $channels as $encoding)
448                }
449            }
450        )+)*};
451    }
452
453    impl_from_palette! {
454        Rgb<S, T> as encoding::Srgb: RgbStandard<Space = encoding::Srgb> => Rgb Srgb,
455        Rgba<S, T> as encoding::Srgb: RgbStandard<Space = encoding::Srgb> => Rgba Srgb,
456        Luma<S, T> as encoding::Srgb: LumaStandard<WhitePoint = D65> => R Srgb,
457        Lumaa<S, T> as encoding::Srgb: LumaStandard<WhitePoint = D65> => Rg Srgb,
458
459        Rgb<S, T> as encoding::Linear<encoding::Srgb>: RgbStandard<Space = encoding::Srgb> => Rgb Unorm | Float,
460        Rgba<S, T> as encoding::Linear<encoding::Srgb>: RgbStandard<Space = encoding::Srgb> => Rgba Unorm | Float,
461
462        Luma<S, T> as encoding::Linear<D65>: LumaStandard<WhitePoint = D65> => R Unorm | Float,
463        Lumaa<S, T> as encoding::Linear<D65>: LumaStandard<WhitePoint = D65> => Rg Unorm | Float,
464    }
465}