<commit_before>use rand::{Rng, thread_rng};
use game::GameState;
use ship::{Ship, ShipDirection};
use space::Space;

pub struct Player {
    pub is_cpu: bool,
    spaces: Vec<Space>,
    ships: Vec<Ship>,
    grid_size: [u8; 2],
    grid_cursor: [u8; 2],
    pub temp_ship_pos: Vec<[u8; 2]>,
    pub temp_ship_dir: ShipDirection,
}

impl Player {
    pub fn new(grid_size: [u8; 2], is_cpu: bool) -> Player {
        let spaces_x = grid_size[0] as usize;
        let spaces_y = grid_size[1] as usize;
        let mut spaces = Vec::with_capacity(spaces_x * spaces_y);

        for col in 0..grid_size[0] {
            for row in 0..grid_size[1] {
                spaces.push(Space::new([col, row]));
            }
        }

        Player {
            is_cpu: is_cpu,
            spaces: spaces,
            ships: vec![],
            grid_size: grid_size,
            grid_cursor: [0, 0],
            temp_ship_pos: vec![[0, 0], [1, 0]],
            temp_ship_dir: ShipDirection::West,
        }
    }

    /// Selects a space and checks the status of ships if there's a hit.
    pub fn select_space(&mut self, pos: &[u8; 2]) -> GameState {
        let mut game_state = GameState::Active;
        let ship_hit = self.ships.iter().position(|s| s.pos().contains(pos));

        let space_index = self.space_index(pos);
        self.spaces[space_index].set_checked(ship_hit.is_some());

        if let Some(ship) = ship_hit {
            let ship_sunk = self.ships[ship].pos().iter()
                .all(|p| self.space(p).is_hit());

            if ship_sunk {
                self.ships[ship].sink();
            }

            let all_sunk = self.ships.iter().all(|s| !s.is_active());
            if all_sunk {
                game_state = GameState::Over;
            }
        }

        game_state
    }

    /// Determines the next space a CPU player will select.
    pub fn cpu_select_space(&self) -> [u8; 2] {
        let mut rng = thread_rng();
        let mut select = Vec::new();
        let mut directions = [
            ShipDirection::North,
            ShipDirection::East,
            ShipDirection::South,
            ShipDirection::West
        ];
        rng.shuffle(&mut directions);

        let mut hit_spaces = self.spaces.iter()
            .filter(|s| s.is_hit())
            .filter(|s| self.ship(s.pos()).unwrap().is_active())
            .collect::<Vec<&Space>>();

        rng.shuffle(&mut hit_spaces);

        // Check for a line of hit spaces.
        for space in &hit_spaces {
            for direction in &directions {
                let unchecked = self.find_unchecked_space(
                    space.pos(),
                    *direction,
                    true
                );

                if let Some(pos) = unchecked {
                    if !select.contains(&pos) {
                        select.push(pos);
                    }
                }
            }
        }

        // If a hit space was found, but no hit spaces next to it, find any
        // unchecked spaces next to it.
        if hit_spaces.len() > 0 && select.is_empty() {
            for direction in &directions {
                let unchecked = self.find_unchecked_space(
                    hit_spaces[0].pos(),
                    *direction,
                    false
                );

                if let Some(pos) = unchecked {
                    select.push(pos);
                }
            }
        }

        // If no spaces have been selected, just select any available space.
        if select.is_empty() {
            let mut pos: Option<[u8; 2]> = None;
            while pos.is_none() {
                let space = self.rng_pos();

                if self.space(&space).is_unchecked() {
                    pos = Some(space);
                }
            }

            select.push(pos.unwrap());
        }

        if select.len() > 1 {
            rng.shuffle(&mut select);
        }

        select[0]
    }

    fn rng_pos(&self) -> [u8; 2] {
        let mut rng = thread_rng();

        [
            rng.gen_range(0, self.grid_size[0]),
            rng.gen_range(0, self.grid_size[1]),
        ]
    }

    pub fn move_temp_ship(&mut self, direction: ShipDirection) {
        let old_head = self.temp_ship_pos[0];

        if let Some(new_head) = self.movement(&old_head, direction) {
            if let Some(ship) = self.get_ship_position(
                new_head,
                self.temp_ship_dir,
                self.temp_ship_pos.len() as u8
            ) {
                self.temp_ship_pos = ship;
            }
        }
    }

    pub fn place_temp_ship(&mut self) {
        let ship = self.temp_ship_pos.clone();

        if self.valid_ship_position(&ship) {
            self.ships.push(Ship::new(ship));

            self.temp_ship_dir = ShipDirection::West;
            self.temp_ship_pos = self.get_ship_position(
                [0, 0],
                self.temp_ship_dir,
                self.temp_ship_pos.len() as u8 + 1
            ).unwrap();
        }
    }

    pub fn rotate_temp_ship(&mut self) {
        let direction = match self.temp_ship_dir {
            ShipDirection::North => ShipDirection::East,
            ShipDirection::East => ShipDirection::South,
            ShipDirection::South => ShipDirection::West,
            ShipDirection::West => ShipDirection::North,
        };

        if let Some(ship) = self.get_ship_position(
            self.temp_ship_pos[0],
            direction,
            self.temp_ship_pos.len() as u8
        ) {
            self.temp_ship_pos = ship;
            self.temp_ship_dir = direction;
        }
    }

    pub fn cpu_place_ships(&mut self) {
        for length in 2..6 {
            let ship_pos = self.cpu_place_ship(length);
            self.ships.push(Ship::new(ship_pos));
        }
    }

    /// RNGs ship locations for CPU players.
    fn cpu_place_ship(&self, length: u8) -> Vec<[u8; 2]> {
        let mut ship = vec![];
        let mut valid = false;
        let mut direction: ShipDirection;
        let mut rng = thread_rng();

        // RNG a position and direction, then make sure it's valid.
        while !valid {
            let pos = self.rng_pos();
            direction = match rng.gen_range(0, 4) {
                0 => ShipDirection::North,
                1 => ShipDirection::East,
                2 => ShipDirection::South,
                3 => ShipDirection::West,
                _ => unreachable!()
            };

            if let Some(s) = self.get_ship_position(pos, direction, length) {
                valid = self.valid_ship_position(&s);

                if valid {
                    ship = s;
                }
            }
        }

        ship
    }

    /// Returns a ship position, given its head position, direction and length.
    ///
    /// `direction` refers to the direction the ship is facing, not the
    /// direction in which positions are generated.
    /// Returns `None` if the resulting ship position would not be contained
    /// within the grid.
    pub fn get_ship_position(
        &self,
        head: [u8; 2],
        direction: ShipDirection,
        length: u8
    ) -> Option<Vec<[u8; 2]>> {
        let valid = match direction {
            ShipDirection::North => head[1] + length <= self.grid_size[1],
            ShipDirection::East => head[0] >= length - 1,
            ShipDirection::South => head[1] >= length - 1,
            ShipDirection::West => head[0] + length <= self.grid_size[0],
        };

        let ship_opt = if valid {
            let mut ship = vec![head];

            for pos in 1..length {
                let pos_u8 = pos as u8;
                let space = match direction {
                    ShipDirection::North => [head[0], head[1] + pos_u8],
                    ShipDirection::East => [head[0] - pos_u8, head[1]],
                    ShipDirection::South => [head[0], head[1] - pos_u8],
                    ShipDirection::West => [head[0] + pos_u8, head[1]],
                };
                ship.push(space);
            }
            Some(ship)
        } else {
            None
        };

        ship_opt
    }

    /// Checks that the given ship position is valid.
    ///
    /// If the player is CPU-controlled, a ship in a space next to another ship
    /// will be considered invalid.
    pub fn valid_ship_position(&self, new_ship: &Vec<[u8; 2]>) -> bool {
        new_ship.iter()
            .all(|s| self.valid_space(s) && !self.ship_is_in_space(s)
                 && !(self.ship_is_next_to(s) && self.is_cpu))
    }

    /// Gets a reference to the ships.
    pub fn ships(&self) -> &Vec<Ship> {
        &self.ships
    }

    /// Gets a reference to a ship if it is in the given position.
    fn ship(&self, pos: &[u8; 2]) -> Option<&Ship> {
        self.ships.iter().find(|s| s.pos().contains(pos))
    }

    /// Returns whether a ship occupies the specified grid coordinates.
    pub fn ship_is_in_space(&self, pos: &[u8; 2]) -> bool {
        self.ships.iter().any(|s| s.pos().contains(pos))
    }

    /// Returns whether there is a ship next to the specified grid coordinates.
    fn ship_is_next_to(&self, pos: &[u8; 2]) -> bool {
        let mut result = false;
        let x = pos[0];
        let y = pos[1];

        // Left
        if x > 0 {
            result = self.ship_is_in_space(&[x - 1, y]);
        }

        // Right
        if x < self.grid_size[0] - 1 && !result {
            result = self.ship_is_in_space(&[x + 1, y]);
        }

        // Above
        if y > 0 && !result {
            result = self.ship_is_in_space(&[x, y - 1]);
        }

        // Below
        if y < self.grid_size[1] - 1 && !result {
            result = self.ship_is_in_space(&[x, y + 1]);
        }

        result
    }

    /// Gets a reference to the spaces.
    pub fn spaces(&self) -> &Vec<Space> {
        &self.spaces
    }

    /// Returns whether the given position is valid.
    fn valid_space(&self, pos: &[u8; 2]) -> bool {
        pos[0] < self.grid_size[0] && pos[1] < self.grid_size[1]
    }

    /// Gets a reference to the space with the given position.
    pub fn space(&self, pos: &[u8; 2]) -> &Space {
        self.spaces.get(self.space_index(pos)).unwrap()
    }

    /// Calculates the index of the given position in the spaces vector.
    fn space_index(&self, pos: &[u8; 2]) -> usize {
        self.grid_size[0] as usize * pos[0] as usize + pos[1] as usize
    }

    /// Returns the coordinates of the player's grid cursor.
    pub fn get_grid_cursor(&self) -> [u8; 2] {
        self.grid_cursor.clone()
    }

    /// Returns the coordinates of a movement from `pos` in a `direction`.
    /// Returns `None` if the movement is not possible.
    pub fn movement(&self, pos: &[u8; 2], direction: ShipDirection) -> Option<[u8; 2]> {
        let valid = match direction {
            ShipDirection::North => pos[1] > 0,
            ShipDirection::East => pos[0] < self.grid_size[0] - 1,
            ShipDirection::South => pos[1] < self.grid_size[1] - 1,
            ShipDirection::West => pos[0] > 0,
        };

        if valid {
            let movement = match direction {
                ShipDirection::North => [pos[0], pos[1] - 1],
                ShipDirection::East => [pos[0] + 1, pos[1]],
                ShipDirection::South => [pos[0], pos[1] + 1],
                ShipDirection::West => [pos[0] - 1, pos[1]],
            };
            Some(movement)
        } else {
            None
        }
    }

    /// Finds the first non-hit, unchecked space in a `direction` from `pos`.
    /// Can also make sure the space is at the end of a `line` of hit spaces.
    /// Returns `None` if the first non-hit space has been checked or if a grid
    /// boundary is reached.
    fn find_unchecked_space(
        &self,
        pos: &[u8; 2],
        direction: ShipDirection,
        check_for_line: bool
    ) -> Option<[u8; 2]> {
        let mut check_pos = self.movement(pos, direction);

        while let Some(next_pos) = check_pos {
            let next_space = self.space(&next_pos);

            match next_space.is_hit() {
                true => check_pos = self.movement(&next_pos, direction),
                false => {
                    if !next_space.is_unchecked() {
                        check_pos = None;
                    }
                    break;
                }
            };
        }

        if check_for_line && check_pos.is_some() {
            let unchecked = check_pos.unwrap();
            let opposite_dir = direction.opposite();
            let prev_pos = self.movement(&unchecked, opposite_dir).unwrap();

            if &prev_pos == pos {
                check_pos = None;
            }
        }

        check_pos
    }

    /// Moves the player's grid cursor in the given `direction` if possible.
    pub fn move_grid_cursor(&mut self, direction: ShipDirection) {
        if let Some(new_cursor) = self.movement(&self.grid_cursor, direction) {
            self.set_grid_cursor(&new_cursor);
        }
    }

    /// Sets the player's grid cursor coordinates.
    pub fn set_grid_cursor(&mut self, new_cursor: &[u8; 2]) {
        self.grid_cursor = *new_cursor;
    }
}

<commit_msg>Fix rng shuffle deprecation warnings<commit_after>use rand::{Rng, thread_rng};
use rand::seq::SliceRandom;
use game::GameState;
use ship::{Ship, ShipDirection};
use space::Space;

pub struct Player {
    pub is_cpu: bool,
    spaces: Vec<Space>,
    ships: Vec<Ship>,
    grid_size: [u8; 2],
    grid_cursor: [u8; 2],
    pub temp_ship_pos: Vec<[u8; 2]>,
    pub temp_ship_dir: ShipDirection,
}

impl Player {
    pub fn new(grid_size: [u8; 2], is_cpu: bool) -> Player {
        let spaces_x = grid_size[0] as usize;
        let spaces_y = grid_size[1] as usize;
        let mut spaces = Vec::with_capacity(spaces_x * spaces_y);

        for col in 0..grid_size[0] {
            for row in 0..grid_size[1] {
                spaces.push(Space::new([col, row]));
            }
        }

        Player {
            is_cpu: is_cpu,
            spaces: spaces,
            ships: vec![],
            grid_size: grid_size,
            grid_cursor: [0, 0],
            temp_ship_pos: vec![[0, 0], [1, 0]],
            temp_ship_dir: ShipDirection::West,
        }
    }

    /// Selects a space and checks the status of ships if there's a hit.
    pub fn select_space(&mut self, pos: &[u8; 2]) -> GameState {
        let mut game_state = GameState::Active;
        let ship_hit = self.ships.iter().position(|s| s.pos().contains(pos));

        let space_index = self.space_index(pos);
        self.spaces[space_index].set_checked(ship_hit.is_some());

        if let Some(ship) = ship_hit {
            let ship_sunk = self.ships[ship].pos().iter()
                .all(|p| self.space(p).is_hit());

            if ship_sunk {
                self.ships[ship].sink();
            }

            let all_sunk = self.ships.iter().all(|s| !s.is_active());
            if all_sunk {
                game_state = GameState::Over;
            }
        }

        game_state
    }

    /// Determines the next space a CPU player will select.
    pub fn cpu_select_space(&self) -> [u8; 2] {
        let mut rng = thread_rng();
        let mut select = Vec::new();
        let mut directions = [
            ShipDirection::North,
            ShipDirection::East,
            ShipDirection::South,
            ShipDirection::West
        ];

        directions.shuffle(&mut rng);

        let mut hit_spaces = self.spaces.iter()
            .filter(|s| s.is_hit())
            .filter(|s| self.ship(s.pos()).unwrap().is_active())
            .collect::<Vec<&Space>>();

        hit_spaces.shuffle(&mut rng);

        // Check for a line of hit spaces.
        for space in &hit_spaces {
            for direction in &directions {
                let unchecked = self.find_unchecked_space(
                    space.pos(),
                    *direction,
                    true
                );

                if let Some(pos) = unchecked {
                    if !select.contains(&pos) {
                        select.push(pos);
                    }
                }
            }
        }

        // If a hit space was found, but no hit spaces next to it, find any
        // unchecked spaces next to it.
        if hit_spaces.len() > 0 && select.is_empty() {
            for direction in &directions {
                let unchecked = self.find_unchecked_space(
                    hit_spaces[0].pos(),
                    *direction,
                    false
                );

                if let Some(pos) = unchecked {
                    select.push(pos);
                }
            }
        }

        // If no spaces have been selected, just select any available space.
        if select.is_empty() {
            let mut pos: Option<[u8; 2]> = None;
            while pos.is_none() {
                let space = self.rng_pos();

                if self.space(&space).is_unchecked() {
                    pos = Some(space);
                }
            }

            select.push(pos.unwrap());
        }

        if select.len() > 1 {
            select.shuffle(&mut rng);
        }

        select[0]
    }

    fn rng_pos(&self) -> [u8; 2] {
        let mut rng = thread_rng();

        [
            rng.gen_range(0, self.grid_size[0]),
            rng.gen_range(0, self.grid_size[1]),
        ]
    }

    pub fn move_temp_ship(&mut self, direction: ShipDirection) {
        let old_head = self.temp_ship_pos[0];

        if let Some(new_head) = self.movement(&old_head, direction) {
            if let Some(ship) = self.get_ship_position(
                new_head,
                self.temp_ship_dir,
                self.temp_ship_pos.len() as u8
            ) {
                self.temp_ship_pos = ship;
            }
        }
    }

    pub fn place_temp_ship(&mut self) {
        let ship = self.temp_ship_pos.clone();

        if self.valid_ship_position(&ship) {
            self.ships.push(Ship::new(ship));

            self.temp_ship_dir = ShipDirection::West;
            self.temp_ship_pos = self.get_ship_position(
                [0, 0],
                self.temp_ship_dir,
                self.temp_ship_pos.len() as u8 + 1
            ).unwrap();
        }
    }

    pub fn rotate_temp_ship(&mut self) {
        let direction = match self.temp_ship_dir {
            ShipDirection::North => ShipDirection::East,
            ShipDirection::East => ShipDirection::South,
            ShipDirection::South => ShipDirection::West,
            ShipDirection::West => ShipDirection::North,
        };

        if let Some(ship) = self.get_ship_position(
            self.temp_ship_pos[0],
            direction,
            self.temp_ship_pos.len() as u8
        ) {
            self.temp_ship_pos = ship;
            self.temp_ship_dir = direction;
        }
    }

    pub fn cpu_place_ships(&mut self) {
        for length in 2..6 {
            let ship_pos = self.cpu_place_ship(length);
            self.ships.push(Ship::new(ship_pos));
        }
    }

    /// RNGs ship locations for CPU players.
    fn cpu_place_ship(&self, length: u8) -> Vec<[u8; 2]> {
        let mut ship = vec![];
        let mut valid = false;
        let mut direction: ShipDirection;
        let mut rng = thread_rng();

        // RNG a position and direction, then make sure it's valid.
        while !valid {
            let pos = self.rng_pos();
            direction = match rng.gen_range(0, 4) {
                0 => ShipDirection::North,
                1 => ShipDirection::East,
                2 => ShipDirection::South,
                3 => ShipDirection::West,
                _ => unreachable!()
            };

            if let Some(s) = self.get_ship_position(pos, direction, length) {
                valid = self.valid_ship_position(&s);

                if valid {
                    ship = s;
                }
            }
        }

        ship
    }

    /// Returns a ship position, given its head position, direction and length.
    ///
    /// `direction` refers to the direction the ship is facing, not the
    /// direction in which positions are generated.
    /// Returns `None` if the resulting ship position would not be contained
    /// within the grid.
    pub fn get_ship_position(
        &self,
        head: [u8; 2],
        direction: ShipDirection,
        length: u8
    ) -> Option<Vec<[u8; 2]>> {
        let valid = match direction {
            ShipDirection::North => head[1] + length <= self.grid_size[1],
            ShipDirection::East => head[0] >= length - 1,
            ShipDirection::South => head[1] >= length - 1,
            ShipDirection::West => head[0] + length <= self.grid_size[0],
        };

        let ship_opt = if valid {
            let mut ship = vec![head];

            for pos in 1..length {
                let pos_u8 = pos as u8;
                let space = match direction {
                    ShipDirection::North => [head[0], head[1] + pos_u8],
                    ShipDirection::East => [head[0] - pos_u8, head[1]],
                    ShipDirection::South => [head[0], head[1] - pos_u8],
                    ShipDirection::West => [head[0] + pos_u8, head[1]],
                };
                ship.push(space);
            }
            Some(ship)
        } else {
            None
        };

        ship_opt
    }

    /// Checks that the given ship position is valid.
    ///
    /// If the player is CPU-controlled, a ship in a space next to another ship
    /// will be considered invalid.
    pub fn valid_ship_position(&self, new_ship: &Vec<[u8; 2]>) -> bool {
        new_ship.iter()
            .all(|s| self.valid_space(s) && !self.ship_is_in_space(s)
                 && !(self.ship_is_next_to(s) && self.is_cpu))
    }

    /// Gets a reference to the ships.
    pub fn ships(&self) -> &Vec<Ship> {
        &self.ships
    }

    /// Gets a reference to a ship if it is in the given position.
    fn ship(&self, pos: &[u8; 2]) -> Option<&Ship> {
        self.ships.iter().find(|s| s.pos().contains(pos))
    }

    /// Returns whether a ship occupies the specified grid coordinates.
    pub fn ship_is_in_space(&self, pos: &[u8; 2]) -> bool {
        self.ships.iter().any(|s| s.pos().contains(pos))
    }

    /// Returns whether there is a ship next to the specified grid coordinates.
    fn ship_is_next_to(&self, pos: &[u8; 2]) -> bool {
        let mut result = false;
        let x = pos[0];
        let y = pos[1];

        // Left
        if x > 0 {
            result = self.ship_is_in_space(&[x - 1, y]);
        }

        // Right
        if x < self.grid_size[0] - 1 && !result {
            result = self.ship_is_in_space(&[x + 1, y]);
        }

        // Above
        if y > 0 && !result {
            result = self.ship_is_in_space(&[x, y - 1]);
        }

        // Below
        if y < self.grid_size[1] - 1 && !result {
            result = self.ship_is_in_space(&[x, y + 1]);
        }

        result
    }

    /// Gets a reference to the spaces.
    pub fn spaces(&self) -> &Vec<Space> {
        &self.spaces
    }

    /// Returns whether the given position is valid.
    fn valid_space(&self, pos: &[u8; 2]) -> bool {
        pos[0] < self.grid_size[0] && pos[1] < self.grid_size[1]
    }

    /// Gets a reference to the space with the given position.
    pub fn space(&self, pos: &[u8; 2]) -> &Space {
        self.spaces.get(self.space_index(pos)).unwrap()
    }

    /// Calculates the index of the given position in the spaces vector.
    fn space_index(&self, pos: &[u8; 2]) -> usize {
        self.grid_size[0] as usize * pos[0] as usize + pos[1] as usize
    }

    /// Returns the coordinates of the player's grid cursor.
    pub fn get_grid_cursor(&self) -> [u8; 2] {
        self.grid_cursor.clone()
    }

    /// Returns the coordinates of a movement from `pos` in a `direction`.
    /// Returns `None` if the movement is not possible.
    pub fn movement(&self, pos: &[u8; 2], direction: ShipDirection) -> Option<[u8; 2]> {
        let valid = match direction {
            ShipDirection::North => pos[1] > 0,
            ShipDirection::East => pos[0] < self.grid_size[0] - 1,
            ShipDirection::South => pos[1] < self.grid_size[1] - 1,
            ShipDirection::West => pos[0] > 0,
        };

        if valid {
            let movement = match direction {
                ShipDirection::North => [pos[0], pos[1] - 1],
                ShipDirection::East => [pos[0] + 1, pos[1]],
                ShipDirection::South => [pos[0], pos[1] + 1],
                ShipDirection::West => [pos[0] - 1, pos[1]],
            };
            Some(movement)
        } else {
            None
        }
    }

    /// Finds the first non-hit, unchecked space in a `direction` from `pos`.
    /// Can also make sure the space is at the end of a `line` of hit spaces.
    /// Returns `None` if the first non-hit space has been checked or if a grid
    /// boundary is reached.
    fn find_unchecked_space(
        &self,
        pos: &[u8; 2],
        direction: ShipDirection,
        check_for_line: bool
    ) -> Option<[u8; 2]> {
        let mut check_pos = self.movement(pos, direction);

        while let Some(next_pos) = check_pos {
            let next_space = self.space(&next_pos);

            match next_space.is_hit() {
                true => check_pos = self.movement(&next_pos, direction),
                false => {
                    if !next_space.is_unchecked() {
                        check_pos = None;
                    }
                    break;
                }
            };
        }

        if check_for_line && check_pos.is_some() {
            let unchecked = check_pos.unwrap();
            let opposite_dir = direction.opposite();
            let prev_pos = self.movement(&unchecked, opposite_dir).unwrap();

            if &prev_pos == pos {
                check_pos = None;
            }
        }

        check_pos
    }

    /// Moves the player's grid cursor in the given `direction` if possible.
    pub fn move_grid_cursor(&mut self, direction: ShipDirection) {
        if let Some(new_cursor) = self.movement(&self.grid_cursor, direction) {
            self.set_grid_cursor(&new_cursor);
        }
    }

    /// Sets the player's grid cursor coordinates.
    pub fn set_grid_cursor(&mut self, new_cursor: &[u8; 2]) {
        self.grid_cursor = *new_cursor;
    }
}

<|endoftext|>


<commit_before>// Extern crates.
use graphics::*;
use input::keyboard;
use current::{ Usage, UseCurrent };

// Local crate.
use action;
use settings;
use object;
use object::Object;
use text;
use game_state;
use player::{ Player };
use colors;
use snake::Snake;
use air_bottle::AirBottle;
use bar::Bar;

pub fn current_cam() -> Usage<'static, Cam> { UseCurrent }
pub fn current_game_state()
    -> Usage<'static, game_state::GameState> { UseCurrent }
pub fn current_objects() -> Usage<'static, Vec<Object>> { UseCurrent }
pub fn current_index() -> Usage<'static, Index> { UseCurrent }
pub fn current_settings() -> Usage<'static, Settings> { UseCurrent }
pub fn current_player() -> Usage<'static, Player> { UseCurrent }
pub fn current_snakes() -> Usage<'static, Vec<Snake>> { UseCurrent }
pub fn current_air_bottles() -> Usage<'static, Vec<AirBottle>> { UseCurrent }
pub fn current_bars() -> Usage<'static, Vec<Bar>> { UseCurrent }

pub fn app() {
    use std::cell::RefCell;
    use current::Current;

    let cam = Cam([0.0, 0.0]);
    let game_state = game_state::Play;
    let objects: Vec<Object> = Vec::new();
    let index = Index::new();
    let settings = Settings::new();
    let player = Player::new();
    let snakes: Vec<Snake> = Vec::new();
    let air_bottles: Vec<AirBottle> = Vec::new();
    let bars: Vec<Bar> = Vec::new();

    let cam = RefCell::new(cam);
    let game_state = RefCell::new(game_state);
    let objects = RefCell::new(objects);
    let index = RefCell::new(index);
    let settings = RefCell::new(settings);
    let player = RefCell::new(player);
    let snakes = RefCell::new(snakes);
    let air_bottles = RefCell::new(air_bottles);
    let bars = RefCell::new(bars);

    let cam_guard = cam.set_current();
    let game_state_guard = game_state.set_current();
    let objects_guard = objects.set_current();
    let index_guard = index.set_current();
    let settings_guard = settings.set_current();
    let player_guard = player.set_current();
    let snakes_guard = snakes.set_current();
    let air_bottles = air_bottles.set_current();
    let bars = bars.set_current();

    start();

    drop(cam_guard);
    drop(game_state_guard);
    drop(objects_guard);
    drop(index_guard);
    drop(settings_guard);
    drop(player_guard);
    drop(snakes_guard);
    drop(air_bottles);
    drop(bars);
}

fn start() {
    use event::{ RenderEvent, UpdateEvent, PressEvent, ReleaseEvent };
    use input;

    load();
    for e in ::events() {
        ::swap_backend(&e);
        e.render(|args| {
            ::render(args);
            ::fps_tick();
        });
        e.update(|args| {
            update(args.dt);
        });
        e.press(|button| {
            if let input::Keyboard(key) = button {
                key_press(key);
            }
        });
        e.release(|button| {
            if let input::Keyboard(key) = button {
                key_release(key);
            }
        });
    }
}

pub struct Cam(pub [f64, ..2]);

impl Cam {
    fn pos(&self) -> [f64, ..2] {
        let Cam(pos) = *self;
        pos
    }

    fn set(&mut self, val: [f64, ..2]) {
        *self = Cam(val);
    }
}

pub struct Index {
    pub player: Option<uint>,
    pub blood_bar: Option<uint>,
    pub air_bar: Option<uint>,
}

impl Index {
    pub fn new() -> Index {
        Index {
            player: None,
            blood_bar: None,
            air_bar: None
        }
    }
}

pub struct Settings {
    // Tells where the surface is.
    pub surface_y: Option<f64>,
    pub camera_follow_percentage: Option<f64>,
}

impl Settings {
    pub fn new() -> Settings {
        Settings {
            surface_y: None,
            camera_follow_percentage: None,
        }
    }
}

pub fn render<B: BackEnd<I>, I: ImageSize>(c: &Context, gl: &mut B) {
    let c = &c.reset();

    // Get camera coordinates.
    let [cam_x, mut cam_y] = current_cam().pos();
    cam_y += 0.4;

    // Render surface.
    let surface_y = current_settings().surface_y.unwrap();
    c.rect(-1.0, surface_y - cam_y, 2.0, 0.05).color(colors::BLUE).draw(gl);

    // Render objects in layers.
    let cam = &c.trans(-cam_x, -cam_y);
    for i in range(0u, settings::NUMBER_OF_LAYERS) {
        for obj in current_objects().iter() {
            if obj.layer == i { obj.render(cam, c, gl); }
        }
    }

    let text_c = c.flip_v();
    let text_c = text_c.zoom(0.0025);
    match *current_game_state() {
        game_state::Win => {
            let pos = settings::YOU_WIN_POS;
            text::text(settings::YOU_WIN_TEXT,
                &text_c
                .trans(pos[0], pos[1])
                .color(settings::YOU_WIN_TEXT_COLOR)
            , gl);
        },
        game_state::Lose => {
            let pos = settings::YOU_LOSE_POS;
            text::text(settings::YOU_LOSE_TEXT,
                &text_c
                .trans(pos[0], pos[1])
                .color(settings::YOU_LOSE_TEXT_COLOR)
            , gl);
        },
        game_state::Play => {

        },
    }
}

pub fn update(dt: f64) {

    fn player_pos() -> [f64, ..2] {
        let player_index = current_index().player.unwrap();
        current_objects()[player_index].pos
    }

    fn update_objects(dt: f64) {
        if *current_game_state() != game_state::Play { return; }

        current_player().update(dt);

        // Update states of objects.
        let player_pos = player_pos();
        let mut attack_damage: f64 = 0.0;
        for obj in current_objects().iter_mut() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }
        // Bite player.
        current_player().bite(attack_damage);

        // Decrease the player's air with time.
        let air = current_player().air;
        current_player().air = air - dt * settings::PLAYER_LOSE_AIR_SPEED;
    }

    update_objects(dt);

    fn fill_air() {
        let player_pos = player_pos();
        let mut air = current_player().air;
        for obj in current_objects().iter_mut() {
            let pos = obj.pos;
            match obj.data {
                object::AirBottleData(i) => {
                    let dx = pos[0] - player_pos[0];
                    let dy = pos[1] - player_pos[1];
                    let d = dx * dx + dy * dy;
                    if d <= settings::AIR_BOTTLE_RADIUS * settings::AIR_BOTTLE_RADIUS {
                        let air_bottle = &mut current_air_bottles()[i];
                        air += air_bottle.fill_up;
                        air_bottle.fill_up = 0.0;
                    }
                },
                _ => {}
            }
        }

        air = if air > 1.0 { 1.0 } else { air };
        current_player().air = air;
    }

    fill_air();

    fn win() {
        let player_pos = player_pos();
        // When player reaches surface, win.
        if player_pos[1] >= current_settings().surface_y.unwrap() {
            *current_game_state() = game_state::Win;
            return;
        }
    }

    win();

    fn lose() {
        let blood = current_player().blood;
        let air = current_player().air;
        if blood < 0.0 || air < 0.0 {
            *current_game_state() = game_state::Lose;
            return;
        }
    }

    lose();

    fn show_blood() {
        if current_index().blood_bar == None { return; }
        // Show blood.
        let player_blood = current_player().blood;
        let blood_bar_index = current_index().blood_bar.unwrap();
        let objects = &mut *current_objects();
        let blood_bar = objects.get_mut(blood_bar_index).unwrap();
        match blood_bar.data {
            object::BarData(i) => {
                current_bars()[i].value = player_blood;
            },
            _ => {},
        }
    }

    show_blood();

    fn show_air() {
        if current_index().air_bar == None { return; }
        // Show air.
        let player_air = current_player().air;
        let air_bar_index = current_index().air_bar.unwrap();
        let objects = &mut *current_objects();
        let ref mut air_bar = objects.get_mut(air_bar_index).unwrap();
        match air_bar.data {
            object::BarData(i) => {
                current_bars()[i].value = player_air;
            },
            _ => {},
        }
    }

    show_air();

    fn follow_player(dt: f64) {
        // Make camera follow player.
        let camera_pos = current_cam().pos();
        let camera_follow_percentage = current_settings().camera_follow_percentage.unwrap();
        let player_pos = player_pos();
        let (dx, dy) = (player_pos[0] - camera_pos[0], player_pos[1] - camera_pos[1]);
        let dx = camera_follow_percentage * dt * dx;
        let dy = camera_follow_percentage * dt * dy;
        current_cam().set([camera_pos[0] + dx, camera_pos[1] + dy]);
    }

    follow_player(dt);
}

pub fn load() {
    current_cam().set(settings::INITIAL_CAMERA_POS);
    current_settings().camera_follow_percentage = Some(settings::CAMERA_FOLLOW_PERCENTAGE);
    *current_game_state() = settings::INITIAL_GAME_STATE;

    // Add player.
    current_objects().push(Object::bar_background());
    current_index().player = Some(0);

    fn add_bars() {
        let objects = &mut *current_objects();
        objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        current_index().air_bar = Some(objects.len() - 1);
        objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        current_index().blood_bar = Some(objects.len() - 1);
    }

    // Add blood and air bar.
    add_bars();

    settings::level_1();
}

fn restart() {
    load();
}

pub fn key_press(key: keyboard::Key) {
    if *current_game_state() != game_state::Play { return; }

    match (key, current_index().player) {
        (keyboard::Right, Some(player_index)) => {
            current_objects()[player_index].move_right();
        },
        (keyboard::Up, Some(player_index)) => {
            println!("TEST move up {}", current_objects()[player_index].data);

            current_objects()[player_index].move_up();
        },
        (keyboard::Left, Some(player_index)) => {
            current_objects()[player_index].move_left();
        },
        (keyboard::Down, Some(player_index)) => {
            current_objects()[player_index].move_down();
        },
        _ => {},
    }
}

pub fn key_release(key: keyboard::Key) {
    if key == keyboard::Return || key == keyboard::Space {
        match *current_game_state() {
            game_state::Win | game_state::Lose => restart(),
            _ => {},
        }
    }
}
<commit_msg>Removed debug print statement<commit_after>// Extern crates.
use graphics::*;
use input::keyboard;
use current::{ Usage, UseCurrent };

// Local crate.
use action;
use settings;
use object;
use object::Object;
use text;
use game_state;
use player::{ Player };
use colors;
use snake::Snake;
use air_bottle::AirBottle;
use bar::Bar;

pub fn current_cam() -> Usage<'static, Cam> { UseCurrent }
pub fn current_game_state()
    -> Usage<'static, game_state::GameState> { UseCurrent }
pub fn current_objects() -> Usage<'static, Vec<Object>> { UseCurrent }
pub fn current_index() -> Usage<'static, Index> { UseCurrent }
pub fn current_settings() -> Usage<'static, Settings> { UseCurrent }
pub fn current_player() -> Usage<'static, Player> { UseCurrent }
pub fn current_snakes() -> Usage<'static, Vec<Snake>> { UseCurrent }
pub fn current_air_bottles() -> Usage<'static, Vec<AirBottle>> { UseCurrent }
pub fn current_bars() -> Usage<'static, Vec<Bar>> { UseCurrent }

pub fn app() {
    use std::cell::RefCell;
    use current::Current;

    let cam = Cam([0.0, 0.0]);
    let game_state = game_state::Play;
    let objects: Vec<Object> = Vec::new();
    let index = Index::new();
    let settings = Settings::new();
    let player = Player::new();
    let snakes: Vec<Snake> = Vec::new();
    let air_bottles: Vec<AirBottle> = Vec::new();
    let bars: Vec<Bar> = Vec::new();

    let cam = RefCell::new(cam);
    let game_state = RefCell::new(game_state);
    let objects = RefCell::new(objects);
    let index = RefCell::new(index);
    let settings = RefCell::new(settings);
    let player = RefCell::new(player);
    let snakes = RefCell::new(snakes);
    let air_bottles = RefCell::new(air_bottles);
    let bars = RefCell::new(bars);

    let cam_guard = cam.set_current();
    let game_state_guard = game_state.set_current();
    let objects_guard = objects.set_current();
    let index_guard = index.set_current();
    let settings_guard = settings.set_current();
    let player_guard = player.set_current();
    let snakes_guard = snakes.set_current();
    let air_bottles = air_bottles.set_current();
    let bars = bars.set_current();

    start();

    drop(cam_guard);
    drop(game_state_guard);
    drop(objects_guard);
    drop(index_guard);
    drop(settings_guard);
    drop(player_guard);
    drop(snakes_guard);
    drop(air_bottles);
    drop(bars);
}

fn start() {
    use event::{ RenderEvent, UpdateEvent, PressEvent, ReleaseEvent };
    use input;

    load();
    for e in ::events() {
        ::swap_backend(&e);
        e.render(|args| {
            ::render(args);
            ::fps_tick();
        });
        e.update(|args| {
            update(args.dt);
        });
        e.press(|button| {
            if let input::Keyboard(key) = button {
                key_press(key);
            }
        });
        e.release(|button| {
            if let input::Keyboard(key) = button {
                key_release(key);
            }
        });
    }
}

pub struct Cam(pub [f64, ..2]);

impl Cam {
    fn pos(&self) -> [f64, ..2] {
        let Cam(pos) = *self;
        pos
    }

    fn set(&mut self, val: [f64, ..2]) {
        *self = Cam(val);
    }
}

pub struct Index {
    pub player: Option<uint>,
    pub blood_bar: Option<uint>,
    pub air_bar: Option<uint>,
}

impl Index {
    pub fn new() -> Index {
        Index {
            player: None,
            blood_bar: None,
            air_bar: None
        }
    }
}

pub struct Settings {
    // Tells where the surface is.
    pub surface_y: Option<f64>,
    pub camera_follow_percentage: Option<f64>,
}

impl Settings {
    pub fn new() -> Settings {
        Settings {
            surface_y: None,
            camera_follow_percentage: None,
        }
    }
}

pub fn render<B: BackEnd<I>, I: ImageSize>(c: &Context, gl: &mut B) {
    let c = &c.reset();

    // Get camera coordinates.
    let [cam_x, mut cam_y] = current_cam().pos();
    cam_y += 0.4;

    // Render surface.
    let surface_y = current_settings().surface_y.unwrap();
    c.rect(-1.0, surface_y - cam_y, 2.0, 0.05).color(colors::BLUE).draw(gl);

    // Render objects in layers.
    let cam = &c.trans(-cam_x, -cam_y);
    for i in range(0u, settings::NUMBER_OF_LAYERS) {
        for obj in current_objects().iter() {
            if obj.layer == i { obj.render(cam, c, gl); }
        }
    }

    let text_c = c.flip_v();
    let text_c = text_c.zoom(0.0025);
    match *current_game_state() {
        game_state::Win => {
            let pos = settings::YOU_WIN_POS;
            text::text(settings::YOU_WIN_TEXT,
                &text_c
                .trans(pos[0], pos[1])
                .color(settings::YOU_WIN_TEXT_COLOR)
            , gl);
        },
        game_state::Lose => {
            let pos = settings::YOU_LOSE_POS;
            text::text(settings::YOU_LOSE_TEXT,
                &text_c
                .trans(pos[0], pos[1])
                .color(settings::YOU_LOSE_TEXT_COLOR)
            , gl);
        },
        game_state::Play => {

        },
    }
}

pub fn update(dt: f64) {

    fn player_pos() -> [f64, ..2] {
        let player_index = current_index().player.unwrap();
        current_objects()[player_index].pos
    }

    fn update_objects(dt: f64) {
        if *current_game_state() != game_state::Play { return; }

        current_player().update(dt);

        // Update states of objects.
        let player_pos = player_pos();
        let mut attack_damage: f64 = 0.0;
        for obj in current_objects().iter_mut() {
            match obj.update(dt, player_pos) {
                action::Passive => {},
                action::Attack(attack) => { attack_damage += attack; },
            }
        }
        // Bite player.
        current_player().bite(attack_damage);

        // Decrease the player's air with time.
        let air = current_player().air;
        current_player().air = air - dt * settings::PLAYER_LOSE_AIR_SPEED;
    }

    update_objects(dt);

    fn fill_air() {
        let player_pos = player_pos();
        let mut air = current_player().air;
        for obj in current_objects().iter_mut() {
            let pos = obj.pos;
            match obj.data {
                object::AirBottleData(i) => {
                    let dx = pos[0] - player_pos[0];
                    let dy = pos[1] - player_pos[1];
                    let d = dx * dx + dy * dy;
                    if d <= settings::AIR_BOTTLE_RADIUS * settings::AIR_BOTTLE_RADIUS {
                        let air_bottle = &mut current_air_bottles()[i];
                        air += air_bottle.fill_up;
                        air_bottle.fill_up = 0.0;
                    }
                },
                _ => {}
            }
        }

        air = if air > 1.0 { 1.0 } else { air };
        current_player().air = air;
    }

    fill_air();

    fn win() {
        let player_pos = player_pos();
        // When player reaches surface, win.
        if player_pos[1] >= current_settings().surface_y.unwrap() {
            *current_game_state() = game_state::Win;
            return;
        }
    }

    win();

    fn lose() {
        let blood = current_player().blood;
        let air = current_player().air;
        if blood < 0.0 || air < 0.0 {
            *current_game_state() = game_state::Lose;
            return;
        }
    }

    lose();

    fn show_blood() {
        if current_index().blood_bar == None { return; }
        // Show blood.
        let player_blood = current_player().blood;
        let blood_bar_index = current_index().blood_bar.unwrap();
        let objects = &mut *current_objects();
        let blood_bar = objects.get_mut(blood_bar_index).unwrap();
        match blood_bar.data {
            object::BarData(i) => {
                current_bars()[i].value = player_blood;
            },
            _ => {},
        }
    }

    show_blood();

    fn show_air() {
        if current_index().air_bar == None { return; }
        // Show air.
        let player_air = current_player().air;
        let air_bar_index = current_index().air_bar.unwrap();
        let objects = &mut *current_objects();
        let ref mut air_bar = objects.get_mut(air_bar_index).unwrap();
        match air_bar.data {
            object::BarData(i) => {
                current_bars()[i].value = player_air;
            },
            _ => {},
        }
    }

    show_air();

    fn follow_player(dt: f64) {
        // Make camera follow player.
        let camera_pos = current_cam().pos();
        let camera_follow_percentage = current_settings().camera_follow_percentage.unwrap();
        let player_pos = player_pos();
        let (dx, dy) = (player_pos[0] - camera_pos[0], player_pos[1] - camera_pos[1]);
        let dx = camera_follow_percentage * dt * dx;
        let dy = camera_follow_percentage * dt * dy;
        current_cam().set([camera_pos[0] + dx, camera_pos[1] + dy]);
    }

    follow_player(dt);
}

pub fn load() {
    current_cam().set(settings::INITIAL_CAMERA_POS);
    current_settings().camera_follow_percentage = Some(settings::CAMERA_FOLLOW_PERCENTAGE);
    *current_game_state() = settings::INITIAL_GAME_STATE;

    // Add player.
    current_objects().push(Object::bar_background());
    current_index().player = Some(0);

    fn add_bars() {
        let objects = &mut *current_objects();
        objects.push(Object::bar(
            settings::AIR_BAR_POS,
            "air",
            settings::AIR_BAR_TEXT_COLOR,
            settings::AIR_BAR_BACKGROUND_COLOR,
            settings::AIR_BAR_BAR_COLOR,
            settings::AIR_BAR_INITIAL_VALUE
        ));
        current_index().air_bar = Some(objects.len() - 1);
        objects.push(Object::bar(
            settings::BLOOD_BAR_POS,
            "blood",
            settings::BLOOD_BAR_TEXT_COLOR,
            settings::BLOOD_BAR_BACKGROUND_COLOR,
            settings::BLOOD_BAR_BAR_COLOR,
            settings::BLOOD_BAR_INITIAL_VALUE
        ));
        current_index().blood_bar = Some(objects.len() - 1);
    }

    // Add blood and air bar.
    add_bars();

    settings::level_1();
}

fn restart() {
    load();
}

pub fn key_press(key: keyboard::Key) {
    if *current_game_state() != game_state::Play { return; }

    match (key, current_index().player) {
        (keyboard::Right, Some(player_index)) => {
            current_objects()[player_index].move_right();
        },
        (keyboard::Up, Some(player_index)) => {
            current_objects()[player_index].move_up();
        },
        (keyboard::Left, Some(player_index)) => {
            current_objects()[player_index].move_left();
        },
        (keyboard::Down, Some(player_index)) => {
            current_objects()[player_index].move_down();
        },
        _ => {},
    }
}

pub fn key_release(key: keyboard::Key) {
    if key == keyboard::Return || key == keyboard::Space {
        match *current_game_state() {
            game_state::Win | game_state::Lose => restart(),
            _ => {},
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::cmp::min;

use arrayvec::ArrayVec;

use coefs::Coefficients;
use consts::MAX_HARMONICS;
use params::BaseParams;
use prev::PrevFrame;

#[derive(Clone)]
pub struct Spectrals(ArrayVec<[f32; MAX_HARMONICS]>);

impl Spectrals {
    pub fn new(coefs: &Coefficients, params: &BaseParams, prev: &PrevFrame) -> Spectrals {
        let mut spectral = ArrayVec::new();

        let indexes = |x: u32| {
            let k = prev.params.harmonics as f32 / params.harmonics as f32 * x as f32;
            (k.trunc() as usize, k.fract())
        };

        let pred = (0.03 * params.harmonics as f32 - 0.05).max(0.4).min(0.7);
        let pred_scaled = pred / params.harmonics as f32;

        let sum = (1...params.harmonics).map(|lambda| {
            let (k, dec) = indexes(lambda);
            (1.0 - dec) * prev.spectrals.get(k).log2() +
                dec * prev.spectrals.get(k + 1).log2()
        }).fold(0.0, |s, x| s + x);

        Spectrals((1...params.harmonics).map(|l| {
            let (k, dec) = indexes(l);

            (
                coefs.get(l as usize) +
                    pred * (1.0 - dec) * prev.spectrals.get(k).log2() +
                    pred * dec * prev.spectrals.get(k + 1).log2() -
                    pred_scaled * sum
            ).exp2()
        }).collect())
    }

    pub fn get(&self, l: usize) -> f32 {
        if l == 0 {
            1.0
        } else {
            self.0[min(l, self.0.len()) - 1]
        }
    }
}

impl std::ops::Deref for Spectrals {
    type Target = ArrayVec<[f32; MAX_HARMONICS]>;
    fn deref(&self) -> &Self::Target { &self.0 }
}

impl Default for Spectrals {
    fn default() -> Spectrals {
        Spectrals((0..MAX_HARMONICS).map(|_| 1.0).collect())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use descramble::{Bootstrap, descramble};
    use gain::Gains;
    use coefs::Coefficients;
    use params::BaseParams;
    use prev::{PrevFrame};

    #[test]
    fn test_spectrals() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10100110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());
        let (amps, _, gain_idx) = descramble(&chunks, &p);
        let g = Gains::new(gain_idx, &amps, &p);
        let c = Coefficients::new(&g, &amps, &p);
        let mut prev = PrevFrame::default();
        let s = Spectrals::new(&c, &p, &prev);

        assert_eq!(s.0.len(), 16);

        assert!((s.get(0) - 1.0).abs() < 0.000001);
        assert!((s.get(1) - 0.5306769781475001).abs() < 0.000001);
        assert!((s.get(2) - 0.3535007196676076).abs() < 0.000001);
        assert!((s.get(3) - 0.9173875577243951).abs() < 0.000001);
        assert!((s.get(4) - 0.13169278935782622).abs() < 0.000001);
        assert!((s.get(5) - 4.438599873836148).abs() < 0.00001);
        assert!((s.get(6) - 0.6796441620283217).abs() < 0.000001);
        assert!((s.get(7) - 0.9439604687782126).abs() < 0.000001);
        assert!((s.get(8) - 10.646341109175768).abs() < 0.000001);
        assert!((s.get(9) - 1.3058035207362984).abs() < 0.000001);
        assert!((s.get(10) - 1.566168983101457).abs() < 0.000001);
        assert!((s.get(11) - 8.325591838823936).abs() < 0.00001);
        assert!((s.get(12) - 1.5943520720633444).abs() < 0.000001);
        assert!((s.get(13) - 1.556318849691248).abs() < 0.000001);
        assert!((s.get(14) - 15.882295806333524).abs() < 0.00001);
        assert!((s.get(15) - 11.386537444591385).abs() < 0.00001);
        assert!((s.get(16) - 12.498792573794846).abs() < 0.00001);
        assert!((s.get(17) - 12.498792573794846).abs() < 0.00001);
        assert!((s.get(30) - 12.498792573794846).abs() < 0.00001);
        assert!((s.get(56) - 12.498792573794846).abs() < 0.00001);

        prev.spectrals = s;
        let s = Spectrals::new(&c, &p, &prev);

        assert!((s.get(1) - 0.18026009141598204).abs() < 0.000001);
        assert!((s.get(2) - 0.09466759399487303).abs() < 0.000001);
        assert!((s.get(3) - 0.546543586730317).abs() < 0.000001);
        assert!((s.get(4) - 0.11240949805284323).abs() < 0.000001);
        assert!((s.get(5) - 2.664303862945382).abs() < 0.000001);
        assert!((s.get(6) - 0.7356498197494585).abs() < 0.000001);
        assert!((s.get(7) - 0.6722918529743475).abs() < 0.000001);
        assert!((s.get(8) - 15.748045510026174).abs() < 0.000001);
        assert!((s.get(9) - 2.010522620838216).abs() < 0.000001);
        assert!((s.get(10) - 2.411402725277654).abs() < 0.000001);
        assert!((s.get(11) - 12.818766727159018).abs() < 0.00001);
        assert!((s.get(12) - 2.4547957296486485).abs() < 0.000001);
        assert!((s.get(13) - 2.396236648815911).abs() < 0.000001);
        assert!((s.get(14) - 24.45369037714974).abs() < 0.0001);
        assert!((s.get(15) - 17.53165062111628).abs() < 0.0001);
        assert!((s.get(16) - 19.244170201509185).abs() < 0.0001);
    }
}
<commit_msg>Revisit spectrals module<commit_after>use std;

use arrayvec::ArrayVec;

use coefs::Coefficients;
use consts::MAX_HARMONICS;
use params::BaseParams;
use prev::PrevFrame;

/// Spectral amplitudes Ml, 1 ≤ l ≤ L, measure the spectral envelope of the
/// voiced/unvoiced signal spectrum.
#[derive(Clone)]
pub struct Spectrals(ArrayVec<[f32; MAX_HARMONICS]>);

impl Spectrals {
    /// Create a new `Spectrals` from the given DCT coefficients vector Tl and
    /// current/previous frame parameters.
    pub fn new(coefs: &Coefficients, params: &BaseParams, prev: &PrevFrame) -> Spectrals {
        // Compute L(-1) / L(0).
        let scale = prev.params.harmonics as f32 / params.harmonics as f32;

        // Compute (k_l,  δ_l) for the given harmonic l [p35].
        let indexes = |l: u32| {
            let k = scale * l as f32;
            (k.trunc() as usize, k.fract())
        };

        // Compute prediction coefficient ρ [p27].
        let pred = (0.03 * params.harmonics as f32 - 0.05).max(0.4).min(0.7);

        // Compute the sum term.
        let sum = (1...params.harmonics).map(|l| indexes(l)).map(|(k, dec)| {
            (1.0 - dec) * prev.spectrals.get(k).log2() +
                dec * prev.spectrals.get(k + 1).log2()
        }).fold(0.0, |s, x| s + x) / params.harmonics as f32;

        // Compute M_l for each harmonic l.
        Spectrals((1...params.harmonics).map(|l| {
            let (k, dec) = indexes(l);

            (
                coefs.get(l as usize) + pred * (
                    (1.0 - dec) * prev.spectrals.get(k).log2() +
                    dec * prev.spectrals.get(k + 1).log2() -
                    sum
                )
            ).exp2()
        }).collect())
    }

    /// Retrieve the spectral amplitude Ml for the given l.
    pub fn get(&self, l: usize) -> f32 {
        if l == 0 {
            // Handles case of Eq 78.
            1.0
        } else if l > self.0.len() {
            // Handle case of Eq 79.
            *self.0.last().unwrap()
        } else {
            self.0[l - 1]
        }
    }
}

impl std::ops::Deref for Spectrals {
    type Target = ArrayVec<[f32; MAX_HARMONICS]>;
    fn deref(&self) -> &Self::Target { &self.0 }
}

impl Default for Spectrals {
    /// Construct the default set of spectral amplitudes.
    fn default() -> Spectrals {
        // By default, M_l = 1 [p35].
        Spectrals((0..MAX_HARMONICS).map(|_| 1.0).collect())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use descramble::{Bootstrap, descramble};
    use gain::Gains;
    use coefs::Coefficients;
    use params::BaseParams;
    use prev::{PrevFrame};

    #[test]
    fn test_spectrals() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10100110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());
        let (amps, _, gain_idx) = descramble(&chunks, &p);
        let g = Gains::new(gain_idx, &amps, &p);
        let c = Coefficients::new(&g, &amps, &p);
        let mut prev = PrevFrame::default();
        let s = Spectrals::new(&c, &p, &prev);

        assert_eq!(s.0.len(), 16);

        assert!((s.get(0) - 1.0).abs() < 0.000001);
        assert!((s.get(1) - 0.5306769781475001).abs() < 0.000001);
        assert!((s.get(2) - 0.3535007196676076).abs() < 0.000001);
        assert!((s.get(3) - 0.9173875577243951).abs() < 0.000001);
        assert!((s.get(4) - 0.13169278935782622).abs() < 0.000001);
        assert!((s.get(5) - 4.438599873836148).abs() < 0.00001);
        assert!((s.get(6) - 0.6796441620283217).abs() < 0.000001);
        assert!((s.get(7) - 0.9439604687782126).abs() < 0.000001);
        assert!((s.get(8) - 10.646341109175768).abs() < 0.000001);
        assert!((s.get(9) - 1.3058035207362984).abs() < 0.000001);
        assert!((s.get(10) - 1.566168983101457).abs() < 0.000001);
        assert!((s.get(11) - 8.325591838823936).abs() < 0.00001);
        assert!((s.get(12) - 1.5943520720633444).abs() < 0.000001);
        assert!((s.get(13) - 1.556318849691248).abs() < 0.000001);
        assert!((s.get(14) - 15.882295806333524).abs() < 0.00001);
        assert!((s.get(15) - 11.386537444591385).abs() < 0.00001);
        assert!((s.get(16) - 12.498792573794846).abs() < 0.00001);
        assert!((s.get(17) - 12.498792573794846).abs() < 0.00001);
        assert!((s.get(30) - 12.498792573794846).abs() < 0.00001);
        assert!((s.get(56) - 12.498792573794846).abs() < 0.00001);

        prev.spectrals = s;
        let s = Spectrals::new(&c, &p, &prev);

        assert!((s.get(1) - 0.18026009141598204).abs() < 0.000001);
        assert!((s.get(2) - 0.09466759399487303).abs() < 0.000001);
        assert!((s.get(3) - 0.546543586730317).abs() < 0.000001);
        assert!((s.get(4) - 0.11240949805284323).abs() < 0.000001);
        assert!((s.get(5) - 2.664303862945382).abs() < 0.000001);
        assert!((s.get(6) - 0.7356498197494585).abs() < 0.000001);
        assert!((s.get(7) - 0.6722918529743475).abs() < 0.000001);
        assert!((s.get(8) - 15.748045510026174).abs() < 0.000001);
        assert!((s.get(9) - 2.010522620838216).abs() < 0.000001);
        assert!((s.get(10) - 2.411402725277654).abs() < 0.000001);
        assert!((s.get(11) - 12.818766727159018).abs() < 0.00001);
        assert!((s.get(12) - 2.4547957296486485).abs() < 0.000001);
        assert!((s.get(13) - 2.396236648815911).abs() < 0.000001);
        assert!((s.get(14) - 24.45369037714974).abs() < 0.0001);
        assert!((s.get(15) - 17.53165062111628).abs() < 0.0001);
        assert!((s.get(16) - 19.244170201509185).abs() < 0.0001);
    }
}
<|endoftext|>


<commit_before>use libc::{pid_t, c_int};
use {Errno, Result};

use sys::signal;

mod ffi {
    use libc::{pid_t, c_int};

    extern {
        pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "android")))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = 0x00000001,
        const WUNTRACED   = 0x00000002,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = 0x00000001,
        const WUNTRACED   = 0x00000002,
        const WEXITED     = 0x00000004,
        const WCONTINUED  = 0x00000008,
        const WNOWAIT     = 0x01000000, // Don't reap, just poll status.
        const __WNOTHREAD = 0x20000000, // Don't wait on children of other threads in this group
        const __WALL      = 0x40000000, // Wait on all children, regardless of type
        // const __WCLONE    = 0x80000000,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
const WSTOPPED: WaitPidFlag = WUNTRACED;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
    Exited(pid_t, i8),
    Signaled(pid_t, signal::SigNum, bool),
    Stopped(pid_t, signal::SigNum),
    Continued(pid_t),
    StillAlive
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
mod status {
    use sys::signal;

    pub fn exited(status: i32) -> bool {
        (status & 0x7F) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status & 0xFF00) >> 8) as i8
    }

    pub fn signaled(status: i32) -> bool {
        ((((status & 0x7f) + 1) as i8) >> 1) > 0
    }

    pub fn term_signal(status: i32) -> signal::SigNum {
        (status & 0x7f) as signal::SigNum
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & 0x80) != 0
    }

    pub fn stopped(status: i32) -> bool {
        (status & 0xff) == 0x7f
    }

    pub fn stop_signal(status: i32) -> signal::SigNum {
        ((status & 0xFF00) >> 8) as signal::SigNum
    }

    pub fn continued(status: i32) -> bool {
        status == 0xFFFF
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod status {
    use sys::signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status >> 8) & 0xFF) as i8
    }

    pub fn stop_signal(status: i32) -> signal::SigNum {
        (status >> 8) as signal::SigNum
    }

    pub fn continued(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) == 0x13
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) != 0x13
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0
    }

    pub fn term_signal(status: i32) -> signal::SigNum {
        wstatus(status) as signal::SigNum
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
mod status {
    use sys::signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED
    }

    pub fn stop_signal(status: i32) -> signal::SigNum {
        (status >> 8) as signal::SigNum
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
    }

    pub fn term_signal(status: i32) -> signal::SigNum {
        wstatus(status) as signal::SigNum
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        (status >> 8) as i8
    }

    pub fn continued(status: i32) -> bool {
        status == 0x13
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

fn decode(pid : pid_t, status: i32) -> WaitStatus {
    if status::exited(status) {
        WaitStatus::Exited(pid, status::exit_status(status))
    } else if status::signaled(status) {
        WaitStatus::Signaled(pid, status::term_signal(status), status::dumped_core(status))
    } else if status::stopped(status) {
        WaitStatus::Stopped(pid, status::stop_signal(status))
    } else {
        assert!(status::continued(status));
        WaitStatus::Continued(pid)
    }
}

pub fn waitpid(pid: pid_t, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
    use self::WaitStatus::*;

    let mut status: i32 = 0;

    let option_bits = match options {
        Some(bits) => bits.bits(),
        None => 0
    };

    let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) };

    Ok(match try!(Errno::result(res)) {
        0 => StillAlive,
        res => decode(res, status),
    })
}

pub fn wait() -> Result<WaitStatus> {
    waitpid(-1, None)
}
<commit_msg>Replace wait constants with libc constants<commit_after>use libc::{self, pid_t, c_int};
use {Errno, Result};

use sys::signal;

mod ffi {
    use libc::{pid_t, c_int};

    extern {
        pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "android")))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
        const WEXITED     = libc::WEXITED,
        const WCONTINUED  = libc::WCONTINUED,
        const WNOWAIT     = libc::WNOWAIT, // Don't reap, just poll status.
        const __WNOTHREAD = libc::__WNOTHREAD, // Don't wait on children of other threads in this group
        const __WALL      = libc::__WALL, // Wait on all children, regardless of type
        const __WCLONE    = libc::__WCLONE,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
const WSTOPPED: WaitPidFlag = WUNTRACED;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
    Exited(pid_t, i8),
    Signaled(pid_t, signal::SigNum, bool),
    Stopped(pid_t, signal::SigNum),
    Continued(pid_t),
    StillAlive
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
mod status {
    use sys::signal;

    pub fn exited(status: i32) -> bool {
        (status & 0x7F) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status & 0xFF00) >> 8) as i8
    }

    pub fn signaled(status: i32) -> bool {
        ((((status & 0x7f) + 1) as i8) >> 1) > 0
    }

    pub fn term_signal(status: i32) -> signal::SigNum {
        (status & 0x7f) as signal::SigNum
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & 0x80) != 0
    }

    pub fn stopped(status: i32) -> bool {
        (status & 0xff) == 0x7f
    }

    pub fn stop_signal(status: i32) -> signal::SigNum {
        ((status & 0xFF00) >> 8) as signal::SigNum
    }

    pub fn continued(status: i32) -> bool {
        status == 0xFFFF
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod status {
    use sys::signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status >> 8) & 0xFF) as i8
    }

    pub fn stop_signal(status: i32) -> signal::SigNum {
        (status >> 8) as signal::SigNum
    }

    pub fn continued(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) == 0x13
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) != 0x13
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0
    }

    pub fn term_signal(status: i32) -> signal::SigNum {
        wstatus(status) as signal::SigNum
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
mod status {
    use sys::signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED
    }

    pub fn stop_signal(status: i32) -> signal::SigNum {
        (status >> 8) as signal::SigNum
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
    }

    pub fn term_signal(status: i32) -> signal::SigNum {
        wstatus(status) as signal::SigNum
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        (status >> 8) as i8
    }

    pub fn continued(status: i32) -> bool {
        status == 0x13
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

fn decode(pid : pid_t, status: i32) -> WaitStatus {
    if status::exited(status) {
        WaitStatus::Exited(pid, status::exit_status(status))
    } else if status::signaled(status) {
        WaitStatus::Signaled(pid, status::term_signal(status), status::dumped_core(status))
    } else if status::stopped(status) {
        WaitStatus::Stopped(pid, status::stop_signal(status))
    } else {
        assert!(status::continued(status));
        WaitStatus::Continued(pid)
    }
}

pub fn waitpid(pid: pid_t, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
    use self::WaitStatus::*;

    let mut status: i32 = 0;

    let option_bits = match options {
        Some(bits) => bits.bits(),
        None => 0
    };

    let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) };

    Ok(match try!(Errno::result(res)) {
        0 => StillAlive,
        res => decode(res, status),
    })
}

pub fn wait() -> Result<WaitStatus> {
    waitpid(-1, None)
}
<|endoftext|>


<commit_before>//! The `render` module takes a tree of layout boxes and paints the screen.

// TODO move this file into it's own module
// TODO seperate drawing logic from command building logic

use gfx;
use gfx_window_glutin;
use glutin;

use gfx::traits::FactoryExt;
use gfx::Device;

pub type DepthFormat = gfx::format::DepthStencil;
pub type ColorFormat = gfx::format::Rgba8;

// TODO integrate with layout module for screen resizing
const SCREEN_WIDTH: usize = 1024;
const SCREEN_HEIGHT: usize = 768;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 2] = "a_Pos",
        color: [f32; 3] = "a_Color",
    }

    pipeline pipe {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        out: gfx::RenderTarget<ColorFormat> = "Target0",
    }
}

const CLEAR_COLOR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

pub fn render_loop() {
    let builder = glutin::WindowBuilder::new()
        .with_title(String::from("feOxy"))
        .with_dimensions(SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32)
        .with_vsync();

    let (window, mut device, mut factory, main_color, _main_depth) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);

    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

    let pso = factory.create_pipeline_simple(
        include_bytes!("shaders/triangle.glslv"),
        include_bytes!("shaders/triangle.glslf"),
        pipe::new()
    ).unwrap();

    let (vertices, index_data) = render_commands(vec![
        DisplayCommand::SolidRect(String::from("red"), Rect {x: 100.0, y: 100.0, height: 100.0, width: 100.0 }),
        DisplayCommand::SolidRect(String::from("green"), Rect {x: 0.0, y: 100.0, height: 100.0, width: 100.0 }),
        DisplayCommand::SolidRect(String::from("blue"), Rect {x: 100.0, y: 0.0, height: 100.0, width: 100.0 })
    ]);

    let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&vertices, &index_data[..]);

    let data = pipe::Data {
        vbuf: vertex_buffer,
        out: main_color,
    };

    'main: loop {
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        encoder.clear(&data.out, CLEAR_COLOR);
        encoder.draw(&slice, &pso, &data);
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

fn render_commands(command_list: DisplayList) -> (Vec<Vertex>, Vec<u16>) {
    let mut vertices = Vec::new();
    let mut index_data = Vec::new();

    for command in command_list {
        match command {
            DisplayCommand::SolidRect(color, rect) => {
                let c;
                if color == "red" {
                    c = [0.5, 0.0, 0.0];
                } else if color == "green" {
                    c = [0.0, 0.5, 0.0];
                } else {
                    c = [0.0, 0.0, 0.5];
                };
                let (mut v, mut i) = render_rect(&c, rect);
                vertices.append(&mut v);
                index_data.append(&mut i);
            },
        }
    }
    return (vertices, index_data);
}

fn render_rect(c: &[f32; 3], rect: Rect) -> (Vec<Vertex>, Vec<u16>) {
    println!("{:?}", rect);
    let (x, y, h, w) = transform_rect(rect);
    let vertices = vec![
        Vertex { pos: [x + w, y], color: *c },
        Vertex { pos: [x, y], color: *c },
        Vertex { pos: [x, y + h], color: *c },
        Vertex { pos: [x + w, y + h], color: *c },
    ];
    let index_data = vec![
        0, 1, 2, 2, 3, 0,
        4, 5, 6, 6, 7, 4,
        8, 9, 10, 10, 11, 8,
    ];

    return (vertices, index_data);
}

/// Transforms a rect into gfx coordinates based on screen size.
///
/// layout_box coord system:    gfx obj coord system:  gfx screen coord system:
///  (x, y)    (x+w, y)           (x, y+h) (x+w, y+h)     (-1, 1)    (1,1)
///     +-------+                     +-------+             +-------+
///     |       |                     |       |             |       |
///     |       |                     |       |             |       |
///     +-------+                     +-------+             +-------+
///  (x, y+h) (x+w, y+h)           (x, y)  (x+w, y)     (-1, -1)  (1, -1)
fn transform_rect(rect: Rect) -> (f32, f32, f32, f32) {
    let w = rect.width / SCREEN_WIDTH as f32 * 2.0;
    let h = rect.height / SCREEN_HEIGHT as f32 * 2.0;
    let x = rect.x / SCREEN_WIDTH as f32 * 2.0 - 1.0;
    let y = -(rect.y / SCREEN_HEIGHT as f32 * 2.0 - 1.0 + h);

    println!("x: {}, y: {}, w: {}, h: {}", x, y, w, h);

    (x, y, h, w)
}

use layout::{LayoutBox, Rect};

pub type DisplayList = Vec<DisplayCommand>;

pub enum DisplayCommand {
    SolidRect(String, Rect),
}

pub fn build_display_commands(root: &LayoutBox) -> DisplayList {
    let mut commands = Vec::new();
    render_layout_box(&mut commands, root);
    commands
}

fn render_layout_box(commands: &mut DisplayList, layout_box: &LayoutBox) {
    render_background(commands, layout_box);
    render_borders(commands, layout_box);
    //TODO: Render text

    for child in &layout_box.children {
        render_layout_box(commands, child);
    }
}

fn render_background(commands: &mut DisplayList, layout_box: &LayoutBox) {
    get_color(layout_box, "background").map(|color|
        commands.push(DisplayCommand::SolidRect(color, layout_box.dimensions.border_box())));
}

fn get_color(layout_box: &LayoutBox, name: &str) -> Option<String> {
    return None;
}

fn render_borders(commands: &mut DisplayList, layout_box: &LayoutBox) {
    let color = match get_color(layout_box, "border-color") {
        Some(color) => color,
        _ => return,
    };

    let d = &layout_box.dimensions;
    let border_box = d.border_box();

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x,
        y: border_box.y,
        width: d.border.left,
        height: border_box.height,
    }));

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x + border_box.width - d.border.right,
        y: border_box.y,
        width: d.border.right,
        height: border_box.height,
    }));

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x,
        y: border_box.y,
        width: border_box.width,
        height: d.border.top,
    }));

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x,
        y: border_box.y + border_box.height - d.border.bottom,
        width: border_box.width,
        height: d.border.bottom,
    }));
}
<commit_msg>fixed index generation<commit_after>//! The `render` module takes a tree of layout boxes and paints the screen.

// TODO move this file into it's own module
// TODO seperate drawing logic from command building logic

use gfx;
use gfx_window_glutin;
use glutin;

use gfx::traits::FactoryExt;
use gfx::Device;

pub type DepthFormat = gfx::format::DepthStencil;
pub type ColorFormat = gfx::format::Rgba8;

// TODO integrate with layout module for screen resizing
const SCREEN_WIDTH: usize = 1024;
const SCREEN_HEIGHT: usize = 768;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 2] = "a_Pos",
        color: [f32; 3] = "a_Color",
    }

    pipeline pipe {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        out: gfx::RenderTarget<ColorFormat> = "Target0",
    }
}

const CLEAR_COLOR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

pub fn render_loop() {
    let builder = glutin::WindowBuilder::new()
        .with_title(String::from("feOxy"))
        .with_dimensions(SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32)
        .with_vsync();

    let (window, mut device, mut factory, main_color, _main_depth) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);

    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();

    let pso = factory.create_pipeline_simple(
        include_bytes!("shaders/triangle.glslv"),
        include_bytes!("shaders/triangle.glslf"),
        pipe::new()
    ).unwrap();

    let (vertices, index_data) = render_commands(vec![
        DisplayCommand::SolidRect(String::from("red"), Rect {x: 100.0, y: 100.0, height: 100.0, width: 100.0 }),
        DisplayCommand::SolidRect(String::from("green"), Rect {x: 0.0, y: 100.0, height: 100.0, width: 100.0 }),
        DisplayCommand::SolidRect(String::from("blue"), Rect {x: 100.0, y: 0.0, height: 100.0, width: 100.0 }),
        DisplayCommand::SolidRect(String::from("yellow"), Rect {x: 0.0, y: 0.0, height: 100.0, width: 100.0 }),
    ]);

    let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&vertices, &index_data[..]);

    let data = pipe::Data {
        vbuf: vertex_buffer,
        out: main_color,
    };

    'main: loop {
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        encoder.clear(&data.out, CLEAR_COLOR);
        encoder.draw(&slice, &pso, &data);
        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

fn render_commands(command_list: DisplayList) -> (Vec<Vertex>, Vec<u16>) {
    let mut vertices = Vec::new();
    let mut index_data = Vec::new();
    let mut rect_num: u16 = 0;

    for command in command_list {
        match command {
            DisplayCommand::SolidRect(color, rect) => {
                let c;
                if color == "red" {
                    c = [1.0, 0.0, 0.0];
                } else if color == "green" {
                    c = [0.0, 1.0, 0.0];
                } else if color == "blue" {
                    c = [0.0, 0.0, 1.0];
                } else {
                    c = [1.0, 1.0, 0.0];
                };
                let mut v = render_rect(&c, rect);
                vertices.append(&mut v);

                let index_base: u16 = rect_num * 4;
                index_data.append(&mut vec![index_base, index_base + 1, index_base + 2, index_base + 2, index_base + 3, index_base]);
                rect_num += 1;
            },
        }
    }
    return (vertices, index_data);
}

fn render_rect(c: &[f32; 3], rect: Rect) -> Vec<Vertex> {
    println!("{:?}", rect);
    let (x, y, h, w) = transform_rect(rect);
    let vertices = vec![
        Vertex { pos: [x + w, y], color: *c },
        Vertex { pos: [x, y], color: *c },
        Vertex { pos: [x, y + h], color: *c },
        Vertex { pos: [x + w, y + h], color: *c },
    ];

    return vertices;
}

/// Transforms a rect into gfx coordinates based on screen size.
///
/// layout_box coord system:    gfx obj coord system:  gfx screen coord system:
///  (x, y)    (x+w, y)           (x, y+h) (x+w, y+h)     (-1, 1)    (1,1)
///     +-------+                     +-------+             +-------+
///     |       |                     |       |             |       |
///     |       |                     |       |             |       |
///     +-------+                     +-------+             +-------+
///  (x, y+h) (x+w, y+h)           (x, y)  (x+w, y)     (-1, -1)  (1, -1)
fn transform_rect(rect: Rect) -> (f32, f32, f32, f32) {
    let w = rect.width / SCREEN_WIDTH as f32 * 2.0;
    let h = rect.height / SCREEN_HEIGHT as f32 * 2.0;
    let x = rect.x / SCREEN_WIDTH as f32 * 2.0 - 1.0;
    let y = -(rect.y / SCREEN_HEIGHT as f32 * 2.0 - 1.0 + h);

    println!("x: {}, y: {}, w: {}, h: {}", x, y, w, h);

    (x, y, h, w)
}

use layout::{LayoutBox, Rect};

pub type DisplayList = Vec<DisplayCommand>;

pub enum DisplayCommand {
    SolidRect(String, Rect),
}

pub fn build_display_commands(root: &LayoutBox) -> DisplayList {
    let mut commands = Vec::new();
    render_layout_box(&mut commands, root);
    commands
}

fn render_layout_box(commands: &mut DisplayList, layout_box: &LayoutBox) {
    render_background(commands, layout_box);
    render_borders(commands, layout_box);
    //TODO: Render text

    for child in &layout_box.children {
        render_layout_box(commands, child);
    }
}

fn render_background(commands: &mut DisplayList, layout_box: &LayoutBox) {
    get_color(layout_box, "background").map(|color|
        commands.push(DisplayCommand::SolidRect(color, layout_box.dimensions.border_box())));
}

fn get_color(layout_box: &LayoutBox, name: &str) -> Option<String> {
    return None;
}

fn render_borders(commands: &mut DisplayList, layout_box: &LayoutBox) {
    let color = match get_color(layout_box, "border-color") {
        Some(color) => color,
        _ => return,
    };

    let d = &layout_box.dimensions;
    let border_box = d.border_box();

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x,
        y: border_box.y,
        width: d.border.left,
        height: border_box.height,
    }));

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x + border_box.width - d.border.right,
        y: border_box.y,
        width: d.border.right,
        height: border_box.height,
    }));

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x,
        y: border_box.y,
        width: border_box.width,
        height: d.border.top,
    }));

    commands.push(DisplayCommand::SolidRect(color.clone(), Rect {
        x: border_box.x,
        y: border_box.y + border_box.height - d.border.bottom,
        width: border_box.width,
        height: d.border.bottom,
    }));
}
<|endoftext|>


<commit_before>use std::fmt;

static ROMAN_MAP: [(usize, &'static str); 13] = [
    (1, "I"),
    (4, "IV"),
    (5, "V"),
    (9, "IX"),
    (10, "X"),
    (40, "XL"),
    (50, "L"),
    (90, "XC"),
    (100, "C"),
    (400, "CD"),
    (500, "D"),
    (900, "CM"),
    (1000, "M"),
];

pub struct Roman {
    num: usize,
}

impl From<usize> for Roman {
    fn from(i: usize) -> Self {
        Roman::new(i)
    }
}

impl fmt::Display for Roman {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut start = self.num.clone();
        let mut result = String::new();
        for &(numeric, roman_string) in ROMAN_MAP.into_iter().rev() {
            while start >= numeric {
                result.push_str(roman_string);
                start -= numeric;
            }
        }
        write!(f, "{}", result)
    }
}

impl Roman {
    fn new(num: usize) -> Roman {
        Roman { num }
    }
}
<commit_msg>roman-numerals: Use `iter` instead of `into_iter` when not moving<commit_after>use std::fmt;

static ROMAN_MAP: [(usize, &'static str); 13] = [
    (1, "I"),
    (4, "IV"),
    (5, "V"),
    (9, "IX"),
    (10, "X"),
    (40, "XL"),
    (50, "L"),
    (90, "XC"),
    (100, "C"),
    (400, "CD"),
    (500, "D"),
    (900, "CM"),
    (1000, "M"),
];

pub struct Roman {
    num: usize,
}

impl From<usize> for Roman {
    fn from(i: usize) -> Self {
        Roman::new(i)
    }
}

impl fmt::Display for Roman {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut start = self.num.clone();
        let mut result = String::new();
        for &(numeric, roman_string) in ROMAN_MAP.iter().rev() {
            while start >= numeric {
                result.push_str(roman_string);
                start -= numeric;
            }
        }
        write!(f, "{}", result)
    }
}

impl Roman {
    fn new(num: usize) -> Roman {
        Roman { num }
    }
}
<|endoftext|>