<commit_before>
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge{count: count, states: states}
    }
}

impl Iterator for Merge  {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> Option<u32> {
        if let Ok(i) = v.parse::<u32>() {
            Some(i)
        } else {
            None
        }
    };
    let values = matches.map(move |s| {
        let numbers = s.split(',').filter_map(|v| to_int(&v));
        numbers.collect::<Vec<_>>()
    }).flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line|
            line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches = lines.filter_map(move |line| {
        r.captures(&line).map(|captures|
            captures[1].to_string()
        )
    });
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap() , 3);
    }

    #[test]
    fn test_output() {
        let output = [1,1,2,2,3,4,4,6,7,9,9,20,21];
        assert_eq!(get_output("../data/test.txt").unwrap().collect::<Vec<_>>(), output);
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(get_collection("../data/test.txt", 1).unwrap().collect::<Vec<_>>(), output);
    }

    fn merge(filename: &str) -> (impl Iterator<Item = u32>, impl Iterator<Item = u32>) {
        let result = Merge::new(filename);
        let output = get_output(filename).unwrap();
        (result, output)
    }

    fn assert_iterator(iter1: &mut impl Iterator<Item = u32>, iter2: &mut impl Iterator<Item = u32>) -> bool {
        loop {
            match (iter1.next(), iter2.next()) {
                (None, None) => return true,
                (Some(v1), Some(v2)) if v1 == v2 => continue,
                _ => return false
            }
        }
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (mut result, mut output) = merge(filename);
        assert!(assert_iterator(&mut result, &mut output));
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (mut result, mut output) = merge(filename);
        assert!(result.next().is_none());
        assert!(output.next().is_none());
    }

    #[test]
    fn test_err() {
        let filename = "../data/err.txt";
        let (mut result, mut output) = merge(filename);
        assert!(!assert_iterator(&mut result, &mut output));
    }
}
<commit_msg>rustfmt<commit_after>use regex::Regex;
use std::fs::File;
use std::io::{self, BufRead};

#[macro_use]
extern crate lazy_static;

struct State<T>(Box<dyn Iterator<Item = T>>, Option<T>);
pub struct Merge {
    count: usize,
    states: Vec<State<u32>>,
}

impl Merge {
    pub fn new(filename: &str) -> Self {
        let count = get_number(filename).unwrap();
        let mut states: Vec<State<u32>> = Vec::with_capacity(count);
        for i in 0..count {
            let collection = Box::new(get_collection(filename, i).unwrap());
            let state = State(collection, None);
            states.push(state);
        }
        Merge {
            count: count,
            states: states,
        }
    }
}

impl Iterator for Merge {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        let count = self.count;
        let states = &mut self.states;
        loop {
            for i in 0..count {
                let mut state = &mut states[i];
                if state.1.is_none() {
                    state.1 = state.0.next();
                }
            }
            let not_done = states.iter().any(|s| s.1.is_some());
            if !not_done {
                return None;
            }

            let mut min = u32::MAX;
            let mut min_index = usize::MIN;
            for i in 0..count {
                let state = &mut states[i];
                if let Some(val) = state.1 {
                    if val < min {
                        min = val;
                        min_index = i;
                    }
                }
            }
            states[min_index].1 = None;
            return Some(min);
        }
    }
}

pub fn get_number(filename: &str) -> io::Result<usize> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"NUMBER=(\d+)").unwrap();
    }
    let mut matches = match_lines(filename, &*RE)?;
    return Ok(matches.next().unwrap().parse().unwrap());
}

pub fn get_output(filename: &str) -> io::Result<impl Iterator<Item = u32>> {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"OUTPUT:(.*)").unwrap();
    }
    get_numbers(filename, &*RE)
}

pub fn get_collection(filename: &str, idx: usize) -> io::Result<impl Iterator<Item = u32>> {
    let regex: Regex = {
        let r = format!("COLLECTION{}:(.*)", idx);
        Regex::new(&r).unwrap()
    };
    get_numbers(filename, &regex)
}

fn get_numbers(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = u32>> {
    let matches = match_lines(filename, regex)?;
    let to_int = |v: &str| -> Option<u32> {
        if let Ok(i) = v.parse::<u32>() {
            Some(i)
        } else {
            None
        }
    };
    let values = matches
        .map(move |s| {
            let numbers = s.split(',').filter_map(|v| to_int(&v));
            numbers.collect::<Vec<_>>()
        })
        .flatten();
    Ok(values)
}

fn match_lines(filename: &str, regex: &Regex) -> io::Result<impl Iterator<Item = String>> {
    let read_lines = move || -> io::Result<_> {
        let file = File::open(filename)?;
        Ok(io::BufReader::new(file).lines().map(|line| line.unwrap()))
    };
    let lines = read_lines()?;
    let r = regex.clone(); // TODO
    let matches =
        lines.filter_map(move |line| r.captures(&line).map(|captures| captures[1].to_string()));
    Ok(matches)
}

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

    #[test]
    fn test_number() {
        assert_eq!(get_number("../data/test.txt").unwrap(), 3);
    }

    #[test]
    fn test_output() {
        let output = [1, 1, 2, 2, 3, 4, 4, 6, 7, 9, 9, 20, 21];
        assert_eq!(
            get_output("../data/test.txt").unwrap().collect::<Vec<_>>(),
            output
        );
    }

    #[test]
    fn test_collection() {
        let output = [2, 4, 6, 9, 20];
        assert_eq!(
            get_collection("../data/test.txt", 1)
                .unwrap()
                .collect::<Vec<_>>(),
            output
        );
    }

    fn merge(filename: &str) -> (impl Iterator<Item = u32>, impl Iterator<Item = u32>) {
        let result = Merge::new(filename);
        let output = get_output(filename).unwrap();
        (result, output)
    }

    fn assert_iterator(
        iter1: &mut impl Iterator<Item = u32>,
        iter2: &mut impl Iterator<Item = u32>,
    ) -> bool {
        loop {
            match (iter1.next(), iter2.next()) {
                (None, None) => return true,
                (Some(v1), Some(v2)) if v1 == v2 => continue,
                _ => return false,
            }
        }
    }

    #[test]
    fn test_merge() {
        let filename = "../data/test.txt";
        let (mut result, mut output) = merge(filename);
        assert!(assert_iterator(&mut result, &mut output));
    }

    #[test]
    #[should_panic]
    fn test_bad_merge() {
        let filename = "../data/bad.txt";
        let (_result, _output) = merge(filename);
    }

    #[test]
    fn test_zero_merge() {
        let filename = "../data/zero.txt";
        let (mut result, mut output) = merge(filename);
        assert!(result.next().is_none());
        assert!(output.next().is_none());
    }

    #[test]
    fn test_err() {
        let filename = "../data/err.txt";
        let (mut result, mut output) = merge(filename);
        assert!(!assert_iterator(&mut result, &mut output));
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use cgmath::vector::{Vec3, Vector, EuclideanVector};
use visualizer::geom::Geom;
use core::types::{MBool, MInt, MapPos, UnitId};
use core::game_state::GameState;
use visualizer::types::{Scene, SceneNode, MFloat, WorldPos, NodeId};

fn unit_id_to_node_id(unit_id: UnitId) -> NodeId {
    let UnitId(id) = unit_id;
    NodeId(id)
}

pub trait EventVisualizer {
    fn is_finished(&self) -> MBool;
    fn draw(&mut self, geom: &Geom, scene: &mut Scene, state: &GameState, dtime: MInt);
    fn end(&mut self, geom: &Geom, scene: &mut Scene, state: &GameState);
}

// TODO: Replace with slot system
fn unit_pos(
    unit_id: UnitId,
    map_pos: MapPos,
    geom: &Geom,
    state: &GameState,
) -> WorldPos {
    let slot_id = state.get_slot_index(unit_id, map_pos);
    let center_pos = geom.map_pos_to_world_pos(map_pos);
    let slot_pos = geom.slot_pos(slot_id);
    center_pos.add_v(&slot_pos)
}

pub struct EventMoveVisualizer {
    priv unit_id: UnitId,
    priv path: ~[WorldPos],
    priv move: MoveHelper,
    priv speed: MFloat,
}

impl EventVisualizer for EventMoveVisualizer {
    fn is_finished(&self) -> MBool {
        self.path.len() == 1
    }

    fn draw(&mut self, geom: &Geom, scene: &mut Scene, _: &GameState, dtime: MInt) {
        let node_id = unit_id_to_node_id(self.unit_id);
        let node = scene.get_mut(&node_id);
        node.pos = self.move.step(dtime);
        if self.move.is_finished() {
            self.path.shift();
            if self.path.len() > 1 {
                self.update_waypoint(geom, node);
            }
            node.pos = self.current_waypoint();
        }
    }

    fn end(&mut self, _: &Geom, scene: &mut Scene, _: &GameState) {
        assert!(self.path.len() == 1);
        let node_id = unit_id_to_node_id(self.unit_id);
        let node = scene.get_mut(&node_id);
        node.pos = self.current_waypoint();
    }
}

impl EventMoveVisualizer {
    pub fn new(
        geom: &Geom,
        scene: &mut Scene,
        state: &GameState,
        unit_id: UnitId,
        path: ~[MapPos]
    ) -> ~EventVisualizer {
        let mut world_path = ~[];
        for map_pos in path.iter() {
            let world_pos = unit_pos(unit_id, *map_pos, geom, state);
            world_path.push(world_pos);
        }
        let speed = 3.8; // TODO: Get from UnitType
        let node_id = unit_id_to_node_id(unit_id);
        let node = scene.get_mut(&node_id);
        node.rot = geom.get_rot_angle(world_path[0], world_path[1]);
        let move = MoveHelper::new(geom, world_path[0], world_path[1], speed);
        let mut vis = ~EventMoveVisualizer {
            unit_id: unit_id,
            path: world_path,
            move: move,
            speed: speed,
        };
        vis.update_waypoint(geom, node);
        vis as ~EventVisualizer
    }

    fn update_waypoint(&mut self, geom: &Geom, node: &mut SceneNode) {
        self.move = MoveHelper::new(
            geom,
            self.current_waypoint(),
            self.next_waypoint(),
            self.speed,
        );
        node.rot = geom.get_rot_angle(
            self.current_waypoint(),
            self.next_waypoint()
        );
    }

    fn current_waypoint(&self) -> WorldPos {
        assert!(self.path.len() >= 1);
        self.path[0]
    }

    fn next_waypoint(&self) -> WorldPos {
        assert!(self.path.len() >= 2);
        self.path[1]
    }
}

pub struct EventEndTurnVisualizer;

impl EventEndTurnVisualizer {
    pub fn new() -> ~EventVisualizer {
        ~EventEndTurnVisualizer as ~EventVisualizer
    }
}

impl EventVisualizer for EventEndTurnVisualizer {
    fn is_finished(&self) -> MBool {
        true
    }

    fn draw(&mut self, _: &Geom, _: &mut Scene, _: &GameState, _: MInt) {}

    fn end(&mut self, _: &Geom, _: &mut Scene, _: &GameState) {}
}

pub struct EventCreateUnitVisualizer {
    priv id: UnitId,
    priv move: MoveHelper,
}

impl EventCreateUnitVisualizer {
    pub fn new(
        geom: &Geom,
        scene: &mut Scene,
        state: &GameState,
        id: UnitId,
        pos: MapPos,
        mesh_id: MInt
    ) -> ~EventVisualizer {
        let node_id = unit_id_to_node_id(id);
        let world_pos = unit_pos(id, pos, geom, state);
        let to = world_pos;
        let from = to.sub_v(&vec3_z(geom.hex_ex_radius / 2.0));
        scene.insert(node_id, SceneNode{pos: from, rot: 0.0, mesh_id: mesh_id});
        let move = MoveHelper::new(geom, from, to, 1.0);
        ~EventCreateUnitVisualizer {
            id: id,
            move: move,
        } as ~EventVisualizer
    }
}

impl EventVisualizer for EventCreateUnitVisualizer {
    fn is_finished(&self) -> MBool {
        self.move.is_finished()
    }

    fn draw(&mut self, _: &Geom, scene: &mut Scene, _: &GameState, dtime: MInt) {
        let node_id = unit_id_to_node_id(self.id);
        let node = scene.get_mut(&node_id);
        node.pos = self.move.step(dtime);
    }

    fn end(&mut self, _: &Geom, _: &mut Scene, _: &GameState) {}
}

pub struct MoveHelper {
    priv from: WorldPos,
    priv to: WorldPos,
    priv current: WorldPos,
    priv dist: MFloat,
    priv current_dist: MFloat,
    priv dir: Vec3<MFloat>,
}

impl MoveHelper {
    pub fn new(
        geom: &Geom,
        from: WorldPos,
        to: WorldPos,
        speed: MFloat
    ) -> MoveHelper {
        let dir = to.sub_v(&from).normalize();
        let dist = geom.dist(from, to);
        MoveHelper {
            from: from,
            to: to,
            current: from,
            dist: dist,
            current_dist: 0.0,
            dir: dir.mul_s(speed),
        }
    }

    pub fn is_finished(&self) -> MBool {
        self.current_dist >= self.dist
    }

    pub fn step(&mut self, dtime: MInt) -> WorldPos {
        let dt = dtime as MFloat / 1000000000.0;
        let step = self.dir.mul_s(dt);
        self.current_dist += step.length();
        self.current.add_self_v(&step);
        self.current
    }
}

fn vec3_z(z: MFloat) -> Vec3<MFloat> {
    Vec3{x: 0.0, y: 0.0, z: z}
}

pub struct EventAttackUnitVisualizer {
    priv attacker_id: UnitId,
    priv defender_id: UnitId,
    priv move: MoveHelper,
    priv shell_move: MoveHelper,
    priv shell_node_id: NodeId,
}

impl EventAttackUnitVisualizer {
    pub fn new(
        geom: &Geom,
        scene: &mut Scene,
        _: &GameState,
        attacker_id: UnitId,
        defender_id: UnitId,
        shell_mesh_id: MInt
    ) -> ~EventVisualizer {
        let node_id = unit_id_to_node_id(defender_id);
        let from = scene.get(&node_id).pos;
        let to = from.sub_v(&vec3_z(geom.hex_ex_radius / 2.0));
        let move = MoveHelper::new(geom, from, to, 1.0);
        let shell_node_id = NodeId(666); // TODO
        let shell_move = {
            let from = scene.get(&unit_id_to_node_id(attacker_id)).pos;
            let to = scene.get(&unit_id_to_node_id(defender_id)).pos;
            scene.insert(shell_node_id, SceneNode {
                pos: from,
                rot: 0.0,
                mesh_id: shell_mesh_id,
            });
            MoveHelper::new(geom, from, to, 10.0)
        };
        ~EventAttackUnitVisualizer {
            attacker_id: attacker_id,
            defender_id: defender_id,
            move: move,
            shell_move: shell_move,
            shell_node_id: shell_node_id,
        } as ~EventVisualizer
    }
}

impl EventVisualizer for EventAttackUnitVisualizer {
    fn is_finished(&self) -> MBool {
        self.move.is_finished() && self.shell_move.is_finished()
    }

    fn draw(&mut self, _: &Geom, scene: &mut Scene, _: &GameState, dtime: MInt) {
        scene.get_mut(&self.shell_node_id).pos = self.shell_move.step(dtime);
        if self.shell_move.is_finished() {
            let node_id = unit_id_to_node_id(self.defender_id);
            scene.get_mut(&node_id).pos = self.move.step(dtime);
        }
    }

    fn end(&mut self, _: &Geom, scene: &mut Scene, _: &GameState) {
        let node_id = unit_id_to_node_id(self.defender_id);
        scene.remove(&node_id);
        scene.remove(&self.shell_node_id);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>EventVisualizer: Random initial unit rotation<commit_after>// See LICENSE file for copyright and license details.

use std::rand;
use std::rand::Rng;
use cgmath::vector::{Vec3, Vector, EuclideanVector};
use visualizer::geom::Geom;
use core::types::{MBool, MInt, MapPos, UnitId};
use core::game_state::GameState;
use visualizer::types::{Scene, SceneNode, MFloat, WorldPos, NodeId};

fn unit_id_to_node_id(unit_id: UnitId) -> NodeId {
    let UnitId(id) = unit_id;
    NodeId(id)
}

pub trait EventVisualizer {
    fn is_finished(&self) -> MBool;
    fn draw(&mut self, geom: &Geom, scene: &mut Scene, state: &GameState, dtime: MInt);
    fn end(&mut self, geom: &Geom, scene: &mut Scene, state: &GameState);
}

// TODO: Replace with slot system
fn unit_pos(
    unit_id: UnitId,
    map_pos: MapPos,
    geom: &Geom,
    state: &GameState,
) -> WorldPos {
    let slot_id = state.get_slot_index(unit_id, map_pos);
    let center_pos = geom.map_pos_to_world_pos(map_pos);
    let slot_pos = geom.slot_pos(slot_id);
    center_pos.add_v(&slot_pos)
}

pub struct EventMoveVisualizer {
    priv unit_id: UnitId,
    priv path: ~[WorldPos],
    priv move: MoveHelper,
    priv speed: MFloat,
}

impl EventVisualizer for EventMoveVisualizer {
    fn is_finished(&self) -> MBool {
        self.path.len() == 1
    }

    fn draw(&mut self, geom: &Geom, scene: &mut Scene, _: &GameState, dtime: MInt) {
        let node_id = unit_id_to_node_id(self.unit_id);
        let node = scene.get_mut(&node_id);
        node.pos = self.move.step(dtime);
        if self.move.is_finished() {
            self.path.shift();
            if self.path.len() > 1 {
                self.update_waypoint(geom, node);
            }
            node.pos = self.current_waypoint();
        }
    }

    fn end(&mut self, _: &Geom, scene: &mut Scene, _: &GameState) {
        assert!(self.path.len() == 1);
        let node_id = unit_id_to_node_id(self.unit_id);
        let node = scene.get_mut(&node_id);
        node.pos = self.current_waypoint();
    }
}

impl EventMoveVisualizer {
    pub fn new(
        geom: &Geom,
        scene: &mut Scene,
        state: &GameState,
        unit_id: UnitId,
        path: ~[MapPos]
    ) -> ~EventVisualizer {
        let mut world_path = ~[];
        for map_pos in path.iter() {
            let world_pos = unit_pos(unit_id, *map_pos, geom, state);
            world_path.push(world_pos);
        }
        let speed = 3.8; // TODO: Get from UnitType
        let node_id = unit_id_to_node_id(unit_id);
        let node = scene.get_mut(&node_id);
        node.rot = geom.get_rot_angle(world_path[0], world_path[1]);
        let move = MoveHelper::new(geom, world_path[0], world_path[1], speed);
        let mut vis = ~EventMoveVisualizer {
            unit_id: unit_id,
            path: world_path,
            move: move,
            speed: speed,
        };
        vis.update_waypoint(geom, node);
        vis as ~EventVisualizer
    }

    fn update_waypoint(&mut self, geom: &Geom, node: &mut SceneNode) {
        self.move = MoveHelper::new(
            geom,
            self.current_waypoint(),
            self.next_waypoint(),
            self.speed,
        );
        node.rot = geom.get_rot_angle(
            self.current_waypoint(),
            self.next_waypoint()
        );
    }

    fn current_waypoint(&self) -> WorldPos {
        assert!(self.path.len() >= 1);
        self.path[0]
    }

    fn next_waypoint(&self) -> WorldPos {
        assert!(self.path.len() >= 2);
        self.path[1]
    }
}

pub struct EventEndTurnVisualizer;

impl EventEndTurnVisualizer {
    pub fn new() -> ~EventVisualizer {
        ~EventEndTurnVisualizer as ~EventVisualizer
    }
}

impl EventVisualizer for EventEndTurnVisualizer {
    fn is_finished(&self) -> MBool {
        true
    }

    fn draw(&mut self, _: &Geom, _: &mut Scene, _: &GameState, _: MInt) {}

    fn end(&mut self, _: &Geom, _: &mut Scene, _: &GameState) {}
}

pub struct EventCreateUnitVisualizer {
    priv id: UnitId,
    priv move: MoveHelper,
}

impl EventCreateUnitVisualizer {
    pub fn new(
        geom: &Geom,
        scene: &mut Scene,
        state: &GameState,
        id: UnitId,
        pos: MapPos,
        mesh_id: MInt
    ) -> ~EventVisualizer {
        let node_id = unit_id_to_node_id(id);
        let world_pos = unit_pos(id, pos, geom, state);
        let to = world_pos;
        let from = to.sub_v(&vec3_z(geom.hex_ex_radius / 2.0));
        let rot = rand::task_rng().gen_range::<MFloat>(0.0, 360.0);
        scene.insert(node_id, SceneNode{pos: from, rot: rot, mesh_id: mesh_id});
        let move = MoveHelper::new(geom, from, to, 1.0);
        ~EventCreateUnitVisualizer {
            id: id,
            move: move,
        } as ~EventVisualizer
    }
}

impl EventVisualizer for EventCreateUnitVisualizer {
    fn is_finished(&self) -> MBool {
        self.move.is_finished()
    }

    fn draw(&mut self, _: &Geom, scene: &mut Scene, _: &GameState, dtime: MInt) {
        let node_id = unit_id_to_node_id(self.id);
        let node = scene.get_mut(&node_id);
        node.pos = self.move.step(dtime);
    }

    fn end(&mut self, _: &Geom, _: &mut Scene, _: &GameState) {}
}

pub struct MoveHelper {
    priv from: WorldPos,
    priv to: WorldPos,
    priv current: WorldPos,
    priv dist: MFloat,
    priv current_dist: MFloat,
    priv dir: Vec3<MFloat>,
}

impl MoveHelper {
    pub fn new(
        geom: &Geom,
        from: WorldPos,
        to: WorldPos,
        speed: MFloat
    ) -> MoveHelper {
        let dir = to.sub_v(&from).normalize();
        let dist = geom.dist(from, to);
        MoveHelper {
            from: from,
            to: to,
            current: from,
            dist: dist,
            current_dist: 0.0,
            dir: dir.mul_s(speed),
        }
    }

    pub fn is_finished(&self) -> MBool {
        self.current_dist >= self.dist
    }

    pub fn step(&mut self, dtime: MInt) -> WorldPos {
        let dt = dtime as MFloat / 1000000000.0;
        let step = self.dir.mul_s(dt);
        self.current_dist += step.length();
        self.current.add_self_v(&step);
        self.current
    }
}

fn vec3_z(z: MFloat) -> Vec3<MFloat> {
    Vec3{x: 0.0, y: 0.0, z: z}
}

pub struct EventAttackUnitVisualizer {
    priv attacker_id: UnitId,
    priv defender_id: UnitId,
    priv move: MoveHelper,
    priv shell_move: MoveHelper,
    priv shell_node_id: NodeId,
}

impl EventAttackUnitVisualizer {
    pub fn new(
        geom: &Geom,
        scene: &mut Scene,
        _: &GameState,
        attacker_id: UnitId,
        defender_id: UnitId,
        shell_mesh_id: MInt
    ) -> ~EventVisualizer {
        let node_id = unit_id_to_node_id(defender_id);
        let from = scene.get(&node_id).pos;
        let to = from.sub_v(&vec3_z(geom.hex_ex_radius / 2.0));
        let move = MoveHelper::new(geom, from, to, 1.0);
        let shell_node_id = NodeId(666); // TODO
        let shell_move = {
            let from = scene.get(&unit_id_to_node_id(attacker_id)).pos;
            let to = scene.get(&unit_id_to_node_id(defender_id)).pos;
            scene.insert(shell_node_id, SceneNode {
                pos: from,
                rot: 0.0,
                mesh_id: shell_mesh_id,
            });
            MoveHelper::new(geom, from, to, 10.0)
        };
        ~EventAttackUnitVisualizer {
            attacker_id: attacker_id,
            defender_id: defender_id,
            move: move,
            shell_move: shell_move,
            shell_node_id: shell_node_id,
        } as ~EventVisualizer
    }
}

impl EventVisualizer for EventAttackUnitVisualizer {
    fn is_finished(&self) -> MBool {
        self.move.is_finished() && self.shell_move.is_finished()
    }

    fn draw(&mut self, _: &Geom, scene: &mut Scene, _: &GameState, dtime: MInt) {
        scene.get_mut(&self.shell_node_id).pos = self.shell_move.step(dtime);
        if self.shell_move.is_finished() {
            let node_id = unit_id_to_node_id(self.defender_id);
            scene.get_mut(&node_id).pos = self.move.step(dtime);
        }
    }

    fn end(&mut self, _: &Geom, scene: &mut Scene, _: &GameState) {
        let node_id = unit_id_to_node_id(self.defender_id);
        scene.remove(&node_id);
        scene.remove(&self.shell_node_id);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


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

use app_units::Au;
use azure::azure_hl::BackendType;
#[cfg(any(target_os = "linux", target_os = "android"))]
use azure::scaled_font::FontInfo;
use azure::scaled_font::ScaledFont;
use fnv::FnvHasher;
use font::FontHandleMethods;
use font::SpecifiedFontStyle;
use font::{Font, FontGroup};
use font_cache_task::FontCacheTask;
use font_template::FontTemplateDescriptor;
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;
use platform::font_template::FontTemplateData;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::hash_state::DefaultState;
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use string_cache::Atom;
use style::computed_values::{font_style, font_variant};
use util::cache::HashCache;
use util::mem::HeapSizeOf;

#[cfg(any(target_os = "linux", target_os = "android"))]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    ScaledFont::new(BackendType::Skia, FontInfo::FontData(&template.bytes),
                    pt_size.to_f32_px())
}

#[cfg(target_os = "macos")]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    let cgfont = template.ctfont().as_ref().unwrap().copy_to_CGFont();
    ScaledFont::new(BackendType::Skia, &cgfont, pt_size.to_f32_px())
}

static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8;      // Matches FireFox (see gfxFont.h)

#[derive(Debug)]
struct LayoutFontCacheEntry {
    family: String,
    font: Option<Rc<RefCell<Font>>>,
}

#[derive(Debug)]
struct FallbackFontCacheEntry {
    font: Rc<RefCell<Font>>,
}

/// A cached azure font (per paint task) that
/// can be shared by multiple text runs.
#[derive(Debug)]
struct PaintFontCacheEntry {
    pt_size: Au,
    identifier: Atom,
    font: Rc<RefCell<ScaledFont>>,
}

/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
/// this one.
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;

/// The FontContext represents the per-thread/task state necessary for
/// working with fonts. It is the public API used by the layout and
/// paint code. It talks directly to the font cache task where
/// required.
#[derive(Debug)]
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_task: FontCacheTask,

    /// TODO: See bug https://github.com/servo/servo/issues/3300.
    layout_font_cache: Vec<LayoutFontCacheEntry>,
    fallback_font_cache: Vec<FallbackFontCacheEntry>,

    /// Strong reference as the paint FontContext is (for now) recycled
    /// per frame. TODO: Make this weak when incremental redraw is done.
    paint_font_cache: Vec<PaintFontCacheEntry>,

    layout_font_group_address_cache: HashMap<usize, Rc<FontGroup>, DefaultState<FnvHasher>>,

    layout_font_group_cache:
        HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, DefaultState<FnvHasher>>,

    epoch: usize,
}

impl FontContext {
    pub fn new(font_cache_task: FontCacheTask) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_task: font_cache_task,
            layout_font_cache: vec!(),
            fallback_font_cache: vec!(),
            paint_font_cache: vec!(),
            layout_font_group_address_cache: HashMap::with_hash_state(Default::default()),
            layout_font_group_cache: HashMap::with_hash_state(Default::default()),
            epoch: 0,
        }
    }

    /// Create a font for use in layout calculations.
    fn create_layout_font(&self, template: Arc<FontTemplateData>,
                            descriptor: FontTemplateDescriptor, pt_size: Au,
                            variant: font_variant::T) -> Result<Font, ()> {
        // TODO: (Bug #3463): Currently we only support fake small-caps
        // painting. We should also support true small-caps (where the
        // font supports it) in the future.
        let actual_pt_size = match variant {
            font_variant::T::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
            font_variant::T::normal => pt_size,
        };

        let handle: Result<FontHandle, _> =
            FontHandleMethods::new_from_template(&self.platform_handle, template,
                                                 Some(actual_pt_size));

        handle.map(|handle| {
            let metrics = handle.metrics();

            Font {
                handle: handle,
                shaper: None,
                variant: variant,
                descriptor: descriptor,
                requested_pt_size: pt_size,
                actual_pt_size: actual_pt_size,
                metrics: metrics,
                shape_cache: HashCache::new(),
                glyph_advance_cache: HashCache::new(),
            }
        })
    }

    fn expire_font_caches_if_necessary(&mut self) {
        let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
        if current_epoch == self.epoch {
            return
        }

        self.layout_font_cache.clear();
        self.fallback_font_cache.clear();
        self.paint_font_cache.clear();
        self.layout_font_group_address_cache.clear();
        self.layout_font_group_cache.clear();
        self.epoch = current_epoch
    }

    /// Create a group of fonts for use in layout calculations. May return
    /// a cached font if this font instance has already been used by
    /// this context.
    pub fn layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>)
                                       -> Rc<FontGroup> {
        self.expire_font_caches_if_necessary();

        let address = &*style as *const SpecifiedFontStyle as usize;
        if let Some(ref cached_font_group) = self.layout_font_group_address_cache.get(&address) {
            return (*cached_font_group).clone()
        }

        let layout_font_group_cache_key = LayoutFontGroupCacheKey {
            pointer: style.clone(),
            size: style.font_size,
        };
        if let Some(ref cached_font_group) = self.layout_font_group_cache.get(
                &layout_font_group_cache_key) {
            self.layout_font_group_address_cache.insert(address, (*cached_font_group).clone());
            return (*cached_font_group).clone()
        }

        // TODO: The font context holds a strong ref to the cached fonts
        // so they will never be released. Find out a good time to drop them.

        let desc = FontTemplateDescriptor::new(style.font_weight,
                                               style.font_stretch,
                                               style.font_style == font_style::T::italic ||
                                                style.font_style == font_style::T::oblique);

        let mut fonts: SmallVec<[Rc<RefCell<Font>>; 8]> = SmallVec::new();

        for family in &style.font_family.0 {
            // GWTODO: Check on real pages if this is faster as Vec() or HashMap().
            let mut cache_hit = false;
            for cached_font_entry in &self.layout_font_cache {
                if cached_font_entry.family == family.name() {
                    match cached_font_entry.font {
                        None => {
                            cache_hit = true;
                            break;
                        }
                        Some(ref cached_font_ref) => {
                            let cached_font = (*cached_font_ref).borrow();
                            if cached_font.descriptor == desc &&
                               cached_font.requested_pt_size == style.font_size &&
                               cached_font.variant == style.font_variant {
                                fonts.push((*cached_font_ref).clone());
                                cache_hit = true;
                                break;
                            }
                        }
                    }
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.find_font_template(family.clone(),
                                                                            desc.clone());
                match font_template {
                    Some(font_template) => {
                        let layout_font = self.create_layout_font(font_template,
                                                                  desc.clone(),
                                                                  style.font_size,
                                                                  style.font_variant);
                        let font = match layout_font {
                            Ok(layout_font) => {
                                let layout_font = Rc::new(RefCell::new(layout_font));
                                fonts.push(layout_font.clone());

                                Some(layout_font)
                            }
                            Err(_) => None
                        };

                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: font
                        });
                    }
                    None => {
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: None,
                        });
                    }
                }
            }
        }

        // If unable to create any of the specified fonts, create one from the
        // list of last resort fonts for this platform.
        if fonts.is_empty() {
            let mut cache_hit = false;
            for cached_font_entry in &self.fallback_font_cache {
                let cached_font = cached_font_entry.font.borrow();
                if cached_font.descriptor == desc &&
                            cached_font.requested_pt_size == style.font_size &&
                            cached_font.variant == style.font_variant {
                    fonts.push(cached_font_entry.font.clone());
                    cache_hit = true;
                    break;
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.last_resort_font_template(desc.clone());
                let layout_font = self.create_layout_font(font_template,
                                                          desc.clone(),
                                                          style.font_size,
                                                          style.font_variant);
                match layout_font {
                    Ok(layout_font) => {
                        let layout_font = Rc::new(RefCell::new(layout_font));
                        self.fallback_font_cache.push(FallbackFontCacheEntry {
                            font: layout_font.clone(),
                        });
                        fonts.push(layout_font);
                    }
                    Err(_) => debug!("Failed to create fallback layout font!")
                }
            }
        }

        let font_group = Rc::new(FontGroup::new(fonts));
        self.layout_font_group_cache.insert(layout_font_group_cache_key, font_group.clone());
        self.layout_font_group_address_cache.insert(address, font_group.clone());
        font_group
    }

    /// Create a paint font for use with azure. May return a cached
    /// reference if already used by this font context.
    pub fn paint_font_from_template(&mut self,
                                        template: &Arc<FontTemplateData>,
                                        pt_size: Au)
                                        -> Rc<RefCell<ScaledFont>> {
        for cached_font in &self.paint_font_cache {
            if cached_font.pt_size == pt_size &&
               cached_font.identifier == template.identifier {
                return cached_font.font.clone();
            }
        }

        let paint_font = Rc::new(RefCell::new(create_scaled_font(template, pt_size)));
        self.paint_font_cache.push(PaintFontCacheEntry {
            font: paint_font.clone(),
            pt_size: pt_size,
            identifier: template.identifier.clone(),
        });
        paint_font
    }

    /// Returns a reference to the font cache task.
    pub fn font_cache_task(&self) -> FontCacheTask {
        self.font_cache_task.clone()
    }
}

impl HeapSizeOf for FontContext {
    fn heap_size_of_children(&self) -> usize {
        // FIXME(njn): Measure other fields eventually.
        self.platform_handle.heap_size_of_children()
    }
}

#[derive(Debug)]
struct LayoutFontGroupCacheKey {
    pointer: Arc<SpecifiedFontStyle>,
    size: Au,
}

impl PartialEq for LayoutFontGroupCacheKey {
    fn eq(&self, other: &LayoutFontGroupCacheKey) -> bool {
        self.pointer == other.pointer && self.size == other.size
    }
}

impl Eq for LayoutFontGroupCacheKey {}

impl Hash for LayoutFontGroupCacheKey {
    fn hash<H>(&self, hasher: &mut H) where H: Hasher {
        self.pointer.hash.hash(hasher)
    }
}

#[inline]
pub fn invalidate_font_caches() {
    FONT_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
}
<commit_msg>Auto merge of #9173 - pcwalton:remove-font-group-address-cache, r=mbrubeck<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use azure::azure_hl::BackendType;
#[cfg(any(target_os = "linux", target_os = "android"))]
use azure::scaled_font::FontInfo;
use azure::scaled_font::ScaledFont;
use fnv::FnvHasher;
use font::FontHandleMethods;
use font::SpecifiedFontStyle;
use font::{Font, FontGroup};
use font_cache_task::FontCacheTask;
use font_template::FontTemplateDescriptor;
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;
use platform::font_template::FontTemplateData;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::hash_state::DefaultState;
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use string_cache::Atom;
use style::computed_values::{font_style, font_variant};
use util::cache::HashCache;
use util::mem::HeapSizeOf;

#[cfg(any(target_os = "linux", target_os = "android"))]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    ScaledFont::new(BackendType::Skia, FontInfo::FontData(&template.bytes),
                    pt_size.to_f32_px())
}

#[cfg(target_os = "macos")]
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
    let cgfont = template.ctfont().as_ref().unwrap().copy_to_CGFont();
    ScaledFont::new(BackendType::Skia, &cgfont, pt_size.to_f32_px())
}

static SMALL_CAPS_SCALE_FACTOR: f32 = 0.8;      // Matches FireFox (see gfxFont.h)

#[derive(Debug)]
struct LayoutFontCacheEntry {
    family: String,
    font: Option<Rc<RefCell<Font>>>,
}

#[derive(Debug)]
struct FallbackFontCacheEntry {
    font: Rc<RefCell<Font>>,
}

/// A cached azure font (per paint task) that
/// can be shared by multiple text runs.
#[derive(Debug)]
struct PaintFontCacheEntry {
    pt_size: Au,
    identifier: Atom,
    font: Rc<RefCell<ScaledFont>>,
}

/// An epoch for the font context cache. The cache is flushed if the current epoch does not match
/// this one.
static FONT_CACHE_EPOCH: AtomicUsize = ATOMIC_USIZE_INIT;

/// The FontContext represents the per-thread/task state necessary for
/// working with fonts. It is the public API used by the layout and
/// paint code. It talks directly to the font cache task where
/// required.
#[derive(Debug)]
pub struct FontContext {
    platform_handle: FontContextHandle,
    font_cache_task: FontCacheTask,

    /// TODO: See bug https://github.com/servo/servo/issues/3300.
    layout_font_cache: Vec<LayoutFontCacheEntry>,
    fallback_font_cache: Vec<FallbackFontCacheEntry>,

    /// Strong reference as the paint FontContext is (for now) recycled
    /// per frame. TODO: Make this weak when incremental redraw is done.
    paint_font_cache: Vec<PaintFontCacheEntry>,

    layout_font_group_cache:
        HashMap<LayoutFontGroupCacheKey, Rc<FontGroup>, DefaultState<FnvHasher>>,

    epoch: usize,
}

impl FontContext {
    pub fn new(font_cache_task: FontCacheTask) -> FontContext {
        let handle = FontContextHandle::new();
        FontContext {
            platform_handle: handle,
            font_cache_task: font_cache_task,
            layout_font_cache: vec!(),
            fallback_font_cache: vec!(),
            paint_font_cache: vec!(),
            layout_font_group_cache: HashMap::with_hash_state(Default::default()),
            epoch: 0,
        }
    }

    /// Create a font for use in layout calculations.
    fn create_layout_font(&self, template: Arc<FontTemplateData>,
                            descriptor: FontTemplateDescriptor, pt_size: Au,
                            variant: font_variant::T) -> Result<Font, ()> {
        // TODO: (Bug #3463): Currently we only support fake small-caps
        // painting. We should also support true small-caps (where the
        // font supports it) in the future.
        let actual_pt_size = match variant {
            font_variant::T::small_caps => pt_size.scale_by(SMALL_CAPS_SCALE_FACTOR),
            font_variant::T::normal => pt_size,
        };

        let handle: Result<FontHandle, _> =
            FontHandleMethods::new_from_template(&self.platform_handle, template,
                                                 Some(actual_pt_size));

        handle.map(|handle| {
            let metrics = handle.metrics();

            Font {
                handle: handle,
                shaper: None,
                variant: variant,
                descriptor: descriptor,
                requested_pt_size: pt_size,
                actual_pt_size: actual_pt_size,
                metrics: metrics,
                shape_cache: HashCache::new(),
                glyph_advance_cache: HashCache::new(),
            }
        })
    }

    fn expire_font_caches_if_necessary(&mut self) {
        let current_epoch = FONT_CACHE_EPOCH.load(Ordering::SeqCst);
        if current_epoch == self.epoch {
            return
        }

        self.layout_font_cache.clear();
        self.fallback_font_cache.clear();
        self.paint_font_cache.clear();
        self.layout_font_group_cache.clear();
        self.epoch = current_epoch
    }

    /// Create a group of fonts for use in layout calculations. May return
    /// a cached font if this font instance has already been used by
    /// this context.
    pub fn layout_font_group_for_style(&mut self, style: Arc<SpecifiedFontStyle>)
                                       -> Rc<FontGroup> {
        self.expire_font_caches_if_necessary();

        let layout_font_group_cache_key = LayoutFontGroupCacheKey {
            pointer: style.clone(),
            size: style.font_size,
        };
        if let Some(ref cached_font_group) = self.layout_font_group_cache.get(
                &layout_font_group_cache_key) {
            return (*cached_font_group).clone()
        }

        // TODO: The font context holds a strong ref to the cached fonts
        // so they will never be released. Find out a good time to drop them.

        let desc = FontTemplateDescriptor::new(style.font_weight,
                                               style.font_stretch,
                                               style.font_style == font_style::T::italic ||
                                                style.font_style == font_style::T::oblique);

        let mut fonts: SmallVec<[Rc<RefCell<Font>>; 8]> = SmallVec::new();

        for family in &style.font_family.0 {
            // GWTODO: Check on real pages if this is faster as Vec() or HashMap().
            let mut cache_hit = false;
            for cached_font_entry in &self.layout_font_cache {
                if cached_font_entry.family == family.name() {
                    match cached_font_entry.font {
                        None => {
                            cache_hit = true;
                            break;
                        }
                        Some(ref cached_font_ref) => {
                            let cached_font = (*cached_font_ref).borrow();
                            if cached_font.descriptor == desc &&
                               cached_font.requested_pt_size == style.font_size &&
                               cached_font.variant == style.font_variant {
                                fonts.push((*cached_font_ref).clone());
                                cache_hit = true;
                                break;
                            }
                        }
                    }
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.find_font_template(family.clone(),
                                                                            desc.clone());
                match font_template {
                    Some(font_template) => {
                        let layout_font = self.create_layout_font(font_template,
                                                                  desc.clone(),
                                                                  style.font_size,
                                                                  style.font_variant);
                        let font = match layout_font {
                            Ok(layout_font) => {
                                let layout_font = Rc::new(RefCell::new(layout_font));
                                fonts.push(layout_font.clone());

                                Some(layout_font)
                            }
                            Err(_) => None
                        };

                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: font
                        });
                    }
                    None => {
                        self.layout_font_cache.push(LayoutFontCacheEntry {
                            family: family.name().to_owned(),
                            font: None,
                        });
                    }
                }
            }
        }

        // If unable to create any of the specified fonts, create one from the
        // list of last resort fonts for this platform.
        if fonts.is_empty() {
            let mut cache_hit = false;
            for cached_font_entry in &self.fallback_font_cache {
                let cached_font = cached_font_entry.font.borrow();
                if cached_font.descriptor == desc &&
                            cached_font.requested_pt_size == style.font_size &&
                            cached_font.variant == style.font_variant {
                    fonts.push(cached_font_entry.font.clone());
                    cache_hit = true;
                    break;
                }
            }

            if !cache_hit {
                let font_template = self.font_cache_task.last_resort_font_template(desc.clone());
                let layout_font = self.create_layout_font(font_template,
                                                          desc.clone(),
                                                          style.font_size,
                                                          style.font_variant);
                match layout_font {
                    Ok(layout_font) => {
                        let layout_font = Rc::new(RefCell::new(layout_font));
                        self.fallback_font_cache.push(FallbackFontCacheEntry {
                            font: layout_font.clone(),
                        });
                        fonts.push(layout_font);
                    }
                    Err(_) => debug!("Failed to create fallback layout font!")
                }
            }
        }

        let font_group = Rc::new(FontGroup::new(fonts));
        self.layout_font_group_cache.insert(layout_font_group_cache_key, font_group.clone());
        font_group
    }

    /// Create a paint font for use with azure. May return a cached
    /// reference if already used by this font context.
    pub fn paint_font_from_template(&mut self,
                                        template: &Arc<FontTemplateData>,
                                        pt_size: Au)
                                        -> Rc<RefCell<ScaledFont>> {
        for cached_font in &self.paint_font_cache {
            if cached_font.pt_size == pt_size &&
               cached_font.identifier == template.identifier {
                return cached_font.font.clone();
            }
        }

        let paint_font = Rc::new(RefCell::new(create_scaled_font(template, pt_size)));
        self.paint_font_cache.push(PaintFontCacheEntry {
            font: paint_font.clone(),
            pt_size: pt_size,
            identifier: template.identifier.clone(),
        });
        paint_font
    }

    /// Returns a reference to the font cache task.
    pub fn font_cache_task(&self) -> FontCacheTask {
        self.font_cache_task.clone()
    }
}

impl HeapSizeOf for FontContext {
    fn heap_size_of_children(&self) -> usize {
        // FIXME(njn): Measure other fields eventually.
        self.platform_handle.heap_size_of_children()
    }
}

#[derive(Debug)]
struct LayoutFontGroupCacheKey {
    pointer: Arc<SpecifiedFontStyle>,
    size: Au,
}

impl PartialEq for LayoutFontGroupCacheKey {
    fn eq(&self, other: &LayoutFontGroupCacheKey) -> bool {
        self.pointer == other.pointer && self.size == other.size
    }
}

impl Eq for LayoutFontGroupCacheKey {}

impl Hash for LayoutFontGroupCacheKey {
    fn hash<H>(&self, hasher: &mut H) where H: Hasher {
        self.pointer.hash.hash(hasher)
    }
}

#[inline]
pub fn invalidate_font_caches() {
    FONT_CACHE_EPOCH.fetch_add(1, Ordering::SeqCst);
}
<|endoftext|>


<commit_before>use glium::backend::Facade;
use glium::{self, BackfaceCullingMode, DepthTest, DrawParameters, IndexBuffer, VertexBuffer};
use glium::index::PrimitiveType;
use Camera;
use util::ToArr;
use base::math::*;
use base::gen::seeded_rng;
use base::prop::plant::{Plant, Tree};
use std::rc::Rc;
use super::PlantRenderer;
use base::prop::plant::ControlPoint;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    vertices: VertexBuffer<Vertex>,
    indices: IndexBuffer<u32>,
    renderer: Rc<PlantRenderer>,
    pos: Point3f,
}

impl PlantView {
    pub fn from_plant<F: Facade>(pos: Point3f,
                                 plant: &Plant,
                                 renderer: Rc<PlantRenderer>,
                                 facade: &F)
                                 -> Self {
        let mut indices = Vec::new();
        let mut vertices = Vec::new();
        match *plant {
            Plant::Tree(Tree { ref branches, branch_color }) => {
                for branch in branches {
                    for i in 1..branch.points.len() {
                        get_vertices_for_branch(&branch.points[i - 1],
                                                &branch.points[i],
                                                &mut vertices,
                                                &mut indices,
                                                branch_color);
                    }
                }
            }
        };

        PlantView {
            vertices: VertexBuffer::new(facade, &vertices).unwrap(),
            indices: IndexBuffer::new(facade,
                                      PrimitiveType::Patches { vertices_per_patch: 3 },
                                      &indices)
                .unwrap(),
            renderer: renderer,
            pos: pos,
        }
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.shadow_program(),
                  &uniforms,
                  &params)
            .unwrap();
    }

    pub fn draw<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let tess_level_inner = 10.0 as f32;
        let tess_level_outer = 10.0 as f32;

        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
            tess_level_inner: tess_level_inner ,
            tess_level_outer: tess_level_outer,
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullCounterClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.program(),
                  &uniforms,
                  &params)
            .unwrap();
    }
}

/// Vertex type used to render plants/trees.
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 3],
    pub normal: [f32; 3],
}

implement_vertex!(Vertex, position, color, normal);

/// generates Vertexbuffer and indexbuffer for a branch
fn get_vertices_for_branch(start: &ControlPoint,
                           end: &ControlPoint,
                           vertices: &mut Vec<Vertex>,
                           indices: &mut Vec<u32>,
                           color: Vector3f) {

    let to_end = end.point - start.point;
    let ortho = get_points_from_vector(to_end);

    let mut cur_len = vertices.len() as u32;

    // Bottom
    for vec in ortho.iter() {
        vertices.push(Vertex {
            position: (start.point + vec * start.diameter).to_arr(),
            normal: (-to_end).normalize().to_arr(),
            color: color.to_arr(),
        });
    }
    indices.extend_from_slice(&[cur_len + 2, cur_len + 0, cur_len + 1]);

    // Top
    cur_len = vertices.len() as u32;

    for vec in ortho.iter() {
        vertices.push(Vertex {
            position: (end.point + vec * end.diameter).to_arr(),
            normal: to_end.normalize().to_arr(),
            color: color.to_arr(),
        });
    }
    indices.extend_from_slice(&[cur_len + 1, cur_len + 0, cur_len + 2]);

    side(vertices, indices, color, start, end, ortho[0], ortho[1]);
    side(vertices, indices, color, start, end, ortho[1], ortho[2]);
    side(vertices, indices, color, start, end, ortho[2], ortho[0]);
}

/// Creates Vertexbuffer and IndexBuffer for a Side of the plants
fn side(vertices: &mut Vec<Vertex>,
        indices: &mut Vec<u32>,
        color: Vector3f,
        start: &ControlPoint,
        end: &ControlPoint,
        first_normal: Vector3f,
        second_normal: Vector3f) {
    let cur_len = vertices.len() as u32;

    vertices.extend_from_slice(&[Vertex {
                                     position: (end.point + first_normal * end.diameter).to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 },
                                 Vertex {
                                     position: (end.point + second_normal * end.diameter).to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 },
                                 Vertex {
                                     position: (start.point + first_normal * start.diameter)
                                         .to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 },
                                 Vertex {
                                     position: (start.point + second_normal * start.diameter)
                                         .to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 }]);

    indices.extend_from_slice(&[cur_len + 2,
                                cur_len + 0,
                                cur_len + 1,
                                cur_len + 2,
                                cur_len + 1,
                                cur_len + 3]);
}

/// generates 3 normalized vectors perpendicular to the given vector
fn get_points_from_vector(vector: Vector3f) -> [Vector3f; 3] {
    let ortho = random_vec_with_angle(&mut seeded_rng(0x2651aa465abded, (), ()), vector, 90.0);
    let rot = Basis3::from_axis_angle(vector, Deg::new(120.0).into());
    let v0 = rot.rotate_vector(ortho);
    let v1 = rot.rotate_vector(v0);

    [ortho.normalize(), v0.normalize(), v1.normalize()]
}
<commit_msg>Fix plant dimension<commit_after>use glium::backend::Facade;
use glium::{self, BackfaceCullingMode, DepthTest, DrawParameters, IndexBuffer, VertexBuffer};
use glium::index::PrimitiveType;
use Camera;
use util::ToArr;
use base::math::*;
use base::gen::seeded_rng;
use base::prop::plant::{Plant, Tree};
use std::rc::Rc;
use super::PlantRenderer;
use base::prop::plant::ControlPoint;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    vertices: VertexBuffer<Vertex>,
    indices: IndexBuffer<u32>,
    renderer: Rc<PlantRenderer>,
    pos: Point3f,
}

impl PlantView {
    pub fn from_plant<F: Facade>(pos: Point3f,
                                 plant: &Plant,
                                 renderer: Rc<PlantRenderer>,
                                 facade: &F)
                                 -> Self {
        let mut indices = Vec::new();
        let mut vertices = Vec::new();
        match *plant {
            Plant::Tree(Tree { ref branches, branch_color }) => {
                for branch in branches {
                    for i in 1..branch.points.len() {
                        get_vertices_for_branch(&branch.points[i - 1],
                                                &branch.points[i],
                                                &mut vertices,
                                                &mut indices,
                                                branch_color);
                    }
                }
            }
        };

        PlantView {
            vertices: VertexBuffer::new(facade, &vertices).unwrap(),
            indices: IndexBuffer::new(facade,
                                      PrimitiveType::Patches { vertices_per_patch: 3 },
                                      &indices)
                .unwrap(),
            renderer: renderer,
            pos: pos,
        }
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.shadow_program(),
                  &uniforms,
                  &params)
            .unwrap();
    }

    pub fn draw<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let tess_level_inner = 10.0 as f32;
        let tess_level_outer = 10.0 as f32;

        let uniforms = uniform! {
            offset: self.pos.to_arr(),
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
            tess_level_inner: tess_level_inner ,
            tess_level_outer: tess_level_outer,
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullCounterClockwise,
            ..Default::default()
        };

        surface.draw(&self.vertices,
                  &self.indices,
                  &self.renderer.program(),
                  &uniforms,
                  &params)
            .unwrap();
    }
}

/// Vertex type used to render plants/trees.
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub color: [f32; 3],
    pub normal: [f32; 3],
}

implement_vertex!(Vertex, position, color, normal);

/// generates Vertexbuffer and indexbuffer for a branch
fn get_vertices_for_branch(start: &ControlPoint,
                           end: &ControlPoint,
                           vertices: &mut Vec<Vertex>,
                           indices: &mut Vec<u32>,
                           color: Vector3f) {

    let to_end = end.point - start.point;
    let ortho = get_points_from_vector(to_end);

    let mut cur_len = vertices.len() as u32;

    // Bottom
    for vec in ortho.iter() {
        vertices.push(Vertex {
            position: (start.point + vec * start.diameter).to_arr(),
            normal: (-to_end).normalize().to_arr(),
            color: color.to_arr(),
        });
    }
    indices.extend_from_slice(&[cur_len + 2, cur_len + 0, cur_len + 1]);

    // Top
    cur_len = vertices.len() as u32;

    for vec in ortho.iter() {
        vertices.push(Vertex {
            position: (end.point + vec * end.diameter).to_arr(),
            normal: to_end.normalize().to_arr(),
            color: color.to_arr(),
        });
    }
    indices.extend_from_slice(&[cur_len + 1, cur_len + 0, cur_len + 2]);

    side(vertices, indices, color, start, end, ortho[0], ortho[1]);
    side(vertices, indices, color, start, end, ortho[1], ortho[2]);
    side(vertices, indices, color, start, end, ortho[2], ortho[0]);
}

/// Creates Vertexbuffer and IndexBuffer for a Side of the plants
fn side(vertices: &mut Vec<Vertex>,
        indices: &mut Vec<u32>,
        color: Vector3f,
        start: &ControlPoint,
        end: &ControlPoint,
        first_normal: Vector3f,
        second_normal: Vector3f) {
    let cur_len = vertices.len() as u32;

    vertices.extend_from_slice(&[Vertex {
                                     position: (end.point + first_normal * end.diameter).to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 },
                                 Vertex {
                                     position: (end.point + second_normal * end.diameter).to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 },
                                 Vertex {
                                     position: (start.point + first_normal * start.diameter)
                                         .to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 },
                                 Vertex {
                                     position: (start.point + second_normal * start.diameter)
                                         .to_arr(),
                                     normal: (first_normal + second_normal).normalize().to_arr(),
                                     color: color.to_arr(),
                                 }]);

    indices.extend_from_slice(&[cur_len + 2,
                                cur_len + 0,
                                cur_len + 1,
                                cur_len + 2,
                                cur_len + 1,
                                cur_len + 3]);
}

/// generates 3 normalized vectors perpendicular to the given vector
fn get_points_from_vector(vector: Vector3f) -> [Vector3f; 3] {
    let ortho = random_vec_with_angle(&mut seeded_rng(0x2651aa465abded, (), ()), vector, 90.0);
    let rot = Basis3::from_axis_angle(vector, Deg::new(105.0).into());
    let v0 = rot.rotate_vector(ortho);
    let v1 = rot.rotate_vector(v0);

    [ortho.normalize(), v0.normalize(), v1.normalize()]
}
<|endoftext|>


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

extern crate "snowmew-core" as core;
extern crate "snowmew-position" as position;
extern crate "snowmew-graphics" as graphics;
extern crate "snowmew-render" as render;
extern crate "snowmew-input" as input;

extern crate wire;
extern crate bchannel;
extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use core::common::{Common, CommonData};
use position::{Positions, PositionData};
use graphics::{Graphics, GraphicsData};
use render::{Renderable, RenderData};
use input::{IoState, GetIoState};

use std::sync::mpsc;
use std::thread::Thread;
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;
use wire::SizeLimit;
use wire::tcp::OutTcpStream;
use rustc_serialize::{Decodable, Encodable};

use core::game::Game;

#[derive(RustcEncodable, RustcDecodable)]
pub enum ServerMessage<T, E> {
    Image(T),
    Event(E)
}

#[derive(RustcEncodable, RustcDecodable)]
pub enum ClientMessage<E> {
    Event(E)
}

pub struct Server<Game, GameData> {
    game: Game,
    data: GameData
}

unsafe impl<T:Send, E:Send, CE:Send> Send for ServerClient<T, E, CE> {}

struct ServerClient<T, E, CE> {
    to_client: OutTcpStream<ServerMessage<T, CE>>,
    from_client: bchannel::Receiver<ClientMessage<E>, bincode::DecodingError>
}

impl<G, GD:Clone+Send+Decodable+Encodable> Server<G, GD> {
    pub fn new(game: G, data: GD) -> Server<G, GD> {
        Server {
            game: game,
            data: data
        }
    }

    pub fn serve<E: Send+Encodable+Clone+Decodable+FromIterator<CE>,
                 CE: Send+Encodable+Clone+Decodable>(mut self, iface: &str, port: u16)
        where G: Game<GD, E> {

        let (listener, _) = wire::listen_tcp(iface, port).unwrap();

        let (tx, rx): (mpsc::Sender<ServerClient<GD, CE, E>>,
                       mpsc::Receiver<ServerClient<GD, CE, E>>) = mpsc::channel();
        Thread::spawn(move || {
            let (read_limit, write_limit) = (SizeLimit::Infinite, SizeLimit::Infinite);

            for connection in listener.into_blocking_iter() {
                let (i, o) = wire::upgrade_tcp(connection, read_limit, write_limit);

                let client = ServerClient {
                    to_client: o,
                    from_client: i
                };

                tx.send(client);
            }
        });

        let mut clients = Vec::new();

        loop {
            // add clients to game
            while clients.len() == 0 {
                let mut res = rx.recv().ok().expect("failed to get message");
                res.to_client.send(&ServerMessage::Image(self.data.clone()));
                clients.push(res);
            }

            while let Ok(mut res) = rx.try_recv() {
                res.to_client.send(&ServerMessage::Image(self.data.clone()));
                clients.push(res)
            }

            let event: E = clients.iter().map(|c| {
                let e = c.from_client.recv_block().expect("client sucks man");
                match e { ClientMessage::Event(e) => e }
            }).collect();

            for c in clients.iter_mut() {
                c.to_client.send(&ServerMessage::Event(event.clone()));
            }
            self.data = self.game.step(event, self.data);
        }
    }
}

#[derive(Clone)]
pub struct ClientState<T, E> {
    sync: bool,
    predict_frame: u32,
    predict: T,
    predict_delta: Vec<(u32, E)>,
    server_frame: u32,
    server: T
}

impl<T, E> Deref for ClientState<T, E> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {
        &self.predict
    }
}

impl<T, E> DerefMut for ClientState<T, E> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.predict
    }
}

impl<E, T: Common> Common for ClientState<T, E> {
    fn get_common<'a>(&'a self) -> &'a CommonData { self.predict.get_common() }
    fn get_common_mut<'a>(&'a mut self) -> &'a mut CommonData { self.predict.get_common_mut() }
}

impl<E, T: Positions> Positions for ClientState<T, E> {
    fn get_position<'a>(&'a self) -> &'a PositionData { self.predict.get_position() }
    fn get_position_mut<'a>(&'a mut self) -> &'a mut PositionData { self.predict.get_position_mut() }
}

impl<E, T: Graphics> Graphics for ClientState<T, E> {
    fn get_graphics<'a>(&'a self) -> &'a GraphicsData { self.predict.get_graphics() }
    fn get_graphics_mut<'a>(&'a mut self) -> &'a mut GraphicsData { self.predict.get_graphics_mut() }
}

impl<E, T: Renderable> Renderable for ClientState<T, E> {
    fn get_render_data<'a>(&'a self) -> &'a RenderData { self.predict.get_render_data() }
    fn get_render_data_mut<'a>(&'a mut self) -> &'a mut RenderData { self.predict.get_render_data_mut() }
}

impl<E, T: GetIoState> GetIoState for ClientState<T, E> {
    fn get_io_state<'a>(&'a self) -> &'a IoState { self.predict.get_io_state() }
    fn get_io_state_mut<'a>(&'a mut self) -> &'a mut IoState { self.predict.get_io_state_mut() }
}

pub struct Client<G, T, SE, CE> {
    game: G,
    to_server: OutTcpStream<ClientMessage<CE>>,
    from_server: bchannel::Receiver<ServerMessage<T, SE>, bincode::DecodingError>
}

impl<G, T:Send+Encodable+Decodable+Clone,
     E:Send+Encodable+Decodable,
     CE:Send+Encodable+Decodable> Client<G, T, E, CE> {

    pub fn new(game: G, server: &str, port: u16) -> Client<G, T, E, CE> {
        let (o, i) = wire::connect_tcp(server, port, SizeLimit::Infinite, SizeLimit::Infinite).unwrap();

        Client {
            game: game,
            to_server: i,
            from_server: o
        }
    }

    pub fn gamedata(&mut self) -> ClientState<T, E> {
        match self.from_server.recv_block().expect("failed to get state") {
            ServerMessage::Image(state) => {
                println!("download done");
                ClientState {
                    sync: false,
                    predict_frame: 0,
                    predict: state.clone(),
                    predict_delta: Vec::new(),
                    server_frame: 0,
                    server: state.clone()
                }
            },
            _ => panic!("expected game data")
        }
    }
}

impl<G: Game<T, SE>,
     T:Send+Encodable+Decodable+Clone,
     SE:Send+Encodable+Decodable+Clone+FromIterator<CE>,
     CE:Send+Encodable+Decodable+Clone>
    Game<ClientState<T, CE>, CE> for Client<G, T, SE, CE> {

    fn step(&mut self, event: CE, mut gd: ClientState<T, CE>) -> ClientState<T, CE> {
        let mut frame = gd.predict.clone();
        let mut index = gd.predict_frame;

        loop {
            match self.from_server.recv() {
                Some(ServerMessage::Image(_)) => panic!("unexpected game data"),
                Some(ServerMessage::Event(e)) => {
                    gd.server = self.game.step(e, gd.server);
                    gd.server_frame += 1;
                    frame = gd.server.clone();
                    index = gd.server_frame;
                },
                None => break
            }
        }

        if gd.sync {
            gd.sync = gd.predict_frame > gd.server_frame + 1;
            if gd.sync { return gd }
        } else if gd.predict_frame > gd.server_frame + 5 {
            gd.sync = true;
            return gd;
        }

        self.to_server.send(&ClientMessage::Event(event.clone()));
        gd.predict_delta.push((gd.predict_frame, event));
        gd.predict_frame += 1;

        let mut predict = Vec::new();
        for (idx, e) in gd.predict_delta.drain() {
            if idx > index {
                println!("{} > {}", idx, index);
                frame = self.game.step([e.clone()].iter().map(|x| x.clone()).collect(), frame);
            }

            if idx > gd.server_frame {
                predict.push((idx, e.clone()));
            }
        }

        gd.predict = frame;
        gd.predict_delta = predict;
        gd
    }
}

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

extern crate "snowmew-core" as core;
extern crate "snowmew-position" as position;
extern crate "snowmew-graphics" as graphics;
extern crate "snowmew-render" as render;
extern crate "snowmew-input" as input;

extern crate wire;
extern crate bchannel;
extern crate bincode;
extern crate "rustc-serialize" as rustc_serialize;

use core::common::{Common, CommonData};
use position::{Positions, PositionData};
use graphics::{Graphics, GraphicsData};
use render::{Renderable, RenderData};
use input::{IoState, GetIoState};

use std::sync::mpsc;
use std::thread::Thread;
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;
use wire::SizeLimit;
use wire::tcp::OutTcpStream;
use rustc_serialize::{Decodable, Encodable};

use core::game::Game;

#[derive(RustcEncodable, RustcDecodable)]
pub enum ServerMessage<T, E> {
    Image(T),
    Event(E)
}

#[derive(RustcEncodable, RustcDecodable)]
pub enum ClientMessage<E> {
    Event(E)
}

pub struct Server<Game, GameData> {
    game: Game,
    data: GameData
}

unsafe impl<T:Send, E:Send, CE:Send> Send for ServerClient<T, E, CE> {}

struct ServerClient<T, E, CE> {
    to_client: OutTcpStream<ServerMessage<T, CE>>,
    from_client: bchannel::Receiver<ClientMessage<E>, bincode::DecodingError>
}

impl<G, GD:Clone+Send+Decodable+Encodable> Server<G, GD> {
    pub fn new(game: G, data: GD) -> Server<G, GD> {
        Server {
            game: game,
            data: data
        }
    }

    pub fn serve<E: Send+Encodable+Clone+Decodable+FromIterator<CE>,
                 CE: Send+Encodable+Clone+Decodable>(mut self, iface: &str, port: u16)
        where G: Game<GD, E> {

        let (listener, _) = wire::listen_tcp(iface, port).unwrap();

        let (tx, rx): (mpsc::Sender<ServerClient<GD, CE, E>>,
                       mpsc::Receiver<ServerClient<GD, CE, E>>) = mpsc::channel();
        Thread::spawn(move || {
            let (read_limit, write_limit) = (SizeLimit::Infinite, SizeLimit::Infinite);

            for connection in listener.into_blocking_iter() {
                let (i, o) = wire::upgrade_tcp(connection, read_limit, write_limit);

                let client = ServerClient {
                    to_client: o,
                    from_client: i
                };

                tx.send(client);
            }
        });

        let mut clients = Vec::new();

        loop {
            // add clients to game
            while clients.len() == 0 {
                let mut res = rx.recv().ok().expect("failed to get message");
                res.to_client.send(&ServerMessage::Image(self.data.clone()));
                clients.push(res);
            }

            while let Ok(mut res) = rx.try_recv() {
                res.to_client.send(&ServerMessage::Image(self.data.clone()));
                clients.push(res)
            }

            let event: E = clients.iter().map(|c| {
                let e = c.from_client.recv_block().expect("client sucks man");
                match e { ClientMessage::Event(e) => e }
            }).collect();

            for c in clients.iter_mut() {
                c.to_client.send(&ServerMessage::Event(event.clone()));
            }
            self.data = self.game.step(event, self.data);
        }
    }
}

#[derive(Clone)]
pub struct ClientState<T, E> {
    sync: bool,
    predict_frame: u32,
    predict: T,
    predict_delta: Vec<(u32, E)>,
    server_frame: u32,
    server: T
}

impl<T, E> Deref for ClientState<T, E> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {
        &self.predict
    }
}

impl<T, E> DerefMut for ClientState<T, E> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.predict
    }
}

impl<E, T: Common> Common for ClientState<T, E> {
    fn get_common<'a>(&'a self) -> &'a CommonData { self.predict.get_common() }
    fn get_common_mut<'a>(&'a mut self) -> &'a mut CommonData { self.predict.get_common_mut() }
}

impl<E, T: Positions> Positions for ClientState<T, E> {
    fn get_position<'a>(&'a self) -> &'a PositionData { self.predict.get_position() }
    fn get_position_mut<'a>(&'a mut self) -> &'a mut PositionData { self.predict.get_position_mut() }
}

impl<E, T: Graphics> Graphics for ClientState<T, E> {
    fn get_graphics<'a>(&'a self) -> &'a GraphicsData { self.predict.get_graphics() }
    fn get_graphics_mut<'a>(&'a mut self) -> &'a mut GraphicsData { self.predict.get_graphics_mut() }
}

impl<E, T: Renderable> Renderable for ClientState<T, E> {
    fn get_render_data<'a>(&'a self) -> &'a RenderData { self.predict.get_render_data() }
    fn get_render_data_mut<'a>(&'a mut self) -> &'a mut RenderData { self.predict.get_render_data_mut() }
}

impl<E, T: GetIoState> GetIoState for ClientState<T, E> {
    fn get_io_state<'a>(&'a self) -> &'a IoState { self.predict.get_io_state() }
    fn get_io_state_mut<'a>(&'a mut self) -> &'a mut IoState { self.predict.get_io_state_mut() }
}

pub struct Client<G, T, SE, CE> {
    game: G,
    to_server: OutTcpStream<ClientMessage<CE>>,
    from_server: bchannel::Receiver<ServerMessage<T, SE>, bincode::DecodingError>
}

impl<G, T:Send+Encodable+Decodable+Clone,
     E:Send+Encodable+Decodable,
     CE:Send+Encodable+Decodable> Client<G, T, E, CE> {

    pub fn new(game: G, server: &str, port: u16) -> Client<G, T, E, CE> {
        let (o, i) = wire::connect_tcp(server, port, SizeLimit::Infinite, SizeLimit::Infinite).unwrap();

        Client {
            game: game,
            to_server: i,
            from_server: o
        }
    }

    pub fn gamedata(&mut self) -> ClientState<T, E> {
        match self.from_server.recv_block().expect("failed to get state") {
            ServerMessage::Image(state) => {
                println!("download done");
                ClientState {
                    sync: false,
                    predict_frame: 0,
                    predict: state.clone(),
                    predict_delta: Vec::new(),
                    server_frame: 0,
                    server: state.clone()
                }
            },
            _ => panic!("expected game data")
        }
    }
}

impl<G: Game<T, SE>,
     T:Send+Encodable+Decodable+Clone,
     SE:Send+Encodable+Decodable+Clone+FromIterator<CE>,
     CE:Send+Encodable+Decodable+Clone>
    Game<ClientState<T, CE>, CE> for Client<G, T, SE, CE> {

    fn step(&mut self, event: CE, mut gd: ClientState<T, CE>) -> ClientState<T, CE> {
        let mut frame = gd.predict.clone();
        let mut index = gd.predict_frame;

        loop {
            match self.from_server.recv() {
                Some(ServerMessage::Image(_)) => panic!("unexpected game data"),
                Some(ServerMessage::Event(e)) => {
                    gd.server = self.game.step(e, gd.server);
                    gd.server_frame += 1;
                    frame = gd.server.clone();
                    index = gd.server_frame;
                },
                None => break
            }
        }

        if gd.sync {
            gd.sync = gd.predict_frame > gd.server_frame + 1;
            if gd.sync { return gd }
        } else if gd.predict_frame > gd.server_frame + 25 {
            gd.sync = true;
            return gd;
        }

        self.to_server.send(&ClientMessage::Event(event.clone()));
        gd.predict_delta.push((gd.predict_frame, event));
        gd.predict_frame += 1;

        let mut predict = Vec::new();
        for (idx, e) in gd.predict_delta.drain() {
            if idx > index {
                println!("{} > {}", idx, index);
                frame = self.game.step([e.clone()].iter().map(|x| x.clone()).collect(), frame);
            }

            if idx > gd.server_frame {
                predict.push((idx, e.clone()));
            }
        }

        gd.predict = frame;
        gd.predict_delta = predict;
        gd
    }
}

<|endoftext|>