<commit_before>use std::num::Zero;
use std::vec;
use nalgebra::na::{Cast, Vec, VecExt, AlgebraicVecExt, AbsoluteRotate, Dim, Transform, Rotate,
                   Translation, Vec4, Vec3};
use nalgebra::na;
use ncollide::bounding_volume::{AABB, HasAABB};
use ncollide::partitioning::bvt;
use ncollide::partitioning::bvt::BVT;
use ncollide::partitioning::bvt_visitor::BVTVisitor;
// use ncollide::partitioning::bvt_visitor::RayInterferencesCollector;
use ncollide::ray::{Ray, RayCast, RayCastWithTransform};
use scene_node::SceneNode;
use image::Image;
use light::Light;

pub struct Scene<N, V, Vlessi, M> {
    priv lights: ~[Light<V>],
    priv world:  BVT<@SceneNode<N, V, M>, AABB<N, V>>
}

impl<N:      'static + Cast<f32> + NumCast + Primitive + Algebraic + Signed + Float + ToStr,
     V:      'static + AlgebraicVecExt<N> + Clone + ToStr,
     Vlessi: VecExt<uint> + Dim + Clone + ToStr,
     M:      Translation<V> + Rotate<V> + Transform<V> + Mul<M, M> + AbsoluteRotate<V> + Dim>
Scene<N, V, Vlessi, M> {
    pub fn new(nodes:  ~[@SceneNode<N, V, M>],
               lights: ~[Light<V>]) -> Scene<N, V, Vlessi, M> {
        let mut nodes_w_bvs = ~[];

        for n in nodes.move_iter() {
            let aabb = n.geometry.aabb(&n.transform);
            nodes_w_bvs.push((n, aabb));
        }

        let bvt = BVT::new_with_partitioner(nodes_w_bvs, bvt::dim_pow_2_aabb_partitioner);

        Scene {
            lights: lights,
            world:  bvt
        }
    }

    pub fn render(&self, resolution: &Vlessi, unproject: &fn(&Vlessi) -> Ray<V>) -> Image<Vlessi> {
        let mut npixels = 1;

        for i in resolution.iter() {
            npixels = npixels * *i;
        }

        let mut curr: Vlessi = Zero::zero();

        // Sample a rectangular n-1 surface (with n the rendering dimension):
        //   * a rectangle for 3d rendering.
        //   * a cube for 4d rendering.
        //   * an hypercube for 5d rendering.
        //   * etc
        let mut pixels    = vec::with_capacity(npixels);

        for _ in range(0u, npixels) {
            // curr contains the index of the current sample point.
            pixels.push(self.trace(&unproject(&curr)));

            for j in range(0u, Dim::dim(None::<Vlessi>)) {
                let inc = curr.at(j) + 1;

                if inc == resolution.at(j) {
                    curr.set(j, 0);
                }
                else {
                    curr.set(j, inc);
                    break;
                }
            }
        }

        Image::new(resolution.clone(), pixels)
    }

    pub fn trace(&self, ray: &Ray<V>) -> Vec4<f64> {
        let mut interferences: ~[@SceneNode<N, V, M>] = ~[];

        {
            let mut collector = RayInterferencesCollector::new(ray, &mut interferences);
            self.world.visit(&mut collector);
        }

        /*
         * Nothing fancy at the moment: simply return the color of the first object hit by the ray.
         */
        let mut intersection = None;
        let mut mintoi:    N    = Bounded::max_value();
        let mut minnormal: V    = Zero::zero();
        for i in interferences.iter() {
            let toi = i.geometry.toi_and_normal_with_transform_and_ray(&i.transform, ray);

            match toi {
                None => { },
                Some((toi, normal)) => {
                    if toi < mintoi {
                        mintoi       = toi;
                        minnormal    = normal;
                        intersection = Some(i);
                    }
                }
            }
        }

        match intersection {
            None    => Vec4::new(0.0, 0.0, 0.0, 1.0),
            Some(i) => {
                // FIXME: create a shader system to handle lighting
                let _ = self.compute_lighting_from(*i, &(ray.orig + ray.dir * mintoi), &minnormal);

                // FIXME: we use NumCast here since the structs::spec::f64Cast trait is private…
                // Find a way to fix that on nalgebra.
                let mut color: Vec3<f64> = Vec3::new(NumCast::from(minnormal.at(0)).unwrap(),
                                                     NumCast::from(minnormal.at(1)).unwrap(),
                                                     NumCast::from(minnormal.at(2)).unwrap());

                color = (color + 1.0) / 2.0;

                na::to_homogeneous(&color)
                // light + i.material.diffuse_color
            }
        }
    }

    pub fn compute_lighting_from(&self, _: @SceneNode<N, V, M>, point: &V, _: &V) -> Vec4<f64> {
        let mut interferences: ~[@SceneNode<N, V, M>] = ~[];

        let mut color = Vec4::new(0.0f64, 0.0, 0.0, 0.0);

        'loop: for l in self.lights.iter() {
            interferences.clear();

            let ray = Ray::new(l.pos.clone(), *point - l.pos);

            {
                let mut collector = RayInterferencesCollector::new(&ray, &mut interferences);
                self.world.visit(&mut collector);
            }

            for i in interferences.iter() {
                if true { // !managed::ptr_eq(*i, node)
                    let toi = i.geometry.toi_with_transform_and_ray(&i.transform, &ray);
                    match toi {
                        None      => { },
                        Some(toi) => {
                            if toi < na::cast(0.75 - 0.00001) {
                                continue 'loop;
                            }
                        }
                    }
                }
            }

            // FIXME: we use NumCast here since the structs::spec::f64Cast trait is private…
            // Find a way to fix that on nalgebra.
            let distance_to_light: f64 = NumCast::from(na::norm(&(*point - l.pos))).unwrap();
            color = color + na::to_homogeneous(&(l.color * (1.0 - distance_to_light / 5.0)));
        }

            color
        }
}

/*
 * ----------------------------------------------------------------------------------------------
 *
 * XXX: This is an exact duplicate of lib/ncollide/src/partitioning/bvt_visitor.rs#RayInterferencesCollector
 * This does not compile cross-crate (ICE).
 *
 * ----------------------------------------------------------------------------------------------
 */
/// Bounding Volume Tree visitor collecting interferences with a given ray.
pub struct RayInterferencesCollector<'self, V, B> {
    priv ray:       &'self Ray<V>,
    priv collector: &'self mut ~[B]
}

impl<'self, V, B> RayInterferencesCollector<'self, V, B> {
    /// Creates a new `RayInterferencesCollector`.
    #[inline]
    pub fn new(ray:    &'self Ray<V>,
               buffer: &'self mut ~[B])
               -> RayInterferencesCollector<'self, V, B> {
        RayInterferencesCollector {
            ray:       ray,
            collector: buffer
        }
    }
}

impl<'self,
     N,
     V:  Vec<N>,
     B:  Clone,
     BV: RayCast<N, V>>
BVTVisitor<B, BV> for RayInterferencesCollector<'self, V, B> {
    #[inline]
    fn visit_internal(&mut self, bv: &BV) -> bool {
        bv.intersects_ray(self.ray)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &B, bv: &BV) {
        if bv.intersects_ray(self.ray) {
            self.collector.push(b.clone())
        }
    }
}
<commit_msg>Implement basic diffuse color technique.<commit_after>use std::num::Zero;
use std::vec;
use nalgebra::na::{Cast, Vec, VecExt, AlgebraicVecExt, AbsoluteRotate, Dim, Transform, Rotate,
                   Translation, Vec4, Vec3};
use nalgebra::na;
use ncollide::bounding_volume::{AABB, HasAABB};
use ncollide::partitioning::bvt;
use ncollide::partitioning::bvt::BVT;
use ncollide::partitioning::bvt_visitor::BVTVisitor;
// use ncollide::partitioning::bvt_visitor::RayInterferencesCollector;
use ncollide::ray::{Ray, RayCast, RayCastWithTransform};
use scene_node::SceneNode;
use image::Image;
use light::Light;

pub struct Scene<N, V, Vlessi, M> {
    priv lights: ~[Light<V>],
    priv world:  BVT<@SceneNode<N, V, M>, AABB<N, V>>
}

impl<N:      'static + Cast<f32> + Send + Freeze + NumCast + Primitive + Algebraic + Signed + Float + ToStr,
     V:      'static + AlgebraicVecExt<N> + Send + Freeze + Clone + ToStr,
     Vlessi: VecExt<uint> + Dim + Clone + ToStr,
     M:      Translation<V> + Rotate<V> + Send + Freeze + Transform<V> + Mul<M, M> + AbsoluteRotate<V> + Dim>
Scene<N, V, Vlessi, M> {
    pub fn new(nodes:  ~[@SceneNode<N, V, M>],
               lights: ~[Light<V>]) -> Scene<N, V, Vlessi, M> {
        let mut nodes_w_bvs = ~[];

        for n in nodes.move_iter() {
            let aabb = n.geometry.aabb(&n.transform);
            nodes_w_bvs.push((n, aabb));
        }

        let bvt = BVT::new_with_partitioner(nodes_w_bvs, bvt::dim_pow_2_aabb_partitioner);

        Scene {
            lights: lights,
            world:  bvt
        }
    }

    pub fn render(&self, resolution: &Vlessi, unproject: &fn(&Vlessi) -> Ray<V>) -> Image<Vlessi> {
        let mut npixels = 1;

        for i in resolution.iter() {
            npixels = npixels * *i;
        }

        let mut curr: Vlessi = Zero::zero();

        // Sample a rectangular n-1 surface (with n the rendering dimension):
        //   * a rectangle for 3d rendering.
        //   * a cube for 4d rendering.
        //   * an hypercube for 5d rendering.
        //   * etc
        let mut pixels    = vec::with_capacity(npixels);

        for _ in range(0u, npixels) {
            // curr contains the index of the current sample point.
            let c = self.trace(&unproject(&curr));
            pixels.push(c);

            for j in range(0u, Dim::dim(None::<Vlessi>)) {
                let inc = curr.at(j) + 1;

                if inc == resolution.at(j) {
                    curr.set(j, 0);
                }
                else {
                    curr.set(j, inc);
                    break;
                }
            }
        }

        Image::new(resolution.clone(), pixels)
    }

    pub fn trace(&self, ray: &Ray<V>) -> Vec4<f64> {
        let mut interferences: ~[@SceneNode<N, V, M>] = ~[];

        {
            let mut collector = RayInterferencesCollector::new(ray, &mut interferences);
            self.world.visit(&mut collector);
        }

        /*
         * Nothing fancy at the moment: simply return the color of the first object hit by the ray.
         */
        let mut intersection = None;
        let mut mintoi:    N    = Bounded::max_value();
        let mut minnormal: V    = Zero::zero();
        for i in interferences.iter() {
            let toi = i.geometry.toi_and_normal_with_transform_and_ray(&i.transform, ray);

            match toi {
                None => { },
                Some((toi, normal)) => {
                    if toi < mintoi {
                        mintoi       = toi;
                        minnormal    = normal;
                        intersection = Some(i);
                    }
                }
            }
        }

        match intersection {
            None    => Vec4::new(0.0, 0.0, 0.0, 1.0),
            Some(i) => {
                // FIXME: create a shader system to handle lighting
               // self.compute_lighting_from(*i, &(ray.orig + ray.dir * mintoi), &minnormal)
               let cos_angle = na::dot(&ray.dir, &minnormal) / (na::norm(&ray.dir) *
                                                                 na::norm(&minnormal));

               // // FIXME: we use NumCast here since the structs::spec::f64Cast trait is private…
               // // Find a way to fix that on nalgebra.
                let mut color: Vec3<f64> = Vec3::new(NumCast::from(-cos_angle).unwrap(), 0., 0.);
                na::to_homogeneous(&color)
            }
        }
    }

    pub fn compute_lighting_from(&self, _: @SceneNode<N, V, M>, point: &V, _: &V) -> Vec4<f64> {
        let mut interferences: ~[@SceneNode<N, V, M>] = ~[];

        let mut color = Vec4::new(0.0f64, 0.0, 0.0, 1.0);

        'loop: for l in self.lights.iter() {
            interferences.clear();

            let ray = Ray::new(l.pos.clone(), *point - l.pos);

            {
                let mut collector = RayInterferencesCollector::new(&ray, &mut interferences);
                self.world.visit(&mut collector);
            }

            for i in interferences.iter() {
                if true { // !managed::ptr_eq(*i, node)
                    let toi = i.geometry.toi_with_transform_and_ray(&i.transform, &ray);
                    match toi {
                        None      => { },
                        Some(toi) => {
                           // if toi < na::cast(0.75 - 0.00001) {
                           //     continue 'loop;
                           // }
                        }
                    }
                }
            }

            // FIXME: we use NumCast here since the structs::spec::f64Cast trait is private…
            // Find a way to fix that on nalgebra.
            let distance_to_light: f64 = NumCast::from(na::norm(&(*point - l.pos))).unwrap();
            color = color + na::to_homogeneous(&(l.color * (1.0 - distance_to_light / 5.0)));
        }

            color
        }
}

/*
 * ----------------------------------------------------------------------------------------------
 *
 * XXX: This is an exact duplicate of lib/ncollide/src/partitioning/bvt_visitor.rs#RayInterferencesCollector
 * This does not compile cross-crate (ICE).
 *
 * ----------------------------------------------------------------------------------------------
 */
/// Bounding Volume Tree visitor collecting interferences with a given ray.
pub struct RayInterferencesCollector<'self, V, B> {
    priv ray:       &'self Ray<V>,
    priv collector: &'self mut ~[B]
}

impl<'self, V, B> RayInterferencesCollector<'self, V, B> {
    /// Creates a new `RayInterferencesCollector`.
    #[inline]
    pub fn new(ray:    &'self Ray<V>,
               buffer: &'self mut ~[B])
               -> RayInterferencesCollector<'self, V, B> {
        RayInterferencesCollector {
            ray:       ray,
            collector: buffer
        }
    }
}

impl<'self,
     N,
     V:  Vec<N>,
     B:  Clone,
     BV: RayCast<N, V>>
BVTVisitor<B, BV> for RayInterferencesCollector<'self, V, B> {
    #[inline]
    fn visit_internal(&mut self, bv: &BV) -> bool {
        bv.intersects_ray(self.ray)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &B, bv: &BV) {
        if bv.intersects_ray(self.ray) {
            self.collector.push(b.clone())
        }
    }
}
<|endoftext|>


<commit_before>use vecmath::*;

use shape::*;
use vec3d::*;
use light::*;
use color::*;

use std;

pub struct Scene {
    shapes: Vec<Box<Shape + Sync>>,
    light: Light,
    camera_pos: Vec3d,
    camera_dir: Vec3d,
    camera_up: Vec3d,
    max_reflection: i32,
}

impl Scene {
    pub fn new(light: Light, camera_pos: Vec3d, camera_dir: Vec3d, camera_up: Vec3d) -> Scene {
        Scene {
            shapes: Vec::new(),
            light: light,
            camera_pos: camera_pos,
            camera_dir: camera_dir,
            camera_up: camera_up,
            max_reflection: 4,
        }
    }

    pub fn add_shape(&mut self, s: Box<Shape + Sync>) {
        self.shapes.push(s);
    }

    pub fn step(&mut self) {
        // self.light.translate(&[1.0, 0.0, 0.0]);
    }

    pub fn mv_camera_fwd(&mut self) {
        self.camera_pos = vec3_add(self.camera_pos, self.camera_dir);
    }

    pub fn mv_camera_back(&mut self) {
        self.camera_pos = vec3_sub(self.camera_pos, self.camera_dir);
    }

    pub fn rot_camera(&mut self, x_rot: f64, y_rot: f64) {
        self.camera_dir = vec3_roty(self.camera_dir, x_rot);

        // project camera_dir to X plane
        let mut x_proj = self.camera_dir;
        x_proj[1] = 0.0;
        x_proj = vec3_normalized(x_proj);

        let angle = if x_proj[0] < 0.0 {
            -vec3_dot([0.0, 0.0, 1.0], x_proj).acos()
        } else {
            vec3_dot([0.0, 0.0, 1.0], x_proj).acos()
        };

        self.camera_dir = vec3_roty(self.camera_dir, -angle);
        self.camera_dir = vec3_rotx(self.camera_dir, y_rot);
        self.camera_dir = vec3_roty(self.camera_dir, angle);

        self.camera_dir = vec3_normalized(self.camera_dir);
    }

    /// Returns an iterator that scans a full frame at given resolution
    pub fn draw_iter(&self, h: usize, v: usize) -> DrawIter {
        DrawIter::new(self, h, v)
    }

    /// draw_iter converted to (u8, u8, u8)
    pub fn draw_iter_u8(&self,
                        h: usize,
                        v: usize)
                        -> std::iter::Map<DrawIter, fn(Color) -> (u8, u8, u8)> {
        self.draw_iter(h, v).map(Color::col_to_u8)
    }

    /// Returns an iterator for a line at given resolution
    pub fn line_iter(&self, h: usize, v: usize, l: usize) -> LineIter {
        LineIter::new(self, h, v, l)
    }

    /// line_iter converted to (u8, u8, u8)
    pub fn line_iter_u8(&self,
                        h: usize,
                        v: usize,
                        l: usize)
                        -> std::iter::Map<LineIter, fn(Color) -> (u8, u8, u8)> {
        self.line_iter(h, v, l).map(Color::col_to_u8)
    }

    // Recursively trace lines
    fn trace(&self, point: &Vec3d, dir: &Vec3d, depth: i32) -> Color {
        if depth >= self.max_reflection {
            return BLACK;
        }

        let intersect_res = self.closest_q(point, dir);
        if let Some(intersect) = intersect_res {
            let feeler_d = vec3_sub(*self.light.get_pos(), intersect.point);
            let dist_light = vec3_len(feeler_d);
            let feeler_d_unit = vec3_normalized(feeler_d);
            let direct_light = self.is_direct_light(&intersect.point, &feeler_d_unit, dist_light);

            let local = phong(point, &intersect, &self.light, direct_light);

            let tmp = vec3_normalized_sub(intersect.point, *point);
            let reflection_dir = vec3_normalized_sub(tmp,
                                                     vec3_scale(intersect.normal,
                                                                2.0 *
                                                                vec3_dot(tmp, intersect.normal)));

            let reflected = self.trace(&intersect.point, &reflection_dir, depth + 1);

            Color::add(&local,
                       &(Color::scale(&reflected, intersect.material.reflectivity)))
        } else {
            BLACK
        }
    }

    // Is there anything on the path to the light
    fn is_direct_light(&self, point: &Vec3d, dir: &Vec3d, dl: f64) -> bool {
        let unitd = vec3_normalized(*dir);
        !self.shapes
            .iter()
            .map(|&ref x| x.intersect_dist(point, &unitd))
            .any(|dist_opt| dist_opt.map(|i| i < dl).unwrap_or(false))
    }

    // Checks against all objects and returns closest intersection
    fn closest_q(&self, point: &Vec3d, dir: &Vec3d) -> Option<Intersection> {
        let unitd = vec3_normalized(*dir);

        let closest = self.shapes
            .iter()
            .map(|x| x.intersect_dist(point, &unitd))
            .enumerate()
            .fold(None, |min, (idx, dist_op)| {
                match (min, dist_op) {
                    (Some((_, dist_min)), Some(dist_val)) if dist_val < dist_min => {
                        Some((idx, dist_val))
                    }
                    (None, Some(dist_val)) => Some((idx, dist_val)),
                    _ => min,
                }
            });

        // get intersection point info
        if let Some((idx, _)) = closest {
            self.shapes[idx].intersect(point, dir)
        } else {
            None
        }
    }
}

/// Iterator that iterates over a full frame
pub struct DrawIter<'a> {
    h_res: usize,
    v_res: usize,
    x: usize,
    y: usize,
    left: Vec3d,
    right_step: Vec3d,
    down_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> DrawIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize) -> DrawIter {
        let left = vec3_normalized(vec3_cross(scene.camera_dir, scene.camera_up));
        let up = vec3_normalized(vec3_cross(left, scene.camera_dir));
        let point = vec3_add(vec3_add(left, up), scene.camera_dir);
        let right_step = vec3_scale(left, -2.0 / h as f64);
        let down_step = vec3_scale(up, -2.0 / v as f64);
        DrawIter {
            h_res: h,
            v_res: v,
            x: 0,
            y: 0,
            left: left,
            point: point,
            right_step: right_step,
            down_step: down_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for DrawIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.y >= self.v_res {
            return None;
        }

        self.point = vec3_add(self.point, self.right_step);

        let c = self.scene.trace(&self.scene.camera_pos, &vec3_normalized(self.point), 0);

        self.x += 1;
        if self.x >= self.h_res {
            self.x = 0;
            self.y += 1;
            self.point = vec3_add(self.point, self.left);
            self.point = vec3_add(self.point, self.left);
            self.point = vec3_add(self.point, self.down_step);
        }

        Some(c)
    }
}

/// Iterator that iterates over a single line
pub struct LineIter<'a> {
    h_res: usize,
    x: usize,
    right_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> LineIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize, l: usize) -> LineIter {
        let left = vec3_normalized(vec3_cross(scene.camera_dir, scene.camera_up));
        let up = vec3_normalized(vec3_cross(left, scene.camera_dir));
        let mut point = vec3_add(vec3_add(left, up), scene.camera_dir);
        let right_step = vec3_scale(left, -2.0 / h as f64);
        let down_step = vec3_scale(up, -2.0 / v as f64);

        point = vec3_add(point, vec3_scale(down_step, l as f64));
        LineIter {
            h_res: h,
            x: 0,
            point: point,
            right_step: right_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for LineIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.x >= self.h_res {
            return None;
        }
        self.x += 1;

        self.point = vec3_add(self.point, self.right_step);

        let c = self.scene.trace(&self.scene.camera_pos, &vec3_normalized(self.point), 0);

        Some(c)
    }
}

// Calculate color with Phong model
fn phong(view_point: &Vec3d,
         intersection: &Intersection,
         light: &Light,
         direct_light: bool)
         -> Color {

    let point_material = intersection.material;
    let light_pos = light.get_pos();
    let light_color = light.get_color();
    let mut d = vec3_dot(vec3_normalized_sub(*light_pos, intersection.point),
                         intersection.normal);

    if d < 0.0 {
        d = 0.0;
    }

    let r_diffuse = if direct_light {
        light_color.0 * point_material.diffuse_color.0 * d
    } else {
        0.0
    };
    let g_diffuse = if direct_light {
        light_color.1 * point_material.diffuse_color.1 * d
    } else {
        0.0
    };
    let b_diffuse = if direct_light {
        light_color.2 * point_material.diffuse_color.2 * d
    } else {
        0.0
    };

    let r_ambient = point_material.ambient_color.0;
    let g_ambient = point_material.ambient_color.1;
    let b_ambient = point_material.ambient_color.2;

    let v = vec3_normalized_sub(*view_point, intersection.point);
    let lt = vec3_normalized_sub(*light_pos, intersection.point);
    let r = vec3_normalized_sub(vec3_scale(intersection.normal,
                                           2.0 * vec3_dot(intersection.normal, lt)),
                                lt);

    let mut s = vec3_dot(r, v).powf(point_material.shininess);
    if s < 0.0 {
        s = 0.0;
    }

    let r_specular = if direct_light {
        light_color.0 * point_material.specular_color.0 * s
    } else {
        0.0
    };
    let g_specular = if direct_light {
        light_color.1 * point_material.specular_color.1 * s
    } else {
        0.0
    };
    let b_specular = if direct_light {
        light_color.2 * point_material.specular_color.2 * s
    } else {
        0.0
    };

    let mut r_sum = r_ambient + r_diffuse + r_specular;
    let mut g_sum = g_ambient + g_diffuse + g_specular;
    let mut b_sum = b_ambient + b_diffuse + b_specular;

    if r_sum > 1.0 {
        r_sum = 1.0;
    }

    if g_sum > 1.0 {
        g_sum = 1.0;
    }

    if b_sum > 1.0 {
        b_sum = 1.0;
    }

    Color(r_sum, g_sum, b_sum)
}
<commit_msg>Move generic min closure outside<commit_after>use vecmath::*;

use shape::*;
use vec3d::*;
use light::*;
use color::*;

use std;

pub struct Scene {
    shapes: Vec<Box<Shape + Sync>>,
    light: Light,
    camera_pos: Vec3d,
    camera_dir: Vec3d,
    camera_up: Vec3d,
    max_reflection: i32,
}

impl Scene {
    pub fn new(light: Light, camera_pos: Vec3d, camera_dir: Vec3d, camera_up: Vec3d) -> Scene {
        Scene {
            shapes: Vec::new(),
            light: light,
            camera_pos: camera_pos,
            camera_dir: camera_dir,
            camera_up: camera_up,
            max_reflection: 4,
        }
    }

    pub fn add_shape(&mut self, s: Box<Shape + Sync>) {
        self.shapes.push(s);
    }

    pub fn step(&mut self) {
        // self.light.translate(&[1.0, 0.0, 0.0]);
    }

    pub fn mv_camera_fwd(&mut self) {
        self.camera_pos = vec3_add(self.camera_pos, self.camera_dir);
    }

    pub fn mv_camera_back(&mut self) {
        self.camera_pos = vec3_sub(self.camera_pos, self.camera_dir);
    }

    pub fn rot_camera(&mut self, x_rot: f64, y_rot: f64) {
        self.camera_dir = vec3_roty(self.camera_dir, x_rot);

        // project camera_dir to X plane
        let mut x_proj = self.camera_dir;
        x_proj[1] = 0.0;
        x_proj = vec3_normalized(x_proj);

        let angle = if x_proj[0] < 0.0 {
            -vec3_dot([0.0, 0.0, 1.0], x_proj).acos()
        } else {
            vec3_dot([0.0, 0.0, 1.0], x_proj).acos()
        };

        self.camera_dir = vec3_roty(self.camera_dir, -angle);
        self.camera_dir = vec3_rotx(self.camera_dir, y_rot);
        self.camera_dir = vec3_roty(self.camera_dir, angle);

        self.camera_dir = vec3_normalized(self.camera_dir);
    }

    /// Returns an iterator that scans a full frame at given resolution
    pub fn draw_iter(&self, h: usize, v: usize) -> DrawIter {
        DrawIter::new(self, h, v)
    }

    /// draw_iter converted to (u8, u8, u8)
    pub fn draw_iter_u8(&self,
                        h: usize,
                        v: usize)
                        -> std::iter::Map<DrawIter, fn(Color) -> (u8, u8, u8)> {
        self.draw_iter(h, v).map(Color::col_to_u8)
    }

    /// Returns an iterator for a line at given resolution
    pub fn line_iter(&self, h: usize, v: usize, l: usize) -> LineIter {
        LineIter::new(self, h, v, l)
    }

    /// line_iter converted to (u8, u8, u8)
    pub fn line_iter_u8(&self,
                        h: usize,
                        v: usize,
                        l: usize)
                        -> std::iter::Map<LineIter, fn(Color) -> (u8, u8, u8)> {
        self.line_iter(h, v, l).map(Color::col_to_u8)
    }

    // Recursively trace lines
    fn trace(&self, point: &Vec3d, dir: &Vec3d, depth: i32) -> Color {
        if depth >= self.max_reflection {
            return BLACK;
        }

        let intersect_res = self.closest_q(point, dir);
        if let Some(intersect) = intersect_res {
            let feeler_d = vec3_sub(*self.light.get_pos(), intersect.point);
            let dist_light = vec3_len(feeler_d);
            let feeler_d_unit = vec3_normalized(feeler_d);
            let direct_light = self.is_direct_light(&intersect.point, &feeler_d_unit, dist_light);

            let local = phong(point, &intersect, &self.light, direct_light);

            let tmp = vec3_normalized_sub(intersect.point, *point);
            let reflection_dir = vec3_normalized_sub(tmp,
                                                     vec3_scale(intersect.normal,
                                                                2.0 *
                                                                vec3_dot(tmp, intersect.normal)));

            let reflected = self.trace(&intersect.point, &reflection_dir, depth + 1);

            Color::add(&local,
                       &(Color::scale(&reflected, intersect.material.reflectivity)))
        } else {
            BLACK
        }
    }

    // Is there anything on the path to the light
    fn is_direct_light(&self, point: &Vec3d, dir: &Vec3d, dl: f64) -> bool {
        let unitd = vec3_normalized(*dir);
        !self.shapes
            .iter()
            .map(|&ref x| x.intersect_dist(point, &unitd))
            .any(|dist_opt| dist_opt.map(|i| i < dl).unwrap_or(false))
    }

    // Checks against all objects and returns closest intersection
    fn closest_q(&self, point: &Vec3d, dir: &Vec3d) -> Option<Intersection> {
        let unitd = vec3_normalized(*dir);

        let find_min_opt = |min, (idx, op_val)| {
            match (min, op_val) {
                (Some((_, min_val)), Some(val)) if val < min_val => Some((idx, val)),
                (None, Some(val)) => Some((idx, val)),
                _ => min,
            }
        };

        let closest = self.shapes
            .iter()
            .map(|x| x.intersect_dist(point, &unitd))
            .enumerate()
            .fold(None, find_min_opt);

        // get intersection point info
        if let Some((idx, _)) = closest {
            self.shapes[idx].intersect(point, dir)
        } else {
            None
        }
    }
}

/// Iterator that iterates over a full frame
pub struct DrawIter<'a> {
    h_res: usize,
    v_res: usize,
    x: usize,
    y: usize,
    left: Vec3d,
    right_step: Vec3d,
    down_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> DrawIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize) -> DrawIter {
        let left = vec3_normalized(vec3_cross(scene.camera_dir, scene.camera_up));
        let up = vec3_normalized(vec3_cross(left, scene.camera_dir));
        let point = vec3_add(vec3_add(left, up), scene.camera_dir);
        let right_step = vec3_scale(left, -2.0 / h as f64);
        let down_step = vec3_scale(up, -2.0 / v as f64);
        DrawIter {
            h_res: h,
            v_res: v,
            x: 0,
            y: 0,
            left: left,
            point: point,
            right_step: right_step,
            down_step: down_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for DrawIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.y >= self.v_res {
            return None;
        }

        self.point = vec3_add(self.point, self.right_step);

        let c = self.scene.trace(&self.scene.camera_pos, &vec3_normalized(self.point), 0);

        self.x += 1;
        if self.x >= self.h_res {
            self.x = 0;
            self.y += 1;
            self.point = vec3_add(self.point, self.left);
            self.point = vec3_add(self.point, self.left);
            self.point = vec3_add(self.point, self.down_step);
        }

        Some(c)
    }
}

/// Iterator that iterates over a single line
pub struct LineIter<'a> {
    h_res: usize,
    x: usize,
    right_step: Vec3d,
    point: Vec3d,
    scene: &'a Scene,
}

impl<'a> LineIter<'a> {
    fn new(scene: &Scene, h: usize, v: usize, l: usize) -> LineIter {
        let left = vec3_normalized(vec3_cross(scene.camera_dir, scene.camera_up));
        let up = vec3_normalized(vec3_cross(left, scene.camera_dir));
        let mut point = vec3_add(vec3_add(left, up), scene.camera_dir);
        let right_step = vec3_scale(left, -2.0 / h as f64);
        let down_step = vec3_scale(up, -2.0 / v as f64);

        point = vec3_add(point, vec3_scale(down_step, l as f64));
        LineIter {
            h_res: h,
            x: 0,
            point: point,
            right_step: right_step,
            scene: scene,
        }
    }
}

impl<'a> Iterator for LineIter<'a> {
    type Item = Color;

    fn next(&mut self) -> Option<Self::Item> {
        if self.x >= self.h_res {
            return None;
        }
        self.x += 1;

        self.point = vec3_add(self.point, self.right_step);

        let c = self.scene.trace(&self.scene.camera_pos, &vec3_normalized(self.point), 0);

        Some(c)
    }
}

// Calculate color with Phong model
fn phong(view_point: &Vec3d,
         intersection: &Intersection,
         light: &Light,
         direct_light: bool)
         -> Color {

    let point_material = intersection.material;
    let light_pos = light.get_pos();
    let light_color = light.get_color();
    let mut d = vec3_dot(vec3_normalized_sub(*light_pos, intersection.point),
                         intersection.normal);

    if d < 0.0 {
        d = 0.0;
    }

    let r_diffuse = if direct_light {
        light_color.0 * point_material.diffuse_color.0 * d
    } else {
        0.0
    };
    let g_diffuse = if direct_light {
        light_color.1 * point_material.diffuse_color.1 * d
    } else {
        0.0
    };
    let b_diffuse = if direct_light {
        light_color.2 * point_material.diffuse_color.2 * d
    } else {
        0.0
    };

    let r_ambient = point_material.ambient_color.0;
    let g_ambient = point_material.ambient_color.1;
    let b_ambient = point_material.ambient_color.2;

    let v = vec3_normalized_sub(*view_point, intersection.point);
    let lt = vec3_normalized_sub(*light_pos, intersection.point);
    let r = vec3_normalized_sub(vec3_scale(intersection.normal,
                                           2.0 * vec3_dot(intersection.normal, lt)),
                                lt);

    let mut s = vec3_dot(r, v).powf(point_material.shininess);
    if s < 0.0 {
        s = 0.0;
    }

    let r_specular = if direct_light {
        light_color.0 * point_material.specular_color.0 * s
    } else {
        0.0
    };
    let g_specular = if direct_light {
        light_color.1 * point_material.specular_color.1 * s
    } else {
        0.0
    };
    let b_specular = if direct_light {
        light_color.2 * point_material.specular_color.2 * s
    } else {
        0.0
    };

    let mut r_sum = r_ambient + r_diffuse + r_specular;
    let mut g_sum = g_ambient + g_diffuse + g_specular;
    let mut b_sum = b_ambient + b_diffuse + b_specular;

    if r_sum > 1.0 {
        r_sum = 1.0;
    }

    if g_sum > 1.0 {
        g_sum = 1.0;
    }

    if b_sum > 1.0 {
        b_sum = 1.0;
    }

    Color(r_sum, g_sum, b_sum)
}
<|endoftext|>


<commit_before>//! Data structures that can be shared between the server and the client.
//!
//! All these structures should be serializable, so that they can be
//! transferred from the server to the client over the network.
use std::convert::Into;
use std::fmt;
use std::collections::HashMap;
use std::mem;

use shapes::Shape;

/// A unit identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub struct UnitId(pub u32);

impl Into<UnitId> for u32 {
    fn into(self) -> UnitId {
        UnitId(self)
    }
}

impl fmt::Display for UnitId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

/// A client/player identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)]
pub struct ClientId(pub u32);

impl Into<ClientId> for u32 {
    fn into(self) -> ClientId {
        ClientId(self)
    }
}

impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

pub const UNIT_SIZE: f64 = 50.0;

/// The state of a single unit
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Unit {
    /// The unit identifier
    pub id: UnitId,

    /// X/Y position in the world in m
    pub position: [f64; 2],

    /// Angle of the unit in radiant
    pub angle: f64,

    /// Direction and speed of the movement. The angle of the movement may be different then the
    /// angle of the unit. The unit is m per milli second.
    pub speed_vector: [f64; 2],

    /// Health of the unit
    pub health: u64,
}

impl Unit {
    pub fn new<T: Into<UnitId>>(id: T, position: [f64; 2]) -> Unit {
        println!("Create unit at {:?}", position);
        Unit {
            id: id.into(),
            position: position,
            angle: 0.0f64,
            speed_vector: [0.0f64, 0.0f64],
            health: 100_000,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }

    pub fn shoot(&self, size: f64, speed: f64) -> Bullet {
        let position = [
            self.position[0] + self.angle.cos() * size,
            self.position[1] + self.angle.sin() * size,
        ];
        let speed = [
            self.angle.cos() * speed,
            self.angle.sin() * speed,
        ];
        Bullet::new(position, speed)
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Bullet {
    pub position: [f64; 2],
    pub speed_vector: [f64; 2],
}

impl Bullet {
    pub fn new(position: [f64; 2], speed: [f64; 2]) -> Bullet {
        Bullet {
            position: position,
            speed_vector: speed,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }
}

/// A player has an ID and consists of 0..N `Unit`s
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Player {
    pub id: ClientId,
    pub units: Vec<Unit>,
}

impl Player {
    pub fn new<T: Into<ClientId>>(id: T) -> Player {
        Player {
            id: id.into(),
            units: vec![],
        }
    }
}

/// Data related to the current game.
///
/// This needs to be transferred to the client every time the game state
/// changes.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GameState {
    /// List of players
    pub players: Vec<Player>,
    pub bullets: Vec<Bullet>,
}

impl GameState {
    pub fn new() -> GameState {
        GameState{
            players: vec![],
            bullets: vec![],
        }
    }

    pub fn update_targets(&mut self, unit_targets: &HashMap<UnitId, [f64; 2]>) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter_mut() {
                if let Some(target) = unit_targets.get(&unit.id) {
                    let speed = 0.0001;
                    unit.speed_vector = [(target[0]-unit.position[0])*speed, (target[1]-unit.position[1])*speed];
                } else {
                    unit.speed_vector = [0.0,0.0];
                }
            }
        }
    }

    pub fn update(&mut self, world: &WorldState, dt: f64) {
        let mut bullets = mem::replace(&mut self.bullets, vec![]);
        'bullet: for bullet in bullets.iter_mut() {
            bullet.update(dt);
            // still inside world?
            if bullet.position[0] > world.x || bullet.position[1] > world.y ||
                bullet.position[0] < 0.0 || bullet.position[1] < 0.0 {
                    continue;
            }

            for player in self.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    if unit.health > 0 && unit.is_hit(UNIT_SIZE, bullet.position) {
                        if unit.health > 10000 {
                            unit.health -= 10000;
                        } else {
                            unit.health = 0;
                        }
                        println!("hit: {}", unit.health);
                        continue 'bullet;
                    }
                }
            }
            self.bullets.push(bullet.clone());
        }
        for player in self.players.iter_mut() {
            // remove units and add them back if still alive to avoid changing the vector while
            // iterating
            let mut units = mem::replace(&mut player.units, vec![]);
            for unit in units.iter_mut() {
                if unit.health > 0 {
                    unit.update(dt);
                    player.units.push(unit.clone());
                } else {
                    println!("killed unit!");
                }
            }
        }
    }

    pub fn shoot(&mut self, id: UnitId) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter() {
                if unit.id == id {
                    let bullet = unit.shoot(UNIT_SIZE, 0.1);
                    self.bullets.push(bullet);
                }
            }
        }
    }
}

/// Data related to the entire world, like width and height.
///
/// This needs to be transferred to the client only once, on connecting.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct WorldState {
    /// Width of the world in m
    pub x: f64,
    /// Height of the world in m
    pub y: f64,
}

impl WorldState {
    pub fn new(x: f64, y: f64) -> WorldState {
        WorldState {
            x: x,
            y: y,
        }
    }
}
<commit_msg>Use Vec::retain instead of mem::replace and loop<commit_after>//! Data structures that can be shared between the server and the client.
//!
//! All these structures should be serializable, so that they can be
//! transferred from the server to the client over the network.
use std::convert::Into;
use std::fmt;
use std::collections::HashMap;

use shapes::Shape;

/// A unit identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone, Hash)]
pub struct UnitId(pub u32);

impl Into<UnitId> for u32 {
    fn into(self) -> UnitId {
        UnitId(self)
    }
}

impl fmt::Display for UnitId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

/// A client/player identifier.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)]
pub struct ClientId(pub u32);

impl Into<ClientId> for u32 {
    fn into(self) -> ClientId {
        ClientId(self)
    }
}

impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

pub const UNIT_SIZE: f64 = 50.0;

/// The state of a single unit
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Unit {
    /// The unit identifier
    pub id: UnitId,

    /// X/Y position in the world in m
    pub position: [f64; 2],

    /// Angle of the unit in radiant
    pub angle: f64,

    /// Direction and speed of the movement. The angle of the movement may be different then the
    /// angle of the unit. The unit is m per milli second.
    pub speed_vector: [f64; 2],

    /// Health of the unit
    pub health: u64,
}

impl Unit {
    pub fn new<T: Into<UnitId>>(id: T, position: [f64; 2]) -> Unit {
        println!("Create unit at {:?}", position);
        Unit {
            id: id.into(),
            position: position,
            angle: 0.0f64,
            speed_vector: [0.0f64, 0.0f64],
            health: 100_000,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }

    pub fn shoot(&self, size: f64, speed: f64) -> Bullet {
        let position = [
            self.position[0] + self.angle.cos() * size,
            self.position[1] + self.angle.sin() * size,
        ];
        let speed = [
            self.angle.cos() * speed,
            self.angle.sin() * speed,
        ];
        Bullet::new(position, speed)
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Bullet {
    pub position: [f64; 2],
    pub speed_vector: [f64; 2],
}

impl Bullet {
    pub fn new(position: [f64; 2], speed: [f64; 2]) -> Bullet {
        Bullet {
            position: position,
            speed_vector: speed,
        }
    }

    pub fn update(&mut self, dt_ms: f64) {
        self.position[0] += self.speed_vector[0] * dt_ms;
        self.position[1] += self.speed_vector[1] * dt_ms;
    }
}

/// A player has an ID and consists of 0..N `Unit`s
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct Player {
    pub id: ClientId,
    pub units: Vec<Unit>,
}

impl Player {
    pub fn new<T: Into<ClientId>>(id: T) -> Player {
        Player {
            id: id.into(),
            units: vec![],
        }
    }
}

/// Data related to the current game.
///
/// This needs to be transferred to the client every time the game state
/// changes.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GameState {
    /// List of players
    pub players: Vec<Player>,
    pub bullets: Vec<Bullet>,
}

impl GameState {
    pub fn new() -> GameState {
        GameState{
            players: vec![],
            bullets: vec![],
        }
    }

    pub fn update_targets(&mut self, unit_targets: &HashMap<UnitId, [f64; 2]>) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter_mut() {
                if let Some(target) = unit_targets.get(&unit.id) {
                    let speed = 0.0001;
                    unit.speed_vector = [(target[0]-unit.position[0])*speed, (target[1]-unit.position[1])*speed];
                } else {
                    unit.speed_vector = [0.0,0.0];
                }
            }
        }
    }

    pub fn update(&mut self, world: &WorldState, dt: f64) {

        for bullet in self.bullets.iter_mut() {
            bullet.update(dt);
        }

        // waiting for non-lexical lifetimes...
        {
            let bullets = &mut self.bullets;
            let players = &mut self.players;
            bullets.retain(|bullet|{
                // still inside world?
                if bullet.position[0] > world.x || bullet.position[1] > world.y ||
                    bullet.position[0] < 0.0 || bullet.position[1] < 0.0 {
                        return false;
                    }

                for player in players.iter_mut() {
                    for unit in player.units.iter_mut() {
                        if unit.health > 0 && unit.is_hit(UNIT_SIZE, bullet.position) {
                            if unit.health > 10000 {
                                unit.health -= 10000;
                            } else {
                                unit.health = 0;
                            }
                            println!("hit: {}", unit.health);
                            return false;
                        }
                    }
                }
                true
            });
        }

        // remove all units where health == 0
        for player in self.players.iter_mut() {
            player.units.retain(|unit| unit.health > 0);
            for unit in player.units.iter_mut() {
                unit.update(dt);
            }
        }
    }

    pub fn shoot(&mut self, id: UnitId) {
        for player in self.players.iter_mut() {
            for unit in player.units.iter() {
                if unit.id == id {
                    let bullet = unit.shoot(UNIT_SIZE, 0.1);
                    self.bullets.push(bullet);
                }
            }
        }
    }
}

/// Data related to the entire world, like width and height.
///
/// This needs to be transferred to the client only once, on connecting.
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct WorldState {
    /// Width of the world in m
    pub x: f64,
    /// Height of the world in m
    pub y: f64,
}

impl WorldState {
    pub fn new(x: f64, y: f64) -> WorldState {
        WorldState {
            x: x,
            y: y,
        }
    }
}
<|endoftext|>


<commit_before>
use libc;
use std::mem;
use std::rc;
use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::{HashMap};

use mruby;
use class;
use class::{Class,HasClass};
use mruby::{mrb_open,mrb_close,mrb_state,mrb_value,Struct_RClass,Struct_mrbc_context};

pub type MrbState = Rc<RefCell<*mut mrb_state>>;
pub type MrbClass = Rc<RefCell<*mut Struct_RClass>>;

pub struct Mrb {
    mrb : MrbState,
    clzs : RefCell<HashMap<String,MrbClass>>
}

pub struct Context {
    mrb : MrbState,
    ctx : *mut Struct_mrbc_context
}

/// Traits for objects that has access to mrb_state.
/// Inspired by rust-hl-lua.
pub trait HasState {
    fn get_state(&self) -> *mut mrb_state;
}

impl HasState for Mrb {
    #[inline(always)]
    fn get_state(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }
}

impl HasState for Context {
    #[inline(always)]
    fn get_state(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }
}

impl Mrb {

    pub fn new() -> Mrb {
        let mrb = unsafe {
            mrb_open()
        };
        let state = mrb.clone();
        let clzs : RefCell<HashMap<String,MrbClass>> = RefCell::new(HashMap::new());
        let m = Mrb{ mrb:Rc::new(RefCell::new(mrb)),clzs:clzs };
        m.clzs.borrow_mut().insert(String::from_str("Object"),Rc::new(RefCell::new(unsafe {(*state).object_class} )));
        m.clzs.borrow_mut().insert(String::from_str("Class"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).class_class
                    })));
        m.clzs.borrow_mut().insert(String::from_str("String"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).string_class
                    })));
        m.clzs.borrow_mut().insert(String::from_str("Array"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).array_class
                    })));
        m.clzs.borrow_mut().insert(String::from_str("Hash"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).hash_class
                    })));
        unsafe { mem::forget(state); }
        m
    }

    pub fn close(&self) {
        if rc::is_unique(&self.mrb) {
            let state = self.get_state();
            unsafe {
                mrb_close(state);
            }
        }
    }

    pub fn get_class(&self,name:&str) -> Option<Class> {
        let mut h = self.clzs.borrow_mut();
        let clzname = String::from_str(name);
        if h.get(&clzname).is_some() {
            return Some(Class{mrb:self.mrb.clone(),clz:h.get(&clzname).unwrap().clone()});
        }
        let state = self.get_state().clone() ;
        let defined = unsafe {
            mruby::mrb_const_defined(self.get_state(),
                                                        mruby::wrap_mrb_obj_value((*state).object_class as *mut libc::c_void),
                                                        mruby::mrb_intern_cstr(self.get_state(),
                                                        name.as_ptr() as *const libc::c_char)) };
        let mclz = match defined {
            0 => unsafe {
                mruby::mrb_define_class(self.get_state(),
                                                  name.as_ptr() as *const libc::c_char,
                                                  (*state).object_class)
            },
            _ => unsafe {
                mruby::mrb_class_get(self.get_state(),
                                     name.as_ptr() as *const libc::c_char)
            }
        };

        unsafe { mem::forget(state); }
        if mclz.is_null() {
            None
        } else {
            let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(mclz))};
            h.insert(clzname,class.clz.clone());
            Some(class)
        }
    }

    pub fn load(&self,code:&str) -> mrb_value {
        unsafe {
            let state = self.get_state();
            mruby::mrb_load_string(state,code.as_ptr() as *const libc::c_char)
        }
    }

    pub fn load_str_ctx(&self,code:&str,ctx:&Context) -> mrb_value {
        unsafe {
            let state = self.get_state();
            mruby::mrb_load_string_cxt(state,
                                       code.as_ptr() as *const libc::c_char,
                                       ctx.ctx)
        }
    }

    pub fn def_class(&self,name:&str,outer:&str) -> Option<Class> {

        if self.clzs.borrow().get(&String::from_str(name)).is_some() {
            panic!("class defined before");
        }

        self.get_class(name)

    }

    pub fn def_mod(&self,name:&str) -> Option<Class> {

        if self.clzs.borrow().get(&String::from_str(name)).is_some() {
            panic!("module defined before");
        }

        let clz = unsafe {
            mruby::mrb_define_module(self.get_state(),
            name.as_ptr() as *const libc::c_char
            )
        };
        let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(clz))};
        let mut h = self.clzs.borrow_mut();
        h.insert(String::from_str(name),class.clz.clone());
        Some(class)

    }

    /*
    pub fn call(&self,v:&mrb_value,method:&str) {
        unsafe {
            mruby::mrb_funcall(self.get_state(),*v,
            method.as_ptr() as *const libc::c_char,0 as mrb_int);
        }
    }

    pub fn inspect(&self,v:&mrb_value) {
        self.call(v,"to_s");
    }
    */

    pub fn new_context(&self) -> Context {
        let ctx = unsafe { mruby::mrbc_context_new(self.get_state()) };
        Context { mrb:self.mrb.clone(),ctx:ctx }
    }

}

#[test]
fn test_mrb_open() {
    let m = Mrb::new();
    m.close();
}

#[test]
fn test_get_class() {
    let m = Mrb::new();
    let arr_clz = m.get_class("Array").unwrap();
    assert!(m.get_class("Class").is_some());
    assert!(m.get_class("Object").is_some());
    assert!(m.get_class("Hash").is_some());
    assert!(m.get_class("String").is_some());
    m.close();
    assert!(m.get_class("String").is_some());
    assert!(rc::strong_count(&arr_clz.mrb) == 2);
}

#[test]
fn test_obj_new() {
    let m = Mrb::new();
    let arr_clz = m.get_class("Array").unwrap();
    let v = arr_clz.new();
    assert!(!v.is_nil());
    m.close();
}

#[test]
fn test_load_str() {
    let m = Mrb::new();
    let mut v = m.load("1..3.each do |i| puts i end");
    assert!(v.is_nil());
    m.close();
}

#[test]
fn test_def_class() {
    let m = Mrb::new();
    let hello = m.def_class("Hello","Object");
    assert!(hello.is_some());
    m.close();
}

#[test]
fn test_def_mod() {
    let m = Mrb::new();
    let hello = m.def_mod("Hello");
    assert!(hello.is_some());
    m.close();
}
<commit_msg>fix mem leak in test with mrb_close<commit_after>
use libc;
use std::mem;
use std::rc;
use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::{HashMap};

use mruby;
use class;
use class::{Class,HasClass};
use mruby::{mrb_open,mrb_close,mrb_state,mrb_value,Struct_RClass,Struct_mrbc_context};

pub type MrbState = Rc<RefCell<*mut mrb_state>>;
pub type MrbClass = Rc<RefCell<*mut Struct_RClass>>;

pub struct Mrb {
    mrb : MrbState,
    clzs : RefCell<HashMap<String,MrbClass>>
}

pub struct Context {
    mrb : MrbState,
    ctx : *mut Struct_mrbc_context
}

/// Traits for objects that has access to mrb_state.
/// Inspired by rust-hl-lua.
pub trait HasState {
    fn get_state(&self) -> *mut mrb_state;
}

impl HasState for Mrb {
    #[inline(always)]
    fn get_state(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }
}

impl HasState for Context {
    #[inline(always)]
    fn get_state(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }
}

impl Mrb {

    pub fn new() -> Mrb {
        let mrb = unsafe {
            mrb_open()
        };
        let state = mrb.clone();
        let clzs : RefCell<HashMap<String,MrbClass>> = RefCell::new(HashMap::new());
        let m = Mrb{ mrb:Rc::new(RefCell::new(mrb)),clzs:clzs };
        m.clzs.borrow_mut().insert(String::from_str("Object"),Rc::new(RefCell::new(unsafe {(*state).object_class} )));
        m.clzs.borrow_mut().insert(String::from_str("Class"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).class_class
                    })));
        m.clzs.borrow_mut().insert(String::from_str("String"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).string_class
                    })));
        m.clzs.borrow_mut().insert(String::from_str("Array"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).array_class
                    })));
        m.clzs.borrow_mut().insert(String::from_str("Hash"),Rc::new(RefCell::new(
                    unsafe {
                    (*state).hash_class
                    })));
        unsafe { mem::forget(state); }
        m
    }

    pub fn close(&self) {
        if rc::is_unique(&self.mrb) {
            let state = self.get_state();
            unsafe {
                mrb_close(state);
            }
        }
    }

    pub fn get_class(&self,name:&str) -> Option<Class> {
        let mut h = self.clzs.borrow_mut();
        let clzname = String::from_str(name);
        if h.get(&clzname).is_some() {
            return Some(Class{mrb:self.mrb.clone(),clz:h.get(&clzname).unwrap().clone()});
        }
        let state = self.get_state().clone() ;
        let defined = unsafe {
            mruby::mrb_const_defined(self.get_state(),
                                                        mruby::wrap_mrb_obj_value((*state).object_class as *mut libc::c_void),
                                                        mruby::mrb_intern_cstr(self.get_state(),
                                                        name.as_ptr() as *const libc::c_char)) };
        let mclz = match defined {
            0 => unsafe {
                mruby::mrb_define_class(self.get_state(),
                                                  name.as_ptr() as *const libc::c_char,
                                                  (*state).object_class)
            },
            _ => unsafe {
                mruby::mrb_class_get(self.get_state(),
                                     name.as_ptr() as *const libc::c_char)
            }
        };

        unsafe { mem::forget(state); }
        if mclz.is_null() {
            None
        } else {
            let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(mclz))};
            h.insert(clzname,class.clz.clone());
            Some(class)
        }
    }

    pub fn load(&self,code:&str) -> mrb_value {
        unsafe {
            let state = self.get_state();
            mruby::mrb_load_string(state,code.as_ptr() as *const libc::c_char)
        }
    }

    pub fn load_str_ctx(&self,code:&str,ctx:&Context) -> mrb_value {
        unsafe {
            let state = self.get_state();
            mruby::mrb_load_string_cxt(state,
                                       code.as_ptr() as *const libc::c_char,
                                       ctx.ctx)
        }
    }

    pub fn def_class(&self,name:&str,outer:&str) -> Option<Class> {

        if self.clzs.borrow().get(&String::from_str(name)).is_some() {
            panic!("class defined before");
        }

        self.get_class(name)

    }

    pub fn def_mod(&self,name:&str) -> Option<Class> {

        if self.clzs.borrow().get(&String::from_str(name)).is_some() {
            panic!("module defined before");
        }

        let clz = unsafe {
            mruby::mrb_define_module(self.get_state(),
            name.as_ptr() as *const libc::c_char
            )
        };
        let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(clz))};
        let mut h = self.clzs.borrow_mut();
        h.insert(String::from_str(name),class.clz.clone());
        Some(class)

    }

    /*
    pub fn call(&self,v:&mrb_value,method:&str) {
        unsafe {
            mruby::mrb_funcall(self.get_state(),*v,
            method.as_ptr() as *const libc::c_char,0 as mrb_int);
        }
    }

    pub fn inspect(&self,v:&mrb_value) {
        self.call(v,"to_s");
    }
    */

    pub fn new_context(&self) -> Context {
        let ctx = unsafe { mruby::mrbc_context_new(self.get_state()) };
        Context { mrb:self.mrb.clone(),ctx:ctx }
    }

}

#[test]
fn test_mrb_open() {
    let m = Mrb::new();
    m.close();
}

#[test]
fn test_get_class() {
    let m = Mrb::new();
    {
        let arr_clz = m.get_class("Array").unwrap();
        assert!(m.get_class("Class").is_some());
        assert!(m.get_class("Object").is_some());
        assert!(m.get_class("Hash").is_some());
        assert!(m.get_class("String").is_some());
        assert!(m.get_class("String").is_some());
        assert!(rc::strong_count(&arr_clz.mrb) == 2);
    }
    m.close();
}

#[test]
fn test_obj_new() {
    let m = Mrb::new();
    {
        let arr_clz = m.get_class("Array").unwrap();
        let v = arr_clz.new();
        assert!(!v.is_nil());
    }
    m.close();
}

#[test]
fn test_load_str() {
    let m = Mrb::new();
    let mut v = m.load("a = 1;");
    m.close();
}

#[test]
fn test_def_class() {
    let m = Mrb::new();
    {
        let hello = m.def_class("Hello","Object");
        assert!(hello.is_some());
    }
    m.close();
}

#[test]
fn test_def_mod() {
    let m = Mrb::new();
    {
        let hello = m.def_mod("Hello");
        assert!(hello.is_some());
    }
    m.close();
}
<|endoftext|>


<commit_before>use std::cmp::Ord;
use rand;
use super::{QuickCheck, StdGen, TestResult, quickcheck};

#[test]
fn prop_oob() {
    fn prop() -> bool {
        let zero: Vec<bool> = vec![];
        zero[0]
    }
    match QuickCheck::new().quicktest(prop as fn() -> bool) {
        Ok(n) => panic!("prop_oob should fail with a runtime error \
                         but instead it passed {} tests.", n),
        _ => return,
    }
}

#[test]
fn prop_reverse_reverse() {
    fn prop(xs: Vec<usize>) -> bool {
        let rev: Vec<_> = xs.clone().into_iter().rev().collect();
        let revrev: Vec<_> = rev.into_iter().rev().collect();
        xs == revrev
    }
    quickcheck(prop as fn(Vec<usize>) -> bool);
}

#[test]
fn reverse_single() {
    fn prop(xs: Vec<usize>) -> TestResult {
        if xs.len() != 1 {
            return TestResult::discard()
        }
        return TestResult::from_bool(
            xs == xs.clone().into_iter().rev().collect::<Vec<_>>()
        )
    }
    quickcheck(prop as fn(Vec<usize>) -> TestResult);
}

#[test]
fn reverse_app() {
    fn prop(xs: Vec<usize>, ys: Vec<usize>) -> bool {
        let mut app = xs.clone();
        app.extend(ys.iter().cloned());
        let app_rev: Vec<usize> = app.into_iter().rev().collect();

        let rxs: Vec<usize> = xs.into_iter().rev().collect();
        let mut rev_app = ys.into_iter().rev().collect::<Vec<usize>>();
        rev_app.extend(rxs.into_iter());

        app_rev == rev_app
    }
    quickcheck(prop as fn(Vec<usize>, Vec<usize>) -> bool);
}

#[test]
fn max() {
    fn prop(x: isize, y: isize) -> TestResult {
        if x > y {
            TestResult::discard()
        } else {
            TestResult::from_bool(::std::cmp::max(x, y) == y)
        }
    }
    quickcheck(prop as fn(isize, isize) -> TestResult);
}

#[test]
fn sort() {
    fn prop(mut xs: Vec<isize>) -> bool {
        xs.sort_by(|x, y| x.cmp(y));
        let upto = if xs.len() == 0 { 0 } else { xs.len()-1 };
        for i in 0..upto {
            if xs[i] > xs[i+1] {
                return false
            }
        }
        true
    }
    quickcheck(prop as fn(Vec<isize>) -> bool);
}

fn sieve(n: usize) -> Vec<usize> {
    if n <= 1 {
        return vec![];
    }

    let mut marked = vec![false; n+1];
    marked[0] = true;
    marked[1] = true;
    marked[2] = true;
    for p in 2..n {
        for i in (2*p..n).filter(|&n| n % p == 0) {
            marked[i] = true;
        }
    }
    marked.iter()
          .enumerate()
          .filter_map(|(i, &m)| if m { None } else { Some(i) })
          .collect()
}

fn is_prime(n: usize) -> bool {
    n != 0 && n != 1 && (2..).take_while(|i| i*i <= n).all(|i| n % i != 0)
}

#[test]
#[should_panic]
fn sieve_not_prime() {
    fn prop_all_prime(n: usize) -> bool {
        sieve(n).into_iter().all(is_prime)
    }
    quickcheck(prop_all_prime as fn(usize) -> bool);
}

#[test]
#[should_panic]
fn sieve_not_all_primes() {
    fn prop_prime_iff_in_the_sieve(n: usize) -> bool {
        sieve(n) == (0..(n + 1)).filter(|&i| is_prime(i)).collect::<Vec<_>>()
    }
    quickcheck(prop_prime_iff_in_the_sieve as fn(usize) -> bool);
}

#[test]
fn testable_result() {
    fn result() -> Result<bool, String> { Ok(true) }
    quickcheck(result as fn() -> Result<bool, String>);
}

#[test]
#[should_panic]
fn testable_result_err() {
    quickcheck(Err::<bool, i32> as fn(i32) -> Result<bool, i32>);
}

#[test]
fn testable_unit() {
    fn do_nothing() {}
    quickcheck(do_nothing as fn());
}

#[test]
fn testable_unit_panic() {
    fn panic() { panic!() }
    assert!(QuickCheck::new().quicktest(panic as fn()).is_err());
}

#[test]
fn regression_issue_83() {
    fn prop(_: u8) -> bool { true }
    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 1024))
        .quickcheck(prop as fn(u8) -> bool)
}

#[test]
fn regression_issue_83_signed() {
    fn prop(_: i8) -> bool { true }
    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 1024))
        .quickcheck(prop as fn(i8) -> bool)
}

// Test that we can show the message after panic
#[test]
#[should_panic(expected = "foo")]
fn panic_msg_1() {
    fn prop() -> bool {
        panic!("foo");
    }
    quickcheck(prop as fn() -> bool);
}

#[test]
#[should_panic(expected = "foo")]
fn panic_msg_2() {
    fn prop() -> bool {
        assert!("foo" == "bar");
        true
    }
    quickcheck(prop as fn() -> bool);
}

#[test]
#[should_panic(expected = "foo")]
fn panic_msg_3() {
    fn prop() -> bool {
        assert_eq!("foo", "bar");
        true
    }
    quickcheck(prop as fn() -> bool);
}
<commit_msg>Add regression test for #107.<commit_after>use std::cmp::Ord;
use rand;
use super::{QuickCheck, StdGen, TestResult, quickcheck};

#[test]
fn prop_oob() {
    fn prop() -> bool {
        let zero: Vec<bool> = vec![];
        zero[0]
    }
    match QuickCheck::new().quicktest(prop as fn() -> bool) {
        Ok(n) => panic!("prop_oob should fail with a runtime error \
                         but instead it passed {} tests.", n),
        _ => return,
    }
}

#[test]
fn prop_reverse_reverse() {
    fn prop(xs: Vec<usize>) -> bool {
        let rev: Vec<_> = xs.clone().into_iter().rev().collect();
        let revrev: Vec<_> = rev.into_iter().rev().collect();
        xs == revrev
    }
    quickcheck(prop as fn(Vec<usize>) -> bool);
}

#[test]
fn reverse_single() {
    fn prop(xs: Vec<usize>) -> TestResult {
        if xs.len() != 1 {
            return TestResult::discard()
        }
        return TestResult::from_bool(
            xs == xs.clone().into_iter().rev().collect::<Vec<_>>()
        )
    }
    quickcheck(prop as fn(Vec<usize>) -> TestResult);
}

#[test]
fn reverse_app() {
    fn prop(xs: Vec<usize>, ys: Vec<usize>) -> bool {
        let mut app = xs.clone();
        app.extend(ys.iter().cloned());
        let app_rev: Vec<usize> = app.into_iter().rev().collect();

        let rxs: Vec<usize> = xs.into_iter().rev().collect();
        let mut rev_app = ys.into_iter().rev().collect::<Vec<usize>>();
        rev_app.extend(rxs.into_iter());

        app_rev == rev_app
    }
    quickcheck(prop as fn(Vec<usize>, Vec<usize>) -> bool);
}

#[test]
fn max() {
    fn prop(x: isize, y: isize) -> TestResult {
        if x > y {
            TestResult::discard()
        } else {
            TestResult::from_bool(::std::cmp::max(x, y) == y)
        }
    }
    quickcheck(prop as fn(isize, isize) -> TestResult);
}

#[test]
fn sort() {
    fn prop(mut xs: Vec<isize>) -> bool {
        xs.sort_by(|x, y| x.cmp(y));
        let upto = if xs.len() == 0 { 0 } else { xs.len()-1 };
        for i in 0..upto {
            if xs[i] > xs[i+1] {
                return false
            }
        }
        true
    }
    quickcheck(prop as fn(Vec<isize>) -> bool);
}

fn sieve(n: usize) -> Vec<usize> {
    if n <= 1 {
        return vec![];
    }

    let mut marked = vec![false; n+1];
    marked[0] = true;
    marked[1] = true;
    marked[2] = true;
    for p in 2..n {
        for i in (2*p..n).filter(|&n| n % p == 0) {
            marked[i] = true;
        }
    }
    marked.iter()
          .enumerate()
          .filter_map(|(i, &m)| if m { None } else { Some(i) })
          .collect()
}

fn is_prime(n: usize) -> bool {
    n != 0 && n != 1 && (2..).take_while(|i| i*i <= n).all(|i| n % i != 0)
}

#[test]
#[should_panic]
fn sieve_not_prime() {
    fn prop_all_prime(n: usize) -> bool {
        sieve(n).into_iter().all(is_prime)
    }
    quickcheck(prop_all_prime as fn(usize) -> bool);
}

#[test]
#[should_panic]
fn sieve_not_all_primes() {
    fn prop_prime_iff_in_the_sieve(n: usize) -> bool {
        sieve(n) == (0..(n + 1)).filter(|&i| is_prime(i)).collect::<Vec<_>>()
    }
    quickcheck(prop_prime_iff_in_the_sieve as fn(usize) -> bool);
}

#[test]
fn testable_result() {
    fn result() -> Result<bool, String> { Ok(true) }
    quickcheck(result as fn() -> Result<bool, String>);
}

#[test]
#[should_panic]
fn testable_result_err() {
    quickcheck(Err::<bool, i32> as fn(i32) -> Result<bool, i32>);
}

#[test]
fn testable_unit() {
    fn do_nothing() {}
    quickcheck(do_nothing as fn());
}

#[test]
fn testable_unit_panic() {
    fn panic() { panic!() }
    assert!(QuickCheck::new().quicktest(panic as fn()).is_err());
}

#[test]
fn regression_issue_83() {
    fn prop(_: u8) -> bool { true }
    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 1024))
        .quickcheck(prop as fn(u8) -> bool)
}

#[test]
fn regression_issue_83_signed() {
    fn prop(_: i8) -> bool { true }
    QuickCheck::new()
        .gen(StdGen::new(rand::thread_rng(), 1024))
        .quickcheck(prop as fn(i8) -> bool)
}

// Test that we can show the message after panic
#[test]
#[should_panic(expected = "foo")]
fn panic_msg_1() {
    fn prop() -> bool {
        panic!("foo");
    }
    quickcheck(prop as fn() -> bool);
}

#[test]
#[should_panic(expected = "foo")]
fn panic_msg_2() {
    fn prop() -> bool {
        assert!("foo" == "bar");
        true
    }
    quickcheck(prop as fn() -> bool);
}

#[test]
#[should_panic(expected = "foo")]
fn panic_msg_3() {
    fn prop() -> bool {
        assert_eq!("foo", "bar");
        true
    }
    quickcheck(prop as fn() -> bool);
}

#[test]
#[should_panic]
fn regression_issue_107_hang() {
    fn prop(a: Vec<u8>) -> bool {
        a.contains(&1)
    }
    quickcheck(prop as fn(_) -> bool);
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod rasterization {
    use cgmath::Point2;
    use rasterization::triangle;

    fn triangle_test(a: Point2<f32>, b: Point2<f32>, c: Point2<f32>, buffer_except: Vec<u32>) {
        let x_size: usize = 7;
        let y_size: usize = 5;
        let mut buffer: Vec<u32> = vec![0; x_size * y_size];
        triangle(&mut buffer, x_size, y_size, a, b, c, 1);

        println!("");
        println!("real: ");
        for y in (0..y_size) {
            print!("   ");
            for x in (0..x_size) {
                print!("{}",if buffer[(y_size - y - 1) * x_size + x]==0 {0} else {1});
            }
            println!("");
        }
        println!("except: ");
        for y in (0..y_size) {
            print!("   ");
            for x in (0..x_size) {
                print!("{}",if buffer_except[y * x_size + x]==0 {0} else {1});
            }
            println!("");
        }
        for y in 0..y_size {
            for x in 0..x_size {
                let val_real = buffer[y * x_size + x];
                let val_except = buffer_except[(y_size - y - 1) * x_size + x];
                debug_assert!((val_real==0) == (val_except==0),
                              "real = {}, except = {}, x = {} y = {}",
                              val_real, val_except, x, y);
            }
        }
    }

    #[test]
    fn triangle_00() {
        triangle_test(Point2::new(1.0,4.0), Point2::new(2.0,1.0), Point2::new(6.0,3.0),
                      vec![0,0,0,0,0,0,0,
                           0,1,1,0,0,0,0,
                           0,1,1,1,1,0,0,
                           0,0,1,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_01() {
        triangle_test(Point2::new(1.4,1.6), Point2::new(2.4,1.6), Point2::new(2.4,2.6),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_02() {
        triangle_test(Point2::new(3.5,1.5), Point2::new(4.5,1.5), Point2::new(4.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_03() {
        triangle_test(Point2::new(2.5,2.5), Point2::new(2.5,2.5), Point2::new(2.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_04() {
        triangle_test(Point2::new(0.0,0.0), Point2::new(4.0,0.0), Point2::new(6.0,2.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,1,0,0,
                           0,1,1,1,0,0,0]);
    }

    #[test]
    fn triangle_05() {
        triangle_test(Point2::new(1.0,2.0), Point2::new(4.0,1.0), Point2::new(3.0,4.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,1,0,0,0,0,
                           0,1,1,0,0,0,0,
                           0,0,1,1,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_06() {
        triangle_test(Point2::new(5.5,2.5), Point2::new(4.0,1.0), Point2::new(3.0,4.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,1,0,0,0,
                           0,0,0,1,1,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_07() {
        triangle_test(Point2::new(1.5,0.5), Point2::new(2.5,0.5), Point2::new(1.5,-2.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,1,0,0,0,0,0]);
    }

    #[test]
    fn triangle_08() {
        triangle_test(Point2::new(0.7,3.5), Point2::new(2.5,0.7), Point2::new(4.6,3.5),
                      vec![0,0,0,0,0,0,0,
                           0,1,1,1,1,0,0,
                           0,1,1,1,0,0,0,
                           0,0,1,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_09() {
        triangle_test(Point2::new(0.7,1.5), Point2::new(2.7,3.2), Point2::new(4.7,1.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,1,1,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_10() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(0.5,2.5), Point2::new(1.5,1.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_11() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(0.5,2.5), Point2::new(2.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,1,0,0,0,0,0,
                           1,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_12() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(2.5,2.5), Point2::new(2.5,0.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,1,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_13() {
        triangle_test(Point2::new(0.5,3.5), Point2::new(1.5,2.5), Point2::new(1.5,0.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_14() {
        triangle_test(Point2::new(0.5,3.5), Point2::new(1.5,2.5), Point2::new(2.0,5.0),
                      vec![0,1,0,0,0,0,0,
                           1,1,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_15() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(2.5,0.5), Point2::new(0.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_16() {
        triangle_test(Point2::new(2.5,2.5), Point2::new(2.5,0.5), Point2::new(0.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,1,0,0,0,0,0,
                           0,1,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_17() {
        triangle_test(Point2::new(5.0,2.0), Point2::new(5.0,-2.0), Point2::new(10.0,2.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,1,1,
                           0,0,0,0,0,1,1]);
    }

    #[test]
    fn triangle_18() {
        triangle_test(Point2::new(5.0,3.0), Point2::new(5.0,10.0), Point2::new(10.0,3.0),
                      vec![0,0,0,0,0,1,1,
                           0,0,0,0,0,1,1,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }
}
<commit_msg>fix tests<commit_after>
#[cfg(test)]
mod rasterization {
    use cgmath::{Point2, Point3, Vector3};
    use rasterization::triangle;
    use shader::Shader;

    fn triangle_test(a_screen: Point2<f32>, b_screen: Point2<f32>, c_screen: Point2<f32>, buffer_except: Vec<u32>) {
        let a = Point3::new(a_screen.x, a_screen.y, 0.5_f32);
        let b = Point3::new(b_screen.x, b_screen.y, 0.5_f32);
        let c = Point3::new(c_screen.x, c_screen.y, 0.5_f32);
        let x_size: usize = 7;
        let y_size: usize = 5;
        let mut cbuffer: Vec<u32> = vec![0; x_size * y_size];
        let mut zbuffer: Vec<f32> = vec![0.0_f32; x_size * y_size];
        let shader = Shader::new(Vector3::new(100.0_f32, 100.0_f32, 100.0_f32), 0.3_f32);
        triangle(&mut cbuffer, &mut zbuffer, x_size, y_size, a, b, c, &shader);

        println!("");
        println!("real: ");
        for y in (0..y_size) {
            print!("   ");
            for x in (0..x_size) {
                print!("{}",if cbuffer[(y_size - y - 1) * x_size + x]==0 {0} else {1});
            }
            println!("");
        }
        println!("except: ");
        for y in (0..y_size) {
            print!("   ");
            for x in (0..x_size) {
                print!("{}",if buffer_except[y * x_size + x]==0 {0} else {1});
            }
            println!("");
        }
        for y in 0..y_size {
            for x in 0..x_size {
                let val_real = cbuffer[y * x_size + x];
                let val_except = buffer_except[(y_size - y - 1) * x_size + x];
                debug_assert!((val_real==0) == (val_except==0),
                              "real = {}, except = {}, x = {} y = {}",
                              val_real, val_except, x, y);
            }
        }
    }

    #[test]
    fn triangle_00() {
        triangle_test(Point2::new(1.0,4.0), Point2::new(2.0,1.0), Point2::new(6.0,3.0),
                      vec![0,0,0,0,0,0,0,
                           0,1,1,0,0,0,0,
                           0,1,1,1,1,0,0,
                           0,0,1,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_01() {
        triangle_test(Point2::new(1.4,1.6), Point2::new(2.4,1.6), Point2::new(2.4,2.6),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_02() {
        triangle_test(Point2::new(3.5,1.5), Point2::new(4.5,1.5), Point2::new(4.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_03() {
        triangle_test(Point2::new(2.5,2.5), Point2::new(2.5,2.5), Point2::new(2.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_04() {
        triangle_test(Point2::new(0.0,0.0), Point2::new(4.0,0.0), Point2::new(6.0,2.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,1,0,0,
                           0,1,1,1,0,0,0]);
    }

    #[test]
    fn triangle_05() {
        triangle_test(Point2::new(1.0,2.0), Point2::new(4.0,1.0), Point2::new(3.0,4.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,1,0,0,0,0,
                           0,1,1,0,0,0,0,
                           0,0,1,1,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_06() {
        triangle_test(Point2::new(5.5,2.5), Point2::new(4.0,1.0), Point2::new(3.0,4.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,1,0,0,0,
                           0,0,0,1,1,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_07() {
        triangle_test(Point2::new(1.5,0.5), Point2::new(2.5,0.5), Point2::new(1.5,-2.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,1,0,0,0,0,0]);
    }

    #[test]
    fn triangle_08() {
        triangle_test(Point2::new(0.7,3.5), Point2::new(2.5,0.7), Point2::new(4.6,3.5),
                      vec![0,0,0,0,0,0,0,
                           0,1,1,1,1,0,0,
                           0,1,1,1,0,0,0,
                           0,0,1,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_09() {
        triangle_test(Point2::new(0.7,1.5), Point2::new(2.7,3.2), Point2::new(4.7,1.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,1,1,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_10() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(0.5,2.5), Point2::new(1.5,1.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_11() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(0.5,2.5), Point2::new(2.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,1,0,0,0,0,0,
                           1,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_12() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(2.5,2.5), Point2::new(2.5,0.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,1,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_13() {
        triangle_test(Point2::new(0.5,3.5), Point2::new(1.5,2.5), Point2::new(1.5,0.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_14() {
        triangle_test(Point2::new(0.5,3.5), Point2::new(1.5,2.5), Point2::new(2.0,5.0),
                      vec![0,1,0,0,0,0,0,
                           1,1,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_15() {
        triangle_test(Point2::new(0.5,0.5), Point2::new(2.5,0.5), Point2::new(0.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_16() {
        triangle_test(Point2::new(2.5,2.5), Point2::new(2.5,0.5), Point2::new(0.5,2.5),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           1,1,0,0,0,0,0,
                           0,1,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }

    #[test]
    fn triangle_17() {
        triangle_test(Point2::new(5.0,2.0), Point2::new(5.0,-2.0), Point2::new(10.0,2.0),
                      vec![0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,1,1,
                           0,0,0,0,0,1,1]);
    }

    #[test]
    fn triangle_18() {
        triangle_test(Point2::new(5.0,3.0), Point2::new(5.0,10.0), Point2::new(10.0,3.0),
                      vec![0,0,0,0,0,1,1,
                           0,0,0,0,0,1,1,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0,
                           0,0,0,0,0,0,0]);
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use forecast::Icon;

#[derive(Debug)]
pub enum Theme {
    Light,
    Dark,
}

impl Theme {
    pub fn icon_path(&self, icon: &Icon) -> Option<PathBuf> {
        match *icon {
            Icon::ClearDay => Some("Sun"),
            Icon::ClearNight => Some("Moon"),
            Icon::Rain => Some("Cloud-Rain"),
            Icon::Snow => Some("Cloud-Snow"),
            Icon::Sleet => Some("Cloud-Snow-Alt"),
            Icon::Wind => Some("Wind"),
            Icon::Fog => Some("Cloud-Fog"),
            Icon::Cloudy => Some("Cloud"),
            Icon::PartlyCloudyDay => Some("Cloud-Sun"),
            Icon::PartlyCloudyNight => Some("Cloud-Moon"),
            Icon::Unknown(_) => None,
        }.map(|x| {
            let theme = match *self {
                Theme::Light => "Light",
                Theme::Dark => "Dark",
            };
            format!("{}-{}", theme, x).into()
        })
    }
}
<commit_msg>Fix icon path<commit_after>use std::path::PathBuf;

use forecast::Icon;

#[derive(Debug)]
pub enum Theme {
    Light,
    Dark,
}

impl Theme {
    pub fn icon_path(&self, icon: &Icon) -> Option<PathBuf> {
        match *icon {
            Icon::ClearDay => Some("Sun"),
            Icon::ClearNight => Some("Moon"),
            Icon::Rain => Some("Cloud-Rain"),
            Icon::Snow => Some("Cloud-Snow"),
            Icon::Sleet => Some("Cloud-Snow-Alt"),
            Icon::Wind => Some("Wind"),
            Icon::Fog => Some("Cloud-Fog"),
            Icon::Cloudy => Some("Cloud"),
            Icon::PartlyCloudyDay => Some("Cloud-Sun"),
            Icon::PartlyCloudyNight => Some("Cloud-Moon"),
            Icon::Unknown(_) => None,
        }.map(|x| {
            let theme = match *self {
                Theme::Light => "Light",
                Theme::Dark => "Dark",
            };
            format!("icons/{}-{}.png", theme, x).into()
        })
    }
}
<|endoftext|>