ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 2.13
Committed: Fri Jan 2 12:47:01 2004 UTC (20 years, 3 months ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6P1, rad3R6
Changes since 2.12: +8 -5 lines
Log Message:
Fixed typing/prototype of getheader() and its callback.

File Contents

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