123 lines
2.5 KiB
C
123 lines
2.5 KiB
C
|
#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);
|
||
|
}
|