diff options
Diffstat (limited to 'src/libdraw/ml-draw.c')
-rw-r--r-- | src/libdraw/ml-draw.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/libdraw/ml-draw.c b/src/libdraw/ml-draw.c new file mode 100644 index 00000000..c352a0b2 --- /dev/null +++ b/src/libdraw/ml-draw.c @@ -0,0 +1,192 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <memdraw.h> +#include <memlayer.h> + +struct Draw +{ + Point deltas; + Point deltam; + Memlayer *dstlayer; + Memimage *src; + Memimage *mask; + int op; +}; + +static +void +ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave) +{ + struct Draw *d; + Point p0, p1; + Rectangle oclipr, srcr, r, mr; + int ok; + + d = etc; + if(insave && d->dstlayer->save==nil) + return; + + p0 = addpt(screenr.min, d->deltas); + p1 = addpt(screenr.min, d->deltam); + + if(insave){ + r = rectsubpt(screenr, d->dstlayer->delta); + clipr = rectsubpt(clipr, d->dstlayer->delta); + }else + r = screenr; + + /* now in logical coordinates */ + + /* clipr may have narrowed what we should draw on, so clip if necessary */ + if(!rectinrect(r, clipr)){ + oclipr = dst->clipr; + dst->clipr = clipr; + ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr); + dst->clipr = oclipr; + if(!ok) + return; + } + memdraw(dst, r, d->src, p0, d->mask, p1, d->op); +} + +void +memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) +{ + struct Draw d; + Rectangle srcr, tr, mr; + Memlayer *dl, *sl; + + if(drawdebug) + iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1); + + if(mask == nil) + mask = memopaque; + + if(mask->layer){ +if(drawdebug) iprint("mask->layer != nil\n"); + return; /* too hard, at least for now */ + } + + Top: + if(dst->layer==nil && src->layer==nil){ + memimagedraw(dst, r, src, p0, mask, p1, op); + return; + } + + if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){ +if(drawdebug) iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr); + return; + } + + /* + * Convert to screen coordinates. + */ + dl = dst->layer; + if(dl != nil){ + r.min.x += dl->delta.x; + r.min.y += dl->delta.y; + r.max.x += dl->delta.x; + r.max.y += dl->delta.y; + } + Clearlayer: + if(dl!=nil && dl->clear){ + if(src == dst){ + p0.x += dl->delta.x; + p0.y += dl->delta.y; + src = dl->screen->image; + } + dst = dl->screen->image; + goto Top; + } + + sl = src->layer; + if(sl != nil){ + p0.x += sl->delta.x; + p0.y += sl->delta.y; + srcr.min.x += sl->delta.x; + srcr.min.y += sl->delta.y; + srcr.max.x += sl->delta.x; + srcr.max.y += sl->delta.y; + } + + /* + * Now everything is in screen coordinates. + * mask is an image. dst and src are images or obscured layers. + */ + + /* + * if dst and src are the same layer, just draw in save area and expose. + */ + if(dl!=nil && dst==src){ + if(dl->save == nil) + return; /* refresh function makes this case unworkable */ + if(rectXrect(r, srcr)){ + tr = r; + if(srcr.min.x < tr.min.x){ + p1.x += tr.min.x - srcr.min.x; + tr.min.x = srcr.min.x; + } + if(srcr.min.y < tr.min.y){ + p1.y += tr.min.x - srcr.min.x; + tr.min.y = srcr.min.y; + } + if(srcr.max.x > tr.max.x) + tr.max.x = srcr.max.x; + if(srcr.max.y > tr.max.y) + tr.max.y = srcr.max.y; + memlhide(dst, tr); + }else{ + memlhide(dst, r); + memlhide(dst, srcr); + } + memdraw(dl->save, rectsubpt(r, dl->delta), dl->save, + subpt(srcr.min, src->layer->delta), mask, p1, op); + memlexpose(dst, r); + return; + } + + if(sl){ + if(sl->clear){ + src = sl->screen->image; + if(dl != nil){ + r.min.x -= dl->delta.x; + r.min.y -= dl->delta.y; + r.max.x -= dl->delta.x; + r.max.y -= dl->delta.y; + } + goto Top; + } + /* relatively rare case; use save area */ + if(sl->save == nil) + return; /* refresh function makes this case unworkable */ + memlhide(src, srcr); + /* convert back to logical coordinates */ + p0.x -= sl->delta.x; + p0.y -= sl->delta.y; + srcr.min.x -= sl->delta.x; + srcr.min.y -= sl->delta.y; + srcr.max.x -= sl->delta.x; + srcr.max.y -= sl->delta.y; + src = src->layer->save; + } + + /* + * src is now an image. dst may be an image or a clear layer + */ + if(dst->layer==nil) + goto Top; + if(dst->layer->clear) + goto Clearlayer; + + /* + * dst is an obscured layer + */ + d.deltas = subpt(p0, r.min); + d.deltam = subpt(p1, r.min); + d.dstlayer = dl; + d.src = src; + d.op = op; + d.mask = mask; + _memlayerop(ldrawop, dst, r, r, &d); +} |