/* Copyright (c) 1986 Regents of the University of California */ #ifndef lint static char SCCSid[] = "$SunId$ LBL"; #endif /* * aedimage.c - RADIANCE driver for AED 512 terminal. * * 3/20/86 * 3/3/88 Added calls to Paul Heckbert's ciq routines */ #include #include #include #include "pic.h" #include "color.h" /* AED command characters */ #define AEDFMT "1888N" /* Format string to send to AED */ #define CSTAT 0100 /* Console status: lower case */ #define SCS 96 /* Set Console Status */ #define SCT 75 /* Set color lookup table */ #define SEC 67 /* Set color for vector drawing */ #define MOV 81 /* Set CAP (current access pointer) to x, y */ #define MVR 105 /* Set CAP relative */ #define DVA 65 /* Draw vector to new CAP x, y */ #define DVR 108 /* Draw vector relative */ #define WHS 88 /* Write horizontal scan */ #define WHR 92 /* Write horizontal runs */ #define OPT 40 /* Miscellaneous terminal control */ #define SEN 71 /* Set encoding types */ #define RST 48 /* Reset terminal */ #define FFD 12 /* Clear screen */ #define SCS 96 /* Set status */ #define DAI 114 /* Define area of interest */ #define EJC 85 /* Enable Joystick cursor positioning */ #define DJC 100 /* Disable Joystick cursor positioning */ #define SCC 99 /* Set Cursor Colors */ #define SCP 93 /* Set Cursor Parameters */ #define RCP 106 /* Read Cursor Position */ #define MAXRLEN 255 /* Maximum runlength for a span */ #define NUL 0 /* Null terminates run sequences */ #define ESC 27 /* Escape starts a command sequence */ #define END 1 /* Ctrl-A used to terminate command mode */ #define BLK 0 /* color table entry for black */ #define WHT 7 /* color table entry for white */ #define command(c) (putc(ESC, stdout), putc(c, stdout)) #define byte(b) putc(b, stdout) #define flush() fflush(stdout) #define GAMMA 2.5 /* gamma value used in correction */ #define MINCOLOR 8 /* start of device color table */ #define NCOLORS 248 /* available color table size */ #define NROWS 512 /* maximum # rows for output */ #define NCOLS 512 /* maximum # columns for output */ int dither = 0; /* dither colors? */ int greyscale = 0; /* grey only? */ int initialized = 0; struct sgttyb oldflags; int oldlmode; int intrcnt = 0; /* interrupt well */ #define disintr() (intrcnt--) /* disable interrupts */ #define enaintr() onintr() /* enable interrupts */ char *progname; char errmsg[128]; COLR scanline[NCOLS]; colormap colrtbl; int cury; int xmax, ymax; FILE *fin; extern long ftell(); long scanpos[NROWS]; extern double atof(); double exposure = 1.0; main(argc, argv) int argc; char *argv[]; { int onintr(), checkhead(); char sbuf[256]; register int i; progname = argv[0]; #ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); #endif if (signal(SIGINT, onintr) == SIG_IGN) signal(SIGINT, SIG_IGN); for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch (argv[i][1]) { case 'd': dither = !dither; break; case 'b': greyscale = !greyscale; break; default: goto userr; } else break; if (i+1 != argc) goto userr; if ((fin = fopen(argv[i], "r")) == NULL) { sprintf(errmsg, "can't open file \"%s\"", argv[i]); quitmsg(errmsg); } /* get header */ getheader(fin, checkhead); /* get picture dimensions */ if (fgetresolu(&xmax, &ymax, fin) != (YMAJOR|YDECR)) quitmsg("bad picture size"); if (xmax > NCOLS || ymax > NROWS) quitmsg("resolution mismatch"); init(); /* initialize terminal for output */ for (i = 0; i < NROWS; i++) scanpos[i] = -1; if (greyscale) /* map colors and display */ biq(dither,NCOLORS,1,colrtbl); else ciq(dither,NCOLORS,1,colrtbl); loopcom(); quitmsg(NULL); userr: fprintf(stderr, "Usage: %s [-d][-b] input\n", progname); quit(1); } checkhead(line) /* deal with line from header */ char *line; { if (!strncmp(line, "EXPOSURE=", 9)) exposure *= atof(line+9); } init() /* initialize terminal */ { struct sgttyb flags; int lmode; if (isatty(1)) { /* Set literal mode so AED gets bit 8 */ ioctl(1, TIOCLGET, &oldlmode); lmode = oldlmode | LLITOUT | LNOFLSH; ioctl(1, TIOCLSET, &lmode); ioctl(1, TIOCLGET, &lmode); /* 4.2 bug */ /* Turn terminal echoing off */ ioctl(1, TIOCGETP, &oldflags); ioctl(1, TIOCGETP, &flags); flags.sg_flags &= ~ECHO; ioctl(1, TIOCSETP, &flags); initialized = 1; } else quitmsg("output must be to a terminal"); /* Reset AED and tell it the data format */ command(RST); longwait(2); command(OPT); byte(6); byte(1); /* AED command set */ command(SEN); fputs(AEDFMT, stdout); command(SCS); byte(CSTAT); /* console status */ command(FFD); /* clear screen */ flush(); } onintr() /* die gracefully */ { if (++intrcnt > 0) quitmsg("interrupt"); } quitmsg(err) /* uninitialize terminal and exit */ char *err; { if (initialized) { /* close AED */ command(DJC); /* disable cursor */ command(SEC); byte(WHT); /* Set color to white */ aedsetcap(0, 0); /* Put cursor in a good place */ byte(END); flush(); ioctl(1, TIOCSETP, &oldflags); ioctl(1, TIOCLSET, &oldlmode); putchar('\n'); } if (err != NULL) { fprintf(stderr, "%s: %s\n", progname, err); exit(1); } exit(0); } eputs(s) char *s; { fputs(s, stderr); } quit(status) int status; { quitmsg(status ? "aborted" : NULL); } loopcom() /* print pixel values interactively */ { int coffset[3]; /* color table offset */ struct sgttyb flags; COLOR cval, ctmp; int rept, x, y, j; register int com, i; /* Set raw mode on input */ ioctl(0, TIOCGETP, &flags); flags.sg_flags |= RAW; flags.sg_flags &= ~ECHO; ioctl(0, TIOCSETP, &flags); coffset[0] = coffset[1] = coffset[2] = 0; /* set cursor type */ command(SCC); byte(BLK); byte(WHT); byte(15); command(SCP); byte('+'); byte(0); byte(1); /* loop on command */ for ( ; ; ) { command(EJC); /* enable cursor */ flush(); rept = 0; /* get command */ while ((com = getc(stdin)) >= '0' && com <= '9') rept = rept*10 + com - '0'; if (rept == 0) rept = 1; command(DJC); /* disable cursor */ switch (com) { case '\r': case '\n': case 'l': case 'L': case 'c': case 'C': case 'p': case 'P': case '=': aedgetcap(&x, &y); /* get cursor position */ y = ymax-1-y; if (y < 0 || scanpos[y] == -1) /* off picture? */ break; /* get value */ setcolor(cval, 0.0, 0.0, 0.0); for (j = rept-1; j >= 0; j--) { if (y+j >= NROWS || scanpos[y+j] == -1) continue; getscan(y+j); for (i = 0; i < rept; i++) if (x+i < xmax) { colr_color(ctmp, scanline[x+i]); addcolor(cval, ctmp); } } scalecolor(cval, 1.0/(rept*rept)); /* print value */ command(SEC); byte(scanline[(x+20)%xmax][EXP] >= COLXS ? BLK : WHT); byte(END); switch (com) { case '\r': case '\n': printf("%-3g", intens(cval)/exposure); break; case 'l': case 'L': printf("%-3gL", bright(cval)*683.0/exposure); break; case 'c': case 'C': printf("(%.2f,%.2f,%.2f)", colval(cval,RED), colval(cval,GRN), colval(cval,BLU)); break; case 'p': case 'P': printf("(%d,%d)", x, y); break; case '=': printf("(%d,%d,%d)", coffset[0], coffset[1], coffset[2]); break; } break; case 'w': rept = -rept; case 'W': coffset[0] += rept; coffset[1] += rept; coffset[2] += rept; movecolor(coffset); break; case 'r': rept = -rept; case 'R': coffset[0] += rept; movecolor(coffset); break; case 'g': rept = -rept; case 'G': coffset[1] += rept; movecolor(coffset); break; case 'b': rept = -rept; case 'B': coffset[2] += rept; movecolor(coffset); break; case '!': coffset[0] = coffset[1] = coffset[2] = 0; movecolor(coffset); break; case 'C'-'@': case 'q': case 'Q': return; } } } getscan(y) int y; { if (y != cury) { if (scanpos[y] == -1) quitmsg("cannot seek in getscan"); if (fseek(fin, scanpos[y], 0) == -1) quitmsg("fseek error"); cury = y; } else scanpos[y] = ftell(fin); if (freadcolrs(scanline, xmax, fin) < 0) quitmsg("read error"); cury++; } picreadline3(y, l3) /* read in 3-byte scanline */ int y; register rgbpixel *l3; { register BYTE *l4; register int shift, c; int i; getscan(y); /* convert scanline */ for (l4=scanline[0], i=xmax; i--; l4+=4, l3++) { shift = l4[EXP] - COLXS; if (shift >= 8) { l3->r = l3->g = l3->b = 255; } else if (shift <= -8) { l3->r = l3->g = l3->b = 0; } else if (shift > 0) { c = l4[RED] << shift; l3->r = c > 255 ? 255 : c; c = l4[GRN] << shift; l3->g = c > 255 ? 255 : c; c = l4[BLU] << shift; l3->b = c > 255 ? 255 : c; } else if (shift < 0) { l3->r = l4[RED] >> -shift; l3->g = l4[GRN] >> -shift; l3->b = l4[BLU] >> -shift; } else { l3->r = l4[RED]; l3->g = l4[GRN]; l3->b = l4[BLU]; } } } picwriteline(y, l) /* output scan line of pixel values */ int y; register pixel *l; { int curpix; register int n, ncols; disintr(); /* disable interrupts */ aedsetcap(0, ymax-1-y); command(DAI); aedcoord(xmax-1, ymax-1-y); ncols = xmax; if (dither) { /* pixel run lengths short */ command(WHS); while (ncols-- > 0) byte(MINCOLOR + *l++); } else { /* pixel run lengths long */ command(WHR); while (ncols-- > 0) { curpix = *l++; for (n = 1; n < MAXRLEN; n++) { if (ncols <= 0 || *l != curpix) break; l++; ncols--; } byte(n); byte(MINCOLOR + curpix); } byte(NUL); } flush(); enaintr(); /* enable interrupts */ } /* * aedsetcap - sets AED's current access pointer to (x, y). Used * before writing a span to put it in the right place. */ aedsetcap(x, y) register int x, y; { command(MOV); aedcoord(x, y); } /* * aedcoord - puts out an (x, y) coordinate in AED 8 bit format. */ aedcoord(x, y) register int x, y; { putc(((x >> 4) & 0x30) | ((y >> 8) & 0x3), stdout); putc(x & 0xff, stdout); putc(y & 0xff, stdout); } aedgetcap(xp, yp) /* get cursor postion */ int *xp, *yp; { register int c; /* get cursor postition */ command(RCP); flush(); c = getc(stdin); *xp = (c & 0x30) << 4; *yp = (c & 0x3) << 8; *xp |= getc(stdin); *yp |= getc(stdin); } movecolor(offset) /* move our color table up or down */ int offset[3]; { register int i, j, c; disintr(); command(SCT); byte(MINCOLOR); byte(NCOLORS); for (i = 0; i < NCOLORS; i++) for (j = 0; j < 3; j++) { c = colrtbl[j][i] + offset[j]; if (c < 0) byte(0); else if (c > 255) byte(255); else byte(c); } shortwait(20); enaintr(); } picreadcm(map) /* do gamma correction */ colormap map; { extern double pow(); register int i, val; for (i = 0; i < 256; i++) { val = pow(i/256.0, 1.0/GAMMA) * 256.0; map[0][i] = map[1][i] = map[2][i] = val; } } picwritecm(map) /* write out color map */ colormap map; { register int i, j; disintr(); command(SCT); byte(MINCOLOR); byte(NCOLORS); for (i = 0; i < NCOLORS; i++) for (j = 0; j < 3; j++) byte(map[j][i]); shortwait(20); enaintr(); } longwait(t) /* longer wait */ int t; { flush(); sleep(t); } shortwait(t) /* shorter wait */ int t; { register long l = t*1000; flush(); while (l--) ; }