--- ray/src/common/color.c 1990/10/19 11:13:02 1.13 +++ ray/src/common/color.c 2004/09/14 02:53:50 2.15 @@ -1,68 +1,107 @@ -/* Copyright (c) 1986 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: color.c,v 2.15 2004/09/14 02:53:50 greg Exp $"; #endif - /* * color.c - routines for color calculations. * - * 10/10/85 + * Externals declared in color.h */ +#include "copyright.h" + #include +#include + +#include + #include "color.h" +#ifdef getc_unlocked /* avoid horrendous overhead of flockfile */ +#undef getc +#undef putc +#define getc getc_unlocked +#define putc putc_unlocked +#endif +#define MINELEN 8 /* minimum scanline length for encoding */ +#define MAXELEN 0x7fff /* maximum scanline length for encoding */ +#define MINRUN 4 /* minimum run length */ + + +char * +tempbuffer(len) /* get a temporary buffer */ +unsigned int len; +{ + static char *tempbuf = NULL; + static unsigned tempbuflen = 0; + + if (len > tempbuflen) { + if (tempbuflen > 0) + tempbuf = (char *)realloc((void *)tempbuf, len); + else + tempbuf = (char *)malloc(len); + tempbuflen = tempbuf==NULL ? 0 : len; + } + return(tempbuf); +} + + +int fwritecolrs(scanline, len, fp) /* write out a colr scanline */ register COLR *scanline; int len; register FILE *fp; { - COLR lastcolr; - int rept; + register int i, j, beg, cnt = 1; + int c2; - lastcolr[RED] = lastcolr[GRN] = lastcolr[BLU] = 1; - lastcolr[EXP] = 0; - rept = 0; - - while (len > 0) { - if (scanline[0][EXP] == lastcolr[EXP] && - scanline[0][RED] == lastcolr[RED] && - scanline[0][GRN] == lastcolr[GRN] && - scanline[0][BLU] == lastcolr[BLU]) - rept++; - else { - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; + if ((len < MINELEN) | (len > MAXELEN)) /* OOBs, write out flat */ + return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len); + /* put magic header */ + putc(2, fp); + putc(2, fp); + putc(len>>8, fp); + putc(len&255, fp); + /* put components seperately */ + for (i = 0; i < 4; i++) { + for (j = 0; j < len; j += cnt) { /* find next run */ + for (beg = j; beg < len; beg += cnt) { + for (cnt = 1; cnt < 127 && beg+cnt < len && + scanline[beg+cnt][i] == scanline[beg][i]; cnt++) + ; + if (cnt >= MINRUN) + break; /* long enough */ + } + if (beg-j > 1 && beg-j < MINRUN) { + c2 = j+1; + while (scanline[c2++][i] == scanline[j][i]) + if (c2 == beg) { /* short run */ + putc(128+beg-j, fp); + putc(scanline[j][i], fp); + j = beg; + break; } - putc(scanline[0][RED], fp); /* new color */ - putc(scanline[0][GRN], fp); - putc(scanline[0][BLU], fp); - putc(scanline[0][EXP], fp); - copycolr(lastcolr, scanline[0]); - rept = 0; } - scanline++; - len--; + while (j < beg) { /* write out non-run */ + if ((c2 = beg-j) > 128) c2 = 128; + putc(c2, fp); + while (c2--) + putc(scanline[j++][i], fp); + } + if (cnt >= MINRUN) { /* write out run */ + putc(128+cnt, fp); + putc(scanline[beg][i], fp); + } else + cnt = 0; + } } - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } return(ferror(fp) ? -1 : 0); } -freadcolrs(scanline, len, fp) /* read in a colr scanline */ +static int +oldreadcolrs(scanline, len, fp) /* read in an old colr scanline */ register COLR *scanline; int len; register FILE *fp; @@ -98,99 +137,115 @@ register FILE *fp; } +int +freadcolrs(scanline, len, fp) /* read in an encoded colr scanline */ +register COLR *scanline; +int len; +register FILE *fp; +{ + register int i, j; + int code, val; + /* determine scanline type */ + if ((len < MINELEN) | (len > MAXELEN)) + return(oldreadcolrs(scanline, len, fp)); + if ((i = getc(fp)) == EOF) + return(-1); + if (i != 2) { + ungetc(i, fp); + return(oldreadcolrs(scanline, len, fp)); + } + scanline[0][GRN] = getc(fp); + scanline[0][BLU] = getc(fp); + if ((i = getc(fp)) == EOF) + return(-1); + if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) { + scanline[0][RED] = 2; + scanline[0][EXP] = i; + return(oldreadcolrs(scanline+1, len-1, fp)); + } + if ((scanline[0][BLU]<<8 | i) != len) + return(-1); /* length mismatch! */ + /* read each component */ + for (i = 0; i < 4; i++) + for (j = 0; j < len; ) { + if ((code = getc(fp)) == EOF) + return(-1); + if (code > 128) { /* run */ + code &= 127; + if ((val = getc(fp)) == EOF) + return -1; + while (code--) + scanline[j++][i] = val; + } else /* non-run */ + while (code--) { + if ((val = getc(fp)) == EOF) + return -1; + scanline[j++][i] = val; + } + } + return(0); +} + + +int fwritescan(scanline, len, fp) /* write out a scanline */ register COLOR *scanline; int len; -register FILE *fp; +FILE *fp; { - COLR lastcolr, thiscolr; - int rept; - - lastcolr[RED] = lastcolr[GRN] = lastcolr[BLU] = 1; - lastcolr[EXP] = 0; - rept = 0; - - while (len > 0) { - setcolr(thiscolr, scanline[0][RED], + COLR *clrscan; + int n; + register COLR *sp; + /* get scanline buffer */ + if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) + return(-1); + clrscan = sp; + /* convert scanline */ + n = len; + while (n-- > 0) { + setcolr(sp[0], scanline[0][RED], scanline[0][GRN], scanline[0][BLU]); - if (thiscolr[EXP] == lastcolr[EXP] && - thiscolr[RED] == lastcolr[RED] && - thiscolr[GRN] == lastcolr[GRN] && - thiscolr[BLU] == lastcolr[BLU]) - rept++; - else { - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - putc(thiscolr[RED], fp); /* new color */ - putc(thiscolr[GRN], fp); - putc(thiscolr[BLU], fp); - putc(thiscolr[EXP], fp); - copycolr(lastcolr, thiscolr); - rept = 0; - } scanline++; - len--; + sp++; } - while (rept) { /* write out count */ - putc(1, fp); - putc(1, fp); - putc(1, fp); - putc(rept & 255, fp); - rept >>= 8; - } - return(ferror(fp) ? -1 : 0); + return(fwritecolrs(clrscan, len, fp)); } +int freadscan(scanline, len, fp) /* read in a scanline */ register COLOR *scanline; int len; -register FILE *fp; +FILE *fp; { - COLR thiscolr; - int rshift; - register int i; - - rshift = 0; - - while (len > 0) { - thiscolr[RED] = getc(fp); - thiscolr[GRN] = getc(fp); - thiscolr[BLU] = getc(fp); - thiscolr[EXP] = getc(fp); - if (feof(fp) || ferror(fp)) - return(-1); - if (thiscolr[RED] == 1 && - thiscolr[GRN] == 1 && - thiscolr[BLU] == 1) { - for (i = thiscolr[EXP] << rshift; i > 0; i--) { - copycolor(scanline[0], scanline[-1]); - scanline++; - len--; - } - rshift += 8; - } else { - colr_color(scanline[0], thiscolr); - scanline++; - len--; - rshift = 0; - } + register COLR *clrscan; + + if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL) + return(-1); + if (freadcolrs(clrscan, len, fp) < 0) + return(-1); + /* convert scanline */ + colr_color(scanline[0], clrscan[0]); + while (--len > 0) { + scanline++; clrscan++; + if (clrscan[0][RED] == clrscan[-1][RED] && + clrscan[0][GRN] == clrscan[-1][GRN] && + clrscan[0][BLU] == clrscan[-1][BLU] && + clrscan[0][EXP] == clrscan[-1][EXP]) + copycolor(scanline[0], scanline[-1]); + else + colr_color(scanline[0], clrscan[0]); } return(0); } +void setcolr(clr, r, g, b) /* assign a short color value */ register COLR clr; double r, g, b; { - double frexp(); double d; int e; @@ -203,15 +258,26 @@ double r, g, b; return; } - d = frexp(d, &e) * 256.0 / d; + d = frexp(d, &e) * 255.9999 / d; - clr[RED] = r * d; - clr[GRN] = g * d; - clr[BLU] = b * d; + if (r > 0.0) + clr[RED] = r * d; + else + clr[RED] = 0; + if (g > 0.0) + clr[GRN] = g * d; + else + clr[GRN] = 0; + if (b > 0.0) + clr[BLU] = b * d; + else + clr[BLU] = 0; + clr[EXP] = e + COLXS; } +void colr_color(col, clr) /* convert short to float color */ register COLOR col; register COLR clr; @@ -229,6 +295,7 @@ register COLR clr; } +int bigdiff(c1, c2, md) /* c1 delta c2 > md? */ register COLOR c1, c2; double md;