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#[derive(Clone, Copy, PartialEq, Eq)]
18pub enum Flip {
19 None,
21 Vertical,
23}
24
25pub struct Texture(pub SrgbTexture2d, pub [SamplerWrapFunction; 2]);
27
28impl Texture {
29 pub fn new(texture: SrgbTexture2d) -> Texture {
31 Texture(texture, [SamplerWrapFunction::Clamp; 2])
32 }
33
34 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 #[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 #[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 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 #[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}