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