The Allegro Wiki is migrating to github at https://github.com/liballeg/allegro_wiki/wiki

NewAPI/Primitives/al draw circle

From Allegro Wiki
Jump to: navigation, search

Planned variations: Just filled and outlined so far. In theory, a gradient one can be made as well. A thick outlined circle is also feasible.

Outlined Circle

Goals:

  • Use the Bresenham criterion for the pixel placement
    • When x and y and r are integers, the output should be precisely like do_circle from allegro 4.4 branch - Done

Problems with the code so far:

  • Circle loses its symmetry when not predicted by the location of the circle... e.g. a circle at (0, 0.5) should be symmetrical around the y axis, but this algorithm creates an asymmetrical one

Potential fixes:

  • Given my experience with the line drawer, it seems that a good approach at this would be to switch the order of the worker macros to do their operations in this order
    1. Handle the non-driving axis first (the error check module)
    2. Plot point
    3. Handle the driving axis
  • That seemed to work well with the line drawer (basically, it fixed all of the problems instantaneously), so perhaps similar success can be had here

A4 test code:


<highlightSyntax language="cpp"> void al_do_circle(BITMAP *bmp, float x, float y, float radius, int d, void (*proc)(BITMAP *, int, int, int)) {

   if(radius < 1)
   {
       proc(bmp, x, y, d);
       return;
   }
   int X, Y;//initial int values
   float fX, fY;//the floating point versions of the above
   float a, b;//fractional differences between the integer center, and the the float center
   int ix, iy;//integer center coordinates
   float xchange, ychange;
   
   ix = floorf(x);
   iy = floorf(y);
   a = x - float(ix);
   b = y - float(iy);
   

#define YDEP(whiletest, Xsign, Comp, Ysign) \ while(whiletest) \ { \ proc(bmp, X + ix, Y + iy, d); \ Y += Ysign 1; \ error += ychange; \ ychange += 2.0; \ if(2.0 * error + xchange Comp 0) \ { \ X += Xsign 1; \ error += xchange; \ xchange += 2.0; \ } \ }

#define XDEP(whiletest, Xsign, Comp, Ysign) \ while(whiletest) \ { \ proc(bmp, X + ix, Y + iy, d); \ X += Xsign 1; \ error += xchange; \ xchange += 2.0; \ if(2.0 * error + ychange Comp 0) \ { \ Y += Ysign 1; \ error += ychange; \ ychange += 2.0; \ } \ }

X = 0; Y = (int)floorf(-sqrtf(radius * radius - (float(ix) - x) * (float(ix) - x)) + y + 0.5f) - iy;

fX = X; fY = Y;

float error = fX * fX + fY * fY - radius * radius + a * (a - 2 * fX) + b * (b - 2 * fY);

xchange = 1.0 + 2.0 * (fX - a); ychange = 1.0 + 2.0 * (fY - b);

XDEP(X < -Y, +, >, +) YDEP(Y < 0, +, <, +)

fX = X; fY = Y; xchange = 1.0 - 2.0 * (fX - a); ychange = 1.0 + 2.0 * (fY - b);

YDEP(X > Y, -, >, +) XDEP(X > 0, -, <, +)

fX = X; fY = Y; xchange = 1.0 - 2.0 * (fX - a); ychange = 1.0 - 2.0 * (fY - b);

XDEP(Y > -X, -, >, -) YDEP(Y > 0, -, <, -)

fX = X; fY = Y; xchange = 1.0 + 2.0 * (fX - a); ychange = 1.0 - 2.0 * (fY - b);

YDEP(-Y < -X, +, >, -) XDEP(X < 0, +, <, -)

#undef XDEP #undef YDEP } </highlightSyntax>

Filled Circle

  • Use the Bresenham criterion for the pixel placement
    • When x and y and r are integers, the output should be precisely like circlefill from allegro 4.4 branch