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