<commit_before>use std::fmt::{ self, Write };

pub struct HrefEscaper<W: Write> {
  inner: W,
}

impl<W: Write> HrefEscaper<W> {
  pub fn new(inner: W) -> HrefEscaper<W> {
    HrefEscaper {
      inner: inner,
    }
  }
}

static HREF_SAFE: [bool; 0x80] = [
  false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
  false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
  false,  true, false,  true,  true,  true, false, false,  true,  true,  true,  true,  true,  true,  true,  true,
   true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true, false,  true, false,  true,
   true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
   true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true, false, false, false, false,  true,
  false,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
   true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true, false, false, false, false, false,
];

impl<W: Write> Write for HrefEscaper<W> {
  fn write_str(&mut self, s: &str) -> fmt::Result {
    for c in s.chars() {
      match c {
        '&' => {
          try!(self.inner.write_str("&"));
        },
        '\'' => {
          try!(self.inner.write_str("'"));
        },
        c if c > '\x7F' || !HREF_SAFE[c as usize] => {
          unimplemented!(); // Need to convert to hex escape string
        },
        _ => {
          try!(self.inner.write_char(c));
        },
      }
    }
    Ok(())
  }
}
<commit_msg>Improve href escaper and add test cases, fixes #3<commit_after>use std::fmt::{ self, Write };

pub struct HrefEscaper<W: Write> {
  inner: W,
}

impl<W: Write> HrefEscaper<W> {
  pub fn new(inner: W) -> HrefEscaper<W> {
    HrefEscaper {
      inner: inner,
    }
  }
}

fn char_to_string(c: char) -> String {
  let mut s = String::with_capacity(4);
  s.push(c);
  s
}

fn percent_encode(c: char) -> String {
  let mut s = String::with_capacity(9);
  for b in char_to_string(c).as_bytes() {
    write!(s, "%{0:X}", b).unwrap();
  }
  s
}

// See https://url.spec.whatwg.org/ for escaping rules
fn escape_char(c: char) -> String {
  if c < '!' {
    // Control characters and space
    return percent_encode(c);
  }

  if c <= '\x7F' {
    // Disallowed ASCII characters
    return match c {
      '"' | '%' | '<' | '>' | '[' | '\\' => percent_encode(c),
      ']' | '^' | '`' | '{' | '|' | '}' | '\x7F' => percent_encode(c),
      _ => char_to_string(c),
    };
  }

  match c {
    // Allowed Unicode ranges
    '\u{00A0}'...'\u{D7FF}'
      | '\u{E000}'...'\u{FDCF}'
      | '\u{FDF0}'...'\u{FFFD}'
      | '\u{10000}'...'\u{1FFFD}'
      | '\u{20000}'...'\u{2FFFD}'
      | '\u{30000}'...'\u{3FFFD}'
      | '\u{40000}'...'\u{4FFFD}'
      | '\u{50000}'...'\u{5FFFD}'
      | '\u{60000}'...'\u{6FFFD}'
      | '\u{70000}'...'\u{7FFFD}'
      | '\u{80000}'...'\u{8FFFD}'
      | '\u{90000}'...'\u{9FFFD}'
      | '\u{A0000}'...'\u{AFFFD}'
      | '\u{B0000}'...'\u{BFFFD}'
      | '\u{C0000}'...'\u{CFFFD}'
      | '\u{D0000}'...'\u{DFFFD}'
      | '\u{E0000}'...'\u{EFFFD}'
      | '\u{F0000}'...'\u{FFFFD}'
      | '\u{100000}'...'\u{10FFFD}' => char_to_string(c),
    _ => percent_encode(c),
  }
}

impl<W: Write> Write for HrefEscaper<W> {
  fn write_str(&mut self, s: &str) -> fmt::Result {
    for c in s.chars() {
      try!(self.write_char(c));
    }
    Ok(())
  }

  fn write_char(&mut self, c: char) -> fmt::Result {
    self.inner.write_str(&*escape_char(c))
  }
}

#[cfg(test)]
mod tests {
  use super::HrefEscaper;

  macro_rules! test_url {
    ($url:expr, $expected:expr) => ({
      use std::fmt::Write;
      let mut s = String::with_capacity(31);
      HrefEscaper::new(&mut s).write_str($url).unwrap();
      assert_eq!(&*s, $expected);
    })
  }

  #[test]
  fn test_poop() {
    test_url!("https://example.org/💩", "https://example.org/💩");
  }

  #[test]
  fn test_ascii() {
    test_url!("https://example.org/something", "https://example.org/something");
  }

  #[test]
  fn test_ascii_escapes() {
    test_url!("https://example.org/\"", "https://example.org/%22");
    test_url!("https://example.org/%", "https://example.org/%25");
    test_url!("https://example.org/<", "https://example.org/%3C");
    test_url!("https://example.org/>", "https://example.org/%3E");
    test_url!("https://example.org/[", "https://example.org/%5B");
    test_url!("https://example.org/\\", "https://example.org/%5C");
    test_url!("https://example.org/]", "https://example.org/%5D");
    test_url!("https://example.org/^", "https://example.org/%5E");
    test_url!("https://example.org/`", "https://example.org/%60");
    test_url!("https://example.org/{", "https://example.org/%7B");
    test_url!("https://example.org/|", "https://example.org/%7C");
    test_url!("https://example.org/}", "https://example.org/%7D");
  }

  #[test]
  fn test_unicode_escapes() {
    test_url!("https://example.org/\u{92}", "https://example.org/%C2%92");
    test_url!("https://example.org/\u{FFFFE}", "https://example.org/%F3%BF%BF%BE");
  }
}
<|endoftext|>


<commit_before>#[feature(globs)];

extern mod native;
extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::str;
use std::vec;
use std::libc;
use std::io::Timer;
use std::hashmap::HashSet;

use gl::types::*;

use cgmath::matrix::Matrix;
use cgmath::matrix::Mat3;
use cgmath::matrix::Mat4;
use cgmath::matrix::ToMat4;
use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;
use cgmath::angle::rad;

#[link(name="GLU")]
extern {}

mod chunk;
mod ratelimiter;

static vertex_shader_src : &'static str = r"
#version 110

uniform mat4 modelview;
uniform mat4 projection;

attribute vec3 position;
attribute vec3 normal;

varying vec4 frag_color;

const vec4 obj_diffuse = vec4(0.2, 0.6, 0.2, 1.0);
const vec3 light_direction = vec3(0.408248, -0.816497, 0.408248);
const vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 0.0);
const vec4 light_ambient = vec4(0.2, 0.2, 0.2, 1.0);

const float planet_radius = 6371000.0 / 10000.0;

void main() {
    vec4 eye_position = modelview * vec4(position, 1.0);

    /* Curvature of the planet */
    float distance_squared = pow(eye_position.x, 2) + pow(eye_position.z, 2);
    eye_position.y -= planet_radius - sqrt(pow(planet_radius, 2) - distance_squared);

    gl_Position = projection * eye_position;

    vec4 diffuse_factor
        = max(-dot(normal, light_direction), 0.0) * light_diffuse;
    vec4 ambient_diffuse_factor = diffuse_factor + light_ambient;

    frag_color = ambient_diffuse_factor * obj_diffuse;
}
";

static fragment_shader_src : &'static str = r"
#version 110

varying vec4 frag_color;

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

pub static WORLD_SIZE: uint = 4;
pub static CHUNK_SIZE: uint = 64;
pub static WORLD_SEED: u32 = 42;

static FRAME_TIME_TARGET_MS : u64 = 16;

struct GraphicsResources {
    program: GLuint,
    uniform_modelview: GLint,
    uniform_projection: GLint,
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    do native::start(argc, argv) {
        main();
    }
}

fn main() {
   glfw::set_error_callback(~ErrorContext);

    do glfw::start {
        let mut window_width = 800;
        let mut window_height = 600;

        let window = glfw::Window::create(window_width, window_height, "Hello, I am a window.", glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.set_cursor_mode(glfw::CursorDisabled);
        window.make_context_current();

        gl::load_with(glfw::get_proc_address);

        gl::Enable(gl::DEPTH_TEST);
        gl::Enable(gl::CULL_FACE);

        glfw::set_swap_interval(1);

        let graphics_resources = load_graphics_resources();

        gl::UseProgram(graphics_resources.program);

        let mut chunk_loader = chunk::ChunkLoader::new(WORLD_SEED, &graphics_resources);

        window.set_key_callback(~KeyContext);

        let (fb_size_port, fb_size_chan): (Port<(u32,u32)>, Chan<(u32,u32)>) = std::comm::Chan::new();
        window.set_framebuffer_size_callback(~FramebufferSizeContext { chan: fb_size_chan });

        let start_time = extra::time::precise_time_ns();
        let mut last_frame_time = start_time;
        let mut num_frames = 0;

        let mut camera_position = Vec3::<f32>::new(0.0f32, 20.0f32, 40.0f32);

        //let mut timer = Timer::new().unwrap();

        let mut needed_chunks : HashSet<(i64, i64)> = HashSet::new();
        let mut load_limiter = ratelimiter::RateLimiter::new(1000*1000*100);

        while !window.should_close() {
            let frame_start_time = extra::time::precise_time_ns();

            glfw::poll_events();

            loop {
                match fb_size_port.try_recv() {
                    Some((w,h)) => {
                        window_width = w;
                        window_height = h;
                    }
                    None => break
                }
            }

            let (cursor_x, cursor_y) = window.get_cursor_pos();
            let camera_angle_y = ((cursor_x * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;
            let camera_angle_x = ((cursor_y * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;

            let mut camera_velocity = Vec3::<f32>::new(0.0f32, 0.0f32, 0.0f32);

            match window.get_key(glfw::KeySpace) {
                glfw::Press => { camera_velocity.y += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyLeftControl) {
                glfw::Press => { camera_velocity.y += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyS) {
                glfw::Press => { camera_velocity.z += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyW) {
                glfw::Press => { camera_velocity.z += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyD) {
                glfw::Press => { camera_velocity.x += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyA) {
                glfw::Press => { camera_velocity.x += -1.0f32 }
                _ => {}
            }

            gl::Viewport(0,0, window_width as GLint, window_height as GLint);

            gl::ClearColor(0.0, 0.75, 1.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            let projection = cgmath::projection::perspective(
                rad(1.57f32),
                window_width as f32 / window_height as f32,
                0.1f32, 1000.0f32);

            unsafe {
                gl::UniformMatrix4fv(graphics_resources.uniform_projection, 1, gl::FALSE, cast::transmute(&projection));
            }

            let camera_translation = Mat4::<f32>::from_cols(
                Vec4::<f32>::unit_x(),
                Vec4::<f32>::unit_y(),
                Vec4::<f32>::unit_z(),
                camera_position.mul_s(-1.0f32).extend(1.0f32));
            let camera_rotation_x = Mat3::<f32>::from_angle_x(rad(camera_angle_x as f32)).to_mat4();
            let camera_rotation_y = Mat3::<f32>::from_angle_y(rad(camera_angle_y as f32)).to_mat4();
            let camera = camera_rotation_x.mul_m(&camera_rotation_y).mul_m(&camera_translation);

            let inv_camera_rotation = Mat3::<f32>::from_euler(rad(-camera_angle_x as f32), rad(-camera_angle_y as f32), rad(0.0f32));
            let absolute_camera_velocity = inv_camera_rotation.mul_v(&camera_velocity).mul_s(0.5f32);
            camera_position.add_self_v(&absolute_camera_velocity);

            let coords = visible_chunks(camera_position.x as i64,
                                        camera_position.z as i64);

            for &(cx, cz) in coords.iter() {
                match chunk_loader.cache.find_mut(&(cx, cz)) {
                    Some(chunk) => {
                        chunk.touch();

                        let chunk_translation = Mat4::<f32>::from_cols(
                            Vec4::<f32>::unit_x(),
                            Vec4::<f32>::unit_y(),
                            Vec4::<f32>::unit_z(),
                            Vec4::<f32>::new(chunk.x as f32, 0.0f32, chunk.z as f32, 1.0f32));

                        let modelview = camera.mul_m(&chunk_translation);

                        gl::BindVertexArray(chunk.vao);

                        unsafe {
                            gl::UniformMatrix4fv(graphics_resources.uniform_modelview, 1, gl::FALSE, cast::transmute(&modelview));
                            gl::DrawElements(gl::TRIANGLES, chunk.num_elements as i32, gl::UNSIGNED_INT, ptr::null());
                        }

                        gl::BindVertexArray(0);
                    },
                    None => {
                        needed_chunks.insert((cx, cz));
                    }
                }
            }

            window.swap_buffers();

            check_gl("main loop");

            if !needed_chunks.is_empty() && load_limiter.limit() {
                let mut loaded = None;

                for &(cx, cz) in needed_chunks.iter() {
                    chunk_loader.load(cx, cz);
                    loaded = Some((cx, cz));
                    break;
                }

                match loaded {
                    Some((cx, cz)) => {
                        needed_chunks.remove(&(cx, cz));
                    },
                    None => {}
                }
            }

            let cur_time = extra::time::precise_time_ns();
            num_frames += 1;
            if (cur_time - last_frame_time) > (1000*1000*1000) {
                println!("{} frames per second", num_frames);
                num_frames = 0;
                last_frame_time = cur_time;
            }

            let frame_end_time = extra::time::precise_time_ns();
            let frame_time_ms = (frame_end_time - frame_start_time)/(1000*1000);
            if (frame_time_ms < FRAME_TIME_TARGET_MS) {
                //timer.sleep(FRAME_TIME_TARGET_MS - frame_time_ms);
            }
        }
    }
}

fn visible_chunks(x: i64, z: i64) -> ~[(i64, i64)] {
    let mask : i64 = !(CHUNK_SIZE as i64 - 1);
    let mut coords = ~[];
    for ix in std::iter::range_inclusive(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
        for iz in std::iter::range_inclusive(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
            let cx : i64 = (x & mask) + ix*CHUNK_SIZE as i64;
            let cz : i64 = (z & mask) + iz*CHUNK_SIZE as i64;
            coords.push((cx, cz));
        }
    }
    coords
}

fn load_graphics_resources() -> GraphicsResources {
    let vs = compile_shader(vertex_shader_src.as_bytes(), gl::VERTEX_SHADER);
    let fs = compile_shader(fragment_shader_src.as_bytes(), gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let uniform_modelview = unsafe { "modelview".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };
    let uniform_projection = unsafe { "projection".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };

    return GraphicsResources {
        program: program,
        uniform_modelview: uniform_modelview,
        uniform_projection: uniform_projection,
    };

}

extern "C" {
    fn gluErrorString(error: GLenum) -> *GLubyte;
}

fn check_gl(message : &str) {
    let err = gl::GetError();
    if (err != gl::NO_ERROR) {
        unsafe {
            let err = std::str::raw::from_c_str(gluErrorString(err) as *i8);
            fail!("GL error {} at {}", err, message);
        }
    }
}

fn compile_shader(src: &[u8], ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        //transmute is used here because `as` causes ICE
        //wait a sec, is `src` null-terminated properly?
        gl::ShaderSource(shader, 1, std::cast::transmute(std::ptr::to_unsafe_ptr(&src.as_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(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    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(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    program
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        fail!("GLFW Error: {:s}", description);
    }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
    fn call(&self, window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
        match (action, key) {
            (glfw::Press, glfw::KeyEscape) => window.set_should_close(true),
            _ => {}
        }
    }
}

struct FramebufferSizeContext {
    chan: Chan<(u32,u32)>
}
impl glfw::FramebufferSizeCallback for FramebufferSizeContext {
    fn call(&self, _: &glfw::Window, width: i32, height: i32) {
        self.chan.send((width as u32,height as u32));
    }
}
<commit_msg>use ratelimiter for fps display<commit_after>#[feature(globs)];

extern mod native;
extern mod extra;
extern mod glfw;
extern mod gl;
extern mod cgmath;
extern mod noise;

use std::cast;
use std::ptr;
use std::str;
use std::vec;
use std::libc;
use std::io::Timer;
use std::hashmap::HashSet;

use gl::types::*;

use cgmath::matrix::Matrix;
use cgmath::matrix::Mat3;
use cgmath::matrix::Mat4;
use cgmath::matrix::ToMat4;
use cgmath::vector::Vector;
use cgmath::vector::Vec3;
use cgmath::vector::Vec4;
use cgmath::angle::rad;

#[link(name="GLU")]
extern {}

mod chunk;
mod ratelimiter;

static vertex_shader_src : &'static str = r"
#version 110

uniform mat4 modelview;
uniform mat4 projection;

attribute vec3 position;
attribute vec3 normal;

varying vec4 frag_color;

const vec4 obj_diffuse = vec4(0.2, 0.6, 0.2, 1.0);
const vec3 light_direction = vec3(0.408248, -0.816497, 0.408248);
const vec4 light_diffuse = vec4(0.8, 0.8, 0.8, 0.0);
const vec4 light_ambient = vec4(0.2, 0.2, 0.2, 1.0);

const float planet_radius = 6371000.0 / 10000.0;

void main() {
    vec4 eye_position = modelview * vec4(position, 1.0);

    /* Curvature of the planet */
    float distance_squared = pow(eye_position.x, 2) + pow(eye_position.z, 2);
    eye_position.y -= planet_radius - sqrt(pow(planet_radius, 2) - distance_squared);

    gl_Position = projection * eye_position;

    vec4 diffuse_factor
        = max(-dot(normal, light_direction), 0.0) * light_diffuse;
    vec4 ambient_diffuse_factor = diffuse_factor + light_ambient;

    frag_color = ambient_diffuse_factor * obj_diffuse;
}
";

static fragment_shader_src : &'static str = r"
#version 110

varying vec4 frag_color;

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

pub static WORLD_SIZE: uint = 4;
pub static CHUNK_SIZE: uint = 64;
pub static WORLD_SEED: u32 = 42;

static FRAME_TIME_TARGET_MS : u64 = 16;

struct GraphicsResources {
    program: GLuint,
    uniform_modelview: GLint,
    uniform_projection: GLint,
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    do native::start(argc, argv) {
        main();
    }
}

fn main() {
   glfw::set_error_callback(~ErrorContext);

    do glfw::start {
        let mut window_width = 800;
        let mut window_height = 600;

        let window = glfw::Window::create(window_width, window_height, "Hello, I am a window.", glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.set_cursor_mode(glfw::CursorDisabled);
        window.make_context_current();

        gl::load_with(glfw::get_proc_address);

        gl::Enable(gl::DEPTH_TEST);
        gl::Enable(gl::CULL_FACE);

        glfw::set_swap_interval(1);

        let graphics_resources = load_graphics_resources();

        gl::UseProgram(graphics_resources.program);

        let mut chunk_loader = chunk::ChunkLoader::new(WORLD_SEED, &graphics_resources);

        window.set_key_callback(~KeyContext);

        let (fb_size_port, fb_size_chan): (Port<(u32,u32)>, Chan<(u32,u32)>) = std::comm::Chan::new();
        window.set_framebuffer_size_callback(~FramebufferSizeContext { chan: fb_size_chan });

        let mut fps_display_limiter = ratelimiter::RateLimiter::new(1000*1000*1000);
        let mut fps_frame_counter = 0;

        let mut camera_position = Vec3::<f32>::new(0.0f32, 20.0f32, 40.0f32);

        //let mut timer = Timer::new().unwrap();

        let mut needed_chunks : HashSet<(i64, i64)> = HashSet::new();
        let mut load_limiter = ratelimiter::RateLimiter::new(1000*1000*100);

        while !window.should_close() {
            let frame_start_time = extra::time::precise_time_ns();

            glfw::poll_events();

            loop {
                match fb_size_port.try_recv() {
                    Some((w,h)) => {
                        window_width = w;
                        window_height = h;
                    }
                    None => break
                }
            }

            let (cursor_x, cursor_y) = window.get_cursor_pos();
            let camera_angle_y = ((cursor_x * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;
            let camera_angle_x = ((cursor_y * 0.0005) % 1.0) * std::f64::consts::PI * 2.0;

            let mut camera_velocity = Vec3::<f32>::new(0.0f32, 0.0f32, 0.0f32);

            match window.get_key(glfw::KeySpace) {
                glfw::Press => { camera_velocity.y += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyLeftControl) {
                glfw::Press => { camera_velocity.y += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyS) {
                glfw::Press => { camera_velocity.z += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyW) {
                glfw::Press => { camera_velocity.z += -1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyD) {
                glfw::Press => { camera_velocity.x += 1.0f32 }
                _ => {}
            }

            match window.get_key(glfw::KeyA) {
                glfw::Press => { camera_velocity.x += -1.0f32 }
                _ => {}
            }

            gl::Viewport(0,0, window_width as GLint, window_height as GLint);

            gl::ClearColor(0.0, 0.75, 1.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            let projection = cgmath::projection::perspective(
                rad(1.57f32),
                window_width as f32 / window_height as f32,
                0.1f32, 1000.0f32);

            unsafe {
                gl::UniformMatrix4fv(graphics_resources.uniform_projection, 1, gl::FALSE, cast::transmute(&projection));
            }

            let camera_translation = Mat4::<f32>::from_cols(
                Vec4::<f32>::unit_x(),
                Vec4::<f32>::unit_y(),
                Vec4::<f32>::unit_z(),
                camera_position.mul_s(-1.0f32).extend(1.0f32));
            let camera_rotation_x = Mat3::<f32>::from_angle_x(rad(camera_angle_x as f32)).to_mat4();
            let camera_rotation_y = Mat3::<f32>::from_angle_y(rad(camera_angle_y as f32)).to_mat4();
            let camera = camera_rotation_x.mul_m(&camera_rotation_y).mul_m(&camera_translation);

            let inv_camera_rotation = Mat3::<f32>::from_euler(rad(-camera_angle_x as f32), rad(-camera_angle_y as f32), rad(0.0f32));
            let absolute_camera_velocity = inv_camera_rotation.mul_v(&camera_velocity).mul_s(0.5f32);
            camera_position.add_self_v(&absolute_camera_velocity);

            let coords = visible_chunks(camera_position.x as i64,
                                        camera_position.z as i64);

            for &(cx, cz) in coords.iter() {
                match chunk_loader.cache.find_mut(&(cx, cz)) {
                    Some(chunk) => {
                        chunk.touch();

                        let chunk_translation = Mat4::<f32>::from_cols(
                            Vec4::<f32>::unit_x(),
                            Vec4::<f32>::unit_y(),
                            Vec4::<f32>::unit_z(),
                            Vec4::<f32>::new(chunk.x as f32, 0.0f32, chunk.z as f32, 1.0f32));

                        let modelview = camera.mul_m(&chunk_translation);

                        gl::BindVertexArray(chunk.vao);

                        unsafe {
                            gl::UniformMatrix4fv(graphics_resources.uniform_modelview, 1, gl::FALSE, cast::transmute(&modelview));
                            gl::DrawElements(gl::TRIANGLES, chunk.num_elements as i32, gl::UNSIGNED_INT, ptr::null());
                        }

                        gl::BindVertexArray(0);
                    },
                    None => {
                        needed_chunks.insert((cx, cz));
                    }
                }
            }

            window.swap_buffers();

            check_gl("main loop");

            if !needed_chunks.is_empty() && load_limiter.limit() {
                let mut loaded = None;

                for &(cx, cz) in needed_chunks.iter() {
                    chunk_loader.load(cx, cz);
                    loaded = Some((cx, cz));
                    break;
                }

                match loaded {
                    Some((cx, cz)) => {
                        needed_chunks.remove(&(cx, cz));
                    },
                    None => {}
                }
            }

            fps_frame_counter += 1;
            if fps_display_limiter.limit() {
                println!("{} frames per second", fps_frame_counter);
                fps_frame_counter = 0;
            }

            let frame_end_time = extra::time::precise_time_ns();
            let frame_time_ms = (frame_end_time - frame_start_time)/(1000*1000);
            if (frame_time_ms < FRAME_TIME_TARGET_MS) {
                //timer.sleep(FRAME_TIME_TARGET_MS - frame_time_ms);
            }
        }
    }
}

fn visible_chunks(x: i64, z: i64) -> ~[(i64, i64)] {
    let mask : i64 = !(CHUNK_SIZE as i64 - 1);
    let mut coords = ~[];
    for ix in std::iter::range_inclusive(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
        for iz in std::iter::range_inclusive(-(WORLD_SIZE as i64)/2, (WORLD_SIZE as i64)/2) {
            let cx : i64 = (x & mask) + ix*CHUNK_SIZE as i64;
            let cz : i64 = (z & mask) + iz*CHUNK_SIZE as i64;
            coords.push((cx, cz));
        }
    }
    coords
}

fn load_graphics_resources() -> GraphicsResources {
    let vs = compile_shader(vertex_shader_src.as_bytes(), gl::VERTEX_SHADER);
    let fs = compile_shader(fragment_shader_src.as_bytes(), gl::FRAGMENT_SHADER);
    let program = link_program(vs, fs);

    let uniform_modelview = unsafe { "modelview".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };
    let uniform_projection = unsafe { "projection".with_c_str(|ptr| gl::GetUniformLocation(program, ptr)) };

    return GraphicsResources {
        program: program,
        uniform_modelview: uniform_modelview,
        uniform_projection: uniform_projection,
    };

}

extern "C" {
    fn gluErrorString(error: GLenum) -> *GLubyte;
}

fn check_gl(message : &str) {
    let err = gl::GetError();
    if (err != gl::NO_ERROR) {
        unsafe {
            let err = std::str::raw::from_c_str(gluErrorString(err) as *i8);
            fail!("GL error {} at {}", err, message);
        }
    }
}

fn compile_shader(src: &[u8], ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        //transmute is used here because `as` causes ICE
        //wait a sec, is `src` null-terminated properly?
        gl::ShaderSource(shader, 1, std::cast::transmute(std::ptr::to_unsafe_ptr(&src.as_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(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    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(), buf.as_mut_ptr() as *mut GLchar);
            fail!(str::raw::from_utf8(buf).to_owned());
        }
    }
    program
}

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        fail!("GLFW Error: {:s}", description);
    }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
    fn call(&self, window: &glfw::Window, key: glfw::Key, _: libc::c_int, action: glfw::Action, _: glfw::Modifiers) {
        match (action, key) {
            (glfw::Press, glfw::KeyEscape) => window.set_should_close(true),
            _ => {}
        }
    }
}

struct FramebufferSizeContext {
    chan: Chan<(u32,u32)>
}
impl glfw::FramebufferSizeCallback for FramebufferSizeContext {
    fn call(&self, _: &glfw::Window, width: i32, height: i32) {
        self.chan.send((width as u32,height as u32));
    }
}
<|endoftext|>


<commit_before>extern crate llvm_sys as llvm;
use std::collections::hash_map::Entry;
use std::ffi::CString;
use std::ptr;
use self::llvm::prelude::*;

use node::*;
use env::Env;

pub struct VM {
    context: LLVMContextRef,
    builder: LLVMBuilderRef,
    module: LLVMModuleRef,
    int_value_type: LLVMTypeRef,
    prims: Env<String>,
}

macro_rules! cptr {
    ($x: expr) => (CString::new($x).unwrap().as_ptr())
}

impl VM {
    pub fn new() -> VM {
        let context = VM::create_context();
        let e = &mut Env::new();
        // alias
        e.register("+", "prim_add".to_string());
        e.register("-", "prim_sub".to_string());
        e.register("*", "prim_mul".to_string());
        e.register("/", "prim_div".to_string());

        VM {
            context: context,
            builder: VM::create_builder_in_context(context),
            module: VM::create_module_with_name("rlisp"),
            int_value_type: VM::int_type(context),
            prims: e.clone(),
        }
    }

    pub fn run(&self, node: &Node) {
        let env = &mut Env::new();
        self.init(env);
        self.pre_gen(node, env);
        self.llvm_ret(self.codegen(node, env));
        self.finalize();
    }

    fn init(&self, env: &mut Env<LLVMValueRef>) {
        self.register_symbols(env);

        // create main
        self.create_fun_and_set_bb("main", self.int_value_type, &mut []);
    }

    fn pre_gen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) {
        if let &Node::Cell(ref car, ref cdr) = ast {
            if rnil() == **cdr {
                self.pre_gen(car, env);
                return;
            }

            match sym_to_str(car) {
                Ok(x) => {
                    match x.as_ref() {
                        "define" => {
                            if let Node::Cell(ref ncar, ref ncdr) = **cdr {
                                // vm should know a type of the return value
                                // TODO: create LLVMValueRef wrapper struct
                                let sym_name = sym_to_str(ncar).unwrap();
                                let val = self.codegen(&rcar(ncdr).unwrap().clone(), env);
                                let ptr = match env.entry(sym_name.as_ref()) {
                                    Entry::Occupied(o) => *o.get(),
                                    Entry::Vacant(v) => {
                                        let p =
                                            self.allocate_mem(sym_name.as_ref(),
                                                              self.int_value_type);
                                        v.insert(p);
                                        p
                                    }
                                };
                                self.llmv_store(val, ptr);
                            }
                        }
                        _ => self.pre_gen(cdr, env),
                    }
                }
                Err(_) => {
                    self.pre_gen(car, env);
                    self.pre_gen(cdr, env);
                }
            }
        }
    }

    fn register_symbols(&self, env: &mut Env<LLVMValueRef>) {
        env.register("+", self.prim_arith("prim_add"));
        env.register("-", self.prim_arith("prim_sub"));
        env.register("*", self.prim_arith("prim_mul"));
        env.register("/", self.prim_arith("prim_div"));
    }

    fn finalize(&self) {
        unsafe {
            llvm::core::LLVMDumpModule(self.module);
            llvm::core::LLVMPrintModuleToFile(self.module, cptr!("out.ll"), ptr::null_mut());

            llvm::core::LLVMDisposeBuilder(self.builder);
            llvm::core::LLVMDisposeModule(self.module);
            llvm::core::LLVMContextDispose(self.context);
        }
    }

    fn prim_arith(&self, name: &str) -> LLVMValueRef {
        let ty = self.int_value_type;
        let arg_types = &mut [ty, ty];
        let fun = self.create_fun_and_set_bb(name, ty, arg_types);
        let lh = self.get_param_fun(&fun, 0);
        let rh = self.get_param_fun(&fun, 1);
        let v = match name {
            "prim_add" => self.llvm_add(lh, rh),
            "prim_sub" => self.llvm_sub(lh, rh),
            "prim_mul" => self.llvm_mul(lh, rh),
            "prim_div" => self.llvm_div(lh, rh),
            _ => {
                println!("{:?}", name);
                panic!("not support arith")
            }
        };
        self.llvm_ret(v);
        fun
    }

    fn llvm_ret(&self, ret: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildRet(self.builder, ret) }
    }

    fn llvm_add(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAdd(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_sub(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildSub(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_mul(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildMul(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_div(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildUDiv(self.builder, lh, rh, cptr!("v")) }
    }

    fn get_param_fun(&self, func: &LLVMValueRef, i: u32) -> LLVMValueRef {
        unsafe { llvm::core::LLVMGetParam(*func, i) }
    }

    fn count_params_fun(&self, func: &LLVMValueRef) -> u32 {
        unsafe { llvm::core::LLVMCountParams(*func) }
    }

    fn get_params_fun(&self, fun: &LLVMValueRef) -> Vec<LLVMValueRef> {
        let count = self.count_params_fun(fun) as usize;
        let p = {
            let buf = &mut Vec::with_capacity(count);
            buf.as_mut_ptr()
        };
        unsafe {
            // std::mem::forget(buf);
            llvm::core::LLVMGetParams(*fun, p);
            Vec::from_raw_parts(p, count, count)
        }
    }

    fn create_fun_and_set_bb(&self,
                             name: &str,
                             ret_ty: LLVMTypeRef,
                             arg_types: &mut [LLVMTypeRef])
                             -> LLVMValueRef {
        let fun_type = self.get_function_type(ret_ty, arg_types);
        let fun = self.add_function(name, fun_type);
        let bb = self.append_basic_block("entry", fun);
        self.set_builder_position_at_end(bb);
        fun
    }

    fn codegen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match *ast {
            Node::Int(val) => self.int_value(val as u64),
            Node::Cell(ref car, ref cdr) => {
                match **car {
                    Node::Sym(ref n) => self.apply_fun(env, n, cdr),
                    _ => panic!("not suport"),
                }
            }
            Node::Sym(ref name) => {
                let ptr = env.find(name).unwrap();
                self.build_load(*ptr, name)
            }
            ref a => {
                println!("{:?}", a);
                panic!("not support in codegen")
            }
        }
    }

    fn apply_fun(&self, env: &mut Env<LLVMValueRef>, name: &str, rest: &Node) -> LLVMValueRef {
        match name {
            "+" | "-" | "*" | "/" => self.codegen_arith(name, rest, env),
            "define" => {
                let c = rcar(rest).and_then(|v| sym_to_str(&v.clone())).unwrap();
                *env.find(c.as_ref()).unwrap()
            }
            "progn" => {
                env.push_local_scope();

                let mut vec = node_to_list(&mut rest.clone());
                let vec2 = vec.split_off(1);
                let mut ret = self.codegen(&vec[0], env);
                for v in vec2 {
                    ret = self.codegen(&v.clone(), env);
                }
                env.pop_local_scope();
                ret
            }
            _ => {
                // env.find(name)
                println!("at apply fun {:?}", name);
                panic!("unknow");
            }
        }
    }

    fn codegen_arith(&self, fname: &str, rest: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match rest {
            &Node::Cell(ref car, ref cdr) => {
                let lh = self.codegen(car, env); // to fix
                if **cdr == rnil() {
                    return lh;
                }
                let rh = self.codegen_arith(fname, cdr, env);
                let v = &fname.into();
                let name = self.prims.find(fname).unwrap_or(v);
                let fun = self.find_function(name).unwrap();
                let args = &mut Vec::new();
                args.push(lh);
                args.push(rh);
                unsafe {
                    llvm::core::LLVMBuildCall(self.builder, fun, args.as_mut_ptr(), 2, cptr!("v"))
                }

            }
            _ => panic!("siran"),
        }
    }

    fn codegen_list(&self, env: &mut Env<LLVMValueRef>, n: &Node) -> Vec<LLVMValueRef> {
        let args = &mut Vec::new();
        let mut node = n;
        while *node != rnil() {
            match node {
                &Node::Cell(ref car, ref cdr) => {
                    args.push(self.codegen(car, env));
                    node = cdr
                }
                _ => panic!("hgoe"),
            }
        }
        args.clone()
    }

    fn apply_codegen(&self,
                     env: &mut Env<LLVMValueRef>,
                     fun: LLVMValueRef,
                     rest: &Node)
                     -> LLVMValueRef {
        let args = self.codegen_list(env, rest);
        let mut_args = args.clone().as_mut_ptr();
        unsafe {
            llvm::core::LLVMBuildCall(self.builder, fun, mut_args, args.len() as u32, cptr!("v"))
        }
    }

    fn find_function(&self, name: &str) -> Option<LLVMValueRef> {
        let v = unsafe { llvm::core::LLVMGetNamedFunction(self.module, cptr!(name)) };
        let is_null = unsafe { llvm::core::LLVMIsNull(v) > 0 };
        if is_null { None } else { Some(v) }
    }

    fn int_value(&self, val: u64) -> LLVMValueRef {
        unsafe { llvm::core::LLVMConstInt(self.int_value_type, val, 0) }
    }

    fn allocate_mem(&self, name: &str, typ: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAlloca(self.builder, typ, cptr!(name)) }
    }

    fn build_load(&self, ptr: LLVMValueRef, name: &str) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildLoad(self.builder, ptr, cptr!(name)) }
    }

    fn llmv_store(&self, val: LLVMValueRef, target: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildStore(self.builder, val, target) }
    }

    fn set_builder_position_at_end(&self, bb: LLVMBasicBlockRef) {
        unsafe {
            llvm::core::LLVMPositionBuilderAtEnd(self.builder, bb);
        }
    }

    fn append_basic_block(&self, name: &str, fun: LLVMValueRef) -> LLVMBasicBlockRef {
        unsafe { llvm::core::LLVMAppendBasicBlockInContext(self.context, fun, cptr!(name)) }
    }

    fn get_function_type(&self,
                         ret_type: LLVMTypeRef,
                         args_type: &mut [LLVMTypeRef])
                         -> LLVMTypeRef {
        let l = args_type.len() as u32;
        if l == 0 {
            unsafe { llvm::core::LLVMFunctionType(ret_type, ptr::null_mut(), 0, 0) }
        } else {
            unsafe { llvm::core::LLVMFunctionType(ret_type, args_type.as_mut_ptr(), l, 0) }
        }
    }

    fn add_function(&self, name: &str, fun_type: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMAddFunction(self.module, cptr!(name), fun_type) }
    }

    fn create_module_with_name(name: &str) -> LLVMModuleRef {
        unsafe { llvm::core::LLVMModuleCreateWithName(cptr!(name)) }
    }

    fn create_builder_in_context(context: LLVMContextRef) -> LLVMBuilderRef {
        unsafe { llvm::core::LLVMCreateBuilderInContext(context) }
    }

    fn create_context() -> LLVMContextRef {
        unsafe { llvm::core::LLVMContextCreate() }
    }

    fn int_type(context: LLVMContextRef) -> LLVMTypeRef {
        unsafe { llvm::core::LLVMInt32TypeInContext(context) }
    }
}
<commit_msg>To make to return actual value (not pointer)<commit_after>extern crate llvm_sys as llvm;
use std::collections::hash_map::Entry;
use std::ffi::CString;
use std::ptr;
use self::llvm::prelude::*;

use node::*;
use env::Env;

pub struct VM {
    context: LLVMContextRef,
    builder: LLVMBuilderRef,
    module: LLVMModuleRef,
    int_value_type: LLVMTypeRef,
    prims: Env<String>,
}

macro_rules! cptr {
    ($x: expr) => (CString::new($x).unwrap().as_ptr())
}

impl VM {
    pub fn new() -> VM {
        let context = VM::create_context();
        let e = &mut Env::new();
        // alias
        e.register("+", "prim_add".to_string());
        e.register("-", "prim_sub".to_string());
        e.register("*", "prim_mul".to_string());
        e.register("/", "prim_div".to_string());

        VM {
            context: context,
            builder: VM::create_builder_in_context(context),
            module: VM::create_module_with_name("rlisp"),
            int_value_type: VM::int_type(context),
            prims: e.clone(),
        }
    }

    pub fn run(&self, node: &Node) {
        let env = &mut Env::new();
        self.init(env);
        self.pre_gen(node, env);
        self.llvm_ret(self.codegen(node, env));
        self.finalize();
    }

    fn init(&self, env: &mut Env<LLVMValueRef>) {
        self.register_symbols(env);

        // create main
        self.create_fun_and_set_bb("main", self.int_value_type, &mut []);
    }

    fn pre_gen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) {
        if let &Node::Cell(ref car, ref cdr) = ast {
            if rnil() == **cdr {
                self.pre_gen(car, env);
                return;
            }

            match sym_to_str(car) {
                Ok(x) => {
                    match x.as_ref() {
                        "define" => {
                            if let Node::Cell(ref ncar, ref ncdr) = **cdr {
                                // vm should know a type of the return value
                                // TODO: create LLVMValueRef wrapper struct
                                let sym_name = sym_to_str(ncar).unwrap();
                                let val = self.codegen(&rcar(ncdr).unwrap().clone(), env);
                                let ptr = match env.entry(sym_name.as_ref()) {
                                    Entry::Occupied(o) => *o.get(),
                                    Entry::Vacant(v) => {
                                        let p =
                                            self.allocate_mem(sym_name.as_ref(),
                                                              self.int_value_type);
                                        v.insert(p);
                                        p
                                    }
                                };
                                self.llmv_store(val, ptr);
                            }
                        }
                        _ => self.pre_gen(cdr, env),
                    }
                }
                Err(_) => {
                    self.pre_gen(car, env);
                    self.pre_gen(cdr, env);
                }
            }
        }
    }

    fn register_symbols(&self, env: &mut Env<LLVMValueRef>) {
        env.register("+", self.prim_arith("prim_add"));
        env.register("-", self.prim_arith("prim_sub"));
        env.register("*", self.prim_arith("prim_mul"));
        env.register("/", self.prim_arith("prim_div"));
    }

    fn finalize(&self) {
        unsafe {
            llvm::core::LLVMDumpModule(self.module);
            llvm::core::LLVMPrintModuleToFile(self.module, cptr!("out.ll"), ptr::null_mut());

            llvm::core::LLVMDisposeBuilder(self.builder);
            llvm::core::LLVMDisposeModule(self.module);
            llvm::core::LLVMContextDispose(self.context);
        }
    }

    fn prim_arith(&self, name: &str) -> LLVMValueRef {
        let ty = self.int_value_type;
        let arg_types = &mut [ty, ty];
        let fun = self.create_fun_and_set_bb(name, ty, arg_types);
        let lh = self.get_param_fun(&fun, 0);
        let rh = self.get_param_fun(&fun, 1);
        let v = match name {
            "prim_add" => self.llvm_add(lh, rh),
            "prim_sub" => self.llvm_sub(lh, rh),
            "prim_mul" => self.llvm_mul(lh, rh),
            "prim_div" => self.llvm_div(lh, rh),
            _ => {
                println!("{:?}", name);
                panic!("not support arith")
            }
        };
        self.llvm_ret(v);
        fun
    }

    fn llvm_ret(&self, ret: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildRet(self.builder, ret) }
    }

    fn llvm_add(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAdd(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_sub(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildSub(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_mul(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildMul(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_div(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildUDiv(self.builder, lh, rh, cptr!("v")) }
    }

    fn get_param_fun(&self, func: &LLVMValueRef, i: u32) -> LLVMValueRef {
        unsafe { llvm::core::LLVMGetParam(*func, i) }
    }

    fn count_params_fun(&self, func: &LLVMValueRef) -> u32 {
        unsafe { llvm::core::LLVMCountParams(*func) }
    }

    fn get_params_fun(&self, fun: &LLVMValueRef) -> Vec<LLVMValueRef> {
        let count = self.count_params_fun(fun) as usize;
        let p = {
            let buf = &mut Vec::with_capacity(count);
            buf.as_mut_ptr()
        };
        unsafe {
            // std::mem::forget(buf);
            llvm::core::LLVMGetParams(*fun, p);
            Vec::from_raw_parts(p, count, count)
        }
    }

    fn create_fun_and_set_bb(&self,
                             name: &str,
                             ret_ty: LLVMTypeRef,
                             arg_types: &mut [LLVMTypeRef])
                             -> LLVMValueRef {
        let fun_type = self.get_function_type(ret_ty, arg_types);
        let fun = self.add_function(name, fun_type);
        let bb = self.append_basic_block("entry", fun);
        self.set_builder_position_at_end(bb);
        fun
    }

    fn codegen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match *ast {
            Node::Int(val) => self.int_value(val as u64),
            Node::Cell(ref car, ref cdr) => {
                match **car {
                    Node::Sym(ref n) => self.apply_fun(env, n, cdr),
                    _ => panic!("not suport"),
                }
            }
            Node::Sym(ref name) => {
                let ptr = env.find(name).unwrap();
                self.build_load(*ptr, name)
            }
            ref a => {
                println!("{:?}", a);
                panic!("not support in codegen")
            }
        }
    }

    fn apply_fun(&self, env: &mut Env<LLVMValueRef>, name: &str, rest: &Node) -> LLVMValueRef {
        match name {
            "+" | "-" | "*" | "/" => self.codegen_arith(name, rest, env),
            "define" => {
                let c = rcar(rest).and_then(|v| sym_to_str(&v.clone())).unwrap();
                self.codegen(&Node::Sym(c), env)
            }
            "progn" => {
                env.push_local_scope();

                let mut vec = node_to_list(&mut rest.clone());
                let vec2 = vec.split_off(1);
                let mut ret = self.codegen(&vec[0], env);
                for v in vec2 {
                    ret = self.codegen(&v.clone(), env);
                }
                env.pop_local_scope();
                ret
            }
            _ => {
                // env.find(name)
                println!("at apply fun {:?}", name);
                panic!("unknow");
            }
        }
    }

    fn codegen_arith(&self, fname: &str, rest: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match rest {
            &Node::Cell(ref car, ref cdr) => {
                let lh = self.codegen(car, env); // to fix
                if **cdr == rnil() {
                    return lh;
                }
                let rh = self.codegen_arith(fname, cdr, env);
                let v = &fname.into();
                let name = self.prims.find(fname).unwrap_or(v);
                let fun = self.find_function(name).unwrap();
                let args = &mut Vec::new();
                args.push(lh);
                args.push(rh);
                unsafe {
                    llvm::core::LLVMBuildCall(self.builder, fun, args.as_mut_ptr(), 2, cptr!("v"))
                }

            }
            _ => panic!("siran"),
        }
    }

    fn codegen_list(&self, env: &mut Env<LLVMValueRef>, n: &Node) -> Vec<LLVMValueRef> {
        let args = &mut Vec::new();
        let mut node = n;
        while *node != rnil() {
            match node {
                &Node::Cell(ref car, ref cdr) => {
                    args.push(self.codegen(car, env));
                    node = cdr
                }
                _ => panic!("hgoe"),
            }
        }
        args.clone()
    }

    fn apply_codegen(&self,
                     env: &mut Env<LLVMValueRef>,
                     fun: LLVMValueRef,
                     rest: &Node)
                     -> LLVMValueRef {
        let args = self.codegen_list(env, rest);
        let mut_args = args.clone().as_mut_ptr();
        unsafe {
            llvm::core::LLVMBuildCall(self.builder, fun, mut_args, args.len() as u32, cptr!("v"))
        }
    }

    fn find_function(&self, name: &str) -> Option<LLVMValueRef> {
        let v = unsafe { llvm::core::LLVMGetNamedFunction(self.module, cptr!(name)) };
        let is_null = unsafe { llvm::core::LLVMIsNull(v) > 0 };
        if is_null { None } else { Some(v) }
    }

    fn int_value(&self, val: u64) -> LLVMValueRef {
        unsafe { llvm::core::LLVMConstInt(self.int_value_type, val, 0) }
    }

    fn allocate_mem(&self, name: &str, typ: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAlloca(self.builder, typ, cptr!(name)) }
    }

    fn build_load(&self, ptr: LLVMValueRef, name: &str) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildLoad(self.builder, ptr, cptr!(name)) }
    }

    fn llmv_store(&self, val: LLVMValueRef, target: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildStore(self.builder, val, target) }
    }

    fn set_builder_position_at_end(&self, bb: LLVMBasicBlockRef) {
        unsafe {
            llvm::core::LLVMPositionBuilderAtEnd(self.builder, bb);
        }
    }

    fn append_basic_block(&self, name: &str, fun: LLVMValueRef) -> LLVMBasicBlockRef {
        unsafe { llvm::core::LLVMAppendBasicBlockInContext(self.context, fun, cptr!(name)) }
    }

    fn get_function_type(&self,
                         ret_type: LLVMTypeRef,
                         args_type: &mut [LLVMTypeRef])
                         -> LLVMTypeRef {
        let l = args_type.len() as u32;
        if l == 0 {
            unsafe { llvm::core::LLVMFunctionType(ret_type, ptr::null_mut(), 0, 0) }
        } else {
            unsafe { llvm::core::LLVMFunctionType(ret_type, args_type.as_mut_ptr(), l, 0) }
        }
    }

    fn add_function(&self, name: &str, fun_type: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMAddFunction(self.module, cptr!(name), fun_type) }
    }

    fn create_module_with_name(name: &str) -> LLVMModuleRef {
        unsafe { llvm::core::LLVMModuleCreateWithName(cptr!(name)) }
    }

    fn create_builder_in_context(context: LLVMContextRef) -> LLVMBuilderRef {
        unsafe { llvm::core::LLVMCreateBuilderInContext(context) }
    }

    fn create_context() -> LLVMContextRef {
        unsafe { llvm::core::LLVMContextCreate() }
    }

    fn int_type(context: LLVMContextRef) -> LLVMTypeRef {
        unsafe { llvm::core::LLVMInt32TypeInContext(context) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! # Usage
//!
//! You can import the pointer style loader and type aliases like so:
//!
//! ~~~rust
//! extern crate gl;
//! // include the OpenGL type aliases
//! use gl::types::*;
//! ~~~
//!
//! You can load the function pointers into their respective function pointers
//! using the `load_with` function. You must supply a loader function from your
//! context library, This is how it would look using [glfw-rs]
//! (https://github.com/bjz/glfw-rs):
//!
//! ~~~rust
//! // the supplied function must be of the type:
//! // `&fn(symbol: &str) -> Option<extern "C" fn()>`
//! gl::load_with(|s| glfw.get_proc_address(s));
//!
//! // loading a specific function pointer
//! gl::Viewport::load_with(|s| glfw.get_proc_address(s));
//! ~~~
//!
//! Calling a function that has not been loaded will result in a failure like:
//! `fail!("gl::Viewport was not loaded")`, which aviods a segfault. This feature
//! does not cause any run time overhead because the failing functions are
//! assigned only when `load_with` is called.
//!
//! ~~~rust
//! // accessing an enum
//! gl::RED_BITS;
//!
//! // calling a function
//! gl::DrawArrays(gl::TRIANGLES, 0, 3);
//!
//! // functions that take pointers are unsafe
//! unsafe { gl::ShaderSource(shader, 1, &c_str, std::ptr::null()) };
//! ~~~
//!
//! Each function pointer has an associated boolean value allowing you to
//! check if a function has been loaded at run time. The function accesses a
//! corresponding global boolean that is set when `load_with` is called, so there
//! shouldn't be much overhead.
//!
//! ~~~rust
//! if gl::Viewport::is_loaded() {
//!     // do something...
//! }
//! ~~~
//!

#![crate_name = "gl"]
#![comment = "An OpenGL function loader."]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(macro_rules)]
#![feature(globs)]
#![feature(phase)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case_functions)]
#![allow(unused_variable)]

#[phase(plugin)]
extern crate gl_generator;
extern crate libc;

use std::mem;
use self::types::*;

generate_gl_bindings!("gl", "core", "4.5", "static", [ "GL_EXT_texture_filter_anisotropic" ])
<commit_msg>Fix rustdoc --test again<commit_after>// Copyright 2013 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! # Usage
//!
//! You can import the pointer style loader and type aliases like so:
//!
//! ~~~no_run
//! # #![feature(globs)]
//! # #![allow(unused_imports)]
//! extern crate gl;
//! # fn main() {
//! // include the OpenGL type aliases
//! use gl::types::*;
//! # }
//! ~~~
//!
//! You can load the function pointers into their respective function pointers
//! using the `load_with` function. You must supply a loader function from your
//! context library, This is how it would look using [glfw-rs]
//! (https://github.com/bjz/glfw-rs):
//!
//! ~~~ignore
//! // the supplied function must be of the type:
//! // `&fn(symbol: &str) -> Option<extern "C" fn()>`
//! gl::load_with(|s| glfw.get_proc_address(s));
//!
//! // loading a specific function pointer
//! gl::Viewport::load_with(|s| glfw.get_proc_address(s));
//! ~~~
//!
//! Calling a function that has not been loaded will result in a failure like:
//! `fail!("gl::Viewport was not loaded")`, which aviods a segfault. This feature
//! does not cause any run time overhead because the failing functions are
//! assigned only when `load_with` is called.
//!
//! ~~~no_run
//! # #![allow(path_statement)]
//! # extern crate gl;
//! # fn main() {
//! // accessing an enum
//! gl::TEXTURE_2D;
//!
//! // calling a function
//! gl::DrawArrays(gl::TRIANGLES, 0, 3);
//!
//! // functions that take pointers are unsafe
//! # let shader = 0;
//! # let c_str: *const i8 = std::ptr::null();
//! unsafe { gl::ShaderSource(shader, 1, &c_str, std::ptr::null()) };
//! # }
//! ~~~
//!
//! Each function pointer has an associated boolean value allowing you to
//! check if a function has been loaded at run time. The function accesses a
//! corresponding global boolean that is set when `load_with` is called, so there
//! shouldn't be much overhead.
//!
//! ~~~no_run
//! if gl::Viewport::is_loaded() {
//!     // do something...
//! }
//! ~~~
//!

#![crate_name = "gl"]
#![comment = "An OpenGL function loader."]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(macro_rules)]
#![feature(globs)]
#![feature(phase)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case_functions)]
#![allow(unused_variable)]

#[phase(plugin)]
extern crate gl_generator;
extern crate libc;

use std::mem;
use self::types::*;

generate_gl_bindings!("gl", "core", "4.5", "static", [ "GL_EXT_texture_filter_anisotropic" ])
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
use core::marker::PhantomData;

use void::Void;

use arch::Registers;
use stack;
use debug::StackId;

/// Context is the heart of libfringe.
/// A context represents a saved thread of execution, along with a stack.
/// It can be swapped into and out of with the swap method,
/// and once you're done with it, you can get the stack back through unwrap.
///
/// Every operation is unsafe, because libfringe can't make any guarantees
/// about the state of the context.
#[derive(Debug)]
pub struct Context<'a, Stack: stack::Stack> {
  regs: Registers,
  _stack_id: StackId,
  stack: Stack,
  _ref: PhantomData<&'a ()>
}

unsafe impl<'a, Stack> Send for Context<'a, Stack>
  where Stack: stack::Stack + Send {}

impl<'a, Stack> Context<'a, Stack> where Stack: stack::Stack {
  /// Create a new Context. When it is swapped into,
  /// it will call the passed closure.
  #[inline]
  pub unsafe fn new<F>(mut stack: Stack, f: F) -> Context<'a, Stack>
    where F: FnOnce() -> Void + Send + 'a {
    let stack_id = StackId::register(&mut stack);
    let regs = Registers::new(&mut stack, f);
    Context {
      regs: regs,
      _stack_id: stack_id,
      stack: stack,
      _ref: PhantomData
    }
  }

  /// Switch to the context, saving the current thread of execution there.
  #[inline(always)]
  pub unsafe fn swap(&mut self) {
    Context::swap2(self, self)
  }

  /// Switch to in_ctx, saving the current thread of execution to out_ctx.
  #[inline(always)]
  pub unsafe fn swap2(out_ctx: *mut Context<'a, Stack>, in_ctx: *const Context<'a, Stack>) {
    Registers::swap2(&mut (*out_ctx).regs, &(*in_ctx).regs)
  }

  /// Unwrap the context, returning the stack it contained.
  #[inline]
  pub unsafe fn unwrap(self) -> Stack {
    self.stack
  }
}
<commit_msg>at least allow different lifetimes in Context::swap2<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) Nathan Zadoks <nathan@nathan7.eu>
// See the LICENSE file included in this distribution.
use core::marker::PhantomData;

use void::Void;

use arch::Registers;
use stack;
use debug::StackId;

/// Context is the heart of libfringe.
/// A context represents a saved thread of execution, along with a stack.
/// It can be swapped into and out of with the swap method,
/// and once you're done with it, you can get the stack back through unwrap.
///
/// Every operation is unsafe, because libfringe can't make any guarantees
/// about the state of the context.
#[derive(Debug)]
pub struct Context<'a, Stack: stack::Stack> {
  regs: Registers,
  _stack_id: StackId,
  stack: Stack,
  _ref: PhantomData<&'a ()>
}

unsafe impl<'a, Stack> Send for Context<'a, Stack>
  where Stack: stack::Stack + Send {}

impl<'a, Stack> Context<'a, Stack> where Stack: stack::Stack {
  /// Create a new Context. When it is swapped into,
  /// it will call the passed closure.
  #[inline]
  pub unsafe fn new<F>(mut stack: Stack, f: F) -> Context<'a, Stack>
    where F: FnOnce() -> Void + Send + 'a {
    let stack_id = StackId::register(&mut stack);
    let regs = Registers::new(&mut stack, f);
    Context {
      regs: regs,
      _stack_id: stack_id,
      stack: stack,
      _ref: PhantomData
    }
  }

  /// Switch to the context, saving the current thread of execution there.
  #[inline(always)]
  pub unsafe fn swap(&mut self) {
    Context::swap2(self, self)
  }

  /// Switch to in_ctx, saving the current thread of execution to out_ctx.
  #[inline(always)]
  pub unsafe fn swap2<'b>(out_ctx: *mut Context<'a, Stack>, in_ctx: *const Context<'b, Stack>) {
    Registers::swap2(&mut (*out_ctx).regs, &(*in_ctx).regs)
  }

  /// Unwrap the context, returning the stack it contained.
  #[inline]
  pub unsafe fn unwrap(self) -> Stack {
    self.stack
  }
}
<|endoftext|>


<commit_before>

use sdl2::{self, Sdl};
use sdl2::surface;
use sdl2::pixels;
use image::{self, GenericImage};

use std::fmt;
use std::io::Read;

use audio;
use conf;
use filesystem::Filesystem;
use graphics;
use timer;
use GameError;
use GameResult;

/// A `Context` is an object that holds on to global resources.
/// It basically tracks hardware state such as the screen, audio
/// system, timers, and so on.  Generally this type is **not** thread-
/// safe and only one `Context` can exist at a time.  Trying to create
/// another one will fail.
///
/// Most functions that interact with the hardware, for instance
/// drawing things, playing sounds, or loading resources (which then
/// need to be transformed into a format the hardware likes) will need
/// to access the `Context`.
pub struct Context {
    pub conf: conf::Conf,
    pub sdl_context: Sdl,
    pub filesystem: Filesystem,
    pub gfx_context: graphics::GraphicsContext,
    pub event_context: sdl2::EventSubsystem,
    pub timer_context: timer::TimeContext,
    pub dpi: (f32, f32, f32),
    pub audio_context: audio::AudioContext,
}

impl fmt::Debug for Context {
    // TODO: Make this more useful.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Context: {:p}>", self)
    }
}

/// Sets the window icon from the Conf window_icon field.
/// Assumes an empty string in the conf's window_icon
/// means to do nothing.
fn set_window_icon(context: &mut Context) -> GameResult<()> {
    if !context.conf.window_icon.is_empty() {
        // Grrr, hackhackhack here with the icon path clone.
        // BUGGO: TODO: Fix this too since we no longer use SDL_image
        let icon_path = context.conf.window_icon.clone();
        let mut f = context.filesystem.open(icon_path)?;
        let mut buf = Vec::new();
        f.read_to_end(&mut buf)?;
        let image = image::load_from_memory(&buf)?;
        let image_data = &mut image.to_rgba();
        let surface = surface::Surface::from_data(
            image_data, image.width(),
            image.height(), 4,
            pixels::PixelFormatEnum::RGBA8888)?;
        let window = context.gfx_context.get_window();
        window.set_icon(surface);
    };
    Ok(())
}

impl Context {
    /// Tries to create a new Context using settings from the given config file.
    /// Usually called by the engine as part of the set-up code.
    pub fn from_conf(conf: conf::Conf, fs: Filesystem, sdl_context: Sdl) -> GameResult<Context> {

        // let window = {

        //     let window_title = &conf.window_title;
        //     init_window(video, &window_title, screen_width, screen_height)?
        // };

        // BUGGO: TODO: Make this part of the GraphicsContext
        // let display_index = window.display_index()?;
        // let dpi = window.subsystem().display_dpi(display_index)?;
        let dpi = (75.0, 75.0, 75.0);
        let video = sdl_context.video()?;

        let audio_context = audio::AudioContext::new()?;
        let event_context = sdl_context.event()?;
        let timer_context = timer::TimeContext::new();
        let graphics_context = graphics::GraphicsContext::new(video,
                                                              &conf.window_title,
                                                              conf.window_width,
                                                              conf.window_height,
                                                              conf.vsync)?;

        let mut ctx = Context {
            conf: conf,
            sdl_context: sdl_context,
            filesystem: fs,
            gfx_context: graphics_context,
            dpi: dpi,

            event_context: event_context,
            timer_context: timer_context,

            audio_context: audio_context,
        };

        set_window_icon(&mut ctx)?;

        Ok(ctx)
    }

    /// Tries to create a new Context loading a config
    /// file from its default path, using the given Conf
    /// object as a default if none is found.
    pub fn load_from_conf(id: &'static str,
                          author: &'static str,
                          default_config: conf::Conf)
                          -> GameResult<Context> {

        let sdl_context = sdl2::init()?;
        let mut fs = Filesystem::new(id, author)?;

        // TODO: Verify config version == this version
        let config = fs.read_config().unwrap_or(default_config);

        Context::from_conf(config, fs, sdl_context)

    }

    /// Prints out information on the resources subsystem.
    pub fn print_resource_stats(&mut self) {
        match self.filesystem.print_all() {
            Err(e) => println!("Error printing out filesystem info: {}", e),
            _ => (),
        }
    }

    /// Triggers a Quit event.
    pub fn quit(&mut self) -> GameResult<()> {
        let now_dur = timer::get_time_since_start(self);
        let now = timer::duration_to_f64(now_dur);
        let e = sdl2::event::Event::Quit { timestamp: now as u32 };
        // println!("Pushing event {:?}", e);
        self.event_context
            .push_event(e)
            .map_err(GameError::from)
    }
}
<commit_msg>Got set_window_icon() working.<commit_after>

use sdl2::{self, Sdl};
use sdl2::surface;
use sdl2::pixels;
use image::{self, GenericImage};

use std::fmt;
use std::io::Read;

use audio;
use conf;
use filesystem::Filesystem;
use graphics;
use timer;
use GameError;
use GameResult;

/// A `Context` is an object that holds on to global resources.
/// It basically tracks hardware state such as the screen, audio
/// system, timers, and so on.  Generally this type is **not** thread-
/// safe and only one `Context` can exist at a time.  Trying to create
/// another one will fail.
///
/// Most functions that interact with the hardware, for instance
/// drawing things, playing sounds, or loading resources (which then
/// need to be transformed into a format the hardware likes) will need
/// to access the `Context`.
pub struct Context {
    pub conf: conf::Conf,
    pub sdl_context: Sdl,
    pub filesystem: Filesystem,
    pub gfx_context: graphics::GraphicsContext,
    pub event_context: sdl2::EventSubsystem,
    pub timer_context: timer::TimeContext,
    pub dpi: (f32, f32, f32),
    pub audio_context: audio::AudioContext,
}

impl fmt::Debug for Context {
    // TODO: Make this more useful.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Context: {:p}>", self)
    }
}

/// Sets the window icon from the Conf window_icon field.
/// Assumes an empty string in the conf's window_icon
/// means to do nothing.
fn set_window_icon(context: &mut Context) -> GameResult<()> {
    if !context.conf.window_icon.is_empty() {
        // Grrr, hackhackhack here with the icon path clone.
        // BUGGO: TODO: Fix this too since we no longer use SDL_image
        let icon_path = context.conf.window_icon.clone();
        let mut f = context.filesystem.open(icon_path)?;
        let mut buf = Vec::new();
        f.read_to_end(&mut buf)?;
        let image = image::load_from_memory(&buf)?;
        let image_data = &mut image.to_rgba();
        // The "pitch" parameter here is not the count
        // between pixels, but the count between rows.
        // For some retarded reason.
        // Also it seems to have strange ideas of what
        // "RGBA" means.
        let surface = surface::Surface::from_data(
            image_data, image.width(),
            image.height(), image.width() * 4,
            pixels::PixelFormatEnum::ABGR8888)?;
        let window = context.gfx_context.get_window();
        window.set_icon(surface);
    };
    Ok(())
}

impl Context {
    /// Tries to create a new Context using settings from the given config file.
    /// Usually called by the engine as part of the set-up code.
    pub fn from_conf(conf: conf::Conf, fs: Filesystem, sdl_context: Sdl) -> GameResult<Context> {

        // let window = {

        //     let window_title = &conf.window_title;
        //     init_window(video, &window_title, screen_width, screen_height)?
        // };

        // BUGGO: TODO: Make this part of the GraphicsContext
        // let display_index = window.display_index()?;
        // let dpi = window.subsystem().display_dpi(display_index)?;
        let dpi = (75.0, 75.0, 75.0);
        let video = sdl_context.video()?;

        let audio_context = audio::AudioContext::new()?;
        let event_context = sdl_context.event()?;
        let timer_context = timer::TimeContext::new();
        let graphics_context = graphics::GraphicsContext::new(video,
                                                              &conf.window_title,
                                                              conf.window_width,
                                                              conf.window_height,
                                                              conf.vsync)?;

        let mut ctx = Context {
            conf: conf,
            sdl_context: sdl_context,
            filesystem: fs,
            gfx_context: graphics_context,
            dpi: dpi,

            event_context: event_context,
            timer_context: timer_context,

            audio_context: audio_context,
        };

        set_window_icon(&mut ctx)?;

        Ok(ctx)
    }

    /// Tries to create a new Context loading a config
    /// file from its default path, using the given Conf
    /// object as a default if none is found.
    pub fn load_from_conf(id: &'static str,
                          author: &'static str,
                          default_config: conf::Conf)
                          -> GameResult<Context> {

        let sdl_context = sdl2::init()?;
        let mut fs = Filesystem::new(id, author)?;

        // TODO: Verify config version == this version
        let config = fs.read_config().unwrap_or(default_config);

        Context::from_conf(config, fs, sdl_context)

    }

    /// Prints out information on the resources subsystem.
    pub fn print_resource_stats(&mut self) {
        match self.filesystem.print_all() {
            Err(e) => println!("Error printing out filesystem info: {}", e),
            _ => (),
        }
    }

    /// Triggers a Quit event.
    pub fn quit(&mut self) -> GameResult<()> {
        let now_dur = timer::get_time_since_start(self);
        let now = timer::duration_to_f64(now_dur);
        let e = sdl2::event::Event::Quit { timestamp: now as u32 };
        // println!("Pushing event {:?}", e);
        self.event_context
            .push_event(e)
            .map_err(GameError::from)
    }
}
<|endoftext|>