processing 0.3.2

An implementation of the Processing environment for Rust, with influences from Cinder and openFrameworks. It is written with Glium and has a Glutin and a GLFW backend. Tested so far on macOS and Linux. It has been developed by Robert Ennis in the lab of Katja Doerschner, a part of the Allgemeine Psychologie Department at the Justus-Liebig Universitaet of Giessen.
Documentation
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]));
// }
// }