xref: /plan9/sys/src/cmd/lens.c (revision 6a9fc400c33447ef5e1cda7185cb4de2c8e8010e)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 
6 enum {
7 	Edge = 5,
8 	Maxmag = 16
9 };
10 
11 Point lastp;
12 Image *red;
13 Image *tmp;
14 Image *grid;
15 Image *gridmatte;
16 Image *veil;
17 Image *chequer;
18 int	screenfd;
19 int	mag = 4;
20 int	showgrid = 0;
21 Rectangle	screenr;
22 uchar	*screenbuf;
23 
24 void	magnify(void);
25 void makegrid(void);
26 
27 void
28 drawit(void)
29 {
30 	Rectangle r;
31 	border(screen, screen->r, Edge, red, ZP);
32 	magnify();
33 	r = insetrect(screen->r, Edge);
34 	draw(screen, r, tmp, nil, tmp->r.min);
35 	flushimage(display, 1);
36 }
37 
38 
39 int bypp;
40 
41 void
42 main(int argc, char *argv[])
43 {
44 	Event e;
45 	char buf[5*12];
46 	ulong chan;
47 	int d;
48 
49 	USED(argc, argv);
50 	if(initdraw(nil, nil, "lens") < 0){
51 		fprint(2, "lens: initdraw failed: %r\n");
52 		exits("initdraw");
53 	}
54 	einit(Emouse|Ekeyboard);
55 	red = allocimage(display, Rect(0, 0, 1, 1), CMAP8, 1, DRed);
56 	veil = allocimage(display, Rect(0, 0, 1, 1), GREY8, 1, 0x3f3f3fff);
57 	chequer = allocimage(display, Rect(0, 0, 2, 2), GREY1, 1, DBlack);
58 	draw(chequer, Rect(0, 0, 1, 1), display->white, nil, ZP);
59 	draw(chequer, Rect(1, 1, 2, 2), display->white, nil, ZP);
60 	lastp = divpt(addpt(screen->r.min, screen->r.max), 2);
61 	screenfd = open("/dev/screen", OREAD);
62 	if(screenfd < 0){
63 		fprint(2, "lens: can't open /dev/screen: %r\n");
64 		exits("screen");
65 	}
66 	if(read(screenfd, buf, sizeof buf) != sizeof buf){
67 		fprint(2, "lens: can't read /dev/screen: %r\n");
68 		exits("screen");
69 	}
70 	chan = strtochan(buf);
71 	d = chantodepth(chan);
72 	if(d < 8){
73 		fprint(2, "lens: can't handle screen format %11.11s\n", buf);
74 		exits("screen");
75 	}
76 	bypp = d/8;
77 	screenr.min.x = atoi(buf+1*12);
78 	screenr.min.y = atoi(buf+2*12);
79 	screenr.max.x = atoi(buf+3*12);
80 	screenr.max.y = atoi(buf+4*12);
81 	screenbuf = malloc(bypp*Dx(screenr)*Dy(screenr));
82 	if(screenbuf == nil){
83 		fprint(2, "lens: buffer malloc failed: %r\n");
84 		exits("malloc");
85 	}
86 	eresized(0);
87 
88 	for(;;)
89 		switch(event(&e)){
90 		case Ekeyboard:
91 			switch(e.kbdc){
92 			case 'q':
93 			case '\04':
94 				exits(nil);
95 			case '=':
96 			case '+':
97 				if(mag < Maxmag){
98 					mag++;
99 					makegrid();
100 					drawit();
101 				}
102 				break;
103 			case 'g':
104 				showgrid = !showgrid;
105 				makegrid();
106 				drawit();
107 				break;
108 			case '-':
109 			case '_':
110 				if(mag > 1){
111 					mag--;
112 					makegrid();
113 					drawit();
114 				}
115 				break;
116 			case '.':
117 			case ' ':
118 				drawit();
119 				break;
120 			case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case'0':
121 				mag = e.kbdc-'0';
122 				if(mag == 0)
123 					mag = 10;
124 				makegrid();
125 				drawit();
126 				break;
127 			}
128 			if(e.kbdc == 'q' || e.kbdc == '\04')
129 				exits(nil);
130 			break;
131 		case Emouse:
132 			if(e.mouse.buttons){
133 				lastp = e.mouse.xy;
134 				drawit();
135 			}
136 			break;
137 		}
138 }
139 
140 void
141 makegrid(void)
142 {
143 	if (grid != nil) {
144 		freeimage(grid);
145 		grid = nil;
146 	}
147 	if (showgrid) {
148 		if (mag < 4) {
149 			grid = allocimage(display, Rect(0, 0, mag*2, mag*2), GREY1, 1, DBlack);
150 			draw(grid, Rect(0, 0, mag, mag), display->white, nil, ZP);
151 			draw(grid, Rect(mag, mag, mag*2, mag*2), display->white, nil, ZP);
152 			gridmatte = veil;
153 		} else {
154 			grid = allocimage(display, Rect(0, 0, mag, mag),
155 				CHAN2(CGrey, 8, CAlpha, 8), 1, DTransparent);
156 			draw(grid, Rect(0, 0, mag, 1), chequer, nil, ZP);
157 			draw(grid, Rect(0, 1, 1, mag), chequer, nil, ZP);
158 			gridmatte = nil;
159 		}
160 	}
161 }
162 
163 void
164 eresized(int new)
165 {
166 	if(new && getwindow(display, Refnone) < 0){
167 		fprint(2, "lens: can't reattach to window: %r\n");
168 		exits("attach");
169 	}
170 	freeimage(tmp);
171 	tmp = allocimage(display, Rect(0, 0, Dx(screen->r)-Edge, Dy(screen->r)-Edge+Maxmag), screen->chan, 0, DNofill);
172 	if(tmp == nil){
173 		fprint(2, "lens: allocimage failed: %r\n");
174 		exits("allocimage");
175 	}
176 	drawit();
177 }
178 
179 void
180 magnify(void)
181 {
182 	int x, y, xx, yy, dd, i;
183 	int dx, dy;
184 	int xoff, yoff;
185 	uchar out[8192];
186 	uchar sp[4];
187 
188 	dx = (Dx(tmp->r)+mag-1)/mag;
189 	dy = (Dy(tmp->r)+mag-1)/mag;
190 	xoff = lastp.x-Dx(tmp->r)/(mag*2);
191 	yoff  = lastp.y-Dy(tmp->r)/(mag*2);
192 
193 	yy = yoff;
194 	dd = dy;
195 	if(yy < 0){
196 		dd += dy;
197 		yy = 0;
198 	}
199 	if(yy+dd > Dy(screenr))
200 		dd = Dy(screenr)-yy;
201 	seek(screenfd, 5*12+bypp*yy*Dx(screenr), 0);
202 	if(readn(screenfd, screenbuf+bypp*yy*Dx(screenr), bypp*Dx(screenr)*dd) != bypp*Dx(screenr)*dd){
203 		fprint(2, "lens: can't read screen: %r\n");
204 		return;
205 	}
206 
207 	for(y=0; y<dy; y++){
208 		yy = yoff+y;
209 		if(yy>=0 && yy<Dy(screenr))
210 			for(x=0; x<dx; x++){
211 				xx = xoff+x;
212 				if(xx>=0 && xx<Dx(screenr))	/* snarf pixel at xx, yy */
213 					for(i=0; i<bypp; i++)
214 						sp[i] = screenbuf[bypp*(yy*Dx(screenr)+xx)+i];
215 				else
216 					sp[0] = sp[1] = sp[2] = sp[3] = 0;
217 
218 				for(xx=0; xx<mag; xx++)
219 					if(x*mag+xx < tmp->r.max.x)
220 						for(i=0; i<bypp; i++)
221 							out[(x*mag+xx)*bypp+i] = sp[i];
222 			}
223 		else
224 			memset(out, 0, bypp*Dx(tmp->r));
225 		for(yy=0; yy<mag && y*mag+yy<Dy(tmp->r); yy++){
226 			werrstr("no error");
227 			if(loadimage(tmp, Rect(0, y*mag+yy, Dx(tmp->r), y*mag+yy+1), out, bypp*Dx(tmp->r)) != bypp*Dx(tmp->r)){
228 				exits("load");
229 			}
230 		}
231 	}
232 	if (showgrid && mag)
233 		draw(tmp, tmp->r, grid, gridmatte, ZP);
234 }
235