Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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

struct Lline
{
        Point                   p0;
        Point                   p1;
        Point                   delta;
        int                     end0;
        int                     end1;
        int                     radius;
        Point                   sp;
        Memlayer                *dstlayer;
        Memimage        *src;
        int                     op;
};

static void llineop(Memimage*, Rectangle, Rectangle, void*, int);

static
void
_memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
{
        Rectangle r;
        struct Lline ll;
        Point d;
        int srcclipped;
        Memlayer *dl;

        if(radius < 0)
                return;
        if(src->layer)  /* can't draw line with layered source */
                return;
        srcclipped = 0;

   Top:
        dl = dst->layer;
        if(dl == nil){
                _memimageline(dst, p0, p1, end0, end1, radius, src, sp, clipr, op);
                return;
        }
        if(!srcclipped){
                d = subpt(sp, p0);
                if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
                        return;
                if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
                        return;
                srcclipped = 1;
        }

        /* dst is known to be a layer */
        p0.x += dl->delta.x;
        p0.y += dl->delta.y;
        p1.x += dl->delta.x;
        p1.y += dl->delta.y;
        clipr.min.x += dl->delta.x;
        clipr.min.y += dl->delta.y;
        clipr.max.x += dl->delta.x;
        clipr.max.y += dl->delta.y;
        if(dl->clear){
                dst = dst->layer->screen->image;
                goto Top;
        }

        /* XXX */
        /* this is not the correct set of tests */
//      if(log2[dst->depth] != log2[src->depth] || log2[dst->depth]!=3)
//              return;

        /* can't use sutherland-cohen clipping because lines are wide */
        r = memlinebbox(p0, p1, end0, end1, radius);
        /*
         * r is now a bounding box for the line;
         * use it as a clipping rectangle for subdivision
         */
        if(rectclip(&r, clipr) == 0)
                return;
        ll.p0 = p0;
        ll.p1 = p1;
        ll.end0 = end0;
        ll.end1 = end1;
        ll.sp = sp;
        ll.dstlayer = dst->layer;
        ll.src = src;
        ll.radius = radius;
        ll.delta = dl->delta;
        ll.op = op;
        _memlayerop(llineop, dst, r, r, &ll);
}

static
void
llineop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
{
        struct Lline *ll;
        Point p0, p1;

        USED(screenr.min.x);
        ll = etc;
        if(insave && ll->dstlayer->save==nil)
                return;
        if(!rectclip(&clipr, screenr))
                return;
        if(insave){
                p0 = subpt(ll->p0, ll->delta);
                p1 = subpt(ll->p1, ll->delta);
                clipr = rectsubpt(clipr, ll->delta);
        }else{
                p0 = ll->p0;
                p1 = ll->p1;
        }
        _memline(dst, p0, p1, ll->end0, ll->end1, ll->radius, ll->src, ll->sp, clipr, ll->op);
}

void
memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
{
        _memline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
}