Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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}
};

static
Point p00;

/*
 * 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(a < 0)
                a = -a;
        if(b < 0)
                b = -b;
        w = t;
        if(w < 0)
                w = 0;
        alpha = -alpha;         /* compensate for upside-down coords */
        phi = -phi;
        beta = alpha + phi;
        if(phi < 0){
                tmp = alpha;
                alpha = beta;
                beta = tmp;
                phi = -phi;
        }
        if(phi >= 360){
                memellipse(dst, c, a, b, t, src, sp, op);
                return;
        }
        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
                */
        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, p00, S);
        figure = allocmemimage(rect, GREY1);
        if(figure == nil)
                goto Return;
        memfillcolor(figure, DTransparent);
        memellipse(figure, p00, a, b, t, memopaque, p00, 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(p00, c), op);

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