similarly for algo_ellipsefill

This commit is contained in:
Steven 2018-02-14 23:07:44 -05:00
parent 8549774060
commit debb8e9f32

View File

@ -63,19 +63,22 @@ void algo_line(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
/* Additional helper functions for the ellipse-drawing helper function
below corresponding to routines in Bresenham's algorithm. */
namespace {
int bresenham_ellipse_error(int rx, int ry, int x, int y) {
int bresenham_ellipse_error(int rx, int ry, int x, int y)
{
return x*x*ry*ry + y*y*rx*rx - rx*rx*ry*ry;
}
// Initialize positions x and y for Bresenham's algorithm
void bresenham_ellipse_init(int rx, int ry, int *px, int *py) {
void bresenham_ellipse_init(int rx, int ry, int *px, int *py)
{
// Start at the fatter pole
if (rx > ry) { *px = 0; *py = ry; }
else { *px = rx; *py = 0; }
}
// Move to next pixel to draw, according to Bresenham's algorithm
void bresenham_ellipse_step(int rx, int ry, int *px, int *py) {
void bresenham_ellipse_step(int rx, int ry, int *px, int *py)
{
int &x = *px, &y = *py;
// Move towards the skinnier pole. Having 2 cases isn't needed, but it ensures
// swapping rx and ry is the same as rotating 90 degrees.
@ -107,11 +110,13 @@ namespace {
for Allegro 4.x.
Adapted for ASEPRITE by David A. Capello. */
void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc) {
void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc)
{
int mx, my, rx, ry;
int x, y;
/* Cheap hack to get elllipses with integer diameter, by just offsetting
* some quadrants by one pixel. */
int mx2, my2;
mx = (x1 + x2) / 2;
@ -147,7 +152,7 @@ void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc) {
proc(mx - rx, my2, data);
}
/* Initialize drawing position */
/* Initialize drawing position at a pole. */
bresenham_ellipse_init(rx, ry, &x, &y);
for (;;) {
@ -155,8 +160,8 @@ void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc) {
bresenham_ellipse_step(rx, ry, &x, &y);
/* Edge conditions */
if (y == 0 && x < rx) ++y; // don't draw on horizontal radius except at pole
if (x == 0 && y < ry) ++x; // don't draw on vertical radius except at pole
if (y == 0 && x < rx) ++y; // don't move to horizontal radius except at pole
if (x == 0 && y < ry) ++x; // don't move to vertical radius except at pole
if (y <= 0 || x <= 0) break; // stop before pole, since it's already drawn
/* Process pixel */
@ -167,14 +172,9 @@ void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc) {
}
}
void algo_ellipsefill(int x1, int y1, int x2, int y2, void *data, AlgoHLine proc)
{
int mx, my, rx, ry;
int err;
int xx, yy;
int xa, ya;
int x, y;
/* Cheap hack to get elllipses with integer diameter, by just offsetting
@ -197,105 +197,30 @@ void algo_ellipsefill(int x1, int y1, int x2, int y2, void *data, AlgoHLine proc
rx /= 2;
ry /= 2;
/* Draw the 4 poles. */
proc(mx, my2 + ry, mx, data);
proc(mx, my - ry, mx, data);
/* proc(mx2 + rx, my, mx2 + rx, data); */
/* proc(mx - rx, my, mx - rx, data); */
/* Draw the north and south poles (possibly 2 pixels) */
proc(mx, my2 + ry, mx2, data);
proc(mx, my - ry, mx2, data);
/* Draw the equator (possibly width 2) */
proc(mx - rx, my, mx2 + rx, data);
if (my != my2) proc(mx - rx, my2, mx2 + rx, data);
/* For even diameter axis, double the poles. */
if (mx != mx2) {
proc(mx2, my2 + ry, mx2, data);
proc(mx2, my - ry, mx2, data);
}
if (my != my2) {
/* proc(mx2 + rx, my2, data); */
/* proc(mx - rx, my2, data); */
proc(mx - rx, my2, mx2 + rx, data);
}
xx = rx * rx;
yy = ry * ry;
/* Do the 'x direction' part of the arc. */
x = 0;
y = ry;
xa = 0;
ya = xx * 2 * ry;
err = xx / 4 - xx * ry;
/* Initialize drawing position at a pole. */
bresenham_ellipse_init(rx, ry, &x, &y);
for (;;) {
err += xa + yy;
if (err >= 0) {
ya -= xx * 2;
err -= ya;
y--;
}
xa += yy * 2;
x++;
if (xa >= ya)
break;
/* Step to the next pixel to draw. */
bresenham_ellipse_step(rx, ry, &x, &y);
/* proc(mx2 + x, my - y, data); */
/* proc(mx - x, my - y, data); */
/* proc(mx2 + x, my2 + y, data); */
/* proc(mx - x, my2 + y, data); */
/* Edge conditions */
if (y == 0 && x < rx) ++y; // don't move to horizontal radius except at pole
if (x == 0 && y < ry) ++x; // don't move to vertical radius except at pole
if (y <= 0 || x <= 0) break; // stop before pole, since it's already drawn
/* Draw the north and south 'lines of latitude' */
proc(mx - x, my - y, mx2 + x, data);
proc(mx - x, my2 + y, mx2 + x, data);
}
/* Fill in missing pixels for very thin ellipses. (This is caused because
* we always take 1-pixel steps above, and thus might jump past the actual
* ellipse line.)
*/
if (y == 0)
while (x < rx) {
/* proc(mx2 + x, my - 1, data); */
/* proc(mx2 + x, my2 + 1, data); */
/* proc(mx - x, my - 1, data); */
/* proc(mx - x, my2 + 1, data); */
x++;
}
/* Do the 'y direction' part of the arc. */
x = rx;
y = 0;
xa = yy * 2 * rx;
ya = 0;
err = yy / 4 - yy * rx;
for (;;) {
err += ya + xx;
if (err >= 0) {
xa -= yy * 2;
err -= xa;
x--;
}
ya += xx * 2;
y++;
if (ya > xa)
break;
/* proc(mx2 + x, my - y, data); */
/* proc(mx - x, my - y, data); */
/* proc(mx2 + x, my2 + y, data); */
/* proc(mx - x, my2 + y, data); */
proc(mx - x, my - y, mx2 + x, data);
proc(mx - x, my2 + y, mx2 + x, data);
}
/* See comment above. */
if (x == 0)
while (y < ry) {
/* proc(mx - 1, my - y, data); */
/* proc(mx2 + 1, my - y, data); */
/* proc(mx - 1, my2 + y, data); */
/* proc(mx2 + 1, my2 + y, data); */
y++;
}
}
// Algorightm from Allegro (allegro/src/spline.c)