[AD] Ellipse errata et al. |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
Here's a patch for the ellipse drawing function I submitted awhile ago, I mainly removed the
spurious requirement for the radius to be >= 1. Now zero radii are allowable (corresponding to
variations on the vertical/horizontal line theme).
Also, I replaced the _soft_ellipsefill function to use the new ellipse algorithm. This is just so
that the do_ellipse and ellipsefill have the same outline.
Again, this is only meant for the 4.3.10+ branch.
Regards,
SiegeLord
Index: src/gfx.c
===================================================================
--- src/gfx.c (revision 10260)
+++ src/gfx.c (working copy)
@@ -1104,9 +1104,10 @@
float two_b_sq;
float stopping_x;
float stopping_y;
+ int midway_x;
- rx = MAX(rx0, 1);
- ry = MAX(ry0, 1);
+ rx = MAX(rx0, 0);
+ ry = MAX(ry0, 0);
two_a_sq = 2 * rx * rx;
two_b_sq = 2 * ry * ry;
@@ -1124,47 +1125,71 @@
stopping_x = two_b_sq * rx;
stopping_y = 0.0;
- /* First set of points, y' > -1. */
- while (stopping_x >= stopping_y) {
+ /* First set of points */
+ while (y <= ry) {
proc(bmp, ix + x, iy + y, d);
- proc(bmp, ix - x, iy + y, d);
+ if (x != 0) {
+ proc(bmp, ix - x, iy + y, d);
+ }
if (y != 0) {
proc(bmp, ix + x, iy - y, d);
- proc(bmp, ix - x, iy - y, d);
+ if (x != 0) {
+ proc(bmp, ix - x, iy - y, d);
+ }
}
-
+
y++;
stopping_y += two_a_sq;
ellipse_error += y_change;
y_change += two_a_sq;
+ midway_x = x;
+
+ if(stopping_x < stopping_y && x > 1) {
+ break;
+ }
if ((2.0f * ellipse_error + x_change) > 0.0) {
- x--;
- stopping_x -= two_b_sq;
- ellipse_error += x_change;
- x_change += two_b_sq;
+ if(x) {
+ x--;
+ stopping_x -= two_b_sq;
+ ellipse_error += x_change;
+ x_change += two_b_sq;
+ }
}
}
+
+ /* To do the other half of the ellipse we reset to the
+ * top of it, and iterate in the opposite direction
+ */
+ x = 0;
+ y = ry;
- /* First point set is done; start the second set of points. We just flip
- * the order of iteration, and continue from where we left off.
- */
- while (x >= 0) {
+ x_change = ry * ry;
+ y_change = rx * rx * (1 - 2 * ry);
+ ellipse_error = 0.0;
+
+ while (x < midway_x) {
proc(bmp, ix + x, iy + y, d);
- proc(bmp, ix + x, iy - y, d);
if (x != 0) {
- proc(bmp, ix - x, iy - y, d);
proc(bmp, ix - x, iy + y, d);
}
+ if (y != 0) {
+ proc(bmp, ix + x, iy - y, d);
+ if (x != 0) {
+ proc(bmp, ix - x, iy - y, d);
+ }
+ }
- x--;
+ x++;
ellipse_error += x_change;
x_change += two_b_sq;
- if ((2.0f * ellipse_error + y_change) < 0.0) {
- y++;
- ellipse_error += y_change;
- y_change += two_a_sq;
+ if ((2.0f * ellipse_error + y_change) > 0.0) {
+ if(y) {
+ y--;
+ ellipse_error += y_change;
+ y_change += two_a_sq;
+ }
}
}
}
@@ -1210,117 +1235,135 @@
/* ellipsefill:
* Draws a filled ellipse.
*/
-void _soft_ellipsefill(BITMAP *bmp, int x, int y, int rx, int ry, int color)
+void _soft_ellipsefill(BITMAP *bmp, int ix, int iy, int rx0, int ry0, int color)
{
- int ix, iy;
- int a, b, c, d;
- int da, db, dc, dd;
- int na, nb, nc, nd;
+ int rx, ry;
+ int x, y;
+ float x_change;
+ float y_change;
+ float ellipse_error;
+ float two_a_sq;
+ float two_b_sq;
+ float stopping_x;
+ float stopping_y;
+ int midway_x;
int clip, sx, sy, dx, dy;
+ int last_drawn_y;
+ int old_y;
ASSERT(bmp);
+ rx = MAX(rx0, 0);
+ ry = MAX(ry0, 0);
+
if (bmp->clip) {
- sx = x-rx-1;
- sy = y-ry-1;
- dx = x+rx+1;
- dy = y+ry+1;
+ sx = ix - rx - 1;
+ sy = iy - ry - 1;
+ dx = ix + rx + 1;
+ dy = iy + ry + 1;
if ((sx >= bmp->cr) || (sy >= bmp->cb) || (dx < bmp->cl) || (dy < bmp->ct))
- return;
+ return;
if ((sx >= bmp->cl) && (sy >= bmp->ct) && (dx < bmp->cr) && (dy < bmp->cb))
- bmp->clip = FALSE;
+ bmp->clip = FALSE;
clip = TRUE;
}
else
clip = FALSE;
-
- if (rx < 1)
- rx = 1;
-
- if (ry < 1)
- ry = 1;
-
+
acquire_bitmap(bmp);
- if (rx > ry) {
- dc = -1;
- dd = 0xFFFF;
- ix = 0;
- iy = rx * 64;
- na = 0;
- nb = (iy + 32) >> 6;
- nc = 0;
- nd = (nb * ry) / rx;
+ two_a_sq = 2 * rx * rx;
+ two_b_sq = 2 * ry * ry;
- do {
- a = na;
- b = nb;
- c = nc;
- d = nd;
+ x = rx;
+ y = 0;
- ix = ix + (iy / rx);
- iy = iy - (ix / rx);
- na = (ix + 32) >> 6;
- nb = (iy + 32) >> 6;
- nc = (na * ry) / rx;
- nd = (nb * ry) / rx;
+ x_change = ry * ry * (1 - 2 * rx);
+ y_change = rx * rx;
+ ellipse_error = 0.0;
- if ((c > dc) && (c < dd)) {
- bmp->vtable->hfill(bmp, x-b, y+c, x+b, color);
- if (c)
- bmp->vtable->hfill(bmp, x-b, y-c, x+b, color);
- dc = c;
- }
+ /* The following two variables decide when to stop. It's easier than
+ * solving for this explicitly.
+ */
+ stopping_x = two_b_sq * rx;
+ stopping_y = 0.0;
- if ((d < dd) && (d > dc)) {
- bmp->vtable->hfill(bmp, x-a, y+d, x+a, color);
- bmp->vtable->hfill(bmp, x-a, y-d, x+a, color);
- dd = d;
- }
+ /* First set of points */
+ while (y <= ry) {
+ bmp->vtable->hfill(bmp, ix - x, iy + y, ix + x, color);
+ if(y) {
+ bmp->vtable->hfill(bmp, ix - x, iy - y, ix + x, color);
+ }
+
+ y++;
+ stopping_y += two_a_sq;
+ ellipse_error += y_change;
+ y_change += two_a_sq;
+ midway_x = x;
+
+ if(stopping_x < stopping_y && x > 1) {
+ break;
+ }
- } while(b > a);
- }
- else {
- da = -1;
- db = 0xFFFF;
- ix = 0;
- iy = ry * 64;
- na = 0;
- nb = (iy + 32) >> 6;
- nc = 0;
- nd = (nb * rx) / ry;
+ if ((2.0f * ellipse_error + x_change) > 0.0) {
+ if(x) {
+ x--;
+ stopping_x -= two_b_sq;
+ ellipse_error += x_change;
+ x_change += two_b_sq;
+ }
+ }
+ }
+
+ last_drawn_y = y - 1;
+
+ /* To do the other half of the ellipse we reset to the
+ * top of it, and iterate in the opposite direction
+ * until we reach the place we stopped at last time
+ */
+ x = 0;
+ y = ry;
- do {
- a = na;
- b = nb;
- c = nc;
- d = nd;
+ x_change = ry * ry;
+ y_change = rx * rx * (1 - 2 * ry);
+ ellipse_error = 0.0;
- ix = ix + (iy / ry);
- iy = iy - (ix / ry);
- na = (ix + 32) >> 6;
- nb = (iy + 32) >> 6;
- nc = (na * rx) / ry;
- nd = (nb * rx) / ry;
+ old_y = y;
- if ((a > da) && (a < db)) {
- bmp->vtable->hfill(bmp, x-d, y+a, x+d, color);
- if (a)
- bmp->vtable->hfill(bmp, x-d, y-a, x+d, color);
- da = a;
- }
+ while (x < midway_x) {
+ if(old_y != y) {
+ bmp->vtable->hfill(bmp, ix - x + 1, iy + old_y, ix + x - 1, color);
+ if(old_y) {
+ bmp->vtable->hfill(bmp, ix - x + 1, iy - old_y, ix + x - 1, color);
+ }
+ }
- if ((b < db) && (b > da)) {
- bmp->vtable->hfill(bmp, x-c, y+b, x+c, color);
- bmp->vtable->hfill(bmp, x-c, y-b, x+c, color);
- db = b;
- }
+ x++;
+ ellipse_error += x_change;
+ x_change += two_b_sq;
+ old_y = y;
- } while(b > a);
+ if ((2.0f * ellipse_error + y_change) > 0.0) {
+ if(y) {
+ y--;
+ ellipse_error += y_change;
+ y_change += two_a_sq;
+ }
+ }
}
-
+
+ /* On occasion, a gap appears between the middle and upper halves
+ * This 'afterthought' fills it in
+ */
+ if(old_y != last_drawn_y) {
+ bmp->vtable->hfill(bmp, ix - x + 1, iy + old_y, ix + x - 1, color);
+ if(old_y) {
+ bmp->vtable->hfill(bmp, ix - x + 1, iy - old_y, ix + x - 1, color);
+ }
+ }
+
release_bitmap(bmp);
bmp->clip = clip;