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