glium_graphics/
glium_texture.rs

1#[cfg(feature = "image")]
2extern crate image;
3
4#[cfg(feature = "image")]
5use std::path::Path;
6
7#[cfg(feature = "image")]
8use self::image::{DynamicImage, RgbaImage};
9use glium::backend::Facade;
10use glium::texture::srgb_texture2d::SrgbTexture2d;
11use glium::texture::{RawImage2d, TextureCreationError};
12use glium::uniforms::SamplerWrapFunction;
13use graphics::ImageSize;
14use texture::{self, CreateTexture, Format, TextureOp, TextureSettings, UpdateTexture};
15
16/// Flip settings.
17#[derive(Clone, Copy, PartialEq, Eq)]
18pub enum Flip {
19    /// Does not flip.
20    None,
21    /// Flips image vertically.
22    Vertical,
23}
24
25/// Wrapper for 2D texture.
26pub struct Texture(pub SrgbTexture2d, pub [SamplerWrapFunction; 2]);
27
28impl Texture {
29    /// Creates a new `Texture`.
30    pub fn new(texture: SrgbTexture2d) -> Texture {
31        Texture(texture, [SamplerWrapFunction::Clamp; 2])
32    }
33
34    /// Returns empty texture.
35    pub fn empty<F>(factory: &mut F) -> Result<Self, TextureCreationError>
36    where
37        F: Facade,
38    {
39        CreateTexture::create(
40            factory,
41            Format::Rgba8,
42            &[0u8; 4],
43            [1, 1],
44            &TextureSettings::new(),
45        )
46    }
47
48    /// Creates a texture from path.
49    #[cfg(feature = "image")]
50    pub fn from_path<F, P>(
51        factory: &mut F,
52        path: P,
53        flip: Flip,
54        settings: &TextureSettings,
55    ) -> Result<Self, String>
56    where
57        F: Facade,
58        P: AsRef<Path>,
59    {
60        let img = image::open(path).map_err(|e| e.to_string())?;
61
62        let img = match img {
63            DynamicImage::ImageRgba8(img) => img,
64            img => img.to_rgba8(),
65        };
66
67        let img = if flip == Flip::Vertical {
68            image::imageops::flip_vertical(&img)
69        } else {
70            img
71        };
72
73        Texture::from_image(factory, &img, settings).map_err(|e| format!("{:?}", e))
74    }
75
76    /// Creates a texture from image.
77    #[cfg(feature = "image")]
78    pub fn from_image<F>(
79        factory: &mut F,
80        img: &RgbaImage,
81        settings: &TextureSettings,
82    ) -> Result<Self, TextureCreationError>
83    where
84        F: Facade,
85    {
86        let (width, height) = img.dimensions();
87        CreateTexture::create(factory, Format::Rgba8, img, [width, height], settings)
88    }
89
90    /// Creates texture from memory alpha.
91    pub fn from_memory_alpha<F>(
92        factory: &mut F,
93        buffer: &[u8],
94        width: u32,
95        height: u32,
96        settings: &TextureSettings,
97    ) -> Result<Self, TextureCreationError>
98    where
99        F: Facade,
100    {
101        if width == 0 || height == 0 {
102            return Texture::empty(factory);
103        }
104
105        let size = [width, height];
106        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
107        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
108    }
109
110    /// Updates texture with an image.
111    #[cfg(feature = "image")]
112    pub fn update<F>(
113        &mut self,
114        factory: &mut F,
115        img: &RgbaImage,
116    ) -> Result<(), TextureCreationError>
117    where
118        F: Facade,
119    {
120        let (width, height) = img.dimensions();
121        UpdateTexture::update(self, factory, Format::Rgba8, img, [0, 0], [width, height])
122    }
123}
124
125impl ImageSize for Texture {
126    fn get_size(&self) -> (u32, u32) {
127        let ref tex = self.0;
128        (tex.get_width(), tex.get_height().unwrap())
129    }
130}
131
132impl<F> TextureOp<F> for Texture {
133    type Error = TextureCreationError;
134}
135
136impl<F> CreateTexture<F> for Texture
137where
138    F: Facade,
139{
140    fn create<S: Into<[u32; 2]>>(
141        factory: &mut F,
142        _format: Format,
143        memory: &[u8],
144        size: S,
145        settings: &TextureSettings,
146    ) -> Result<Self, Self::Error> {
147        use texture::Wrap;
148        let size = size.into();
149
150        let f = |wrap| match wrap {
151            Wrap::ClampToEdge => SamplerWrapFunction::Clamp,
152            Wrap::Repeat => SamplerWrapFunction::Repeat,
153            Wrap::MirroredRepeat => SamplerWrapFunction::Mirror,
154            Wrap::ClampToBorder => SamplerWrapFunction::BorderClamp,
155        };
156
157        let wrap_u = f(settings.get_wrap_u());
158        let wrap_v = f(settings.get_wrap_v());
159        Ok(Texture(
160            SrgbTexture2d::new(
161                factory,
162                RawImage2d::from_raw_rgba_reversed(memory, (size[0], size[1]))
163            )?,
164            [wrap_u, wrap_v],
165        ))
166    }
167}
168
169impl<F> UpdateTexture<F> for Texture
170where
171    F: Facade,
172{
173    #[allow(unused_variables)]
174    fn update<O: Into<[u32; 2]>, S: Into<[u32; 2]>>(
175        &mut self,
176        factory: &mut F,
177        _format: Format,
178        memory: &[u8],
179        offset: O,
180        size: S,
181    ) -> Result<(), Self::Error> {
182        use glium::Rect;
183
184        let offset = offset.into();
185        let size = size.into();
186        let (_, h) = self.get_size();
187        self.0.write(
188            Rect {
189                left: offset[0],
190                bottom: h - offset[1] - size[1],
191                width: size[0],
192                height: size[1],
193            },
194            RawImage2d::from_raw_rgba_reversed(memory, (size[0], size[1])),
195        );
196        Ok(())
197    }
198}