ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 2.8
Committed: Tue Oct 27 09:08:28 1998 UTC (25 years, 6 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 2.7: +2 -0 lines
Log Message:
changed getheader() to listen to return value of passed function

File Contents

# Content
1 /* Copyright (c) 1987 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * ximage.c - driver for X-windows
9 *
10 * 4/30/87
11 * 3/3/88 Added calls to xraster & Paul Heckbert's ciq routines
12 */
13
14 #include "standard.h"
15
16 #include <X/Xlib.h>
17 #include <X/cursors/bcross.cursor>
18 #include <X/cursors/bcross_mask.cursor>
19
20 #include <sys/types.h>
21
22 #include <ctype.h>
23
24 #include "color.h"
25
26 #include "resolu.h"
27
28 #include "xraster.h"
29
30 #include "view.h"
31
32 #include "pic.h"
33
34 #include "random.h"
35
36 #define controlshift(e) (((XButtonEvent *)(e))->detail & (ShiftMask|ControlMask))
37
38 #define FONTNAME "9x15" /* text font we'll use */
39
40 #define CTRL(c) ((c)-'@')
41
42 #define BORWIDTH 5 /* border width */
43 #define BARHEIGHT 25 /* menu bar size */
44
45 double gamcor = 2.2; /* gamma correction */
46
47 XRASTER *ourras = NULL; /* our stored raster image */
48
49 int dither = 1; /* dither colors? */
50 int fast = 0; /* keep picture in Pixmap? */
51
52 Window wind = 0; /* our output window */
53 Font fontid; /* our font */
54
55 int maxcolors = 0; /* maximum colors */
56 int greyscale = 0; /* in grey */
57
58 int scale = 0; /* scalefactor; power of two */
59
60 int xoff = 0; /* x image offset */
61 int yoff = 0; /* y image offset */
62
63 VIEW ourview = STDVIEW; /* image view parameters */
64 int gotview = 0; /* got parameters from file */
65
66 COLR *scanline; /* scan line buffer */
67
68 int xmax, ymax; /* picture resolution */
69 int width, height; /* window size */
70 char *fname = NULL; /* input file name */
71 FILE *fin = stdin; /* input file */
72 long *scanpos = NULL; /* scan line positions in file */
73 int cury = 0; /* current scan location */
74
75 double exposure = 1.0; /* exposure compensation used */
76
77 int wrongformat = 0; /* input in another format */
78
79 struct {
80 int xmin, ymin, xsiz, ysiz;
81 } box = {0, 0, 0, 0}; /* current box */
82
83 char *geometry = NULL; /* geometry specification */
84
85 char *progname;
86
87 char errmsg[128];
88
89 extern long ftell();
90
91 extern char *malloc(), *calloc();
92
93 extern double pow(), log();
94
95
96 main(argc, argv)
97 int argc;
98 char *argv[];
99 {
100 extern char *getenv();
101 char *gv;
102 int headline();
103 int i;
104
105 progname = argv[0];
106 if ((gv = getenv("DISPLAY_GAMMA")) != NULL)
107 gamcor = atof(gv);
108
109 for (i = 1; i < argc; i++)
110 if (argv[i][0] == '-')
111 switch (argv[i][1]) {
112 case 'c':
113 maxcolors = atoi(argv[++i]);
114 break;
115 case 'b':
116 greyscale = !greyscale;
117 break;
118 case 'm':
119 maxcolors = 2;
120 break;
121 case 'd':
122 dither = !dither;
123 break;
124 case 'f':
125 fast = !fast;
126 break;
127 case 'e':
128 if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
129 goto userr;
130 scale = atoi(argv[++i]);
131 break;
132 case 'g':
133 gamcor = atof(argv[++i]);
134 break;
135 default:
136 goto userr;
137 }
138 else if (argv[i][0] == '=')
139 geometry = argv[i];
140 else
141 break;
142
143 if (argc-i == 1) {
144 fname = argv[i];
145 fin = fopen(fname, "r");
146 if (fin == NULL) {
147 sprintf(errmsg, "can't open file \"%s\"", fname);
148 quiterr(errmsg);
149 }
150 }
151 /* get header */
152 getheader(fin, headline, NULL);
153 /* get picture dimensions */
154 if (wrongformat || fgetresolu(&xmax, &ymax, fin) != (YMAJOR|YDECR))
155 quiterr("bad picture size");
156 /* set view parameters */
157 if (gotview && setview(&ourview) != NULL)
158 gotview = 0;
159 if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
160 quiterr("out of memory");
161
162 init(); /* get file and open window */
163
164 for ( ; ; )
165 getevent(); /* main loop */
166 userr:
167 fprintf(stderr,
168 "Usage: %s [=geometry][-b][-m][-d][-f][-c ncolors][-e +/-stops] file\n",
169 progname);
170 quit(1);
171 }
172
173
174 int
175 headline(s) /* get relevant info from header */
176 char *s;
177 {
178 char fmt[32];
179
180 if (isexpos(s))
181 exposure *= exposval(s);
182 else if (isformat(s)) {
183 formatval(fmt, s);
184 wrongformat = strcmp(fmt, COLRFMT);
185 } else if (isview(s) && sscanview(&ourview, s) > 0)
186 gotview++;
187 return(0);
188 }
189
190
191 init() /* get data and open window */
192 {
193 register int i;
194 OpaqueFrame mainframe;
195 char defgeom[32];
196
197 if (fname != NULL) {
198 scanpos = (long *)malloc(ymax*sizeof(long));
199 if (scanpos == NULL)
200 goto memerr;
201 for (i = 0; i < ymax; i++)
202 scanpos[i] = -1;
203 }
204 if (XOpenDisplay(NULL) == NULL)
205 quiterr("can't open display; DISPLAY variable set?");
206 #ifdef notdef
207 if (DisplayWidth() - 2*BORWIDTH < xmax ||
208 DisplayHeight() - 2*BORWIDTH - BARHEIGHT < ymax)
209 quiterr("resolution mismatch");
210 #endif
211 if (maxcolors == 0) { /* get number of available colors */
212 maxcolors = 1<<DisplayPlanes();
213 if (maxcolors > 4) maxcolors -= 2;
214 }
215 /* store image */
216 getras();
217
218 mainframe.bdrwidth = BORWIDTH;
219 mainframe.border = WhitePixmap;
220 mainframe.background = BlackPixmap;
221 sprintf(defgeom, "=%dx%d+0+22", xmax, ymax);
222 wind = XCreate("Radiance Image", progname, geometry, defgeom,
223 &mainframe, 16, 16);
224 if (wind == 0)
225 quiterr("can't create window");
226 width = mainframe.width;
227 height = mainframe.height;
228 fontid = XGetFont(FONTNAME);
229 if (fontid == 0)
230 quiterr("can't get font");
231 XStoreName(wind, fname == NULL ? progname : fname);
232 XDefineCursor(wind, XCreateCursor(bcross_width, bcross_height,
233 bcross_bits, bcross_mask_bits,
234 bcross_x_hot, bcross_y_hot,
235 BlackPixel, WhitePixel, GXcopy));
236 XSelectInput(wind, ButtonPressed|ButtonReleased|UnmapWindow
237 |RightDownMotion|MiddleDownMotion|LeftDownMotion
238 |KeyPressed|ExposeWindow|ExposeRegion);
239 XMapWindow(wind);
240 return;
241 memerr:
242 quiterr("out of memory");
243 }
244
245
246 quiterr(err) /* print message and exit */
247 char *err;
248 {
249 if (err != NULL)
250 fprintf(stderr, "%s: %s\n", progname, err);
251
252 exit(err == NULL ? 0 : 1);
253 }
254
255
256 eputs(s)
257 char *s;
258 {
259 fputs(s, stderr);
260 }
261
262
263 quit(code)
264 int code;
265 {
266 exit(code);
267 }
268
269
270 getras() /* get raster file */
271 {
272 colormap ourmap;
273
274 ourras = (XRASTER *)calloc(1, sizeof(XRASTER));
275 if (ourras == NULL)
276 goto memerr;
277 ourras->width = xmax;
278 ourras->height = ymax;
279 if (maxcolors <= 2) { /* monochrome */
280 ourras->data.m = (unsigned short *)malloc(BitmapSize(xmax,ymax));
281 if (ourras->data.m == NULL)
282 goto memerr;
283 getmono();
284 } else {
285 ourras->data.bz = (unsigned char *)malloc(BZPixmapSize(xmax,ymax));
286 if (ourras->data.bz == NULL)
287 goto memerr;
288 if (greyscale)
289 biq(dither,maxcolors,1,ourmap);
290 else
291 ciq(dither,maxcolors,1,ourmap);
292 if (init_rcolors(ourras, ourmap) == 0)
293 goto memerr;
294 }
295 return;
296 memerr:
297 quiterr("out of memory");
298 }
299
300
301 getevent() /* process the next event */
302 {
303 WindowInfo info;
304 XEvent e;
305
306 XNextEvent(&e);
307 switch (e.type) {
308 case KeyPressed:
309 docom(&e);
310 break;
311 case ExposeWindow:
312 XQueryWindow(wind, &info); /* in case resized */
313 width = info.width;
314 height = info.height;
315 /* fall through */
316 case ExposeRegion:
317 fixwindow(&e);
318 break;
319 case UnmapWindow:
320 unmap_rcolors(ourras);
321 break;
322 case ButtonPressed:
323 if (controlshift(&e))
324 moveimage(&e);
325 else
326 getbox(&e);
327 break;
328 }
329 }
330
331
332 fixwindow(eexp) /* fix new or stepped-on window */
333 XExposeEvent *eexp;
334 {
335 redraw(eexp->x, eexp->y, eexp->width, eexp->height);
336 }
337
338
339 redraw(x, y, w, h) /* redraw section of window */
340 int x, y;
341 int w, h;
342 {
343 if (ourras->ncolors && map_rcolors(ourras) == NULL) {
344 fprintf(stderr, "%s: cannot allocate colors\n", progname);
345 return(-1);
346 }
347 if (fast)
348 make_rpixmap(ourras);
349 return(patch_raster(wind,x-xoff,y-yoff,x,y,w,h,ourras) ? 0 : -1);
350 }
351
352
353 docom(ekey) /* execute command */
354 XKeyEvent *ekey;
355 {
356 char buf[80];
357 COLOR cval;
358 Color cvx;
359 char *cp;
360 int n;
361 double comp;
362 FVECT rorg, rdir;
363
364 cp = XLookupMapping(ekey, &n);
365 if (n == 0)
366 return(0);
367 switch (*cp) { /* interpret command */
368 case 'q':
369 case CTRL('D'): /* quit */
370 quit(0);
371 case '\n':
372 case '\r':
373 case 'l':
374 case 'c': /* value */
375 if (avgbox(cval) == -1)
376 return(-1);
377 switch (*cp) {
378 case '\n':
379 case '\r': /* radiance */
380 sprintf(buf, "%.3f", intens(cval)/exposure);
381 break;
382 case 'l': /* luminance */
383 sprintf(buf, "%.0fL", luminance(cval)/exposure);
384 break;
385 case 'c': /* color */
386 comp = pow(2.0, (double)scale);
387 sprintf(buf, "(%.2f,%.2f,%.2f)",
388 colval(cval,RED)*comp,
389 colval(cval,GRN)*comp,
390 colval(cval,BLU)*comp);
391 break;
392 }
393 XText(wind, box.xmin, box.ymin, buf, strlen(buf),
394 fontid, BlackPixel, WhitePixel);
395 return(0);
396 case 'i': /* identify (contour) */
397 if (ourras->pixels == NULL)
398 return(-1);
399 n = ourras->data.bz[ekey->x-xoff+BZPixmapSize(xmax,ekey->y-yoff)];
400 n = ourras->pmap[n];
401 cvx.pixel = ourras->cdefs[n].pixel;
402 cvx.red = random() & 65535;
403 cvx.green = random() & 65535;
404 cvx.blue = random() & 65535;
405 XStoreColor(&cvx);
406 return(0);
407 case 'p': /* position */
408 sprintf(buf, "(%d,%d)", ekey->x-xoff, ymax-1-ekey->y+yoff);
409 XText(wind, ekey->x, ekey->y, buf, strlen(buf),
410 fontid, BlackPixel, WhitePixel);
411 return(0);
412 case 't': /* trace */
413 if (!gotview) {
414 XFeep(0);
415 return(-1);
416 }
417 if (viewray(rorg, rdir, &ourview, (ekey->x-xoff+.5)/xmax,
418 (ymax-1-ekey->y+yoff+.5)/ymax) < 0)
419 return(-1);
420 printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
421 printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]);
422 fflush(stdout);
423 return(0);
424 case '=': /* adjust exposure */
425 if (avgbox(cval) == -1)
426 return(-1);
427 n = log(.5/bright(cval))/.69315 - scale; /* truncate */
428 if (n == 0)
429 return(0);
430 scale_rcolors(ourras, pow(2.0, (double)n));
431 scale += n;
432 sprintf(buf, "%+d", scale);
433 XText(wind, box.xmin, box.ymin, buf, strlen(buf),
434 fontid, BlackPixel, WhitePixel);
435 XFlush();
436 free_raster(ourras);
437 getras();
438 /* fall through */
439 case CTRL('R'): /* redraw */
440 case CTRL('L'):
441 unmap_rcolors(ourras);
442 XClear(wind);
443 return(redraw(0, 0, width, height));
444 case ' ': /* clear */
445 return(redraw(box.xmin, box.ymin, box.xsiz, box.ysiz));
446 default:
447 XFeep(0);
448 return(-1);
449 }
450 }
451
452
453 moveimage(ep) /* shift the image */
454 XButtonEvent *ep;
455 {
456 XButtonEvent eb;
457
458 XMaskEvent(ButtonReleased, &eb);
459 xoff += eb.x - ep->x;
460 yoff += eb.y - ep->y;
461 XClear(wind);
462 return(redraw(0, 0, width, height));
463 }
464
465
466 getbox(ebut) /* get new box */
467 XButtonEvent *ebut;
468 {
469 union {
470 XEvent e;
471 XButtonEvent b;
472 XMouseMovedEvent m;
473 } e;
474
475 XMaskEvent(ButtonReleased|MouseMoved, &e.e);
476 while (e.e.type == MouseMoved) {
477 revbox(ebut->x, ebut->y, box.xmin = e.m.x, box.ymin = e.m.y);
478 XMaskEvent(ButtonReleased|MouseMoved, &e.e);
479 revbox(ebut->x, ebut->y, box.xmin, box.ymin);
480 }
481 box.xmin = e.b.x<0 ? 0 : (e.b.x>=width ? width-1 : e.b.x);
482 box.ymin = e.b.y<0 ? 0 : (e.b.y>=height ? height-1 : e.b.y);
483 if (box.xmin > ebut->x) {
484 box.xsiz = box.xmin - ebut->x + 1;
485 box.xmin = ebut->x;
486 } else {
487 box.xsiz = ebut->x - box.xmin + 1;
488 }
489 if (box.ymin > ebut->y) {
490 box.ysiz = box.ymin - ebut->y + 1;
491 box.ymin = ebut->y;
492 } else {
493 box.ysiz = ebut->y - box.ymin + 1;
494 }
495 }
496
497
498 revbox(x0, y0, x1, y1) /* draw box with reversed lines */
499 int x0, y0, x1, y1;
500 {
501 XLine(wind, x0, y0, x1, y0, 1, 1, 0, GXinvert, AllPlanes);
502 XLine(wind, x0, y1, x1, y1, 1, 1, 0, GXinvert, AllPlanes);
503 XLine(wind, x0, y0, x0, y1, 1, 1, 0, GXinvert, AllPlanes);
504 XLine(wind, x1, y0, x1, y1, 1, 1, 0, GXinvert, AllPlanes);
505 }
506
507
508 avgbox(clr) /* average color over current box */
509 COLOR clr;
510 {
511 int left, right, top, bottom;
512 int y;
513 double d;
514 COLOR ctmp;
515 register int x;
516
517 setcolor(clr, 0.0, 0.0, 0.0);
518 left = box.xmin - xoff;
519 right = left + box.xsiz;
520 if (left < 0)
521 left = 0;
522 if (right > xmax)
523 right = xmax;
524 if (left >= right)
525 return(-1);
526 top = box.ymin - yoff;
527 bottom = top + box.ysiz;
528 if (top < 0)
529 top = 0;
530 if (bottom > ymax)
531 bottom = ymax;
532 if (top >= bottom)
533 return(-1);
534 for (y = top; y < bottom; y++) {
535 if (getscan(y) == -1)
536 return(-1);
537 for (x = left; x < right; x++) {
538 colr_color(ctmp, scanline[x]);
539 addcolor(clr, ctmp);
540 }
541 }
542 d = 1.0/((right-left)*(bottom-top));
543 scalecolor(clr, d);
544 return(0);
545 }
546
547
548 getmono() /* get monochrome data */
549 {
550 register unsigned short *dp;
551 register int x, err;
552 int y, errp;
553 rgbpixel *inl;
554 short *cerr;
555
556 if ((inl = (rgbpixel *)malloc(xmax*sizeof(rgbpixel))) == NULL
557 || (cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
558 quiterr("out of memory in getmono");
559 dp = ourras->data.m - 1;
560 for (y = 0; y < ymax; y++) {
561 picreadline3(y, inl);
562 err = 0;
563 for (x = 0; x < xmax; x++) {
564 if (!(x&0xf))
565 *++dp = 0;
566 errp = err;
567 err += rgb_bright(&inl[x]) + cerr[x];
568 if (err > 127)
569 err -= 255;
570 else
571 *dp |= 1<<(x&0xf);
572 err /= 3;
573 cerr[x] = err + errp;
574 }
575 }
576 free((char *)inl);
577 free((char *)cerr);
578 }
579
580
581 init_rcolors(xr, cmap) /* (re)assign color values */
582 register XRASTER *xr;
583 colormap cmap;
584 {
585 register int i;
586 register unsigned char *p;
587
588 xr->pmap = (int *)malloc(256*sizeof(int));
589 if (xr->pmap == NULL)
590 return(0);
591 xr->cdefs = (Color *)malloc(256*sizeof(Color));
592 if (xr->cdefs == NULL)
593 return(0);
594 for (i = 0; i < 256; i++)
595 xr->pmap[i] = -1;
596 xr->ncolors = 0;
597 for (p = xr->data.bz, i = BZPixmapSize(xr->width,xr->height); i--; p++)
598 if (xr->pmap[*p] == -1) {
599 xr->cdefs[xr->ncolors].red = cmap[0][*p] << 8;
600 xr->cdefs[xr->ncolors].green = cmap[1][*p] << 8;
601 xr->cdefs[xr->ncolors].blue = cmap[2][*p] << 8;
602 xr->cdefs[xr->ncolors].pixel = *p;
603 xr->pmap[*p] = xr->ncolors++;
604 }
605 xr->cdefs = (Color *)realloc((char *)xr->cdefs, xr->ncolors*sizeof(Color));
606 if (xr->cdefs == NULL)
607 return(0);
608 return(1);
609 }
610
611
612 scale_rcolors(xr, sf) /* scale color map */
613 register XRASTER *xr;
614 double sf;
615 {
616 register int i;
617 long maxv;
618
619 if (xr->pixels == NULL)
620 return;
621
622 sf = pow(sf, 1.0/gamcor);
623 maxv = 65535/sf;
624
625 for (i = xr->ncolors; i--; ) {
626 xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
627 65535 :
628 xr->cdefs[i].red * sf;
629 xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
630 65535 :
631 xr->cdefs[i].green * sf;
632 xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
633 65535 :
634 xr->cdefs[i].blue * sf;
635 }
636 XStoreColors(xr->ncolors, xr->cdefs);
637 }
638
639
640 getscan(y)
641 int y;
642 {
643 if (y != cury) {
644 if (scanpos == NULL || scanpos[y] == -1)
645 return(-1);
646 if (fseek(fin, scanpos[y], 0) == -1)
647 quiterr("fseek error");
648 cury = y;
649 } else if (scanpos != NULL && scanpos[y] == -1)
650 scanpos[y] = ftell(fin);
651
652 if (freadcolrs(scanline, xmax, fin) < 0)
653 quiterr("read error");
654
655 cury++;
656 return(0);
657 }
658
659
660 picreadline3(y, l3) /* read in 3-byte scanline */
661 int y;
662 register rgbpixel *l3;
663 {
664 register int i;
665 /* read scanline */
666 if (getscan(y) < 0)
667 quiterr("cannot seek for picreadline");
668 /* convert scanline */
669 normcolrs(scanline, xmax, scale);
670 for (i = 0; i < xmax; i++) {
671 l3[i].r = scanline[i][RED];
672 l3[i].g = scanline[i][GRN];
673 l3[i].b = scanline[i][BLU];
674 }
675 }
676
677
678 picwriteline(y, l) /* add 8-bit scanline to image */
679 int y;
680 pixel *l;
681 {
682 bcopy((char *)l, (char *)ourras->data.bz+BZPixmapSize(xmax,y), BZPixmapSize(xmax,1));
683 }
684
685
686 picreadcm(map) /* do gamma correction */
687 colormap map;
688 {
689 extern double pow();
690 register int i, val;
691
692 for (i = 0; i < 256; i++) {
693 val = pow((i+0.5)/256.0, 1.0/gamcor) * 256.0;
694 map[0][i] = map[1][i] = map[2][i] = val;
695 }
696 }
697
698
699 picwritecm(map) /* handled elsewhere */
700 colormap map;
701 {
702 #ifdef DEBUG
703 register int i;
704
705 for (i = 0; i < 256; i++)
706 printf("%d %d %d\n", map[0][i],map[1][i],map[2][i]);
707 #endif
708 }