ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmtxop.c
Revision: 2.33
Committed: Thu May 16 18:59:19 2024 UTC (6 days, 8 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.32: +1 -2 lines
Log Message:
fix: Made use of resolu.h more consistent and reliable

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.33 static const char RCSid[] = "$Id: rmtxop.c,v 2.32 2023/12/19 16:09:20 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * General component matrix operations.
6     */
7    
8 greg 2.11 #include <errno.h>
9 greg 2.1 #include "rtio.h"
10     #include "rmatrix.h"
11 greg 2.10 #include "platform.h"
12 greg 2.1
13 greg 2.22 #define MAXCOMP MAXCSAMP /* #components we support */
14 greg 2.1
15 greg 2.22 /* Unary matrix operation(s) */
16 greg 2.1 typedef struct {
17 greg 2.27 double cmat[MAXCOMP*MAXCOMP]; /* component transformation */
18 greg 2.1 double sca[MAXCOMP]; /* scalar coefficients */
19 greg 2.27 const char *csym; /* symbolic coefs or file */
20     short clen; /* number of coefficients */
21 greg 2.13 short nsf; /* number of scalars */
22 greg 2.27 short transpose; /* do transpose? */
23 greg 2.13 } RUNARYOP;
24    
25 greg 2.22 /* Matrix input source and requested operation(s) */
26 greg 2.13 typedef struct {
27     const char *inspec; /* input specification */
28 greg 2.18 RMPref rmp; /* matrix preference */
29 greg 2.13 RUNARYOP preop; /* unary operation(s) */
30     RMATRIX *mtx; /* original matrix if loaded */
31     int binop; /* binary op with next (or 0) */
32     } ROPMAT;
33 greg 2.1
34     int verbose = 0; /* verbose reporting? */
35    
36 greg 2.13 /* Load matrix */
37     static int
38     loadmatrix(ROPMAT *rop)
39 greg 2.1 {
40 greg 2.20 if (rop->mtx != NULL) /* already loaded? */
41 greg 2.13 return(0);
42    
43 greg 2.18 rop->mtx = rmx_load(rop->inspec, rop->rmp);
44 greg 2.23
45     return(!rop->mtx ? -1 : 1);
46 greg 2.1 }
47    
48 greg 2.27 static int checksymbolic(ROPMAT *rop);
49    
50     /* Check/set transform based on a reference input file */
51     static int
52     checkreffile(ROPMAT *rop)
53     {
54     static const char *curRF = NULL;
55     static RMATRIX refm;
56     const int nc = rop->mtx->ncomp;
57     int i;
58    
59     if (!curRF || strcmp(rop->preop.csym, curRF)) {
60     FILE *fp = fopen(rop->preop.csym, "rb");
61     if (!rmx_load_header(&refm, fp)) {
62     fprintf(stderr, "%s: cannot read info header\n",
63     rop->preop.csym);
64     curRF = NULL;
65     if (fp) fclose(fp);
66     return(-1);
67     }
68     fclose(fp);
69     curRF = rop->preop.csym;
70     }
71 greg 2.30 if (refm.ncomp == 3) {
72 greg 2.27 rop->preop.csym = (refm.dtype == DTxyze) ? "XYZ" : "RGB";
73     return(checksymbolic(rop));
74     }
75     if (refm.ncomp == 2) {
76     fprintf(stderr, "%s: cannot convert to 2 components\n",
77     curRF);
78     return(-1);
79     }
80     if (refm.ncomp == 1) {
81     rop->preop.csym = "Y"; /* XXX big assumption */
82     return(checksymbolic(rop));
83     }
84     if (refm.ncomp == nc &&
85     !memcmp(refm.wlpart, rop->mtx->wlpart, sizeof(refm.wlpart)))
86     return(0); /* nothing to do */
87    
88     if ((nc <= 3) | (nc > MAXCSAMP) | (refm.ncomp > MAXCSAMP)) {
89     fprintf(stderr, "%s: cannot resample from %d to %d components\n",
90     curRF, nc, refm.ncomp);
91     return(-1);
92     }
93     rop->preop.clen = refm.ncomp * nc; /* compute spec to ref */
94    
95     for (i = 0; i < nc; i++) {
96     SCOLOR scstim, scresp;
97     int j;
98     memset(scstim, 0, sizeof(COLORV)*nc);
99     scstim[i] = 1.f;
100     convertscolor(scresp, refm.ncomp, refm.wlpart[0], refm.wlpart[3],
101     scstim, nc, rop->mtx->wlpart[0], rop->mtx->wlpart[3]);
102     for (j = refm.ncomp; j-- > 0; )
103     rop->preop.cmat[j*nc + i] = scresp[j];
104     }
105 greg 2.29 memcpy(rop->mtx->wlpart, refm.wlpart, sizeof(rop->mtx->wlpart));
106 greg 2.27 return(0);
107     }
108    
109 greg 2.22 /* Compute conversion row from spectrum to one channel of RGB */
110     static void
111     rgbrow(ROPMAT *rop, int r, int p)
112     {
113     const int nc = rop->mtx->ncomp;
114     const float * wlp = rop->mtx->wlpart;
115     int i;
116    
117     for (i = nc; i--; ) {
118     int nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
119     int nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
120     COLOR crgb;
121     spec_rgb(crgb, nmStart, nmEnd);
122     rop->preop.cmat[r*nc+i] = crgb[p];
123     }
124     }
125    
126     /* Compute conversion row from spectrum to one channel of XYZ */
127     static void
128     xyzrow(ROPMAT *rop, int r, int p)
129     {
130     const int nc = rop->mtx->ncomp;
131     const float * wlp = rop->mtx->wlpart;
132     int i;
133    
134     for (i = nc; i--; ) {
135     int nmEnd = wlp[0] + (wlp[3] - wlp[0])*i/nc;
136     int nmStart = wlp[0] + (wlp[3] - wlp[0])*(i+1)/nc;
137     COLOR cxyz;
138     spec_cie(cxyz, nmStart, nmEnd);
139     rop->preop.cmat[r*nc+i] = cxyz[p];
140     }
141     }
142    
143     /* Use the spectral sensitivity function to compute matrix coefficients */
144     static void
145     sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, int ncs, const float wlpt[4]))
146     {
147     const int nc = rop->mtx->ncomp;
148     int i;
149    
150     for (i = nc; i--; ) {
151     SCOLOR sclr;
152 greg 2.27 memset(sclr, 0, sizeof(COLORV)*nc);
153 greg 2.24 sclr[i] = 1.f;
154 greg 2.22 rop->preop.cmat[r*nc+i] = (*sf)(sclr, nc, rop->mtx->wlpart);
155     }
156     }
157    
158     /* Check/set symbolic transform */
159     static int
160     checksymbolic(ROPMAT *rop)
161     {
162     const int nc = rop->mtx->ncomp;
163     const int dt = rop->mtx->dtype;
164 greg 2.31 double cf = 1;
165 greg 2.22 int i, j;
166 greg 2.27 /* check suffix => reference file */
167     if (strchr(rop->preop.csym, '.') > rop->preop.csym)
168     return(checkreffile(rop));
169 greg 2.22
170     if (nc < 3) {
171     fprintf(stderr, "%s: -c '%s' requires at least 3 components\n",
172     rop->inspec, rop->preop.csym);
173     return(-1);
174     }
175     rop->preop.clen = strlen(rop->preop.csym) * nc;
176     if (rop->preop.clen > MAXCOMP*MAXCOMP) {
177     fprintf(stderr, "%s: -c '%s' results in too many components\n",
178     rop->inspec, rop->preop.csym);
179     return(-1);
180     }
181     for (j = 0; rop->preop.csym[j]; j++) {
182     int comp = 0;
183     switch (rop->preop.csym[j]) {
184     case 'B':
185 greg 2.31 case 'b':
186 greg 2.22 ++comp;
187     /* fall through */
188     case 'G':
189 greg 2.31 case 'g':
190 greg 2.22 ++comp;
191     /* fall through */
192     case 'R':
193 greg 2.31 case 'r':
194     if (rop->preop.csym[j] <= 'Z')
195     cf = 1./WHTEFFICACY;
196 greg 2.22 if (dt == DTxyze) {
197     for (i = 3; i--; )
198 greg 2.31 rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
199 greg 2.22 } else if (nc == 3)
200     rop->preop.cmat[j*nc+comp] = 1.;
201     else
202     rgbrow(rop, j, comp);
203     break;
204     case 'Z':
205 greg 2.31 case 'z':
206 greg 2.22 ++comp;
207     /* fall through */
208     case 'Y':
209 greg 2.31 case 'y':
210 greg 2.22 ++comp;
211     /* fall through */
212     case 'X':
213 greg 2.31 case 'x':
214     if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
215     cf = WHTEFFICACY;
216 greg 2.22 if (dt == DTxyze) {
217     rop->preop.cmat[j*nc+comp] = 1.;
218     } else if (nc == 3) {
219     for (i = 3; i--; )
220     rop->preop.cmat[j*nc+i] =
221     rgb2xyzmat[comp][i];
222     } else if (comp == CIEY)
223     sensrow(rop, j, scolor2photopic);
224     else
225     xyzrow(rop, j, comp);
226    
227 greg 2.31 for (i = nc*(cf != 1); i--; )
228     rop->preop.cmat[j*nc+i] *= cf;
229 greg 2.22 break;
230 greg 2.24 case 'S': /* scotopic (il)luminance */
231 greg 2.31 cf = WHTSCOTOPIC;
232     /* fall through */
233     case 's':
234 greg 2.22 sensrow(rop, j, scolor2scotopic);
235 greg 2.31 for (i = nc*(cf != 1); i--; )
236     rop->preop.cmat[j*nc+i] *= cf;
237 greg 2.22 break;
238 greg 2.24 case 'M': /* melanopic (il)luminance */
239 greg 2.31 cf = WHTMELANOPIC;
240     /* fall through */
241     case 'm':
242 greg 2.22 sensrow(rop, j, scolor2melanopic);
243 greg 2.31 for (i = nc*(cf != 1); i--; )
244     rop->preop.cmat[j*nc+i] *= cf;
245 greg 2.22 break;
246 greg 2.24 case 'A': /* average component */
247 greg 2.31 case 'a':
248 greg 2.24 for (i = nc; i--; )
249 greg 2.25 rop->preop.cmat[j*nc+i] = 1./(double)nc;
250 greg 2.24 break;
251 greg 2.22 default:
252     fprintf(stderr, "%s: -c '%c' unsupported\n",
253     rop->inspec, rop->preop.csym[j]);
254     return(-1);
255     }
256     }
257     /* return recommended output type */
258 greg 2.32 if (!strcasecmp(rop->preop.csym, "XYZ")) {
259 greg 2.22 if (dt <= DTspec)
260     return(DTxyze);
261 greg 2.32 } else if (!strcasecmp(rop->preop.csym, "RGB")) {
262 greg 2.22 if (dt <= DTspec)
263     return(DTrgbe);
264 greg 2.30 } else if (dt == DTspec)
265 greg 2.22 return(DTfloat); /* probably not actual spectrum */
266     return(0);
267     }
268    
269 greg 2.13 /* Get matrix and perform unary operations */
270 greg 2.1 static RMATRIX *
271 greg 2.13 loadop(ROPMAT *rop)
272 greg 2.1 {
273 greg 2.22 int outtype = 0;
274 greg 2.13 RMATRIX *mres;
275 greg 2.22 int i, j;
276 greg 2.1
277 greg 2.13 if (loadmatrix(rop) < 0) /* make sure we're loaded */
278 greg 2.1 return(NULL);
279 greg 2.13
280 greg 2.27 if (rop->preop.csym && /* symbolic transform? */
281 greg 2.22 (outtype = checksymbolic(rop)) < 0)
282     goto failure;
283     if (rop->preop.clen > 0) { /* apply component transform? */
284     if (rop->preop.clen % rop->mtx->ncomp) {
285     fprintf(stderr, "%s: -c must have N x %d coefficients\n",
286     rop->inspec, rop->mtx->ncomp);
287     goto failure;
288     }
289     if (rop->preop.nsf > 0) { /* scale transform, first */
290     if (rop->preop.nsf == 1) {
291     for (i = rop->preop.clen; i--; )
292     rop->preop.cmat[i] *= rop->preop.sca[0];
293 greg 2.28 } else if (rop->preop.nsf*rop->mtx->ncomp != rop->preop.clen) {
294 greg 2.22 fprintf(stderr, "%s: -s must have one or %d factors\n",
295 greg 2.28 rop->inspec,
296     rop->preop.clen/rop->mtx->ncomp);
297 greg 2.22 goto failure;
298     } else {
299 greg 2.28 for (i = rop->preop.nsf; i--; )
300     for (j = rop->mtx->ncomp; j--; )
301     rop->preop.cmat[i*rop->mtx->ncomp+j]
302     *= rop->preop.sca[i];
303 greg 2.22 }
304     }
305     mres = rmx_transform(rop->mtx, rop->preop.clen/rop->mtx->ncomp,
306     rop->preop.cmat);
307     if (mres == NULL) {
308     fprintf(stderr, "%s: matrix transform failed\n",
309     rop->inspec);
310 greg 2.13 goto failure;
311 greg 2.1 }
312 greg 2.22 if (verbose)
313     fprintf(stderr, "%s: applied %d x %d transform%s\n",
314     rop->inspec, mres->ncomp,
315     rop->mtx->ncomp,
316     rop->preop.nsf ? " (* scalar)" : "");
317 greg 2.26 rop->preop.nsf = 0; /* now folded in */
318 greg 2.22 if ((mres->ncomp > 3) & (mres->dtype <= DTspec))
319     outtype = DTfloat; /* probably not actual spectrum */
320     rmx_free(rop->mtx);
321     rop->mtx = mres;
322     }
323     if (rop->preop.nsf > 0) { /* apply scalar(s)? */
324 greg 2.13 if (rop->preop.nsf == 1) {
325     for (i = rop->mtx->ncomp; --i; )
326     rop->preop.sca[i] = rop->preop.sca[0];
327     } else if (rop->preop.nsf != rop->mtx->ncomp) {
328 greg 2.1 fprintf(stderr, "%s: -s must have one or %d factors\n",
329 greg 2.13 rop->inspec, rop->mtx->ncomp);
330     goto failure;
331 greg 2.1 }
332 greg 2.13 if (!rmx_scale(rop->mtx, rop->preop.sca)) {
333     fputs(rop->inspec, stderr);
334 greg 2.1 fputs(": scalar operation failed\n", stderr);
335 greg 2.13 goto failure;
336 greg 2.1 }
337     if (verbose) {
338 greg 2.13 fputs(rop->inspec, stderr);
339 greg 2.1 fputs(": applied scalar (", stderr);
340 greg 2.13 for (i = 0; i < rop->preop.nsf; i++)
341     fprintf(stderr, " %f", rop->preop.sca[i]);
342 greg 2.1 fputs(" )\n", stderr);
343     }
344     }
345 greg 2.22 if (rop->preop.transpose) { /* transpose matrix? */
346 greg 2.13 mres = rmx_transpose(rop->mtx);
347     if (mres == NULL) {
348     fputs(rop->inspec, stderr);
349 greg 2.12 fputs(": transpose failed\n", stderr);
350 greg 2.13 goto failure;
351 greg 2.12 }
352     if (verbose) {
353 greg 2.13 fputs(rop->inspec, stderr);
354 greg 2.12 fputs(": transposed rows and columns\n", stderr);
355     }
356 greg 2.13 rmx_free(rop->mtx);
357     rop->mtx = mres;
358     }
359     mres = rop->mtx;
360     rop->mtx = NULL;
361 greg 2.22 if (outtype)
362     mres->dtype = outtype;
363 greg 2.13 return(mres);
364     failure:
365     rmx_free(rop->mtx);
366     return(rop->mtx = NULL);
367     }
368    
369     /* Execute binary operation, free matrix arguments and return new result */
370     static RMATRIX *
371     binaryop(const char *inspec, RMATRIX *mleft, int op, RMATRIX *mright)
372     {
373     RMATRIX *mres = NULL;
374     int i;
375    
376     if ((mleft == NULL) | (mright == NULL))
377     return(NULL);
378     switch (op) {
379     case '.': /* concatenate */
380 greg 2.16 if (mleft->ncomp != mright->ncomp) {
381     fputs(inspec, stderr);
382     fputs(": # components do not match\n", stderr);
383     } else if (mleft->ncols != mright->nrows) {
384     fputs(inspec, stderr);
385     fputs(": mismatched dimensions\n",
386     stderr);
387     } else
388     mres = rmx_multiply(mleft, mright);
389 greg 2.13 rmx_free(mleft);
390 greg 2.12 rmx_free(mright);
391 greg 2.1 if (mres == NULL) {
392 greg 2.13 fputs(inspec, stderr);
393 greg 2.16 fputs(": concatenation failed\n", stderr);
394 greg 2.1 return(NULL);
395     }
396     if (verbose) {
397 greg 2.13 fputs(inspec, stderr);
398 greg 2.1 fputs(": concatenated matrix\n", stderr);
399     }
400 greg 2.13 break;
401     case '+':
402     if (!rmx_sum(mleft, mright, NULL)) {
403     fputs(inspec, stderr);
404 greg 2.1 fputs(": matrix sum failed\n", stderr);
405 greg 2.13 rmx_free(mleft);
406 greg 2.1 rmx_free(mright);
407     return(NULL);
408     }
409     if (verbose) {
410 greg 2.13 fputs(inspec, stderr);
411 greg 2.1 fputs(": added in matrix\n", stderr);
412     }
413     rmx_free(mright);
414 greg 2.13 mres = mleft;
415     break;
416     case '*':
417     case '/': {
418     const char * tnam = (op == '/') ?
419 greg 2.11 "division" : "multiplication";
420     errno = 0;
421 greg 2.13 if (!rmx_elemult(mleft, mright, (op == '/'))) {
422 greg 2.11 fprintf(stderr, "%s: element-wise %s failed\n",
423 greg 2.13 inspec, tnam);
424     rmx_free(mleft);
425 greg 2.11 rmx_free(mright);
426     return(NULL);
427     }
428     if (errno)
429     fprintf(stderr,
430     "%s: warning - error during element-wise %s\n",
431 greg 2.13 inspec, tnam);
432 greg 2.11 else if (verbose)
433 greg 2.13 fprintf(stderr, "%s: element-wise %s\n", inspec, tnam);
434 greg 2.11 rmx_free(mright);
435 greg 2.13 mres = mleft;
436     } break;
437     default:
438     fprintf(stderr, "%s: unknown operation '%c'\n", inspec, op);
439     rmx_free(mleft);
440 greg 2.1 rmx_free(mright);
441     return(NULL);
442     }
443 greg 2.13 return(mres);
444     }
445    
446     /* Perform matrix operations from left to right */
447     static RMATRIX *
448     op_left2right(ROPMAT *mop)
449     {
450     RMATRIX *mleft = loadop(mop);
451    
452     while (mop->binop) {
453     if (mleft == NULL)
454     break;
455     mleft = binaryop(mop[1].inspec,
456     mleft, mop->binop, loadop(mop+1));
457     mop++;
458     }
459 greg 2.1 return(mleft);
460     }
461    
462 greg 2.13 /* Perform matrix operations from right to left */
463     static RMATRIX *
464     op_right2left(ROPMAT *mop)
465     {
466     RMATRIX *mright;
467     int rpos = 0;
468     /* find end of list */
469     while (mop[rpos].binop)
470 greg 2.14 if (mop[rpos++].binop != '.') {
471     fputs(
472     "Right-to-left evaluation only for matrix multiplication!\n",
473     stderr);
474     return(NULL);
475     }
476 greg 2.13 mright = loadop(mop+rpos);
477     while (rpos-- > 0) {
478     if (mright == NULL)
479     break;
480 greg 2.20 mright = binaryop(mop[rpos+1].inspec,
481 greg 2.13 loadop(mop+rpos), mop[rpos].binop, mright);
482     }
483     return(mright);
484     }
485    
486     #define t_nrows(mop) ((mop)->preop.transpose ? (mop)->mtx->ncols \
487     : (mop)->mtx->nrows)
488     #define t_ncols(mop) ((mop)->preop.transpose ? (mop)->mtx->nrows \
489     : (mop)->mtx->ncols)
490    
491     /* Should we prefer concatenating from rightmost matrix towards left? */
492     static int
493     prefer_right2left(ROPMAT *mop)
494     {
495     int mri = 0;
496    
497     while (mop[mri].binop) /* find rightmost matrix */
498     if (mop[mri++].binop != '.')
499     return(0); /* pre-empt reversal for other ops */
500    
501     if (mri <= 1)
502     return(0); /* won't matter */
503    
504     if (loadmatrix(mop+mri) < 0) /* load rightmost cat */
505     return(1); /* fail will bail in a moment */
506    
507     if (t_ncols(mop+mri) == 1)
508     return(1); /* definitely better R->L */
509    
510     if (t_ncols(mop+mri) >= t_nrows(mop+mri))
511     return(0); /* ...probably worse */
512    
513     if (loadmatrix(mop) < 0) /* load leftmost */
514     return(0); /* fail will bail in a moment */
515    
516     return(t_ncols(mop+mri) < t_nrows(mop));
517     }
518    
519 greg 2.1 static int
520     get_factors(double da[], int n, char *av[])
521     {
522     int ac;
523    
524     for (ac = 0; ac < n && isflt(av[ac]); ac++)
525     da[ac] = atof(av[ac]);
526     return(ac);
527     }
528    
529 greg 2.13 static ROPMAT *
530 greg 2.26 resize_moparr(ROPMAT *mop, int n2alloc)
531 greg 2.13 {
532     int nmats = 0;
533 greg 2.26 int i;
534 greg 2.13
535     while (mop[nmats++].binop)
536     ;
537 greg 2.26 for (i = nmats; i > n2alloc; i--)
538     rmx_free(mop[i].mtx);
539 greg 2.13 mop = (ROPMAT *)realloc(mop, n2alloc*sizeof(ROPMAT));
540     if (mop == NULL) {
541 greg 2.26 fputs("Out of memory in resize_moparr()\n", stderr);
542 greg 2.13 exit(1);
543     }
544     if (n2alloc > nmats)
545     memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
546     return(mop);
547     }
548    
549 greg 2.1 /* Load one or more matrices and operate on them, sending results to stdout */
550     int
551     main(int argc, char *argv[])
552     {
553 greg 2.27 int outfmt = DTfromHeader;
554     const char *defCsym = NULL;
555     int nall = 2;
556     ROPMAT *mop = (ROPMAT *)calloc(nall, sizeof(ROPMAT));
557     int nmats = 0;
558     RMATRIX *mres = NULL;
559     int stdin_used = 0;
560     int i;
561 greg 2.1 /* get options and arguments */
562 greg 2.13 for (i = 1; i < argc; i++) {
563 greg 2.11 if (argv[i][0] && !argv[i][1] &&
564 greg 2.13 strchr(".+*/", argv[i][0]) != NULL) {
565 greg 2.15 if (!nmats || mop[nmats-1].binop) {
566 greg 2.14 fprintf(stderr,
567 greg 2.15 "%s: missing matrix argument before '%c' operation\n",
568 greg 2.14 argv[0], argv[i][0]);
569 greg 2.13 return(1);
570     }
571 greg 2.15 mop[nmats-1].binop = argv[i][0];
572 greg 2.1 } else if (argv[i][0] != '-' || !argv[i][1]) {
573 greg 2.13 if (argv[i][0] == '-') {
574     if (stdin_used++) {
575     fprintf(stderr,
576     "%s: standard input used for more than one matrix\n",
577     argv[0]);
578     return(1);
579     }
580     mop[nmats].inspec = stdin_name;
581     } else
582     mop[nmats].inspec = argv[i];
583 greg 2.27 if (!mop[nmats].preop.csym)
584     mop[nmats].preop.csym = defCsym;
585 greg 2.13 if (nmats > 0 && !mop[nmats-1].binop)
586     mop[nmats-1].binop = '.';
587     nmats++;
588 greg 2.1 } else {
589     int n = argc-1 - i;
590     switch (argv[i][1]) { /* get option */
591     case 'v':
592 greg 2.14 verbose++;
593 greg 2.1 break;
594     case 'f':
595     switch (argv[i][2]) {
596     case 'd':
597     outfmt = DTdouble;
598     break;
599     case 'f':
600     outfmt = DTfloat;
601     break;
602     case 'a':
603     outfmt = DTascii;
604     break;
605     case 'c':
606     outfmt = DTrgbe;
607     break;
608     default:
609     goto userr;
610     }
611     break;
612     case 't':
613 greg 2.13 mop[nmats].preop.transpose = 1;
614 greg 2.1 break;
615     case 's':
616     if (n > MAXCOMP) n = MAXCOMP;
617 greg 2.13 i += mop[nmats].preop.nsf =
618     get_factors(mop[nmats].preop.sca,
619     n, argv+i+1);
620 greg 2.22 if (mop[nmats].preop.nsf <= 0) {
621     fprintf(stderr, "%s: -s missing arguments\n",
622     argv[0]);
623     goto userr;
624     }
625 greg 2.1 break;
626 greg 2.27 case 'C':
627     if (!n || isflt(argv[i+1]))
628     goto userr;
629     defCsym = mop[nmats].preop.csym = argv[++i];
630     mop[nmats].preop.clen = 0;
631     break;
632 greg 2.1 case 'c':
633 greg 2.27 if (n && !isflt(argv[i+1])) {
634     mop[nmats].preop.csym = argv[++i];
635 greg 2.22 mop[nmats].preop.clen = 0;
636     break;
637     }
638 greg 2.1 if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
639 greg 2.13 i += mop[nmats].preop.clen =
640     get_factors(mop[nmats].preop.cmat,
641     n, argv+i+1);
642 greg 2.22 if (mop[nmats].preop.clen <= 0) {
643     fprintf(stderr, "%s: -c missing arguments\n",
644     argv[0]);
645     goto userr;
646     }
647 greg 2.27 mop[nmats].preop.csym = NULL;
648 greg 2.1 break;
649 greg 2.18 case 'r':
650     if (argv[i][2] == 'f')
651     mop[nmats].rmp = RMPreflF;
652     else if (argv[i][2] == 'b')
653     mop[nmats].rmp = RMPreflB;
654     else
655     goto userr;
656     break;
657 greg 2.1 default:
658     fprintf(stderr, "%s: unknown operation '%s'\n",
659     argv[0], argv[i]);
660     goto userr;
661     }
662     }
663 greg 2.14 if (nmats >= nall)
664 greg 2.26 mop = resize_moparr(mop, nall += 2);
665 greg 2.13 }
666     if (mop[0].inspec == NULL) /* nothing to do? */
667 greg 2.1 goto userr;
668 greg 2.15 if (mop[nmats-1].binop) {
669     fprintf(stderr,
670     "%s: missing matrix argument after '%c' operation\n",
671     argv[0], mop[nmats-1].binop);
672     return(1);
673     }
674 greg 2.13 /* favor quicker concatenation */
675 greg 2.14 mop[nmats].mtx = prefer_right2left(mop) ? op_right2left(mop)
676     : op_left2right(mop);
677     if (mop[nmats].mtx == NULL)
678     return(1);
679     /* apply trailing unary operations */
680     mop[nmats].inspec = "trailing_ops";
681     mres = loadop(mop+nmats);
682     if (mres == NULL)
683 greg 2.13 return(1);
684 greg 2.22 if (outfmt == DTfromHeader) /* check data type */
685 greg 2.6 outfmt = mres->dtype;
686 greg 2.22 if (outfmt == DTrgbe) {
687     if (mres->ncomp > 3)
688     outfmt = DTspec;
689     else if (mres->dtype == DTxyze)
690     outfmt = DTxyze;
691     }
692 greg 2.26 newheader("RADIANCE", stdout); /* write result to stdout */
693 greg 2.1 printargs(argc, argv, stdout);
694 greg 2.23 return(rmx_write(mres, outfmt, stdout) ? 0 : 1);
695 greg 2.1 userr:
696     fprintf(stderr,
697 greg 2.26 "Usage: %s [-v][-f{adfc}][-t][-s sf .. | -c ce ..][-rf|-rb] m1 [.+*/] .. > mres\n",
698 greg 2.1 argv[0]);
699     return(1);
700     }