ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/x11image.c
Revision: 2.32
Committed: Thu Oct 28 11:39:59 1993 UTC (30 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.31: +15 -8 lines
Log Message:
fixed problem where parent would stall after child aborted

File Contents

# User Rev Content
1 greg 2.24 /* Copyright (c) 1993 Regents of the University of California */
2 greg 1.1
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * x11image.c - driver for X-windows
9     *
10     * 3/1/90
11     */
12    
13     /*
14     * Modified for X11
15     *
16     * January 1990
17     *
18     * Anat Grynberg and Greg Ward
19     */
20    
21    
22     #include "standard.h"
23    
24 greg 2.29 #include <signal.h>
25 greg 1.1 #include <X11/Xlib.h>
26     #include <X11/cursorfont.h>
27     #include <X11/Xutil.h>
28 greg 2.24 #include <X11/Xatom.h>
29 greg 1.1
30     #include "color.h"
31     #include "view.h"
32     #include "x11raster.h"
33     #include "random.h"
34 greg 1.26 #include "resolu.h"
35 greg 1.1
36 greg 2.28 #ifdef __alpha
37     #define int4 int
38     #endif
39     #ifndef int4
40     #define int4 long
41     #endif
42    
43 greg 1.1 #define FONTNAME "8x13" /* text font we'll use */
44    
45 greg 2.3 #define CTRL(c) ((c)-'@')
46 greg 1.1
47     #define BORWIDTH 5 /* border width */
48    
49 greg 1.18 #define ICONSIZ (8*10) /* maximum icon dimension (even 8) */
50 greg 1.17
51 greg 1.1 #define ourscreen DefaultScreen(thedisplay)
52     #define ourroot RootWindow(thedisplay,ourscreen)
53    
54 greg 1.5 #define revline(x0,y0,x1,y1) XDrawLine(thedisplay,wind,revgc,x0,y0,x1,y1)
55    
56 greg 1.2 #define redraw(x,y,w,h) patch_raster(wind,(x)-xoff,(y)-yoff,x,y,w,h,ourras)
57    
58 greg 1.1 double gamcor = 2.2; /* gamma correction */
59    
60     int dither = 1; /* dither colors? */
61     int fast = 0; /* keep picture in Pixmap? */
62    
63 greg 2.6 char *dispname = NULL; /* our display name */
64    
65 greg 1.1 Window wind = 0; /* our output window */
66 greg 2.9 unsigned long ourblack=0, ourwhite=1; /* black and white for this visual */
67 greg 1.2 int maxcolors = 0; /* maximum colors */
68 greg 1.1 int greyscale = 0; /* in grey */
69    
70     int scale = 0; /* scalefactor; power of two */
71    
72     int xoff = 0; /* x image offset */
73     int yoff = 0; /* y image offset */
74    
75 greg 2.29 int parent = 0; /* number of children, -1 if child */
76    
77 greg 1.1 VIEW ourview = STDVIEW; /* image view parameters */
78     int gotview = 0; /* got parameters from file */
79    
80     COLR *scanline; /* scan line buffer */
81    
82 greg 1.26 RESOLU inpres; /* input resolution and ordering */
83     int xmax, ymax; /* picture dimensions */
84 greg 1.1 int width, height; /* window size */
85     char *fname = NULL; /* input file name */
86     FILE *fin = stdin; /* input file */
87     long *scanpos = NULL; /* scan line positions in file */
88     int cury = 0; /* current scan location */
89    
90     double exposure = 1.0; /* exposure compensation used */
91    
92 greg 1.14 int wrongformat = 0; /* input in another format? */
93    
94 greg 2.6 GC ourgc; /* standard graphics context */
95 greg 1.5 GC revgc; /* graphics context with GXinvert */
96    
97 greg 2.6 int *ourrank; /* our visual class ranking */
98     XVisualInfo ourvis; /* our visual */
99     XRASTER *ourras; /* our stored image */
100 greg 1.1 unsigned char *ourdata; /* our image data */
101    
102     struct {
103     int xmin, ymin, xsiz, ysiz;
104     } box = {0, 0, 0, 0}; /* current box */
105    
106     char *geometry = NULL; /* geometry specification */
107    
108 greg 1.18 char icondata[ICONSIZ*ICONSIZ/8]; /* icon bitmap data */
109 greg 1.17 int iconwidth = 0, iconheight = 0;
110    
111 greg 1.1 char *progname;
112    
113     char errmsg[128];
114    
115 greg 2.13 extern BYTE clrtab[256][3]; /* global color map */
116    
117 greg 1.1 extern long ftell();
118    
119     Display *thedisplay;
120 greg 2.24 Atom closedownAtom, wmProtocolsAtom;
121 greg 1.1
122 greg 2.32 int sigrecv;
123 greg 2.14
124 greg 2.32 int onsig() { sigrecv++; }
125 greg 2.29
126 greg 2.32
127 greg 1.1 main(argc, argv)
128     int argc;
129     char *argv[];
130     {
131 greg 2.10 extern char *getenv();
132     char *gv;
133 greg 1.1 int headline();
134     int i;
135 greg 2.29 int pid;
136 greg 1.1
137     progname = argv[0];
138 greg 2.10 if ((gv = getenv("GAMMA")) != NULL)
139     gamcor = atof(gv);
140 greg 1.1
141     for (i = 1; i < argc; i++)
142     if (argv[i][0] == '-')
143     switch (argv[i][1]) {
144     case 'c':
145     maxcolors = atoi(argv[++i]);
146     break;
147     case 'b':
148     greyscale = !greyscale;
149     break;
150     case 'm':
151     maxcolors = 2;
152     break;
153     case 'd':
154 greg 2.7 if (argv[i][2] == 'i')
155 greg 2.6 dispname = argv[++i];
156 greg 2.7 else
157     dither = !dither;
158 greg 1.1 break;
159     case 'f':
160     fast = !fast;
161     break;
162     case 'e':
163     if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
164     goto userr;
165     scale = atoi(argv[++i]);
166     break;
167     case 'g':
168 greg 2.7 if (argv[i][2] == 'e')
169 greg 1.1 geometry = argv[++i];
170     else
171     gamcor = atof(argv[++i]);
172     break;
173     default:
174     goto userr;
175     }
176 greg 1.3 else if (argv[i][0] == '=')
177     geometry = argv[i];
178 greg 1.1 else
179     break;
180    
181 greg 2.29 if (i > argc)
182     goto userr;
183     while (i < argc-1) {
184 greg 2.32 sigrecv = 0;
185     signal(SIGCONT, onsig);
186 greg 2.29 if ((pid=fork()) == 0) { /* a child for each picture */
187     parent = -1;
188     break;
189     }
190     if (pid < 0)
191     quiterr("fork failed");
192     parent++;
193 greg 2.32 while (!sigrecv)
194     pause(); /* wait for wake-up call */
195 greg 2.29 i++;
196     }
197     if (i < argc) { /* open picture file */
198 greg 1.1 fname = argv[i];
199     fin = fopen(fname, "r");
200     if (fin == NULL) {
201 greg 2.6 sprintf(errmsg, "cannot open file \"%s\"", fname);
202 greg 1.1 quiterr(errmsg);
203     }
204 greg 2.29 }
205 greg 1.1 /* get header */
206 greg 1.14 getheader(fin, headline, NULL);
207 greg 1.1 /* get picture dimensions */
208 greg 1.26 if (wrongformat || !fgetsresolu(&inpres, fin))
209 greg 1.14 quiterr("bad picture format");
210 greg 1.26 xmax = scanlen(&inpres);
211     ymax = numscans(&inpres);
212 greg 1.1 /* set view parameters */
213     if (gotview && setview(&ourview) != NULL)
214     gotview = 0;
215     if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
216     quiterr("out of memory");
217    
218 greg 2.24 init(argc, argv); /* get file and open window */
219 greg 1.1
220 greg 2.32 if (parent < 0) {
221 greg 2.29 kill(getppid(), SIGCONT); /* signal parent if child */
222 greg 2.32 sigrecv--;
223     }
224 greg 1.1 for ( ; ; )
225     getevent(); /* main loop */
226     userr:
227     fprintf(stderr,
228 greg 2.29 "Usage: %s [-di disp][[-ge] spec][-b][-m][-d][-f][-c nclrs][-e +/-stops] pic ..\n",
229 greg 1.1 progname);
230 greg 2.21 exit(1);
231 greg 1.1 }
232    
233    
234     headline(s) /* get relevant info from header */
235     char *s;
236     {
237 greg 1.14 char fmt[32];
238 greg 1.1
239 greg 1.2 if (isexpos(s))
240     exposure *= exposval(s);
241 greg 1.14 else if (isformat(s)) {
242     formatval(fmt, s);
243     wrongformat = strcmp(fmt, COLRFMT);
244 greg 2.4 } else if (isview(s) && sscanview(&ourview, s) > 0)
245     gotview++;
246 greg 1.1 }
247    
248    
249 greg 2.24 init(argc, argv) /* get data and open window */
250     int argc;
251     char **argv;
252 greg 1.1 {
253 greg 1.4 XSetWindowAttributes ourwinattr;
254 greg 2.24 XClassHint xclshints;
255     XWMHints xwmhints;
256     XSizeHints xszhints;
257     XTextProperty windowName, iconName;
258     XGCValues xgcv;
259     char *name;
260 greg 2.6 register int i;
261 greg 1.1
262     if (fname != NULL) {
263     scanpos = (long *)malloc(ymax*sizeof(long));
264     if (scanpos == NULL)
265 greg 2.24 quiterr("out of memory");
266 greg 1.1 for (i = 0; i < ymax; i++)
267     scanpos[i] = -1;
268 greg 2.24 name = fname;
269     } else
270     name = progname;
271     /* remove directory prefix from name */
272     for (i = strlen(name); i-- > 0; )
273     if (name[i] == '/')
274     break;
275     name += i+1;
276 greg 2.6 if ((thedisplay = XOpenDisplay(dispname)) == NULL)
277     quiterr("cannot open display");
278     /* get best visual for default screen */
279     getbestvis();
280 greg 1.4 /* store image */
281     getras();
282 greg 2.20 /* get size and position */
283 greg 2.24 xszhints.flags = 0;
284     xszhints.width = xmax; xszhints.height = ymax;
285 greg 2.20 if (geometry != NULL) {
286 greg 2.24 i = XParseGeometry(geometry, &xszhints.x, &xszhints.y,
287     (unsigned *)&xszhints.width,
288     (unsigned *)&xszhints.height);
289 greg 2.20 if ((i&(WidthValue|HeightValue)) == (WidthValue|HeightValue))
290 greg 2.24 xszhints.flags |= USSize;
291 greg 2.20 else
292 greg 2.24 xszhints.flags |= PSize;
293 greg 2.20 if ((i&(XValue|YValue)) == (XValue|YValue)) {
294 greg 2.24 xszhints.flags |= USPosition;
295 greg 2.20 if (i & XNegative)
296 greg 2.24 xszhints.x += DisplayWidth(thedisplay,
297     ourscreen)-1-xszhints.width-2*BORWIDTH;
298 greg 2.20 if (i & YNegative)
299 greg 2.24 xszhints.y += DisplayHeight(thedisplay,
300     ourscreen)-1-xszhints.height-2*BORWIDTH;
301 greg 2.20 }
302     }
303 greg 2.24 /* open window */
304 greg 2.23 ourwinattr.border_pixel = ourwhite;
305     ourwinattr.background_pixel = ourblack;
306 greg 2.6 ourwinattr.colormap = XCreateColormap(thedisplay, ourroot,
307     ourvis.visual, AllocNone);
308 greg 2.24 ourwinattr.event_mask = ExposureMask|KeyPressMask|ButtonPressMask|
309     ButtonReleaseMask|ButtonMotionMask|StructureNotifyMask;
310     ourwinattr.cursor = XCreateFontCursor(thedisplay, XC_diamond_cross);
311     wind = XCreateWindow(thedisplay, ourroot, xszhints.x, xszhints.y,
312     xszhints.width, xszhints.height, BORWIDTH,
313     ourvis.depth, InputOutput, ourvis.visual, CWEventMask|
314     CWCursor|CWBackPixel|CWBorderPixel|CWColormap, &ourwinattr);
315 greg 1.4 if (wind == 0)
316 greg 2.6 quiterr("cannot create window");
317 greg 1.5 width = xmax;
318     height = ymax;
319 greg 2.32 /* prepare graphics drawing context */
320     if ((xgcv.font = XLoadFont(thedisplay, FONTNAME)) == 0)
321     quiterr("cannot get font");
322 greg 2.24 xgcv.foreground = ourblack;
323     xgcv.background = ourwhite;
324     ourgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground|
325     GCFont, &xgcv);
326     xgcv.function = GXinvert;
327     revgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground|
328     GCFunction, &xgcv);
329    
330     /* set up the window manager */
331     xwmhints.flags = InputHint|IconPixmapHint;
332     xwmhints.input = True;
333     xwmhints.icon_pixmap = XCreateBitmapFromData(thedisplay,
334 greg 1.17 wind, icondata, iconwidth, iconheight);
335 greg 2.24
336     windowName.encoding = iconName.encoding = XA_STRING;
337     windowName.format = iconName.format = 8;
338     windowName.value = (u_char *)name;
339     windowName.nitems = strlen(windowName.value);
340     iconName.value = (u_char *)name;
341     iconName.nitems = strlen(windowName.value);
342    
343     xclshints.res_name = NULL;
344     xclshints.res_class = "Ximage";
345     XSetWMProperties(thedisplay, wind, &windowName, &iconName,
346     argv, argc, &xszhints, &xwmhints, &xclshints);
347     closedownAtom = XInternAtom(thedisplay, "WM_DELETE_WINDOW", False);
348     wmProtocolsAtom = XInternAtom(thedisplay, "WM_PROTOCOLS", False);
349     XSetWMProtocols(thedisplay, wind, &closedownAtom, 1);
350    
351 greg 1.1 XMapWindow(thedisplay, wind);
352     return;
353     } /* end of init */
354    
355    
356     quiterr(err) /* print message and exit */
357     char *err;
358     {
359 greg 2.31 register int es;
360     int cs;
361    
362     if (es = err != NULL)
363 greg 2.29 fprintf(stderr, "%s: %s: %s\n", progname,
364     fname==NULL?"<stdin>":fname, err);
365 greg 2.31 if (parent > 0 & wind != 0) {
366 greg 2.29 XDestroyWindow(thedisplay, wind);
367     XFlush(thedisplay);
368 greg 2.32 } else if (parent < 0 & sigrecv == 0)
369     kill(getppid(), SIGCONT);
370 greg 2.31 while (parent > 0 && wait(&cs) != -1) { /* wait for any children */
371     if (es == 0)
372     es = cs>>8 & 0xff;
373 greg 2.29 parent--;
374 greg 2.31 }
375     exit(es);
376 greg 1.1 }
377    
378    
379 greg 2.6 static int
380     viscmp(v1,v2) /* compare visual to see which is better, descending */
381     register XVisualInfo *v1, *v2;
382     {
383     int bad1 = 0, bad2 = 0;
384     register int *rp;
385    
386     if (v1->class == v2->class) {
387     if (v1->class == TrueColor || v1->class == DirectColor) {
388     /* prefer 24-bit to 32-bit */
389     if (v1->depth == 24 && v2->depth == 32)
390     return(-1);
391     if (v1->depth == 32 && v2->depth == 24)
392     return(1);
393     return(0);
394     }
395     /* don't be too greedy */
396     if (maxcolors <= 1<<v1->depth && maxcolors <= 1<<v2->depth)
397     return(v1->depth - v2->depth);
398     return(v2->depth - v1->depth);
399     }
400     /* prefer Pseudo when < 24-bit */
401     if ((v1->class == TrueColor || v1->class == DirectColor) &&
402     v1->depth < 24)
403     bad1 = 1;
404     if ((v2->class == TrueColor || v2->class == DirectColor) &&
405     v2->depth < 24)
406     bad2 = -1;
407     if (bad1 | bad2)
408     return(bad1+bad2);
409     /* otherwise, use class ranking */
410     for (rp = ourrank; *rp != -1; rp++) {
411     if (v1->class == *rp)
412     return(-1);
413     if (v2->class == *rp)
414     return(1);
415     }
416     return(0);
417     }
418    
419    
420     getbestvis() /* get the best visual for this screen */
421     {
422 greg 2.7 #ifdef DEBUG
423 greg 2.6 static char vistype[][12] = {
424     "StaticGray",
425     "GrayScale",
426     "StaticColor",
427     "PseudoColor",
428     "TrueColor",
429     "DirectColor"
430     };
431 greg 2.7 #endif
432 greg 2.6 static int rankings[3][6] = {
433     {TrueColor,DirectColor,PseudoColor,GrayScale,StaticGray,-1},
434 greg 2.7 {PseudoColor,GrayScale,StaticGray,-1},
435     {PseudoColor,GrayScale,StaticGray,-1}
436 greg 2.6 };
437     XVisualInfo *xvi;
438     int vismatched;
439     register int i, j;
440    
441     if (greyscale) {
442     ourrank = rankings[2];
443     if (maxcolors < 2) maxcolors = 256;
444     } else if (maxcolors >= 2 && maxcolors <= 256)
445     ourrank = rankings[1];
446     else {
447     ourrank = rankings[0];
448     maxcolors = 256;
449     }
450     /* find best visual */
451     ourvis.screen = ourscreen;
452     xvi = XGetVisualInfo(thedisplay,VisualScreenMask,&ourvis,&vismatched);
453     if (xvi == NULL)
454     quiterr("no visuals for this screen!");
455 greg 2.7 #ifdef DEBUG
456     fprintf(stderr, "Supported visuals:\n");
457     for (i = 0; i < vismatched; i++)
458     fprintf(stderr, "\ttype %s, depth %d\n",
459     vistype[xvi[i].class], xvi[i].depth);
460     #endif
461 greg 2.6 for (i = 0, j = 1; j < vismatched; j++)
462     if (viscmp(&xvi[i],&xvi[j]) > 0)
463     i = j;
464     /* compare to least acceptable */
465     for (j = 0; ourrank[j++] != -1; )
466     ;
467     ourvis.class = ourrank[--j];
468     ourvis.depth = 1;
469     if (viscmp(&xvi[i],&ourvis) > 0)
470     quiterr("inadequate visuals on this screen");
471     /* OK, we'll use it */
472     copystruct(&ourvis, &xvi[i]);
473 greg 2.7 #ifdef DEBUG
474     fprintf(stderr, "Selected visual type %s, depth %d\n",
475     vistype[ourvis.class], ourvis.depth);
476     #endif
477 greg 2.8 /* make appropriate adjustments */
478 greg 2.6 if (ourvis.class == GrayScale || ourvis.class == StaticGray)
479     greyscale = 1;
480 greg 2.7 if (ourvis.depth <= 8 && ourvis.colormap_size < maxcolors)
481     maxcolors = ourvis.colormap_size;
482 greg 2.8 if (ourvis.class == StaticGray) {
483     ourblack = 0;
484     ourwhite = 255;
485     } else if (ourvis.class == PseudoColor) {
486     ourblack = BlackPixel(thedisplay,ourscreen);
487     ourwhite = WhitePixel(thedisplay,ourscreen);
488 greg 2.9 if ((ourblack|ourwhite) & ~255L) {
489     ourblack = 0;
490     ourwhite = 1;
491     }
492 greg 2.13 if (maxcolors > 4)
493     maxcolors -= 2;
494 greg 2.8 } else {
495     ourblack = 0;
496 greg 2.9 ourwhite = ourvis.red_mask|ourvis.green_mask|ourvis.blue_mask;
497 greg 2.8 }
498 greg 2.6 XFree((char *)xvi);
499     }
500    
501    
502 greg 1.1 getras() /* get raster file */
503     {
504     XVisualInfo vinfo;
505    
506     if (maxcolors <= 2) { /* monochrome */
507     ourdata = (unsigned char *)malloc(ymax*((xmax+7)/8));
508     if (ourdata == NULL)
509     goto fail;
510 greg 2.6 ourras = make_raster(thedisplay, &ourvis, 1, ourdata,
511 greg 1.1 xmax, ymax, 8);
512     if (ourras == NULL)
513     goto fail;
514     getmono();
515 greg 2.13 } else if (ourvis.class == TrueColor | ourvis.class == DirectColor) {
516 greg 2.28 ourdata = (unsigned char *)malloc(sizeof(int4)*xmax*ymax);
517 greg 1.1 if (ourdata == NULL)
518     goto fail;
519 greg 2.28 ourras = make_raster(thedisplay, &ourvis, sizeof(int4)*8,
520 greg 2.6 ourdata, xmax, ymax, 32);
521 greg 1.1 if (ourras == NULL)
522     goto fail;
523     getfull();
524     } else {
525     ourdata = (unsigned char *)malloc(xmax*ymax);
526     if (ourdata == NULL)
527     goto fail;
528 greg 2.6 ourras = make_raster(thedisplay, &ourvis, 8, ourdata,
529 greg 1.1 xmax, ymax, 8);
530     if (ourras == NULL)
531     goto fail;
532 greg 2.13 if (greyscale | ourvis.class == StaticGray)
533 greg 2.7 getgrey();
534 greg 2.13 else
535     getmapped();
536     if (ourvis.class != StaticGray && !init_rcolors(ourras,clrtab))
537     goto fail;
538 greg 1.1 }
539 greg 2.13 return;
540 greg 1.1 fail:
541 greg 1.9 quiterr("could not create raster image");
542 greg 1.1 }
543    
544    
545     getevent() /* process the next event */
546     {
547 greg 2.24 XEvent xev;
548 greg 1.1
549 greg 2.24 XNextEvent(thedisplay, &xev);
550     switch ((int)xev.type) {
551 greg 1.1 case KeyPress:
552 greg 2.24 docom(&xev.xkey);
553 greg 1.1 break;
554     case ConfigureNotify:
555 greg 2.24 width = xev.xconfigure.width;
556     height = xev.xconfigure.height;
557 greg 1.1 break;
558     case MapNotify:
559     map_rcolors(ourras, wind);
560     if (fast)
561 greg 2.6 make_rpixmap(ourras, wind);
562 greg 1.1 break;
563     case UnmapNotify:
564 greg 2.7 if (!fast)
565     unmap_rcolors(ourras);
566 greg 1.1 break;
567     case Expose:
568 greg 2.24 redraw(xev.xexpose.x, xev.xexpose.y,
569     xev.xexpose.width, xev.xexpose.height);
570 greg 1.1 break;
571     case ButtonPress:
572 greg 2.24 if (xev.xbutton.state & (ShiftMask|ControlMask))
573     moveimage(&xev.xbutton);
574     else if (xev.xbutton.button == Button2)
575     traceray(xev.xbutton.x, xev.xbutton.y);
576 greg 1.1 else
577 greg 2.24 getbox(&xev.xbutton);
578 greg 1.1 break;
579 greg 2.29 case ClientMessage:
580 greg 2.24 if ((xev.xclient.message_type == wmProtocolsAtom) &&
581     (xev.xclient.data.l[0] == closedownAtom))
582     quiterr(NULL);
583     break;
584 greg 1.1 }
585     }
586    
587    
588 greg 2.22 traceray(xpos, ypos) /* print ray corresponding to pixel */
589     int xpos, ypos;
590     {
591     FLOAT hv[2];
592     FVECT rorg, rdir;
593    
594     if (!gotview) { /* no view, no can do */
595     XBell(thedisplay, 0);
596     return(-1);
597     }
598     pix2loc(hv, &inpres, xpos-xoff, ypos-yoff);
599     if (viewray(rorg, rdir, &ourview, hv[0], hv[1]) < 0)
600     return(-1);
601     printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
602     printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]);
603     fflush(stdout);
604     return(0);
605     }
606    
607    
608     docom(ekey) /* execute command */
609 greg 1.1 XKeyPressedEvent *ekey;
610     {
611     char buf[80];
612     COLOR cval;
613     XColor cvx;
614     int com, n;
615     double comp;
616 greg 1.26 FLOAT hv[2];
617 greg 1.1
618     n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
619     if (n == 0)
620     return(0);
621     com = buf[0];
622     switch (com) { /* interpret command */
623     case 'q':
624 greg 2.22 case 'Q':
625 greg 2.3 case CTRL('D'): /* quit */
626 greg 2.21 quiterr(NULL);
627 greg 1.1 case '\n':
628     case '\r':
629     case 'l':
630     case 'c': /* value */
631     if (avgbox(cval) == -1)
632     return(-1);
633     switch (com) {
634     case '\n':
635     case '\r': /* radiance */
636     sprintf(buf, "%.3f", intens(cval)/exposure);
637     break;
638     case 'l': /* luminance */
639 greg 1.16 sprintf(buf, "%.0fL", luminance(cval)/exposure);
640 greg 1.1 break;
641     case 'c': /* color */
642     comp = pow(2.0, (double)scale);
643     sprintf(buf, "(%.2f,%.2f,%.2f)",
644     colval(cval,RED)*comp,
645     colval(cval,GRN)*comp,
646     colval(cval,BLU)*comp);
647     break;
648     }
649 greg 1.3 XDrawImageString(thedisplay, wind, ourgc,
650     box.xmin, box.ymin+box.ysiz, buf, strlen(buf));
651 greg 1.1 return(0);
652     case 'i': /* identify (contour) */
653     if (ourras->pixels == NULL)
654     return(-1);
655     n = ourdata[ekey->x-xoff+xmax*(ekey->y-yoff)];
656     n = ourras->pmap[n];
657     cvx.pixel = ourras->cdefs[n].pixel;
658     cvx.red = random() & 65535;
659     cvx.green = random() & 65535;
660     cvx.blue = random() & 65535;
661 greg 1.2 cvx.flags = DoRed|DoGreen|DoBlue;
662     XStoreColor(thedisplay, ourras->cmap, &cvx);
663 greg 1.1 return(0);
664     case 'p': /* position */
665 greg 1.26 pix2loc(hv, &inpres, ekey->x-xoff, ekey->y-yoff);
666     sprintf(buf, "(%d,%d)", (int)(hv[0]*inpres.xr),
667     (int)(hv[1]*inpres.yr));
668 greg 1.1 XDrawImageString(thedisplay, wind, ourgc, ekey->x, ekey->y,
669     buf, strlen(buf));
670     return(0);
671     case 't': /* trace */
672 greg 2.22 return(traceray(ekey->x, ekey->y));
673 greg 1.1 case '=': /* adjust exposure */
674 greg 2.25 case '@': /* adaptation level */
675 greg 1.1 if (avgbox(cval) == -1)
676     return(-1);
677 greg 2.25 comp = com=='@'
678 greg 2.26 ? 106./pow(1.219+pow(luminance(cval)/exposure,.4),2.5)/exposure
679 greg 2.25 : .5/bright(cval) ;
680     comp = log(comp)/.69315 - scale;
681     n = comp < 0 ? comp-.5 : comp+.5 ; /* round */
682 greg 1.1 if (n == 0)
683     return(0);
684     scale_rcolors(ourras, pow(2.0, (double)n));
685     scale += n;
686     sprintf(buf, "%+d", scale);
687 greg 1.3 XDrawImageString(thedisplay, wind, ourgc,
688     box.xmin, box.ymin+box.ysiz, buf, strlen(buf));
689 greg 1.1 XFlush(thedisplay);
690     free(ourdata);
691     free_raster(ourras);
692     getras();
693     /* fall through */
694 greg 2.3 case CTRL('R'): /* redraw */
695     case CTRL('L'):
696 greg 1.1 unmap_rcolors(ourras);
697     XClearWindow(thedisplay, wind);
698     map_rcolors(ourras, wind);
699     if (fast)
700 greg 2.12 make_rpixmap(ourras, wind);
701 greg 1.1 redraw(0, 0, width, height);
702     return(0);
703 greg 2.27 case 'f': /* turn on fast redraw */
704     fast = 1;
705     make_rpixmap(ourras, wind);
706     return(0);
707     case 'F': /* turn off fast redraw */
708     fast = 0;
709     free_rpixmap(ourras);
710     return(0);
711 greg 2.19 case '0': /* recenter origin */
712     if (xoff == 0 & yoff == 0)
713     return(0);
714     xoff = yoff = 0;
715     XClearWindow(thedisplay, wind);
716     redraw(0, 0, width, height);
717     return(0);
718 greg 1.1 case ' ': /* clear */
719     redraw(box.xmin, box.ymin, box.xsiz, box.ysiz);
720     return(0);
721     default:
722 greg 1.2 XBell(thedisplay, 0);
723 greg 1.1 return(-1);
724     }
725     }
726    
727    
728 greg 1.2 moveimage(ebut) /* shift the image */
729     XButtonPressedEvent *ebut;
730 greg 1.1 {
731 greg 2.24 XEvent e;
732 greg 1.5 int mxo, myo;
733 greg 1.1
734 greg 2.24 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
735     while (e.type == MotionNotify) {
736     mxo = e.xmotion.x;
737     myo = e.xmotion.y;
738 greg 1.5 revline(ebut->x, ebut->y, mxo, myo);
739     revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
740     xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
741 greg 2.24 XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
742 greg 1.5 revline(ebut->x, ebut->y, mxo, myo);
743     revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
744     xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
745 greg 1.3 }
746 greg 2.24 xoff += e.xbutton.x - ebut->x;
747     yoff += e.xbutton.y - ebut->y;
748 greg 1.1 XClearWindow(thedisplay, wind);
749     redraw(0, 0, width, height);
750     }
751    
752    
753     getbox(ebut) /* get new box */
754     XButtonPressedEvent *ebut;
755     {
756 greg 2.24 XEvent e;
757 greg 1.1
758 greg 2.24 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
759     while (e.type == MotionNotify) {
760     revbox(ebut->x, ebut->y, box.xmin = e.xmotion.x, box.ymin = e.xmotion.y);
761     XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
762 greg 1.1 revbox(ebut->x, ebut->y, box.xmin, box.ymin);
763     }
764 greg 2.24 box.xmin = e.xbutton.x<0 ? 0 : (e.xbutton.x>=width ? width-1 : e.xbutton.x);
765     box.ymin = e.xbutton.y<0 ? 0 : (e.xbutton.y>=height ? height-1 : e.xbutton.y);
766 greg 1.1 if (box.xmin > ebut->x) {
767     box.xsiz = box.xmin - ebut->x + 1;
768     box.xmin = ebut->x;
769     } else {
770     box.xsiz = ebut->x - box.xmin + 1;
771     }
772     if (box.ymin > ebut->y) {
773     box.ysiz = box.ymin - ebut->y + 1;
774     box.ymin = ebut->y;
775     } else {
776     box.ysiz = ebut->y - box.ymin + 1;
777     }
778     }
779    
780    
781     revbox(x0, y0, x1, y1) /* draw box with reversed lines */
782     int x0, y0, x1, y1;
783     {
784 greg 1.5 revline(x0, y0, x1, y0);
785     revline(x0, y1, x1, y1);
786     revline(x0, y0, x0, y1);
787     revline(x1, y0, x1, y1);
788     }
789 greg 1.1
790    
791     avgbox(clr) /* average color over current box */
792     COLOR clr;
793     {
794 greg 1.25 static COLOR lc;
795     static int ll, lr, lt, lb;
796 greg 1.1 int left, right, top, bottom;
797     int y;
798     double d;
799     COLOR ctmp;
800     register int x;
801    
802     setcolor(clr, 0.0, 0.0, 0.0);
803     left = box.xmin - xoff;
804     right = left + box.xsiz;
805     if (left < 0)
806     left = 0;
807     if (right > xmax)
808     right = xmax;
809     if (left >= right)
810     return(-1);
811     top = box.ymin - yoff;
812     bottom = top + box.ysiz;
813     if (top < 0)
814     top = 0;
815     if (bottom > ymax)
816     bottom = ymax;
817     if (top >= bottom)
818     return(-1);
819 greg 1.25 if (left == ll && right == lr && top == lt && bottom == lb) {
820     copycolor(clr, lc);
821 greg 2.15 return(0);
822 greg 1.25 }
823 greg 1.1 for (y = top; y < bottom; y++) {
824     if (getscan(y) == -1)
825     return(-1);
826     for (x = left; x < right; x++) {
827     colr_color(ctmp, scanline[x]);
828     addcolor(clr, ctmp);
829     }
830     }
831     d = 1.0/((right-left)*(bottom-top));
832     scalecolor(clr, d);
833 greg 1.25 ll = left; lr = right; lt = top; lb = bottom;
834     copycolor(lc, clr);
835 greg 1.1 return(0);
836     }
837    
838    
839     getmono() /* get monochrome data */
840     {
841     register unsigned char *dp;
842     register int x, err;
843 greg 1.23 int y, errp;
844 greg 1.1 short *cerr;
845    
846 greg 1.10 if ((cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
847 greg 1.9 quiterr("out of memory in getmono");
848 greg 1.1 dp = ourdata - 1;
849     for (y = 0; y < ymax; y++) {
850 greg 2.15 getscan(y);
851 greg 2.16 add2icon(y, scanline);
852 greg 1.10 normcolrs(scanline, xmax, scale);
853 greg 1.1 err = 0;
854     for (x = 0; x < xmax; x++) {
855     if (!(x&7))
856     *++dp = 0;
857 greg 1.23 errp = err;
858 greg 1.10 err += normbright(scanline[x]) + cerr[x];
859 greg 1.1 if (err > 127)
860     err -= 255;
861     else
862 greg 1.3 *dp |= 1<<(7-(x&07));
863 greg 1.23 err /= 3;
864     cerr[x] = err + errp;
865 greg 1.1 }
866     }
867     free((char *)cerr);
868     }
869    
870    
871 greg 1.17 add2icon(y, scan) /* add a scanline to our icon data */
872     int y;
873     COLR *scan;
874     {
875     static short cerr[ICONSIZ];
876 greg 1.20 static int ynext;
877     static char *dp;
878 greg 2.17 COLR clr;
879 greg 1.17 register int err;
880 greg 1.20 register int x, ti;
881 greg 1.23 int errp;
882 greg 1.17
883     if (iconheight == 0) { /* initialize */
884 greg 1.18 if (xmax <= ICONSIZ && ymax <= ICONSIZ) {
885 greg 1.17 iconwidth = xmax;
886     iconheight = ymax;
887     } else if (xmax > ymax) {
888     iconwidth = ICONSIZ;
889     iconheight = ICONSIZ*ymax/xmax;
890 greg 1.24 if (iconheight < 1)
891     iconheight = 1;
892 greg 1.17 } else {
893     iconwidth = ICONSIZ*xmax/ymax;
894 greg 1.24 if (iconwidth < 1)
895     iconwidth = 1;
896 greg 1.17 iconheight = ICONSIZ;
897     }
898 greg 1.20 ynext = 0;
899 greg 1.17 dp = icondata - 1;
900     }
901 greg 1.20 if (y < ynext*ymax/iconheight) /* skip this one */
902 greg 1.17 return;
903     err = 0;
904     for (x = 0; x < iconwidth; x++) {
905     if (!(x&7))
906     *++dp = 0;
907 greg 1.23 errp = err;
908 greg 1.20 ti = x*xmax/iconwidth;
909 greg 2.17 copycolr(clr, scan[ti]);
910     normcolrs(clr, 1, scale);
911     err += normbright(clr) + cerr[x];
912 greg 1.17 if (err > 127)
913     err -= 255;
914     else
915     *dp |= 1<<(x&07);
916 greg 1.23 err /= 3;
917     cerr[x] = err + errp;
918 greg 1.17 }
919 greg 1.20 ynext++;
920 greg 1.17 }
921    
922    
923 greg 1.1 getfull() /* get full (24-bit) data */
924     {
925     int y;
926 greg 2.28 register unsigned int4 *dp;
927 greg 1.10 register int x;
928     /* set gamma correction */
929     setcolrgam(gamcor);
930     /* read and convert file */
931 greg 2.28 dp = (unsigned int4 *)ourdata;
932 greg 1.10 for (y = 0; y < ymax; y++) {
933 greg 2.15 getscan(y);
934 greg 2.16 add2icon(y, scanline);
935 greg 1.10 if (scale)
936     shiftcolrs(scanline, xmax, scale);
937     colrs_gambs(scanline, xmax);
938 greg 2.6 if (ourras->image->blue_mask & 1)
939     for (x = 0; x < xmax; x++)
940     *dp++ = scanline[x][RED] << 16 |
941     scanline[x][GRN] << 8 |
942     scanline[x][BLU] ;
943     else
944     for (x = 0; x < xmax; x++)
945     *dp++ = scanline[x][RED] |
946     scanline[x][GRN] << 8 |
947     scanline[x][BLU] << 16 ;
948 greg 1.10 }
949 greg 1.1 }
950    
951    
952 greg 2.7 getgrey() /* get greyscale data */
953     {
954     int y;
955     register unsigned char *dp;
956     register int x;
957     /* set gamma correction */
958     setcolrgam(gamcor);
959     /* read and convert file */
960     dp = ourdata;
961     for (y = 0; y < ymax; y++) {
962 greg 2.15 getscan(y);
963 greg 2.16 add2icon(y, scanline);
964 greg 2.7 if (scale)
965     shiftcolrs(scanline, xmax, scale);
966 greg 2.18 for (x = 0; x < xmax; x++)
967     scanline[x][GRN] = normbright(scanline[x]);
968 greg 2.7 colrs_gambs(scanline, xmax);
969 greg 2.13 if (maxcolors < 256)
970 greg 2.7 for (x = 0; x < xmax; x++)
971 greg 2.18 *dp++ = ((long)scanline[x][GRN] *
972     maxcolors + maxcolors/2) >> 8;
973 greg 2.7 else
974     for (x = 0; x < xmax; x++)
975 greg 2.18 *dp++ = scanline[x][GRN];
976 greg 2.7 }
977 greg 2.13 for (x = 0; x < maxcolors; x++)
978     clrtab[x][RED] = clrtab[x][GRN] =
979 greg 2.18 clrtab[x][BLU] = ((long)x*256 + 128)/maxcolors;
980 greg 2.7 }
981    
982    
983 greg 2.13 getmapped() /* get color-mapped data */
984     {
985     int y;
986 greg 2.30 /* make sure we can do it first */
987     if (fname == NULL)
988     quiterr("cannot map colors from standard input");
989 greg 2.13 /* set gamma correction */
990     setcolrgam(gamcor);
991     /* make histogram */
992     new_histo();
993     for (y = 0; y < ymax; y++) {
994     if (getscan(y) < 0)
995 greg 2.30 break;
996 greg 2.16 add2icon(y, scanline);
997 greg 2.13 if (scale)
998     shiftcolrs(scanline, xmax, scale);
999     colrs_gambs(scanline, xmax);
1000     cnt_colrs(scanline, xmax);
1001     }
1002     /* map pixels */
1003     if (!new_clrtab(maxcolors))
1004     quiterr("cannot create color map");
1005     for (y = 0; y < ymax; y++) {
1006 greg 2.30 getscan(y);
1007 greg 2.13 if (scale)
1008     shiftcolrs(scanline, xmax, scale);
1009     colrs_gambs(scanline, xmax);
1010     if (dither)
1011     dith_colrs(ourdata+y*xmax, scanline, xmax);
1012     else
1013     map_colrs(ourdata+y*xmax, scanline, xmax);
1014     }
1015     }
1016    
1017    
1018 greg 1.1 scale_rcolors(xr, sf) /* scale color map */
1019     register XRASTER *xr;
1020     double sf;
1021     {
1022     register int i;
1023     long maxv;
1024    
1025     if (xr->pixels == NULL)
1026     return;
1027    
1028     sf = pow(sf, 1.0/gamcor);
1029     maxv = 65535/sf;
1030    
1031     for (i = xr->ncolors; i--; ) {
1032     xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
1033     65535 :
1034     xr->cdefs[i].red * sf;
1035     xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
1036     65535 :
1037     xr->cdefs[i].green * sf;
1038     xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
1039     65535 :
1040     xr->cdefs[i].blue * sf;
1041     }
1042     XStoreColors(thedisplay, xr->cmap, xr->cdefs, xr->ncolors);
1043     }
1044    
1045    
1046     getscan(y)
1047     int y;
1048     {
1049 greg 2.30 static int trunced = -1; /* truncated file? */
1050     skipit:
1051     if (trunced >= 0 && y >= trunced) {
1052     bzero(scanline, xmax*sizeof(COLR));
1053     return(-1);
1054     }
1055 greg 1.1 if (y != cury) {
1056     if (scanpos == NULL || scanpos[y] == -1)
1057     return(-1);
1058     if (fseek(fin, scanpos[y], 0) == -1)
1059 greg 1.9 quiterr("fseek error");
1060 greg 1.1 cury = y;
1061 greg 2.11 } else if (scanpos != NULL && scanpos[y] == -1)
1062 greg 1.1 scanpos[y] = ftell(fin);
1063    
1064 greg 2.30 if (freadcolrs(scanline, xmax, fin) < 0) {
1065     fprintf(stderr, "%s: %s: unfinished picture\n",
1066     progname, fname==NULL?"<stdin>":fname);
1067     trunced = y;
1068     goto skipit;
1069     }
1070 greg 1.1 cury++;
1071     return(0);
1072     }