<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLfloat,
    GLint,
    GLsizei,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            Gl {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba;
        // xy makes two floats.
        let size_vertices: i32 = 2;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_vertices = gl::FALSE;
        // The data is tightly packed.
        let stride_vertices = 0;
        gl::BindBuffer(
            gl::ARRAY_BUFFER,   // buffer type
            self.position_id    // position buffer for xy coordinates
        );
        unsafe {
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_colors = 4;
        let normalize_colors = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_colors,
                gl::FLOAT,
                normalize_colors,
                stride_fill_colors,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba_uv;
        let size_vertices: i32 = 2;
        let normalize_vertices = gl::FALSE;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_vertices = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, self.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_color = 4;
        let normalize_fill_color = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_color,
                gl::FLOAT,
                normalize_fill_color,
                stride_fill_colors,
                ptr::null()
            );
        }

        // uv makes two floats.
        let size_tex_coord = 2;
        let texture_coords_byte_len = (
                texture_coords.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_texture_coords = gl::FALSE;
        // The data is tightly packed.
        let stride_texture_coords = 0;
        gl::EnableVertexAttribArray(shader.a_v2TexCoord as GLuint);
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.tex_coord_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                texture_coords_byte_len,
                mem::transmute(&texture_coords[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint,
                size_tex_coord,
                gl::FLOAT,
                normalize_texture_coords,
                stride_texture_coords,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        gl::DisableVertexAttribArray(shader.a_v2TexCoord as GLuint);
    }
}

<commit_msg>Fix combining filled shapes and textures<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLfloat,
    GLint,
    GLsizei,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }

    fn enable_attributes(&self) {
        gl::EnableVertexAttribArray(self.a_v4Position as GLuint);
        gl::EnableVertexAttribArray(self.a_v4FillColor as GLuint);
    }

    fn disable_attributes(&self) {
        gl::DisableVertexAttribArray(self.a_v4Position as GLuint);
        gl::DisableVertexAttribArray(self.a_v4FillColor as GLuint);
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }

    fn enable_attributes(&self) {
        gl::EnableVertexAttribArray(self.a_v4Position as GLuint);
        gl::EnableVertexAttribArray(self.a_v4FillColor as GLuint);
        gl::EnableVertexAttribArray(self.a_v2TexCoord as GLuint);
    }

    fn disable_attributes(&self) {
        gl::DisableVertexAttribArray(self.a_v4Position as GLuint);
        gl::DisableVertexAttribArray(self.a_v4FillColor as GLuint);
        gl::DisableVertexAttribArray(self.a_v2TexCoord as GLuint);
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            Gl {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba;
        shader.enable_attributes();

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_vertices = gl::FALSE;
        // The data is tightly packed.
        let stride_vertices = 0;
        gl::BindBuffer(
            gl::ARRAY_BUFFER,   // buffer type
            self.position_id    // position buffer for xy coordinates
        );
        unsafe {
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_colors = 4;
        let normalize_colors = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_colors,
                gl::FLOAT,
                normalize_colors,
                stride_fill_colors,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        shader.disable_attributes();
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba_uv;
        shader.enable_attributes();

        let size_vertices: i32 = 2;
        let normalize_vertices = gl::FALSE;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_vertices = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, self.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_color = 4;
        let normalize_fill_color = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_color,
                gl::FLOAT,
                normalize_fill_color,
                stride_fill_colors,
                ptr::null()
            );
        }

        // uv makes two floats.
        let size_tex_coord = 2;
        let texture_coords_byte_len = (
                texture_coords.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_texture_coords = gl::FALSE;
        // The data is tightly packed.
        let stride_texture_coords = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.tex_coord_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                texture_coords_byte_len,
                mem::transmute(&texture_coords[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint,
                size_tex_coord,
                gl::FLOAT,
                normalize_texture_coords,
                stride_texture_coords,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        shader.disable_attributes();
    }
}

<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLfloat,
    GLint,
    GLsizei,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }

    fn enable_attributes(&self) {
        gl::EnableVertexAttribArray(self.a_v4Position as GLuint);
        gl::EnableVertexAttribArray(self.a_v4FillColor as GLuint);
    }

    fn disable_attributes(&self) {
        gl::DisableVertexAttribArray(self.a_v4Position as GLuint);
        gl::DisableVertexAttribArray(self.a_v4FillColor as GLuint);
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }

    fn enable_attributes(&self) {
        gl::EnableVertexAttribArray(self.a_v4Position as GLuint);
        gl::EnableVertexAttribArray(self.a_v4FillColor as GLuint);
        gl::EnableVertexAttribArray(self.a_v2TexCoord as GLuint);
    }

    fn disable_attributes(&self) {
        gl::DisableVertexAttribArray(self.a_v4Position as GLuint);
        gl::DisableVertexAttribArray(self.a_v4FillColor as GLuint);
        gl::DisableVertexAttribArray(self.a_v2TexCoord as GLuint);
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            Gl {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba;
        shader.enable_attributes();

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_vertices = gl::FALSE;
        // The data is tightly packed.
        let stride_vertices = 0;
        gl::BindBuffer(
            gl::ARRAY_BUFFER,   // buffer type
            self.position_id    // position buffer for xy coordinates
        );
        unsafe {
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_colors = 4;
        let normalize_colors = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_colors,
                gl::FLOAT,
                normalize_colors,
                stride_fill_colors,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        shader.disable_attributes();
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba_uv;
        shader.enable_attributes();

        let size_vertices: i32 = 2;
        let normalize_vertices = gl::FALSE;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_vertices = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, self.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_color = 4;
        let normalize_fill_color = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_color,
                gl::FLOAT,
                normalize_fill_color,
                stride_fill_colors,
                ptr::null()
            );
        }

        // uv makes two floats.
        let size_tex_coord = 2;
        let texture_coords_byte_len = (
                texture_coords.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_texture_coords = gl::FALSE;
        // The data is tightly packed.
        let stride_texture_coords = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.tex_coord_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                texture_coords_byte_len,
                mem::transmute(&texture_coords[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint,
                size_tex_coord,
                gl::FLOAT,
                normalize_texture_coords,
                stride_texture_coords,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        shader.disable_attributes();
    }
}

<commit_msg>Upgraded shaders to OpenGL 3.3<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use graphics::BackEnd;
use gl;
use gl::types::{
    GLfloat,
    GLint,
    GLsizei,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};

// Local crate.
use Texture;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
in vec4 a_v4Position;
in vec4 a_v4FillColor;

out vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
#version 330
out vec4 out_color;
in vec4 v_v4FillColor;

void main()
{
    out_color = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
in vec4 a_v4Position;
in vec4 a_v4FillColor;
in vec2 a_v2TexCoord;

uniform sampler2D s_texture;

out vec2 v_v2TexCoord;
out vec4 v_v4FillColor;

void main()
{
    v_v2TexCoord = a_v2TexCoord;
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
#version 330
out vec4 out_color;

uniform sampler2D s_texture;

in vec2 v_v2TexCoord;
in vec4 v_v4FillColor;

void main()
{
    out_color = texture(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl Drop for TriListXYRGBA {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA      // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA    // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }

    fn enable_attributes(&self) {
        gl::EnableVertexAttribArray(self.a_v4Position as GLuint);
        gl::EnableVertexAttribArray(self.a_v4FillColor as GLuint);
    }

    fn disable_attributes(&self) {
        gl::DisableVertexAttribArray(self.a_v4Position as GLuint);
        gl::DisableVertexAttribArray(self.a_v4FillColor as GLuint);
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl Drop for TriListXYRGBAUV {
    fn drop(&mut self) {
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.vertex_shader);
        gl::DeleteShader(self.fragment_shader);
    }
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            VERTEX_SHADER_TRI_LIST_XY_RGBA_UV   // shader type
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV // shader source
        ) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            let a_v4FillColor = "a_v4FillColor".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(
                |ptr| gl::GetAttribLocation(program, ptr)
            );

            "out_color".with_c_str(
                |ptr| gl::BindFragDataLocation(program, 0, ptr)
            );

            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }

    fn enable_attributes(&self) {
        gl::EnableVertexAttribArray(self.a_v4Position as GLuint);
        gl::EnableVertexAttribArray(self.a_v4FillColor as GLuint);
        gl::EnableVertexAttribArray(self.a_v2TexCoord as GLuint);
    }

    fn disable_attributes(&self) {
        gl::DisableVertexAttribArray(self.a_v4Position as GLuint);
        gl::DisableVertexAttribArray(self.a_v4FillColor as GLuint);
        gl::DisableVertexAttribArray(self.a_v2TexCoord as GLuint);
    }
}

/// Contains OpenGL data.
pub struct Gl {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> Gl {
    /// Creates a new OpenGl back-end.
    pub fn new() -> Gl {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            Gl {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl BackEnd<Texture> for Gl {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture: &Texture) {
        let texture = texture.get_id();
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba;
        shader.enable_attributes();

        // xy makes two floats.
        let size_vertices: i32 = 2;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_vertices = gl::FALSE;
        // The data is tightly packed.
        let stride_vertices = 0;
        gl::BindBuffer(
            gl::ARRAY_BUFFER,   // buffer type
            self.position_id    // position buffer for xy coordinates
        );
        unsafe {
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_colors = 4;
        let normalize_colors = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_colors,
                gl::FLOAT,
                normalize_colors,
                stride_fill_colors,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
        shader.disable_attributes();
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.tri_list_xy_rgba_uv.program;
            self.use_program(shader_program);
        }
        let shader = &self.tri_list_xy_rgba_uv;
        shader.enable_attributes();

        let size_vertices: i32 = 2;
        let normalize_vertices = gl::FALSE;
        let vertices_byte_len = (
                vertices.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_vertices = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, self.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertices_byte_len,
                mem::transmute(&vertices[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint,
                size_vertices,
                gl::FLOAT,
                normalize_vertices,
                stride_vertices,
                ptr::null()
            );
        }

        // rgba makes 4 floats.
        let size_fill_color = 4;
        let normalize_fill_color = gl::FALSE;
        let fill_colors_byte_len = (
                colors.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        // The data is tightly packed.
        let stride_fill_colors = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.fill_color_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                fill_colors_byte_len,
                mem::transmute(&colors[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint,
                size_fill_color,
                gl::FLOAT,
                normalize_fill_color,
                stride_fill_colors,
                ptr::null()
            );
        }

        // uv makes two floats.
        let size_tex_coord = 2;
        let texture_coords_byte_len = (
                texture_coords.len() * mem::size_of::<GLfloat>()
            ) as GLsizeiptr;
        let normalize_texture_coords = gl::FALSE;
        // The data is tightly packed.
        let stride_texture_coords = 0;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER,
                self.tex_coord_id
            );
            gl::BufferData(
                gl::ARRAY_BUFFER,
                texture_coords_byte_len,
                mem::transmute(&texture_coords[0]),
                gl::DYNAMIC_DRAW
            );
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint,
                size_tex_coord,
                gl::FLOAT,
                normalize_texture_coords,
                stride_texture_coords,
                ptr::null()
            );
        }

        // Render triangles whether they are facing
        // clockwise or counter clockwise.
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);

        // TEST
        // println!("{}", gl::GetError());

        shader.disable_attributes();
    }
}

<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use nalgebra::{Mat3, Mat4, Vec3, Pnt3};
use nalgebra;
use std::mem;
use std::num::FloatMath;
use yaglw::gl_context::GLContext;
use yaglw::shader::Shader;

pub struct Camera {
  // projection matrix components
  pub translation: Mat4<GLfloat>,
  pub rotation: Mat4<GLfloat>,
  pub fov: Mat4<GLfloat>,
  pub position: Pnt3<GLfloat>,
}

/// Create a 3D translation matrix.
pub fn translation(t: Vec3<GLfloat>) -> Mat4<GLfloat> {
  Mat4 {
    m11: 1.0, m12: 0.0, m13: 0.0, m14: t.x,
    m21: 0.0, m22: 1.0, m23: 0.0, m24: t.y,
    m31: 0.0, m32: 0.0, m33: 1.0, m34: t.z,
    m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0,
  }
}

pub fn from_axis_angle3(axis: Vec3<GLfloat>, angle: GLfloat) -> Mat3<GLfloat> {
  let (s, c) = angle.sin_cos();
  let Vec3 { x: xs, y: ys, z: zs } = axis * s;
  let vsub1c = axis * (1.0 - c);
  nalgebra::outer(&vsub1c, &vsub1c) +
    Mat3 {
      m11: c,   m12: -zs, m13: ys,
      m21: zs,  m22: c,   m23: -xs,
      m31: -ys, m32: xs,  m33: c,
    }
}

/// Create a matrix from a rotation around an arbitrary axis.
pub fn from_axis_angle4(axis: Vec3<GLfloat>, angle: GLfloat) -> Mat4<GLfloat> {
  let (s, c) = angle.sin_cos();
  let sub1c = 1.0 - c;
  let Vec3 { x: xs, y: ys, z: zs } = axis * s;
  let (x, y, z) = (axis.x, axis.y, axis.z);
  Mat4 {
    m11: x*x*sub1c + c,  m12: x*y*sub1c - zs, m13: x*z*sub1c + ys, m14: 0.0,
    m21: y*x*sub1c + zs, m22: y*y*sub1c + c,  m23: y*z*sub1c - xs, m24: 0.0,
    m31: z*x*sub1c - ys, m32: z*y*sub1c + xs, m33: z*z*sub1c + c,  m34: 0.0,
    m41: 0.0,            m42: 0.0,            m43: 0.0,            m44: 1.0,
  }
}

/// Create a 3D perspective initialization matrix.
pub fn perspective(fovy: GLfloat, aspect: GLfloat, near: GLfloat, far: GLfloat) -> Mat4<GLfloat> {
  Mat4 {
    m11: fovy / aspect, m12: 0.0,   m13: 0.0,                         m14: 0.0,
    m21: 0.0,           m22: fovy,  m23: 0.0,                         m24: 0.0,
    m31: 0.0,           m32: 0.0,   m33: (near + far) / (near - far), m34: 2.0 * near * far / (near - far),
    m41: 0.0,           m42: 0.0,   m43: -1.0,                        m44: 0.0,
  }
}

#[allow(dead_code)]
pub fn ortho(left: GLfloat, right: GLfloat, bottom: GLfloat, top: GLfloat, near: GLfloat, far: GLfloat) -> Mat4<GLfloat> {
  Mat4 {
    m11: 2.0 / (right - left),  m12: 0.0,                   m13: 0.0,                 m14: (left + right) / (left - right),
    m21: 0.0,                   m22: 2.0 / (top - bottom),  m23: 0.0,                 m24: (bottom + top) / (bottom - top),
    m31: 0.0,                   m32: 0.0,                   m33: 2.0 / (near - far),  m34: (near + far) / (near - far),
    m41: 0.0,                   m42: 0.0,                   m43: 0.0,                 m44: 1.0,
  }
}

/// Create a XY symmetric ortho matrix.
pub fn sortho(dx: GLfloat, dy: GLfloat, near: GLfloat, far: GLfloat) -> Mat4<GLfloat> {
  Mat4 {
    m11: 1.0 / dx,  m12: 0.0,       m13: 0.0,                 m14: 0.0,
    m21: 0.0,       m22: 1.0 / dy,  m23: 0.0,                 m24: 0.0,
    m31: 0.0,       m32: 0.0,       m33: 2.0 / (near - far),  m34: (near + far) / (near - far),
    m41: 0.0,       m42: 0.0,       m43: 0.0,                 m44: 1.0,
  }
}

impl Camera {
  /// this Camera sits at (0, 0, 0),
  /// maps [-1, 1] in x horizontally,
  /// maps [-1, 1] in y vertically,
  /// and [0, -1] in z in depth.
  pub fn unit() -> Camera {
    Camera {
      translation: nalgebra::new_identity(4),
      rotation: nalgebra::new_identity(4),
      fov: nalgebra::new_identity(4),
      position: Pnt3::new(0.0, 0.0, 0.0),
    }
  }

  pub fn projection_matrix(&self) -> Mat4<GLfloat> {
    self.fov * self.rotation * self.translation
  }

  /// Shift the camera by a vector.
  pub fn translate(&mut self, v: Vec3<GLfloat>) {
    self.translation = self.translation * translation(-v);
    self.position = self.position + v;
  }

  /// Rotate about a given vector, by `r` radians.
  pub fn rotate(&mut self, v: Vec3<GLfloat>, r: GLfloat) {
    self.rotation = self.rotation * from_axis_angle4(v, -r);
  }
}

pub fn set_camera(shader: &mut Shader, gl: &mut GLContext, c: &Camera) {
  let projection_matrix = shader.get_uniform_location("projection_matrix");
  shader.use_shader(gl);
  unsafe {
    let ptr = mem::transmute(&c.projection_matrix());
    gl::UniformMatrix4fv(projection_matrix, 1, 0, ptr);
  }
}
<commit_msg>fix pointer lifetime issue in camera::set_camera<commit_after>use gl;
use gl::types::*;
use nalgebra::{Mat3, Mat4, Vec3, Pnt3};
use nalgebra;
use std::mem;
use std::num::FloatMath;
use yaglw::gl_context::GLContext;
use yaglw::shader::Shader;

pub struct Camera {
  // projection matrix components
  pub translation: Mat4<GLfloat>,
  pub rotation: Mat4<GLfloat>,
  pub fov: Mat4<GLfloat>,
  pub position: Pnt3<GLfloat>,
}

/// Create a 3D translation matrix.
pub fn translation(t: Vec3<GLfloat>) -> Mat4<GLfloat> {
  Mat4 {
    m11: 1.0, m12: 0.0, m13: 0.0, m14: t.x,
    m21: 0.0, m22: 1.0, m23: 0.0, m24: t.y,
    m31: 0.0, m32: 0.0, m33: 1.0, m34: t.z,
    m41: 0.0, m42: 0.0, m43: 0.0, m44: 1.0,
  }
}

pub fn from_axis_angle3(axis: Vec3<GLfloat>, angle: GLfloat) -> Mat3<GLfloat> {
  let (s, c) = angle.sin_cos();
  let Vec3 { x: xs, y: ys, z: zs } = axis * s;
  let vsub1c = axis * (1.0 - c);
  nalgebra::outer(&vsub1c, &vsub1c) +
    Mat3 {
      m11: c,   m12: -zs, m13: ys,
      m21: zs,  m22: c,   m23: -xs,
      m31: -ys, m32: xs,  m33: c,
    }
}

/// Create a matrix from a rotation around an arbitrary axis.
pub fn from_axis_angle4(axis: Vec3<GLfloat>, angle: GLfloat) -> Mat4<GLfloat> {
  let (s, c) = angle.sin_cos();
  let sub1c = 1.0 - c;
  let Vec3 { x: xs, y: ys, z: zs } = axis * s;
  let (x, y, z) = (axis.x, axis.y, axis.z);
  Mat4 {
    m11: x*x*sub1c + c,  m12: x*y*sub1c - zs, m13: x*z*sub1c + ys, m14: 0.0,
    m21: y*x*sub1c + zs, m22: y*y*sub1c + c,  m23: y*z*sub1c - xs, m24: 0.0,
    m31: z*x*sub1c - ys, m32: z*y*sub1c + xs, m33: z*z*sub1c + c,  m34: 0.0,
    m41: 0.0,            m42: 0.0,            m43: 0.0,            m44: 1.0,
  }
}

/// Create a 3D perspective initialization matrix.
pub fn perspective(fovy: GLfloat, aspect: GLfloat, near: GLfloat, far: GLfloat) -> Mat4<GLfloat> {
  Mat4 {
    m11: fovy / aspect, m12: 0.0,   m13: 0.0,                         m14: 0.0,
    m21: 0.0,           m22: fovy,  m23: 0.0,                         m24: 0.0,
    m31: 0.0,           m32: 0.0,   m33: (near + far) / (near - far), m34: 2.0 * near * far / (near - far),
    m41: 0.0,           m42: 0.0,   m43: -1.0,                        m44: 0.0,
  }
}

#[allow(dead_code)]
pub fn ortho(left: GLfloat, right: GLfloat, bottom: GLfloat, top: GLfloat, near: GLfloat, far: GLfloat) -> Mat4<GLfloat> {
  Mat4 {
    m11: 2.0 / (right - left),  m12: 0.0,                   m13: 0.0,                 m14: (left + right) / (left - right),
    m21: 0.0,                   m22: 2.0 / (top - bottom),  m23: 0.0,                 m24: (bottom + top) / (bottom - top),
    m31: 0.0,                   m32: 0.0,                   m33: 2.0 / (near - far),  m34: (near + far) / (near - far),
    m41: 0.0,                   m42: 0.0,                   m43: 0.0,                 m44: 1.0,
  }
}

/// Create a XY symmetric ortho matrix.
pub fn sortho(dx: GLfloat, dy: GLfloat, near: GLfloat, far: GLfloat) -> Mat4<GLfloat> {
  Mat4 {
    m11: 1.0 / dx,  m12: 0.0,       m13: 0.0,                 m14: 0.0,
    m21: 0.0,       m22: 1.0 / dy,  m23: 0.0,                 m24: 0.0,
    m31: 0.0,       m32: 0.0,       m33: 2.0 / (near - far),  m34: (near + far) / (near - far),
    m41: 0.0,       m42: 0.0,       m43: 0.0,                 m44: 1.0,
  }
}

impl Camera {
  /// this Camera sits at (0, 0, 0),
  /// maps [-1, 1] in x horizontally,
  /// maps [-1, 1] in y vertically,
  /// and [0, -1] in z in depth.
  pub fn unit() -> Camera {
    Camera {
      translation: nalgebra::new_identity(4),
      rotation: nalgebra::new_identity(4),
      fov: nalgebra::new_identity(4),
      position: Pnt3::new(0.0, 0.0, 0.0),
    }
  }

  pub fn projection_matrix(&self) -> Mat4<GLfloat> {
    self.fov * self.rotation * self.translation
  }

  /// Shift the camera by a vector.
  pub fn translate(&mut self, v: Vec3<GLfloat>) {
    self.translation = self.translation * translation(-v);
    self.position = self.position + v;
  }

  /// Rotate about a given vector, by `r` radians.
  pub fn rotate(&mut self, v: Vec3<GLfloat>, r: GLfloat) {
    self.rotation = self.rotation * from_axis_angle4(v, -r);
  }
}

pub fn set_camera(shader: &mut Shader, gl: &mut GLContext, c: &Camera) {
  let projection_matrix = shader.get_uniform_location("projection_matrix");
  shader.use_shader(gl);
  unsafe {
    let val = c.projection_matrix();
    let ptr = mem::transmute(&val);
    gl::UniformMatrix4fv(projection_matrix, 1, 0, ptr);
  }
}
<|endoftext|>


<commit_before>extern crate curl;

use std::str;
use curl::http;

#[derive(Copy)]
pub struct Client;

impl Client {
    pub fn request(self, url: &str) -> String {
        let res = http::handle()
            .get(url)
            .header("User-Agent", "Rust-Github-Client")
            .exec().unwrap();

        let body = match str::from_utf8(res.get_body()) {
            Ok(b) => b,
            Err(..) => "Unable to parse"
        };

        return body.to_string();
    }
}
<commit_msg>Implementing Clone and Copy too<commit_after>extern crate curl;

use std::str;
use curl::http;

#[derive(Copy,Clone)]
pub struct Client;

impl Client {
    pub fn request(self, url: &str) -> String {
        let res = http::handle()
            .get(url)
            .header("User-Agent", "Rust-Github-Client")
            .exec().unwrap();

        let body = match str::from_utf8(res.get_body()) {
            Ok(b) => b,
            Err(..) => "Unable to parse"
        };

        return body.to_string();
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSContext, JSObject, JSPropertyDescriptor, JSBool};

pub type JSJitPropertyOp = *const u8;

pub struct JSJitInfo {
    pub op: JSJitPropertyOp,
    pub protoID: u32,
    pub depth: u32,
    pub isInfallible: bool,
    pub isConstant: bool
}

extern {
pub fn JS_ObjectToOuterObject(cx: *mut JSContext,
                              obj: *mut JSObject) -> *mut JSObject;
pub fn JS_WrapPropertyDescriptor(cx: *mut JSContext,
                                 desc: *mut JSPropertyDescriptor) -> JSBool;
}

//pub type JSJitInfo = JSJitInfo_struct;

pub mod bindgen {
    use jsapi::{JSContext, JSObject, JSClass, JSRuntime};
    use libc::{uintptr_t, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, c_float, c_double};

    extern {
        pub fn JS_NewObjectWithUniqueType(cx: *mut JSContext, clasp: *const JSClass,
                                          proto: *const JSObject, parent: *const JSObject) -> *mut JSObject;
        pub fn JS_GetAddressableObject(rt: *mut JSRuntime, candidateObj: uintptr_t) -> *mut JSObject;

        pub fn JS_NewInt8Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetInt8ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut int8_t;

        pub fn JS_NewUint8Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint8ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint8_t;

        pub fn JS_NewUint8ClampedArray(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint8ClampedArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint8_t;

        pub fn JS_NewInt16Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetInt16ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut int16_t;

        pub fn JS_NewUint16Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint16ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint16_t;

        pub fn JS_NewInt32Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetInt32ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut int32_t;

        pub fn JS_NewUint32Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint32ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint32_t;

        pub fn JS_NewFloat32Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetFloat32ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut c_float;

        pub fn JS_NewFloat64Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetFloat64ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut c_double;
    }
}
<commit_msg>Declare JS_GetObjectAsArrayBufferView.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSContext, JSObject, JSPropertyDescriptor, JSBool};

pub type JSJitPropertyOp = *const u8;

pub struct JSJitInfo {
    pub op: JSJitPropertyOp,
    pub protoID: u32,
    pub depth: u32,
    pub isInfallible: bool,
    pub isConstant: bool
}

extern {
pub fn JS_ObjectToOuterObject(cx: *mut JSContext,
                              obj: *mut JSObject) -> *mut JSObject;
pub fn JS_WrapPropertyDescriptor(cx: *mut JSContext,
                                 desc: *mut JSPropertyDescriptor) -> JSBool;
}

//pub type JSJitInfo = JSJitInfo_struct;

pub mod bindgen {
    use jsapi::{JSContext, JSObject, JSClass, JSRuntime};
    use libc::{uintptr_t, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, c_float, c_double};

    extern {
        pub fn JS_NewObjectWithUniqueType(cx: *mut JSContext, clasp: *const JSClass,
                                          proto: *const JSObject, parent: *const JSObject) -> *mut JSObject;
        pub fn JS_GetAddressableObject(rt: *mut JSRuntime, candidateObj: uintptr_t) -> *mut JSObject;

        pub fn JS_NewInt8Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetInt8ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut int8_t;

        pub fn JS_NewUint8Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint8ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint8_t;

        pub fn JS_NewUint8ClampedArray(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint8ClampedArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint8_t;

        pub fn JS_NewInt16Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetInt16ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut int16_t;

        pub fn JS_NewUint16Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint16ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint16_t;

        pub fn JS_NewInt32Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetInt32ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut int32_t;

        pub fn JS_NewUint32Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetUint32ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut uint32_t;

        pub fn JS_NewFloat32Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetFloat32ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut c_float;

        pub fn JS_NewFloat64Array(cx: *mut JSContext, nelements: uint32_t) -> *mut JSObject;
        pub fn JS_GetFloat64ArrayData(obj: *mut JSObject, cx: *mut JSContext) -> *mut c_double;

        pub fn JS_GetObjectAsArrayBufferView(cx: *mut JSContext,
                                             obj: *mut JSObject,
                                             length: *mut uint32_t,
                                             data: *mut *mut uint8_t)
                                             -> *mut JSObject;
    }
}
<|endoftext|>


<commit_before>#![allow(missing_docs)]
#![unstable(feature = "raw", issue = "27751")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in
//! `rustc_middle::ty::layout`.

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<dyn AnotherTrait>`.
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g., the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SomeTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// [`std::mem::transmute`][transmute]. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// [transmute]: ../intrinsics/fn.transmute.html
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behavior.
///
/// # Examples
///
/// ```
/// #![feature(raw)]
///
/// use std::{mem, raw};
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
///
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &dyn Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &dyn Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable,
///      })
/// };
///
/// // it should work just as if we had constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}
<commit_msg>Rollup merge of #72532 - ratijas:dyn-trait-object-doc, r=jonas-schievink<commit_after>#![allow(missing_docs)]
#![unstable(feature = "raw", issue = "27751")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in
//! `rustc_middle::ty::layout`.

/// The representation of a trait object like `&dyn SomeTrait`.
///
/// This struct has the same layout as types like `&dyn SomeTrait` and
/// `Box<dyn AnotherTrait>`.
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g., the fields are not directly accessible
/// on a `&dyn SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&dyn SomeTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// [`std::mem::transmute`][transmute]. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// [transmute]: ../intrinsics/fn.transmute.html
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behavior.
///
/// # Examples
///
/// ```
/// #![feature(raw)]
///
/// use std::{mem, raw};
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
///
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &dyn Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &dyn Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable,
///      })
/// };
///
/// // it should work just as if we had constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}
<|endoftext|>


<commit_before>use crate::time::driver::{Handle, TimerEntry};
use crate::time::{error::Error, Duration, Instant};

use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};

/// Waits until `deadline` is reached.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
pub fn sleep_until(deadline: Instant) -> Sleep {
    Sleep::new_timeout(deadline)
}

/// Waits until `duration` has elapsed.
///
/// Equivalent to `sleep_until(Instant::now() + duration)`. An asynchronous
/// analog to `std::thread::sleep`.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// To run something regularly on a schedule, see [`interval`].
///
/// The maximum duration for a sleep is 68719476734 milliseconds (approximately 2.2 years).
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
///
/// # Examples
///
/// Wait 100ms and print "100 ms have elapsed".
///
/// ```
/// use tokio::time::{sleep, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     sleep(Duration::from_millis(100)).await;
///     println!("100 ms have elapsed");
/// }
/// ```
///
/// [`interval`]: crate::time::interval()
pub fn sleep(duration: Duration) -> Sleep {
    sleep_until(Instant::now() + duration)
}

pin_project! {
    /// Future returned by [`sleep`](sleep) and
    /// [`sleep_until`](sleep_until).
    #[derive(Debug)]
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct Sleep {
        deadline: Instant,

        // The link between the `Sleep` instance and the timer that drives it.
        #[pin]
        entry: TimerEntry,
    }
}

impl Sleep {
    pub(crate) fn new_timeout(deadline: Instant) -> Sleep {
        let handle = Handle::current();
        let entry = TimerEntry::new(&handle, deadline);

        Sleep { deadline, entry }
    }

    /// Returns the instant at which the future will complete.
    pub fn deadline(&self) -> Instant {
        self.deadline
    }

    /// Returns `true` if `Sleep` has elapsed.
    ///
    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
    pub fn is_elapsed(&self) -> bool {
        self.entry.is_elapsed()
    }

    /// Resets the `Sleep` instance to a new deadline.
    ///
    /// Calling this function allows changing the instant at which the `Sleep`
    /// future completes without having to create new associated state.
    ///
    /// This function can be called both before and after the future has
    /// completed.
    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {
        let me = self.project();
        me.entry.reset(deadline);
        *me.deadline = deadline;
    }

    fn poll_elapsed(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<(), Error>> {
        let me = self.project();

        // Keep track of task budget
        let coop = ready!(crate::coop::poll_proceed(cx));

        me.entry.poll_elapsed(cx).map(move |r| {
            coop.made_progress();
            r
        })
    }
}

impl Future for Sleep {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        // `poll_elapsed` can return an error in two cases:
        //
        // - AtCapacity: this is a pathological case where far too many
        //   sleep instances have been scheduled.
        // - Shutdown: No timer has been setup, which is a mis-use error.
        //
        // Both cases are extremely rare, and pretty accurately fit into
        // "logic errors", so we just panic in this case. A user couldn't
        // really do much better if we passed the error onwards.
        match ready!(self.as_mut().poll_elapsed(cx)) {
            Ok(()) => Poll::Ready(()),
            Err(e) => panic!("timer error: {}", e),
        }
    }
}
<commit_msg>time: document that Sleep is not Unpin (#3457)<commit_after>use crate::time::driver::{Handle, TimerEntry};
use crate::time::{error::Error, Duration, Instant};

use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};

/// Waits until `deadline` is reached.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
pub fn sleep_until(deadline: Instant) -> Sleep {
    Sleep::new_timeout(deadline)
}

/// Waits until `duration` has elapsed.
///
/// Equivalent to `sleep_until(Instant::now() + duration)`. An asynchronous
/// analog to `std::thread::sleep`.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// To run something regularly on a schedule, see [`interval`].
///
/// The maximum duration for a sleep is 68719476734 milliseconds (approximately 2.2 years).
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
///
/// # Examples
///
/// Wait 100ms and print "100 ms have elapsed".
///
/// ```
/// use tokio::time::{sleep, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     sleep(Duration::from_millis(100)).await;
///     println!("100 ms have elapsed");
/// }
/// ```
///
/// [`interval`]: crate::time::interval()
pub fn sleep(duration: Duration) -> Sleep {
    sleep_until(Instant::now() + duration)
}

pin_project! {
    /// Future returned by [`sleep`](sleep) and [`sleep_until`](sleep_until).
    ///
    /// This type does not implement the `Unpin` trait, which means that if you
    /// use it with [`select!`] or by calling `poll`, you have to pin it first.
    /// If you use it with `.await`, this does not apply.
    ///
    /// # Examples
    ///
    /// Wait 100ms and print "100 ms have elapsed".
    ///
    /// ```
    /// use tokio::time::{sleep, Duration};
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     sleep(Duration::from_millis(100)).await;
    ///     println!("100 ms have elapsed");
    /// }
    /// ```
    ///
    /// Use with [`select!`]. Pinning the `Sleep` with [`tokio::pin!`] is
    /// necessary when the same `Sleep` is selected on multiple times.
    /// ```no_run
    /// use tokio::time::{self, Duration, Instant};
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let sleep = time::sleep(Duration::from_millis(10));
    ///     tokio::pin!(sleep);
    ///
    ///     loop {
    ///         tokio::select! {
    ///             () = &mut sleep => {
    ///                 println!("timer elapsed");
    ///                 sleep.as_mut().reset(Instant::now() + Duration::from_millis(50));
    ///             },
    ///         }
    ///     }
    /// }
    /// ```
    /// Use in a struct with boxing. By pinning the `Sleep` with a `Box`, the
    /// `HasSleep` struct implements `Unpin`, even though `Sleep` does not.
    /// ```
    /// use std::future::Future;
    /// use std::pin::Pin;
    /// use std::task::{Context, Poll};
    /// use tokio::time::Sleep;
    ///
    /// struct HasSleep {
    ///     sleep: Pin<Box<Sleep>>,
    /// }
    ///
    /// impl Future for HasSleep {
    ///     type Output = ();
    ///
    ///     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
    ///         self.sleep.as_mut().poll(cx)
    ///     }
    /// }
    /// ```
    /// Use in a struct with pin projection. This method avoids the `Box`, but
    /// the `HasSleep` struct will not be `Unpin` as a consequence.
    /// ```
    /// use std::future::Future;
    /// use std::pin::Pin;
    /// use std::task::{Context, Poll};
    /// use tokio::time::Sleep;
    /// use pin_project_lite::pin_project;
    ///
    /// pin_project! {
    ///     struct HasSleep {
    ///         #[pin]
    ///         sleep: Sleep,
    ///     }
    /// }
    ///
    /// impl Future for HasSleep {
    ///     type Output = ();
    ///
    ///     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
    ///         self.project().sleep.poll(cx)
    ///     }
    /// }
    /// ```
    ///
    /// [`select!`]: ../macro.select.html
    /// [`tokio::pin!`]: ../macro.pin.html
    #[derive(Debug)]
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct Sleep {
        deadline: Instant,

        // The link between the `Sleep` instance and the timer that drives it.
        #[pin]
        entry: TimerEntry,
    }
}

impl Sleep {
    pub(crate) fn new_timeout(deadline: Instant) -> Sleep {
        let handle = Handle::current();
        let entry = TimerEntry::new(&handle, deadline);

        Sleep { deadline, entry }
    }

    /// Returns the instant at which the future will complete.
    pub fn deadline(&self) -> Instant {
        self.deadline
    }

    /// Returns `true` if `Sleep` has elapsed.
    ///
    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
    pub fn is_elapsed(&self) -> bool {
        self.entry.is_elapsed()
    }

    /// Resets the `Sleep` instance to a new deadline.
    ///
    /// Calling this function allows changing the instant at which the `Sleep`
    /// future completes without having to create new associated state.
    ///
    /// This function can be called both before and after the future has
    /// completed.
    ///
    /// To call this method, you will usually combine the call with
    /// [`Pin::as_mut`], which lets you call the method with consuming the
    /// `Sleep` itself.
    ///
    /// # Example
    ///
    /// ```
    /// use tokio::time::{Duration, Instant};
    ///
    /// # #[tokio::main(flavor = "current_thread")]
    /// # async fn main() {
    /// let sleep = tokio::time::sleep(Duration::from_millis(10));
    /// tokio::pin!(sleep);
    ///
    /// sleep.as_mut().reset(Instant::now() + Duration::from_millis(20));
    /// # }
    /// ```
    ///
    /// [`Pin::as_mut`]: fn@std::pin::Pin::as_mut
    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {
        let me = self.project();
        me.entry.reset(deadline);
        *me.deadline = deadline;
    }

    fn poll_elapsed(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<(), Error>> {
        let me = self.project();

        // Keep track of task budget
        let coop = ready!(crate::coop::poll_proceed(cx));

        me.entry.poll_elapsed(cx).map(move |r| {
            coop.made_progress();
            r
        })
    }
}

impl Future for Sleep {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        // `poll_elapsed` can return an error in two cases:
        //
        // - AtCapacity: this is a pathological case where far too many
        //   sleep instances have been scheduled.
        // - Shutdown: No timer has been setup, which is a mis-use error.
        //
        // Both cases are extremely rare, and pretty accurately fit into
        // "logic errors", so we just panic in this case. A user couldn't
        // really do much better if we passed the error onwards.
        match ready!(self.as_mut().poll_elapsed(cx)) {
            Ok(()) => Poll::Ready(()),
            Err(e) => panic!("timer error: {}", e),
        }
    }
}
<|endoftext|>