3 * subseg2display encoding.ppm [status-info ...]
5 * status-info args are:
6 * <idchar> <alpha> <red> <green> <blue>
7 * .. <alpha> <red> <green> <blue>
8 * 0. <alpha> <red> <green> <blue>
11 * `..' group is for unspecified segments.
12 * `0.' group is for background.
15 * <segnum> for fixed track
16 * <segnum>.<movfeatpos> for part of a moveable feature
17 * where numbers are in strtoul base=0 format, movfeatpos is the
18 * moveable feature and position as in segcmapassign and
22 * (|alpha| * DIRECTION_COLOUR) + ((1-|alpha|) * [ green ] )
25 * where DIRECTION_COLOUR corresponds to the reverse of the stated
26 * direction iff alpha<0.
28 * All of alpha, red, green, blue are out of 1000.
45 /*---------- lookup data structure ----------*/
51 typedef unsigned char id;
60 static struct result idinfo[NCHARS];
61 static struct result background;
66 static struct movperseg *moveable;
67 static int moveable_a;
69 /*---------- arg parsing helper routines ----------*/
73 static void badusage(void) {
74 fprintf(stderr,"bad usage\n");
78 static const char *nextarg(void) {
79 if (!*argv) badusage();
83 static double channelarg(void) {
84 const char *arg= nextarg();
91 if (errno) badusage();
92 if (!finite(v)) badusage();
97 /*---------- specification args ----------*/
99 static void resultargs(struct result *r) {
102 r->alpha= channelarg();
104 r->rgb[i]= channelarg();
107 static void idgroupargs(id ix) {
108 resultargs(&idinfo[ix]);
111 static void ensure_somethings(void **ary, int *allocd, int want, size_t item,
112 void zero(void *data, int count)) {
115 if (*allocd > want) return;
116 new_allocd= (want+1)*2;
117 *ary= xrealloc(*ary, new_allocd * item);
118 zero((char*)*ary + item * *allocd, new_allocd - *allocd);
122 static void zero_ids(void *data, int count) {
123 memset(data,0, count*sizeof(id));
126 static void zero_mps(void *data_v, int count) {
127 struct movperseg *data= data_v;
128 for (count /= sizeof(*data);
136 #define ENSURE_THINGS(sfx,type) \
137 static void ensure_##sfx(type **ary_io, int *allocd, int want) { \
138 void *ary= *ary_io; \
139 ensure_somethings(&ary,allocd,want,sizeof(**ary_io),zero_##sfx); \
144 ENSURE_THINGS(ids,id);
145 ENSURE_THINGS(mps,struct movperseg);
147 static void subsegarg(id ix, const char *arg) {
149 struct movperseg *mps;
150 unsigned long segnum, movfeatpos;
156 segnum= strtoul(arg,&ep,0);
157 if (errno) badusage();
158 if (segnum > SEGNUM_MAX) badusage();
161 ensure_ids(&fixed,&fixed_a,segnum);
166 if (*ep != '.') badusage();
169 movfeatpos= strtoul(ep+1,&ep,0);
170 if (*ep || errno) badusage();
171 if (movfeatpos > MOVFEATPOS_MAX) badusage();
173 ensure_mps(&moveable,&moveable_a,segnum);
174 mps= &moveable[segnum];
175 ensure_ids(&mps->lookup,&mps->lookup_a, movfeatpos ^ MOVFEATPOS_MAX);
176 mps->lookup[movfeatpos ^ MOVFEATPOS_MAX]= ix;
179 /*---------- actual image processing ----------*/
181 static int cols, rows, informat, row, col;
182 static pixval maxval;
183 static FILE *encodingfile;
185 static void badformat(const char *m) {
186 fprintf(stderr,"bad format (row=%d,col=%d): %s\n", row,col, m);
190 static void angle_to_colour(double result[3],
191 int angle_i /* [0..ANGLE_MAX> */) {
193 double angle, f, u, d, U, D;
195 angle= angle_i / (double)NANGLES * 6.0;
205 #define R(r,g,b) if(1){ result[0]=r; result[1]=g*0.9; result[2]=b; break; }else
206 case 0: R( D, U, 0 );
207 case 1: R( d, 1, u );
208 case 2: R( 0, D, U );
209 case 3: R( u, d, 1 );
210 case 4: R( U, 0, D );
211 case 5: R( 1, u, d );
216 static double anglemap[NANGLES][3];
218 static void angle_to_colour_init(void) {
221 for (i=0; i<NANGLES; i++)
222 angle_to_colour(anglemap[i],i);
225 static void process(void) {
227 unsigned char rgbob[3];
229 ppm_readppminit(encodingfile, &cols, &rows, &maxval, &informat);
230 if (maxval != 255) badformat("wrong maxval");
231 if (informat != RPPM_FORMAT) badformat("wrong format");
232 ppm_writeppminit(stdout, cols, rows, 255, 0);
235 rgbob[i]= background.rgb[i] * 255.0;
237 angle_to_colour_init();
239 for (row=0; row<rows; row++)
240 for (col=0; col<cols; col++) {
241 unsigned char rgbi[3], rgbo[3];
244 if (fread(rgbi,1,3,encodingfile)!=3) {
245 if (ferror(encodingfile)) { perror("reading"); exit(12); }
246 else badformat("truncated file");
249 datum= ARY2DATUM(rgbi);
251 if (datum == BACKGROUND) {
253 if (fwrite(rgbob,1,3,stdout)!=3) { perror("filling"); exit(12); }
256 int segnum, movfeatpos, movfeatposix, ix, angle;
257 double *rgbdirn, alpha;
260 if (datum & RESERVED_MASK) badformat("reserved bits set");
261 angle= DATUM2(ANGLE,datum);
263 segnum= DATUM2(SEGNUM,datum);
264 movfeatpos= DATUM2(MOVFEATPOS,datum);
265 movfeatposix= movfeatpos ^ MOVFEATPOS_MAX;
268 (segnum < fixed_a ? fixed[segnum] : 0) :
269 (segnum < moveable_a && movfeatposix < moveable[segnum].lookup_a
270 ? moveable[segnum].lookup[movfeatposix] : 0);
274 rgbdirn= anglemap[ angle ^ (r->alpha < 0 ? ANGLE_TOPBIT : 0) ];
275 alpha= fabs(r->alpha);
277 for (i=0; i<3; i++) {
279 v= alpha * rgbdirn[i] + (1.0 - alpha) * r->rgb[i];
283 if (fwrite(rgbo,1,3,stdout)!=3) { perror("writing"); exit(12); }
288 /*---------- main program ----------*/
290 int main(int argc_spec, char **argv_spec) {
291 const char *arg, *encodingfilename;
293 ppm_init(&argc_spec,argv_spec);
297 encodingfilename= nextarg();
300 if (!*arg) badusage();
301 if (!arg[1]) idgroupargs(arg[0]);
302 else if (!strcmp(arg,"..")) idgroupargs(0);
303 else if (!strcmp(arg,"0.")) resultargs(&background);
304 else subsegarg(arg[0],arg+1);
307 encodingfile= fopen(encodingfilename, "rb");
308 if (!encodingfile) { perror(encodingfilename); exit(8); }