Blame


1 24c02865 2005-01-04 devnull /*
2 24c02865 2005-01-04 devnull * Rotate an image 180° in O(log Dx + log Dy)
3 24c02865 2005-01-04 devnull * draw calls, using an extra buffer the same size
4 24c02865 2005-01-04 devnull * as the image.
5 24c02865 2005-01-04 devnull *
6 24c02865 2005-01-04 devnull * The basic concept is that you can invert an array by
7 24c02865 2005-01-04 devnull * inverting the top half, inverting the bottom half, and
8 24c02865 2005-01-04 devnull * then swapping them.
9 fa325e9b 2020-01-10 cross *
10 24c02865 2005-01-04 devnull * This is usually overkill, but it speeds up slow remote
11 24c02865 2005-01-04 devnull * connections quite a bit.
12 24c02865 2005-01-04 devnull */
13 24c02865 2005-01-04 devnull
14 24c02865 2005-01-04 devnull #include <u.h>
15 24c02865 2005-01-04 devnull #include <libc.h>
16 24c02865 2005-01-04 devnull #include <bio.h>
17 24c02865 2005-01-04 devnull #include <draw.h>
18 05a4d855 2007-03-26 devnull #include <thread.h>
19 17157e4a 2006-03-20 devnull #include <cursor.h>
20 24c02865 2005-01-04 devnull #include "page.h"
21 24c02865 2005-01-04 devnull
22 24c02865 2005-01-04 devnull int ndraw = 0;
23 24c02865 2005-01-04 devnull
24 24c02865 2005-01-04 devnull enum {
25 24c02865 2005-01-04 devnull Xaxis,
26 05a4d855 2007-03-26 devnull Yaxis,
27 24c02865 2005-01-04 devnull };
28 24c02865 2005-01-04 devnull
29 24c02865 2005-01-04 devnull static void reverse(Image*, Image*, int);
30 24c02865 2005-01-04 devnull static void shuffle(Image*, Image*, int, int, Image*, int, int);
31 24c02865 2005-01-04 devnull static void writefile(char *name, Image *im, int gran);
32 24c02865 2005-01-04 devnull static void halvemaskdim(Image*);
33 24c02865 2005-01-04 devnull static void swapranges(Image*, Image*, int, int, int, int);
34 24c02865 2005-01-04 devnull
35 24c02865 2005-01-04 devnull /*
36 24c02865 2005-01-04 devnull * Rotate the image 180° by reflecting first
37 24c02865 2005-01-04 devnull * along the X axis, and then along the Y axis.
38 24c02865 2005-01-04 devnull */
39 24c02865 2005-01-04 devnull void
40 24c02865 2005-01-04 devnull rot180(Image *img)
41 24c02865 2005-01-04 devnull {
42 24c02865 2005-01-04 devnull Image *tmp;
43 24c02865 2005-01-04 devnull
44 24c02865 2005-01-04 devnull tmp = xallocimage(display, img->r, img->chan, 0, DNofill);
45 24c02865 2005-01-04 devnull if(tmp == nil)
46 24c02865 2005-01-04 devnull return;
47 24c02865 2005-01-04 devnull
48 24c02865 2005-01-04 devnull reverse(img, tmp, Xaxis);
49 24c02865 2005-01-04 devnull reverse(img, tmp, Yaxis);
50 24c02865 2005-01-04 devnull
51 24c02865 2005-01-04 devnull freeimage(tmp);
52 24c02865 2005-01-04 devnull }
53 24c02865 2005-01-04 devnull
54 24c02865 2005-01-04 devnull Image *mtmp;
55 24c02865 2005-01-04 devnull
56 24c02865 2005-01-04 devnull static void
57 24c02865 2005-01-04 devnull reverse(Image *img, Image *tmp, int axis)
58 24c02865 2005-01-04 devnull {
59 24c02865 2005-01-04 devnull Image *mask;
60 24c02865 2005-01-04 devnull Rectangle r;
61 24c02865 2005-01-04 devnull int i, d;
62 24c02865 2005-01-04 devnull
63 24c02865 2005-01-04 devnull /*
64 24c02865 2005-01-04 devnull * We start by swapping large chunks at a time.
65 24c02865 2005-01-04 devnull * The chunk size should be the largest power of
66 24c02865 2005-01-04 devnull * two that fits in the dimension.
67 24c02865 2005-01-04 devnull */
68 24c02865 2005-01-04 devnull d = axis==Xaxis ? Dx(img) : Dy(img);
69 24c02865 2005-01-04 devnull for(i = 1; i*2 <= d; i *= 2)
70 24c02865 2005-01-04 devnull ;
71 24c02865 2005-01-04 devnull
72 24c02865 2005-01-04 devnull r = axis==Xaxis ? Rect(0,0, i,100) : Rect(0,0, 100,i);
73 24c02865 2005-01-04 devnull mask = xallocimage(display, r, GREY1, 1, DTransparent);
74 24c02865 2005-01-04 devnull mtmp = xallocimage(display, r, GREY1, 1, DTransparent);
75 24c02865 2005-01-04 devnull
76 24c02865 2005-01-04 devnull /*
77 24c02865 2005-01-04 devnull * Now color the bottom (or left) half of the mask opaque.
78 24c02865 2005-01-04 devnull */
79 24c02865 2005-01-04 devnull if(axis==Xaxis)
80 24c02865 2005-01-04 devnull r.max.x /= 2;
81 24c02865 2005-01-04 devnull else
82 24c02865 2005-01-04 devnull r.max.y /= 2;
83 24c02865 2005-01-04 devnull
84 24c02865 2005-01-04 devnull draw(mask, r, display->opaque, nil, ZP);
85 24c02865 2005-01-04 devnull writefile("mask", mask, i);
86 24c02865 2005-01-04 devnull
87 24c02865 2005-01-04 devnull /*
88 24c02865 2005-01-04 devnull * Shuffle will recur, shuffling the pieces as necessary
89 24c02865 2005-01-04 devnull * and making the mask a finer and finer grating.
90 24c02865 2005-01-04 devnull */
91 24c02865 2005-01-04 devnull shuffle(img, tmp, axis, d, mask, i, 0);
92 24c02865 2005-01-04 devnull
93 24c02865 2005-01-04 devnull freeimage(mask);
94 24c02865 2005-01-04 devnull }
95 24c02865 2005-01-04 devnull
96 24c02865 2005-01-04 devnull /*
97 24c02865 2005-01-04 devnull * Shuffle the image by swapping pieces of size maskdim.
98 24c02865 2005-01-04 devnull */
99 24c02865 2005-01-04 devnull static void
100 24c02865 2005-01-04 devnull shuffle(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int maskdim)
101 24c02865 2005-01-04 devnull {
102 24c02865 2005-01-04 devnull int slop;
103 24c02865 2005-01-04 devnull
104 24c02865 2005-01-04 devnull if(maskdim == 0)
105 24c02865 2005-01-04 devnull return;
106 24c02865 2005-01-04 devnull
107 24c02865 2005-01-04 devnull /*
108 24c02865 2005-01-04 devnull * Figure out how much will be left over that needs to be
109 24c02865 2005-01-04 devnull * shifted specially to the bottom.
110 24c02865 2005-01-04 devnull */
111 24c02865 2005-01-04 devnull slop = imgdim % maskdim;
112 24c02865 2005-01-04 devnull
113 24c02865 2005-01-04 devnull /*
114 24c02865 2005-01-04 devnull * Swap adjacent grating lines as per mask.
115 24c02865 2005-01-04 devnull */
116 24c02865 2005-01-04 devnull swapadjacent(img, tmp, axis, imgdim - slop, mask, maskdim);
117 24c02865 2005-01-04 devnull
118 24c02865 2005-01-04 devnull /*
119 24c02865 2005-01-04 devnull * Calculate the mask with gratings half as wide and recur.
120 24c02865 2005-01-04 devnull */
121 24c02865 2005-01-04 devnull halvemaskdim(mask, maskdim, axis);
122 24c02865 2005-01-04 devnull writefile("mask", mask, maskdim/2);
123 24c02865 2005-01-04 devnull
124 24c02865 2005-01-04 devnull shuffle(img, tmp, axis, imgdim, mask, maskdim/2);
125 24c02865 2005-01-04 devnull
126 24c02865 2005-01-04 devnull /*
127 24c02865 2005-01-04 devnull * Move the slop down to the bottom of the image.
128 24c02865 2005-01-04 devnull */
129 24c02865 2005-01-04 devnull swapranges(img, tmp, 0, imgdim-slop, imgdim, axis);
130 24c02865 2005-01-04 devnull moveup(im, tmp, lastnn, nn, n, axis);
131 24c02865 2005-01-04 devnull }
132 24c02865 2005-01-04 devnull
133 24c02865 2005-01-04 devnull /*
134 24c02865 2005-01-04 devnull * Halve the grating period in the mask.
135 fa325e9b 2020-01-10 cross * The grating currently looks like
136 24c02865 2005-01-04 devnull * ####____####____####____####____
137 24c02865 2005-01-04 devnull * where #### is opacity.
138 24c02865 2005-01-04 devnull *
139 24c02865 2005-01-04 devnull * We want
140 24c02865 2005-01-04 devnull * ##__##__##__##__##__##__##__##__
141 24c02865 2005-01-04 devnull * which is achieved by shifting the mask
142 24c02865 2005-01-04 devnull * and drawing on itself through itself.
143 fa325e9b 2020-01-10 cross * Draw doesn't actually allow this, so
144 24c02865 2005-01-04 devnull * we have to copy it first.
145 24c02865 2005-01-04 devnull *
146 24c02865 2005-01-04 devnull * ####____####____####____####____ (dst)
147 24c02865 2005-01-04 devnull * + ____####____####____####____#### (src)
148 24c02865 2005-01-04 devnull * in __####____####____####____####__ (mask)
149 24c02865 2005-01-04 devnull * ===========================================
150 24c02865 2005-01-04 devnull * ##__##__##__##__##__##__##__##__
151 24c02865 2005-01-04 devnull */
152 24c02865 2005-01-04 devnull static void
153 24c02865 2005-01-04 devnull halvemaskdim(Image *m, int maskdim, int axis)
154 24c02865 2005-01-04 devnull {
155 24c02865 2005-01-04 devnull Point δ;
156 24c02865 2005-01-04 devnull
157 24c02865 2005-01-04 devnull δ = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim);
158 24c02865 2005-01-04 devnull draw(mtmp, mtmp->r, mask, nil, mask->r.min);
159 24c02865 2005-01-04 devnull gendraw(mask, mask->r, mtmp, δ, mtmp, divpt(δ,2));
160 24c02865 2005-01-04 devnull writefile("mask", mask, maskdim/2);
161 24c02865 2005-01-04 devnull }
162 24c02865 2005-01-04 devnull
163 24c02865 2005-01-04 devnull /*
164 24c02865 2005-01-04 devnull * Swap the regions [a,b] and [b,c]
165 24c02865 2005-01-04 devnull */
166 24c02865 2005-01-04 devnull static void
167 24c02865 2005-01-04 devnull swapranges(Image *img, Image *tmp, int a, int b, int c, int axis)
168 24c02865 2005-01-04 devnull {
169 24c02865 2005-01-04 devnull Rectangle r;
170 24c02865 2005-01-04 devnull Point δ;
171 24c02865 2005-01-04 devnull
172 24c02865 2005-01-04 devnull if(a == b || b == c)
173 24c02865 2005-01-04 devnull return;
174 24c02865 2005-01-04 devnull
175 24c02865 2005-01-04 devnull writefile("swap", img, 0);
176 24c02865 2005-01-04 devnull draw(tmp, tmp->r, im, nil, im->r.min);
177 24c02865 2005-01-04 devnull
178 24c02865 2005-01-04 devnull /* [a,a+(c-b)] gets [b,c] */
179 24c02865 2005-01-04 devnull r = img->r;
180 24c02865 2005-01-04 devnull if(axis==Xaxis){
181 24c02865 2005-01-04 devnull δ = Pt(1,0);
182 24c02865 2005-01-04 devnull r.min.x = img->r.min.x + a;
183 24c02865 2005-01-04 devnull r.max.x = img->r.min.x + a + (c-b);
184 24c02865 2005-01-04 devnull }else{
185 24c02865 2005-01-04 devnull δ = Pt(0,1);
186 24c02865 2005-01-04 devnull r.min.y = img->r.min.y + a;
187 24c02865 2005-01-04 devnull r.max.y = img->r.min.y + a + (c-b);
188 24c02865 2005-01-04 devnull }
189 24c02865 2005-01-04 devnull draw(img, r, tmp, nil, addpt(tmp->r.min, mulpt(δ, b)));
190 24c02865 2005-01-04 devnull
191 24c02865 2005-01-04 devnull /* [a+(c-b), c] gets [a,b] */
192 24c02865 2005-01-04 devnull r = img->r;
193 24c02865 2005-01-04 devnull if(axis==Xaxis){
194 24c02865 2005-01-04 devnull r.min.x = img->r.min.x + a + (c-b);
195 24c02865 2005-01-04 devnull r.max.x = img->r.min.x + c;
196 24c02865 2005-01-04 devnull }else{
197 24c02865 2005-01-04 devnull r.min.y = img->r.min.y + a + (c-b);
198 24c02865 2005-01-04 devnull r.max.y = img->r.min.y + c;
199 24c02865 2005-01-04 devnull }
200 24c02865 2005-01-04 devnull draw(img, r, tmp, nil, addpt(tmp->r.min, mulpt(δ, a)));
201 24c02865 2005-01-04 devnull writefile("swap", img, 1);
202 24c02865 2005-01-04 devnull }
203 24c02865 2005-01-04 devnull
204 24c02865 2005-01-04 devnull /*
205 24c02865 2005-01-04 devnull * Swap adjacent regions as specified by the grating.
206 24c02865 2005-01-04 devnull * We do this by copying the image through the mask twice,
207 24c02865 2005-01-04 devnull * once aligned with the grading and once 180° out of phase.
208 24c02865 2005-01-04 devnull */
209 24c02865 2005-01-04 devnull static void
210 24c02865 2005-01-04 devnull swapadjacent(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int maskdim)
211 24c02865 2005-01-04 devnull {
212 24c02865 2005-01-04 devnull Point δ;
213 24c02865 2005-01-04 devnull Rectangle r0, r1;
214 24c02865 2005-01-04 devnull
215 24c02865 2005-01-04 devnull δ = axis==Xaxis ? Pt(1,0) : Pt(0,1);
216 24c02865 2005-01-04 devnull
217 24c02865 2005-01-04 devnull r0 = img->r;
218 24c02865 2005-01-04 devnull r1 = img->r;
219 24c02865 2005-01-04 devnull switch(axis){
220 24c02865 2005-01-04 devnull case Xaxis:
221 24c02865 2005-01-04 devnull r0.max.x = imgdim;
222 24c02865 2005-01-04 devnull r1.min.x = imgdim;
223 24c02865 2005-01-04 devnull break;
224 24c02865 2005-01-04 devnull case Yaxis:
225 24c02865 2005-01-04 devnull r0.max.y = imgdim;
226 24c02865 2005-01-04 devnull r1.min.y = imgdim;
227 24c02865 2005-01-04 devnull }
228 24c02865 2005-01-04 devnull
229 24c02865 2005-01-04 devnull /*
230 24c02865 2005-01-04 devnull * r0 is the lower rectangle, while r1 is the upper one.
231 24c02865 2005-01-04 devnull */
232 fa325e9b 2020-01-10 cross draw(tmp, tmp->r, img, nil,
233 24c02865 2005-01-04 devnull }
234 24c02865 2005-01-04 devnull
235 24c02865 2005-01-04 devnull void
236 24c02865 2005-01-04 devnull interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
237 24c02865 2005-01-04 devnull {
238 24c02865 2005-01-04 devnull Point p0, p1;
239 24c02865 2005-01-04 devnull Rectangle r0, r1;
240 24c02865 2005-01-04 devnull
241 24c02865 2005-01-04 devnull r0 = im->r;
242 24c02865 2005-01-04 devnull r1 = im->r;
243 24c02865 2005-01-04 devnull switch(axis) {
244 24c02865 2005-01-04 devnull case Xaxis:
245 24c02865 2005-01-04 devnull r0.max.x = n;
246 24c02865 2005-01-04 devnull r1.min.x = n;
247 24c02865 2005-01-04 devnull p0 = (Point){gran, 0};
248 24c02865 2005-01-04 devnull p1 = (Point){-gran, 0};
249 24c02865 2005-01-04 devnull break;
250 24c02865 2005-01-04 devnull case Yaxis:
251 24c02865 2005-01-04 devnull r0.max.y = n;
252 24c02865 2005-01-04 devnull r1.min.y = n;
253 24c02865 2005-01-04 devnull p0 = (Point){0, gran};
254 24c02865 2005-01-04 devnull p1 = (Point){0, -gran};
255 24c02865 2005-01-04 devnull break;
256 24c02865 2005-01-04 devnull }
257 24c02865 2005-01-04 devnull
258 24c02865 2005-01-04 devnull draw(tmp, im->r, im, display->black, im->r.min);
259 24c02865 2005-01-04 devnull gendraw(im, r0, tmp, p0, mask, mask->r.min);
260 24c02865 2005-01-04 devnull gendraw(im, r0, tmp, p1, mask, p1);
261 24c02865 2005-01-04 devnull }
262 24c02865 2005-01-04 devnull
263 24c02865 2005-01-04 devnull
264 24c02865 2005-01-04 devnull static void
265 24c02865 2005-01-04 devnull writefile(char *name, Image *im, int gran)
266 24c02865 2005-01-04 devnull {
267 24c02865 2005-01-04 devnull static int c = 100;
268 24c02865 2005-01-04 devnull int fd;
269 24c02865 2005-01-04 devnull char buf[200];
270 24c02865 2005-01-04 devnull
271 24c02865 2005-01-04 devnull snprint(buf, sizeof buf, "%d%s%d", c++, name, gran);
272 24c02865 2005-01-04 devnull fd = create(buf, OWRITE, 0666);
273 24c02865 2005-01-04 devnull if(fd < 0)
274 fa325e9b 2020-01-10 cross return;
275 24c02865 2005-01-04 devnull writeimage(fd, im, 0);
276 24c02865 2005-01-04 devnull close(fd);
277 24c02865 2005-01-04 devnull }