ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rv2.c
Revision: 2.80
Committed: Sat Jun 7 05:09:46 2025 UTC (19 hours, 12 minutes ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.79: +1 -2 lines
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

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