ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rv2.c
Revision: 2.45
Committed: Fri Jan 21 00:52:59 2005 UTC (19 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.44: +42 -3 lines
Log Message:
Fixed bug in rvu "move" command from last change and added "focus" command

File Contents

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