ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.19
Committed: Mon Sep 12 20:31:34 2016 UTC (7 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.18: +11 -5 lines
Log Message:
Hopeful fix to issue with rcontrib writing multiple records/pixel

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.19 static const char RCSid[] = "$Id: rc2.c,v 2.18 2016/08/18 00:52:48 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.9 fputs("NCOMP=3\n", fout); /* always RGB */
117 greg 2.1 if (info != NULL) /* add extra info if given */
118     fputs(info, fout);
119     fputformat(formstr(outfmt), fout);
120     fputc('\n', fout); /* empty line ends header */
121     }
122    
123    
124     /* Write resolution string to given output stream */
125     static void
126     printresolu(FILE *fout, int xr, int yr)
127     {
128     if ((xr > 0) & (yr > 0)) /* resolution string */
129     fprtresolu(xr, yr, fout);
130     }
131    
132    
133     /* Get output stream pointer (open and write header if new and noopen==0) */
134     STREAMOUT *
135     getostream(const char *ospec, const char *mname, int bn, int noopen)
136     {
137     static STREAMOUT stdos;
138 greg 2.9 char info[1024];
139 greg 2.1 int ofl;
140     char oname[1024];
141     LUENT *lep;
142     STREAMOUT *sop;
143 greg 2.11 char *cp;
144 greg 2.1
145     if (ospec == NULL) { /* use stdout? */
146 greg 2.3 if (!noopen & !using_stdout) {
147 greg 2.1 if (outfmt != 'a')
148     SET_FILE_BINARY(stdout);
149 greg 2.9 if (header) {
150 greg 2.11 cp = info;
151     if (yres > 0) {
152     sprintf(cp, "NROWS=%d\n", yres *
153     (xres + !xres) );
154     while (*cp) ++cp;
155     }
156 greg 2.13 if ((xres <= 0) | (stdos.reclen > 1))
157     sprintf(cp, "NCOLS=%d\n", stdos.reclen);
158 greg 2.9 printheader(stdout, info);
159     }
160 greg 2.13 if (stdos.reclen == 1)
161     printresolu(stdout, xres, yres);
162 greg 2.1 if (waitflush > 0)
163     fflush(stdout);
164     stdos.xr = xres; stdos.yr = yres;
165 greg 2.15 #ifdef getc_unlocked
166 greg 2.1 flockfile(stdout); /* avoid lock/unlock overhead */
167     #endif
168     using_stdout = 1;
169     }
170     stdos.ofp = stdout;
171     stdos.reclen += noopen;
172     return(&stdos);
173     }
174     ofl = ofname(oname, ospec, mname, bn); /* get output name */
175     if (ofl < 0) {
176     sprintf(errmsg, "bad output format '%s'", ospec);
177     error(USER, errmsg);
178     }
179     lep = lu_find(&ofiletab, oname); /* look it up */
180     if (lep->key == NULL) /* new entry */
181     lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
182     sop = (STREAMOUT *)lep->data;
183     if (sop == NULL) { /* allocate stream */
184     sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
185     if (sop == NULL)
186     error(SYSTEM, "out of memory in getostream");
187 greg 2.19 sop->outpipe = (oname[0] == '!');
188 greg 2.1 sop->reclen = 0;
189     sop->ofp = NULL; /* open iff noopen==0 */
190     sop->xr = xres; sop->yr = yres;
191     lep->data = (char *)sop;
192     if (!sop->outpipe & !force_open & !recover &&
193     access(oname, F_OK) == 0) {
194     errno = EEXIST; /* file exists */
195     goto openerr;
196     }
197 greg 2.19 } else if (noopen && outfmt == 'c' && /* stream exists to picture? */
198     (sop->xr > 0) & (sop->yr > 0)) {
199     if (ofl & OF_BIN)
200     return(NULL); /* let caller offset bins */
201     sprintf(errmsg, "output '%s' not a valid picture", oname);
202     error(WARNING, errmsg);
203 greg 2.1 }
204     if (!noopen && sop->ofp == NULL) { /* open output stream */
205     if (oname[0] == '!') /* output to command */
206     sop->ofp = popen(oname+1, "w");
207     else /* else open file */
208     sop->ofp = fopen(oname, "w");
209     if (sop->ofp == NULL)
210     goto openerr;
211     if (outfmt != 'a')
212     SET_FILE_BINARY(sop->ofp);
213 greg 2.15 #ifdef getc_unlocked
214 greg 2.1 flockfile(sop->ofp); /* avoid lock/unlock overhead */
215     #endif
216 greg 2.11 if (accumulate > 0) { /* global resolution */
217     sop->xr = xres; sop->yr = yres;
218     }
219 greg 2.1 if (header) {
220 greg 2.11 cp = info;
221 greg 2.1 if (ofl & OF_MODIFIER || sop->reclen == 1) {
222     sprintf(cp, "MODIFIER=%s\n", mname);
223     while (*cp) ++cp;
224     }
225     if (ofl & OF_BIN) {
226     sprintf(cp, "BIN=%d\n", bn);
227     while (*cp) ++cp;
228     }
229 greg 2.11 if (sop->yr > 0) {
230     sprintf(cp, "NROWS=%d\n", sop->yr *
231     (sop->xr + !sop->xr) );
232     while (*cp) ++cp;
233     }
234 greg 2.13 if ((sop->xr <= 0) | (sop->reclen > 1))
235     sprintf(cp, "NCOLS=%d\n", sop->reclen);
236 greg 2.1 printheader(sop->ofp, info);
237     }
238 greg 2.13 if (sop->reclen == 1)
239     printresolu(sop->ofp, sop->xr, sop->yr);
240 greg 2.1 if (waitflush > 0)
241     fflush(sop->ofp);
242     }
243     sop->reclen += noopen; /* add to length if noopen */
244     return(sop); /* return output stream */
245     openerr:
246     sprintf(errmsg, "cannot open '%s' for writing", oname);
247     error(SYSTEM, errmsg);
248     return(NULL); /* pro forma return */
249     }
250    
251    
252     /* Get a vector from stdin */
253     int
254     getvec(FVECT vec)
255     {
256     float vf[3];
257     double vd[3];
258     char buf[32];
259     int i;
260    
261     switch (inpfmt) {
262     case 'a': /* ascii */
263     for (i = 0; i < 3; i++) {
264     if (fgetword(buf, sizeof(buf), stdin) == NULL ||
265     !isflt(buf))
266     return(-1);
267     vec[i] = atof(buf);
268     }
269     break;
270     case 'f': /* binary float */
271 greg 2.18 if (getbinary((char *)vf, sizeof(float), 3, stdin) != 3)
272 greg 2.1 return(-1);
273     VCOPY(vec, vf);
274     break;
275     case 'd': /* binary double */
276 greg 2.18 if (getbinary((char *)vd, sizeof(double), 3, stdin) != 3)
277 greg 2.1 return(-1);
278     VCOPY(vec, vd);
279     break;
280     default:
281     error(CONSISTENCY, "botched input format");
282     }
283     return(0);
284     }
285    
286    
287     /* Put out ray contribution to file */
288     static void
289     put_contrib(const DCOLOR cnt, FILE *fout)
290     {
291     double sf = 1;
292 greg 2.2 COLOR fv;
293 greg 2.1 COLR cv;
294    
295     if (accumulate > 1)
296     sf = 1./(double)accumulate;
297     switch (outfmt) {
298     case 'a':
299     if (accumulate > 1)
300     fprintf(fout, "%.6e\t%.6e\t%.6e\t",
301     sf*cnt[0], sf*cnt[1], sf*cnt[2]);
302     else
303     fprintf(fout, "%.6e\t%.6e\t%.6e\t",
304     cnt[0], cnt[1], cnt[2]);
305     break;
306     case 'f':
307     if (accumulate > 1) {
308 greg 2.2 copycolor(fv, cnt);
309     scalecolor(fv, sf);
310 greg 2.1 } else
311     copycolor(fv, cnt);
312 greg 2.18 putbinary(fv, sizeof(float), 3, fout);
313 greg 2.1 break;
314     case 'd':
315     if (accumulate > 1) {
316 greg 2.2 DCOLOR dv;
317     copycolor(dv, cnt);
318     scalecolor(dv, sf);
319 greg 2.18 putbinary(dv, sizeof(double), 3, fout);
320 greg 2.1 } else
321 greg 2.18 putbinary(cnt, sizeof(double), 3, fout);
322 greg 2.1 break;
323     case 'c':
324     if (accumulate > 1)
325     setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]);
326     else
327     setcolr(cv, cnt[0], cnt[1], cnt[2]);
328 greg 2.18 putbinary(cv, sizeof(cv), 1, fout);
329 greg 2.1 break;
330     default:
331     error(INTERNAL, "botched output format");
332     }
333     }
334    
335    
336     /* Output modifier values to appropriate stream(s) */
337     void
338     mod_output(MODCONT *mp)
339     {
340 greg 2.19 STREAMOUT *sop = getostream(mp->outspec, mp->modname, mp->bin0, 0);
341 greg 2.1 int j;
342    
343     put_contrib(mp->cbin[0], sop->ofp);
344     if (mp->nbins > 3 && /* minor optimization */
345 greg 2.19 sop == getostream(mp->outspec, mp->modname, mp->bin0+1, 0)) {
346 greg 2.1 for (j = 1; j < mp->nbins; j++)
347     put_contrib(mp->cbin[j], sop->ofp);
348 greg 2.3 } else {
349 greg 2.1 for (j = 1; j < mp->nbins; j++) {
350 greg 2.19 sop = getostream(mp->outspec, mp->modname, mp->bin0+j, 0);
351 greg 2.1 put_contrib(mp->cbin[j], sop->ofp);
352     }
353 greg 2.3 }
354 greg 2.1 }
355    
356    
357     /* callback to output newline to ASCII file and/or flush as requested */
358     static int
359     puteol(const LUENT *e, void *p)
360     {
361     STREAMOUT *sop = (STREAMOUT *)e->data;
362    
363     if (outfmt == 'a')
364     putc('\n', sop->ofp);
365     if (!waitflush)
366     fflush(sop->ofp);
367     if (ferror(sop->ofp)) {
368     sprintf(errmsg, "write error on file '%s'", e->key);
369     error(SYSTEM, errmsg);
370     }
371     return(0);
372     }
373    
374    
375     /* Terminate record output and flush if time */
376     void
377     end_record()
378     {
379     --waitflush;
380 greg 2.7 lu_doall(&ofiletab, &puteol, NULL);
381 greg 2.1 if (using_stdout & (outfmt == 'a'))
382     putc('\n', stdout);
383     if (!waitflush) {
384     waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
385     if (using_stdout)
386     fflush(stdout);
387     }
388     }
389    
390     /************************** PARTIAL RESULTS RECOVERY ***********************/
391    
392     /* Get ray contribution from previous file */
393     static int
394     get_contrib(DCOLOR cnt, FILE *finp)
395     {
396     COLOR fv;
397     COLR cv;
398    
399     switch (outfmt) {
400     case 'a':
401     return(fscanf(finp,"%lf %lf %lf",&cnt[0],&cnt[1],&cnt[2]) == 3);
402     case 'f':
403 greg 2.18 if (getbinary(fv, sizeof(fv[0]), 3, finp) != 3)
404 greg 2.1 return(0);
405     copycolor(cnt, fv);
406     return(1);
407     case 'd':
408 greg 2.18 return(getbinary(cnt, sizeof(cnt[0]), 3, finp) == 3);
409 greg 2.1 case 'c':
410 greg 2.18 if (getbinary(cv, sizeof(cv), 1, finp) != 1)
411 greg 2.1 return(0);
412     colr_color(fv, cv);
413     copycolor(cnt, fv);
414     return(1);
415     default:
416     error(INTERNAL, "botched output format");
417     }
418     return(0); /* pro forma return */
419     }
420    
421    
422     /* Close output file opened for input */
423     static int
424     myclose(const LUENT *e, void *p)
425     {
426     STREAMOUT *sop = (STREAMOUT *)e->data;
427    
428     if (sop->ofp == NULL)
429     return(0);
430     fclose(sop->ofp);
431     sop->ofp = NULL;
432     return(0);
433     }
434    
435    
436     /* Load previously accumulated values */
437     void
438     reload_output()
439     {
440     int i, j;
441     MODCONT *mp;
442     int ofl;
443     char oname[1024];
444     char *fmode = "rb";
445     char *outvfmt;
446     LUENT *oent;
447     int xr, yr;
448     STREAMOUT sout;
449     DCOLOR rgbv;
450    
451     if (outfmt == 'a')
452     fmode = "r";
453     outvfmt = formstr(outfmt);
454     /* reload modifier values */
455     for (i = 0; i < nmods; i++) {
456     mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
457     if (mp->outspec == NULL)
458     error(USER, "cannot reload from stdout");
459     if (mp->outspec[0] == '!')
460     error(USER, "cannot reload from command");
461     for (j = 0; ; j++) { /* load each modifier bin */
462     ofl = ofname(oname, mp->outspec, mp->modname, j);
463     if (ofl < 0)
464     error(USER, "bad output file specification");
465     oent = lu_find(&ofiletab, oname);
466     if (oent->data != NULL) {
467     sout = *(STREAMOUT *)oent->data;
468     } else {
469     sout.reclen = 0;
470     sout.outpipe = 0;
471     sout.xr = xres; sout.yr = yres;
472     sout.ofp = NULL;
473     }
474     if (sout.ofp == NULL) { /* open output as input */
475     sout.ofp = fopen(oname, fmode);
476     if (sout.ofp == NULL) {
477     if (j == mp->nbins)
478     break; /* assume end of modifier */
479     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.1 flockfile(sout.ofp);
486     #endif
487     if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) {
488     sprintf(errmsg, "format mismatch for '%s'",
489     oname);
490     error(USER, errmsg);
491     }
492 greg 2.16 if ((sout.reclen == 1) & (sout.xr > 0) & (sout.yr > 0) &&
493 greg 2.1 (!fscnresolu(&xr, &yr, sout.ofp) ||
494     (xr != sout.xr) |
495     (yr != sout.yr))) {
496     sprintf(errmsg, "resolution mismatch for '%s'",
497     oname);
498     error(USER, errmsg);
499     }
500     }
501     /* read in RGB value */
502     if (!get_contrib(rgbv, sout.ofp)) {
503     if (!j) {
504     fclose(sout.ofp);
505     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     }
514     if (j >= mp->nbins) { /* check modifier size */
515     sprintf(errmsg,
516     "mismatched -bn setting for reloading '%s'",
517     modname[i]);
518     error(USER, errmsg);
519     }
520    
521     copycolor(mp->cbin[j], rgbv);
522     if (oent->key == NULL) /* new file entry */
523     oent->key = strcpy((char *)
524     malloc(strlen(oname)+1), oname);
525     if (oent->data == NULL)
526     oent->data = (char *)malloc(sizeof(STREAMOUT));
527     *(STREAMOUT *)oent->data = sout;
528     }
529     }
530 greg 2.7 lu_doall(&ofiletab, &myclose, NULL); /* close all files */
531 greg 2.1 }
532    
533    
534     /* Seek on the given output file */
535     static int
536     myseeko(const LUENT *e, void *p)
537     {
538     STREAMOUT *sop = (STREAMOUT *)e->data;
539     off_t nbytes = *(off_t *)p;
540    
541     if (sop->reclen > 1)
542     nbytes = nbytes * sop->reclen;
543     if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
544     sprintf(errmsg, "seek error on file '%s'", e->key);
545     error(SYSTEM, errmsg);
546     }
547     return(0);
548     }
549    
550    
551     /* Recover output if possible */
552     void
553     recover_output()
554     {
555     off_t lastout = -1;
556     int outvsiz, recsiz;
557     char *outvfmt;
558     int i, j;
559     MODCONT *mp;
560     int ofl;
561     char oname[1024];
562     LUENT *oent;
563     STREAMOUT sout;
564     off_t nvals;
565     int xr, yr;
566    
567     switch (outfmt) {
568     case 'a':
569     error(USER, "cannot recover ASCII output");
570     return;
571     case 'f':
572     outvsiz = sizeof(float)*3;
573     break;
574     case 'd':
575     outvsiz = sizeof(double)*3;
576     break;
577     case 'c':
578     outvsiz = sizeof(COLR);
579     break;
580     default:
581     error(INTERNAL, "botched output format");
582     return;
583     }
584     outvfmt = formstr(outfmt);
585     /* check modifier outputs */
586     for (i = 0; i < nmods; i++) {
587     mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
588     if (mp->outspec == NULL)
589     error(USER, "cannot recover from stdout");
590     if (mp->outspec[0] == '!')
591     error(USER, "cannot recover from command");
592     for (j = 0; ; j++) { /* check each bin's file */
593     ofl = ofname(oname, mp->outspec, mp->modname, j);
594     if (ofl < 0)
595     error(USER, "bad output file specification");
596     oent = lu_find(&ofiletab, oname);
597     if (oent->data != NULL) {
598     sout = *(STREAMOUT *)oent->data;
599     } else {
600     sout.reclen = 0;
601     sout.outpipe = 0;
602 greg 2.16 sout.xr = xres;
603     sout.yr = yres;
604 greg 2.1 sout.ofp = NULL;
605     }
606     if (sout.ofp != NULL) { /* already open? */
607     if (ofl & OF_BIN)
608     continue;
609     break;
610     }
611     /* open output */
612     sout.ofp = fopen(oname, "rb+");
613     if (sout.ofp == NULL) {
614     if (j == mp->nbins)
615     break; /* assume end of modifier */
616     sprintf(errmsg, "missing recover file '%s'",
617     oname);
618     error(WARNING, errmsg);
619     break;
620     }
621     nvals = lseek(fileno(sout.ofp), 0, SEEK_END);
622     if (nvals <= 0) {
623     lastout = 0; /* empty output, quit here */
624     fclose(sout.ofp);
625     break;
626     }
627     if (!sout.reclen) {
628     if (!(ofl & OF_BIN)) {
629     sprintf(errmsg,
630     "need -bn to recover file '%s'",
631     oname);
632     error(USER, errmsg);
633     }
634     recsiz = outvsiz;
635     } else
636     recsiz = outvsiz * sout.reclen;
637    
638     lseek(fileno(sout.ofp), 0, SEEK_SET);
639     if (header && checkheader(sout.ofp, outvfmt, NULL) != 1) {
640     sprintf(errmsg, "format mismatch for '%s'",
641     oname);
642     error(USER, errmsg);
643     }
644 greg 2.16 if ((sout.reclen == 1) & (sout.xr > 0) & (sout.yr > 0) &&
645 greg 2.1 (!fscnresolu(&xr, &yr, sout.ofp) ||
646     (xr != sout.xr) |
647     (yr != sout.yr))) {
648     sprintf(errmsg, "resolution mismatch for '%s'",
649     oname);
650     error(USER, errmsg);
651     }
652     nvals = (nvals - (off_t)ftell(sout.ofp)) / recsiz;
653     if ((lastout < 0) | (nvals < lastout))
654     lastout = nvals;
655     if (oent->key == NULL) /* new entry */
656     oent->key = strcpy((char *)
657     malloc(strlen(oname)+1), oname);
658     if (oent->data == NULL)
659     oent->data = (char *)malloc(sizeof(STREAMOUT));
660     *(STREAMOUT *)oent->data = sout;
661     if (!(ofl & OF_BIN))
662     break; /* no bin separation */
663     }
664     if (!lastout) { /* empty output */
665     error(WARNING, "no previous data to recover");
666     lu_done(&ofiletab); /* reclose all outputs */
667     return;
668     }
669     if (j > mp->nbins) { /* check modifier size */
670     sprintf(errmsg,
671     "mismatched -bn setting for recovering '%s'",
672     modname[i]);
673     error(USER, errmsg);
674     }
675     }
676     if (lastout < 0) {
677     error(WARNING, "no output files to recover");
678     return;
679     }
680     if (raysleft && lastout >= raysleft/accumulate) {
681     error(WARNING, "output appears to be complete");
682     /* XXX should read & discard input? */
683     quit(0);
684     }
685     /* seek on all files */
686     nvals = lastout * outvsiz;
687 greg 2.7 lu_doall(&ofiletab, &myseeko, &nvals);
688 greg 2.1 /* skip repeated input */
689 greg 2.5 lastout *= accumulate;
690 greg 2.1 for (nvals = 0; nvals < lastout; nvals++) {
691     FVECT vdummy;
692     if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
693     error(USER, "unexpected EOF on input");
694     }
695 greg 2.5 lastray = lastdone = (RNUMBER)lastout;
696 greg 2.1 if (raysleft)
697     raysleft -= lastray;
698     }