<commit_before>//! This module contains the game logic

use std::f64;
use std::env::current_exe;

use graphics::{self, Transformed};
use itertools;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::*;
use rand::{self, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

const UPS: u16 = 120;
const BULLET_RATE: f64 = 0.01;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        let exe_directory = current_exe().unwrap().parent().unwrap().to_owned();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources { font: GlyphCache::new(&exe_directory.join("resources/FiraMono-Bold.ttf")).unwrap() }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Processes a button press
    pub fn button_press(&mut self, controller: ControllerButton) {
        self.handle_button(controller, true);
    }

    /// Processes a button release
    pub fn button_release(&mut self, controller: ControllerButton) {
        self.handle_button(controller, false);
    }

    /// Handles a button press or release
    fn handle_button(&mut self, controller: ControllerButton, pressed: bool) {
        // Button 10 is A button on XInput
        match controller.button {
            10 => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Handles a controller axis input
    pub fn handle_axis(&mut self, controller: ControllerAxisArgs) {

        // Axis 0 is left stick (XInput). -1.0 left to 1.0 right
        if controller.axis == 0 {
            match controller.position {
                -1.0 ... -0.2 => {
                    self.actions.rotate_left = true;
                    self.actions.rotate_right = false;
                },
                0.2 ... 1.0 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = true;
                },
                -0.199 ... 0.199 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = false;
                },
                _ => {}
            }
        }

        // Axis 5 is right trigger (XInput). -1.0 is not pressed, 1.0 is fully pressed
        if controller.axis == 5 {
            match controller.position {
                -0.8 ... 1.0 => {
                    self.actions.boost = true;
                },
                -1.0 ... -0.799 => {
                    self.actions.boost = false;
                },
                _ => {}
            }
        }

        // TODO: Actually use stick position value to affect rotation amount
        //       Actually use trigger position value affect boost amount
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: graphics::context::Context, g: &mut GlGraphics) {
        // Clear everything
        graphics::clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        let mut text = graphics::Text::new(22);
        text.color = color::ORANGE;
        text.draw(&format!("Score: {}", self.score),
                  &mut self.resources.font,
                  &c.draw_state,
                  c.trans(10.0, 20.0).transform,
                  g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += (-0.06 * UPS as f64) * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += (0.06 * UPS as f64) * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 400.0  } else { 200.0 };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > 0.05 {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(), 0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(), self.world.player.direction())));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * 500.0);
        }

        // Remove bullets outside the viewport
        { // Shorten the lifetime of size
        let size = &self.world.size;
        self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > 1.0 {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy: Enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * 100.0, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        { // We introduce a scope to shorten the lifetime of the borrows below
        // The references are to avoid using self in the closure
        // (the borrow checker doesn't like that)
        let bullets = &mut self.world.bullets;
        let enemies = &mut self.world.enemies;
        let particles = &mut self.world.particles;

        bullets.retain(|bullet| {
            // Remove the first enemy that collides with a bullet (if any)
            // Add an explosion on its place
            if let Some((index, position)) = enemies.iter().enumerate()
                .find(|&(_, enemy)| enemy.collides_with(bullet))
                .map(|(index, enemy)| (index, enemy.position()))
            {
                Game::make_explosion(particles, position, 10);
                enemies.remove(index);
                false
            } else {
                true
            }
        });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    /// Generates a new explosion of the given intensity at the given position. This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<commit_msg>Expand glob import.<commit_after>//! This module contains the game logic

use std::f64;
use std::env::current_exe;

use graphics::{self, Transformed};
use itertools;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{ControllerButton, ControllerAxisArgs, Key};
use rand::{self, ThreadRng};

use drawing::{color, Point, Size};
use models::{Bullet, Enemy, Particle, Vector, World};
use traits::{Advance, Collide, Position};

const UPS: u16 = 120;
const BULLET_RATE: f64 = 0.01;

/// The data structure that drives the game
pub struct Game {
    /// The world contains everything that needs to be drawn
    world: World,
    /// The current score of the player
    score: u32,
    /// The active actions
    actions: Actions,
    /// Timers needed by the game
    timers: Timers,
    /// A random number generator
    rng: ThreadRng,
    /// Resources needed for drawing
    resources: Resources
}

/// Active actions (toggled by user input)
#[derive(Default)]
struct Actions {
    rotate_left: bool,
    rotate_right: bool,
    boost: bool,
    shoot: bool
}

/// Timers to handle creation of bullets, enemies and particles
#[derive(Default)]
struct Timers {
    current_time: f64,
    last_tail_particle: f64,
    last_shoot: f64,
    last_spawned_enemy: f64
}

/// Additional resources needed for the game
struct Resources {
    font: GlyphCache<'static>
}

impl Game {
    /// Returns a new `Game` containing a `World` of the given `Size`
    pub fn new(size: Size) -> Game {
        let mut rng = rand::thread_rng();
        let exe_directory = current_exe().unwrap().parent().unwrap().to_owned();
        Game {
            world: World::new(&mut rng, size),
            score: 0,
            actions: Actions::default(),
            timers: Timers::default(),
            rng: rng,
            resources: Resources { font: GlyphCache::new(&exe_directory.join("resources/FiraMono-Bold.ttf")).unwrap() }
        }
    }

    /// Processes a key press
    pub fn key_press(&mut self, key: Key) {
        self.handle_key(key, true);
    }

    /// Processes a key release
    pub fn key_release(&mut self, key: Key) {
        self.handle_key(key, false);
    }

    /// Handles a key press or release
    fn handle_key(&mut self, key: Key, pressed: bool) {
        match key {
            Key::Left => self.actions.rotate_left = pressed,
            Key::Right => self.actions.rotate_right = pressed,
            Key::Up => self.actions.boost = pressed,
            Key::Space => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Processes a button press
    pub fn button_press(&mut self, controller: ControllerButton) {
        self.handle_button(controller, true);
    }

    /// Processes a button release
    pub fn button_release(&mut self, controller: ControllerButton) {
        self.handle_button(controller, false);
    }

    /// Handles a button press or release
    fn handle_button(&mut self, controller: ControllerButton, pressed: bool) {
        // Button 10 is A button on XInput
        match controller.button {
            10 => self.actions.shoot = pressed,
            _ => ()
        }
    }

    /// Handles a controller axis input
    pub fn handle_axis(&mut self, controller: ControllerAxisArgs) {

        // Axis 0 is left stick (XInput). -1.0 left to 1.0 right
        if controller.axis == 0 {
            match controller.position {
                -1.0 ... -0.2 => {
                    self.actions.rotate_left = true;
                    self.actions.rotate_right = false;
                },
                0.2 ... 1.0 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = true;
                },
                -0.199 ... 0.199 => {
                    self.actions.rotate_left = false;
                    self.actions.rotate_right = false;
                },
                _ => {}
            }
        }

        // Axis 5 is right trigger (XInput). -1.0 is not pressed, 1.0 is fully pressed
        if controller.axis == 5 {
            match controller.position {
                -0.8 ... 1.0 => {
                    self.actions.boost = true;
                },
                -1.0 ... -0.799 => {
                    self.actions.boost = false;
                },
                _ => {}
            }
        }

        // TODO: Actually use stick position value to affect rotation amount
        //       Actually use trigger position value affect boost amount
    }

    /// Renders the game to the screen
    pub fn render(&mut self, c: graphics::context::Context, g: &mut GlGraphics) {
        // Clear everything
        graphics::clear(color::BLACK, g);

        // Render the world
        self.world.render(c, g);

        // Render the score
        let mut text = graphics::Text::new(22);
        text.color = color::ORANGE;
        text.draw(&format!("Score: {}", self.score),
                  &mut self.resources.font,
                  &c.draw_state,
                  c.trans(10.0, 20.0).transform,
                  g);
    }

    /// Updates the game
    ///
    /// `dt` is the amount of seconds that have passed since the last update
    pub fn update(&mut self, dt: f64) {
        self.timers.current_time += dt;

        // Update rocket rotation
        if self.actions.rotate_left {
            *self.world.player.direction_mut() += (-0.06 * UPS as f64) * dt;
        }
        if self.actions.rotate_right {
            *self.world.player.direction_mut() += (0.06 * UPS as f64) * dt;
        };

        // Set speed and advance the player with wrap around
        let speed = if self.actions.boost { 400.0  } else { 200.0 };
        self.world.player.advance_wrapping(dt * speed, self.world.size.clone());

        // Update particles
        for particle in &mut self.world.particles {
            particle.update(dt);
        }

        // Remove old particles
        self.world.particles.retain(|p| p.ttl > 0.0);

        // Add new particles at the player's position, to leave a trail
        if self.timers.current_time - self.timers.last_tail_particle > 0.05 {
            self.timers.last_tail_particle = self.timers.current_time;
            self.world.particles.push(Particle::new(self.world.player.vector.clone().invert(), 0.5));
        }

        // Add bullets
        if self.actions.shoot && self.timers.current_time - self.timers.last_shoot > BULLET_RATE {
            self.timers.last_shoot = self.timers.current_time;
            self.world.bullets.push(Bullet::new(Vector::new(self.world.player.nose(), self.world.player.direction())));
        }

        // Advance bullets
        for bullet in &mut self.world.bullets {
            bullet.update(dt * 500.0);
        }

        // Remove bullets outside the viewport
        { // Shorten the lifetime of size
        let size = &self.world.size;
        self.world.bullets.retain(|b| size.contains(b.position()));
        }

        // Spawn enemies at random locations
        if self.timers.current_time - self.timers.last_spawned_enemy > 1.0 {
            self.timers.last_spawned_enemy = self.timers.current_time;
            let mut new_enemy: Enemy;
            loop {
                new_enemy = Enemy::new(Vector::random(&mut self.rng, self.world.size.clone()));
                if !self.world.player.collides_with(&new_enemy) {
                    break;
                }
            }
            self.world.enemies.push(new_enemy);
        }

        // Move enemies in the player's direction
        for enemy in &mut self.world.enemies {
            enemy.update(dt * 100.0, self.world.player.position());
        }

        self.handle_player_collisions();
        self.handle_bullet_collisions();
    }

    /// Handles collisions between the bullets and the enemies
    ///
    /// When an enemy is reached by a bullet, both the enemy and the bullet
    /// will be removed. Additionally, the score will be increased by 10
    fn handle_bullet_collisions(&mut self) {
        let old_enemy_count = self.world.enemies.len();

        { // We introduce a scope to shorten the lifetime of the borrows below
        // The references are to avoid using self in the closure
        // (the borrow checker doesn't like that)
        let bullets = &mut self.world.bullets;
        let enemies = &mut self.world.enemies;
        let particles = &mut self.world.particles;

        bullets.retain(|bullet| {
            // Remove the first enemy that collides with a bullet (if any)
            // Add an explosion on its place
            if let Some((index, position)) = enemies.iter().enumerate()
                .find(|&(_, enemy)| enemy.collides_with(bullet))
                .map(|(index, enemy)| (index, enemy.position()))
            {
                Game::make_explosion(particles, position, 10);
                enemies.remove(index);
                false
            } else {
                true
            }
        });
        }

        let killed_enemies = (old_enemy_count - self.world.enemies.len()) as u32;
        self.score += 10 * killed_enemies;
    }

    /// reset our game-state
    fn reset(&mut self) {
        // Reset player position
        *self.world.player.x_mut() = self.world.size.random_x(&mut self.rng);
        *self.world.player.y_mut() = self.world.size.random_y(&mut self.rng);

        // Reset score
        self.score = 0;

        // Remove all enemies and bullets
        self.world.bullets.clear();
        self.world.enemies.clear();
    }

    /// Handles collisions between the player and the enemies
    fn handle_player_collisions(&mut self) {
        if self.world.enemies.iter().any(|enemy| self.world.player.collides_with(enemy)) {
            // Make an explosion where the player was
            let ppos = self.world.player.position();
            Game::make_explosion(&mut self.world.particles, ppos, 8);

            self.reset();
        }
    }

    /// Generates a new explosion of the given intensity at the given position. This works best with values between 5 and 25
    fn make_explosion(particles: &mut Vec<Particle>, position: Point, intensity: u8) {
        for rotation in itertools::linspace(0.0, 2.0 * f64::consts::PI, 30) {
            for ttl in (1..intensity).map(|x| (x as f64) / 10.0) {
                particles.push(Particle::new(Vector::new(position.clone(), rotation), ttl));
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::slice;
use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALCreate(
            hDriver: *(),
            pszFilename: *c_char,
            nXSize: c_int,
            nYSize: c_int,
            nBands: c_int,
            eBandType: c_int,
            papszOptions: **c_char
        ) -> *();
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALGetRasterBand(hDS: *(), nBandId: c_int) -> *();
    fn GDALRasterIO(
            hBand: *(),
            eRWFlag: c_int,
            nXOff: c_int,
            nYOff: c_int,
            nXSize: c_int,
            nYSize: c_int,
            pData: *(),
            nBufXSize: c_int,
            nBufYSize: c_int,
            GDALDataType: c_int,
            nPixelSpace: c_int,
            nLineSpace: c_int
        ) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}

static GA_ReadOnly:  c_int = 0;
static GA_Update:    c_int = 1;

static GDT_Unknown:  c_int = 0;
static GDT_Byte:     c_int = 1;
static GDT_UInt16:   c_int = 2;
static GDT_Int16:    c_int = 3;
static GDT_UInt32:   c_int = 4;
static GDT_Int32:    c_int = 5;
static GDT_Float32:  c_int = 6;
static GDT_Float64:  c_int = 7;
static GDT_CInt16:   c_int = 8;
static GDT_CInt32:   c_int = 9;
static GDT_CFloat32: c_int = 10;
static GDT_CFloat64: c_int = 11;

static GF_Read:      c_int = 0;
static GF_Write:     c_int = 1;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let rv = GDALVersionInfo(c_key);
            return raw::from_c_str(rv);
        };
    });
    return info;
}

struct Dataset {
    c_dataset: *(),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        let size_x = unsafe { GDALGetRasterXSize(self.c_dataset) } as int;
        let size_y = unsafe { GDALGetRasterYSize(self.c_dataset) } as int;
        return (size_x, size_y);
    }

    pub fn get_driver(&self) -> Driver {
        let c_driver = unsafe { GDALGetDatasetDriver(self.c_dataset) };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        return unsafe { GDALGetRasterCount(self.c_dataset) } as int;
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let rv = GDALGetProjectionRef(self.c_dataset);
            return raw::from_c_str(rv);
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe { GDALSetProjection(self.c_dataset, c_projection) };
        });
    }

    pub fn read_raster(
        &self,
        band_index: int,
        window_x: int, window_y: int,
        window_width: uint, window_height: uint,
        buffer_width: uint, buffer_height: uint
    ) -> ByteBuffer {
        let buffer_size = buffer_width * buffer_height;
        let mut data: ~[u8] = slice::with_capacity(buffer_size);
        for _ in range(0, buffer_size) { data.push(0u8); } // TODO zero fill
        unsafe {
            let c_band = GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = GDALRasterIO(
                c_band,
                GF_Read,
                window_x as c_int,
                window_y as c_int,
                window_width as c_int,
                window_height as c_int,
                data.as_mut_ptr() as *(),
                buffer_width as c_int,
                buffer_height as c_int,
                GDT_Byte,
                0,
                0
            ) as int;
            assert!(rv == 0);
        };
        return ByteBuffer{
            width: buffer_width,
            height: buffer_height,
            data: data,
        };
    }
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

struct Driver {
    c_driver: *(),
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverShortName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverLongName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn create(
        &self,
        filename: &str,
        size_x: int,
        size_y: int,
        bands: int
    ) -> Option<Dataset> {
        use std::ptr::null;
        let c_dataset = filename.with_c_str(|c_filename| {
            unsafe {
                return GDALCreate(
                    self.c_driver,
                    c_filename,
                    size_x as c_int,
                    size_y as c_int,
                    bands as c_int,
                    GDT_Byte,
                    null()
                );
            }
        });
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        return unsafe { GDALGetDriverByName(c_name) };
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

struct ByteBuffer {
    width: uint,
    height: uint,
    data: ~[u8],
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_read_raster() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let raster = dataset.read_raster(1, 20, 30, 10, 10, 3, 5);
    assert_eq!(raster.width, 3);
    assert_eq!(raster.height, 5);
    assert_eq!(raster.data, ~[13, 3, 18, 6, 9, 1, 2, 9, 4, 6, 11, 4, 6, 2, 9]);
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}

#[test]
fn test_create() {
    let driver = get_driver("MEM").unwrap();
    let dataset = driver.create("", 10, 20, 3).unwrap();
    assert_eq!(dataset.get_raster_size(), (10, 20));
    assert_eq!(dataset.get_raster_count(), 3);
    assert_eq!(dataset.get_driver().get_short_name(), ~"MEM");
}
<commit_msg>write raster data<commit_after>use std::slice;
use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALCreate(
            hDriver: *(),
            pszFilename: *c_char,
            nXSize: c_int,
            nYSize: c_int,
            nBands: c_int,
            eBandType: c_int,
            papszOptions: **c_char
        ) -> *();
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALClose(hDS: *());
    fn GDALGetDatasetDriver(hDataset: *()) -> *();
    fn GDALGetRasterXSize(hDataset: *()) -> c_int;
    fn GDALGetRasterYSize(hDataset: *()) -> c_int;
    fn GDALGetRasterCount(hDataset: *()) -> c_int;
    fn GDALGetProjectionRef(hDS: *()) -> *c_char;
    fn GDALSetProjection(hDS: *(), pszProjection: *c_char) -> c_int;
    fn GDALGetRasterBand(hDS: *(), nBandId: c_int) -> *();
    fn GDALRasterIO(
            hBand: *(),
            eRWFlag: c_int,
            nXOff: c_int,
            nYOff: c_int,
            nXSize: c_int,
            nYSize: c_int,
            pData: *(),
            nBufXSize: c_int,
            nBufYSize: c_int,
            GDALDataType: c_int,
            nPixelSpace: c_int,
            nLineSpace: c_int
        ) -> c_int;
    fn GDALAllRegister();
    fn GDALGetDriverByName(pszName: *c_char) -> *();
    fn GDALGetDriverShortName(hDriver: *()) -> *c_char;
    fn GDALGetDriverLongName(hDriver: *()) -> *c_char;
}

static GA_ReadOnly:  c_int = 0;
static GA_Update:    c_int = 1;

static GDT_Unknown:  c_int = 0;
static GDT_Byte:     c_int = 1;
static GDT_UInt16:   c_int = 2;
static GDT_Int16:    c_int = 3;
static GDT_UInt32:   c_int = 4;
static GDT_Int32:    c_int = 5;
static GDT_Float32:  c_int = 6;
static GDT_Float64:  c_int = 7;
static GDT_CInt16:   c_int = 8;
static GDT_CInt32:   c_int = 9;
static GDT_CFloat32: c_int = 10;
static GDT_CFloat64: c_int = 11;

static GF_Read:      c_int = 0;
static GF_Write:     c_int = 1;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            GDALAllRegister();
            registered_drivers = true;
        }
    }
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        unsafe {
            let rv = GDALVersionInfo(c_key);
            return raw::from_c_str(rv);
        };
    });
    return info;
}

struct Dataset {
    c_dataset: *(),
}

impl Drop for Dataset {
    fn drop(&mut self) {
        unsafe { GDALClose(self.c_dataset); }
    }
}

impl Dataset {
    pub fn get_raster_size(&self) -> (int, int) {
        let size_x = unsafe { GDALGetRasterXSize(self.c_dataset) } as int;
        let size_y = unsafe { GDALGetRasterYSize(self.c_dataset) } as int;
        return (size_x, size_y);
    }

    pub fn get_driver(&self) -> Driver {
        let c_driver = unsafe { GDALGetDatasetDriver(self.c_dataset) };
        return Driver{c_driver: c_driver};
    }

    pub fn get_raster_count(&self) -> int {
        return unsafe { GDALGetRasterCount(self.c_dataset) } as int;
    }

    pub fn get_projection(&self) -> ~str {
        unsafe {
            let rv = GDALGetProjectionRef(self.c_dataset);
            return raw::from_c_str(rv);
        }
    }

    pub fn set_projection(&self, projection: &str) {
        projection.with_c_str(|c_projection| {
            unsafe { GDALSetProjection(self.c_dataset, c_projection) };
        });
    }

    pub fn read_raster(
        &self,
        band_index: int,
        window_x: int, window_y: int,
        window_width: uint, window_height: uint,
        buffer_width: uint, buffer_height: uint
    ) -> ByteBuffer {
        let buffer_size = buffer_width * buffer_height;
        let mut data: ~[u8] = slice::with_capacity(buffer_size);
        for _ in range(0, buffer_size) { data.push(0u8); } // TODO zero fill
        unsafe {
            let c_band = GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = GDALRasterIO(
                c_band,
                GF_Read,
                window_x as c_int,
                window_y as c_int,
                window_width as c_int,
                window_height as c_int,
                data.as_mut_ptr() as *(),
                buffer_width as c_int,
                buffer_height as c_int,
                GDT_Byte,
                0,
                0
            ) as int;
            assert!(rv == 0);
        };
        return ByteBuffer{
            width: buffer_width,
            height: buffer_height,
            data: data,
        };
    }

    pub fn write_raster(
        &self,
        band_index: int,
        window_x: int, window_y: int,
        window_width: uint, window_height: uint,
        buffer: ByteBuffer
    ) {
        unsafe {
            let c_band = GDALGetRasterBand(self.c_dataset, band_index as c_int);
            let rv = GDALRasterIO(
                c_band,
                GF_Write,
                window_x as c_int,
                window_y as c_int,
                window_width as c_int,
                window_height as c_int,
                buffer.data.as_ptr() as *(),
                buffer.width as c_int,
                buffer.height as c_int,
                GDT_Byte,
                0,
                0
            ) as int;
            assert!(rv == 0);
        };
    }
}

pub fn open(path: &Path) -> Option<Dataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

struct Driver {
    c_driver: *(),
}

impl Driver {
    pub fn get_short_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverShortName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn get_long_name(&self) -> ~str {
        unsafe {
            let rv = GDALGetDriverLongName(self.c_driver);
            return raw::from_c_str(rv);
        }
    }

    pub fn create(
        &self,
        filename: &str,
        size_x: int,
        size_y: int,
        bands: int
    ) -> Option<Dataset> {
        use std::ptr::null;
        let c_dataset = filename.with_c_str(|c_filename| {
            unsafe {
                return GDALCreate(
                    self.c_driver,
                    c_filename,
                    size_x as c_int,
                    size_y as c_int,
                    bands as c_int,
                    GDT_Byte,
                    null()
                );
            }
        });
        return match c_dataset.is_null() {
            true  => None,
            false => Some(Dataset{c_dataset: c_dataset}),
        };
    }
}

pub fn get_driver(name: &str) -> Option<Driver> {
    register_drivers();
    let c_driver = name.with_c_str(|c_name| {
        return unsafe { GDALGetDriverByName(c_name) };
    });
    return match c_driver.is_null() {
        true  => None,
        false => Some(Driver{c_driver: c_driver}),
    };
}

struct ByteBuffer {
    width: uint,
    height: uint,
    data: ~[u8],
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}

#[test]
fn test_get_raster_size() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let (size_x, size_y) = dataset.get_raster_size();
    assert_eq!(size_x, 100);
    assert_eq!(size_y, 50);
}

#[test]
fn test_get_raster_count() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let count = dataset.get_raster_count();
    assert_eq!(count, 3);
}

#[test]
fn test_get_projection() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    //dataset.set_projection("WGS84");
    let projection = dataset.get_projection();
    assert_eq!(projection.slice(0, 16), "GEOGCS[\"WGS 84\",");
}

#[test]
fn test_read_raster() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let raster = dataset.read_raster(1, 20, 30, 10, 10, 3, 5);
    assert_eq!(raster.width, 3);
    assert_eq!(raster.height, 5);
    assert_eq!(raster.data, ~[13, 3, 18, 6, 9, 1, 2, 9, 4, 6, 11, 4, 6, 2, 9]);
}

#[test]
fn test_write_raster() {
    let driver = get_driver("MEM").unwrap();
    let dataset = driver.create("", 20, 10, 1).unwrap();

    // create a 2x1 raster
    let raster = ByteBuffer{width: 2, height: 1, data: ~[50u8, 20u8]};

    // epand it to fill the image (20x10)
    dataset.write_raster(1, 0, 0, 20, 10, raster);

    // read a pixel from the left side
    let left = dataset.read_raster(1, 5, 5, 1, 1, 1, 1);
    assert_eq!(left.data[0], 50u8);

    // read a pixel from the right side
    let right = dataset.read_raster(1, 15, 5, 1, 1, 1, 1);
    assert_eq!(right.data[0], 20u8);
}

#[test]
fn test_get_dataset_driver() {
    let dataset = open(&fixture_path("tinymarble.jpeg")).unwrap();
    let driver = dataset.get_driver();
    assert_eq!(driver.get_short_name(), ~"JPEG");
    assert_eq!(driver.get_long_name(), ~"JPEG JFIF");
}

#[test]
fn test_get_driver_by_name() {
    let missing_driver = get_driver("wtf");
    assert!(missing_driver.is_none());

    let ok_driver = get_driver("GTiff");
    assert!(ok_driver.is_some());
    let driver = ok_driver.unwrap();
    assert_eq!(driver.get_short_name(), ~"GTiff");
    assert_eq!(driver.get_long_name(), ~"GeoTIFF");
}

#[test]
fn test_create() {
    let driver = get_driver("MEM").unwrap();
    let dataset = driver.create("", 10, 20, 3).unwrap();
    assert_eq!(dataset.get_raster_size(), (10, 20));
    assert_eq!(dataset.get_raster_count(), 3);
    assert_eq!(dataset.get_driver().get_short_name(), ~"MEM");
}
<|endoftext|>


<commit_before>//! A generic event loop for games and interactive applications

#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

extern crate window;
extern crate input;
extern crate viewport;
extern crate time;

use std::thread::sleep;
use std::time::Duration;
use std::cmp;
use window::Window;
use input::{ AfterRenderArgs, Event, IdleArgs, RenderArgs, UpdateArgs };

/// A trait for create event iterator from window.
pub trait Events {
    /// Creates event iterator from window.
    fn events(&self) -> WindowEvents;
}

impl<W> Events for W where W: Window {
    fn events(&self) -> WindowEvents {
        WindowEvents::new()
    }
}

/// Tells whether last emitted event was idle or not.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Idle {
    No,
    Yes
}

// Stores the update state right after sleep.
// This is used to avoid logic error when changing settings
// in the event loop followed by an update.
#[derive(Copy, Clone, Debug)]
struct UpdateState {
    dt_update_in_ns: u64,
    dt: f64,
}

#[derive(Copy, Clone, Debug)]
enum State {
    Render,
    SwapBuffers,
    UpdateLoop(Idle),
    HandleEvents(UpdateState),
    Update(UpdateState),
}

/// Methods implements for event loop settings.
pub trait EventLoop: Sized {
    /// The number of updates per second
    ///
    /// This is the fixed update rate on average over time.
    /// If the event loop lags, it will try to catch up.
    fn set_ups(&mut self, frames: u64);

    /// The number of updates per second
    ///
    /// This is the fixed update rate on average over time.
    /// If the event loop lags, it will try to catch up.
    fn ups(mut self, frames: u64) -> Self {
        self.set_ups(frames);
        self
    }

    /// The maximum number of frames per second
    ///
    /// The frame rate can be lower because the
    /// next frame is always scheduled from the previous frame.
    /// This causes the frames to "slip" over time.
    fn set_max_fps(&mut self, frames: u64);

    /// The maximum number of frames per second
    ///
    /// The frame rate can be lower because the
    /// next frame is always scheduled from the previous frame.
    /// This causes the frames to "slip" over time.
    fn max_fps(mut self, frames: u64) -> Self {
        self.set_max_fps(frames);
        self
    }

    /// Enable or disable automatic swapping of buffers.
    fn set_swap_buffers(&mut self, enable: bool);

    /// Enable or disable automatic swapping of buffers.
    fn swap_buffers(mut self, enable: bool) -> Self {
        self.set_swap_buffers(enable);
        self
    }

    /// Enable or disable benchmark mode.
    /// When enabled, it will render and update without sleep and ignore input.
    /// Used to test performance by playing through as fast as possible.
    fn set_bench_mode(&mut self, enable: bool);

    /// Enable or disable benchmark mode.
    /// When enabled, it will render and update without sleep and ignore input.
    /// Used to test performance by playing through as fast as possible.
    fn bench_mode(mut self, enable: bool) -> Self {
        self.set_bench_mode(enable);
        self
    }
}

/// An event loop iterator
///
/// *Warning: Because the iterator polls events from the window back-end,
/// it must be used on the same thread as the window back-end (usually main thread),
/// unless the window back-end supports multi-thread event polling.*
#[derive(Copy, Clone)]
pub struct WindowEvents {
    state: State,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
    swap_buffers: bool,
    bench_mode: bool,
}

static BILLION: u64 = 1_000_000_000;

fn ns_to_duration(ns: u64) -> Duration {
    let secs = ns / BILLION;
    let nanos = (ns % BILLION) as u32;
    Duration::new(secs, nanos)
}

/// The default updates per second.
pub const DEFAULT_UPS: u64 = 120;
/// The default maximum frames per second.
pub const DEFAULT_MAX_FPS: u64 = 60;

impl WindowEvents
{
    /// Creates a new event iterator with default UPS and FPS settings.
    pub fn new() -> WindowEvents {
        let start = time::precise_time_ns();
        let updates_per_second = DEFAULT_UPS;
        let max_frames_per_second = DEFAULT_MAX_FPS;
        WindowEvents {
            state: State::Render,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: BILLION / updates_per_second,
            dt_frame_in_ns: BILLION / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
            swap_buffers: true,
            bench_mode: false,
        }
    }

    /// Returns the next game event.
    pub fn next<W>(&mut self, window: &mut W) -> Option<Event<W::Event>>
        where W: Window
    {
        loop {
            if window.should_close() { return None; }
            self.state = match self.state {
                State::Render => {
                    // Handle input events before rendering,
                    // because window might be closed and destroy
                    // the graphics context.
                    if let Some(e) = window.poll_event() {
                        return Some(Event::Input(e));
                    }
                    if window.should_close() {
                        return None;
                    }

                    if self.bench_mode {
                        // In benchmark mode, pretend FPS is perfect.
                        self.last_frame += self.dt_frame_in_ns;
                    } else {
                        // In normal mode, let the FPS slip if late.
                        self.last_frame = time::precise_time_ns();
                    }

                    let size = window.size();
                    let draw_size = window.draw_size();
                    if size.width != 0 && size.height != 0 {
                        // Swap buffers next time.
                        self.state = State::SwapBuffers;
                        return Some(Event::Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            ext_dt: (self.last_frame - self.last_update) as f64
                                    / BILLION as f64,
                            width: size.width,
                            height: size.height,
                            draw_width: draw_size.width,
                            draw_height: draw_size.height,
                        }));
                    }

                    State::UpdateLoop(Idle::No)
                }
                State::SwapBuffers => {
                    if self.swap_buffers {
                        window.swap_buffers();
                    }
                    self.state = State::UpdateLoop(Idle::No);
                    return Some(Event::AfterRender(AfterRenderArgs));
                }
                State::UpdateLoop(ref mut idle) => {
                    if self.bench_mode {
                        // In benchmark mode, pick the next event without sleep.
                        // Idle and input events are ignored.
                        let next_frame = self.last_frame + self.dt_frame_in_ns;
                        let next_update = self.last_update + self.dt_update_in_ns;
                        let next_event = cmp::min(next_frame, next_update);
                        if next_event == next_frame {
                            State::Render
                        } else {
                            State::HandleEvents(UpdateState {
                                dt_update_in_ns: self.dt_update_in_ns,
                                dt: self.dt,
                            })
                        }
                    } else {
                        let current_time = time::precise_time_ns();
                        let next_frame = self.last_frame + self.dt_frame_in_ns;
                        let next_update = self.last_update + self.dt_update_in_ns;
                        let next_event = cmp::min(next_frame, next_update);
                        if next_event > current_time {
                            if let Some(x) = window.poll_event() {
                                *idle = Idle::No;
                                return Some(Event::Input(x));
                            } else if *idle == Idle::No {
                                *idle = Idle::Yes;
                                let seconds = ((next_event - current_time) as f64) / (BILLION as f64);
                                return Some(Event::Idle(IdleArgs { dt: seconds }))
                            }
                            sleep(ns_to_duration(next_event - current_time));
                            State::UpdateLoop(Idle::No)
                        } else if next_event == next_frame {
                            State::Render
                        } else {
                            State::HandleEvents(UpdateState {
                                dt_update_in_ns: self.dt_update_in_ns,
                                dt: self.dt,
                            })
                        }
                    }
                }
                State::HandleEvents(update_state) => {
                    if self.bench_mode {
                        // Ignore input to prevent it affecting the benchmark.
                        match window.poll_event() {
                            None => State::Update(update_state),
                            Some(_) => State::HandleEvents(update_state),
                        }
                    } else {
                        // Handle all events before updating.
                        match window.poll_event() {
                            None => State::Update(update_state),
                            Some(x) => { return Some(Event::Input(x)); },
                        }
                    }
                }
                State::Update(update_state) => {
                    self.state = State::UpdateLoop(Idle::No);
                    // Use the update state stored right after sleep.
                    // If there are any changes in settings, these will be applied on next update.
                    self.last_update += update_state.dt_update_in_ns;
                    return Some(Event::Update(UpdateArgs{ dt: update_state.dt }));
                }
            };
        }
    }
}

impl EventLoop for WindowEvents {
    fn set_ups(&mut self, frames: u64) {
        self.dt_update_in_ns = BILLION / frames;
        self.dt = 1.0 / frames as f64;
    }

    fn set_max_fps(&mut self, frames: u64) {
        self.dt_frame_in_ns = BILLION / frames;
    }

    fn set_swap_buffers(&mut self, enable: bool) {
        self.swap_buffers = enable;
    }

    fn set_bench_mode(&mut self, enable: bool) {
        self.bench_mode = enable;
    }
}
<commit_msg>Fixed bug in bench mode when handling input<commit_after>//! A generic event loop for games and interactive applications

#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

extern crate window;
extern crate input;
extern crate viewport;
extern crate time;

use std::thread::sleep;
use std::time::Duration;
use std::cmp;
use window::Window;
use input::{ AfterRenderArgs, Event, IdleArgs, RenderArgs, UpdateArgs };

/// A trait for create event iterator from window.
pub trait Events {
    /// Creates event iterator from window.
    fn events(&self) -> WindowEvents;
}

impl<W> Events for W where W: Window {
    fn events(&self) -> WindowEvents {
        WindowEvents::new()
    }
}

/// Tells whether last emitted event was idle or not.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Idle {
    No,
    Yes
}

// Stores the update state right after sleep.
// This is used to avoid logic error when changing settings
// in the event loop followed by an update.
#[derive(Copy, Clone, Debug)]
struct UpdateState {
    dt_update_in_ns: u64,
    dt: f64,
}

#[derive(Copy, Clone, Debug)]
enum State {
    Render,
    SwapBuffers,
    UpdateLoop(Idle),
    HandleEvents(UpdateState),
    Update(UpdateState),
}

/// Methods implements for event loop settings.
pub trait EventLoop: Sized {
    /// The number of updates per second
    ///
    /// This is the fixed update rate on average over time.
    /// If the event loop lags, it will try to catch up.
    fn set_ups(&mut self, frames: u64);

    /// The number of updates per second
    ///
    /// This is the fixed update rate on average over time.
    /// If the event loop lags, it will try to catch up.
    fn ups(mut self, frames: u64) -> Self {
        self.set_ups(frames);
        self
    }

    /// The maximum number of frames per second
    ///
    /// The frame rate can be lower because the
    /// next frame is always scheduled from the previous frame.
    /// This causes the frames to "slip" over time.
    fn set_max_fps(&mut self, frames: u64);

    /// The maximum number of frames per second
    ///
    /// The frame rate can be lower because the
    /// next frame is always scheduled from the previous frame.
    /// This causes the frames to "slip" over time.
    fn max_fps(mut self, frames: u64) -> Self {
        self.set_max_fps(frames);
        self
    }

    /// Enable or disable automatic swapping of buffers.
    fn set_swap_buffers(&mut self, enable: bool);

    /// Enable or disable automatic swapping of buffers.
    fn swap_buffers(mut self, enable: bool) -> Self {
        self.set_swap_buffers(enable);
        self
    }

    /// Enable or disable benchmark mode.
    /// When enabled, it will render and update without sleep and ignore input.
    /// Used to test performance by playing through as fast as possible.
    fn set_bench_mode(&mut self, enable: bool);

    /// Enable or disable benchmark mode.
    /// When enabled, it will render and update without sleep and ignore input.
    /// Used to test performance by playing through as fast as possible.
    fn bench_mode(mut self, enable: bool) -> Self {
        self.set_bench_mode(enable);
        self
    }
}

/// An event loop iterator
///
/// *Warning: Because the iterator polls events from the window back-end,
/// it must be used on the same thread as the window back-end (usually main thread),
/// unless the window back-end supports multi-thread event polling.*
#[derive(Copy, Clone)]
pub struct WindowEvents {
    state: State,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
    swap_buffers: bool,
    bench_mode: bool,
}

static BILLION: u64 = 1_000_000_000;

fn ns_to_duration(ns: u64) -> Duration {
    let secs = ns / BILLION;
    let nanos = (ns % BILLION) as u32;
    Duration::new(secs, nanos)
}

/// The default updates per second.
pub const DEFAULT_UPS: u64 = 120;
/// The default maximum frames per second.
pub const DEFAULT_MAX_FPS: u64 = 60;

impl WindowEvents
{
    /// Creates a new event iterator with default UPS and FPS settings.
    pub fn new() -> WindowEvents {
        let start = time::precise_time_ns();
        let updates_per_second = DEFAULT_UPS;
        let max_frames_per_second = DEFAULT_MAX_FPS;
        WindowEvents {
            state: State::Render,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: BILLION / updates_per_second,
            dt_frame_in_ns: BILLION / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
            swap_buffers: true,
            bench_mode: false,
        }
    }

    /// Returns the next game event.
    pub fn next<W>(&mut self, window: &mut W) -> Option<Event<W::Event>>
        where W: Window
    {
        loop {
            if window.should_close() { return None; }
            self.state = match self.state {
                State::Render => {
                    // Handle input events before rendering,
                    // because window might be closed and destroy
                    // the graphics context.
                    if let Some(e) = window.poll_event() {
                        if self.bench_mode {
                            // Ignore input events in benchmark mode.
                            // This is to avoid the input events affecting
                            // the application state when benchmarking.
                            continue
                        } else {
                            return Some(Event::Input(e));
                        }
                    }
                    if window.should_close() {
                        return None;
                    }

                    if self.bench_mode {
                        // In benchmark mode, pretend FPS is perfect.
                        self.last_frame += self.dt_frame_in_ns;
                    } else {
                        // In normal mode, let the FPS slip if late.
                        self.last_frame = time::precise_time_ns();
                    }

                    let size = window.size();
                    let draw_size = window.draw_size();
                    if size.width != 0 && size.height != 0 {
                        // Swap buffers next time.
                        self.state = State::SwapBuffers;
                        return Some(Event::Render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            ext_dt: (self.last_frame - self.last_update) as f64
                                    / BILLION as f64,
                            width: size.width,
                            height: size.height,
                            draw_width: draw_size.width,
                            draw_height: draw_size.height,
                        }));
                    }

                    State::UpdateLoop(Idle::No)
                }
                State::SwapBuffers => {
                    if self.swap_buffers {
                        window.swap_buffers();
                    }
                    self.state = State::UpdateLoop(Idle::No);
                    return Some(Event::AfterRender(AfterRenderArgs));
                }
                State::UpdateLoop(ref mut idle) => {
                    if self.bench_mode {
                        // In benchmark mode, pick the next event without sleep.
                        // Idle and input events are ignored.
                        // This is to avoid the input events affecting
                        // the application state when benchmarking.
                        let next_frame = self.last_frame + self.dt_frame_in_ns;
                        let next_update = self.last_update + self.dt_update_in_ns;
                        let next_event = cmp::min(next_frame, next_update);
                        if next_event == next_frame {
                            State::Render
                        } else {
                            State::HandleEvents(UpdateState {
                                dt_update_in_ns: self.dt_update_in_ns,
                                dt: self.dt,
                            })
                        }
                    } else {
                        let current_time = time::precise_time_ns();
                        let next_frame = self.last_frame + self.dt_frame_in_ns;
                        let next_update = self.last_update + self.dt_update_in_ns;
                        let next_event = cmp::min(next_frame, next_update);
                        if next_event > current_time {
                            if let Some(x) = window.poll_event() {
                                *idle = Idle::No;
                                return Some(Event::Input(x));
                            } else if *idle == Idle::No {
                                *idle = Idle::Yes;
                                let seconds = ((next_event - current_time) as f64) / (BILLION as f64);
                                return Some(Event::Idle(IdleArgs { dt: seconds }))
                            }
                            sleep(ns_to_duration(next_event - current_time));
                            State::UpdateLoop(Idle::No)
                        } else if next_event == next_frame {
                            State::Render
                        } else {
                            State::HandleEvents(UpdateState {
                                dt_update_in_ns: self.dt_update_in_ns,
                                dt: self.dt,
                            })
                        }
                    }
                }
                State::HandleEvents(update_state) => {
                    if self.bench_mode {
                        // Ignore input events.
                        // This is to avoid the input events affecting
                        // the application state when benchmarking.
                        match window.poll_event() {
                            None => State::Update(update_state),
                            Some(_) => State::HandleEvents(update_state),
                        }
                    } else {
                        // Handle all events before updating.
                        match window.poll_event() {
                            None => State::Update(update_state),
                            Some(x) => { return Some(Event::Input(x)); },
                        }
                    }
                }
                State::Update(update_state) => {
                    self.state = State::UpdateLoop(Idle::No);
                    // Use the update state stored right after sleep.
                    // If there are any changes in settings, these will be applied on next update.
                    self.last_update += update_state.dt_update_in_ns;
                    return Some(Event::Update(UpdateArgs{ dt: update_state.dt }));
                }
            };
        }
    }
}

impl EventLoop for WindowEvents {
    fn set_ups(&mut self, frames: u64) {
        self.dt_update_in_ns = BILLION / frames;
        self.dt = 1.0 / frames as f64;
    }

    fn set_max_fps(&mut self, frames: u64) {
        self.dt_frame_in_ns = BILLION / frames;
    }

    fn set_swap_buffers(&mut self, enable: bool) {
        self.swap_buffers = enable;
    }

    fn set_bench_mode(&mut self, enable: bool) {
        self.bench_mode = enable;
    }
}
<|endoftext|>


<commit_before>use {MultiDeciderImpl, TypedDecider, ImpliedDeciderImpl, MultiDecider, Decider, Decision, Result};

use std::time::Instant;

impl Decider for Allower {}
impl MultiDecider for Allower {}

#[derive(Copy, Clone)]
/// The most naive implementation of a rate-limiter ever: Always
/// allows every cell through.
/// # Example
/// ```
/// use ratelimit_meter::{Decider};
/// use ratelimit_meter::example_algorithms::Allower;
/// let mut allower = Allower::new();
/// assert!(allower.check().unwrap().is_compliant());
/// ```
pub struct Allower {}

impl Allower {
    pub fn new() -> Allower {
        Allower {}
    }
}

impl TypedDecider for Allower {
    /// Allower never returns a negative answer, so negative answers
    /// don't carry information.
    type T = ();
}

impl MultiDeciderImpl for Allower {
    /// Allows all cells through unconditionally.
    fn test_n_and_update(&mut self, _n: u32, _t0: Instant) -> Result<Decision<()>> {
        Ok(Decision::Yes)
    }
}

impl ImpliedDeciderImpl for Allower {}
<commit_msg>Make clippy happy: Derive Default for Allower<commit_after>use {MultiDeciderImpl, TypedDecider, ImpliedDeciderImpl, MultiDecider, Decider, Decision, Result};

use std::time::Instant;

impl Decider for Allower {}
impl MultiDecider for Allower {}

#[derive(Default, Copy, Clone)]
/// The most naive implementation of a rate-limiter ever: Always
/// allows every cell through.
/// # Example
/// ```
/// use ratelimit_meter::{Decider};
/// use ratelimit_meter::example_algorithms::Allower;
/// let mut allower = Allower::new();
/// assert!(allower.check().unwrap().is_compliant());
/// ```
pub struct Allower {}

impl Allower {
    pub fn new() -> Allower {
        Allower::default()
    }
}

impl TypedDecider for Allower {
    /// Allower never returns a negative answer, so negative answers
    /// don't carry information.
    type T = ();
}

impl MultiDeciderImpl for Allower {
    /// Allows all cells through unconditionally.
    fn test_n_and_update(&mut self, _n: u32, _t0: Instant) -> Result<Decision<()>> {
        Ok(Decision::Yes)
    }
}

impl ImpliedDeciderImpl for Allower {}
<|endoftext|>


<commit_before>//! Las points.

use super::{Error, Result};

/// A las point.
///
/// As we do for the `Header` we encasulate different point formats by using `Option<T>`.
#[derive(Debug, Default, PartialEq)]
pub struct Point {
    /// The x value of the point.
    ///
    /// This value is assumed to not include a scaling and offset -- in other words, this is the
    /// "true" value, not the value stored in the lasfile.
    pub x: f64,
    /// The y value of the point.
    ///
    /// This value is assumed to not include a scaling and offset -- in other words, this is the
    /// "true" value, not the value stored in the lasfile.
    pub y: f64,
    /// The z value of the point.
    ///
    /// This value is assumed to not include a scaling and offset -- in other words, this is the
    /// "true" value, not the value stored in the lasfile.
    pub z: f64,
    /// The intensity of the point.
    pub intensity: u16,
    /// The return number of the point for its pulse.
    ///
    /// TODO these aren't actually u8s.
    pub return_number: u8,
    /// The number of returns in total for the pulse that produced this point.
    pub number_of_returns: u8,
    /// The `ScanDirection` of the point.
    pub scan_direction: ScanDirection,
    /// True if this point is on the edge of a flight line.
    pub edge_of_flight_line: bool,
    /// The `Classification` of this point.
    pub classification: Classification,
    /// The scan angle range -- basically, the integer value of the scan angle.
    pub scan_angle_rank: i8,
    /// Custom data that the user can provide.
    pub user_data: u8,
    /// The "file" from which this point originated.
    pub point_source_id: u16,
    /// The gps time of this point.
    pub gps_time: Option<f64>,
    /// The red channel for this point.
    pub red: Option<u16>,
    /// The green channel for this point.
    pub green: Option<u16>,
    /// The blue channel for this point.
    pub blue: Option<u16>,
}

#[derive(Debug, PartialEq)]
pub enum ScanDirection {
    Backward = 0,
    Forward = 1,
}

impl Default for ScanDirection {
    fn default() -> ScanDirection {
        ScanDirection::Forward
    }
}

impl ScanDirection {
    /// Translates a u8 into a scan direction.
    ///
    /// Returns an error if the u8 is not zero or one.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::ScanDirection;
    /// assert_eq!(ScanDirection::Backward, ScanDirection::from_u8(0);
    /// assert_eq!(ScanDirection::Forward, ScanDirection::from_u8(1);
    /// ```
    pub fn from_u8(n: u8) -> Result<ScanDirection> {
        match n {
            0 => Ok(ScanDirection::Backward),
            1 => Ok(ScanDirection::Forward),
            _ => Err(Error::InvalidScanDirection(n)),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Classification {
    CreatedNeverClassified = 0,
    Unclassified = 1,
    Ground = 2,
    LowVegetation = 3,
    MediumVegetation = 4,
    HighVegetation = 5,
    Building = 6,
    LowPoint = 7,
    ModelKeyPoint = 8,
    Water = 9,
    Reserved10 = 10,
    Reserved11 = 11,
    Overlap = 12,
    Reserved,
}

impl Default for Classification {
    fn default() -> Classification {
        Classification::CreatedNeverClassified
    }
}

impl From<u8> for Classification {
    fn from(n: u8) -> Self {
        match n {
            0 => Classification::CreatedNeverClassified,
            1 => Classification::Unclassified,
            2 => Classification::Ground,
            3 => Classification::LowVegetation,
            4 => Classification::MediumVegetation,
            5 => Classification::HighVegetation,
            6 => Classification::Building,
            7 => Classification::LowPoint,
            8 => Classification::ModelKeyPoint,
            9 => Classification::Water,
            10 => Classification::Reserved10,
            11 => Classification::Reserved11,
            12 => Classification::Overlap,
            _ => Classification::Reserved,
       }
    }
}
<commit_msg>Clean up ScanDirection<commit_after>//! Las points.

use super::{Error, Result};

/// A las point.
///
/// As we do for the `Header` we encasulate different point formats by using `Option<T>`.
#[derive(Debug, Default, PartialEq)]
pub struct Point {
    /// The x value of the point.
    ///
    /// This value is assumed to not include a scaling and offset -- in other words, this is the
    /// "true" value, not the value stored in the lasfile.
    pub x: f64,
    /// The y value of the point.
    ///
    /// This value is assumed to not include a scaling and offset -- in other words, this is the
    /// "true" value, not the value stored in the lasfile.
    pub y: f64,
    /// The z value of the point.
    ///
    /// This value is assumed to not include a scaling and offset -- in other words, this is the
    /// "true" value, not the value stored in the lasfile.
    pub z: f64,
    /// The intensity of the point.
    pub intensity: u16,
    /// The return number of the point for its pulse.
    ///
    /// TODO these aren't actually u8s.
    pub return_number: u8,
    /// The number of returns in total for the pulse that produced this point.
    pub number_of_returns: u8,
    /// The `ScanDirection` of the point.
    pub scan_direction: ScanDirection,
    /// True if this point is on the edge of a flight line.
    pub edge_of_flight_line: bool,
    /// The `Classification` of this point.
    pub classification: Classification,
    /// The scan angle range -- basically, the integer value of the scan angle.
    pub scan_angle_rank: i8,
    /// Custom data that the user can provide.
    pub user_data: u8,
    /// The "file" from which this point originated.
    pub point_source_id: u16,
    /// The gps time of this point.
    pub gps_time: Option<f64>,
    /// The red channel for this point.
    pub red: Option<u16>,
    /// The green channel for this point.
    pub green: Option<u16>,
    /// The blue channel for this point.
    pub blue: Option<u16>,
}

/// The scan direction of the mirror when this point was collected.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ScanDirection {
    /// The scan was moving backward, whatever that means.
    Backward = 0,
    /// The scan was moving forward, whatever that means.
    Forward = 1,
}

impl Default for ScanDirection {
    fn default() -> ScanDirection {
        ScanDirection::Forward
    }
}

impl ScanDirection {
    /// Translates a u8 into a scan direction.
    ///
    /// Returns an error if the u8 is not zero or one.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::ScanDirection;
    /// assert_eq!(ScanDirection::Backward, ScanDirection::from_u8(0);
    /// assert_eq!(ScanDirection::Forward, ScanDirection::from_u8(1);
    /// ```
    pub fn from_u8(n: u8) -> Result<ScanDirection> {
        match n {
            0 => Ok(ScanDirection::Backward),
            1 => Ok(ScanDirection::Forward),
            _ => Err(Error::InvalidScanDirection(n)),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Classification {
    CreatedNeverClassified = 0,
    Unclassified = 1,
    Ground = 2,
    LowVegetation = 3,
    MediumVegetation = 4,
    HighVegetation = 5,
    Building = 6,
    LowPoint = 7,
    ModelKeyPoint = 8,
    Water = 9,
    Reserved10 = 10,
    Reserved11 = 11,
    Overlap = 12,
    Reserved,
}

impl Default for Classification {
    fn default() -> Classification {
        Classification::CreatedNeverClassified
    }
}

impl From<u8> for Classification {
    fn from(n: u8) -> Self {
        match n {
            0 => Classification::CreatedNeverClassified,
            1 => Classification::Unclassified,
            2 => Classification::Ground,
            3 => Classification::LowVegetation,
            4 => Classification::MediumVegetation,
            5 => Classification::HighVegetation,
            6 => Classification::Building,
            7 => Classification::LowPoint,
            8 => Classification::ModelKeyPoint,
            9 => Classification::Water,
            10 => Classification::Reserved10,
            11 => Classification::Reserved11,
            12 => Classification::Overlap,
            _ => Classification::Reserved,
       }
    }
}
<|endoftext|>


<commit_before>//! Module for creating text textures.

use std::ffi::CString;
use std::path::Path;
use sdl2_sys::pixels::{SDL_Color,SDL_PIXELFORMAT_ARGB8888};
use sdl2_sys::surface::SDL_Surface;
use sdl2_sys::surface;
use gl;

use common::color::Color4;

use yaglw::gl_context::GLContext;
use yaglw::texture::Texture2D;

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(missing_docs)]
pub mod ffi {
  extern crate libc;

  use sdl2_sys::pixels::SDL_Color;
  use sdl2_sys::surface::SDL_Surface;

  pub use self::libc::{c_int, c_char, c_void, c_long};

  pub type TTF_Font = c_void;

  pub type TTF_StyleFlag = c_int;
  pub static TTF_STYLE_NORMAL: TTF_StyleFlag = 0x00;
  pub static TTF_STYLE_BOLD: TTF_StyleFlag = 0x01;
  pub static TTF_STYLE_ITALIC: TTF_StyleFlag = 0x02;
  pub static TTF_STYLE_UNDERLINE: c_int = 0x04;
  pub static TTF_STYLE_STRIKETHROUGH: c_int = 0x08;

  pub type TTF_Hinting = c_int;
  pub static TTF_HINTING_NORMAL: TTF_Hinting = 0;
  pub static TTF_HINTING_LIGHT: TTF_Hinting = 1;
  pub static TTF_HINTING_MONO: TTF_Hinting = 2;
  pub static TTF_HINTING_NONE: TTF_Hinting = 3;

  #[link(name="SDL2_ttf")]
  extern "C" {
    pub fn TTF_Init() -> c_int;
    pub fn TTF_WasInit() -> c_int;
    pub fn TTF_Quit();
    pub fn TTF_OpenFont(file: *const c_char, ptsize: c_int) -> *mut TTF_Font;
    pub fn TTF_OpenFontIndex(file: *const c_char, ptsize: c_int, index: c_long) -> *mut TTF_Font;
    pub fn TTF_CloseFont(font: *mut TTF_Font);

    pub fn TTF_GetFontStyle(font: *const TTF_Font) -> TTF_StyleFlag;
    pub fn TTF_SetFontStyle(font: *mut TTF_Font, style: TTF_StyleFlag);
    pub fn TTF_GetFontOutline(font: *const TTF_Font) -> c_int;
    pub fn TTF_SetFontOutline(font: *mut TTF_Font, outline: c_int);
    pub fn TTF_GetFontHinting(font: *const TTF_Font) -> TTF_Hinting;
    pub fn TTF_SetFontHinting(font: *mut TTF_Font, hinting: TTF_Hinting);
    pub fn TTF_GetFontKerning(font: *const TTF_Font) -> c_int;
    pub fn TTF_SetFontKerning(font: *mut TTF_Font, kerning: c_int);
    pub fn TTF_FontHeight(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontAscent(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontDescent(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontLineSkip(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontFaces(font: *const TTF_Font) -> c_long;
    pub fn TTF_FontFaceIsFixedWidth(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontFaceFamilyName(font: *const TTF_Font) -> *const c_char;
    pub fn TTF_GlyphIsProvided(font: *const TTF_Font, glyph: u16) -> c_int;
    pub fn TTF_GlyphMetrics(font: *const TTF_Font, glyph: u16, minx: *mut c_int, maxx: *mut c_int, miny: *mut c_int, maxy: *mut c_int, advance: *mut c_int) -> c_int;
    pub fn TTF_SizeUTF8(font: *mut TTF_Font, text: *const c_char, w: *mut c_int, h: *mut c_int) -> c_int;

    pub fn TTF_RenderUTF8_Solid(font: *const TTF_Font, text: *const c_char, fg: SDL_Color) -> *mut SDL_Surface;
    pub fn TTF_RenderUTF8_Shaded(font:  *const TTF_Font, text: *const c_char, fg: SDL_Color, bg: SDL_Color) -> *mut SDL_Surface;
    pub fn TTF_RenderUTF8_Blended(font: *const TTF_Font, text: *const c_char, fg: SDL_Color)                -> *mut SDL_Surface;
  }
}

/// SDL Font datatype.
pub struct Font {
  p: *mut ffi::TTF_Font
}

fn ensure_init() {
  unsafe {
    if ffi::TTF_WasInit() == 0 {
      assert_eq!(ffi::TTF_Init(), 0);
    }
  }
}

impl Font {
  #[allow(missing_docs)]
  pub fn new(font: &Path, point_size: u32) -> Font {
    ensure_init();

    let c_path = CString::new(font.to_str().unwrap().as_bytes()).unwrap();
    let ptr = c_path.as_ptr() as *const i8;
    let p = unsafe { ffi::TTF_OpenFont(ptr, point_size as ffi::c_int) };

    assert!(!p.is_null());

    Font { p: p }
  }

  /// Color is rgba
  pub fn render<'a, 'b:'a>(
    &self,
    gl: &'a GLContext,
    txt: &str,
    color: Color4<u8>,
  ) -> Texture2D<'b> {
    let sdl_color = SDL_Color {
      r: color.r,
      g: color.g,
      b: color.b,
      a: color.a
    };

    let surface_ptr = {
      let c_str = CString::new(txt.as_bytes()).unwrap();
      let ptr = c_str.as_ptr() as *const i8;
      unsafe {
        ffi::TTF_RenderUTF8_Blended(self.p as *const ffi::c_void, ptr, sdl_color)
      }
    };

    let tex = unsafe {
      surface_ptr.as_ref().expect("Cannot render text.")
    };

    unsafe {
      assert_eq!((*tex.format).format, SDL_PIXELFORMAT_ARGB8888);
    }

    let texture = Texture2D::new(gl);
    unsafe {
      gl::BindTexture(gl::TEXTURE_2D, texture.handle.gl_id);
      gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, tex.w, tex.h, 0, gl::BGRA, gl::UNSIGNED_INT_8_8_8_8_REV, tex.pixels as *const _);
      gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
      gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

      surface::SDL_FreeSurface(surface_ptr as *mut SDL_Surface);
    }

    texture
  }

  /// Color the text red.
  #[allow(dead_code)]
  pub fn red<'a>(&self, gl: &'a GLContext, txt: &str) -> Texture2D<'a> {
    self.render(gl, txt, Color4::of_rgba(0xFF, 0x00, 0x00, 0xFF))
  }

  /// dark black #333
  #[allow(dead_code)]
  pub fn dark<'a>(&self, gl: &'a GLContext, txt: &str) -> Texture2D<'a> {
    self.render(gl, txt, Color4::of_rgba(0x33, 0x33, 0x33, 0xFF))
  }

  /// light black #555
  #[allow(dead_code)]
  pub fn light<'a>(&self, gl: &'a GLContext, txt: &str) -> Texture2D<'a> {
    self.render(gl, txt, Color4::of_rgba(0x55, 0x55, 0x55, 0xFF))
  }
}

impl Drop for Font {
  fn drop(&mut self) {
    unsafe { ffi::TTF_CloseFont(self.p) }
  }
}

#[test]
fn load_and_unload() {
  Font::new(&Path::new("fonts/Open_Sans/OpenSans-Regular.ttf"), 12);
}
<commit_msg>flaky test<commit_after>//! Module for creating text textures.

use std::ffi::CString;
use std::path::Path;
use sdl2_sys::pixels::{SDL_Color,SDL_PIXELFORMAT_ARGB8888};
use sdl2_sys::surface::SDL_Surface;
use sdl2_sys::surface;
use gl;

use common::color::Color4;

use yaglw::gl_context::GLContext;
use yaglw::texture::Texture2D;

#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[allow(missing_docs)]
pub mod ffi {
  extern crate libc;

  use sdl2_sys::pixels::SDL_Color;
  use sdl2_sys::surface::SDL_Surface;

  pub use self::libc::{c_int, c_char, c_void, c_long};

  pub type TTF_Font = c_void;

  pub type TTF_StyleFlag = c_int;
  pub static TTF_STYLE_NORMAL: TTF_StyleFlag = 0x00;
  pub static TTF_STYLE_BOLD: TTF_StyleFlag = 0x01;
  pub static TTF_STYLE_ITALIC: TTF_StyleFlag = 0x02;
  pub static TTF_STYLE_UNDERLINE: c_int = 0x04;
  pub static TTF_STYLE_STRIKETHROUGH: c_int = 0x08;

  pub type TTF_Hinting = c_int;
  pub static TTF_HINTING_NORMAL: TTF_Hinting = 0;
  pub static TTF_HINTING_LIGHT: TTF_Hinting = 1;
  pub static TTF_HINTING_MONO: TTF_Hinting = 2;
  pub static TTF_HINTING_NONE: TTF_Hinting = 3;

  #[link(name="SDL2_ttf")]
  extern "C" {
    pub fn TTF_Init() -> c_int;
    pub fn TTF_WasInit() -> c_int;
    pub fn TTF_Quit();
    pub fn TTF_OpenFont(file: *const c_char, ptsize: c_int) -> *mut TTF_Font;
    pub fn TTF_OpenFontIndex(file: *const c_char, ptsize: c_int, index: c_long) -> *mut TTF_Font;
    pub fn TTF_CloseFont(font: *mut TTF_Font);

    pub fn TTF_GetFontStyle(font: *const TTF_Font) -> TTF_StyleFlag;
    pub fn TTF_SetFontStyle(font: *mut TTF_Font, style: TTF_StyleFlag);
    pub fn TTF_GetFontOutline(font: *const TTF_Font) -> c_int;
    pub fn TTF_SetFontOutline(font: *mut TTF_Font, outline: c_int);
    pub fn TTF_GetFontHinting(font: *const TTF_Font) -> TTF_Hinting;
    pub fn TTF_SetFontHinting(font: *mut TTF_Font, hinting: TTF_Hinting);
    pub fn TTF_GetFontKerning(font: *const TTF_Font) -> c_int;
    pub fn TTF_SetFontKerning(font: *mut TTF_Font, kerning: c_int);
    pub fn TTF_FontHeight(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontAscent(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontDescent(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontLineSkip(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontFaces(font: *const TTF_Font) -> c_long;
    pub fn TTF_FontFaceIsFixedWidth(font: *const TTF_Font) -> c_int;
    pub fn TTF_FontFaceFamilyName(font: *const TTF_Font) -> *const c_char;
    pub fn TTF_GlyphIsProvided(font: *const TTF_Font, glyph: u16) -> c_int;
    pub fn TTF_GlyphMetrics(font: *const TTF_Font, glyph: u16, minx: *mut c_int, maxx: *mut c_int, miny: *mut c_int, maxy: *mut c_int, advance: *mut c_int) -> c_int;
    pub fn TTF_SizeUTF8(font: *mut TTF_Font, text: *const c_char, w: *mut c_int, h: *mut c_int) -> c_int;

    pub fn TTF_RenderUTF8_Solid(font: *const TTF_Font, text: *const c_char, fg: SDL_Color) -> *mut SDL_Surface;
    pub fn TTF_RenderUTF8_Shaded(font:  *const TTF_Font, text: *const c_char, fg: SDL_Color, bg: SDL_Color) -> *mut SDL_Surface;
    pub fn TTF_RenderUTF8_Blended(font: *const TTF_Font, text: *const c_char, fg: SDL_Color)                -> *mut SDL_Surface;
  }
}

/// SDL Font datatype.
pub struct Font {
  p: *mut ffi::TTF_Font
}

fn ensure_init() {
  unsafe {
    if ffi::TTF_WasInit() == 0 {
      assert_eq!(ffi::TTF_Init(), 0);
    }
  }
}

impl Font {
  #[allow(missing_docs)]
  pub fn new(font: &Path, point_size: u32) -> Font {
    ensure_init();

    let c_path = CString::new(font.to_str().unwrap().as_bytes()).unwrap();
    let ptr = c_path.as_ptr() as *const i8;
    let p = unsafe { ffi::TTF_OpenFont(ptr, point_size as ffi::c_int) };

    assert!(!p.is_null());

    Font { p: p }
  }

  /// Color is rgba
  pub fn render<'a, 'b:'a>(
    &self,
    gl: &'a GLContext,
    txt: &str,
    color: Color4<u8>,
  ) -> Texture2D<'b> {
    let sdl_color = SDL_Color {
      r: color.r,
      g: color.g,
      b: color.b,
      a: color.a
    };

    let surface_ptr = {
      let c_str = CString::new(txt.as_bytes()).unwrap();
      let ptr = c_str.as_ptr() as *const i8;
      unsafe {
        ffi::TTF_RenderUTF8_Blended(self.p as *const ffi::c_void, ptr, sdl_color)
      }
    };

    let tex = unsafe {
      surface_ptr.as_ref().expect("Cannot render text.")
    };

    unsafe {
      assert_eq!((*tex.format).format, SDL_PIXELFORMAT_ARGB8888);
    }

    let texture = Texture2D::new(gl);
    unsafe {
      gl::BindTexture(gl::TEXTURE_2D, texture.handle.gl_id);
      gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGBA as i32, tex.w, tex.h, 0, gl::BGRA, gl::UNSIGNED_INT_8_8_8_8_REV, tex.pixels as *const _);
      gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
      gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);

      surface::SDL_FreeSurface(surface_ptr as *mut SDL_Surface);
    }

    texture
  }

  /// Color the text red.
  #[allow(dead_code)]
  pub fn red<'a>(&self, gl: &'a GLContext, txt: &str) -> Texture2D<'a> {
    self.render(gl, txt, Color4::of_rgba(0xFF, 0x00, 0x00, 0xFF))
  }

  /// dark black #333
  #[allow(dead_code)]
  pub fn dark<'a>(&self, gl: &'a GLContext, txt: &str) -> Texture2D<'a> {
    self.render(gl, txt, Color4::of_rgba(0x33, 0x33, 0x33, 0xFF))
  }

  /// light black #555
  #[allow(dead_code)]
  pub fn light<'a>(&self, gl: &'a GLContext, txt: &str) -> Texture2D<'a> {
    self.render(gl, txt, Color4::of_rgba(0x55, 0x55, 0x55, 0xFF))
  }
}

impl Drop for Font {
  fn drop(&mut self) {
    unsafe { ffi::TTF_CloseFont(self.p) }
  }
}

//#[test]
//fn load_and_unload() {
//  Font::new(&Path::new("fonts/Open_Sans/OpenSans-Regular.ttf"), 12);
//}
<|endoftext|>


<commit_before>extern crate serialize;

use benchmark::Metric;
use collections::HashMap;
use file::{read,write};
use hash::Hashes;
use language::Language;
use serialize::Decodable;
use serialize::json;

pub fn parse_language_file(language_file: &Path) -> Language {
    let mut decoder = match json::from_str(read(language_file).as_slice()) {
        Err(_) => fail!("{} is invalid json", language_file.display()),
        Ok(json) => json::Decoder::new(json),
    };

    match Decodable::decode(&mut decoder) {
        Err(_) => fail!("couldn't decode {}", language_file.display()),
        Ok(language) => language,
    }
}

pub fn load_hashes(id: &str) -> Hashes {
    let file = Path::new(format!("hashes/{}.json", id));

    if file.exists() {
        match json::from_str(read(&file).as_slice()) {
            Err(_) => HashMap::new(),
            Ok(json) => {
                match Decodable::decode(&mut json::Decoder::new(json)) {
                    Err(_) => HashMap::new(),
                    Ok(map) => map,
                }
            }
        }
    } else {
        HashMap::new()
    }
}

pub fn load_metrics(id: &str) -> Vec<Metric> {
    let file = Path::new(format!("metrics/{}.json", id));

    if file.exists() {
        match json::from_str(read(&file).as_slice()) {
            Err(_) => Vec::new(),
            Ok(json) => {
                match Decodable::decode(&mut json::Decoder::new(json)) {
                    Err(_) => Vec::new(),
                    Ok(map) => map,
                }
            }
        }
    } else {
        Vec::new()
    }
}

pub fn save_hashes(id: &str, hashes: &Hashes) {
    let hashes_file = Path::new(format!("hashes/{}.json", id));

    write(&hashes_file, json::Encoder::str_encode(hashes).as_slice());
}

pub fn update_metrics(id: &str, mut new_metrics: Vec<Metric>) {
    let metrics_file = Path::new(format!("metrics/{}.json", id));
    let mut old_metrics = load_metrics(id);
    let mut metrics = Vec::new();

    old_metrics.sort_by(|a, b| {
        a.language().cmp(&b.language())
    });
    new_metrics.sort_by(|a, b| {
        a.language().cmp(&b.language())
    });

    loop {
        match (old_metrics.pop(), new_metrics.pop()) {
            (None, None) => break,
            (Some(old), None) => {
                metrics.push(old);
            },
            (None, Some(new)) => {
                metrics.push(new);
            },
            (Some(old), Some(new)) => {
                match old.language().cmp(&new.language()) {
                    Less => {
                        metrics.push(new);
                        old_metrics.push(old);
                    },
                    Equal => {
                        let diff = (new.median() / old.median() - 1.0) * 100.0;

                        if new.min() > old.max() {
                            println!("* {} improved by {:.2}%",
                                     new.language(),
                                     diff)
                        } else if new.max() < old.min() {
                            println!("* {} regressed by {:.2}%",
                                     new.language(),
                                     -diff)
                        }

                        metrics.push(new);
                    },
                    Greater => {
                        metrics.push(old);
                        new_metrics.push(new);
                    },
                }
            }
        }
    }

    metrics.sort_by(|a, b| {
        ((1000.0 * a.median()) as u64).cmp(&((1000.0 * b.median()) as u64))
    });

    write(&metrics_file, json::Encoder::str_encode(&metrics).as_slice());
}
<commit_msg>eulermark: fix logic of metric diff reporter<commit_after>extern crate serialize;

use benchmark::Metric;
use collections::HashMap;
use file::{read,write};
use hash::Hashes;
use language::Language;
use serialize::Decodable;
use serialize::json;

pub fn parse_language_file(language_file: &Path) -> Language {
    let mut decoder = match json::from_str(read(language_file).as_slice()) {
        Err(_) => fail!("{} is invalid json", language_file.display()),
        Ok(json) => json::Decoder::new(json),
    };

    match Decodable::decode(&mut decoder) {
        Err(_) => fail!("couldn't decode {}", language_file.display()),
        Ok(language) => language,
    }
}

pub fn load_hashes(id: &str) -> Hashes {
    let file = Path::new(format!("hashes/{}.json", id));

    if file.exists() {
        match json::from_str(read(&file).as_slice()) {
            Err(_) => HashMap::new(),
            Ok(json) => {
                match Decodable::decode(&mut json::Decoder::new(json)) {
                    Err(_) => HashMap::new(),
                    Ok(map) => map,
                }
            }
        }
    } else {
        HashMap::new()
    }
}

pub fn load_metrics(id: &str) -> Vec<Metric> {
    let file = Path::new(format!("metrics/{}.json", id));

    if file.exists() {
        match json::from_str(read(&file).as_slice()) {
            Err(_) => Vec::new(),
            Ok(json) => {
                match Decodable::decode(&mut json::Decoder::new(json)) {
                    Err(_) => Vec::new(),
                    Ok(map) => map,
                }
            }
        }
    } else {
        Vec::new()
    }
}

pub fn save_hashes(id: &str, hashes: &Hashes) {
    let hashes_file = Path::new(format!("hashes/{}.json", id));

    write(&hashes_file, json::Encoder::str_encode(hashes).as_slice());
}

pub fn update_metrics(id: &str, mut new_metrics: Vec<Metric>) {
    let metrics_file = Path::new(format!("metrics/{}.json", id));
    let mut old_metrics = load_metrics(id);
    let mut metrics = Vec::new();

    old_metrics.sort_by(|a, b| {
        a.language().cmp(&b.language())
    });
    new_metrics.sort_by(|a, b| {
        a.language().cmp(&b.language())
    });

    loop {
        match (old_metrics.pop(), new_metrics.pop()) {
            (None, None) => break,
            (Some(old), None) => {
                metrics.push(old);
            },
            (None, Some(new)) => {
                metrics.push(new);
            },
            (Some(old), Some(new)) => {
                match old.language().cmp(&new.language()) {
                    Less => {
                        metrics.push(new);
                        old_metrics.push(old);
                    },
                    Equal => {
                        let diff = (new.median() / old.median() - 1.0) * 100.0;

                        if new.min() > old.max() {
                            println!("* {} regressed by {:.2}%",
                                     new.language(),
                                     diff)
                        } else if new.max() < old.min() {
                            println!("* {} improved by {:.2}%",
                                     new.language(),
                                     -diff)
                        }

                        metrics.push(new);
                    },
                    Greater => {
                        metrics.push(old);
                        new_metrics.push(new);
                    },
                }
            }
        }
    }

    metrics.sort_by(|a, b| {
        ((1000.0 * a.median()) as u64).cmp(&((1000.0 * b.median()) as u64))
    });

    write(&metrics_file, json::Encoder::str_encode(&metrics).as_slice());
}
<|endoftext|>