* <idchar><subseg>
*
* `..' group is for unspecified segments.
+ * `0.' group is for background.
*
* <subseg> is
* <segnum> for fixed track
/*---------- lookup data structure ----------*/
-struct idinfo {
- double alpha, red, green, blue;
+struct result {
+ double alpha, rgb[3];
};
typedef unsigned char id;
#define MAXSEGNUM ((1<<10)-1)
#define MAXMOVFEATPOS ((1<<6)-1)
-static struct idinfo idinfo[NCHARS];
+static struct result idinfo[NCHARS];
+static struct result background;
static id *fixed;
static int fixed_a;
/*---------- specification args ----------*/
static void idgroupargs(id ix) {
- struct idinfo *r;
+ struct result *r;
+ int i;
r= &idinfo[ix];
- r->alpha = doublearg();
- r->red = doublearg();
- r->green = doublearg();
- r->blue = doublearg();
+ r->alpha= doublearg();
+ for (i=0; i<3; i++)
+ r->rgb[i]= doublearg();
}
static void ensure_somethings(void **ary, int *allocd, int want, size_t item,
ENSURE_THINGS(mps,struct movperseg);
static void subsegarg(id ix, const char *arg) {
- struct idinfo *r;
+ struct result *r;
struct movperseg *mps;
unsigned long segnum, movfeatpos;
char *ep;
exit(12);
}
+static unsigned reverse_bits_in_byte (unsigned a) {
+ unsigned b, c, d;
+ b= ((a >> 1) & 0x55) | ((a << 1) & 0xaa);
+ c= ((b >> 2) & 0x33) | ((b << 2) & 0xcc);
+ d= ((c >> 4) & 0x0f) | ((c << 4) & 0xf0);
+ return d;
+}
+
+static void angle_to_colour(double result[3],
+ double angle /* in units of 2pi radians< <1.0 */) {
+ /* Inspired by http://www.acm.org/jgt/papers/SmithLyons96/hsv_rgb.html */
+ int i;
+ double f;
+
+ angle *= 6.0;
+ i= floor(angle);
+ f= angle - i;
+
+ if (i&1) f= 1.0 - f;
+
+ switch (i) {
+#define R(r,g,b) if(1){ result[0]=r; result[1]=g; result[2]=b; break; }else
+ case 0: R( 1, f, 0 );
+ case 1: R( f, 1, 0 );
+ case 2: R( 0, 1, f );
+ case 3: R( 0, f, 1 );
+ case 4: R( f, 0, 1 );
+ case 5: R( 1, 0, f );
+#undef R
+ }
+}
+
static void process(void) {
+ int row, col, i;
+
ppm_readppminit(encodingfile, &cols, &rows, &maxval, &informat);
- if (maxval != 255) badformat("bad maxval");
- if (informat != RPPM_FORMAT) badformat("bad format");
+ if (maxval != 255) badformat("wrong maxval");
+ if (informat != RPPM_FORMAT) badformat("wrong format");
ppm_writeppminit(stdout, cols, rows, 255, 0);
+
+ for (row=0; row<rows; row++)
+ for (col=0; col<cols; col++) {
+ unsigned char rgbi[3], rgbo[3];
+ double rgbod[3];
+
+ if (fread(rgbi,1,3,encodingfile)!=-3) {
+ if (ferror(encodingfile)) { perror("reading"); exit(12); }
+ else badformat("truncated file");
+ }
+
+ if (rgbi[0]==255 && rgbi[1]==255 && rgbi[2]==255) {
+
+ for (i=0; i<3; i++)
+ rgbod[i]= background.rgb[i];
+
+ } else {
+ int segnum, movfeatpos, red, blue, green, ix;
+ double rgbdirn[3], angle;
+ struct result *r;
+
+ red= rgbi[0];
+ green= reverse_bits_in_byte(rgbi[1]);
+ blue= reverse_bits_in_byte(rgbi[2]);
+
+ if (red & 0x03) badformat("reserved bits set in red");
+ angle= ((red >> 2) & 0x3f) / 64.0;
+
+ segnum= blue | ((green & 0xc0) << 2);
+ movfeatpos= green & 0x3f;
+
+ assert(segnum <= MAXSEGNUM);
+ assert(movfeatpos <= MAXMOVFEATPOS);
+
+ angle_to_colour(rgbdirn, angle);
+
+ ix= !movfeatpos ?
+ (segnum < fixed_a ? fixed[segnum] : fixed[0]) :
+ (segnum < moveable_a && movfeatpos < moveable[segnum].lookup_a
+ ? moveable[segnum].lookup[movfeatpos] : fixed[0]);
+
+ r= &idinfo[ix];
+
+ for (i=0; i<3; i++)
+ rgbod[i]= r->alpha * rgbdirn[i] + (1.0 - r->alpha) * r->rgb[i];
+
+ }
+
+ for (i=0; i<3; i++)
+ rgbo[i]= rgbod[i] * 255.0;
+
+ if (fwrite(rgbi,1,3,stdout)!=3) { perror("writing"); exit(12); }
+ }
}
int main(int argc_spec, char **argv_spec) {