ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rmtxop.c
Revision: 2.41
Committed: Fri Apr 18 23:59:03 2025 UTC (13 days, 14 hours ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.40: +22 -5 lines
Log Message:
refactor(rmtxop,rcomb,pvsum): Removed BSDF library dependency where unneeded

File Contents

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