ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 2.12
Committed: Mon Jun 30 14:59:12 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.11: +3 -9 lines
Log Message:
Replaced most outdated BSD function calls with their posix equivalents, and cleaned up a few other platform dependencies.

File Contents

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