示例#1
0
/*
 * Returns the normal vector of a cone on a given position. The vector is
 * already normalized.
 *
 * posn: Position at which the intersection occured
 * cone_ptr: Pointer to a cone figure.
 */
Vector get_cone_normal_vector(Vector posn, void* cone_ptr)
{
	Cone cone = *((Cone*) cone_ptr);
	Vector border, normal_vec;
	border = subtract_vectors(posn, cone.anchor);
	long double distance = normalize_vector(&border);
	if(do_dot_product(border, cone.direction) < 0)
		distance *= -1;
	normal_vec = multiply_vector(1.0/ fabsl(distance), subtract_vectors(posn, get_ray_position(cone.anchor, cone.direction, distance * sqrt(2))));
	normalize_vector(&normal_vec);
	return normal_vec;
}
示例#2
0
static void dye_fun(double const coords[3], double* v)
{
  double x[3];
  double const l[3] = {.25, .5, 0};
  double const r[3] = {.75, .5, 0};
  double dir = 1;
  subtract_vectors(coords, l, x, 3);
  if (vector_norm(x, 3) > .25) {
    dir = -1;
    subtract_vectors(coords, r, x, 3);
  }
  if (vector_norm(x, 3) > .25) {
    v[0] = 0;
    return;
  }
  v[0] = 4 * dir * (.25 - vector_norm(x, 3));
}
示例#3
0
static void warp_fun(double const* coords, double* v)
{
  double x[3];
  double const mid[3] = {.5, .5, 0};
  subtract_vectors(coords, mid, x, 3);
  double polar_a = atan2(x[1], x[0]);
  double polar_r = vector_norm(x, 3);
  double rot_a = 0;
  if (polar_r < .5)
    rot_a = the_rotation * (2 * (.5 - polar_r));
  double dest_a = polar_a + rot_a;
  double dst[3];
  dst[0] = cos(dest_a) * polar_r;
  dst[1] = sin(dest_a) * polar_r;
  dst[2] = 0;
  subtract_vectors(dst, x, v, 3);
}
示例#4
0
/*
 * Returns a pointer to the intersection between a cone and a ray.
 *
 * eye: Position from which the ray is thrown.
 * dir_vec: Direction towards which the ray is thrown. Must be normalized.
 * object_ptr: Pointer to the Object struct that represents the cone.
 * length: Output parameter for the number of intersections found.
 */
void* get_cone_intersection(Vector eye, Vector dir_vec, void* object_ptr, int *length)
{
	Cone* cone_ptr =  (Cone*) ((Object*)object_ptr)->figure;
	long double termQD, termQE;
	Vector varD, varE, anchor_to_anchor;
	anchor_to_anchor = subtract_vectors(eye, cone_ptr->anchor);

	termQD = do_dot_product(cone_ptr->direction, dir_vec);
	termQE = do_dot_product(cone_ptr->direction, anchor_to_anchor);

	varD = subtract_vectors(multiply_vector(termQD, cone_ptr->direction), dir_vec);
	varE = get_ray_position(cone_ptr->anchor, subtract_vectors(multiply_vector(termQE, cone_ptr->direction), eye), 1);

	long double a = pow(varD.x, 2) + pow(varD.y, 2) + pow(varD.z, 2) - pow(cone_ptr->radius, 2) * pow(termQD, 2);
	long double b = 2 * (do_dot_product(varE, varD) - pow(cone_ptr->radius, 2) * termQD * termQE);
	long double c = pow(varE.x, 2) + pow(varE.y, 2) + pow(varE.z, 2) - pow(cone_ptr->radius, 2) * pow(termQE, 2);

	return get_cyl_cone_intersection(a, b, c, eye, dir_vec, object_ptr, length);
}
示例#5
0
文件: shading.c 项目: tenyoung795/mdl
void calculate_intensity(struct vector *c,
			 struct constants *k,
			 color ambient,
			 struct light *light,
			 struct vector *p,
			 struct vector *n,
			 struct vector *v) {
  /* I = Ke + Ia Ka + Ip Kd (->L * ->N) + Ip Ks [(2->N(->L * ->N)- ->L) * ->V] */
  double dotd, dots;
  struct vector l, tmp;

  l = *p;
  subtract_vectors(&l, &light->l);
  normalize(&l);

  dotd = dot(&l, n);
  if (dotd < 0) {
    dotd = dots = 0;
    goto add_terms;
  }
    
  tmp = *n;
  scalar_mult(2 * dotd, &tmp);
  subtract_vectors(&tmp, &l);
  dots = dot(&tmp, v);
  if (dots < 0)
    dots = 0;

 add_terms:
  ctov(c, k->e);

  ctov(&tmp, ambient);
  tmp.x *= k->r[Ka];
  tmp.y *= k->g[Ka];
  tmp.z *= k->b[Ka];
  add_vectors(c, &tmp);

  ctov(&tmp, light->c);
  tmp.x *= k->r[Kd] * dotd + k->r[Ks] * dots;
  tmp.y *= k->g[Kd] * dotd + k->g[Kd] * dots;
  tmp.z *= k->b[Kd] * dotd + k->b[Ks] * dots;
  add_vectors(c, &tmp);
}
示例#6
0
roots intersection_with_ray(sphere s, ray r)
{
	// We need r in sphere-coordinates

	ray r_sphere_coordinates;
	matrix s_transform_inverse = inverse_of_matrix(s.transform);
	r_sphere_coordinates.point     = transform_point(s_transform_inverse, r.point);
	r_sphere_coordinates.direction = transform_ray(s_transform_inverse, r.direction);

	vector point_minus_center = subtract_vectors(r_sphere_coordinates.point, s.center);

	float polynomials[3];

	polynomials[2] = square_of_magnitude_of_vector(r_sphere_coordinates.direction);
	polynomials[1] = 2 * dot_product(point_minus_center, r_sphere_coordinates.direction);
	polynomials[0] = square_of_magnitude_of_vector(point_minus_center) - s.radius * s.radius;

	roots quad_roots;

	quad_roots = quadratic(polynomials[2], polynomials[1], polynomials[0]);

	return quad_roots;
}
示例#7
0
/*
 * Adds the effect of the given light over the given intersection.
 *
 * light: Light that is being applied.
 * inter: Intersection over which the light is being applied.
 * normal_vec:  Normal vector of the intersection point. It is passed by as a
 *              parameter for optimization purposes.
 * rev_dir_vec: Reverse vector of the direction of the ray that comes from the
 *              eye. It is passed by as a parameter for optimization purposes.
 * all_lights_color: Accumulated amount of light sources effect. The effect of
 *              the given light is added to this total.
 * all_lights_color: Accumulated amount of the specular light effect. The
 *              specular effect of the given light is added to this total.
 * conf: Configuration of the scene.
 */
void apply_light_source(Light light,
                        Intersection inter,
                        Vector normal_vec,
                        Vector rev_dir_vec,
                        Color *all_lights_color,
                        long double *all_spec_light,
                        SceneConfig conf)
{
    Vector light_vec;
    long double light_distance, illum_cos, att_factor, spec_cos;
    Color light_filter;
    Intersection* shadow_inter;
    int shadow_i, shadow_inter_length;
    Object shadow_obj;

    // Find the vector that points from the intersection point to the light
    // source, and normalize it
    light_vec = subtract_vectors(light.anchor, inter.posn);
    light_distance = normalize_vector(&light_vec);
    // We check for any object making a shadow from that light
    light_filter = (Color){ .red = 1.0, .green = 1.0, .blue = 1.0 };;
    shadow_inter = get_intersections(inter.posn, light_vec, &shadow_inter_length, conf);
    // If the intersection is beyond the light source, we ignore it
    if(shadow_inter)
    {   // Object(s) is/are actually behind the light
        for(shadow_i = 0; shadow_i < shadow_inter_length && !is_color_empty(light_filter); shadow_i++)
        {
            if(shadow_inter[shadow_i].distance < light_distance)
            {
                shadow_obj = shadow_inter[shadow_i].obj;
                if(shadow_obj.translucency_material)
                {
                    light_filter = multiply_color(shadow_obj.translucency_material, multiply_colors(light_filter, shadow_obj.color));
                }
                else
                {
                    light_filter = get_empty_color();
                }
            }

        }
        if(!is_color_empty(light_filter))
        {
            free(shadow_inter);
            shadow_inter = NULL;
        }
    }
    // If there aren't any shadows
    if(!shadow_inter)
    {
        illum_cos = do_dot_product(normal_vec, light_vec);
        // We only take it into account if the angle is lower than 90 degrees
        if(illum_cos > 0)
        {
            Vector light_mirror_vec = subtract_vectors(multiply_vector(2 * illum_cos, normal_vec), light_vec);
            // Attenuation factor, reduces the light energy depending on the distance
            att_factor = get_attenuation_factor(light, light_distance);
            spec_cos = do_dot_product(rev_dir_vec, light_mirror_vec);
            // We add the light source effect
            light_filter = multiply_color(illum_cos * inter.obj.light_material * att_factor, light_filter);
            *all_lights_color = add_colors(*all_lights_color, multiply_colors(light_filter, light.color));
            // The specular light, is the white stain on the objects
            if(spec_cos > 0)
            {
                *all_spec_light += pow(spec_cos * inter.obj.specular_material * att_factor, inter.obj.specular_pow);
            }
        }
    }
    else free(shadow_inter);
}

/*
 * Gets the color of the intersection by calculating light intensity,
 * (which includes specular light, shadows, transparency, etc)
 *
 * light: Light for which the attenuation factor is calculated.
 * distance: Distance between the light and an illuminated spot.
 * mirror_level: Current level of reflection.
 * conf: Configuration of the scene.
 */
Color get_intersection_color(Vector eye,
                             Vector dir_vec,
                             Intersection *inter_list,
                             int inter_length,
                             int mirror_level,
                             int transparency_level,
                             SceneConfig conf)
{
    Intersection inter;
    int light_index;
    long double spec_light_factor, mirror_factor, transparency_factor;
    Vector normal_vec, rev_dir_vec, reflection_vec;
    Light light;
    Color all_lights_color, color_found, reflection_color,
          transparency_color, final_color;

    inter = inter_list[transparency_level];
    // Light intensity
    all_lights_color = (Color){ .red = 0.0, .green = 0.0, .blue = 0.0 };
    // Specular light intensity
    spec_light_factor = 0.0;
    normal_vec = get_normal_vector(&inter);
    // Pick up the normal vector that is pointing to the eye
    if(do_dot_product(normal_vec, dir_vec) > 0)
        normal_vec = multiply_vector(-1, normal_vec);
    // Initialize reverse direction vector for mirrors and specular light
    rev_dir_vec = multiply_vector(-1, dir_vec);
    for(light_index = 0; light_index < conf.lights_length; light_index++)
    {
        light = conf.lights[light_index];
        apply_light_source(light, inter, normal_vec, rev_dir_vec, &all_lights_color, &spec_light_factor, conf);
    }
    // We add the environmental light of the scene
    all_lights_color = add_colors(all_lights_color, multiply_color(inter.obj.light_ambiental, conf.environment_light));
    if(spec_light_factor > 1.0)
        spec_light_factor = 1.0;
    color_found = multiply_colors(all_lights_color, inter.obj.color);
    // Specular light gives a color between enlightened color and the light color.
    color_found.red += (1 - color_found.red) * spec_light_factor;
    color_found.green += (1 - color_found.green) * spec_light_factor;
    color_found.blue += (1 - color_found.blue) * spec_light_factor;
    // Get transparency color
    transparency_factor = inter.obj.transparency_material;
    if (transparency_level < conf.max_transparency_level &&
        transparency_factor > 0.0)
    {
        if(transparency_level + 1 < inter_length)
        {
            transparency_color = get_intersection_color(eye,dir_vec,inter_list,inter_length,0,transparency_level+1, conf);
        }
        else
        {
            transparency_color = conf.background;
        }
    }
    else
    {
        transparency_factor = 0.0;
        transparency_color = get_empty_color();
    }
    // Get reflection color
    mirror_factor = inter.obj.mirror_material;
    if (mirror_level < conf.max_mirror_level &&
        mirror_factor > 0.0)
    {
        reflection_vec = subtract_vectors(multiply_vector(2 * do_dot_product(normal_vec, rev_dir_vec), normal_vec), rev_dir_vec);
        reflection_color = get_color(inter.posn, reflection_vec, mirror_level + 1, conf);
    }
    else
    {
        mirror_factor = 0;
        reflection_color = get_empty_color();
    }
    // Calculate final color
    transparency_color = multiply_color(transparency_factor, transparency_color);
    reflection_color = multiply_color((1.0-transparency_factor) * mirror_factor, reflection_color);
    color_found = multiply_color((1.0-transparency_factor) * (1.0-mirror_factor), color_found);
    final_color = add_colors(transparency_color, add_colors(reflection_color, color_found));
    return final_color;
}

/*
 * Returns the color that is seen from the position 'eye' when looking at the
 * tridimensional scene towards the direction 'dir_vec'.
 *
 * eye: Position from which the scene is seen.
 * dir_vec: Direction at which the eye is looking. This vector must be normalized.
 * mirror_level: Current level of reflection.
 * conf: Configuration of the scene.
 */
Color get_color(Vector eye, Vector dir_vec, int mirror_level, SceneConfig conf)
{
	Intersection *inter_list;
	Color color;
	// Get intersections on the given direction. Intersections are ordered from the nearest to the farthest.
	int inter_list_length;
	inter_list = get_intersections(eye, dir_vec, &inter_list_length, conf);
	// If we don't find an intersection we return the background, otherwise we check for the intersections's color.
	if (!inter_list) return conf.background;
	color = get_intersection_color(eye, dir_vec, inter_list, inter_list_length, mirror_level, 0, conf);
	free(inter_list);
	return color;
}
示例#8
0
文件: shading.c 项目: tenyoung795/mdl
void horizontal_convert(polygon poly,
			struct screen *s,
			enum shading_t type,
			struct constants *k,
			color ambient,
			struct light *l,
			struct vector norm[3],
			struct vector *v) {
  const double
    y0 = poly[0]->y,
    y1 = poly[1]->y,
    y2 = poly[2]->y;

  int ib, im, it;
  int dy_bt, dy_bm, dy_mt;
  double dx;

  struct vector pb, pm, pt;
  struct vector dp_dy_bt, dp_dy_bm, dp_dy_mt;
  struct vector p0, p1;
  edge e = {&p0, &p1};
  struct vector p;
  double dz_dx;

  struct vector cb, cm, ct;
  struct vector dc_dy_bt, dc_dy_bm, dc_dy_mt;
  struct vector c0, c1;
  struct vector c;
  struct vector dc_dx;

  struct vector dn_dy_bt, dn_dy_bm, dn_dy_mt;
  struct vector n0, n1;
  struct vector n;
  struct vector dn_dx;

  if (y0 <= y1 && y1 <= y2) {
    ib = 0;
    im = 1;
    it = 2;
  }
  else if (y0 <= y2 && y2 <= y1) {
    ib = 0;
    im = 2;
    it = 1;
  }
  else if (y1 <= y0 && y0 <= y2) {
    ib = 1;
    im = 0;
    it = 2;
  }
  else if (y1 <= y2 && y2 <= y0) {
    ib = 1;
    im = 2;
    it = 0;
  }
  else if (y2 <= y0 && y0 <= y1) {
    ib = 2;
    im = 0;
    it = 1;
  }
  else {
    ib = 2;
    im = 1;
    it = 0;
  }

  pb = *poly[ib];
  pm = *poly[im];
  pt = *poly[it];

  pb.y = (int)pb.y; 
  pm.y = (int)pm.y; 
  pt.y = (int)pt.y; 

  dy_bt = pt.y - pb.y;
  dy_bm = pm.y - pb.y;
  dy_mt = pt.y - pm.y;

  p0 = pb;
  p1 = pb.y != pm.y? pb : pm;

  dp_dy_bt = pt;
  subtract_vectors(&dp_dy_bt, &pb);
  scalar_div(dy_bt, &dp_dy_bt);

  dp_dy_bm = pm;
  subtract_vectors(&dp_dy_bm, &pb);
  scalar_div(dy_bm, &dp_dy_bm);

  dp_dy_mt = pt;
  subtract_vectors(&dp_dy_mt, &pm);
  scalar_div(dy_mt, &dp_dy_mt);

  switch (type) {
  case FLAT:
    calculate_centroid(&p, poly);
    calculate_intensity(&c, k, ambient, l, &p, norm, v);

    for (p.y = pb.y; p.y <= pt.y; p.y++) {
      p0.y = p1.y = p.y;
      draw_line(e, s, vtoc(&c) );

      add_vectors(&p0, &dp_dy_bt);
      add_vectors(&p1, (p.y < pm.y? &dp_dy_bm : &dp_dy_mt) );
    }
    break;

  case GOROUD:
    calculate_intensity(&cb, k, ambient, l, poly[ib], norm + ib, v);
    calculate_intensity(&cm, k, ambient, l, poly[im], norm + im, v);
    calculate_intensity(&ct, k, ambient, l, poly[it], norm + it, v);

    c0 = cb;
    c1 = (pb.y != pm.y? cb : cm);

    dc_dy_bt = ct;
    subtract_vectors(&dc_dy_bt, &cb);
    scalar_div(dy_bt, &dc_dy_bt);

    dc_dy_bm = cm;
    subtract_vectors(&dc_dy_bm, &cb);
    scalar_div(dy_bm, &dc_dy_bm);

    dc_dy_mt = ct;
    subtract_vectors(&dc_dy_mt, &cm);
    scalar_div(dy_mt, &dc_dy_mt);

    for (p.y = pb.y; p.y <= pt.y; p.y++) {
      dx = p1.x - p0.x;

      dc_dx = c1;
      subtract_vectors(&dc_dx, &c0);
      scalar_div(dx, &dc_dx);

      dz_dx = (p1.z - p0.z) / dx;

      p.x = p0.x;
      p.z = p0.z;

      c = c0;
      while (1) {
	plot(s, vtoc(&c), &p);

	if (p0.x < p1.x) {
	  p.z += dz_dx;
	  add_vectors(&c, &dc_dx);
	  p.x++;
	  if (p.x > p1.x)
	    break;
	}
	else {
	  p.z -= dz_dx;
	  subtract_vectors(&c, &dc_dx);
	  p.x--;
	  if (p.x < p1.x)
	    break;
	}
      }

      add_vectors(&p0, &dp_dy_bt);
      add_vectors(&c0, &dc_dy_bt);

      if (p.y < pm.y) {
	add_vectors(&p1, &dp_dy_bm);
	add_vectors(&c1, &dc_dy_bm);
      }
      else {
	add_vectors(&p1, &dp_dy_mt);
	add_vectors(&c1, &dc_dy_mt);
      }
    }

    break;
      
  case PHONG:
    n0 = norm[ib];
    n1 = norm[pb.y != pm.y? ib : im];
    
    dn_dy_bt = norm[it];
    subtract_vectors(&dn_dy_bt, norm + ib);
    scalar_div(dy_bt, &dn_dy_bt);

    dn_dy_bm = norm[im];
    subtract_vectors(&dn_dy_bm, norm + ib);
    scalar_div(dy_bm, &dn_dy_bm);

    dn_dy_mt = norm[it];
    subtract_vectors(&dn_dy_mt, norm + im);
    scalar_div(dy_mt, &dn_dy_mt);

    for (p.y = pb.y; p.y <= pt.y; p.y++) {
      dx = p1.x - p0.x;

      dn_dx = n1;
      subtract_vectors(&dn_dx, &n0);
      scalar_div(dx, &dn_dx);

      dz_dx = (p1.z - p0.z) / dx;

      p = p0;
      n = n0;
      while (1) {
	calculate_intensity(&c, k, ambient, l, &p, &n, v);
	plot(s, vtoc(&c), &p);

	if (p0.x < p1.x) {
	  p.z += dz_dx;
	  add_vectors(&n, &dn_dx);
	  p.x++;
	  if (p.x > p1.x)
	    break;
	}
	else {
	  p.z -= dz_dx;
	  subtract_vectors(&n, &dn_dx);
	  p.x--;
	  if (p.x < p1.x)
	    break;
	}
      }

      add_vectors(&p0, &dp_dy_bt);
      add_vectors(&n0, &dn_dy_bt);
      
      if (p.y < pm.y) {
	add_vectors(&p1, &dp_dy_bm);
	add_vectors(&n1, &dn_dy_bm);
      }
      else {
	add_vectors(&p1, &dp_dy_mt);
	add_vectors(&n1, &dn_dy_mt);
      }
    }

    break;
  }
}
示例#9
0
文件: shading.c 项目: tenyoung795/mdl
void draw_shaded_edge(int x,
		      polygon poly,
		      struct screen *s,
		      enum shading_t type,
		      struct constants *k,
		      color ambient,
		      struct light *l,
		      struct vector norm[3],
		      struct vector *v) {
  int i, j, tmp;

  struct vector p, *p1, dp;
  int d;
  double derz; /* derz: derivative of z */
  
  struct vector n, dern;
  struct vector c;

  switch (x) {
  case 0:
    i = 0;
    j = 1;
    break;
  case 1:
    i = 1;
    j = 2;
    break;
  case 2:
    i = 2;
    j = 0;
    break;
  }
  
  //swap points so we're always draing left to right
  if (poly[i]->x > poly[j]->x) {
    tmp = i;
    i = j;
    j = tmp;
  }

  p = *poly[i];
  p1 = poly[j];

  dp = *p1;
  subtract_vectors(&dp, &p);

  //positive slope: Octants 1, 2 (5 and 6)
  if (dp.y > 0 ) {

    //slope < 1: Octant 1 (5)
    if (dp.x > dp.y) {
      d = 2 * dp.y - dp.x;
      derz = dp.z / dp.x;

      n = norm[i];
	
      dern = norm[j];
      subtract_vectors(&dern, &n);
      scalar_div(dp.x, &dern);

      for (; p.x <= p1->x; p.x++) {
	calculate_intensity(&c, k, ambient, l, &p, &n, v);
	plot(s, vtoc(&c), &p);

	p.z += derz;
	add_vectors(&n, &dern);

	if ( d < 0 )
	  d += 2 * dp.y;
	else {
	  p.y++;
	  d += 2 * (dp.y - dp.x);
	}
      }
    }

    //slope > 1: Octant 2 (6)
    else {
      d = dp.y - 2 * dp.x;
      derz = dp.z / dp.y;

      n = norm[i];
	
      dern = norm[j];
      subtract_vectors(&dern, &n);
      scalar_div(dp.y, &dern);

      for (; p.y <= p1->y; p.y++) {
	calculate_intensity(&c, k, ambient, l, &p, &n, v);
	plot(s, vtoc(&c), &p);

	p.z += derz;
	add_vectors(&n, &dern);

	if ( d > 0 )
	  d -= 2 * dp.x;
	else {
	  p.x++;
	  d += 2 * (dp.y - dp.x);
	}
      }
    }
  }

  //negative slope: Octants 7, 8 (3 and 4)

    //slope > -1: Octant 8 (4)
  else {
    if ( dp.x > fabs(dp.y) ) {
      d = 2 * dp.y + dp.x;
      derz = dp.z / dp.x;

      n = norm[i];
	
      dern = norm[j];
      subtract_vectors(&dern, &n);
      scalar_div(dp.x, &dern);

      for (; p.x <= p1->x; p.x++) {
	calculate_intensity(&c, k, ambient, l, &p, &n, v);
	plot(s, vtoc(&c), &p);

	p.z += derz;
	add_vectors(&n, &dern);

	if ( d > 0 )
	  d += 2 * dp.y;
	else {
	  p.y--;
	  d += 2 * (dp.y + dp.x);
	}
      }

    }

    //slope < -1: Octant 7 (3)
    else {
      d = dp.y + 2 * dp.x;
      derz = dp.z / dp.y;

      n = norm[i];
	
      dern = norm[j];
      subtract_vectors(&dern, &n);
      scalar_div(dp.y, &dern);

      for (; p.y >= p1->y; p.y--) {
	calculate_intensity(&c, k, ambient, l, &p, &n, v);
	plot(s, vtoc(&c), &p);

	p.z -= derz;
	subtract_vectors(&n, &dern);

	if ( d < 0 )
	  d += 2 * dp.x;
	else {
	  p.x++;
	  d += 2 * (dp.y + dp.x);
	}
      }

    }
  }
}
示例#10
0
文件: shading.c 项目: tenyoung795/mdl
void vertical_convert(polygon poly,
		      struct screen *s,
		      enum shading_t type,
		      struct constants *k,
		      color ambient,
		      struct light *l,
		      struct vector norm[3],
		      struct vector *v) {  
  const double
    x0 = poly[0]->x,
    x1 = poly[1]->x,
    x2 = poly[2]->x;

  int il, im, ir;
  int dx_lr, dx_lm, dx_mr;
  double dy;

  struct vector pl, pm, pr;
  struct vector dp_dx_lr, dp_dx_lm, dp_dx_mr;
  struct vector p0, p1;
  edge e = {&p0, &p1};
  struct vector p;
  double dz_dy;

  struct vector cl, cm, cr;
  struct vector dc_dx_lr, dc_dx_lm, dc_dx_mr;
  struct vector c0, c1;
  struct vector c;
  struct vector dc_dy;

  struct vector dn_dx_lr, dn_dx_lm, dn_dx_mr;
  struct vector n0, n1;
  struct vector n;
  struct vector dn_dy;

  if (x0 <= x1 && x1 <= x2) {
    il = 0;
    im = 1;
    ir = 2;
  }
  else if (x0 <= x2 && x2 <= x1) {
    il = 0;
    im = 2;
    ir = 1;
  }
  else if (x1 <= x0 && x0 <= x2) {
    il = 1;
    im = 0;
    ir = 2;
  }
  else if (x1 <= x2 && x2 <= x0) {
    il = 1;
    im = 2;
    ir = 0;
  }
  else if (x2 <= x0 && x0 <= x1) {
    il = 2;
    im = 0;
    ir = 1;
  }
  else {
    il = 2;
    im = 1;
    ir = 0;
  }

  pl = *poly[il];
  pm = *poly[im];
  pr = *poly[ir];

  pl.x = (int)pl.x; 
  pm.x = (int)pm.x; 
  pr.x = (int)pr.x; 

  dx_lr = pr.x - pl.x;
  dx_lm = pm.x - pl.x;
  dx_mr = pr.x - pm.x;

  p0 = pl;
  p1 = pl.x != pm.x? pl : pm;

  dp_dx_lr = pr;
  subtract_vectors(&dp_dx_lr, &pl);
  scalar_div(dx_lr, &dp_dx_lr);

  dp_dx_lm = pm;
  subtract_vectors(&dp_dx_lm, &pl);
  scalar_div(dx_lm, &dp_dx_lm);

  dp_dx_mr = pr;
  subtract_vectors(&dp_dx_mr, &pm);
  scalar_div(dx_mr, &dp_dx_mr);

  switch (type) {
  case FLAT:
    calculate_centroid(&p, poly);
    calculate_intensity(&c, k, ambient, l, &p, norm, v);

    for (p.x = pl.x; p.x <= pr.x; p.x++) {
      p0.x = p1.x = p.x;
      draw_line(e, s, vtoc(&c) );

      add_vectors(&p0, &dp_dx_lr);
      add_vectors(&p1, (p.x < pm.x? &dp_dx_lm : &dp_dx_mr) );
    }
    break;

  case GOROUD:
    calculate_intensity(&cl, k, ambient, l, poly[il], norm + il, v);
    calculate_intensity(&cm, k, ambient, l, poly[im], norm + im, v);
    calculate_intensity(&cr, k, ambient, l, poly[ir], norm + ir, v);

    c0 = cl;
    c1 = (pl.x != pm.x? cl : cm);

    dc_dx_lr = cr;
    subtract_vectors(&dc_dx_lr, &cl);
    scalar_div(dx_lr, &dc_dx_lr);

    dc_dx_lm = cm;
    subtract_vectors(&dc_dx_lm, &cl);
    scalar_div(dx_lm, &dc_dx_lm);

    dc_dx_mr = cr;
    subtract_vectors(&dc_dx_mr, &cm);
    scalar_div(dx_mr, &dc_dx_mr);

    for (p.x = pl.x; p.x <= pr.x; p.x++) {
      dy = p1.y - p0.y;

      dc_dy = c1;
      subtract_vectors(&dc_dy, &c0);
      scalar_div(dy, &dc_dy);

      dz_dy = (p1.z - p0.z) / dy;

      p.y = p0.y;
      p.z = p0.z;

      c = c0;
      while (1) {
	plot(s, vtoc(&c), &p);

	if (p0.y < p1.y) {
	  p.z += dz_dy;
	  add_vectors(&c, &dc_dy);
	  p.y++;
	  if (p.y > p1.y)
	    break;
	}
	else {
	  p.z -= dz_dy;
	  subtract_vectors(&c, &dc_dy);
	  p.y--;
	  if (p.y < p1.y)
	    break;
	}
      }

      add_vectors(&p0, &dp_dx_lr);
      add_vectors(&c0, &dc_dx_lr);

      if (p.x < pm.x) {
	add_vectors(&p1, &dp_dx_lm);
	add_vectors(&c1, &dc_dx_lm);
      }
      else {
	add_vectors(&p1, &dp_dx_mr);
	add_vectors(&c1, &dc_dx_mr);
      }
    }

    break;
      
  case PHONG:
    n0 = norm[il];
    n1 = norm[pl.x != pm.x? il : im];
    
    dn_dx_lr = norm[ir];
    subtract_vectors(&dn_dx_lr, norm + il);
    scalar_div(dx_lr, &dn_dx_lr);

    dn_dx_lm = norm[im];
    subtract_vectors(&dn_dx_lm, norm + il);
    scalar_div(dx_lm, &dn_dx_lm);

    dn_dx_mr = norm[ir];
    subtract_vectors(&dn_dx_mr, norm + im);
    scalar_div(dx_mr, &dn_dx_mr);

    for (p.x = pl.x; p.x <= pr.x; p.x++) {
      dy = p1.y - p0.y;

      dn_dy = n1;
      subtract_vectors(&dn_dy, &n0);
      scalar_div(dy, &dn_dy);

      dz_dy = (p1.z - p0.z) / dy;

      p = p0;
      n = n0;
      while (1) {
	calculate_intensity(&c, k, ambient, l, &p, &n, v);
	plot(s, vtoc(&c), &p);

	if (p0.y < p1.y) {
	  p.z += dz_dy;
	  add_vectors(&n, &dn_dy);
	  p.y++;
	  if (p.y > p1.y)
	    break;
	}
	else {
	  p.z -= dz_dy;
	  subtract_vectors(&n, &dn_dy);
	  p.y--;
	  if (p.y < p1.y)
	    break;
	}
      }

      add_vectors(&p0, &dp_dx_lr);
      add_vectors(&n0, &dn_dx_lr);
      
      if (p.x < pm.x) {
	add_vectors(&p1, &dp_dx_lm);
	add_vectors(&n1, &dn_dx_lm);
      }
      else {
	add_vectors(&p1, &dp_dx_mr);
	add_vectors(&n1, &dn_dx_mr);
      }
    }

    break;
  }
}