ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.48
Committed: Tue Jan 18 03:59:41 2005 UTC (19 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.47: +69 -57 lines
Log Message:
Created pmdblur script and added DBLUR variable to ranimate

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ranimate.c,v 2.47 2004/06/08 19:48:31 greg Exp $";
3 #endif
4 /*
5 * Radiance animation control program
6 *
7 * The main difference between this program and ranimove is that
8 * we have many optimizations here for camera motion in static
9 * environments, calling rpict and pinterp on multiple processors,
10 * where ranimove puts its emphasis on object motion, and does
11 * not use any external programs for image generation.
12 *
13 * See the ranimate(1) man page for further details.
14 */
15
16 #include "copyright.h"
17
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <sys/stat.h>
21 #include <time.h>
22 #include <signal.h>
23
24 #include "platform.h"
25 #include "paths.h"
26 #include "standard.h"
27 #include "view.h"
28 #include "vars.h"
29 #include "netproc.h"
30 /* default blur samples */
31 #ifndef DEF_NBLUR
32 #define DEF_NBLUR 5
33 #endif
34 /* default remote shell */
35 #define REMSH "rsh"
36 /* input variables (alphabetical by name) */
37 #define ANIMATE 0 /* animation command */
38 #define ARCHIVE 1 /* archiving command */
39 #define BASENAME 2 /* output image base name */
40 #define DBLUR 3 /* depth of field blur */
41 #define DIRECTORY 4 /* working (sub)directory */
42 #define DISKSPACE 5 /* how much disk space to use */
43 #define END 6 /* ending frame number */
44 #define EXPOSURE 7 /* how to compute exposure */
45 #define HOST 8 /* rendering host machine */
46 #define INTERP 9 /* # frames to interpolate */
47 #define MBLUR 10 /* motion blur parameters */
48 #define NEXTANIM 11 /* next animation file */
49 #define OCTREE 12 /* octree file name */
50 #define OVERSAMP 13 /* # times to oversample image */
51 #define PFILT 14 /* pfilt options */
52 #define PINTERP 15 /* pinterp options */
53 #define RENDER 16 /* rendering options */
54 #define RESOLUTION 17 /* desired final resolution */
55 #define RIF 18 /* rad input file */
56 #define RSH 19 /* remote shell script or program */
57 #define RTRACE 20 /* use rtrace with pinterp? */
58 #define START 21 /* starting frame number */
59 #define TRANSFER 22 /* frame transfer command */
60 #define VIEWFILE 23 /* animation frame views */
61
62 int NVARS = 24; /* total number of variables */
63
64 VARIABLE vv[] = { /* variable-value pairs */
65 {"ANIMATE", 2, 0, NULL, onevalue},
66 {"ARCHIVE", 2, 0, NULL, onevalue},
67 {"BASENAME", 3, 0, NULL, onevalue},
68 {"DBLUR", 2, 0, NULL, onevalue},
69 {"DIRECTORY", 3, 0, NULL, onevalue},
70 {"DISKSPACE", 3, 0, NULL, fltvalue},
71 {"END", 2, 0, NULL, intvalue},
72 {"EXPOSURE", 3, 0, NULL, onevalue},
73 {"host", 4, 0, NULL, NULL},
74 {"INTERPOLATE", 3, 0, NULL, intvalue},
75 {"MBLUR", 2, 0, NULL, onevalue},
76 {"NEXTANIM", 3, 0, NULL, onevalue},
77 {"OCTREE", 3, 0, NULL, onevalue},
78 {"OVERSAMPLE", 2, 0, NULL, fltvalue},
79 {"pfilt", 2, 0, NULL, catvalues},
80 {"pinterp", 2, 0, NULL, catvalues},
81 {"render", 3, 0, NULL, catvalues},
82 {"RESOLUTION", 3, 0, NULL, onevalue},
83 {"RIF", 3, 0, NULL, onevalue},
84 {"RSH", 3, 0, NULL, onevalue},
85 {"RTRACE", 2, 0, NULL, boolvalue},
86 {"START", 2, 0, NULL, intvalue},
87 {"TRANSFER", 2, 0, NULL, onevalue},
88 {"VIEWFILE", 2, 0, NULL, onevalue},
89 };
90
91 #define SFNAME "STATUS" /* status file name */
92
93 struct {
94 char host[64]; /* control host name */
95 int pid; /* control process id */
96 char cfname[128]; /* control file name */
97 int rnext; /* next frame to render */
98 int fnext; /* next frame to filter */
99 int tnext; /* next frame to transfer */
100 } astat; /* animation status */
101
102 char *progname; /* our program name */
103 char *cfname; /* our control file name */
104
105 int nowarn = 0; /* turn warnings off? */
106 int silent = 0; /* silent mode? */
107 int noaction = 0; /* take no action? */
108
109 char *remsh; /* remote shell program/script */
110 char rendopt[2048]; /* rendering options */
111 char rresopt[32]; /* rendering resolution options */
112 char fresopt[32]; /* filter resolution options */
113 int pfiltalways; /* always use pfilt? */
114
115 char arcargs[10240]; /* files to archive */
116 char *arcfirst, *arcnext; /* pointers to first and next argument */
117
118 struct pslot {
119 int pid; /* process ID (0 if empty) */
120 int fout; /* output frame number */
121 int (*rcvf)(); /* recover function */
122 } *pslot; /* process slots */
123 int npslots; /* number of process slots */
124
125 #define phostname(ps) ((ps)->hostname[0] ? (ps)->hostname : astat.host)
126 PSERVER *lastpserver; /* last process server with error */
127
128 static struct pslot * findpslot(int pid);
129 static void checkdir(void);
130 static VIEW * getview(int n);
131
132 static char * dirfile(char *df, register char *path);
133 static char * getexp(int n);
134 static int getblur(double *mbf, double *dbf);
135 static int getastat(void);
136 static void getradfile(char *rfargs);
137 static void badvalue(int vc);
138 static int rmfile(char *fn);
139 static int runcom(char *cs);
140 static int pruncom(char *com, char *ppins, int maxcopies);
141 static void bwait(int ncoms);
142 static int bruncom(char *com, int fout, int (*rf)());
143 static int serverdown(void);
144 static pscompfunc donecom;
145 static int countviews(void);
146 static int dofilt(int frame, int rvr);
147 static void archive(void);
148 static int frecover(int frame);
149 static int recover(int frame);
150 static void sethosts(void);
151 static void walkwait(int first, int last, char *vfn);
152 static void animrend(int frame, VIEW *vp);
153 static void transferframes(void);
154 static void filterframes(void);
155 static void renderframes(int nframes);
156 static void animate(void);
157 static void setdefaults(void);
158 static void putastat(void);
159
160
161 int
162 main(
163 int argc,
164 char *argv[]
165 )
166 {
167 int explicate = 0;
168 int i;
169
170 progname = argv[0]; /* get arguments */
171 for (i = 1; i < argc && argv[i][0] == '-'; i++)
172 switch (argv[i][1]) {
173 case 'e': /* print variables */
174 explicate++;
175 break;
176 case 'w': /* turn off warnings */
177 nowarn++;
178 break;
179 case 's': /* silent mode */
180 silent++;
181 break;
182 case 'n': /* take no action */
183 noaction++;
184 break;
185 default:
186 goto userr;
187 }
188 if (i != argc-1)
189 goto userr;
190 cfname = argv[i];
191 /* load variables */
192 loadvars(cfname);
193 /* check variables */
194 checkvalues();
195 /* did we get DIRECTORY? */
196 checkdir();
197 /* check status */
198 if (getastat() < 0) {
199 fprintf(stderr, "%s: exiting\n", progname);
200 quit(1);
201 }
202 /* pfilt always if options given */
203 pfiltalways = vdef(PFILT);
204 /* load RIF if any */
205 if (vdef(RIF))
206 getradfile(vval(RIF));
207 /* set defaults */
208 setdefaults();
209 /* print variables */
210 if (explicate)
211 printvars(stdout);
212 /* set up process servers */
213 sethosts();
214 /* run animation */
215 animate();
216 /* all done */
217 if (vdef(NEXTANIM)) {
218 argv[i] = vval(NEXTANIM); /* just change input file */
219 if (!silent)
220 printargs(argc, argv, stdout);
221 if ((argv[0] = getpath(progname,getenv("PATH"),X_OK)) == NULL)
222 fprintf(stderr, "%s: command not found\n", progname);
223 else
224 execv(progname, argv);
225 quit(1);
226 }
227 quit(0);
228 return 0; /* pro forma return */
229 userr:
230 fprintf(stderr, "Usage: %s [-s][-n][-w][-e] anim_file\n", progname);
231 quit(1);
232 return 1; /* pro forma return */
233 }
234
235
236 static int
237 getastat(void) /* check/set animation status */
238 {
239 char sfname[256];
240 FILE *fp;
241
242 sprintf(sfname, "%s/%s", vval(DIRECTORY), SFNAME);
243 if ((fp = fopen(sfname, "r")) == NULL) {
244 if (errno != ENOENT) {
245 perror(sfname);
246 return(-1);
247 }
248 astat.rnext = astat.fnext = astat.tnext = 0;
249 goto setours;
250 }
251 if (fscanf(fp, "Control host: %s\n", astat.host) != 1)
252 goto fmterr;
253 if (fscanf(fp, "Control PID: %d\n", &astat.pid) != 1)
254 goto fmterr;
255 if (fscanf(fp, "Control file: %s\n", astat.cfname) != 1)
256 goto fmterr;
257 if (fscanf(fp, "Next render: %d\n", &astat.rnext) != 1)
258 goto fmterr;
259 if (fscanf(fp, "Next filter: %d\n", &astat.fnext) != 1)
260 goto fmterr;
261 if (fscanf(fp, "Next transfer: %d\n", &astat.tnext) != 1)
262 goto fmterr;
263 fclose(fp);
264 if (astat.pid != 0) { /* thinks it's still running */
265 if (strcmp(myhostname(), astat.host)) {
266 fprintf(stderr,
267 "%s: process %d may still be running on host %s\n",
268 progname, astat.pid, astat.host);
269 return(-1);
270 }
271 if (kill(astat.pid, 0) != -1 || errno != ESRCH) {
272 fprintf(stderr, "%s: process %d is still running\n",
273 progname, astat.pid);
274 return(-1);
275 }
276 /* assume it is dead */
277 }
278 if (strcmp(cfname, astat.cfname) && astat.pid != 0) { /* other's */
279 fprintf(stderr, "%s: unfinished job \"%s\"\n",
280 progname, astat.cfname);
281 return(-1);
282 }
283 /* check control file mods. */
284 if (!nowarn && fdate(cfname) > fdate(sfname))
285 fprintf(stderr,
286 "%s: warning - control file modified since last run\n",
287 progname);
288 setours: /* set our values */
289 strcpy(astat.host, myhostname());
290 astat.pid = getpid();
291 strcpy(astat.cfname, cfname);
292 return(0);
293 fmterr:
294 fprintf(stderr, "%s: format error in status file \"%s\"\n",
295 progname, sfname);
296 fclose(fp);
297 return(-1);
298 }
299
300
301 static void
302 putastat(void) /* put out current status */
303 {
304 char buf[256];
305 FILE *fp;
306
307 if (noaction)
308 return;
309 sprintf(buf, "%s/%s", vval(DIRECTORY), SFNAME);
310 if ((fp = fopen(buf, "w")) == NULL) {
311 perror(buf);
312 quit(1);
313 }
314 fprintf(fp, "Control host: %s\n", astat.host);
315 fprintf(fp, "Control PID: %d\n", astat.pid);
316 fprintf(fp, "Control file: %s\n", astat.cfname);
317 fprintf(fp, "Next render: %d\n", astat.rnext);
318 fprintf(fp, "Next filter: %d\n", astat.fnext);
319 fprintf(fp, "Next transfer: %d\n", astat.tnext);
320 fclose(fp);
321 }
322
323
324 static void
325 checkdir(void) /* make sure we have our directory */
326 {
327 struct stat stb;
328
329 if (!vdef(DIRECTORY)) {
330 fprintf(stderr, "%s: %s undefined\n",
331 progname, vnam(DIRECTORY));
332 quit(1);
333 }
334 if (stat(vval(DIRECTORY), &stb) == -1) {
335 if (errno == ENOENT && mkdir(vval(DIRECTORY), 0777) == 0)
336 return;
337 perror(vval(DIRECTORY));
338 quit(1);
339 }
340 if (!(stb.st_mode & S_IFDIR)) {
341 fprintf(stderr, "%s: not a directory\n", vval(DIRECTORY));
342 quit(1);
343 }
344 }
345
346
347 static void
348 setdefaults(void) /* set default values */
349 {
350 extern char *atos();
351 int decades;
352 char buf[256];
353
354 if (vdef(ANIMATE)) {
355 vval(OCTREE) = NULL;
356 vdef(OCTREE) = 0;
357 } else if (!vdef(OCTREE)) {
358 fprintf(stderr, "%s: either %s or %s must be defined\n",
359 progname, vnam(OCTREE), vnam(ANIMATE));
360 quit(1);
361 }
362 if (!vdef(VIEWFILE)) {
363 fprintf(stderr, "%s: %s undefined\n", progname, vnam(VIEWFILE));
364 quit(1);
365 }
366 if (!vdef(HOST)) {
367 vval(HOST) = LHOSTNAME;
368 vdef(HOST)++;
369 }
370 if (!vdef(START)) {
371 vval(START) = "1";
372 vdef(START)++;
373 }
374 if (!vdef(END)) {
375 sprintf(buf, "%d", countviews()+vint(START)-1);
376 vval(END) = savqstr(buf);
377 vdef(END)++;
378 }
379 if (vint(END) < vint(START)) {
380 fprintf(stderr, "%s: ending frame less than starting frame\n",
381 progname);
382 quit(1);
383 }
384 if (!vdef(BASENAME)) {
385 decades = (int)log10((double)vint(END)) + 1;
386 if (decades < 3) decades = 3;
387 sprintf(buf, "%s/frame%%0%dd", vval(DIRECTORY), decades);
388 vval(BASENAME) = savqstr(buf);
389 vdef(BASENAME)++;
390 }
391 if (!vdef(RESOLUTION)) {
392 vval(RESOLUTION) = "640";
393 vdef(RESOLUTION)++;
394 }
395 if (!vdef(OVERSAMP)) {
396 vval(OVERSAMP) = "2";
397 vdef(OVERSAMP)++;
398 }
399 if (!vdef(INTERP)) {
400 vval(INTERP) = "0";
401 vdef(INTERP)++;
402 }
403 if (!vdef(MBLUR)) {
404 vval(MBLUR) = "0";
405 vdef(MBLUR)++;
406 }
407 if (!vdef(RTRACE)) {
408 vval(RTRACE) = "F";
409 vdef(RTRACE)++;
410 }
411 if (!vdef(DISKSPACE)) {
412 if (!nowarn)
413 fprintf(stderr,
414 "%s: warning - no %s setting, assuming 100 Mbytes available\n",
415 progname, vnam(DISKSPACE));
416 vval(DISKSPACE) = "100";
417 vdef(DISKSPACE)++;
418 }
419 if (!vdef(RSH)) {
420 vval(RSH) = REMSH;
421 vdef(RSH)++;
422 }
423 /* locate remote shell program */
424 atos(buf, sizeof(buf), vval(RSH));
425 if ((remsh = getpath(buf, getenv("PATH"), X_OK)) != NULL)
426 remsh = savqstr(remsh);
427 else
428 remsh = vval(RSH); /* will generate error if used */
429
430 /* append rendering options */
431 if (vdef(RENDER))
432 sprintf(rendopt+strlen(rendopt), " %s", vval(RENDER));
433 }
434
435
436 static void
437 sethosts(void) /* set up process servers */
438 {
439 extern char *iskip();
440 char buf[256], *dir, *uname;
441 int np;
442 register char *cp;
443 int i;
444
445 npslots = 0;
446 if (noaction)
447 return;
448 for (i = 0; i < vdef(HOST); i++) { /* add each host */
449 dir = uname = NULL;
450 np = 1;
451 strcpy(cp=buf, nvalue(HOST, i)); /* copy to buffer */
452 cp = sskip(cp); /* skip host name */
453 while (isspace(*cp))
454 *cp++ = '\0';
455 if (*cp) { /* has # processes? */
456 np = atoi(cp);
457 if ((cp = iskip(cp)) == NULL || (*cp && !isspace(*cp)))
458 badvalue(HOST);
459 while (isspace(*cp))
460 cp++;
461 if (*cp) { /* has directory? */
462 dir = cp;
463 cp = sskip(cp); /* skip dir. */
464 while (isspace(*cp))
465 *cp++ = '\0';
466 if (*cp) { /* has user? */
467 uname = cp;
468 if (*sskip(cp))
469 badvalue(HOST);
470 }
471 }
472 }
473 if (addpserver(buf, dir, uname, np) == NULL) {
474 if (!nowarn)
475 fprintf(stderr,
476 "%s: cannot execute on host \"%s\"\n",
477 progname, buf);
478 } else
479 npslots += np;
480 }
481 if (npslots == 0) {
482 fprintf(stderr, "%s: no working process servers\n", progname);
483 quit(1);
484 }
485 pslot = (struct pslot *)calloc(npslots, sizeof(struct pslot));
486 if (pslot == NULL) {
487 perror("malloc");
488 quit(1);
489 }
490 }
491
492 static void
493 getradfile(char *rfargs) /* run rad and get needed variables */
494 {
495 static short mvar[] = {OCTREE,PFILT,RESOLUTION,EXPOSURE,-1};
496 char combuf[256];
497 register int i;
498 register char *cp;
499 char *pippt = NULL;
500 /* create rad command */
501 sprintf(rendopt, " @%s/render.opt", vval(DIRECTORY));
502 sprintf(combuf,
503 "rad -v 0 -s -e -w %s OPTFILE=%s | egrep '^[ \t]*(NOMATCH",
504 rfargs, rendopt+2);
505 cp = combuf;
506 while (*cp) {
507 if (*cp == '|') pippt = cp;
508 cp++;
509 } /* match unset variables */
510 for (i = 0; mvar[i] >= 0; i++)
511 if (!vdef(mvar[i])) {
512 *cp++ = '|';
513 strcpy(cp, vnam(mvar[i]));
514 while (*cp) cp++;
515 pippt = NULL;
516 }
517 if (pippt != NULL)
518 strcpy(pippt, "> " NULL_DEVICE); /* nothing to match */
519 else {
520 sprintf(cp, ")[ \t]*=' > %s/radset.var", vval(DIRECTORY));
521 cp += 11; /* point to file name */
522 }
523 system(combuf); /* ignore exit code */
524 if (pippt == NULL) { /* load variables and remove file */
525 loadvars(cp);
526 unlink(cp);
527 }
528 }
529
530
531 static void
532 animate(void) /* run animation */
533 {
534 int xres, yres;
535 float pa, mult;
536 int frames_batch;
537 register int i;
538 double d1, d2;
539 /* compute rpict resolution */
540 i = sscanf(vval(RESOLUTION), "%d %d %f", &xres, &yres, &pa);
541 mult = vflt(OVERSAMP);
542 if (i == 3) {
543 sprintf(rresopt, "-x %d -y %d -pa %.3f", (int)(mult*xres),
544 (int)(mult*yres), pa);
545 sprintf(fresopt, "-x %d -y %d -pa %.3f", xres, yres, pa);
546 } else if (i) {
547 if (i == 1) yres = xres;
548 sprintf(rresopt, "-x %d -y %d", (int)(mult*xres),
549 (int)(mult*yres));
550 sprintf(fresopt, "-x %d -y %d -pa 1", xres, yres);
551 } else
552 badvalue(RESOLUTION);
553 /* consistency checks */
554 if (vdef(ANIMATE)) {
555 if (vint(INTERP)) {
556 if (!nowarn)
557 fprintf(stderr,
558 "%s: resetting %s=0 for animation\n",
559 progname, vnam(INTERP));
560 vval(INTERP) = "0";
561 }
562 if (strcmp(vval(MBLUR),"0")) { /* can't handle this */
563 if (!nowarn)
564 fprintf(stderr,
565 "%s: resetting %s=0 for animation\n",
566 progname, vnam(MBLUR));
567 vval(MBLUR) = "0";
568 }
569 }
570 /* figure # frames per batch */
571 d1 = mult*xres*mult*yres*4; /* space for orig. picture */
572 if ((i=vint(INTERP)) || getblur(NULL, NULL) > 1)
573 d1 += mult*xres*mult*yres*sizeof(float); /* Z-buffer */
574 d2 = xres*yres*4; /* space for final picture */
575 frames_batch = (i+1)*(vflt(DISKSPACE)*1048576.-d1)/(d1+i*d2);
576 if (frames_batch < i+2) {
577 fprintf(stderr, "%s: insufficient disk space allocated\n",
578 progname);
579 quit(1);
580 }
581 /* initialize archive argument list */
582 i = vdef(ARCHIVE) ? strlen(vval(ARCHIVE))+132 : 132;
583 arcnext = arcfirst = arcargs + i;
584 /* initialize status file */
585 if (astat.rnext == 0)
586 astat.rnext = astat.fnext = astat.tnext = vint(START);
587 putastat();
588 /* render in batches */
589 while (astat.tnext <= vint(END)) {
590 renderframes(frames_batch);
591 filterframes();
592 transferframes();
593 }
594 /* mark status as finished */
595 astat.pid = 0;
596 putastat();
597 /* close open files */
598 getview(0);
599 getexp(0);
600 }
601
602
603 static void
604 renderframes(int nframes) /* render next nframes frames */
605 {
606 static char vendbuf[16];
607 VIEW *vp;
608 FILE *fp = NULL;
609 char vfname[128];
610 int lastframe;
611 register int i;
612
613 if (astat.tnext < astat.rnext) /* other work to do first */
614 return;
615 /* create batch view file */
616 if (!vdef(ANIMATE)) {
617 sprintf(vfname, "%s/anim.vf", vval(DIRECTORY));
618 if ((fp = fopen(vfname, "w")) == NULL) {
619 perror(vfname);
620 quit(1);
621 }
622 }
623 /* bound batch properly */
624 lastframe = astat.rnext + nframes - 1;
625 if ((lastframe-1) % (vint(INTERP)+1)) /* need even interval */
626 lastframe += vint(INTERP)+1 - ((lastframe-1)%(vint(INTERP)+1));
627 if (lastframe > vint(END)) /* check for end */
628 lastframe = vint(END);
629 /* render each view */
630 for (i = astat.rnext; i <= lastframe; i++) {
631 if ((vp = getview(i)) == NULL) {
632 if (!nowarn)
633 fprintf(stderr,
634 "%s: ran out of views before last frame\n",
635 progname);
636 sprintf(vval(END)=vendbuf, "%d", i-1);
637 lastframe = i - 1;
638 break;
639 }
640 if (vdef(ANIMATE)) /* animate frame */
641 animrend(i, vp);
642 else { /* else record it */
643 fputs(VIEWSTR, fp);
644 fprintview(vp, fp);
645 putc('\n', fp);
646 }
647 }
648 if (vdef(ANIMATE)) /* wait for renderings to finish */
649 bwait(0);
650 else { /* else if walk-through */
651 fclose(fp); /* close view file */
652 walkwait(astat.rnext, lastframe, vfname); /* walk it */
653 unlink(vfname); /* remove view file */
654 }
655 astat.rnext = i; /* update status */
656 putastat();
657 }
658
659
660 static void
661 filterframes(void) /* catch up with filtering */
662 {
663 register int i;
664
665 if (astat.tnext < astat.fnext) /* other work to do first */
666 return;
667 /* filter each view */
668 for (i = astat.fnext; i < astat.rnext; i++)
669 dofilt(i, 0);
670
671 bwait(0); /* wait for filter processes */
672 archive(); /* archive originals */
673 astat.fnext = i; /* update status */
674 putastat();
675 }
676
677
678 static void
679 transferframes(void) /* catch up with picture transfers */
680 {
681 char combuf[10240], *fbase;
682 register char *cp;
683 register int i;
684
685 if (astat.tnext >= astat.fnext) /* nothing to do, yet */
686 return;
687 if (!vdef(TRANSFER)) { /* no transfer function -- leave 'em */
688 astat.tnext = astat.fnext;
689 putastat(); /* update status */
690 return;
691 }
692 strcpy(combuf, "cd "); /* start transfer command */
693 fbase = dirfile(cp = combuf+3, vval(BASENAME));
694 if (*cp) {
695 while (*++cp) ;
696 *cp++ = ';'; *cp++ = ' ';
697 } else
698 cp = combuf;
699 strcpy(cp, vval(TRANSFER));
700 while (*cp) cp++;
701 /* make argument list */
702 for (i = astat.tnext; i < astat.fnext; i++) {
703 *cp++ = ' ';
704 sprintf(cp, fbase, i);
705 while (*cp) cp++;
706 strcpy(cp, ".pic");
707 cp += 4;
708 }
709 if (runcom(combuf)) { /* transfer frames */
710 fprintf(stderr, "%s: error running transfer command\n",
711 progname);
712 quit(1);
713 }
714 astat.tnext = i; /* update status */
715 putastat();
716 }
717
718
719 static void
720 animrend( /* start animation frame */
721 int frame,
722 VIEW *vp
723 )
724 {
725 char combuf[2048];
726 char fname[128];
727
728 sprintf(fname, vval(BASENAME), frame);
729 strcat(fname, ".unf");
730 if (access(fname, F_OK) == 0)
731 return;
732 sprintf(combuf, "%s %d | rpict%s%s -w0 %s > %s", vval(ANIMATE), frame,
733 rendopt, viewopt(vp), rresopt, fname);
734 bruncom(combuf, frame, recover); /* run in background */
735 }
736
737
738 static void
739 walkwait( /* walk-through frames */
740 int first,
741 int last,
742 char *vfn
743 )
744 {
745 double mblurf, dblurf;
746 int nblur = getblur(&mblurf, &dblurf);
747 char combuf[2048];
748 register char *inspoint;
749 register int i;
750
751 if (!noaction && vint(INTERP)) /* create dummy frames */
752 for (i = first; i <= last; i++)
753 if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
754 sprintf(combuf, vval(BASENAME), i);
755 strcat(combuf, ".unf");
756 close(open(combuf, O_RDONLY|O_CREAT, 0666));
757 }
758 /* create command */
759 sprintf(combuf, "rpict%s%s -w0", rendopt,
760 viewopt(getview(first>1 ? first-1 : 1)));
761 inspoint = combuf;
762 while (*inspoint) inspoint++;
763 if (nblur) {
764 sprintf(inspoint, " -pm %.3f", mblurf/nblur);
765 while (*inspoint) inspoint++;
766 sprintf(inspoint, " -pd %.3f", dblurf/nblur);
767 while (*inspoint) inspoint++;
768 }
769 if (nblur > 1 || vint(INTERP)) {
770 sprintf(inspoint, " -z %s.zbf", vval(BASENAME));
771 while (*inspoint) inspoint++;
772 }
773 sprintf(inspoint, " -o %s.unf %s -S %d",
774 vval(BASENAME), rresopt, first);
775 while (*inspoint) inspoint++;
776 sprintf(inspoint, " %s < %s", vval(OCTREE), vfn);
777 /* run in parallel */
778 i = (last-first+1)/(vint(INTERP)+1);
779 if (i < 1) i = 1;
780 if (pruncom(combuf, inspoint, i)) {
781 fprintf(stderr, "%s: error rendering frames %d through %d\n",
782 progname, first, last);
783 quit(1);
784 }
785 if (!noaction && vint(INTERP)) /* remove dummy frames */
786 for (i = first; i <= last; i++)
787 if (i < vint(END) && (i-1) % (vint(INTERP)+1)) {
788 sprintf(combuf, vval(BASENAME), i);
789 strcat(combuf, ".unf");
790 unlink(combuf);
791 }
792 }
793
794
795 static int
796 recover(int frame) /* recover the specified frame */
797 {
798 static int *rfrm; /* list of recovered frames */
799 static int nrfrms = 0;
800 double mblurf, dblurf;
801 int nblur = getblur(&mblurf, &dblurf);
802 char combuf[2048];
803 char fname[128];
804 register char *cp;
805 register int i;
806 /* check to see if recovered already */
807 for (i = nrfrms; i--; )
808 if (rfrm[i] == frame)
809 return(0);
810 /* build command */
811 sprintf(fname, vval(BASENAME), frame);
812 if (vdef(ANIMATE))
813 sprintf(combuf, "%s %d | rpict%s -w0",
814 vval(ANIMATE), frame, rendopt);
815 else
816 sprintf(combuf, "rpict%s -w0", rendopt);
817 cp = combuf;
818 while (*cp) cp++;
819 if (nblur) {
820 sprintf(cp, " -pm %.3f", mblurf/nblur);
821 while (*cp) cp++;
822 sprintf(cp, " -pd %.3f", dblurf/nblur);
823 while (*cp) cp++;
824 }
825 if (nblur > 1 || vint(INTERP)) {
826 sprintf(cp, " -z %s.zbf", fname);
827 while (*cp) cp++;
828 }
829 sprintf(cp, " -ro %s.unf", fname);
830 while (*cp) cp++;
831 if (!vdef(ANIMATE)) {
832 *cp++ = ' ';
833 strcpy(cp, vval(OCTREE));
834 }
835 if (runcom(combuf)) /* run command */
836 return(1);
837 /* add frame to recovered list */
838 if (nrfrms)
839 rfrm = (int *)realloc((void *)rfrm, (nrfrms+1)*sizeof(int));
840 else
841 rfrm = (int *)malloc(sizeof(int));
842 if (rfrm == NULL) {
843 perror("malloc");
844 quit(1);
845 }
846 rfrm[nrfrms++] = frame;
847 return(0);
848 }
849
850
851 static int
852 frecover(int frame) /* recover filtered frame */
853 {
854 if (dofilt(frame, 2) && dofilt(frame, 1))
855 return(1);
856 return(0);
857 }
858
859
860 static void
861 archive(void) /* archive and remove renderings */
862 {
863 #define RMCOML (sizeof(rmcom)-1)
864 static char rmcom[] = "rm -f";
865 char basedir[128];
866 int dlen, alen;
867 register int j;
868
869 if (arcnext == arcfirst)
870 return; /* nothing to do */
871 dirfile(basedir, vval(BASENAME));
872 dlen = strlen(basedir);
873 if (vdef(ARCHIVE)) { /* run archive command */
874 alen = strlen(vval(ARCHIVE));
875 if (dlen) {
876 j = alen + dlen + 5;
877 strncpy(arcfirst-j, "cd ", 3);
878 strncpy(arcfirst-j+3, basedir, dlen);
879 (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
880 } else
881 j = alen;
882 strncpy(arcfirst-alen, vval(ARCHIVE), alen);
883 if (runcom(arcfirst-j)) {
884 fprintf(stderr, "%s: error running archive command\n",
885 progname);
886 quit(1);
887 }
888 }
889 if (dlen) {
890 j = RMCOML + dlen + 5;
891 strncpy(arcfirst-j, "cd ", 3);
892 strncpy(arcfirst-j+3, basedir, dlen);
893 (arcfirst-j)[dlen+3] = ';'; (arcfirst-j)[dlen+4] = ' ';
894 } else
895 j = RMCOML;
896 /* run remove command */
897 strncpy(arcfirst-RMCOML, rmcom, RMCOML);
898 runcom(arcfirst-j);
899 arcnext = arcfirst; /* reset argument list */
900 #undef RMCOML
901 }
902
903
904 static int
905 dofilt( /* filter frame */
906 int frame,
907 int rvr
908 )
909 {
910 static int iter = 0;
911 double mblurf, dblurf;
912 int nblur = getblur(&mblurf, &dblurf);
913 VIEW *vp = getview(frame);
914 char *ep = getexp(frame);
915 char fnbefore[128], fnafter[128], *fbase;
916 char combuf[1024], fname0[128], fname1[128];
917 int usepinterp, usepfilt, nora_rgbe;
918 int frseq[2];
919 /* check what is needed */
920 if (vp == NULL) {
921 fprintf(stderr,
922 "%s: unexpected error reading view for frame %d\n",
923 progname, frame);
924 quit(1);
925 }
926 usepinterp = (nblur > 1);
927 usepfilt = pfiltalways | (ep==NULL);
928 if (ep != NULL && !strcmp(ep, "1"))
929 ep = "+0";
930 nora_rgbe = strcmp(vval(OVERSAMP),"1") || ep==NULL ||
931 *ep != '+' || *ep != '-' || !isint(ep);
932 /* compute rendered views */
933 frseq[0] = frame - ((frame-1) % (vint(INTERP)+1));
934 frseq[1] = frseq[0] + vint(INTERP) + 1;
935 fbase = dirfile(NULL, vval(BASENAME));
936 if (frseq[1] > vint(END))
937 frseq[1] = vint(END);
938 if (frseq[1] == frame) { /* pfilt only */
939 frseq[0] = frseq[1];
940 usepinterp = 0; /* update what's needed */
941 usepfilt |= nora_rgbe;
942 } else if (frseq[0] == frame) { /* no interpolation needed */
943 if (!rvr && frame > 1+vint(INTERP)) { /* archive previous */
944 *arcnext++ = ' ';
945 sprintf(arcnext, fbase, frame-vint(INTERP)-1);
946 while (*arcnext) arcnext++;
947 strcpy(arcnext, ".unf");
948 arcnext += 4;
949 if (usepinterp || vint(INTERP)) { /* and Z-buf */
950 *arcnext++ = ' ';
951 sprintf(arcnext, fbase, frame-vint(INTERP)-1);
952 while (*arcnext) arcnext++;
953 strcpy(arcnext, ".zbf");
954 arcnext += 4;
955 }
956 }
957 if (!usepinterp) /* update what's needed */
958 usepfilt |= nora_rgbe;
959 } else /* interpolation needed */
960 usepinterp++;
961 if (frseq[1] >= astat.rnext) /* next batch unavailable */
962 frseq[1] = frseq[0];
963 sprintf(fnbefore, vval(BASENAME), frseq[0]);
964 sprintf(fnafter, vval(BASENAME), frseq[1]);
965 if (rvr == 1 && recover(frseq[0])) /* recover before frame? */
966 return(1);
967 /* generate command */
968 if (usepinterp) { /* using pinterp */
969 if (rvr == 2 && recover(frseq[1])) /* recover after? */
970 return(1);
971 if (nblur > 1) { /* with pdmblur */
972 sprintf(fname0, "%s/vw0%c", vval(DIRECTORY),
973 'a'+(iter%26));
974 sprintf(fname1, "%s/vw1%c", vval(DIRECTORY),
975 'a'+(iter%26));
976 if (!noaction) {
977 FILE *fp; /* motion blurring */
978 if ((fp = fopen(fname0, "w")) == NULL) {
979 perror(fname0); quit(1);
980 }
981 fputs(VIEWSTR, fp);
982 fprintview(vp, fp);
983 putc('\n', fp); fclose(fp);
984 if ((vp = getview(frame+1)) == NULL) {
985 fprintf(stderr,
986 "%s: unexpected error reading view for frame %d\n",
987 progname, frame+1);
988 quit(1);
989 }
990 if ((fp = fopen(fname1, "w")) == NULL) {
991 perror(fname1); quit(1);
992 }
993 fputs(VIEWSTR, fp);
994 fprintview(vp, fp);
995 putc('\n', fp); fclose(fp);
996 }
997 sprintf(combuf,
998 "(pmdblur %.3f %.3f %d %s %s; rm -f %s %s) | pinterp -B -a",
999 mblurf, dblurf, nblur,
1000 fname0, fname1, fname0, fname1);
1001 iter++;
1002 } else /* no blurring */
1003 strcpy(combuf, "pinterp");
1004 strcat(combuf, viewopt(vp));
1005 if (vbool(RTRACE))
1006 sprintf(combuf+strlen(combuf), " -ff -fr '%s -w0 %s'",
1007 rendopt+1, vval(OCTREE));
1008 if (vdef(PINTERP))
1009 sprintf(combuf+strlen(combuf), " %s", vval(PINTERP));
1010 if (usepfilt)
1011 sprintf(combuf+strlen(combuf), " %s", rresopt);
1012 else
1013 sprintf(combuf+strlen(combuf), " -a %s -e %s",
1014 fresopt, ep);
1015 sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
1016 fnbefore, fnbefore);
1017 if (frseq[1] != frseq[0])
1018 sprintf(combuf+strlen(combuf), " %s.unf %s.zbf",
1019 fnafter, fnafter);
1020 if (usepfilt) { /* also pfilt */
1021 if (vdef(PFILT))
1022 sprintf(combuf+strlen(combuf), " | pfilt %s",
1023 vval(PFILT));
1024 else
1025 strcat(combuf, " | pfilt");
1026 if (ep != NULL)
1027 sprintf(combuf+strlen(combuf), " -1 -e %s %s",
1028 ep, fresopt);
1029 else
1030 sprintf(combuf+strlen(combuf), " %s", fresopt);
1031 }
1032 } else if (usepfilt) { /* pfilt only */
1033 if (rvr == 2)
1034 return(1);
1035 if (vdef(PFILT))
1036 sprintf(combuf, "pfilt %s", vval(PFILT));
1037 else
1038 strcpy(combuf, "pfilt");
1039 if (ep != NULL)
1040 sprintf(combuf+strlen(combuf), " -1 -e %s %s %s.unf",
1041 ep, fresopt, fnbefore);
1042 else
1043 sprintf(combuf+strlen(combuf), " %s %s.unf",
1044 fresopt, fnbefore);
1045 } else { /* else just check it */
1046 if (rvr == 2)
1047 return(1);
1048 sprintf(combuf, "ra_rgbe -e %s -r %s.unf", ep, fnbefore);
1049 }
1050 /* output file name */
1051 sprintf(fname0, vval(BASENAME), frame);
1052 sprintf(combuf+strlen(combuf), " > %s.pic", fname0);
1053 if (rvr) /* in recovery */
1054 return(runcom(combuf));
1055 bruncom(combuf, frame, frecover); /* else run in background */
1056 return(0);
1057 }
1058
1059
1060 static VIEW *
1061 getview(int n) /* get view number n */
1062 {
1063 static FILE *viewfp = NULL; /* view file pointer */
1064 static int viewnum = 0; /* current view number */
1065 static VIEW curview = STDVIEW; /* current view */
1066 char linebuf[256];
1067
1068 if (n == 0) { /* signal to close file and clean up */
1069 if (viewfp != NULL) {
1070 fclose(viewfp);
1071 viewfp = NULL;
1072 viewnum = 0;
1073 curview = stdview;
1074 }
1075 return(NULL);
1076 }
1077 if (viewfp == NULL) { /* open file */
1078 if ((viewfp = fopen(vval(VIEWFILE), "r")) == NULL) {
1079 perror(vval(VIEWFILE));
1080 quit(1);
1081 }
1082 } else if (n > 0 && n < viewnum) { /* rewind file */
1083 if (viewnum == 1 && feof(viewfp))
1084 return(&curview); /* just one view */
1085 if (fseek(viewfp, 0L, 0) == EOF) {
1086 perror(vval(VIEWFILE));
1087 quit(1);
1088 }
1089 curview = stdview;
1090 viewnum = 0;
1091 }
1092 if (n < 0) { /* get next view */
1093 register int c = getc(viewfp);
1094 if (c == EOF)
1095 return((VIEW *)NULL); /* that's it */
1096 ungetc(c, viewfp);
1097 n = viewnum + 1;
1098 }
1099 while (n > viewnum) { /* scan to desired view */
1100 if (fgets(linebuf, sizeof(linebuf), viewfp) == NULL)
1101 return(viewnum==1 ? &curview : (VIEW *)NULL);
1102 if (isview(linebuf) && sscanview(&curview, linebuf) > 0)
1103 viewnum++;
1104 }
1105 return(&curview); /* return it */
1106 }
1107
1108
1109 static int
1110 countviews(void) /* count views in view file */
1111 {
1112 int n;
1113
1114 if (getview(n=1) == NULL)
1115 return(0);
1116 while (getview(-1) != NULL)
1117 n++;
1118 return(n);
1119 }
1120
1121
1122 static char *
1123 getexp(int n) /* get exposure for nth frame */
1124 {
1125 extern char *fskip();
1126 static char expval[32];
1127 static FILE *expfp = NULL;
1128 static long *exppos;
1129 static int curfrm;
1130 register char *cp;
1131
1132 if (n == 0) { /* signal to close file */
1133 if (expfp != NULL) {
1134 fclose(expfp);
1135 free((void *)exppos);
1136 expfp = NULL;
1137 }
1138 return(NULL);
1139 } else if (n > vint(END)) /* request past end (error?) */
1140 return(NULL);
1141 if (!vdef(EXPOSURE)) /* no setting (auto) */
1142 return(NULL);
1143 if (isflt(vval(EXPOSURE))) /* always the same */
1144 return(vval(EXPOSURE));
1145 if (expfp == NULL) { /* open exposure file */
1146 if ((expfp = fopen(vval(EXPOSURE), "r")) == NULL) {
1147 fprintf(stderr,
1148 "%s: cannot open exposure file \"%s\"\n",
1149 progname, vval(EXPOSURE));
1150 quit(1);
1151 }
1152 curfrm = vint(END) + 1; /* init lookup tab. */
1153 exppos = (long *)malloc(curfrm*sizeof(long *));
1154 if (exppos == NULL) {
1155 perror(progname);
1156 quit(1);
1157 }
1158 while (curfrm--)
1159 exppos[curfrm] = -1L;
1160 curfrm = 0;
1161 }
1162 /* find position in file */
1163 if (n-1 != curfrm && n != curfrm && exppos[n-1] >= 0 &&
1164 fseek(expfp, exppos[curfrm=n-1], 0) == EOF) {
1165 fprintf(stderr, "%s: seek error on exposure file\n", progname);
1166 quit(1);
1167 }
1168 while (n > curfrm) { /* read exposure */
1169 if (exppos[curfrm] < 0)
1170 exppos[curfrm] = ftell(expfp);
1171 if (fgets(expval, sizeof(expval), expfp) == NULL) {
1172 fprintf(stderr, "%s: too few exposures\n",
1173 vval(EXPOSURE));
1174 quit(1);
1175 }
1176 curfrm++;
1177 cp = fskip(expval); /* check format */
1178 if (cp != NULL)
1179 while (isspace(*cp))
1180 *cp++ = '\0';
1181 if (cp == NULL || *cp) {
1182 fprintf(stderr,
1183 "%s: exposure format error on line %d\n",
1184 vval(EXPOSURE), curfrm);
1185 quit(1);
1186 }
1187 }
1188 return(expval); /* return value */
1189 }
1190
1191
1192 static struct pslot *
1193 findpslot(int pid) /* find or allocate a process slot */
1194 {
1195 register struct pslot *psempty = NULL;
1196 register int i;
1197
1198 for (i = 0; i < npslots; i++) { /* look for match */
1199 if (pslot[i].pid == pid)
1200 return(pslot+i);
1201 if (psempty == NULL && pslot[i].pid == 0)
1202 psempty = pslot+i;
1203 }
1204 return(psempty); /* return emtpy slot (error if NULL) */
1205 }
1206
1207
1208 static int
1209 donecom( /* clean up after finished process */
1210 PSERVER *ps,
1211 int pn,
1212 int status
1213 )
1214 {
1215 register NETPROC *pp;
1216 register struct pslot *psl;
1217
1218 pp = ps->proc + pn;
1219 if (pp->elen) { /* pass errors */
1220 if (ps->hostname[0])
1221 fprintf(stderr, "%s: ", ps->hostname);
1222 fprintf(stderr, "Error output from: %s\n", pp->com);
1223 fputs(pp->errs, stderr);
1224 fflush(stderr);
1225 if (ps->hostname[0])
1226 status = 1; /* because rsh doesn't return status */
1227 }
1228 lastpserver = NULL;
1229 psl = findpslot(pp->pid); /* check for bruncom() slot */
1230 if (psl->pid) {
1231 if (status) {
1232 if (psl->rcvf != NULL) /* attempt recovery */
1233 status = (*psl->rcvf)(psl->fout);
1234 if (status) {
1235 fprintf(stderr,
1236 "%s: error rendering frame %d\n",
1237 progname, psl->fout);
1238 quit(1);
1239 }
1240 lastpserver = ps;
1241 }
1242 psl->pid = 0; /* free process slot */
1243 } else if (status)
1244 lastpserver = ps;
1245 freestr(pp->com); /* free command string */
1246 return(status);
1247 }
1248
1249
1250 static int
1251 serverdown(void) /* check status of last process server */
1252 {
1253 if (lastpserver == NULL || !lastpserver->hostname[0])
1254 return(0);
1255 if (pserverOK(lastpserver)) /* server still up? */
1256 return(0);
1257 delpserver(lastpserver); /* else delete it */
1258 if (pslist == NULL) {
1259 fprintf(stderr, "%s: all process servers are down\n",
1260 progname);
1261 quit(1);
1262 }
1263 return(1);
1264 }
1265
1266
1267 static int
1268 bruncom( /* run a command in the background */
1269 char *com,
1270 int fout,
1271 int (*rf)()
1272 )
1273 {
1274 int pid;
1275 register struct pslot *psl;
1276
1277 if (noaction) {
1278 if (!silent)
1279 printf("\t%s\n", com); /* echo command */
1280 return(0);
1281 }
1282 com = savestr(com); /* else start it when we can */
1283 while ((pid = startjob(NULL, com, donecom)) == -1)
1284 bwait(1);
1285 if (!silent) { /* echo command */
1286 PSERVER *ps;
1287 int psn = pid;
1288 ps = findjob(&psn);
1289 printf("\t%s\n", com);
1290 printf("\tProcess started on %s\n", phostname(ps));
1291 fflush(stdout);
1292 }
1293 psl = findpslot(pid); /* record info. in appropriate slot */
1294 psl->pid = pid;
1295 psl->fout = fout;
1296 psl->rcvf = rf;
1297 return(pid);
1298 }
1299
1300
1301 static void
1302 bwait(int ncoms) /* wait for batch job(s) to finish */
1303 {
1304 int status;
1305
1306 if (noaction)
1307 return;
1308 while ((status = wait4job(NULL, -1)) != -1) {
1309 serverdown(); /* update server status */
1310 if (--ncoms == 0)
1311 break; /* done enough */
1312 }
1313 }
1314
1315
1316 static int
1317 pruncom( /* run a command in parallel over network */
1318 char *com,
1319 char *ppins,
1320 int maxcopies
1321 )
1322 {
1323 int retstatus = 0;
1324 int hostcopies;
1325 char buf[10240], *com1, *s;
1326 int status;
1327 int pfd;
1328 register int n;
1329 register PSERVER *ps;
1330
1331 if (!silent)
1332 printf("\t%s\n", com); /* echo command */
1333 if (noaction)
1334 return(0);
1335 fflush(stdout);
1336 /* start jobs on each server */
1337 for (ps = pslist; ps != NULL; ps = ps->next) {
1338 hostcopies = 0;
1339 if (maxcopies > 1 && ps->nprocs > 1 && ppins != NULL) {
1340 strcpy(com1=buf, com); /* build -PP command */
1341 sprintf(com1+(ppins-com), " -PP %s/%s.persist",
1342 vval(DIRECTORY), phostname(ps));
1343 unlink(com1+(ppins-com)+5);
1344 strcat(com1, ppins);
1345 } else
1346 com1 = com;
1347 while (maxcopies > 0) {
1348 s = savestr(com1);
1349 if (startjob(ps, s, donecom) != -1) {
1350 sleep(20);
1351 hostcopies++;
1352 maxcopies--;
1353 } else {
1354 freestr(s);
1355 break;
1356 }
1357 }
1358 if (!silent && hostcopies) {
1359 if (hostcopies > 1)
1360 printf("\t%d duplicate processes", hostcopies);
1361 else
1362 printf("\tProcess");
1363 printf(" started on %s\n", phostname(ps));
1364 fflush(stdout);
1365 }
1366 }
1367 /* wait for jobs to finish */
1368 while ((status = wait4job(NULL, -1)) != -1)
1369 retstatus += status && !serverdown();
1370 /* terminate parallel rpict's */
1371 for (ps = pslist; ps != NULL; ps = ps->next) {
1372 sprintf(buf, "%s/%s.persist", vval(DIRECTORY), phostname(ps));
1373 if ((pfd = open(buf, O_RDONLY)) >= 0) {
1374 n = read(pfd, buf, sizeof(buf)-1); /* get PID */
1375 buf[n] = '\0';
1376 close(pfd);
1377 for (n = 0; buf[n] && !isspace(buf[n]); n++)
1378 ;
1379 /* terminate */
1380 sprintf(buf, "kill -ALRM %d", atoi(buf+n));
1381 wait4job(ps, startjob(ps, buf, NULL));
1382 }
1383 }
1384 return(retstatus);
1385 }
1386
1387
1388 static int
1389 runcom(char *cs) /* run a command locally and wait for it */
1390 {
1391 if (!silent) /* echo it */
1392 printf("\t%s\n", cs);
1393 if (noaction)
1394 return(0);
1395 fflush(stdout); /* flush output and pass to shell */
1396 return(system(cs));
1397 }
1398
1399
1400 static int
1401 rmfile(char *fn) /* remove a file */
1402 {
1403 if (!silent)
1404 #ifdef _WIN32
1405 printf("\tdel %s\n", fn);
1406 #else
1407 printf("\trm -f %s\n", fn);
1408 #endif
1409 if (noaction)
1410 return(0);
1411 return(unlink(fn));
1412 }
1413
1414
1415 static void
1416 badvalue(int vc) /* report bad variable value and exit */
1417 {
1418 fprintf(stderr, "%s: bad value for variable '%s'\n",
1419 progname, vnam(vc));
1420 quit(1);
1421 }
1422
1423
1424 static char *
1425 dirfile( /* separate path into directory and file */
1426 char *df,
1427 register char *path
1428 )
1429 {
1430 register int i;
1431 int psep;
1432
1433 for (i = 0, psep = -1; path[i]; i++)
1434 if (path[i] == '/')
1435 psep = i;
1436 if (df != NULL) {
1437 if (psep == 0) {
1438 df[0] = '/';
1439 df[1] = '\0';
1440 } else if (psep > 0) {
1441 strncpy(df, path, psep);
1442 df[psep] = '\0';
1443 } else
1444 df[0] = '\0';
1445 }
1446 return(path+psep+1);
1447 }
1448
1449
1450 static int
1451 getblur(double *mbf, double *dbf) /* get # blur samples (and fraction) */
1452 {
1453 double mblurf, dblurf;
1454 int nmblur, ndblur;
1455 char *s;
1456 /* get motion blur */
1457 if (!vdef(MBLUR) || (mblurf = atof(vval(MBLUR))) < 0.0)
1458 mblurf = 0.0;
1459 if (mbf != NULL)
1460 *mbf = mblurf;
1461 if (mblurf <= FTINY)
1462 nmblur = 0;
1463 else if (!*(s = sskip(vval(MBLUR))))
1464 nmblur = DEF_NBLUR;
1465 else if ((nmblur = atoi(s)) <= 0)
1466 nmblur = 1;
1467 /* get depth-of-field blur */
1468 if (!vdef(DBLUR) || (dblurf = atof(vval(DBLUR))) < 0.0)
1469 dblurf = 0.0;
1470 if (dbf != NULL)
1471 *dbf = dblurf;
1472 if (dblurf <= FTINY)
1473 ndblur = 0;
1474 else if (!*(s = sskip(vval(DBLUR))))
1475 ndblur = DEF_NBLUR;
1476 else if ((ndblur = atoi(s)) <= 0)
1477 ndblur = 1;
1478 if ((nmblur == 1) & (ndblur == 1))
1479 return(1);
1480 /* return combined samples */
1481 return(nmblur + ndblur);
1482 }