processing/
textures.rs

1use std::ops::DerefMut;
2
3use glium;
4use image_ext;
5
6use {Screen, ScreenType};
7use errors::ProcessingErr;
8
9// not a part of the standard OpenGL specs?...
10const GL_TEXTURE_MAX_ANISOTROPY_EXT: u32 = 0x84FE;
11
12impl<'a> Screen<'a> {
13	/// Take an image (in particular anything that implements image::ImageBuffer,
14	/// such as the image::ImageRgba returned by processing.load_image()) and upload
15	/// it to the GPU as a texture for later use. In return, you will get a reference
16	/// to the texture, its width in normalized screen coordinates (i.e., [0,1]),
17	/// and its height in normalized screen coordinates.
18    pub fn texture<P, S, C>(
19        &mut self,
20        img: &image_ext::ImageBuffer<P, C>,
21    ) -> Result<(glium::texture::Texture2d, f64, f64), ProcessingErr>
22    where
23        P: image_ext::Pixel<Subpixel = S> + 'static,
24        S: image_ext::Primitive + 'static + glium::texture::ToClientFormat + glium::texture::PixelValue,
25        C: DerefMut<Target = [P::Subpixel]>,
26    {
27        let wh = img.dimensions();
28        // let raw = img.into_raw().clone();
29        let image_ext = glium::texture::RawImage2d::from_raw_rgba_reversed(&img, wh);
30        let texture = match self.display {
31            ScreenType::Window(ref d) => {
32                glium::texture::Texture2d::with_format(
33                    d,
34                    image_ext,
35                    glium::texture::UncompressedFloatFormat::F32F32F32F32,
36                    glium::texture::MipmapsOption::AutoGeneratedMipmaps,
37                ).map_err(|e| ProcessingErr::TextureNoCreate(e))?
38            }
39            ScreenType::Headless(ref d) => {
40                glium::texture::Texture2d::with_format(
41                    d,
42                    image_ext,
43                    glium::texture::UncompressedFloatFormat::F32F32F32F32,
44                    glium::texture::MipmapsOption::AutoGeneratedMipmaps,
45                ).map_err(|e| ProcessingErr::TextureNoCreate(e))?
46            }
47        };
48
49        // maxAniso := []float32{0.0}
50        // gl::GetFloatv(GL_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso[0])
51        // gl::TexParameterf(gl::TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso[0])
52        // this will require some performance testing. it might be too heavy for
53        // psychophysics
54        // gl::TexParameterf(gl::TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16f32);
55
56        Ok((
57            texture,
58            wh.0 as f64 / self.width as f64,
59            wh.1 as f64 / self.height as f64,
60        ))
61    }
62
63	/// Create an empty texture on the GPU. The output is the same as screen.texture(),
64	/// so see that for more info. This function is useful in circumstances where you
65	/// want to draw something onto a texture and use that for a later purpose, rather
66	/// than load an external image. See the framebuffers module for more info.
67    pub fn empty_texture(&self, w: u32, h: u32) -> Result<(glium::texture::Texture2d, f64, f64), ProcessingErr> {
68        let texture = match self.display {
69            ScreenType::Window(ref d) => {
70                glium::texture::Texture2d::empty_with_format(
71                    d,
72                    glium::texture::UncompressedFloatFormat::F32F32F32F32,
73                    glium::texture::MipmapsOption::AutoGeneratedMipmaps,
74                    w,
75                    h,
76                ).map_err(|e| ProcessingErr::TextureNoCreate(e))?
77            }
78            ScreenType::Headless(ref d) => {
79                glium::texture::Texture2d::empty_with_format(
80                    d,
81                    glium::texture::UncompressedFloatFormat::F32F32F32F32,
82                    glium::texture::MipmapsOption::AutoGeneratedMipmaps,
83                    w,
84                    h,
85                ).map_err(|e| ProcessingErr::TextureNoCreate(e))?
86            }
87        };
88
89        Ok((
90            texture,
91            w as f64 / self.width as f64,
92            h as f64 / self.height as f64,
93        ))
94    }
95
96	/// Rather than create a texture from an external image or creating an empty texture
97	/// and drawing to it, you can create a texture from arbitrary data. It expects a
98	/// Vec of Vec (mimicing the layout of an image) that contains anything that
99	/// implements glium::texture::PixelValue.
100    pub fn texture_from_data<P: glium::texture::PixelValue>(
101        &self,
102        data: Vec<Vec<P>>,
103    ) -> Result<(glium::texture::Texture2d, f64, f64), ProcessingErr> {
104        let h = data.len();
105        let w = data[0].len();
106        let texture = match self.display {
107            ScreenType::Window(ref d) => {
108                glium::texture::Texture2d::with_mipmaps(
109                    d,
110                    data,
111                    glium::texture::MipmapsOption::AutoGeneratedMipmaps,
112                ).map_err(|e| ProcessingErr::TextureNoCreate(e))?
113            }
114            ScreenType::Headless(ref d) => {
115                glium::texture::Texture2d::with_mipmaps(
116                    d,
117                    data,
118                    glium::texture::MipmapsOption::AutoGeneratedMipmaps,
119                ).map_err(|e| ProcessingErr::TextureNoCreate(e))?
120            }
121        };
122
123
124        Ok((
125            texture,
126            w as f64 / self.width as f64,
127            h as f64 / self.height as f64,
128        ))
129    }
130
131	/// A texture array is a uniform sampler on the GPU that will place many
132	/// 2-dimensional textures (i.e., pre-processed RGBA images) in one part of memory.     /// For the user, this means that you can upload a movie for instance and step
133	/// through the frames in your shader via an overloaded call to texture().
134	/// Please see OpenGL tutorials and documentation for more info. This function
135	/// returns a glium::texture::Texture2dArray, which is accepted by the
136	/// `create_uniforms{}` macro.
137    pub fn texture_array<T: Clone + 'a + glium::texture::PixelValue>(&mut self, images: Vec<glium::texture::RawImage2d<T>>) -> Result<glium::texture::Texture2dArray, ProcessingErr> {
138            match self.display {
139                ScreenType::Window(ref d) => {
140                    glium::texture::Texture2dArray::with_format(d,
141                        images,
142                        glium::texture::UncompressedFloatFormat::F32F32F32F32,
143                        glium::texture::MipmapsOption::AutoGeneratedMipmaps)
144                        	.map_err(|e| ProcessingErr::TextureNoCreate(e))
145                }
146                ScreenType::Headless(ref d) => {
147                    glium::texture::Texture2dArray::with_format(d,
148                        images,
149                        glium::texture::UncompressedFloatFormat::F32F32F32F32,
150                        glium::texture::MipmapsOption::AutoGeneratedMipmaps)
151                        	.map_err(|e| ProcessingErr::TextureNoCreate(e))
152                }
153        }
154    }
155
156
157	/// When you sample outside the boundaries of a texture, should it wrap around and
158	/// repeat ("REPEAT", the default) or should it clamp ("CLAMP") at the edge. See
159	/// the official Processing reference for more info and examples.
160    pub fn texture_wrap(&mut self, wrap: &str) {
161        if wrap == "CLAMP" {
162            self.wrap = glium::uniforms::SamplerWrapFunction::Clamp;
163        } else if wrap == "REPEAT" {
164            self.wrap = glium::uniforms::SamplerWrapFunction::Repeat;
165        }
166    }
167}
168
169// pub fn del_textures(texs: &[u32]) {
170// unsafe {
171// gl::DeleteTextures(texs.len() as i32, mem::transmute(&texs[0]));
172// }
173// }