ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.27
Committed: Wed May 22 21:44:03 2024 UTC (10 days, 9 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.26: +3 -1 lines
Log Message:
fix(rcontrib): Added output of wavelength splits for hyperspectral results

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.27 static const char RCSid[] = "$Id: rc2.c,v 2.26 2023/11/15 18:02:53 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Accumulate ray contributions for a set of materials
6     * File i/o and recovery
7     */
8    
9 schorsch 2.17 #include <ctype.h>
10     #include "platform.h"
11 greg 2.1 #include "rcontrib.h"
12     #include "resolu.h"
13    
14 greg 2.3 /* Close output stream and free record */
15     static void
16     closestream(void *p)
17     {
18     STREAMOUT *sop = (STREAMOUT *)p;
19    
20     if (sop->ofp != NULL) {
21     int status = 0;
22     if (sop->outpipe)
23     status = pclose(sop->ofp);
24     else if (sop->ofp != stdout)
25     status = fclose(sop->ofp);
26     if (status)
27     error(SYSTEM, "error closing output stream");
28     }
29     free(p);
30     }
31    
32     LUTAB ofiletab = LU_SINIT(free,closestream); /* output file table */
33    
34 greg 2.1 #define OF_MODIFIER 01
35     #define OF_BIN 02
36    
37     /************************** STREAM & FILE I/O ***************************/
38    
39     /* Construct output file name and return flags whether modifier/bin present */
40     static int
41     ofname(char *oname, const char *ospec, const char *mname, int bn)
42     {
43     const char *mnp = NULL;
44     const char *bnp = NULL;
45     const char *cp;
46    
47     if (ospec == NULL)
48     return(-1);
49     for (cp = ospec; *cp; cp++) /* check format position(s) */
50     if (*cp == '%') {
51     do
52     ++cp;
53     while (isdigit(*cp));
54     switch (*cp) {
55     case '%':
56     break;
57     case 's':
58     if (mnp != NULL)
59     return(-1);
60     mnp = cp;
61     break;
62     case 'd':
63     case 'i':
64     case 'o':
65     case 'x':
66     case 'X':
67     if (bnp != NULL)
68     return(-1);
69     bnp = cp;
70     break;
71     default:
72     return(-1);
73     }
74     }
75     if (mnp != NULL) { /* create file name */
76     if (bnp != NULL) {
77     if (bnp > mnp)
78     sprintf(oname, ospec, mname, bn);
79     else
80     sprintf(oname, ospec, bn, mname);
81     return(OF_MODIFIER|OF_BIN);
82     }
83     sprintf(oname, ospec, mname);
84     return(OF_MODIFIER);
85     }
86     if (bnp != NULL) {
87     sprintf(oname, ospec, bn);
88     return(OF_BIN);
89     }
90     strcpy(oname, ospec);
91     return(0);
92     }
93    
94    
95     /* Write header to the given output stream */
96     static void
97     printheader(FILE *fout, const char *info)
98     {
99     extern char VersionID[];
100     /* copy octree header */
101     if (octname[0] == '!') {
102     newheader("RADIANCE", fout);
103     fputs(octname+1, fout);
104     if (octname[strlen(octname)-1] != '\n')
105     fputc('\n', fout);
106     } else {
107 greg 2.2 FILE *fin = fopen(octname, (outfmt=='a') ? "r" : "rb");
108 greg 2.1 if (fin == NULL)
109     quit(1);
110 greg 2.2 checkheader(fin, OCTFMT, fout);
111 greg 2.1 fclose(fin);
112     }
113     printargs(gargc-1, gargv, fout); /* add our command */
114     fprintf(fout, "SOFTWARE= %s\n", VersionID);
115     fputnow(fout);
116 greg 2.26 fputncomp(NCSAMP, fout);
117 greg 2.27 if (NCSAMP > 3)
118     fputwlsplit(WLPART, fout);
119 greg 2.1 if (info != NULL) /* add extra info if given */
120     fputs(info, fout);
121 greg 2.23 if ((outfmt == 'f') | (outfmt == 'd'))
122     fputendian(fout);
123 greg 2.1 fputformat(formstr(outfmt), fout);
124     fputc('\n', fout); /* empty line ends header */
125     }
126    
127    
128     /* Write resolution string to given output stream */
129     static void
130     printresolu(FILE *fout, int xr, int yr)
131     {
132     if ((xr > 0) & (yr > 0)) /* resolution string */
133     fprtresolu(xr, yr, fout);
134     }
135    
136    
137     /* Get output stream pointer (open and write header if new and noopen==0) */
138     STREAMOUT *
139     getostream(const char *ospec, const char *mname, int bn, int noopen)
140     {
141     static STREAMOUT stdos;
142 greg 2.9 char info[1024];
143 greg 2.1 int ofl;
144     char oname[1024];
145     LUENT *lep;
146     STREAMOUT *sop;
147 greg 2.11 char *cp;
148 greg 2.25
149     info[0] = '\0';
150 greg 2.1 if (ospec == NULL) { /* use stdout? */
151 greg 2.3 if (!noopen & !using_stdout) {
152 greg 2.1 if (outfmt != 'a')
153     SET_FILE_BINARY(stdout);
154 greg 2.24 #ifdef getc_unlocked
155     flockfile(stdout); /* avoid lock/unlock overhead */
156     #endif
157 greg 2.9 if (header) {
158 greg 2.11 cp = info;
159     if (yres > 0) {
160     sprintf(cp, "NROWS=%d\n", yres *
161     (xres + !xres) );
162     while (*cp) ++cp;
163     }
164 greg 2.13 if ((xres <= 0) | (stdos.reclen > 1))
165     sprintf(cp, "NCOLS=%d\n", stdos.reclen);
166 greg 2.9 printheader(stdout, info);
167     }
168 greg 2.13 if (stdos.reclen == 1)
169     printresolu(stdout, xres, yres);
170 greg 2.1 if (waitflush > 0)
171     fflush(stdout);
172     stdos.xr = xres; stdos.yr = yres;
173     using_stdout = 1;
174     }
175     stdos.ofp = stdout;
176     stdos.reclen += noopen;
177     return(&stdos);
178     }
179     ofl = ofname(oname, ospec, mname, bn); /* get output name */
180     if (ofl < 0) {
181     sprintf(errmsg, "bad output format '%s'", ospec);
182     error(USER, errmsg);
183     }
184     lep = lu_find(&ofiletab, oname); /* look it up */
185     if (lep->key == NULL) /* new entry */
186     lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
187     sop = (STREAMOUT *)lep->data;
188     if (sop == NULL) { /* allocate stream */
189     sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
190     if (sop == NULL)
191     error(SYSTEM, "out of memory in getostream");
192 greg 2.19 sop->outpipe = (oname[0] == '!');
193 greg 2.1 sop->reclen = 0;
194     sop->ofp = NULL; /* open iff noopen==0 */
195     sop->xr = xres; sop->yr = yres;
196     lep->data = (char *)sop;
197     if (!sop->outpipe & !force_open & !recover &&
198     access(oname, F_OK) == 0) {
199     errno = EEXIST; /* file exists */
200     goto openerr;
201     }
202 greg 2.19 } else if (noopen && outfmt == 'c' && /* stream exists to picture? */
203     (sop->xr > 0) & (sop->yr > 0)) {
204     if (ofl & OF_BIN)
205     return(NULL); /* let caller offset bins */
206     sprintf(errmsg, "output '%s' not a valid picture", oname);
207     error(WARNING, errmsg);
208 greg 2.1 }
209     if (!noopen && sop->ofp == NULL) { /* open output stream */
210     if (oname[0] == '!') /* output to command */
211     sop->ofp = popen(oname+1, "w");
212     else /* else open file */
213     sop->ofp = fopen(oname, "w");
214     if (sop->ofp == NULL)
215     goto openerr;
216     if (outfmt != 'a')
217     SET_FILE_BINARY(sop->ofp);
218 greg 2.15 #ifdef getc_unlocked
219 greg 2.1 flockfile(sop->ofp); /* avoid lock/unlock overhead */
220     #endif
221 greg 2.11 if (accumulate > 0) { /* global resolution */
222     sop->xr = xres; sop->yr = yres;
223     }
224 greg 2.1 if (header) {
225 greg 2.11 cp = info;
226 greg 2.1 if (ofl & OF_MODIFIER || sop->reclen == 1) {
227     sprintf(cp, "MODIFIER=%s\n", mname);
228     while (*cp) ++cp;
229     }
230     if (ofl & OF_BIN) {
231     sprintf(cp, "BIN=%d\n", bn);
232     while (*cp) ++cp;
233     }
234 greg 2.11 if (sop->yr > 0) {
235     sprintf(cp, "NROWS=%d\n", sop->yr *
236     (sop->xr + !sop->xr) );
237     while (*cp) ++cp;
238     }
239 greg 2.13 if ((sop->xr <= 0) | (sop->reclen > 1))
240     sprintf(cp, "NCOLS=%d\n", sop->reclen);
241 greg 2.1 printheader(sop->ofp, info);
242     }
243 greg 2.13 if (sop->reclen == 1)
244     printresolu(sop->ofp, sop->xr, sop->yr);
245 greg 2.1 if (waitflush > 0)
246     fflush(sop->ofp);
247     }
248     sop->reclen += noopen; /* add to length if noopen */
249     return(sop); /* return output stream */
250     openerr:
251     sprintf(errmsg, "cannot open '%s' for writing", oname);
252     error(SYSTEM, errmsg);
253     return(NULL); /* pro forma return */
254     }
255    
256    
257     /* Get a vector from stdin */
258     int
259     getvec(FVECT vec)
260     {
261     float vf[3];
262     double vd[3];
263     char buf[32];
264     int i;
265    
266     switch (inpfmt) {
267     case 'a': /* ascii */
268     for (i = 0; i < 3; i++) {
269     if (fgetword(buf, sizeof(buf), stdin) == NULL ||
270     !isflt(buf))
271     return(-1);
272     vec[i] = atof(buf);
273     }
274     break;
275     case 'f': /* binary float */
276 greg 2.26 if (getbinary(vf, sizeof(float), 3, stdin) != 3)
277 greg 2.1 return(-1);
278     VCOPY(vec, vf);
279     break;
280     case 'd': /* binary double */
281 greg 2.26 if (getbinary(vd, sizeof(double), 3, stdin) != 3)
282 greg 2.1 return(-1);
283     VCOPY(vec, vd);
284     break;
285     default:
286     error(CONSISTENCY, "botched input format");
287     }
288     return(0);
289     }
290    
291    
292     /* Put out ray contribution to file */
293     static void
294 greg 2.26 put_contrib(const DCOLORV *cnt, FILE *fout)
295 greg 2.1 {
296     double sf = 1;
297 greg 2.26 SCOLOR fv;
298     SCOLR cv;
299     int i;
300 greg 2.1
301     if (accumulate > 1)
302     sf = 1./(double)accumulate;
303     switch (outfmt) {
304     case 'a':
305 greg 2.26 for (i = 0; i < NCSAMP; i++)
306     fprintf(fout, "%.6e\t", sf*cnt[i]);
307 greg 2.1 break;
308     case 'f':
309 greg 2.26 for (i = NCSAMP; i-- > 0; )
310     fv[i] = cnt[i];
311     if (accumulate > 1)
312     scalescolor(fv, sf);
313     putbinary(fv, sizeof(COLORV), NCSAMP, fout);
314 greg 2.1 break;
315     case 'd':
316     if (accumulate > 1) {
317 greg 2.26 DCOLORV dv[MAXCSAMP];
318     for (i = NCSAMP; i-- > 0; )
319     dv[i] = sf*cnt[i];
320     putbinary(dv, sizeof(DCOLORV), NCSAMP, fout);
321 greg 2.1 } else
322 greg 2.26 putbinary(cnt, sizeof(DCOLORV), NCSAMP, fout);
323 greg 2.1 break;
324     case 'c':
325 greg 2.26 for (i = NCSAMP; i-- > 0; )
326     fv[i] = cnt[i];
327 greg 2.1 if (accumulate > 1)
328 greg 2.26 scalescolor(fv, sf);
329     scolor_scolr(cv, fv);
330     putbinary(cv, 1, LSCOLR, fout);
331 greg 2.1 break;
332     default:
333     error(INTERNAL, "botched output format");
334     }
335     }
336    
337    
338     /* Output modifier values to appropriate stream(s) */
339     void
340     mod_output(MODCONT *mp)
341     {
342 greg 2.19 STREAMOUT *sop = getostream(mp->outspec, mp->modname, mp->bin0, 0);
343 greg 2.1 int j;
344    
345 greg 2.26 put_contrib(mp->cbin, sop->ofp);
346 greg 2.1 if (mp->nbins > 3 && /* minor optimization */
347 greg 2.19 sop == getostream(mp->outspec, mp->modname, mp->bin0+1, 0)) {
348 greg 2.1 for (j = 1; j < mp->nbins; j++)
349 greg 2.26 put_contrib(mcbin(mp,j), sop->ofp);
350 greg 2.3 } else {
351 greg 2.1 for (j = 1; j < mp->nbins; j++) {
352 greg 2.19 sop = getostream(mp->outspec, mp->modname, mp->bin0+j, 0);
353 greg 2.26 put_contrib(mcbin(mp,j), sop->ofp);
354 greg 2.1 }
355 greg 2.3 }
356 greg 2.1 }
357    
358    
359     /* callback to output newline to ASCII file and/or flush as requested */
360     static int
361     puteol(const LUENT *e, void *p)
362     {
363     STREAMOUT *sop = (STREAMOUT *)e->data;
364    
365     if (outfmt == 'a')
366     putc('\n', sop->ofp);
367     if (!waitflush)
368     fflush(sop->ofp);
369     if (ferror(sop->ofp)) {
370     sprintf(errmsg, "write error on file '%s'", e->key);
371     error(SYSTEM, errmsg);
372     }
373     return(0);
374     }
375    
376    
377     /* Terminate record output and flush if time */
378     void
379     end_record()
380     {
381     --waitflush;
382 greg 2.7 lu_doall(&ofiletab, &puteol, NULL);
383 greg 2.1 if (using_stdout & (outfmt == 'a'))
384     putc('\n', stdout);
385     if (!waitflush) {
386     waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
387     if (using_stdout)
388     fflush(stdout);
389     }
390     }
391    
392     /************************** PARTIAL RESULTS RECOVERY ***********************/
393    
394     /* Get ray contribution from previous file */
395     static int
396 greg 2.26 get_contrib(DCOLORV *cnt, FILE *finp)
397 greg 2.1 {
398 greg 2.26 SCOLOR fv;
399     SCOLR cv;
400     int i;
401 greg 2.1
402     switch (outfmt) {
403     case 'a':
404 greg 2.26 for (i = 0; i < NCSAMP; i++)
405     if (fscanf(finp, "%lf", &cnt[i]) != 1)
406     return(0);
407     return(1);
408     case 'd':
409     return(getbinary(cnt, sizeof(DCOLORV), NCSAMP, finp) == NCSAMP);
410 greg 2.1 case 'f':
411 greg 2.26 if (getbinary(fv, sizeof(COLORV), NCSAMP, finp) != NCSAMP)
412 greg 2.1 return(0);
413 greg 2.26 break;
414 greg 2.1 case 'c':
415 greg 2.26 if (getbinary(cv, 1, LSCOLR, finp) != LSCOLR)
416 greg 2.1 return(0);
417 greg 2.26 scolr_scolor(fv, cv);
418     break;
419 greg 2.1 default:
420     error(INTERNAL, "botched output format");
421     }
422 greg 2.26 /* copy result from SCOLOR */
423     for (i = NCSAMP; i-- > 0; )
424     cnt[i] = fv[i];
425     return(1);
426 greg 2.1 }
427    
428    
429     /* Close output file opened for input */
430     static int
431     myclose(const LUENT *e, void *p)
432     {
433     STREAMOUT *sop = (STREAMOUT *)e->data;
434    
435     if (sop->ofp == NULL)
436     return(0);
437     fclose(sop->ofp);
438     sop->ofp = NULL;
439     return(0);
440     }
441    
442    
443     /* Load previously accumulated values */
444     void
445     reload_output()
446     {
447     int i, j;
448     MODCONT *mp;
449     int ofl;
450     char oname[1024];
451     char *fmode = "rb";
452     char *outvfmt;
453     LUENT *oent;
454     int xr, yr;
455 greg 2.20 STREAMOUT *sop;
456 greg 2.26 DCOLORV contr[MAXCSAMP];
457 greg 2.1
458     if (outfmt == 'a')
459     fmode = "r";
460 greg 2.26 outvfmt = (char *)formstr(outfmt);
461 greg 2.1 /* reload modifier values */
462     for (i = 0; i < nmods; i++) {
463     mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
464     if (mp->outspec == NULL)
465     error(USER, "cannot reload from stdout");
466     if (mp->outspec[0] == '!')
467     error(USER, "cannot reload from command");
468 greg 2.20 for (j = 0; j < mp->nbins; j++) { /* load each modifier bin */
469     ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
470 greg 2.1 if (ofl < 0)
471     error(USER, "bad output file specification");
472     oent = lu_find(&ofiletab, oname);
473 greg 2.20 if (oent->data == NULL)
474     error(INTERNAL, "unallocated stream in reload_output()");
475     sop = (STREAMOUT *)oent->data;
476     if (sop->ofp == NULL) { /* open output as input */
477     sop->ofp = fopen(oname, fmode);
478     if (sop->ofp == NULL) {
479 greg 2.1 sprintf(errmsg, "missing reload file '%s'",
480     oname);
481     error(WARNING, errmsg);
482     break;
483     }
484 greg 2.15 #ifdef getc_unlocked
485 greg 2.20 flockfile(sop->ofp);
486 greg 2.1 #endif
487 greg 2.20 if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
488 greg 2.1 sprintf(errmsg, "format mismatch for '%s'",
489     oname);
490     error(USER, errmsg);
491     }
492 greg 2.20 if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
493     (!fscnresolu(&xr, &yr, sop->ofp) ||
494     (xr != sop->xr) |
495     (yr != sop->yr))) {
496 greg 2.1 sprintf(errmsg, "resolution mismatch for '%s'",
497     oname);
498     error(USER, errmsg);
499     }
500     }
501 greg 2.26 /* read in spectral value */
502     if (!get_contrib(contr, sop->ofp)) {
503 greg 2.1 if (!j) {
504 greg 2.20 fclose(sop->ofp);
505 greg 2.1 break; /* ignore empty file */
506     }
507     if (j < mp->nbins) {
508     sprintf(errmsg, "missing data in '%s'",
509     oname);
510     error(USER, errmsg);
511     }
512     break;
513 greg 2.26 }
514     memcpy(mcbin(mp,j), contr, DCOLORSIZ);
515 greg 2.1 }
516     }
517 greg 2.7 lu_doall(&ofiletab, &myclose, NULL); /* close all files */
518 greg 2.1 }
519    
520    
521     /* Seek on the given output file */
522     static int
523     myseeko(const LUENT *e, void *p)
524     {
525     STREAMOUT *sop = (STREAMOUT *)e->data;
526     off_t nbytes = *(off_t *)p;
527    
528     if (sop->reclen > 1)
529 greg 2.22 nbytes *= (off_t)sop->reclen;
530 greg 2.1 if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
531     sprintf(errmsg, "seek error on file '%s'", e->key);
532     error(SYSTEM, errmsg);
533     }
534     return(0);
535     }
536    
537    
538     /* Recover output if possible */
539     void
540     recover_output()
541     {
542     off_t lastout = -1;
543     int outvsiz, recsiz;
544     char *outvfmt;
545     int i, j;
546     MODCONT *mp;
547     int ofl;
548     char oname[1024];
549     LUENT *oent;
550 greg 2.20 STREAMOUT *sop;
551 greg 2.1 off_t nvals;
552     int xr, yr;
553    
554     switch (outfmt) {
555     case 'a':
556     error(USER, "cannot recover ASCII output");
557     return;
558     case 'f':
559 greg 2.26 outvsiz = sizeof(float)*NCSAMP;
560 greg 2.1 break;
561     case 'd':
562 greg 2.26 outvsiz = sizeof(double)*NCSAMP;
563 greg 2.1 break;
564     case 'c':
565 greg 2.26 outvsiz = LSCOLR;
566 greg 2.1 break;
567     default:
568     error(INTERNAL, "botched output format");
569     return;
570     }
571 greg 2.26 outvfmt = (char *)formstr(outfmt);
572 greg 2.1 /* check modifier outputs */
573     for (i = 0; i < nmods; i++) {
574     mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
575     if (mp->outspec == NULL)
576     error(USER, "cannot recover from stdout");
577     if (mp->outspec[0] == '!')
578     error(USER, "cannot recover from command");
579 greg 2.20 for (j = 0; j < mp->nbins; j++) { /* check each bin's file */
580     ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
581 greg 2.1 if (ofl < 0)
582     error(USER, "bad output file specification");
583     oent = lu_find(&ofiletab, oname);
584 greg 2.20 if (oent->data == NULL)
585     error(INTERNAL, "unallocated stream in recover_output()");
586     sop = (STREAMOUT *)oent->data;
587     if (sop->ofp != NULL) { /* already open? */
588 greg 2.1 if (ofl & OF_BIN)
589     continue;
590     break;
591     }
592     /* open output */
593 greg 2.20 sop->ofp = fopen(oname, "rb+");
594     if (sop->ofp == NULL) {
595 greg 2.1 sprintf(errmsg, "missing recover file '%s'",
596     oname);
597     error(WARNING, errmsg);
598 greg 2.21 lastout = 0;
599 greg 2.1 break;
600     }
601 greg 2.20 nvals = lseek(fileno(sop->ofp), 0, SEEK_END);
602 greg 2.1 if (nvals <= 0) {
603     lastout = 0; /* empty output, quit here */
604 greg 2.20 fclose(sop->ofp);
605 greg 2.1 break;
606     }
607 greg 2.20 recsiz = outvsiz * sop->reclen;
608 greg 2.1
609 greg 2.20 lseek(fileno(sop->ofp), 0, SEEK_SET);
610     if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
611 greg 2.1 sprintf(errmsg, "format mismatch for '%s'",
612     oname);
613     error(USER, errmsg);
614     }
615 greg 2.20 if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
616     (!fscnresolu(&xr, &yr, sop->ofp) ||
617     (xr != sop->xr) |
618     (yr != sop->yr))) {
619 greg 2.1 sprintf(errmsg, "resolution mismatch for '%s'",
620     oname);
621     error(USER, errmsg);
622     }
623 greg 2.20 nvals = (nvals - (off_t)ftell(sop->ofp)) / recsiz;
624 greg 2.1 if ((lastout < 0) | (nvals < lastout))
625     lastout = nvals;
626     if (!(ofl & OF_BIN))
627     break; /* no bin separation */
628     }
629     if (!lastout) { /* empty output */
630     error(WARNING, "no previous data to recover");
631 greg 2.21 /* reclose all outputs */
632     lu_doall(&ofiletab, &myclose, NULL);
633 greg 2.1 return;
634     }
635     }
636     if (lastout < 0) {
637     error(WARNING, "no output files to recover");
638     return;
639     }
640     if (raysleft && lastout >= raysleft/accumulate) {
641     error(WARNING, "output appears to be complete");
642     /* XXX should read & discard input? */
643     quit(0);
644     }
645     /* seek on all files */
646     nvals = lastout * outvsiz;
647 greg 2.7 lu_doall(&ofiletab, &myseeko, &nvals);
648 greg 2.1 /* skip repeated input */
649 greg 2.5 lastout *= accumulate;
650 greg 2.1 for (nvals = 0; nvals < lastout; nvals++) {
651     FVECT vdummy;
652     if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
653     error(USER, "unexpected EOF on input");
654     }
655 greg 2.5 lastray = lastdone = (RNUMBER)lastout;
656 greg 2.1 if (raysleft)
657     raysleft -= lastray;
658     }