<commit_before>// Copyright 2013 Torste Aikio and gl-rs developers.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[feature(globs)];
#[feature(macro_rules)];

extern mod glfw;
extern mod gl;

use std::libc;

use std::cast;
use std::ptr;
use std::str;
use std::sys;
use std::vec;

use std::io;
use std::path;

use gl::types::*;

// COMPONENT DEFINITIONS
struct Position {
    x: f64,
    y: f64
}

struct HorizVelocity {
    x: f64
}

struct VertVelocity {
    y: f64
}

struct Sprite {
    x_size: f64,
    y_size: f64,
    color: [f64, ..4]
}

struct Components {
    position: Option<@mut Position>,
    horiz_velocity: Option<@mut HorizVelocity>,
    vert_velocity: Option<@mut VertVelocity>,
    sprite: Option<@mut Sprite>
}

// SYSTEM DEFINITIONS
trait System {
    fn process(&self, entity: @Components) -> ();
}

struct MovementSystem;

impl System for MovementSystem {
    fn process(&self, entity: @Components) -> () {
        match entity.position {
            Some(pos) => {
                match entity.vert_velocity {
                    Some(v) => pos.y += v.y,
                    None => ()
                }
                match entity.horiz_velocity {
                    Some(v) => pos.x += v.x,
                    None => ()
                }
            },
            None => ()
        }
    }
}

struct EdgeCollisionSystem;

impl System for EdgeCollisionSystem {
    fn process(&self, entity: @Components) -> () {
        match (entity.position, entity.vert_velocity) {
            (Some(pos), Some(vel)) => {
                if pos.y >= 4.0 || pos.y <= 0.0 {
                    vel.y *= -1.0;
                }
            },
            (_, _) => ()
        }
    }
}

struct PaddleCollisionSystem {
    left_paddle: @Components,
    right_paddle: @Components,
}

impl System for PaddleCollisionSystem {
    fn process(&self, entity: @Components) -> () {
        //TODO use a hitbox or something instead of sprite
        match (entity.position, entity.horiz_velocity, entity.sprite) {
            (Some(pos), Some(vel), Some(spr)) => {
                if (pos.x+(spr.x_size)/2.0) >= (self.right_paddle.position.unwrap().x-(self.right_paddle.sprite.unwrap().x_size)/2.0) {
                    if std::num::abs(pos.y - self.right_paddle.position.unwrap().y) < (self.right_paddle.sprite.unwrap().y_size/2.0) {
                        vel.x *= -1.0;
                    }
                }
                if (pos.x-(spr.x_size)/2.0) <= (self.left_paddle.position.unwrap().x+(self.left_paddle.sprite.unwrap().x_size)/2.0) {
                    if std::num::abs(pos.y - self.left_paddle.position.unwrap().y) < (self.left_paddle.sprite.unwrap().y_size/2.0) {
                        vel.x *= -1.0;
                    }
                }
            },
            (_, _, _) => ()
        }
    }
}

struct RenderSystem {
    program: GLuint,
    fs: GLuint,
    vs: GLuint,
    vbo: GLuint,
    vao: GLuint,
    position_uniform: GLint,
    scale_uniform: GLint,
    color_uniform: GLint,
    window_uniform: GLint
}

impl System for RenderSystem {
    fn process(&self, entity: @Components) -> () {
        match (entity.position, entity.sprite) {
            (Some(pos), Some(sprite)) => {
                // Set uniforms
                gl::ProgramUniform2f(self.program, self.position_uniform, pos.x as f32, pos.y as f32);
                gl::ProgramUniform2f(self.program, self.scale_uniform, sprite.x_size as f32, sprite.y_size as f32);
                gl::ProgramUniform4f(self.program, self.color_uniform, sprite.color[0] as f32, sprite.color[1] as f32, sprite.color[2] as f32, sprite.color[3] as f32);
                // Draw a rect from the 4 vertices
                gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
            },
            (_, _) => ()
        }
    }
}

// WORLD DEFINITION
// We need to figure out how to integrate World with the main game loop
// in Artemis world has a `setDelta` method for timestep
struct World {
    entities: ~[@Components],
    systems: ~[@System]
}

impl World {
    fn new() -> World {
        return World {entities: ~[], systems: ~[]};
    }

    fn process(&self) {
        for system in self.systems.iter() {
            for entity in self.entities.iter() {
                system.process(*entity);
            }
        }
    }
}

//ENTITY CONSTRUCTORS
enum PaddleSide {
    RIGHT,
    LEFT
}

fn new_ball() -> @Components {
    @Components {
        position: Some(@mut Position { x: 2.0, y: 1.5 }),
        horiz_velocity: Some(@mut HorizVelocity { x: 1.0/60.0 }),
        vert_velocity: Some(@mut VertVelocity { y: 0.0 }),
        sprite: Some(@mut Sprite {
            x_size: 0.05,
            y_size: 0.05,
            color: [0.8, 0.7, 0.3, 1.0]
        })
    }
}

fn new_paddle(side: PaddleSide) -> @Components {
    let xpos = match side {
        RIGHT => 3.9,
        LEFT => 0.1
    };
    @Components {
        position: Some(@mut Position { x: xpos, y: 1.5 }),
        horiz_velocity: None,
        vert_velocity: Some(@mut VertVelocity { y: 0.0 }),
        sprite: Some(@mut Sprite {
            x_size: 0.1,
            y_size: 0.4,
            color: [xpos/4.0, 1.0-(xpos/4.0), 0.3, 1.0]
        })
    }
}

fn new_background_2() -> @Components {
    @Components {
        position: Some(@mut Position { x: 2.0, y: 1.5 }),
        horiz_velocity: None,
        vert_velocity: None,
        sprite: Some(@mut Sprite {
            x_size: 3.0,
            y_size: 2.0,
            color: [0.0, 0.0, 0.0, 0.3]
        })
    }
}

fn new_background() -> @Components {
    @Components {
        position: Some(@mut Position { x: 2.0, y: 1.5 }),
        horiz_velocity: None,
        vert_velocity: None,
        sprite: Some(@mut Sprite {
            x_size: 4.0,
            y_size: 3.0,
            color: [0.45, 0.4, 1.0, 1.0]
        })
    }
}

// OPENGL ETC STUFF

// Vertex data
static VERTEX_DATA: [GLfloat, ..8] = [
    -0.5,  0.5,
    -0.5, -0.5,
     0.5,  0.5,
     0.5, -0.5
];

#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint, out_color: &str) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    // gl::BindFragDataLocation needs to be called before linking to have effect
    unsafe {
        out_color.with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));
    }
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    program
}

impl RenderSystem {
    fn new() -> RenderSystem {
        // Create GLSL shaders
        let vs_src = io::read_whole_file_str(&std::path::Path::new("main.vs.glsl")).unwrap();
        let vs = compile_shader(vs_src, gl::VERTEX_SHADER);
        let fs_src = io::read_whole_file_str(&std::path::Path::new("main.fs.glsl")).unwrap();
        let fs = compile_shader(fs_src, gl::FRAGMENT_SHADER);
        let program = link_program(vs, fs, "out_color");

        let mut vao = 0;
        let mut vbo = 0;

        let position_uniform: GLint;
        let scale_uniform: GLint;
        let color_uniform: GLint;
        let window_uniform: GLint;

        unsafe {
            position_uniform = "position".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            scale_uniform = "scale".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            color_uniform = "color".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            window_uniform = "window".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            // Create Vertex Array Object
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl::GenBuffers(1, &mut vbo);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(gl::ARRAY_BUFFER,
                           (VERTEX_DATA.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                           cast::transmute(&VERTEX_DATA[0]),
                           gl::STATIC_DRAW);

            // Use shader program
            gl::UseProgram(program);

            // Specify the layout of the vertex data
            let vert_attr = "vertex".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(vert_attr as GLuint);
            gl::VertexAttribPointer(vert_attr as GLuint, 2, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());
        }
        //enable alpha blending
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        RenderSystem {
            program: program,
            fs: fs,
            vs: vs,
            vbo: vbo,
            vao: vao,
            position_uniform: position_uniform,
            scale_uniform: scale_uniform,
            color_uniform: color_uniform,
            window_uniform: window_uniform
        }
    }
}

impl Drop for RenderSystem {
    fn drop(&mut self) {
        // Cleanup
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.fs);
        gl::DeleteShader(self.vs);
        unsafe {
            gl::DeleteBuffers(1, &self.vbo);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

fn main() {
    do glfw::set_error_callback |_, description| {
        println!("GLFW Error: {}", description);
    }

    do glfw::start {
        // initialize game world
        let left_paddle: @Components = new_paddle(LEFT);
        let right_paddle: @Components = new_paddle(RIGHT);
        let ball: @Components = new_ball();
        let background: @Components = new_background();
        let background_2: @Components = new_background_2();
        let ms = @MovementSystem;
        let es = @EdgeCollisionSystem;
        let ps = @PaddleCollisionSystem{ right_paddle: right_paddle, left_paddle: left_paddle };

        let mut world: World = World::new();
        world.entities.push(background);
        world.entities.push(background_2);
        world.entities.push(left_paddle);
        world.entities.push(right_paddle);
        world.entities.push(ball);
        world.systems.push(ms as @System);
        world.systems.push(es as @System);
        world.systems.push(ps as @System);

        // Choose a GL profile that is compatible with OS X 10.7+
        glfw::window_hint::context_version(3, 2);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::opengl_forward_compat(true);

        let window_width = 800;
        let window_height = 480;
        let window = glfw::Window::create(window_width, window_height, "Pong", glfw::Windowed).unwrap();
        window.set_key_callback(key_callback);
        window.make_context_current();

        // Load the OpenGL function pointers
        gl::load_with(glfw::get_proc_address);

        let rs = @RenderSystem::new();
        gl::ProgramUniform2f(rs.program, rs.window_uniform, window_width as f32, window_height as f32);
        /* // TODO figure out how to make this work
        window.set_framebuffer_size_callback(|_: &glfw::Window, width: int, height: int| {
            gl::ProgramUniform2f(rs.program, rs.window_uniform, width as f32, height as f32);
        });
        */

        world.systems.push(rs as @System);

        while !window.should_close() {
            // Poll events
            glfw::poll_events();

            // Clear the screen
            gl::ClearColor(0.8, 0.8, 0.8, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // process game world
            world.process();

            // Swap buffers
            window.swap_buffers();
        }
    }
}

fn key_callback(window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
    if action == glfw::Press && key == glfw::KeyEscape {
        window.set_should_close(true);
    }
}

<commit_msg>removed unused import<commit_after>// Copyright 2013 Torste Aikio and gl-rs developers.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[feature(globs)];
#[feature(macro_rules)];

extern mod glfw;
extern mod gl;

use std::libc;

use std::cast;
use std::ptr;
use std::str;
use std::sys;
use std::vec;

use std::io;

use gl::types::*;

// COMPONENT DEFINITIONS
struct Position {
    x: f64,
    y: f64
}

struct HorizVelocity {
    x: f64
}

struct VertVelocity {
    y: f64
}

struct Sprite {
    x_size: f64,
    y_size: f64,
    color: [f64, ..4]
}

struct Components {
    position: Option<@mut Position>,
    horiz_velocity: Option<@mut HorizVelocity>,
    vert_velocity: Option<@mut VertVelocity>,
    sprite: Option<@mut Sprite>
}

// SYSTEM DEFINITIONS
trait System {
    fn process(&self, entity: @Components) -> ();
}

struct MovementSystem;

impl System for MovementSystem {
    fn process(&self, entity: @Components) -> () {
        match entity.position {
            Some(pos) => {
                match entity.vert_velocity {
                    Some(v) => pos.y += v.y,
                    None => ()
                }
                match entity.horiz_velocity {
                    Some(v) => pos.x += v.x,
                    None => ()
                }
            },
            None => ()
        }
    }
}

struct EdgeCollisionSystem;

impl System for EdgeCollisionSystem {
    fn process(&self, entity: @Components) -> () {
        match (entity.position, entity.vert_velocity) {
            (Some(pos), Some(vel)) => {
                if pos.y >= 4.0 || pos.y <= 0.0 {
                    vel.y *= -1.0;
                }
            },
            (_, _) => ()
        }
    }
}

struct PaddleCollisionSystem {
    left_paddle: @Components,
    right_paddle: @Components,
}

impl System for PaddleCollisionSystem {
    fn process(&self, entity: @Components) -> () {
        //TODO use a hitbox or something instead of sprite
        match (entity.position, entity.horiz_velocity, entity.sprite) {
            (Some(pos), Some(vel), Some(spr)) => {
                if (pos.x+(spr.x_size)/2.0) >= (self.right_paddle.position.unwrap().x-(self.right_paddle.sprite.unwrap().x_size)/2.0) {
                    if std::num::abs(pos.y - self.right_paddle.position.unwrap().y) < (self.right_paddle.sprite.unwrap().y_size/2.0) {
                        vel.x *= -1.0;
                    }
                }
                if (pos.x-(spr.x_size)/2.0) <= (self.left_paddle.position.unwrap().x+(self.left_paddle.sprite.unwrap().x_size)/2.0) {
                    if std::num::abs(pos.y - self.left_paddle.position.unwrap().y) < (self.left_paddle.sprite.unwrap().y_size/2.0) {
                        vel.x *= -1.0;
                    }
                }
            },
            (_, _, _) => ()
        }
    }
}

struct RenderSystem {
    program: GLuint,
    fs: GLuint,
    vs: GLuint,
    vbo: GLuint,
    vao: GLuint,
    position_uniform: GLint,
    scale_uniform: GLint,
    color_uniform: GLint,
    window_uniform: GLint
}

impl System for RenderSystem {
    fn process(&self, entity: @Components) -> () {
        match (entity.position, entity.sprite) {
            (Some(pos), Some(sprite)) => {
                // Set uniforms
                gl::ProgramUniform2f(self.program, self.position_uniform, pos.x as f32, pos.y as f32);
                gl::ProgramUniform2f(self.program, self.scale_uniform, sprite.x_size as f32, sprite.y_size as f32);
                gl::ProgramUniform4f(self.program, self.color_uniform, sprite.color[0] as f32, sprite.color[1] as f32, sprite.color[2] as f32, sprite.color[3] as f32);
                // Draw a rect from the 4 vertices
                gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
            },
            (_, _) => ()
        }
    }
}

// WORLD DEFINITION
// We need to figure out how to integrate World with the main game loop
// in Artemis world has a `setDelta` method for timestep
struct World {
    entities: ~[@Components],
    systems: ~[@System]
}

impl World {
    fn new() -> World {
        return World {entities: ~[], systems: ~[]};
    }

    fn process(&self) {
        for system in self.systems.iter() {
            for entity in self.entities.iter() {
                system.process(*entity);
            }
        }
    }
}

//ENTITY CONSTRUCTORS
enum PaddleSide {
    RIGHT,
    LEFT
}

fn new_ball() -> @Components {
    @Components {
        position: Some(@mut Position { x: 2.0, y: 1.5 }),
        horiz_velocity: Some(@mut HorizVelocity { x: 1.0/60.0 }),
        vert_velocity: Some(@mut VertVelocity { y: 0.0 }),
        sprite: Some(@mut Sprite {
            x_size: 0.05,
            y_size: 0.05,
            color: [0.8, 0.7, 0.3, 1.0]
        })
    }
}

fn new_paddle(side: PaddleSide) -> @Components {
    let xpos = match side {
        RIGHT => 3.9,
        LEFT => 0.1
    };
    @Components {
        position: Some(@mut Position { x: xpos, y: 1.5 }),
        horiz_velocity: None,
        vert_velocity: Some(@mut VertVelocity { y: 0.0 }),
        sprite: Some(@mut Sprite {
            x_size: 0.1,
            y_size: 0.4,
            color: [xpos/4.0, 1.0-(xpos/4.0), 0.3, 1.0]
        })
    }
}

fn new_background_2() -> @Components {
    @Components {
        position: Some(@mut Position { x: 2.0, y: 1.5 }),
        horiz_velocity: None,
        vert_velocity: None,
        sprite: Some(@mut Sprite {
            x_size: 3.0,
            y_size: 2.0,
            color: [0.0, 0.0, 0.0, 0.3]
        })
    }
}

fn new_background() -> @Components {
    @Components {
        position: Some(@mut Position { x: 2.0, y: 1.5 }),
        horiz_velocity: None,
        vert_velocity: None,
        sprite: Some(@mut Sprite {
            x_size: 4.0,
            y_size: 3.0,
            color: [0.45, 0.4, 1.0, 1.0]
        })
    }
}

// OPENGL ETC STUFF

// Vertex data
static VERTEX_DATA: [GLfloat, ..8] = [
    -0.5,  0.5,
    -0.5, -0.5,
     0.5,  0.5,
     0.5, -0.5
];

#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint, out_color: &str) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    // gl::BindFragDataLocation needs to be called before linking to have effect
    unsafe {
        out_color.with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));
    }
    gl::LinkProgram(program);
    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), vec::raw::to_mut_ptr(buf) as *mut GLchar);
            fail!(str::raw::from_utf8(buf));
        }
    }
    program
}

impl RenderSystem {
    fn new() -> RenderSystem {
        // Create GLSL shaders
        let vs_src = io::read_whole_file_str(&std::path::Path::new("main.vs.glsl")).unwrap();
        let vs = compile_shader(vs_src, gl::VERTEX_SHADER);
        let fs_src = io::read_whole_file_str(&std::path::Path::new("main.fs.glsl")).unwrap();
        let fs = compile_shader(fs_src, gl::FRAGMENT_SHADER);
        let program = link_program(vs, fs, "out_color");

        let mut vao = 0;
        let mut vbo = 0;

        let position_uniform: GLint;
        let scale_uniform: GLint;
        let color_uniform: GLint;
        let window_uniform: GLint;

        unsafe {
            position_uniform = "position".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            scale_uniform = "scale".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            color_uniform = "color".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            window_uniform = "window".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));
            // Create Vertex Array Object
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl::GenBuffers(1, &mut vbo);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
            gl::BufferData(gl::ARRAY_BUFFER,
                           (VERTEX_DATA.len() * sys::size_of::<GLfloat>()) as GLsizeiptr,
                           cast::transmute(&VERTEX_DATA[0]),
                           gl::STATIC_DRAW);

            // Use shader program
            gl::UseProgram(program);

            // Specify the layout of the vertex data
            let vert_attr = "vertex".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(vert_attr as GLuint);
            gl::VertexAttribPointer(vert_attr as GLuint, 2, gl::FLOAT,
                                    gl::FALSE as GLboolean, 0, ptr::null());
        }
        //enable alpha blending
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        RenderSystem {
            program: program,
            fs: fs,
            vs: vs,
            vbo: vbo,
            vao: vao,
            position_uniform: position_uniform,
            scale_uniform: scale_uniform,
            color_uniform: color_uniform,
            window_uniform: window_uniform
        }
    }
}

impl Drop for RenderSystem {
    fn drop(&mut self) {
        // Cleanup
        gl::DeleteProgram(self.program);
        gl::DeleteShader(self.fs);
        gl::DeleteShader(self.vs);
        unsafe {
            gl::DeleteBuffers(1, &self.vbo);
            gl::DeleteVertexArrays(1, &self.vao);
        }
    }
}

fn main() {
    do glfw::set_error_callback |_, description| {
        println!("GLFW Error: {}", description);
    }

    do glfw::start {
        // initialize game world
        let left_paddle: @Components = new_paddle(LEFT);
        let right_paddle: @Components = new_paddle(RIGHT);
        let ball: @Components = new_ball();
        let background: @Components = new_background();
        let background_2: @Components = new_background_2();
        let ms = @MovementSystem;
        let es = @EdgeCollisionSystem;
        let ps = @PaddleCollisionSystem{ right_paddle: right_paddle, left_paddle: left_paddle };

        let mut world: World = World::new();
        world.entities.push(background);
        world.entities.push(background_2);
        world.entities.push(left_paddle);
        world.entities.push(right_paddle);
        world.entities.push(ball);
        world.systems.push(ms as @System);
        world.systems.push(es as @System);
        world.systems.push(ps as @System);

        // Choose a GL profile that is compatible with OS X 10.7+
        glfw::window_hint::context_version(3, 2);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::opengl_forward_compat(true);

        let window_width = 800;
        let window_height = 480;
        let window = glfw::Window::create(window_width, window_height, "Pong", glfw::Windowed).unwrap();
        window.set_key_callback(key_callback);
        window.make_context_current();

        // Load the OpenGL function pointers
        gl::load_with(glfw::get_proc_address);

        let rs = @RenderSystem::new();
        gl::ProgramUniform2f(rs.program, rs.window_uniform, window_width as f32, window_height as f32);
        /* // TODO figure out how to make this work
        window.set_framebuffer_size_callback(|_: &glfw::Window, width: int, height: int| {
            gl::ProgramUniform2f(rs.program, rs.window_uniform, width as f32, height as f32);
        });
        */

        world.systems.push(rs as @System);

        while !window.should_close() {
            // Poll events
            glfw::poll_events();

            // Clear the screen
            gl::ClearColor(0.8, 0.8, 0.8, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // process game world
            world.process();

            // Swap buffers
            window.swap_buffers();
        }
    }
}

fn key_callback(window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
    if action == glfw::Press && key == glfw::KeyEscape {
        window.set_should_close(true);
    }
}

<|endoftext|>


<commit_before>extern crate rand;

use super::std;
use super::std::time::{Duration, Instant};

use super::bus::Bus;
use super::io::{Audio, Display, Input, Pixel};
use super::io::{SCREEN_WIDTH, SCREEN_HEIGHT};
use super::memory::Memory;

// Constants
///////////////////////////////////////////////////////////////////////

const FRAME_RATE:u64 = 17;

// Processor
////////////////////////////////////////////////////////////////////////

#[derive(Clone, Copy)]
enum Key {
    Up,
    Down(Instant),
}

pub struct Processor {
    oc:u16, // Opt Code
    pc:u16, // Program Counter
    sp:u16, // Stack Pointer
    index:u16, // Index

    delay_timer:u8,
    sound_timer:u8,

    draw_flag:bool,

    v:[u8;0x10],
    stack:[u16;0x10],
    screen:[bool;SCREEN_WIDTH*SCREEN_HEIGHT],
    keys:[Key;0x10],
}

impl Default for Processor {
    fn default() -> Processor {
        Processor{
            oc:0x0,
            pc:0x200,
            sp:0x0,
            index:0x0,

            delay_timer:0x0,
            sound_timer:0x0,

            draw_flag:false,

            v:[0x0;0x10],
            stack:[0x0;0x10],
            screen:[false;SCREEN_WIDTH*SCREEN_HEIGHT],
            keys:[Key::Up;0x10],
        }
    }
}

impl Processor {

    // non-self functions

    fn read_address(pointer:u16, memory:&Memory) -> u16 {
        let top = (memory.read_memory(pointer) as u16) << 0x8;
        let bot = (memory.read_memory(pointer + 0x1) & 0xFF) as u16;
        top | bot
    }

    // &self functions

    // &mut self functions

    fn load_optcode(&mut self, memory:&Memory){
        self.oc = Processor::read_address(self.pc, memory);
    }

    fn run_optcode<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        let b1 = (self.oc & 0xF000) >> 0xC;
        let b2 = ((self.oc & 0x0F00) >> 0x8) as usize;
        let b3 = ((self.oc & 0x00F0) >> 0x4) as usize;
        let b4 = self.oc & 0x000F;

        match (b1, b2, b3, b4) {
            (0x0,0x0,0xE,0x0) => { // clear the screen
                self.screen[..]
                        .copy_from_slice(&[false;SCREEN_WIDTH*SCREEN_HEIGHT]);
                self.pc += 2;
            },
            (0x0,0x0,0xE,0xE) => { // return from subroutine
                self.sp -= 1;
                self.pc = self.stack[self.sp as usize];
                self.pc += 2;
            },
            (0x0,_,_,_) => { // call RCA 1802 program at address NNN
                /* TODO */
                panic!("TODO -- 0x0NNN");
            },
            (0x1,_,_,_) => { // jump to address NNN
                self.pc = self.oc & 0x0FFF;
            },
            (0x2,_,_,_) => { // call subroutine at NNN
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;
                self.pc = self.oc & 0x0FFF;
            },
            (0x3,x,_,_) => { // skip next instruction if VX == NN
                self.pc += if self.v[x] as u16 == (self.oc & 0x00FF) {
                    4
                } else {
                    2
                };
            },
            (0x4,x,_,_) => { // skip next instruction if VX != NN
                self.pc += if self.v[x] as u16 != (self.oc & 0x00FF) {
                    4
                } else {
                    2
                };
            },
            (0x5,x,y,0x0) => { // skip next instruction if VX == VY
                self.pc += if self.v[x] == self.v[y] {
                    4
                } else {
                    2
                };
            },
            (0x6,x,_,_) => { // set VX to NN
                self.v[x] = (self.oc & 0x00FF) as u8;
                self.pc += 2;
            },
            (0x7,x,_,_) => { // add NN to VX
                self.v[x] = self.v[x].wrapping_add((self.oc & 0x00FF) as u8);
                self.pc += 2;
            },
            (0x8,x,y,0x0) => { // set VX to VY
                self.v[x] = self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x1) => { // or VX with VY
                self.v[x] |= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x2) => { // and VX with VY
                self.v[x] &= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x3) => { // xor VX with VY
                self.v[x] ^= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x4) => { // add VY to VX. VF = if carry {1} else {0}
                let (value, flag) = self.v[x].overflowing_add(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0x8,x,y,0x5) => { // sub VY from VX. VF = if borrow {0} else {1}
                let (value, flag) = self.v[x].overflowing_sub(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0x6) => { // shift VX right. VF set to dropped bit.
                let bit = self.v[x] & 0x1;
                self.v[x] >>= 1;
                self.v[0xF] = bit;
                self.pc += 2;
            },
            (0x8,x,y,0x7) => { // set VX to VY - VX. if borrow {0} else {1}
                let (value, flag) =  self.v[y].overflowing_sub(self.v[x]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0xE) => { // shift VX left. VF set to dropped bit.
               let bit = (self.v[x] >> 0x7) & 0x1;
               self.v[x] <<= 1;
               self.v[0xF] = bit;
               self.pc += 2;
            },
            (0x9,x,y,0x0) => { // skip next instruction if VX != VY
                self.pc = if  self.v[x] != self.v[y] {
                    4
                } else {
                    2
                };
            },
            (0xA,_,_,_) => { // set I to NNN
                self.index = self.oc & 0x0FFF;
                self.pc += 2;
            },
            (0xB,_,_,_) => { // jump to address NNN + V0
                self.pc = (self.oc & 0x0FFF) + (self.v[0] as u16);
            },
            (0xC,x,_,_) => { // set VX to random number & NN
                self.v[x] = rand::random::<u8>() & (self.oc & 0xFF) as u8;
                self.pc += 2;
            },
            (0xD,x,y,n) => { // complicated
                let x = self.v[x] as usize;
                let y = self.v[y] as usize;
                self.draw_sprite(x, y, n as usize, &bus.memory);
                self.pc += 2;
            },
            (0xE,x,0x9,0xE) => { // skip next if key in VX is pressed;
                match self.keys[self.v[x] as usize] {
                    Key::Down(_) => self.pc += 4,
                    Key::Up => self.pc += 2,
                }
                self.keys[self.v[x] as usize] = Key::Up;
            },
            (0xE,x,0xA,0x1) => { // skip next if key in VX is not pressed;
                match self.keys[self.v[x] as usize] {
                    Key::Down(_)  => self.pc += 2,
                    Key::Up => self.pc += 4,
                }
                self.keys[self.v[x] as usize] = Key::Up;
            },
            (0xF,x,0x0,0x7) => {
                self.v[x] = self.delay_timer;
                self.pc += 2;
            },
            (0xF,x,0x0,0xA) => { // a keypress is awaited, then stored in v[x]
                self.v[x] = bus.input.get_key();
            },
            (0xF,x,0x1,0x5) => { // set delay timer to VX
                self.delay_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0x8) => {
                self.sound_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0xE) => {
                let (value, flag) = self.index.overflowing_add(self.v[x] as u16);
                self.index = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0xF,x,0x2,0x9) => {
                self.index = (self.v[x] as u16)*5;
                self.pc += 2;
            },
            (0xF,x,0x3,0x3) => {
                let i = self.index;
                let vx = self.v[x];
                bus.memory.write_memory(i,vx/100);
                bus.memory.write_memory(i+1,(vx/10)%100);
                bus.memory.write_memory(i+2,(vx%100)%10);
                self.pc += 2;
            },
            (0xF,x,0x5,0x5) => { // stores V0 to VX (inclusive) starting at I
                let index = self.index;
                bus.memory.set_range(index, &self.v[0..(x+1)]);
                self.pc += 2;
            },
            (0xF,x,0x6,0x5) => { // fills V0 to VX (inclusive) starting from I
                for i in 0..(x+1) as u16{
                    self.v[i as usize] = bus.memory.read_memory(self.index + i);
                }
                self.pc += 2;
            },
            _ => panic!("unknown instruction received"),
        };
    }

    fn decrement_delay_timer(&mut self){
        if self.delay_timer > 0x0 {
            self.delay_timer -= 0x1;
        }
    }

    fn decrement_sound_timer<A:Audio>(&mut self, audio:&A){
        if self.sound_timer > 0x0 {
            if self.sound_timer == 0x1 {
                audio.beep();
            }
            self.sound_timer -= 0x1;
        }
    }

    fn print_screen<D:Display>(&self, display:&mut D){
        for row in 0..SCREEN_HEIGHT {
            for col in 0..SCREEN_WIDTH {
                let pixel = if self.screen[SCREEN_WIDTH*row + col] {
                    Pixel::On
                } else {
                    Pixel::Off
                };
                let _ = display.set(row, col, pixel);
            }
        }
        display.refresh();
    }

    fn draw_sprite(&mut self, x:usize, y:usize, height:usize, memory:&Memory){
        self.v[0xF] = 0x0;
        let location = x + y*SCREEN_WIDTH;
        let index = self.index as usize;
        for i in 0..height {
            if y + i < SCREEN_HEIGHT {
                let byte = memory.read_memory((index + i) as u16) as usize;
                self.draw_byte(location + i*SCREEN_WIDTH, byte);
            }
        }
    }

    fn draw_byte(&mut self, loc:usize, byte:usize){
        for i in 0..8 {
            if (byte & (0x80 >> i)) != 0 {
                self.draw_flag = true;
                if self.screen[loc+i] {self.v[0xF] = 0x1};
                self.screen[loc+i] ^= true;
            }
        }
    }

    fn set_pushed<I:Input>(&mut self, input:&I){
        let timeout = Duration::new(1,0);

        for key in &mut self.keys {
            *key = match *key {
                Key::Down(x) if x.elapsed() > timeout => Key::Up,
                _ => *key,
            };
        }

        for key in input.get_keys(){
            self.keys[key as usize] = Key::Down(Instant::now());
        }
    }
    // pub &mut self functions

    pub fn cycle<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        self.load_optcode(&bus.memory);
        self.run_optcode(bus);
        self.decrement_delay_timer();
        self.decrement_sound_timer(&bus.audio);

        if self.draw_flag {
            self.print_screen(&mut bus.display);
            self.draw_flag = false;
            std::thread::sleep(Duration::from_millis(FRAME_RATE));
        }
        self.set_pushed(&bus.input);
    }
}
<commit_msg>fixed setting of program counter to increment, not set<commit_after>extern crate rand;

use super::std;
use super::std::time::{Duration, Instant};

use super::bus::Bus;
use super::io::{Audio, Display, Input, Pixel};
use super::io::{SCREEN_WIDTH, SCREEN_HEIGHT};
use super::memory::Memory;

// Constants
///////////////////////////////////////////////////////////////////////

const FRAME_RATE:u64 = 17;

// Processor
////////////////////////////////////////////////////////////////////////

#[derive(Clone, Copy)]
enum Key {
    Up,
    Down(Instant),
}

pub struct Processor {
    oc:u16, // Opt Code
    pc:u16, // Program Counter
    sp:u16, // Stack Pointer
    index:u16, // Index

    delay_timer:u8,
    sound_timer:u8,

    draw_flag:bool,

    v:[u8;0x10],
    stack:[u16;0x10],
    screen:[bool;SCREEN_WIDTH*SCREEN_HEIGHT],
    keys:[Key;0x10],
}

impl Default for Processor {
    fn default() -> Processor {
        Processor{
            oc:0x0,
            pc:0x200,
            sp:0x0,
            index:0x0,

            delay_timer:0x0,
            sound_timer:0x0,

            draw_flag:false,

            v:[0x0;0x10],
            stack:[0x0;0x10],
            screen:[false;SCREEN_WIDTH*SCREEN_HEIGHT],
            keys:[Key::Up;0x10],
        }
    }
}

impl Processor {

    // non-self functions

    fn read_address(pointer:u16, memory:&Memory) -> u16 {
        let top = (memory.read_memory(pointer) as u16) << 0x8;
        let bot = (memory.read_memory(pointer + 0x1) & 0xFF) as u16;
        top | bot
    }

    // &self functions

    // &mut self functions

    fn load_optcode(&mut self, memory:&Memory){
        self.oc = Processor::read_address(self.pc, memory);
    }

    fn run_optcode<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        let b1 = (self.oc & 0xF000) >> 0xC;
        let b2 = ((self.oc & 0x0F00) >> 0x8) as usize;
        let b3 = ((self.oc & 0x00F0) >> 0x4) as usize;
        let b4 = self.oc & 0x000F;

        match (b1, b2, b3, b4) {
            (0x0,0x0,0xE,0x0) => { // clear the screen
                self.screen[..]
                        .copy_from_slice(&[false;SCREEN_WIDTH*SCREEN_HEIGHT]);
                self.pc += 2;
            },
            (0x0,0x0,0xE,0xE) => { // return from subroutine
                self.sp -= 1;
                self.pc = self.stack[self.sp as usize];
                self.pc += 2;
            },
            (0x0,_,_,_) => { // call RCA 1802 program at address NNN
                /* TODO */
                panic!("TODO -- 0x0NNN");
            },
            (0x1,_,_,_) => { // jump to address NNN
                self.pc = self.oc & 0x0FFF;
            },
            (0x2,_,_,_) => { // call subroutine at NNN
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;
                self.pc = self.oc & 0x0FFF;
            },
            (0x3,x,_,_) => { // skip next instruction if VX == NN
                self.pc += if self.v[x] as u16 == (self.oc & 0x00FF) {
                    4
                } else {
                    2
                };
            },
            (0x4,x,_,_) => { // skip next instruction if VX != NN
                self.pc += if self.v[x] as u16 != (self.oc & 0x00FF) {
                    4
                } else {
                    2
                };
            },
            (0x5,x,y,0x0) => { // skip next instruction if VX == VY
                self.pc += if self.v[x] == self.v[y] {
                    4
                } else {
                    2
                };
            },
            (0x6,x,_,_) => { // set VX to NN
                self.v[x] = (self.oc & 0x00FF) as u8;
                self.pc += 2;
            },
            (0x7,x,_,_) => { // add NN to VX
                self.v[x] = self.v[x].wrapping_add((self.oc & 0x00FF) as u8);
                self.pc += 2;
            },
            (0x8,x,y,0x0) => { // set VX to VY
                self.v[x] = self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x1) => { // or VX with VY
                self.v[x] |= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x2) => { // and VX with VY
                self.v[x] &= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x3) => { // xor VX with VY
                self.v[x] ^= self.v[y];
                self.pc += 2;
            },
            (0x8,x,y,0x4) => { // add VY to VX. VF = if carry {1} else {0}
                let (value, flag) = self.v[x].overflowing_add(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0x8,x,y,0x5) => { // sub VY from VX. VF = if borrow {0} else {1}
                let (value, flag) = self.v[x].overflowing_sub(self.v[y]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0x6) => { // shift VX right. VF set to dropped bit.
                let bit = self.v[x] & 0x1;
                self.v[x] >>= 1;
                self.v[0xF] = bit;
                self.pc += 2;
            },
            (0x8,x,y,0x7) => { // set VX to VY - VX. if borrow {0} else {1}
                let (value, flag) =  self.v[y].overflowing_sub(self.v[x]);
                self.v[x] = value;
                self.v[0xF] = if flag {0} else {1};
                self.pc += 2;
            },
            (0x8,x,_,0xE) => { // shift VX left. VF set to dropped bit.
               let bit = (self.v[x] >> 0x7) & 0x1;
               self.v[x] <<= 1;
               self.v[0xF] = bit;
               self.pc += 2;
            },
            (0x9,x,y,0x0) => { // skip next instruction if VX != VY
                self.pc += if self.v[x] != self.v[y] {
                    4
                } else {
                    2
                };
            },
            (0xA,_,_,_) => { // set I to NNN
                self.index = self.oc & 0x0FFF;
                self.pc += 2;
            },
            (0xB,_,_,_) => { // jump to address NNN + V0
                self.pc = (self.oc & 0x0FFF) + (self.v[0] as u16);
            },
            (0xC,x,_,_) => { // set VX to random number & NN
                self.v[x] = rand::random::<u8>() & (self.oc & 0xFF) as u8;
                self.pc += 2;
            },
            (0xD,x,y,n) => { // complicated
                let x = self.v[x] as usize;
                let y = self.v[y] as usize;
                self.draw_sprite(x, y, n as usize, &bus.memory);
                self.pc += 2;
            },
            (0xE,x,0x9,0xE) => { // skip next if key in VX is pressed;
                match self.keys[self.v[x] as usize] {
                    Key::Down(_) => self.pc += 4,
                    Key::Up => self.pc += 2,
                }
                self.keys[self.v[x] as usize] = Key::Up;
            },
            (0xE,x,0xA,0x1) => { // skip next if key in VX is not pressed;
                match self.keys[self.v[x] as usize] {
                    Key::Down(_)  => self.pc += 2,
                    Key::Up => self.pc += 4,
                }
                self.keys[self.v[x] as usize] = Key::Up;
            },
            (0xF,x,0x0,0x7) => {
                self.v[x] = self.delay_timer;
                self.pc += 2;
            },
            (0xF,x,0x0,0xA) => { // a keypress is awaited, then stored in v[x]
                self.v[x] = bus.input.get_key();
            },
            (0xF,x,0x1,0x5) => { // set delay timer to VX
                self.delay_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0x8) => {
                self.sound_timer = self.v[x];
                self.pc += 2;
            },
            (0xF,x,0x1,0xE) => {
                let (value, flag) = self.index.overflowing_add(self.v[x] as u16);
                self.index = value;
                self.v[0xF] = if flag {1} else {0};
                self.pc += 2;
            },
            (0xF,x,0x2,0x9) => {
                self.index = (self.v[x] as u16)*5;
                self.pc += 2;
            },
            (0xF,x,0x3,0x3) => {
                let i = self.index;
                let vx = self.v[x];
                bus.memory.write_memory(i,vx/100);
                bus.memory.write_memory(i+1,(vx/10)%100);
                bus.memory.write_memory(i+2,(vx%100)%10);
                self.pc += 2;
            },
            (0xF,x,0x5,0x5) => { // stores V0 to VX (inclusive) starting at I
                let index = self.index;
                bus.memory.set_range(index, &self.v[0..(x+1)]);
                self.pc += 2;
            },
            (0xF,x,0x6,0x5) => { // fills V0 to VX (inclusive) starting from I
                for i in 0..(x+1) as u16{
                    self.v[i as usize] = bus.memory.read_memory(self.index + i);
                }
                self.pc += 2;
            },
            _ => panic!("unknown instruction received"),
        };
    }

    fn decrement_delay_timer(&mut self){
        if self.delay_timer > 0x0 {
            self.delay_timer -= 0x1;
        }
    }

    fn decrement_sound_timer<A:Audio>(&mut self, audio:&A){
        if self.sound_timer > 0x0 {
            if self.sound_timer == 0x1 {
                audio.beep();
            }
            self.sound_timer -= 0x1;
        }
    }

    fn print_screen<D:Display>(&self, display:&mut D){
        for row in 0..SCREEN_HEIGHT {
            for col in 0..SCREEN_WIDTH {
                let pixel = if self.screen[SCREEN_WIDTH*row + col] {
                    Pixel::On
                } else {
                    Pixel::Off
                };
                let _ = display.set(row, col, pixel);
            }
        }
        display.refresh();
    }

    fn draw_sprite(&mut self, x:usize, y:usize, height:usize, memory:&Memory){
        self.v[0xF] = 0x0;
        let location = x + y*SCREEN_WIDTH;
        let index = self.index as usize;
        for i in 0..height {
            if y + i < SCREEN_HEIGHT {
                let byte = memory.read_memory((index + i) as u16) as usize;
                self.draw_byte(location + i*SCREEN_WIDTH, byte);
            }
        }
    }

    fn draw_byte(&mut self, loc:usize, byte:usize){
        for i in 0..8 {
            if (byte & (0x80 >> i)) != 0 {
                self.draw_flag = true;
                if self.screen[loc+i] {self.v[0xF] = 0x1};
                self.screen[loc+i] ^= true;
            }
        }
    }

    fn set_pushed<I:Input>(&mut self, input:&I){
        let timeout = Duration::new(1,0);

        for key in &mut self.keys {
            *key = match *key {
                Key::Down(x) if x.elapsed() > timeout => Key::Up,
                _ => *key,
            };
        }

        for key in input.get_keys(){
            self.keys[key as usize] = Key::Down(Instant::now());
        }
    }
    // pub &mut self functions

    pub fn cycle<A, D, I>(&mut self, bus:&mut Bus<A, D, I>)
            where
                A: Audio,
                D: Display,
                I: Input {
        self.load_optcode(&bus.memory);
        self.run_optcode(bus);
        self.decrement_delay_timer();
        self.decrement_sound_timer(&bus.audio);

        if self.draw_flag {
            self.print_screen(&mut bus.display);
            self.draw_flag = false;
            std::thread::sleep(Duration::from_millis(FRAME_RATE));
        }
        self.set_pushed(&bus.input);
    }
}
<|endoftext|>


<commit_before>use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;
use std::ptr;

bitflags!(
    #[repr(C)]
    flags EpollFlags: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLEXCLUSIVE = 1 << 28,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

libc_bitflags!{
    flags EpollCreateFlags: c_int {
        EPOLL_CLOEXEC,
    }
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct EpollEvent {
    event: libc::epoll_event,
}

impl EpollEvent {
    pub fn new(events: EpollFlags, data: u64) -> EpollEvent {
        EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
    }

    pub fn events(&self) -> EpollFlags {
        EpollFlags::from_bits(self.event.events).unwrap()
    }

    pub fn data(&self) -> u64 {
        self.event.u64
    }
}

impl<'a> Into<&'a mut EpollEvent> for Option<&'a mut EpollEvent> {
    #[inline]
    fn into(self) -> &'a mut EpollEvent {
        match self {
            Some(epoll_event) => epoll_event,
            None => unsafe { &mut *ptr::null_mut::<EpollEvent>() }
        }
    }
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { libc::epoll_create(1024) };

    Errno::result(res)
}

#[inline]
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
    let res = unsafe { libc::epoll_create1(flags.bits()) };

    Errno::result(res)
}

#[inline]
pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
    where T: Into<&'a mut EpollEvent>
{
    let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.into().event) };
    Errno::result(res).map(drop)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
    };

    Errno::result(res).map(|r| r as usize)
}
<commit_msg>add empty() in EpollEvent.<commit_after>use {Errno, Result};
use libc::{self, c_int};
use std::os::unix::io::RawFd;
use std::ptr;

bitflags!(
    #[repr(C)]
    flags EpollFlags: u32 {
        const EPOLLIN = 0x001,
        const EPOLLPRI = 0x002,
        const EPOLLOUT = 0x004,
        const EPOLLRDNORM = 0x040,
        const EPOLLRDBAND = 0x080,
        const EPOLLWRNORM = 0x100,
        const EPOLLWRBAND = 0x200,
        const EPOLLMSG = 0x400,
        const EPOLLERR = 0x008,
        const EPOLLHUP = 0x010,
        const EPOLLRDHUP = 0x2000,
        const EPOLLEXCLUSIVE = 1 << 28,
        const EPOLLWAKEUP = 1 << 29,
        const EPOLLONESHOT = 1 << 30,
        const EPOLLET = 1 << 31
    }
);

#[derive(Clone, Copy)]
#[repr(C)]
pub enum EpollOp {
    EpollCtlAdd = 1,
    EpollCtlDel = 2,
    EpollCtlMod = 3
}

libc_bitflags!{
    flags EpollCreateFlags: c_int {
        EPOLL_CLOEXEC,
    }
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct EpollEvent {
    event: libc::epoll_event,
}

impl EpollEvent {
    pub fn new(events: EpollFlags, data: u64) -> Self {
        EpollEvent { event: libc::epoll_event { events: events.bits(), u64: data } }
    }

    pub empty() -> Self {
        EpollEvent::new(EpollFlags::from_bits(0), 0);
    }

    pub fn events(&self) -> EpollFlags {
        EpollFlags::from_bits(self.event.events).unwrap()
    }

    pub fn data(&self) -> u64 {
        self.event.u64
    }
}

impl<'a> Into<&'a mut EpollEvent> for Option<&'a mut EpollEvent> {
    #[inline]
    fn into(self) -> &'a mut EpollEvent {
        match self {
            Some(epoll_event) => epoll_event,
            None => unsafe { &mut *ptr::null_mut::<EpollEvent>() }
        }
    }
}

#[inline]
pub fn epoll_create() -> Result<RawFd> {
    let res = unsafe { libc::epoll_create(1024) };

    Errno::result(res)
}

#[inline]
pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
    let res = unsafe { libc::epoll_create1(flags.bits()) };

    Errno::result(res)
}

#[inline]
pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
    where T: Into<&'a mut EpollEvent>
{
    let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.into().event) };
    Errno::result(res).map(drop)
}

#[inline]
pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
    let res = unsafe {
        libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
    };

    Errno::result(res).map(|r| r as usize)
}
<|endoftext|>


<commit_before>
use spv::*;
use spv::op::*;
use spv::types::*;
use spv::raw::*;
use spv::logical::*;
use glsl450;

const NOOP_SPV: &'static [u8] = include_bytes!("noop.spv");
const NOOP_DIS: &'static str = include_str!("noop.dis");
const WRITE_MULTIPLY_SPV: &'static [u8] = include_bytes!("write_multiply.spv");
const WRITE_MULTIPLY_DIS: &'static str = include_str!("write_multiply.dis");
const COND_TRIG_SPV: &'static [u8] = include_bytes!("cond_trig.spv");
const COND_TRIG_DIS: &'static str = include_str!("cond_trig.dis");

fn read(module: &'static [u8]) -> ReadResult<RawModule> {
    let inst_sets: Vec<Box<ExtInstSet>> = vec![Box::new(glsl450::InstSet)];
    read_module(module, inst_sets)
}

#[test]
fn load_noop() {
    let result = read(NOOP_SPV);
    let glsl450 = OpExtInstImport {
        result_id: ResultId(1),
        name: "GLSL.std.450".into(),
    };
    let mem_model = OpMemoryModel {
        addressing_model: AddressingModel::Logical,
        memory_model: MemoryModel::Glsl450,
    };
    let entry_point = OpEntryPoint {
        execution_model: ExecutionModel::GlCompute,
        entry_point: OpId(4),
        name: "main".into(),
        interface: vec![],
    };
    let local_size = ExecutionMode::LocalSize(32, 32, 32);
    let source = OpSource {
        language: SourceLanguage::Glsl,
        version: SourceVersion(430),
        file: None,
        source: None,
    };
    let workgroup = OpDecorate {
        target: OpId(9),
        decoration: Decoration::BuiltIn(BuiltIn::WorkgroupSize),
    };
    let ty_void = Core::OpTypeVoid(OpTypeVoid { result_id: ResultId(2) });
    let ty_main = Core::OpTypeFunction(OpTypeFunction {
        result_id: ResultId(3),
        return_type: OpId(2),
        parameter_types: vec![],
    });
    let ty_int = Core::OpTypeInt(OpTypeInt {
        result_id: ResultId(6),
        width: 32,
        signedness: Signedness::UnsignedOrNone,
    });
    let ty_vec = Core::OpTypeVector(OpTypeVector {
        result_id: ResultId(7),
        component_type: OpId(6),
        component_count: 3,
    });
    let int_32 = Core::OpConstant(OpConstant {
        result_type: OpId(6),
        result_id: ResultId(8),
        value: vec![32],
    });
    let int_32_x3 = vec![OpId(8), OpId(8), OpId(8)];
    let int_32x3 = Core::OpConstantComposite(OpConstantComposite {
        result_type: OpId(7),
        result_id: ResultId(9),
        constituents: int_32_x3,
    });
    let main = OpFunction {
        result_type: OpId(2),
        result_id: ResultId(4),
        function_control: FunctionControl::default(),
        function_type: OpId(3),
    };
    let instructions = vec![Core::OpCapability(OpCapability { capability: Capability::Shader }),
                            Core::OpExtInstImport(glsl450),
                            Core::OpMemoryModel(mem_model),
                            Core::OpEntryPoint(entry_point),
                            Core::OpExecutionMode(OpExecutionMode {
                                entry_point: OpId(4),
                                mode: local_size,
                            }),
                            Core::OpSource(source),
                            Core::OpName(OpName {
                                target: OpId(4),
                                name: "main".to_string(),
                            }),
                            Core::OpDecorate(workgroup),
                            ty_void,
                            ty_main,
                            ty_int,
                            ty_vec,
                            int_32,
                            int_32x3,
                            Core::OpFunction(main),
                            Core::OpLabel(OpLabel { result_id: ResultId(5) }),
                            Core::OpReturn(OpReturn),
                            Core::OpFunctionEnd(OpFunctionEnd)];
    let expected = RawModule {
        version: Version(1, 0),
        generator: Generator {
            tool: Tool::KhronosGlslang,
            version: 1,
        },
        bound: 10,
        instructions: instructions,
    };
    assert_eq!(result, Ok(expected));
}

#[test]
fn dis_noop() {
    let raw_module = read(NOOP_SPV).expect("Failed to load noop.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(NOOP_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(NOOP_DIS, disassembly);
}

#[test]
fn validate_noop() {
    let raw_module = read(NOOP_SPV).expect("Failed to load noop.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_write_multiply() {
    let raw_module = read(WRITE_MULTIPLY_SPV).expect("Failed to load write_multiply.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(WRITE_MULTIPLY_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(WRITE_MULTIPLY_DIS, disassembly);
}

#[test]
fn validate_write_multiply() {
    let raw_module = read(WRITE_MULTIPLY_SPV).expect("Failed to load write_multiply.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_cond_trig() {
    let raw_module = read(COND_TRIG_SPV).expect("Failed to load cond_trig.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(COND_TRIG_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(COND_TRIG_DIS, disassembly);
}
<commit_msg>Add validate test for cond_trig.spv<commit_after>
use spv::*;
use spv::op::*;
use spv::types::*;
use spv::raw::*;
use spv::logical::*;
use glsl450;

const NOOP_SPV: &'static [u8] = include_bytes!("noop.spv");
const NOOP_DIS: &'static str = include_str!("noop.dis");
const WRITE_MULTIPLY_SPV: &'static [u8] = include_bytes!("write_multiply.spv");
const WRITE_MULTIPLY_DIS: &'static str = include_str!("write_multiply.dis");
const COND_TRIG_SPV: &'static [u8] = include_bytes!("cond_trig.spv");
const COND_TRIG_DIS: &'static str = include_str!("cond_trig.dis");

fn read(module: &'static [u8]) -> ReadResult<RawModule> {
    let inst_sets: Vec<Box<ExtInstSet>> = vec![Box::new(glsl450::InstSet)];
    read_module(module, inst_sets)
}

#[test]
fn load_noop() {
    let result = read(NOOP_SPV);
    let glsl450 = OpExtInstImport {
        result_id: ResultId(1),
        name: "GLSL.std.450".into(),
    };
    let mem_model = OpMemoryModel {
        addressing_model: AddressingModel::Logical,
        memory_model: MemoryModel::Glsl450,
    };
    let entry_point = OpEntryPoint {
        execution_model: ExecutionModel::GlCompute,
        entry_point: OpId(4),
        name: "main".into(),
        interface: vec![],
    };
    let local_size = ExecutionMode::LocalSize(32, 32, 32);
    let source = OpSource {
        language: SourceLanguage::Glsl,
        version: SourceVersion(430),
        file: None,
        source: None,
    };
    let workgroup = OpDecorate {
        target: OpId(9),
        decoration: Decoration::BuiltIn(BuiltIn::WorkgroupSize),
    };
    let ty_void = Core::OpTypeVoid(OpTypeVoid { result_id: ResultId(2) });
    let ty_main = Core::OpTypeFunction(OpTypeFunction {
        result_id: ResultId(3),
        return_type: OpId(2),
        parameter_types: vec![],
    });
    let ty_int = Core::OpTypeInt(OpTypeInt {
        result_id: ResultId(6),
        width: 32,
        signedness: Signedness::UnsignedOrNone,
    });
    let ty_vec = Core::OpTypeVector(OpTypeVector {
        result_id: ResultId(7),
        component_type: OpId(6),
        component_count: 3,
    });
    let int_32 = Core::OpConstant(OpConstant {
        result_type: OpId(6),
        result_id: ResultId(8),
        value: vec![32],
    });
    let int_32_x3 = vec![OpId(8), OpId(8), OpId(8)];
    let int_32x3 = Core::OpConstantComposite(OpConstantComposite {
        result_type: OpId(7),
        result_id: ResultId(9),
        constituents: int_32_x3,
    });
    let main = OpFunction {
        result_type: OpId(2),
        result_id: ResultId(4),
        function_control: FunctionControl::default(),
        function_type: OpId(3),
    };
    let instructions = vec![Core::OpCapability(OpCapability { capability: Capability::Shader }),
                            Core::OpExtInstImport(glsl450),
                            Core::OpMemoryModel(mem_model),
                            Core::OpEntryPoint(entry_point),
                            Core::OpExecutionMode(OpExecutionMode {
                                entry_point: OpId(4),
                                mode: local_size,
                            }),
                            Core::OpSource(source),
                            Core::OpName(OpName {
                                target: OpId(4),
                                name: "main".to_string(),
                            }),
                            Core::OpDecorate(workgroup),
                            ty_void,
                            ty_main,
                            ty_int,
                            ty_vec,
                            int_32,
                            int_32x3,
                            Core::OpFunction(main),
                            Core::OpLabel(OpLabel { result_id: ResultId(5) }),
                            Core::OpReturn(OpReturn),
                            Core::OpFunctionEnd(OpFunctionEnd)];
    let expected = RawModule {
        version: Version(1, 0),
        generator: Generator {
            tool: Tool::KhronosGlslang,
            version: 1,
        },
        bound: 10,
        instructions: instructions,
    };
    assert_eq!(result, Ok(expected));
}

#[test]
fn dis_noop() {
    let raw_module = read(NOOP_SPV).expect("Failed to load noop.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(NOOP_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(NOOP_DIS, disassembly);
}

#[test]
fn validate_noop() {
    let raw_module = read(NOOP_SPV).expect("Failed to load noop.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_write_multiply() {
    let raw_module = read(WRITE_MULTIPLY_SPV).expect("Failed to load write_multiply.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(WRITE_MULTIPLY_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(WRITE_MULTIPLY_DIS, disassembly);
}

#[test]
fn validate_write_multiply() {
    let raw_module = read(WRITE_MULTIPLY_SPV).expect("Failed to load write_multiply.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_cond_trig() {
    let raw_module = read(COND_TRIG_SPV).expect("Failed to load cond_trig.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(COND_TRIG_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(COND_TRIG_DIS, disassembly);
}

#[test]
fn validate_cond_trig() {
    let raw_module = read(COND_TRIG_SPV).expect("Failed to load cond_trig.spv");
    let module = validate(raw_module);
    module.unwrap();
}
<|endoftext|>


<commit_before>
use spv::*;
use spv::op::*;
use spv::types::*;
use spv::raw::*;
use spv::logical::*;
use glsl450;

const NOOP_SPV: &'static [u8] = include_bytes!("noop.spv");
const NOOP_DIS: &'static str = include_str!("noop.dis");
const WRITE_MULTIPLY_SPV: &'static [u8] = include_bytes!("write_multiply.spv");
const WRITE_MULTIPLY_DIS: &'static str = include_str!("write_multiply.dis");
const COND_TRIG_SPV: &'static [u8] = include_bytes!("cond_trig.spv");
const COND_TRIG_DIS: &'static str = include_str!("cond_trig.dis");
const NEST_IF_SPV: &'static [u8] = include_bytes!("nest_if.spv");
const NEST_IF_DIS: &'static str = include_str!("nest_if.dis");

fn read(module: &'static [u8]) -> ReadResult<RawModule> {
    let inst_sets: Vec<Box<ExtInstSet>> = vec![Box::new(glsl450::InstSet)];
    read_module(module, inst_sets)
}

#[test]
fn load_noop() {
    let result = read(NOOP_SPV);
    let glsl450 = OpExtInstImport {
        result_id: ResultId(1),
        name: "GLSL.std.450".into(),
    };
    let mem_model = OpMemoryModel {
        addressing_model: AddressingModel::Logical,
        memory_model: MemoryModel::Glsl450,
    };
    let entry_point = OpEntryPoint {
        execution_model: ExecutionModel::GlCompute,
        entry_point: OpId(4),
        name: "main".into(),
        interface: vec![],
    };
    let local_size = ExecutionMode::LocalSize(32, 32, 32);
    let source = OpSource {
        language: SourceLanguage::Glsl,
        version: SourceVersion(430),
        file: None,
        source: None,
    };
    let workgroup = OpDecorate {
        target: OpId(9),
        decoration: Decoration::BuiltIn(BuiltIn::WorkgroupSize),
    };
    let ty_void = Core::OpTypeVoid(OpTypeVoid { result_id: ResultId(2) });
    let ty_main = Core::OpTypeFunction(OpTypeFunction {
        result_id: ResultId(3),
        return_type: OpId(2),
        parameter_types: vec![],
    });
    let ty_int = Core::OpTypeInt(OpTypeInt {
        result_id: ResultId(6),
        width: 32,
        signedness: Signedness::UnsignedOrNone,
    });
    let ty_vec = Core::OpTypeVector(OpTypeVector {
        result_id: ResultId(7),
        component_type: OpId(6),
        component_count: 3,
    });
    let int_32 = Core::OpConstant(OpConstant {
        result_type: OpId(6),
        result_id: ResultId(8),
        value: vec![32],
    });
    let int_32_x3 = vec![OpId(8), OpId(8), OpId(8)];
    let int_32x3 = Core::OpConstantComposite(OpConstantComposite {
        result_type: OpId(7),
        result_id: ResultId(9),
        constituents: int_32_x3,
    });
    let main = OpFunction {
        result_type: OpId(2),
        result_id: ResultId(4),
        function_control: FunctionControl::default(),
        function_type: OpId(3),
    };
    let instructions = vec![Core::OpCapability(OpCapability { capability: Capability::Shader }),
                            Core::OpExtInstImport(glsl450),
                            Core::OpMemoryModel(mem_model),
                            Core::OpEntryPoint(entry_point),
                            Core::OpExecutionMode(OpExecutionMode {
                                entry_point: OpId(4),
                                mode: local_size,
                            }),
                            Core::OpSource(source),
                            Core::OpName(OpName {
                                target: OpId(4),
                                name: "main".to_string(),
                            }),
                            Core::OpDecorate(workgroup),
                            ty_void,
                            ty_main,
                            ty_int,
                            ty_vec,
                            int_32,
                            int_32x3,
                            Core::OpFunction(main),
                            Core::OpLabel(OpLabel { result_id: ResultId(5) }),
                            Core::OpReturn(OpReturn),
                            Core::OpFunctionEnd(OpFunctionEnd)];
    let expected = RawModule {
        version: Version(1, 0),
        generator: Generator {
            tool: Tool::KhronosGlslang,
            version: 1,
        },
        bound: 10,
        instructions: instructions,
    };
    assert_eq!(result, Ok(expected));
}

#[test]
fn dis_noop() {
    let raw_module = read(NOOP_SPV).expect("Failed to load noop.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(NOOP_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(NOOP_DIS, disassembly);
}

#[test]
fn validate_noop() {
    let raw_module = read(NOOP_SPV).expect("Failed to load noop.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_write_multiply() {
    let raw_module = read(WRITE_MULTIPLY_SPV).expect("Failed to load write_multiply.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(WRITE_MULTIPLY_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(WRITE_MULTIPLY_DIS, disassembly);
}

#[test]
fn validate_write_multiply() {
    let raw_module = read(WRITE_MULTIPLY_SPV).expect("Failed to load write_multiply.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_cond_trig() {
    let raw_module = read(COND_TRIG_SPV).expect("Failed to load cond_trig.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(COND_TRIG_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(COND_TRIG_DIS, disassembly);
}

#[test]
fn validate_cond_trig() {
    let raw_module = read(COND_TRIG_SPV).expect("Failed to load cond_trig.spv");
    let module = validate(raw_module);
    module.unwrap();
}

#[test]
fn dis_next_if() {
    let raw_module = read(NEST_IF_SPV).expect("Failed to load nest_if.spv");
    let disassembly = format!("{}", raw_module);
    for (dis, expect) in disassembly.lines().zip(NEST_IF_DIS.lines()) {
        assert_eq!(dis, expect);
    }
    assert_eq!(NEST_IF_DIS, disassembly);
}

#[test]
fn validate_next_if() {
    let raw_module = read(NEST_IF_SPV).expect("Failed to load nest_if.spv");
    let module = validate(raw_module);
    module.unwrap();
}
<commit_msg>Remove duplication in tests by using more macros<commit_after>
use spv::*;
use spv::op::*;
use spv::types::*;
use spv::raw::*;
use glsl450;

fn read(module: &'static [u8]) -> ReadResult<RawModule> {
    let inst_sets: Vec<Box<ExtInstSet>> = vec![Box::new(glsl450::InstSet)];
    read_module(module, inst_sets)
}

#[test]
fn load_noop() {
    let result = read(include_bytes!("noop.spv"));
    let glsl450 = OpExtInstImport {
        result_id: ResultId(1),
        name: "GLSL.std.450".into(),
    };
    let mem_model = OpMemoryModel {
        addressing_model: AddressingModel::Logical,
        memory_model: MemoryModel::Glsl450,
    };
    let entry_point = OpEntryPoint {
        execution_model: ExecutionModel::GlCompute,
        entry_point: OpId(4),
        name: "main".into(),
        interface: vec![],
    };
    let local_size = ExecutionMode::LocalSize(32, 32, 32);
    let source = OpSource {
        language: SourceLanguage::Glsl,
        version: SourceVersion(430),
        file: None,
        source: None,
    };
    let workgroup = OpDecorate {
        target: OpId(9),
        decoration: Decoration::BuiltIn(BuiltIn::WorkgroupSize),
    };
    let ty_void = Core::OpTypeVoid(OpTypeVoid { result_id: ResultId(2) });
    let ty_main = Core::OpTypeFunction(OpTypeFunction {
        result_id: ResultId(3),
        return_type: OpId(2),
        parameter_types: vec![],
    });
    let ty_int = Core::OpTypeInt(OpTypeInt {
        result_id: ResultId(6),
        width: 32,
        signedness: Signedness::UnsignedOrNone,
    });
    let ty_vec = Core::OpTypeVector(OpTypeVector {
        result_id: ResultId(7),
        component_type: OpId(6),
        component_count: 3,
    });
    let int_32 = Core::OpConstant(OpConstant {
        result_type: OpId(6),
        result_id: ResultId(8),
        value: vec![32],
    });
    let int_32_x3 = vec![OpId(8), OpId(8), OpId(8)];
    let int_32x3 = Core::OpConstantComposite(OpConstantComposite {
        result_type: OpId(7),
        result_id: ResultId(9),
        constituents: int_32_x3,
    });
    let main = OpFunction {
        result_type: OpId(2),
        result_id: ResultId(4),
        function_control: FunctionControl::default(),
        function_type: OpId(3),
    };
    let instructions = vec![Core::OpCapability(OpCapability { capability: Capability::Shader }),
                            Core::OpExtInstImport(glsl450),
                            Core::OpMemoryModel(mem_model),
                            Core::OpEntryPoint(entry_point),
                            Core::OpExecutionMode(OpExecutionMode {
                                entry_point: OpId(4),
                                mode: local_size,
                            }),
                            Core::OpSource(source),
                            Core::OpName(OpName {
                                target: OpId(4),
                                name: "main".to_string(),
                            }),
                            Core::OpDecorate(workgroup),
                            ty_void,
                            ty_main,
                            ty_int,
                            ty_vec,
                            int_32,
                            int_32x3,
                            Core::OpFunction(main),
                            Core::OpLabel(OpLabel { result_id: ResultId(5) }),
                            Core::OpReturn(OpReturn),
                            Core::OpFunctionEnd(OpFunctionEnd)];
    let expected = RawModule {
        version: Version(1, 0),
        generator: Generator {
            tool: Tool::KhronosGlslang,
            version: 1,
        },
        bound: 10,
        instructions: instructions,
    };
    assert_eq!(result, Ok(expected));
}

macro_rules! def_test {
    ($name: ident) => {
        mod $name {

            use super::read;
            use spv::logical::validate;

            const SPV: &'static [u8] = include_bytes!(concat!(stringify!($name), ".spv"));
            const DIS: &'static str = include_str!(concat!(stringify!($name), ".dis"));

            #[test]
            fn disassemble() {
                let raw_module = read(SPV).expect("Failed to load spv");
                let disassembly = format!("{}", raw_module);
                for (dis, expect) in disassembly.lines().zip(DIS.lines()) {
                    assert_eq!(dis, expect);
                }
                assert_eq!(DIS, disassembly);
            }

            #[test]
            fn logical_pass() {
                let raw_module = read(SPV).expect("Failed to load spv");
                let module = validate(raw_module);
                module.unwrap();
            }
        }
    }
}

def_test!(noop);
def_test!(write_multiply);
def_test!(cond_trig);
def_test!(nest_if);
<|endoftext|>