|
|
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 |
}
|