#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>

/*
* elarc(dst,c,a,b,t,src,sp,alpha,phi)
*   draws the part of an ellipse between rays at angles alpha and alpha+phi
*   measured counterclockwise from the positive x axis. other
*   arguments are as for ellipse(dst,c,a,b,t,src,sp)
*/

enum
{
       R, T, L, B      /* right, top, left, bottom */
};

static
Point corners[] = {
       {1,1},
       {-1,1},
       {-1,-1},
       {1,-1}
};

/*
* make a "wedge" mask covering the desired angle and contained in
* a surrounding square; draw a full ellipse; intersect that with the
* wedge to make a mask through which to copy src to dst.
*/
void
memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
{
       int i, w, beta, tmp, c1, c2, m, m1;
       Rectangle rect;
       Point p,        bnd[8];
       Memimage *wedge, *figure, *mask;

       if(phi == 0)
               return;
       if(phi <= -360 || phi >= 360){
               memellipse(dst, c, a, b, t, src, sp, op);
               return;
       }
       alpha %= 360;
       alpha = -alpha;         /* compensate for upside-down coords */
       phi = -phi;
       beta = alpha + phi;
       if(phi < 0){
               tmp = alpha;
               alpha = beta;
               beta = tmp;
               phi = -phi;
       }
       while(alpha < 0)
               alpha += 360;
       while(beta < 0)
               beta += 360;
       c1 = alpha/90 & 3;      /* number of nearest corner */
       c2 = beta/90 & 3;
               /*
                * icossin returns point at radius ICOSSCALE.
                * multiplying by m1 moves it outside the ellipse
               */

       if(a < 0)
               a = -a;
       if(b < 0)
               b = -b;
       w = t;
       if(w < 0)
               w = 0;

       rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
       m = rect.max.x; /* inradius of bounding square */
       if(m < rect.max.y)
               m = rect.max.y;
       m1 = (m+ICOSSCALE-1) >> 10;
       m = m1 << 10;           /* assure m1*cossin is inside */
       i = 0;
       bnd[i++] = Pt(0,0);
       icossin(alpha, &p.x, &p.y);
       bnd[i++] = mulpt(p, m1);
       for(;;) {
               bnd[i++] = mulpt(corners[c1], m);
               if(c1==c2 && phi<180)
                       break;
               c1 = (c1+1) & 3;
               phi -= 90;
       }
       icossin(beta, &p.x, &p.y);
       bnd[i++] = mulpt(p, m1);

       figure = nil;
       mask = nil;
       wedge = allocmemimage(rect, GREY1);
       if(wedge == nil)
               goto Return;
       memfillcolor(wedge, DTransparent);
       memfillpoly(wedge, bnd, i, ~0, memopaque, ZP, S);
       figure = allocmemimage(rect, GREY1);
       if(figure == nil)
               goto Return;
       memfillcolor(figure, DTransparent);
       memellipse(figure, ZP, a, b, t, memopaque, ZP, S);
       mask = allocmemimage(rect, GREY1);
       if(mask == nil)
               goto Return;
       memfillcolor(mask, DTransparent);
       memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
       c = subpt(c, dst->r.min);
       memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(ZP, c), op);

   Return:
       freememimage(wedge);
       freememimage(figure);
       freememimage(mask);
}