Blame onefile/line.c

a5e8d6
a5e8d6
#include <math.h></math.h>
a5e8d6
#include <stdio.h></stdio.h>
a5e8d6
#include <stdlib.h></stdlib.h>
a5e8d6
#include <helianthus.h></helianthus.h>
a5e8d6
a5e8d6
a5e8d6
a5e8d6
a5e8d6
typedef struct {
a5e8d6
  double x, y;
a5e8d6
  double color[4];
a5e8d6
} Vertex;
a5e8d6
a5e8d6
int cs = 5, vw = 120, vh = 90;
a5e8d6
int lx1, ly1, lx2, ly2, lx3, ly3;
a5e8d6
Vertex tv1, tv2, tv3;
a5e8d6
a5e8d6
a5e8d6
void grid(int w, int h) {
a5e8d6
  saveState();
a5e8d6
  strokeWidth(0.1);
a5e8d6
  stroke(colorByNameA("gray", 0.5));
a5e8d6
  for(int x = 0; x <= w; ++x) line(x, 0, x, h);
a5e8d6
  for(int y = 0; y <= h; ++y) line(0, y, w, y);
a5e8d6
  restoreState();
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void dot(int x, int y)
a5e8d6
  { rect(x, y, 1, 1); }
a5e8d6
a5e8d6
void dotColored(int x, int y, double *color) {
a5e8d6
  saveState();
a5e8d6
  fill(colorByRGBA(color[0], color[1], color[2], color[3]));
a5e8d6
  dot(x, y);
a5e8d6
  restoreState();
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void lineBase(int x1, int y1, int x2, int y2) {
a5e8d6
	int x_start_line;	// put the lowest x in start line and the highest in end line
a5e8d6
	int x_end_line;
a5e8d6
	int y_start_line;	// put the lowest y in start line and the highest in end line
a5e8d6
	int need_reflect;
a5e8d6
	int dist_point_to_line;
a5e8d6
	int switch_roles = FALSE;
a5e8d6
	int delta_x;
a5e8d6
	int delta_y;
a5e8d6
	int temp;
a5e8d6
a5e8d6
	// take care of end cases when the two points share an index value
a5e8d6
	// take care of end cases when the two points share an index value// take care of end cases when the two points share an index value// take care of end cases when the two points share an index value
a5e8d6
	//	need to take care of the case where the point is outside of the window frame
a5e8d6
a5e8d6
		// Initialization for the Bershenham algorithm:
a5e8d6
	x_start_line = x1, y_start_line = y1;
a5e8d6
	x_end_line = x1;
a5e8d6
	delta_x = (x2 - x1);
a5e8d6
	if (delta_x < 0)
a5e8d6
		delta_x = delta_x * (-1);	// make delta_x positive
a5e8d6
	delta_y = (y2 - y1);
a5e8d6
	if (delta_y < 0)
a5e8d6
		delta_y = delta_y * (-1);	// make delta_y positive
a5e8d6
	if (delta_x != 0 || delta_y != 0)
a5e8d6
	{
a5e8d6
		// first case: 0
a5e8d6
		if (delta_y < delta_x)	// check if the incline is a fraction or not, because they are both positive
a5e8d6
		{						// meaning -1
a5e8d6
			if (x1 < x2)
a5e8d6
			{
a5e8d6
				x_start_line = x1, y_start_line = y1;
a5e8d6
				x_end_line = x2;
a5e8d6
				need_reflect = (y1 < y2) ? 1 : -1;	// take care of the case of negative incline
a5e8d6
			}
a5e8d6
			else	// the start point is p2
a5e8d6
			{
a5e8d6
				x_start_line = x2, y_start_line = y2;
a5e8d6
				x_end_line = x1;
a5e8d6
				need_reflect = (y2 < y1) ? 1 : -1;	// take care of the case of negative incline
a5e8d6
			}
a5e8d6
		}
a5e8d6
		else	// the incline is either incline>1 or incline<-1
a5e8d6
		{		// so we need to change the x and y roles
a5e8d6
			if (y1 < y2)	// the start point is p1 and switch the x and y
a5e8d6
			{
a5e8d6
				x_start_line = y1;	// swith roles of x and y
a5e8d6
				y_start_line = x1;
a5e8d6
				x_end_line = y2;
a5e8d6
				need_reflect = (x1 < x2) ? 1 : -1;
a5e8d6
			}
a5e8d6
			else	// the start point is p2 and switch the x and y roles
a5e8d6
			{
a5e8d6
				x_start_line = y2;
a5e8d6
				y_start_line = x2;
a5e8d6
				x_end_line = y1;
a5e8d6
				need_reflect = (x2 < x1) ? 1 : -1;
a5e8d6
			}
a5e8d6
			switch_roles = TRUE;
a5e8d6
			temp = delta_x;	// switch the delta_x and delta_y because the roles have changed
a5e8d6
			delta_x = delta_y;
a5e8d6
			delta_y = temp;
a5e8d6
		}
a5e8d6
		dist_point_to_line = 2 * delta_y - delta_x;
a5e8d6
		// Testing Barriers:
a5e8d6
		if (x_end_line > vw)	// need to add barrier for viewport height without causing lines to disappear
a5e8d6
			x_end_line = vw;
a5e8d6
		if (x_start_line < 0)
a5e8d6
			x_start_line = 0;
a5e8d6
		if (y_start_line < 0)
a5e8d6
			y_start_line = 0;
a5e8d6
		for (int i = x_start_line; i <= x_end_line; i++)	// go over the incline from start point to end point and draw the line
a5e8d6
		{													// put each pixel in the right place
a5e8d6
			switch_roles ? dot(y_start_line, i) : dot(i, y_start_line);
a5e8d6
			// new stuff for edge walking
a5e8d6
a5e8d6
			// end of new stuff
a5e8d6
			if (dist_point_to_line > 0)
a5e8d6
			{
a5e8d6
				y_start_line = y_start_line + need_reflect;
a5e8d6
				dist_point_to_line = dist_point_to_line - 2 * delta_x;
a5e8d6
			}
a5e8d6
			dist_point_to_line = dist_point_to_line + 2 * delta_y;
a5e8d6
		}	//x_start_line,x_end_line,switch_roles,y_start_line,need_reflect,dist_point_to_line,delta_x,delta_y
a5e8d6
	}
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void lineNew(int x1, int y1, int x2, int y2) {
a5e8d6
  if (y1 > y2) { int x = x1, y = y1; x1 = x2; y1 = y2; x2 = x; y2 = y; }
a5e8d6
a5e8d6
	int x = x1;
a5e8d6
	int dx = x2 - x1;
a5e8d6
	int dy = y2 - y1;
a5e8d6
	if (dy > 0) {
a5e8d6
    int sign_x = dx < 0 ? -1 : 1;
a5e8d6
    int step_x = dx/dy;
a5e8d6
    int sub_step_x = abs(dx)%dy;
a5e8d6
    int sub_step_accum = -dy/2;
a5e8d6
    for(int y = y1; y < y2; ++y) {
a5e8d6
      dot(x, y);
a5e8d6
a5e8d6
      x += step_x;
a5e8d6
      sub_step_accum += sub_step_x;
a5e8d6
      if (sub_step_accum > 0) {
a5e8d6
        sub_step_accum -= dy;
a5e8d6
        x += sign_x;
a5e8d6
      }
a5e8d6
    }
a5e8d6
  } else {
a5e8d6
    dot(x1, y1);
a5e8d6
  }
a5e8d6
a5e8d6
	dot(x2, y2);
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void row(int y, int x1, int x2) {
a5e8d6
  if (x1 > x2) { int x = x1; x1 = x2; x2 = x; }
a5e8d6
  if (x1 < 0) x1 = 0;
a5e8d6
  if (x2 > vw) x2 = vw;
a5e8d6
  for(int x = x1; x < x2; ++x) dot(x, y);
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void triangle(int vx1, int vy1, int vx2, int vy2, int vx3, int vy3) {
a5e8d6
  if (vy1 > vy3) { int x = vx1, y = vy1; vx1 = vx3; vy1 = vy3; vx3 = x; vy3 = y; }
a5e8d6
  if (vy2 > vy3) { int x = vx2, y = vy2; vx2 = vx3; vy2 = vy3; vx3 = x; vy3 = y; }
a5e8d6
  if (vy1 > vy2) { int x = vx1, y = vy1; vx1 = vx2; vy1 = vy2; vx2 = x; vy2 = y; }
a5e8d6
a5e8d6
	// split triangle to two triangles by the middle vertex
a5e8d6
	//
a5e8d6
	//       *__
a5e8d6
	//      /    --__    - top triangle here
a5e8d6
	//     /-------__-*  - split triangle by this line
a5e8d6
	//    /    __--
a5e8d6
	//   / __--          - bottom triangle here
a5e8d6
	//  *--
a5e8d6
a5e8d6
	// include pixels at left and top sides, but exclude at right and bottom
a5e8d6
	// it required to seamless clue neighboring triangles without overlapping
a5e8d6
a5e8d6
	if (vy1 >= vy3) return;
a5e8d6
	if (vy1 >= vh || vy3 <= 0) return;
a5e8d6
	if (vx1 >= vw && vx2 >= vw && vx3 >= vw) return;
a5e8d6
	if (vx1 <= 0  && vx2 <= 0  && vx3 <= 0 ) return;
a5e8d6
a5e8d6
	// configure line from top vertex to bottom vertex
a5e8d6
	int x1 = vx1;
a5e8d6
	int dx1 = vx3 - vx1;
a5e8d6
	int dy1 = vy3 - vy1;
a5e8d6
  int sign_x1 = dx1 < 0 ? -1 : 1;
a5e8d6
  int step_x1 = dx1/dy1;
a5e8d6
  int sub_step_x1 = abs(dx1)%dy1;
a5e8d6
  int sub_step_accum1 = -dy1/2;
a5e8d6
a5e8d6
  // draw top triangle
a5e8d6
	if (vy2 > vy1) {
a5e8d6
    // configure line from top vertex to middle vertex
a5e8d6
    int x2 = vx1;
a5e8d6
    int dx2 = vx2 - vx1;
a5e8d6
    int dy2 = vy2 - vy1;
a5e8d6
    int sign_x2 = dx2 < 0 ? -1 : 1;
a5e8d6
    int step_x2 = dx2/dy2;
a5e8d6
    int sub_step_x2 = abs(dx2)%dy2;
a5e8d6
    int sub_step_accum2 = -dy2/2;
a5e8d6
a5e8d6
    // skip invisible rows
a5e8d6
    int y1 = vy1, y2 = vy2;
a5e8d6
    if (y1 < 0) {
a5e8d6
      const int rows = (y2 < 0 ? y2 : 0) - y1;
a5e8d6
      y1 += rows;
a5e8d6
      x1 += rows*step_x1;
a5e8d6
      sub_step_accum1 += rows*sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0) {
a5e8d6
        const int count = sub_step_accum1/dy1 + 1;
a5e8d6
        sub_step_accum1 -= count*dy1;
a5e8d6
        x1 += count*sign_x1;
a5e8d6
      }
a5e8d6
a5e8d6
      x2 += rows*step_x2;
a5e8d6
      sub_step_accum2 += rows*sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0) {
a5e8d6
        const int count = sub_step_accum2/dy2 + 1;
a5e8d6
        sub_step_accum2 -= count*dy2;
a5e8d6
        x2 += count*sign_x2;
a5e8d6
      }
a5e8d6
    }
a5e8d6
    if (y2 > vh) y2 = vh;
a5e8d6
a5e8d6
    // iterate over visible rows
a5e8d6
    for(int y = y1; y < y2; ++y) {
a5e8d6
      row(y, x1, x2);
a5e8d6
a5e8d6
      // increment line 1
a5e8d6
      x1 += step_x1;
a5e8d6
      sub_step_accum1 += sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0)
a5e8d6
        { sub_step_accum1 -= dy1; x1 += sign_x1; }
a5e8d6
a5e8d6
      // increment line 2
a5e8d6
      x2 += step_x2;
a5e8d6
      sub_step_accum2 += sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0)
a5e8d6
        { sub_step_accum2 -= dy2; x2 += sign_x2; }
a5e8d6
    }
a5e8d6
  }
a5e8d6
a5e8d6
  // draw bottom triangle
a5e8d6
	if (vy3 > vy2) {
a5e8d6
    // configure line from middle vertex to bottom vertex
a5e8d6
    int x2 = vx2;
a5e8d6
    int dx2 = vx3 - vx2;
a5e8d6
    int dy2 = vy3 - vy2;
a5e8d6
    int sign_x2 = dx2 < 0 ? -1 : 1;
a5e8d6
    int step_x2 = dx2/dy2;
a5e8d6
    int sub_step_x2 = abs(dx2)%dy2;
a5e8d6
    int sub_step_accum2 = -dy2/2;
a5e8d6
a5e8d6
    // skip invisible rows
a5e8d6
    int y1 = vy2, y2 = vy3;
a5e8d6
    if (y1 < 0) {
a5e8d6
      const int rows = -y1;
a5e8d6
      y1 += rows;
a5e8d6
      x1 += rows*step_x1;
a5e8d6
      sub_step_accum1 += rows*sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0) {
a5e8d6
        const int count = sub_step_accum1/dy1 + 1;
a5e8d6
        sub_step_accum1 -= count*dy1;
a5e8d6
        x1 += count*sign_x1;
a5e8d6
      }
a5e8d6
a5e8d6
      x2 += rows*step_x2;
a5e8d6
      sub_step_accum2 += rows*sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0) {
a5e8d6
        const int count = sub_step_accum2/dy2 + 1;
a5e8d6
        sub_step_accum2 -= count*dy2;
a5e8d6
        x2 += count*sign_x2;
a5e8d6
      }
a5e8d6
    }
a5e8d6
    if (y2 > vh) y2 = vh;
a5e8d6
a5e8d6
    // iterate over visible rows
a5e8d6
    for(int y = y1; y < y2; ++y) {
a5e8d6
      row(y, x1, x2);
a5e8d6
a5e8d6
      // increment line 1
a5e8d6
      x1 += step_x1;
a5e8d6
      sub_step_accum1 += sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0)
a5e8d6
        { sub_step_accum1 -= dy1; x1 += sign_x1; }
a5e8d6
a5e8d6
      // increment line 2
a5e8d6
      x2 += step_x2;
a5e8d6
      sub_step_accum2 += sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0)
a5e8d6
        { sub_step_accum2 -= dy2; x2 += sign_x2; }
a5e8d6
    }
a5e8d6
  }
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void rowNew(int y, int x1, int x2, double *color, double *inc) {
a5e8d6
  if (x1 < x2) {
a5e8d6
    if (x1 >= vw || x2 <= 0) return;
a5e8d6
    if (x1 < 0) {
a5e8d6
      int skip = -x1;
a5e8d6
      for(int i = 0; i < 4; ++i) color[i] += skip*inc[i];
a5e8d6
      x1 += skip;
a5e8d6
    }
a5e8d6
    if (x2 > vw) x2 = vw;
a5e8d6
    for(int x = x1; x < x2; ++x) {
a5e8d6
      dotColored(x, y, color);
a5e8d6
      for(int i = 0; i < 4; ++i) color[i] += inc[i];
a5e8d6
    }
a5e8d6
  } else {
a5e8d6
    if (x2 >= vw || x1 <= 0) return;
a5e8d6
    if (x1 > vw) {
a5e8d6
      int skip = vw - x1;
a5e8d6
      for(int i = 0; i < 4; ++i) color[i] += skip*inc[i];
a5e8d6
      x1 += skip;
a5e8d6
    }
a5e8d6
    if (x2 < 0) x2 = 0;
a5e8d6
    for(int x = x1-1; x >= x2; --x) {
a5e8d6
      for(int i = 0; i < 4; ++i) color[i] -= inc[i];
a5e8d6
      dotColored(x, y, color);
a5e8d6
    }
a5e8d6
  }
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void triangleNew(const Vertex *v1, const Vertex *v2, const Vertex *v3) {
a5e8d6
  if (v1->y > v3->y) { const Vertex *v = v1; v1 = v3; v3 = v; }
a5e8d6
  if (v2->y > v3->y) { const Vertex *v = v2; v2 = v3; v3 = v; }
a5e8d6
  if (v1->y > v2->y) { const Vertex *v = v1; v1 = v2; v2 = v; }
a5e8d6
a5e8d6
	// split triangle to two triangles by the middle vertex
a5e8d6
	//
a5e8d6
	//       *__
a5e8d6
	//      /    --__    - top triangle here
a5e8d6
	//     /-------__-*  - split triangle by this line
a5e8d6
	//    /    __--
a5e8d6
	//   / __--          - bottom triangle here
a5e8d6
	//  *--
a5e8d6
a5e8d6
	// include pixels at left and top sides, but exclude at right and bottom
a5e8d6
	// it required to seamless clue neighboring triangles without overlapping
a5e8d6
a5e8d6
	const int vx1 = (int)floor(v1->x);
a5e8d6
	const int vy1 = (int)floor(v1->y);
a5e8d6
	const int vx2 = (int)floor(v2->x);
a5e8d6
	const int vy2 = (int)floor(v2->y);
a5e8d6
	const int vx3 = (int)floor(v3->x);
a5e8d6
	const int vy3 = (int)floor(v3->y);
a5e8d6
a5e8d6
	const int dx31 = vx3 - vx1;
a5e8d6
	const int dy31 = vy3 - vy1;
a5e8d6
a5e8d6
	const int dx21 = vx2 - vx1;
a5e8d6
	const int dy21 = vy2 - vy1;
a5e8d6
a5e8d6
	const int dx32 = vx3 - vx2;
a5e8d6
	const int dy32 = vy3 - vy2;
a5e8d6
a5e8d6
	if (dy31 <= 0) return;
a5e8d6
	if (vy1 >= vh || vy3 <= 0) return;
a5e8d6
	if (vx1 >= vw && vx2 >= vw && vx3 >= vw) return;
a5e8d6
	if (vx1 <= 0  && vx2 <= 0  && vx3 <= 0 ) return;
a5e8d6
a5e8d6
	// calculate area
a5e8d6
	const int double_area = dx31*dy31 - dx21*dy21 + dx32*dy32 - 2*dx32*dy31;
a5e8d6
	if (!double_area) return;
a5e8d6
	const double one_div_2a = 1.0/double_area;
a5e8d6
a5e8d6
	// configure line from top vertex to bottom vertex
a5e8d6
  const int sign_x1 = dx31 < 0 ? -1 : 1;
a5e8d6
  const int step_x1 = dx31/dy31;
a5e8d6
  const int sub_step_x1 = abs(dx31)%dy31;
a5e8d6
	int x1 = vx1;
a5e8d6
  int sub_step_accum1 = -dy31/2;
a5e8d6
a5e8d6
  // configure interpolation coefficients for the middle vertex
a5e8d6
	const double k2_dx = one_div_2a*dy31;
a5e8d6
	const double k2_dy = one_div_2a*(dy31*step_x1 - dx31);
a5e8d6
  double k2 = 0;
a5e8d6
a5e8d6
  // draw top triangle
a5e8d6
	if (vy2 > vy1) {
a5e8d6
    // configure line from top vertex to middle vertex
a5e8d6
    const int sign_x2 = dx21 < 0 ? -1 : 1;
a5e8d6
    const int step_x2 = dx21/dy21;
a5e8d6
    const int sub_step_x2 = abs(dx21)%dy21;
a5e8d6
    int x2 = vx1;
a5e8d6
    int sub_step_accum2 = -dy21/2;
a5e8d6
a5e8d6
    // configure interpolation coefficients for the bottom vertex
a5e8d6
    const double k3_dx = -one_div_2a*dy21;
a5e8d6
    const double k3_dy = -one_div_2a*(dy21*step_x1 - dx21);
a5e8d6
    double color[4], inc[4];
a5e8d6
    double k3 = 0;
a5e8d6
    for(int i = 0; i < 4; ++i)
a5e8d6
      inc[i] = k2_dx*v2->color[i] + k3_dx*v3->color[i] - (k2_dx + k3_dx)*v1->color[i];
a5e8d6
a5e8d6
    // skip invisible rows
a5e8d6
    int y1 = vy1, y2 = vy2;
a5e8d6
    if (y1 < 0) {
a5e8d6
      const int rows = (y2 < 0 ? y2 : 0) - y1;
a5e8d6
      y1 += rows;
a5e8d6
      x1 += rows*step_x1;
a5e8d6
      k2 += rows*k2_dy;
a5e8d6
      k3 += rows*k3_dy;
a5e8d6
      sub_step_accum1 += rows*sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0) {
a5e8d6
        const int count = sub_step_accum1/dy31 + 1;
a5e8d6
        sub_step_accum1 -= count*dy31;
a5e8d6
        x1 += count*sign_x1;
a5e8d6
        k2 += count*sign_x1*k2_dx;
a5e8d6
        k3 += count*sign_x1*k3_dx;
a5e8d6
      }
a5e8d6
a5e8d6
      x2 += rows*step_x2;
a5e8d6
      sub_step_accum2 += rows*sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0) {
a5e8d6
        const int count = sub_step_accum2/dy21 + 1;
a5e8d6
        sub_step_accum2 -= count*dy21;
a5e8d6
        x2 += count*sign_x2;
a5e8d6
      }
a5e8d6
    }
a5e8d6
    if (y2 > vh) y2 = vh;
a5e8d6
a5e8d6
    // iterate over visible rows
a5e8d6
    for(int y = y1; y < y2; ++y) {
a5e8d6
      double k1 = 1 - k2 - k3;
a5e8d6
      for(int i = 0; i < 4; ++i)
a5e8d6
        color[i] = k1*v1->color[i] + k2*v2->color[i] + k3*v3->color[i];
a5e8d6
      rowNew(y, x1, x2, color, inc);
a5e8d6
a5e8d6
      // increment line 1
a5e8d6
      x1 += step_x1;
a5e8d6
      k2 += k2_dy;
a5e8d6
      k3 += k3_dy;
a5e8d6
      sub_step_accum1 += sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0) {
a5e8d6
        sub_step_accum1 -= dy31;
a5e8d6
        x1 += sign_x1;
a5e8d6
        k2 += sign_x1*k2_dx;
a5e8d6
        k3 += sign_x1*k3_dx;
a5e8d6
      }
a5e8d6
a5e8d6
      // increment line 2
a5e8d6
      x2 += step_x2;
a5e8d6
      sub_step_accum2 += sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0)
a5e8d6
        { sub_step_accum2 -= dy21; x2 += sign_x2; }
a5e8d6
    }
a5e8d6
  }
a5e8d6
a5e8d6
  // draw bottom triangle
a5e8d6
	if (vy3 > vy2 && vy2 < vh) {
a5e8d6
    // configure line from middle vertex to bottom vertex
a5e8d6
    const int sign_x2 = dx32 < 0 ? -1 : 1;
a5e8d6
    const int step_x2 = dx32/dy32;
a5e8d6
    const int sub_step_x2 = abs(dx32)%dy32;
a5e8d6
    int sub_step_accum2 = -dy32/2;
a5e8d6
    int x2 = vx2;
a5e8d6
a5e8d6
    // configure interpolation coefficients for the top vertex
a5e8d6
    const double k1_dx = -one_div_2a*dy32;
a5e8d6
    const double k1_dy = -one_div_2a*(dy32*step_x1 - dx32);
a5e8d6
    double color[4], inc[4];
a5e8d6
    double k1 = -one_div_2a*dy32*(x1 - vx2);
a5e8d6
    for(int i = 0; i < 4; ++i)
a5e8d6
      inc[i] = k1_dx*v1->color[i] + k2_dx*v2->color[i] - (k1_dx + k2_dx)*v3->color[i];
a5e8d6
a5e8d6
    // skip invisible rows
a5e8d6
    int y1 = vy2, y2 = vy3;
a5e8d6
    if (y1 < 0) {
a5e8d6
      const int rows = -y1;
a5e8d6
      y1 += rows;
a5e8d6
      x1 += rows*step_x1;
a5e8d6
      k1 += rows*k1_dy;
a5e8d6
      k2 += rows*k2_dy;
a5e8d6
      sub_step_accum1 += rows*sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0) {
a5e8d6
        const int count = sub_step_accum1/dy31 + 1;
a5e8d6
        sub_step_accum1 -= count*dy31;
a5e8d6
        x1 += count*sign_x1;
a5e8d6
        k1 += count*sign_x1*k1_dx;
a5e8d6
        k2 += count*sign_x1*k2_dx;
a5e8d6
      }
a5e8d6
a5e8d6
      x2 += rows*step_x2;
a5e8d6
      sub_step_accum2 += rows*sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0) {
a5e8d6
        const int count = sub_step_accum2/dy32 + 1;
a5e8d6
        sub_step_accum2 -= count*dy32;
a5e8d6
        x2 += count*sign_x2;
a5e8d6
      }
a5e8d6
    }
a5e8d6
    if (y2 > vh) y2 = vh;
a5e8d6
a5e8d6
    // iterate over visible rows
a5e8d6
    for(int y = y1; y < y2; ++y) {
a5e8d6
      double k3 = 1 - k1 - k2;
a5e8d6
      for(int i = 0; i < 4; ++i)
a5e8d6
        color[i] = k1*v1->color[i] + k2*v2->color[i] + k3*v3->color[i];
a5e8d6
      rowNew(y, x1, x2, color, inc);
a5e8d6
a5e8d6
      // increment line 1
a5e8d6
      x1 += step_x1;
a5e8d6
      k1 += k1_dy;
a5e8d6
      k2 += k2_dy;
a5e8d6
      sub_step_accum1 += sub_step_x1;
a5e8d6
      if (sub_step_accum1 > 0) {
a5e8d6
        sub_step_accum1 -= dy31;
a5e8d6
        x1 += sign_x1;
a5e8d6
        k1 += sign_x1*k1_dx;
a5e8d6
        k2 += sign_x1*k2_dx;
a5e8d6
      }
a5e8d6
a5e8d6
      // increment line 2
a5e8d6
      x2 += step_x2;
a5e8d6
      sub_step_accum2 += sub_step_x2;
a5e8d6
      if (sub_step_accum2 > 0)
a5e8d6
        { sub_step_accum2 -= dy32; x2 += sign_x2; }
a5e8d6
    }
a5e8d6
  }
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void setTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
a5e8d6
  tv1.x = lx1 = x1; tv1.y = ly1 = y1;
a5e8d6
  tv2.x = lx2 = x2; tv2.y = ly2 = y2;
a5e8d6
  tv3.x = lx3 = x3; tv3.y = ly3 = y3;
a5e8d6
  printf("setTriangle(%2d, %2d, %2d, %2d, %2d, %2d);\n", lx1, ly1, lx2, ly2, lx3, ly3);
a5e8d6
}
a5e8d6
a5e8d6
void setLine(int x1, int y1, int x2, int y2) {
a5e8d6
  lx1 = x1; ly1 = y1;
a5e8d6
  lx2 = x2; ly2 = y2;
a5e8d6
  printf("setLine(%2d, %2d, %2d, %2d);\n", lx1, ly1, lx2, ly2);
a5e8d6
}
a5e8d6
a5e8d6
void generateLine() {
a5e8d6
  setLine( randomNumber(0, vw-1), randomNumber(0, vh-1),
a5e8d6
           randomNumber(0, vw-1), randomNumber(0, vh-1) );
a5e8d6
}
a5e8d6
a5e8d6
void generateTriangle() {
a5e8d6
  setTriangle( randomNumber(-vw/2, vw+vw/2), randomNumber(-vh/2, vh+vh/2),
a5e8d6
               randomNumber(-vw/2, vw+vw/2), randomNumber(-vh/2, vh+vh/2),
a5e8d6
               randomNumber(-vw/2, vw+vw/2), randomNumber(-vh/2, vh+vh/2) );
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void init() {
a5e8d6
  tv1.color[0] = tv1.color[3] = 1;
a5e8d6
  tv2.color[1] = tv2.color[3] = 1;
a5e8d6
  tv3.color[2] = tv3.color[3] = 1;
a5e8d6
a5e8d6
  //generateLine();
a5e8d6
  //setLine( 2, 18, 14,  1);
a5e8d6
  //setLine(14,  1,  2, 18);
a5e8d6
  //setLine( 0,  0, 12,  7);
a5e8d6
  //generateTriangle();
a5e8d6
  setTriangle(94, 155, 116, 46, 236, 96);
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void deinit() { }
a5e8d6
a5e8d6
a5e8d6
void draw() {
a5e8d6
  double w = windowGetWidth();
a5e8d6
  double h = windowGetHeight();
a5e8d6
a5e8d6
  saveState();
a5e8d6
  translate(0.5*w, 0.5*h);
a5e8d6
  zoom(cs);
a5e8d6
  translate(-0.5*vw, -0.5*vh);
a5e8d6
  grid(vw, vh);
a5e8d6
a5e8d6
  if (keyWentDown("space")) generateTriangle();
a5e8d6
a5e8d6
a5e8d6
  noStroke();
a5e8d6
  fill(colorByNameA("blue", 0.5));
a5e8d6
  triangle(lx1, ly1, lx2, ly2, lx3, ly3);
a5e8d6
  //triangleNew(&tv1, &tv2, &tv3);
a5e8d6
a5e8d6
  stroke(colorByName("black"));
a5e8d6
  strokeWidth(0.1);
a5e8d6
  dotColored(lx1, ly1, tv1.color);
a5e8d6
  dotColored(lx2, ly2, tv2.color);
a5e8d6
  dotColored(lx3, ly3, tv3.color);
a5e8d6
a5e8d6
  restoreState();
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
int main() {
a5e8d6
  windowSetVariableFrameRate();
a5e8d6
  windowSetResizable(TRUE);
a5e8d6
  windowSetSize(2*cs*vw, 2*cs*vh);
a5e8d6
  windowSetInit(&init);
a5e8d6
  windowSetDeinit(&deinit);
a5e8d6
  windowSetDraw(&draw);
a5e8d6
  windowRun();
a5e8d6
}