ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimate.c
Revision: 2.47
Committed: Tue Jun 8 19:48:31 2004 UTC (19 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6, rad3R6P1
Changes since 2.46: +2 -4 lines
Log Message:
Removed redundant #include's and fixed ordering on some headers

File Contents

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