ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.49
Committed: Mon Feb 7 17:08:17 2005 UTC (19 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1
Changes since 2.48: +4 -2 lines
Log Message:
Switched from using "rsh" to "ssh" in ranimate

File Contents

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