]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmemlayer/draw.c
c352a0b2c3fbceaab100c4d5af5f7ad829dd0921
[plan9front.git] / sys / src / libmemlayer / draw.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <memlayer.h>
6
7 struct Draw
8 {
9         Point   deltas;
10         Point   deltam;
11         Memlayer                *dstlayer;
12         Memimage        *src;
13         Memimage        *mask;
14         int     op;
15 };
16
17 static
18 void
19 ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
20 {
21         struct Draw *d;
22         Point p0, p1;
23         Rectangle oclipr, srcr, r, mr;
24         int ok;
25
26         d = etc;
27         if(insave && d->dstlayer->save==nil)
28                 return;
29
30         p0 = addpt(screenr.min, d->deltas);
31         p1 = addpt(screenr.min, d->deltam);
32
33         if(insave){
34                 r = rectsubpt(screenr, d->dstlayer->delta);
35                 clipr = rectsubpt(clipr, d->dstlayer->delta);
36         }else
37                 r = screenr;
38
39         /* now in logical coordinates */
40
41         /* clipr may have narrowed what we should draw on, so clip if necessary */
42         if(!rectinrect(r, clipr)){
43                 oclipr = dst->clipr;
44                 dst->clipr = clipr;
45                 ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
46                 dst->clipr = oclipr;
47                 if(!ok)
48                         return;
49         }
50         memdraw(dst, r, d->src, p0, d->mask, p1, d->op);
51 }
52
53 void
54 memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
55 {
56         struct Draw d;
57         Rectangle srcr, tr, mr;
58         Memlayer *dl, *sl;
59
60         if(drawdebug)
61                 iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1);
62
63         if(mask == nil)
64                 mask = memopaque;
65
66         if(mask->layer){
67 if(drawdebug)   iprint("mask->layer != nil\n");
68                 return; /* too hard, at least for now */
69         }
70
71     Top:
72         if(dst->layer==nil && src->layer==nil){
73                 memimagedraw(dst, r, src, p0, mask, p1, op);
74                 return;
75         }
76
77         if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){
78 if(drawdebug)   iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr);
79                 return;
80         }
81
82         /*
83          * Convert to screen coordinates.
84          */
85         dl = dst->layer;
86         if(dl != nil){
87                 r.min.x += dl->delta.x;
88                 r.min.y += dl->delta.y;
89                 r.max.x += dl->delta.x;
90                 r.max.y += dl->delta.y;
91         }
92     Clearlayer:
93         if(dl!=nil && dl->clear){
94                 if(src == dst){
95                         p0.x += dl->delta.x;
96                         p0.y += dl->delta.y;
97                         src = dl->screen->image;
98                 }
99                 dst = dl->screen->image;
100                 goto Top;
101         }
102
103         sl = src->layer;
104         if(sl != nil){
105                 p0.x += sl->delta.x;
106                 p0.y += sl->delta.y;
107                 srcr.min.x += sl->delta.x;
108                 srcr.min.y += sl->delta.y;
109                 srcr.max.x += sl->delta.x;
110                 srcr.max.y += sl->delta.y;
111         }
112
113         /*
114          * Now everything is in screen coordinates.
115          * mask is an image.  dst and src are images or obscured layers.
116          */
117
118         /*
119          * if dst and src are the same layer, just draw in save area and expose.
120          */
121         if(dl!=nil && dst==src){
122                 if(dl->save == nil)
123                         return; /* refresh function makes this case unworkable */
124                 if(rectXrect(r, srcr)){
125                         tr = r;
126                         if(srcr.min.x < tr.min.x){
127                                 p1.x += tr.min.x - srcr.min.x;
128                                 tr.min.x = srcr.min.x;
129                         }
130                         if(srcr.min.y < tr.min.y){
131                                 p1.y += tr.min.x - srcr.min.x;
132                                 tr.min.y = srcr.min.y;
133                         }
134                         if(srcr.max.x > tr.max.x)
135                                 tr.max.x = srcr.max.x;
136                         if(srcr.max.y > tr.max.y)
137                                 tr.max.y = srcr.max.y;
138                         memlhide(dst, tr);
139                 }else{
140                         memlhide(dst, r);
141                         memlhide(dst, srcr);
142                 }
143                 memdraw(dl->save, rectsubpt(r, dl->delta), dl->save,
144                         subpt(srcr.min, src->layer->delta), mask, p1, op);
145                 memlexpose(dst, r);
146                 return;
147         }
148
149         if(sl){
150                 if(sl->clear){
151                         src = sl->screen->image;
152                         if(dl != nil){
153                                 r.min.x -= dl->delta.x;
154                                 r.min.y -= dl->delta.y;
155                                 r.max.x -= dl->delta.x;
156                                 r.max.y -= dl->delta.y;
157                         }
158                         goto Top;
159                 }
160                 /* relatively rare case; use save area */
161                 if(sl->save == nil)
162                         return; /* refresh function makes this case unworkable */
163                 memlhide(src, srcr);
164                 /* convert back to logical coordinates */
165                 p0.x -= sl->delta.x;
166                 p0.y -= sl->delta.y;
167                 srcr.min.x -= sl->delta.x;
168                 srcr.min.y -= sl->delta.y;
169                 srcr.max.x -= sl->delta.x;
170                 srcr.max.y -= sl->delta.y;
171                 src = src->layer->save;
172         }
173
174         /*
175          * src is now an image.  dst may be an image or a clear layer
176          */
177         if(dst->layer==nil)
178                 goto Top;
179         if(dst->layer->clear)
180                 goto Clearlayer;
181
182         /*
183          * dst is an obscured layer
184          */
185         d.deltas = subpt(p0, r.min);
186         d.deltam = subpt(p1, r.min);
187         d.dstlayer = dl;
188         d.src = src;
189         d.op = op;
190         d.mask = mask;
191         _memlayerop(ldrawop, dst, r, r, &d);
192 }