Skip to main content

radiant_rs/core/
texture.rs

1use crate::prelude::*;
2use crate::core::{Context, Color, Uniform, AsUniform, RenderTarget, AsRenderTarget, Point2};
3use crate::core::builder::*;
4use image::{self, GenericImageView};
5use crate::backends::backend;
6
7/// A texture to draw or draw to.
8///
9/// Textures serve as drawing targets for userdefined [`Postprocessors`](trait.Postprocessor.html)
10/// or custom [`Programs`](struct.Program.html). A texture can also be drawn with
11/// [`Renderer::rect()`](struct.Renderer.html#method.rect).
12#[derive(Clone)]
13pub struct Texture {
14    pub(crate) handle       : Rc<backend::Texture2d>,
15    pub(crate) minify       : TextureFilter,
16    pub(crate) magnify      : TextureFilter,
17    pub(crate) wrap         : TextureWrap,
18    pub(crate) dimensions   : Point2<u32>,
19}
20
21impl Debug for Texture {
22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23        f.debug_struct("Texture")
24            .field("minify", &self.minify)
25            .field("magnify", &self.magnify)
26            .field("wrap", &self.wrap)
27            .field("dimensions", &self.dimensions)
28            .finish()
29    }
30}
31
32impl Texture {
33    /// Returns a texture builder for texture construction.
34    ///
35    /// # Examples
36    ///
37    /// ```rust
38    /// # use radiant_rs::*;
39    /// # let display = Display::builder().hidden().build().unwrap();
40    /// # let renderer = Renderer::new(&display).unwrap();
41    /// # let context = display.context();
42    /// let tex = Texture::builder(&context)
43    ///                     .dimensions((640, 480))
44    ///                     .magnify(TextureFilter::Nearest)
45    ///                     .minify(TextureFilter::Linear)
46    ///                     .build()
47    ///                     .unwrap();
48    /// ```
49    pub fn builder(context: &Context) -> TextureBuilder<'_> {
50        TextureBuilder::new(context)
51    }
52    /// Creates a new texture with given dimensions. The texture will use linear interpolation
53    /// for magnification or minification and internally use the `F16F16F16F16` format.
54    pub fn new(context: &Context, width: u32, height: u32) -> Self {
55        Self::builder(context).width(width).height(height).build().unwrap()
56    }
57    /// Creates a new texture from given file.
58    pub fn from_file(context: &Context, file: &str) -> crate::core::Result<Self> {
59        Self::builder(context).file(file).build()
60    }
61    /// Creates a new texture with given dimensions and filters. It will internally use the `F16F16F16F16` format.
62    pub fn filtered(context: &Context, width: u32, height: u32, minify: TextureFilter, magnify: TextureFilter) -> Self {
63        Self::builder(context).width(width).height(height).minify(minify).magnify(magnify).build().unwrap()
64    }
65    /// Clones texture with new filters and wrapping function. Both source and clone reference the same texture data.
66    pub fn clone_with_options(self: &Self, minify: TextureFilter, magnify: TextureFilter, wrap: TextureWrap) -> Self {
67        Texture {
68            handle      : self.handle.clone(),
69            minify      : minify,
70            magnify     : magnify,
71            wrap        : wrap,
72            dimensions  : self.dimensions,
73        }
74    }
75    /// Clears the texture with given color.
76    pub fn clear(self: &Self, color: Color) {
77        self.handle.clear(color);
78    }
79    /// Returns the dimensions of the texture.
80    pub fn dimensions(self: &Self) -> Point2<u32> {
81        self.dimensions
82    }
83    /// Creates a new texture from given TextureBuilder.
84    pub(crate) fn from_builder(mut builder: TextureBuilder) -> crate::core::Result<Self> {
85        let mut context = builder.context.lock();
86        let context = context.deref_mut();
87        if let Some(filename) = builder.file {
88            let image = image::open(filename)?;
89            builder.width = image.dimensions().0;
90            builder.height = image.dimensions().1;
91            builder.format = crate::core::TextureFormat::U8U8U8U8;
92            builder.data = Some(crate::core::RawFrame {
93                data: crate::core::convert_color(image.into_rgba8()).into_raw(),
94                width: builder.width,
95                height: builder.height,
96                channels: 4,
97            });
98        }
99        let texture = backend::Texture2d::new(context.backend_context.as_ref().unwrap(), builder.width, builder.height, builder.format, builder.data);
100        Ok(Texture {
101            handle      : Rc::new(texture),
102            minify      : builder.minify,
103            magnify     : builder.magnify,
104            wrap        : builder.wrap,
105            dimensions  : (builder.width, builder.height),
106        })
107    }
108}
109
110impl AsRenderTarget for Texture {
111    fn as_render_target(self: &Self) -> RenderTarget {
112        RenderTarget::texture(self)
113    }
114}
115
116impl AsUniform for Texture {
117    fn as_uniform(self: &Self) -> Uniform {
118        Uniform::Texture(self.clone())
119    }
120}
121
122/// Texture minify- or magnify filtering function.
123#[derive(Copy, Clone, Debug, PartialEq)]
124pub enum TextureFilter {
125    /// All nearby texels will be loaded and their values will be merged.
126    Linear,
127    /// The nearest texel will be loaded.
128    Nearest,
129}
130
131/// Texture wrapping function.
132#[derive(Copy, Clone, Debug, PartialEq)]
133pub enum TextureWrap {
134    /// Samples at coord x + 1 map to coord x.
135    Repeat,
136    /// Samples at coord x + 1 map to coord 1 - x.
137    Mirror,
138    /// Samples at coord x + 1 map to coord 1.
139    Clamp,
140    /// Same as Mirror, but only for one repetition.
141    MirrorClamp,
142}
143
144/// Internal texture format. Note that the shader will always see a floating
145/// point representation. U[n]* will have their minimum value mapped to 0.0 and
146/// their maximum to 1.0.
147#[derive(Copy, Clone, Debug, PartialEq)]
148pub enum TextureFormat {
149    U8,
150    U16,
151    U8U8,
152    U16U16,
153    U10U10U10,
154    U12U12U12,
155    U16U16U16,
156    U2U2U2U2,
157    U4U4U4U4,
158    U5U5U5U1,
159    U8U8U8U8,
160    U10U10U10U2,
161    U12U12U12U12,
162    U16U16U16U16,
163    I16I16I16I16,
164    F16,
165    F16F16,
166    F16F16F16F16,
167    F32,
168    F32F32,
169    F32F32F32F32,
170    F11F11F10,
171}