aboutsummaryrefslogtreecommitdiff
path: root/src/libdraw/ml-line.c
blob: 8c09a53592f42b750bc77df0bd156bb543c53b1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#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);
}