luminance/backend/
color_slot.rs

1//! Color slot backend interface.
2//!
3//! This interface defines the low-level API color slots must implement to be usable.
4//!
5//! # Note to backend contributors
6//!
7//! If you are implementing a backend, there is nothing here to implement, but you will likely want to use some traits /
8//! types from this module to use as constraint.
9
10use crate::{
11  backend::{framebuffer::Framebuffer, texture::Texture as TextureBackend},
12  context::GraphicsContext,
13  framebuffer::FramebufferError,
14  texture::{TexelUpload, Texture},
15};
16use crate::{
17  pixel::{ColorPixel, PixelFormat, RenderablePixel},
18  texture::{Dimensionable, Sampler},
19};
20
21/// A color slot.
22///
23/// A color slot represents the associated _color data_ within a [`Framebuffer`]. This type is entirely constructed at
24/// compile-time to ensure type safety. Even though this trait lives on the backend side of luminance, no backend is
25/// supposed to implement it, but instead use it.
26///
27/// Three types of color slots exist:
28///
29/// - None, represented by the `()` implementor.
30/// - A single color [`Texture`]. This type of color slot is often suitable for renderable framebuffer.
31/// - A tuple of different color [`Texture`]. This situation is mostly used for _multi render target_, allowing to
32///   render (via a fragment shader) into different part of the color slot.
33///
34/// For color slots that have color textures, the pixel type must be a [`RenderablePixel`] as well as a [`ColorPixel`].
35///
36/// Feel free to have a look at the list of implementors of this trait to know which types you can use as color slots.
37pub trait ColorSlot<B, D>
38where
39  B: ?Sized + Framebuffer<D>,
40  D: Dimensionable,
41  D::Size: Copy,
42{
43  /// The associated data.
44  ///
45  /// This type represents the available, constructed object that will be usable outside of the [`Framebuffer`]. There
46  /// is no trait to implement on this type but you mostly want to map a single [`Texture`] or a tuple of texture by
47  /// using this as a type family for your implementor type.
48  type ColorTextures;
49
50  /// Pixel format representing the color slot.
51  ///
52  /// Those [`PixelFormat`] represent the format of each part of the color slot.
53  fn color_formats() -> Vec<PixelFormat>;
54
55  /// Reify the color slots into 0, 1 or several textures.
56  ///
57  /// This function must construct and initialize all the required textures.
58  fn reify_color_textures<C>(
59    ctx: &mut C,
60    size: D::Size,
61    mipmaps: usize,
62    sampler: &Sampler,
63    framebuffer: &mut B::FramebufferRepr,
64    attachment_index: usize,
65  ) -> Result<Self::ColorTextures, FramebufferError>
66  where
67    C: GraphicsContext<Backend = B>;
68}
69
70impl<B, D> ColorSlot<B, D> for ()
71where
72  B: ?Sized + Framebuffer<D>,
73  D: Dimensionable,
74  D::Size: Copy,
75{
76  type ColorTextures = ();
77
78  fn color_formats() -> Vec<PixelFormat> {
79    Vec::new()
80  }
81
82  fn reify_color_textures<C>(
83    _: &mut C,
84    _: D::Size,
85    _: usize,
86    _: &Sampler,
87    _: &mut B::FramebufferRepr,
88    _: usize,
89  ) -> Result<Self::ColorTextures, FramebufferError>
90  where
91    C: GraphicsContext<Backend = B>,
92  {
93    Ok(())
94  }
95}
96
97impl<B, D, P> ColorSlot<B, D> for P
98where
99  B: ?Sized + Framebuffer<D> + TextureBackend<D, P>,
100  D: Dimensionable,
101  D::Size: Copy,
102  Self: ColorPixel + RenderablePixel,
103{
104  type ColorTextures = Texture<B, D, P>;
105
106  fn color_formats() -> Vec<PixelFormat> {
107    vec![P::pixel_format()]
108  }
109
110  fn reify_color_textures<C>(
111    ctx: &mut C,
112    size: D::Size,
113    mipmaps: usize,
114    sampler: &Sampler,
115    framebuffer: &mut B::FramebufferRepr,
116    attachment_index: usize,
117  ) -> Result<Self::ColorTextures, FramebufferError>
118  where
119    C: GraphicsContext<Backend = B>,
120  {
121    let texture = Texture::new(ctx, size, sampler.clone(), TexelUpload::reserve(mipmaps))?;
122
123    unsafe { B::attach_color_texture(framebuffer, &texture.repr, attachment_index)? };
124
125    Ok(texture)
126  }
127}
128
129macro_rules! impl_color_slot_tuple {
130  ($($pf:ident),*) => {
131    impl<B, D, $($pf),*> ColorSlot<B, D> for ($($pf),*)
132    where
133      B: ?Sized + Framebuffer<D> + $(TextureBackend<D, $pf> +)*,
134      D: Dimensionable,
135      D::Size: Copy,
136      $(
137        $pf: ColorPixel + RenderablePixel
138      ),*
139    {
140      type ColorTextures = ($(Texture<B, D, $pf>),*);
141
142      fn color_formats() -> Vec<PixelFormat> {
143        vec![$($pf::pixel_format()),*]
144
145      }
146
147      impl_reify_color_textures!{ $($pf),* }
148    }
149  }
150}
151
152// A small helper macro to implement reify_color_textures in impl_color_slot_tuple!.
153//
154// We need this macro so that we can implement the increment logic without having to do weird
155// arithmetic at runtime or have dead code.
156macro_rules! impl_reify_color_textures {
157  ($pf:ident , $($pfr:ident),*) => {
158    fn reify_color_textures<C>(
159      ctx: &mut C,
160      size: D::Size,
161      mipmaps: usize,
162      sampler: &Sampler,
163      framebuffer: &mut B::FramebufferRepr,
164      mut attachment_index: usize,
165    ) -> Result<Self::ColorTextures, FramebufferError>
166    where
167      C: GraphicsContext<Backend = B>,
168    {
169      let textures = (
170        // first element of the tuple
171        <$pf as ColorSlot<B, D>>::reify_color_textures(
172          ctx,
173          size,
174          mipmaps,
175          sampler,
176          framebuffer,
177          attachment_index,
178        )?,
179        // rest of the tuple
180        $({
181          attachment_index += 1;
182          let texture = <$pfr as ColorSlot<B, D>>::reify_color_textures(
183            ctx,
184            size,
185            mipmaps,
186            sampler,
187            framebuffer,
188            attachment_index,
189          )?;
190
191          texture
192        }),*
193      );
194
195      Ok(textures)
196    }
197  }
198}
199
200macro_rules! impl_color_slot_tuples {
201  ($first:ident , $second:ident) => {
202    // stop at pairs
203    impl_color_slot_tuple!($first, $second);
204  };
205
206  ($first:ident , $($pf:ident),*) => {
207    // implement the same list without the first type (reduced by one)
208    impl_color_slot_tuples!($($pf),*);
209    // implement the current list
210    impl_color_slot_tuple!($first, $($pf),*);
211  };
212}
213
214impl_color_slot_tuples!(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11);