ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rv2.c
Revision: 2.42
Committed: Mon Jul 21 22:30:19 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.41: +7 -7 lines
Log Message:
Eliminated copystruct() macro, which is unnecessary in ANSI.
Reduced ambiguity warnings for nested if/if/else clauses.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rv2.c,v 2.41 2003/06/30 14:59:13 schorsch Exp $";
3 #endif
4 /*
5 * rv2.c - command routines used in tracing a view.
6 *
7 * External symbols declared in rpaint.h
8 */
9
10 #include "copyright.h"
11
12 #include <ctype.h>
13 #include <string.h>
14
15 #include "platform.h"
16 #include "ray.h"
17 #include "otypes.h"
18 #include "rpaint.h"
19
20 extern int psample; /* pixel sample size */
21 extern double maxdiff; /* max. sample difference */
22
23 #define CTRL(c) ((c)-'@')
24
25 #ifdef SMLFLT
26 #define sscanvec(s,v) (sscanf(s,"%f %f %f",v,v+1,v+2)==3)
27 #else
28 #define sscanvec(s,v) (sscanf(s,"%lf %lf %lf",v,v+1,v+2)==3)
29 #endif
30
31 extern char rifname[128]; /* rad input file name */
32
33 extern char *progname;
34 extern char *octname;
35
36
37 void
38 getframe(s) /* get a new frame */
39 char *s;
40 {
41 if (getrect(s, &pframe) < 0)
42 return;
43 pdepth = 0;
44 }
45
46
47 void
48 getrepaint(s) /* get area and repaint */
49 char *s;
50 {
51 RECT box;
52
53 if (getrect(s, &box) < 0)
54 return;
55 paintrect(&ptrunk, 0, 0, hresolu, vresolu, &box);
56 }
57
58
59 void
60 getview(s) /* get/show view parameters */
61 char *s;
62 {
63 FILE *fp;
64 char buf[128];
65 char *fname;
66 int change = 0;
67 VIEW nv;
68
69 while (isspace(*s))
70 s++;
71 if (*s == '-') { /* command line parameters */
72 nv = ourview;
73 if (sscanview(&nv, s))
74 newview(&nv);
75 else
76 error(COMMAND, "bad view option(s)");
77 return;
78 }
79 if (sscanf(s, "%s", buf) == 1) { /* write parameters to a file */
80 if ((fname = getpath(buf, NULL, 0)) == NULL ||
81 (fp = fopen(fname, "a")) == NULL) {
82 sprintf(errmsg, "cannot open \"%s\"", buf);
83 error(COMMAND, errmsg);
84 return;
85 }
86 fputs(progname, fp);
87 fprintview(&ourview, fp);
88 fputs(sskip(s), fp);
89 putc('\n', fp);
90 fclose(fp);
91 return;
92 }
93 sprintf(buf, "view type (%c): ", ourview.type);
94 (*dev->comout)(buf);
95 (*dev->comin)(buf, NULL);
96 if (buf[0] == CTRL('C')) return;
97 if (buf[0] && buf[0] != ourview.type) {
98 nv.type = buf[0];
99 change++;
100 } else
101 nv.type = ourview.type;
102 sprintf(buf, "view point (%.6g %.6g %.6g): ",
103 ourview.vp[0], ourview.vp[1], ourview.vp[2]);
104 (*dev->comout)(buf);
105 (*dev->comin)(buf, NULL);
106 if (buf[0] == CTRL('C')) return;
107 if (sscanvec(buf, nv.vp))
108 change++;
109 else
110 VCOPY(nv.vp, ourview.vp);
111 sprintf(buf, "view direction (%.6g %.6g %.6g): ",
112 ourview.vdir[0], ourview.vdir[1], ourview.vdir[2]);
113 (*dev->comout)(buf);
114 (*dev->comin)(buf, NULL);
115 if (buf[0] == CTRL('C')) return;
116 if (sscanvec(buf, nv.vdir))
117 change++;
118 else
119 VCOPY(nv.vdir, ourview.vdir);
120 sprintf(buf, "view up (%.6g %.6g %.6g): ",
121 ourview.vup[0], ourview.vup[1], ourview.vup[2]);
122 (*dev->comout)(buf);
123 (*dev->comin)(buf, NULL);
124 if (buf[0] == CTRL('C')) return;
125 if (sscanvec(buf, nv.vup))
126 change++;
127 else
128 VCOPY(nv.vup, ourview.vup);
129 sprintf(buf, "view horiz and vert size (%.6g %.6g): ",
130 ourview.horiz, ourview.vert);
131 (*dev->comout)(buf);
132 (*dev->comin)(buf, NULL);
133 if (buf[0] == CTRL('C')) return;
134 if (sscanf(buf, "%lf %lf", &nv.horiz, &nv.vert) == 2)
135 change++;
136 else {
137 nv.horiz = ourview.horiz; nv.vert = ourview.vert;
138 }
139 sprintf(buf, "fore and aft clipping plane (%.6g %.6g): ",
140 ourview.vfore, ourview.vaft);
141 (*dev->comout)(buf);
142 (*dev->comin)(buf, NULL);
143 if (buf[0] == CTRL('C')) return;
144 if (sscanf(buf, "%lf %lf", &nv.vfore, &nv.vaft) == 2)
145 change++;
146 else {
147 nv.vfore = ourview.vfore; nv.vaft = ourview.vaft;
148 }
149 sprintf(buf, "view shift and lift (%.6g %.6g): ",
150 ourview.hoff, ourview.voff);
151 (*dev->comout)(buf);
152 (*dev->comin)(buf, NULL);
153 if (buf[0] == CTRL('C')) return;
154 if (sscanf(buf, "%lf %lf", &nv.hoff, &nv.voff) == 2)
155 change++;
156 else {
157 nv.hoff = ourview.hoff; nv.voff = ourview.voff;
158 }
159 if (change)
160 newview(&nv);
161 }
162
163
164 void
165 lastview(s) /* return to a previous view */
166 char *s;
167 {
168 char buf[128];
169 char *fname;
170 int success;
171 VIEW nv;
172
173 if (sscanf(s, "%s", buf) == 1) { /* get parameters from a file */
174 nv = stdview;
175 if ((fname = getpath(buf, "", R_OK)) == NULL ||
176 (success = viewfile(fname, &nv, NULL)) == -1) {
177 sprintf(errmsg, "cannot open \"%s\"", buf);
178 error(COMMAND, errmsg);
179 return;
180 }
181 if (!success)
182 error(COMMAND, "wrong file format");
183 else
184 newview(&nv);
185 return;
186 }
187 if (oldview.type == 0) { /* no old view! */
188 error(COMMAND, "no previous view");
189 return;
190 }
191 nv = ourview;
192 ourview = oldview;
193 oldview = nv;
194 newimage();
195 }
196
197
198 void
199 saveview(s) /* save view to rad file */
200 char *s;
201 {
202 char view[64];
203 char *fname;
204 FILE *fp;
205
206 if (*atos(view, sizeof(view), s)) {
207 if (isint(view)) {
208 error(COMMAND, "cannot write view by number");
209 return;
210 }
211 s = sskip(s);
212 }
213 while (isspace(*s))
214 s++;
215 if (*s)
216 atos(rifname, sizeof(rifname), s);
217 else if (rifname[0] == '\0') {
218 error(COMMAND, "no previous rad file");
219 return;
220 }
221 if ((fname = getpath(rifname, NULL, 0)) == NULL ||
222 (fp = fopen(fname, "a")) == NULL) {
223 sprintf(errmsg, "cannot open \"%s\"", rifname);
224 error(COMMAND, errmsg);
225 return;
226 }
227 fputs("view= ", fp);
228 fputs(view, fp);
229 fprintview(&ourview, fp);
230 putc('\n', fp);
231 fclose(fp);
232 }
233
234
235 void
236 loadview(s) /* load view from rad file */
237 char *s;
238 {
239 char buf[512];
240 char *fname;
241 FILE *fp;
242 VIEW nv;
243
244 strcpy(buf, "rad -n -s -V -v ");
245 if (sscanf(s, "%s", buf+strlen(buf)) == 1)
246 s = sskip(s);
247 else
248 strcat(buf, "1");
249 if (*s)
250 atos(rifname, sizeof(rifname), s);
251 else if (rifname[0] == '\0') {
252 error(COMMAND, "no previous rad file");
253 return;
254 }
255 if ((fname = getpath(rifname, "", R_OK)) == NULL) {
256 sprintf(errmsg, "cannot access \"%s\"", rifname);
257 error(COMMAND, errmsg);
258 return;
259 }
260 sprintf(buf+strlen(buf), " %s", fname);
261 if ((fp = popen(buf, "r")) == NULL) {
262 error(COMMAND, "cannot run rad");
263 return;
264 }
265 buf[0] = '\0';
266 fgets(buf, sizeof(buf), fp);
267 pclose(fp);
268 nv = stdview;
269 if (!sscanview(&nv, buf)) {
270 error(COMMAND, "rad error -- no such view?");
271 return;
272 }
273 newview(&nv);
274 }
275
276
277 void
278 getaim(s) /* aim camera */
279 char *s;
280 {
281 double zfact;
282 VIEW nv;
283
284 if (getinterest(s, 1, nv.vdir, &zfact) < 0)
285 return;
286 nv.type = ourview.type;
287 VCOPY(nv.vp, ourview.vp);
288 VCOPY(nv.vup, ourview.vup);
289 nv.horiz = ourview.horiz; nv.vert = ourview.vert;
290 nv.vfore = ourview.vfore; nv.vaft = ourview.vaft;
291 nv.hoff = ourview.hoff; nv.voff = ourview.voff;
292 zoomview(&nv, zfact);
293 newview(&nv);
294 }
295
296
297 void
298 getmove(s) /* move camera */
299 char *s;
300 {
301 FVECT vc;
302 double mag;
303
304 if (getinterest(s, 0, vc, &mag) < 0)
305 return;
306 moveview(0.0, 0.0, mag, vc);
307 }
308
309
310 void
311 getrotate(s) /* rotate camera */
312 char *s;
313 {
314 VIEW nv;
315 FVECT v1;
316 double angle, elev, zfact;
317
318 elev = 0.0; zfact = 1.0;
319 if (sscanf(s, "%lf %lf %lf", &angle, &elev, &zfact) < 1) {
320 error(COMMAND, "missing angle");
321 return;
322 }
323 nv.type = ourview.type;
324 VCOPY(nv.vp, ourview.vp);
325 VCOPY(nv.vup, ourview.vup);
326 nv.hoff = ourview.hoff; nv.voff = ourview.voff;
327 nv.vfore = ourview.vfore; nv.vaft = ourview.vaft;
328 spinvector(nv.vdir, ourview.vdir, ourview.vup, angle*(PI/180.));
329 if (elev != 0.0) {
330 fcross(v1, nv.vdir, ourview.vup);
331 normalize(v1);
332 spinvector(nv.vdir, nv.vdir, v1, elev*(PI/180.));
333 }
334 nv.horiz = ourview.horiz; nv.vert = ourview.vert;
335 zoomview(&nv, zfact);
336 newview(&nv);
337 }
338
339
340 void
341 getpivot(s) /* pivot viewpoint */
342 register char *s;
343 {
344 FVECT vc;
345 double angle, elev, mag;
346
347 elev = 0.0;
348 if (sscanf(s, "%lf %lf", &angle, &elev) < 1) {
349 error(COMMAND, "missing angle");
350 return;
351 }
352 if (getinterest(sskip2(s,2), 0, vc, &mag) < 0)
353 return;
354 moveview(angle, elev, mag, vc);
355 }
356
357
358 void
359 getexposure(s) /* get new exposure */
360 char *s;
361 {
362 char buf[128];
363 register char *cp;
364 RECT r;
365 int x, y;
366 register PNODE *p = &ptrunk;
367 int adapt = 0;
368 double e = 1.0;
369
370 for (cp = s; isspace(*cp); cp++)
371 ;
372 if (*cp == '@') {
373 adapt++;
374 while (isspace(*++cp))
375 ;
376 }
377 if (*cp == '\0') { /* normalize to point */
378 if (dev->getcur == NULL)
379 return;
380 (*dev->comout)("Pick point for exposure\n");
381 if ((*dev->getcur)(&x, &y) == ABORT)
382 return;
383 r.l = r.d = 0;
384 r.r = hresolu; r.u = vresolu;
385 p = findrect(x, y, &ptrunk, &r, -1);
386 } else {
387 if (*cp == '=') { /* absolute setting */
388 p = NULL;
389 e = 1.0/exposure;
390 for (cp++; isspace(*cp); cp++)
391 ;
392 if (*cp == '\0') { /* interactive */
393 sprintf(buf, "exposure (%f): ", exposure);
394 (*dev->comout)(buf);
395 (*dev->comin)(buf, NULL);
396 for (cp = buf; isspace(*cp); cp++)
397 ;
398 if (*cp == '\0')
399 return;
400 }
401 }
402 if (*cp == '+' || *cp == '-') /* f-stops */
403 e *= pow(2.0, atof(cp));
404 else /* multiplier */
405 e *= atof(cp);
406 }
407 if (p != NULL) { /* relative setting */
408 if (bright(p->v) < 1e-15) {
409 error(COMMAND, "cannot normalize to zero");
410 return;
411 }
412 if (adapt)
413 e *= 106./pow(1.219+pow(luminance(p->v)/exposure,.4),2.5)/exposure;
414 else
415 e *= 0.5 / bright(p->v);
416 }
417 if (e <= FTINY || fabs(1.0 - e) <= FTINY)
418 return;
419 scalepict(&ptrunk, e);
420 exposure *= e;
421 redraw();
422 }
423
424 typedef union {int i; double d; COLOR C;} *MyUptr;
425
426 int
427 getparam(str, dsc, typ, p) /* get variable from user */
428 char *str, *dsc;
429 int typ;
430 void *p;
431 {
432 register MyUptr ptr = (MyUptr)p;
433 int i0;
434 double d0, d1, d2;
435 char buf[48];
436
437 switch (typ) {
438 case 'i': /* integer */
439 if (sscanf(str, "%d", &i0) != 1) {
440 (*dev->comout)(dsc);
441 sprintf(buf, " (%d): ", ptr->i);
442 (*dev->comout)(buf);
443 (*dev->comin)(buf, NULL);
444 if (sscanf(buf, "%d", &i0) != 1)
445 return(0);
446 }
447 ptr->i = i0;
448 return(1);
449 case 'r': /* real */
450 if (sscanf(str, "%lf", &d0) != 1) {
451 (*dev->comout)(dsc);
452 sprintf(buf, " (%.6g): ", ptr->d);
453 (*dev->comout)(buf);
454 (*dev->comin)(buf, NULL);
455 if (sscanf(buf, "%lf", &d0) != 1)
456 return(0);
457 }
458 ptr->d = d0;
459 return(1);
460 case 'b': /* boolean */
461 if (sscanf(str, "%1s", buf) != 1) {
462 (*dev->comout)(dsc);
463 sprintf(buf, "? (%c): ", ptr->i ? 'y' : 'n');
464 (*dev->comout)(buf);
465 (*dev->comin)(buf, NULL);
466 if (buf[0] == '\0' ||
467 strchr("yY+1tTnN-0fF", buf[0]) == NULL)
468 return(0);
469 }
470 ptr->i = strchr("yY+1tT", buf[0]) != NULL;
471 return(1);
472 case 'C': /* color */
473 if (sscanf(str, "%lf %lf %lf", &d0, &d1, &d2) != 3) {
474 (*dev->comout)(dsc);
475 sprintf(buf, " (%.6g %.6g %.6g): ",
476 colval(ptr->C,RED),
477 colval(ptr->C,GRN),
478 colval(ptr->C,BLU));
479 (*dev->comout)(buf);
480 (*dev->comin)(buf, NULL);
481 if (sscanf(buf, "%lf %lf %lf", &d0, &d1, &d2) != 3)
482 return(0);
483 }
484 setcolor(ptr->C, d0, d1, d2);
485 return(1);
486 }
487 }
488
489
490 void
491 setparam(s) /* get/set program parameter */
492 register char *s;
493 {
494 char buf[128];
495
496 if (s[0] == '\0') {
497 (*dev->comout)(
498 "aa ab ad ar as av aw b dc dv dj ds dt i lr lw me ma mg ms ps pt sj st bv: ");
499 (*dev->comin)(buf, NULL);
500 s = buf;
501 }
502 switch (s[0]) {
503 case 'l': /* limit */
504 switch (s[1]) {
505 case 'w': /* weight */
506 getparam(s+2, "limit weight", 'r',
507 (void *)&minweight);
508 break;
509 case 'r': /* reflection */
510 getparam(s+2, "limit reflection", 'i',
511 (void *)&maxdepth);
512 break;
513 default:
514 goto badparam;
515 }
516 break;
517 case 'd': /* direct */
518 switch (s[1]) {
519 case 'j': /* jitter */
520 getparam(s+2, "direct jitter", 'r',
521 (void *)&dstrsrc);
522 break;
523 case 'c': /* certainty */
524 getparam(s+2, "direct certainty", 'r',
525 (void *)&shadcert);
526 break;
527 case 't': /* threshold */
528 getparam(s+2, "direct threshold", 'r',
529 (void *)&shadthresh);
530 break;
531 case 'v': /* visibility */
532 getparam(s+2, "direct visibility", 'b',
533 (void *)&directvis);
534 break;
535 case 's': /* sampling */
536 getparam(s+2, "direct sampling", 'r',
537 (void *)&srcsizerat);
538 break;
539 default:
540 goto badparam;
541 }
542 break;
543 case 'b': /* back faces or black and white */
544 switch (s[1]) {
545 case 'v': /* back face visibility */
546 getparam(s+2, "back face visibility", 'b',
547 (void *)&backvis);
548 break;
549 case '\0': /* black and white */
550 case ' ':
551 case 'y': case 'Y': case 't': case 'T': case '1': case '+':
552 case 'n': case 'N': case 'f': case 'F': case '0': case '-':
553 getparam(s+1, "black and white", 'b',
554 (void *)&greyscale);
555 break;
556 default:
557 goto badparam;
558 }
559 break;
560 case 'i': /* irradiance */
561 getparam(s+1, "irradiance", 'b',
562 (void *)&do_irrad);
563 break;
564 case 'a': /* ambient */
565 switch (s[1]) {
566 case 'v': /* value */
567 getparam(s+2, "ambient value", 'C',
568 (void *)ambval);
569 break;
570 case 'w': /* weight */
571 getparam(s+2, "ambient value weight", 'i',
572 (void *)&ambvwt);
573 break;
574 case 'a': /* accuracy */
575 if (getparam(s+2, "ambient accuracy", 'r',
576 (void *)&ambacc))
577 setambacc(ambacc);
578 break;
579 case 'd': /* divisions */
580 getparam(s+2, "ambient divisions", 'i',
581 (void *)&ambdiv);
582 break;
583 case 's': /* samples */
584 getparam(s+2, "ambient super-samples", 'i',
585 (void *)&ambssamp);
586 break;
587 case 'b': /* bounces */
588 getparam(s+2, "ambient bounces", 'i',
589 (void *)&ambounce);
590 break;
591 case 'r':
592 if (getparam(s+2, "ambient resolution", 'i',
593 (void *)&ambres))
594 setambres(ambres);
595 break;
596 default:
597 goto badparam;
598 }
599 break;
600 case 'm': /* medium */
601 switch (s[1]) {
602 case 'e': /* extinction coefficient */
603 getparam(s+2, "extinction coefficient", 'C',
604 (void *)cextinction);
605 break;
606 case 'a': /* scattering albedo */
607 getparam(s+2, "scattering albedo", 'C',
608 (void *)salbedo);
609 break;
610 case 'g': /* scattering eccentricity */
611 getparam(s+2, "scattering eccentricity", 'r',
612 (void *)&seccg);
613 break;
614 case 's': /* sampling distance */
615 getparam(s+2, "mist sampling distance", 'r',
616 (void *)&ssampdist);
617 break;
618 default:
619 goto badparam;
620 }
621 break;
622 case 'p': /* pixel */
623 switch (s[1]) {
624 case 's': /* sample */
625 if (getparam(s+2, "pixel sample", 'i',
626 (void *)&psample))
627 pdepth = 0;
628 break;
629 case 't': /* threshold */
630 if (getparam(s+2, "pixel threshold", 'r',
631 (void *)&maxdiff))
632 pdepth = 0;
633 break;
634 default:
635 goto badparam;
636 }
637 break;
638 case 's': /* specular */
639 switch (s[1]) {
640 case 'j': /* jitter */
641 getparam(s+2, "specular jitter", 'r',
642 (void *)&specjitter);
643 break;
644 case 't': /* threshold */
645 getparam(s+2, "specular threshold", 'r',
646 (void *)&specthresh);
647 break;
648 default:
649 goto badparam;
650 }
651 break;
652 case '\0': /* nothing */
653 break;
654 default:;
655 badparam:
656 *sskip(s) = '\0';
657 sprintf(errmsg, "%s: unknown variable", s);
658 error(COMMAND, errmsg);
659 break;
660 }
661 }
662
663
664 void
665 traceray(s) /* trace a single ray */
666 char *s;
667 {
668 char buf[128];
669 int x, y;
670 OBJREC *ino;
671 RAY thisray;
672
673 thisray.rmax = 0.0;
674
675 if (!sscanvec(s, thisray.rorg) ||
676 !sscanvec(sskip2(s,3), thisray.rdir)) {
677
678 if (dev->getcur == NULL)
679 return;
680 (*dev->comout)("Pick ray\n");
681 if ((*dev->getcur)(&x, &y) == ABORT)
682 return;
683
684 if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir,
685 &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) {
686 error(COMMAND, "not on image");
687 return;
688 }
689
690 } else if (normalize(thisray.rdir) == 0.0) {
691 error(COMMAND, "zero ray direction");
692 return;
693 }
694
695 rayorigin(&thisray, NULL, PRIMARY, 1.0);
696
697 rayvalue(&thisray);
698
699 if (thisray.ro == NULL)
700 (*dev->comout)("ray hit nothing");
701 else {
702 sprintf(buf, "ray hit %s%s %s \"%s\"",
703 thisray.rod < 0.0 ? "back of " : "",
704 thisray.ro->omod == OVOID ? VOIDID :
705 objptr(thisray.ro->omod)->oname,
706 ofun[thisray.ro->otype].funame,
707 thisray.ro->oname);
708 if ((ino = objptr(thisray.robj)) != thisray.ro)
709 sprintf(buf+strlen(buf), " in %s \"%s\"",
710 ofun[ino->otype].funame, ino->oname);
711 (*dev->comout)(buf);
712 (*dev->comin)(buf, NULL);
713 if (thisray.rot >= FHUGE)
714 (*dev->comout)("at infinity");
715 else {
716 sprintf(buf, "at (%.6g %.6g %.6g) (%.6g)",
717 thisray.rop[0], thisray.rop[1],
718 thisray.rop[2], thisray.rt);
719 (*dev->comout)(buf);
720 }
721 (*dev->comin)(buf, NULL);
722 sprintf(buf, "value (%.5g %.5g %.5g) (%.3gL)",
723 colval(thisray.rcol,RED),
724 colval(thisray.rcol,GRN),
725 colval(thisray.rcol,BLU),
726 luminance(thisray.rcol));
727 (*dev->comout)(buf);
728 }
729 (*dev->comin)(buf, NULL);
730 }
731
732
733 void
734 writepict(s) /* write the picture to a file */
735 char *s;
736 {
737 static char buf[128];
738 char *fname;
739 FILE *fp;
740 COLR *scanline;
741 int y;
742
743 while (isspace(*s))
744 s++;
745 if (*s)
746 atos(buf, sizeof(buf), s);
747 else if (buf[0] == '\0') {
748 error(COMMAND, "no file");
749 return;
750 }
751 if ((fname = getpath(buf, NULL, 0)) == NULL ||
752 (fp = fopen(fname, "w")) == NULL) {
753 sprintf(errmsg, "cannot open \"%s\"", buf);
754 error(COMMAND, errmsg);
755 return;
756 }
757 SET_FILE_BINARY(fp);
758 (*dev->comout)("writing \"");
759 (*dev->comout)(fname);
760 (*dev->comout)("\"...\n");
761 /* write header */
762 newheader("RADIANCE", fp);
763 fputs(progname, fp);
764 fprintview(&ourview, fp);
765 if (octname != NULL)
766 fprintf(fp, " %s\n", octname);
767 else
768 putc('\n', fp);
769 fprintf(fp, "SOFTWARE= %s\n", VersionID);
770 fputnow(fp);
771 if (exposure != 1.0)
772 fputexpos(exposure, fp);
773 if (dev->pixaspect != 1.0)
774 fputaspect(dev->pixaspect, fp);
775 fputformat(COLRFMT, fp);
776 putc('\n', fp);
777 fprtresolu(hresolu, vresolu, fp);
778
779 scanline = (COLR *)malloc(hresolu*sizeof(COLR));
780 if (scanline == NULL) {
781 error(COMMAND, "not enough memory!");
782 fclose(fp);
783 unlink(fname);
784 return;
785 }
786 for (y = vresolu-1; y >= 0; y--) {
787 getpictcolrs(y, scanline, &ptrunk, hresolu, vresolu);
788 if (fwritecolrs(scanline, hresolu, fp) < 0)
789 break;
790 }
791 free((void *)scanline);
792 if (fclose(fp) < 0)
793 error(COMMAND, "write error");
794 }