mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 04:19:12 +00:00
algo_ellipse restructure/reimplement
This commit is contained in:
parent
6012f2389f
commit
8549774060
123
src/doc/algo.cpp
123
src/doc/algo.cpp
@ -60,6 +60,42 @@ 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) {
|
||||
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) {
|
||||
// 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) {
|
||||
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.
|
||||
if (rx > ry) {
|
||||
int ex = bresenham_ellipse_error(rx, ry, x, y-1);
|
||||
int ey = bresenham_ellipse_error(rx, ry, x+1, y);
|
||||
int exy = bresenham_ellipse_error(rx, ry, x+1, y-1);
|
||||
if (ex + exy < 0) ++x;
|
||||
if (ey + exy > 0) --y;
|
||||
}
|
||||
else {
|
||||
int ex = bresenham_ellipse_error(rx, ry, x, y+1);
|
||||
int ey = bresenham_ellipse_error(rx, ry, x-1, y);
|
||||
int exy = bresenham_ellipse_error(rx, ry, x-1, y+1);
|
||||
if (ex + exy > 0) --x;
|
||||
if (ey + exy < 0) ++y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function for the ellipse drawing routines. Calculates the
|
||||
points of an ellipse which fits onto the rectangle specified by x1,
|
||||
y1, x2 and y2, and calls the specified routine for each one. The
|
||||
@ -71,17 +107,11 @@ void algo_line(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
|
||||
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 err;
|
||||
int xx, yy;
|
||||
int xa, ya;
|
||||
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;
|
||||
@ -117,84 +147,27 @@ void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc)
|
||||
proc(mx - rx, my2, 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 */
|
||||
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);
|
||||
|
||||
/* 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 <= 0) break; // stop before pole, since it's already drawn
|
||||
|
||||
/* Process pixel */
|
||||
proc(mx2 + x, my - y, data);
|
||||
proc(mx - x, my - y, data);
|
||||
proc(mx2 + x, my2 + y, data);
|
||||
proc(mx - x, my2 + y, 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);
|
||||
}
|
||||
|
||||
/* 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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void algo_ellipsefill(int x1, int y1, int x2, int y2, void *data, AlgoHLine proc)
|
||||
{
|
||||
int mx, my, rx, ry;
|
||||
|
Loading…
x
Reference in New Issue
Block a user