ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 2.10
Committed: Wed Apr 23 00:52:34 2003 UTC (21 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.9: +1 -1 lines
Log Message:
Added (void *) cast to realloc calls

File Contents

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