ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 2.1
Committed: Tue Nov 12 16:05:14 1991 UTC (32 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.31: +2 -0 lines
Log Message:
updated revision number for release 2.0

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